Skip to content

Commit

Permalink
ramping-vus: Targets validation improvement (#3470)
Browse files Browse the repository at this point in the history
Added a validation step in case an exaggerated high number is set as a stage's target.
  • Loading branch information
VincentSchmid authored Feb 28, 2024
1 parent 3a7bf2c commit b217bbf
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 1 deletion.
27 changes: 27 additions & 0 deletions lib/executor/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ import (
"go.k6.io/k6/ui/pb"
)

const (
// maxConcurrentVUs is an arbitrary limit for sanity checks.
// It prevents running an exaggeratedly large number of concurrent VUs which may lead to an out-of-memory.
maxConcurrentVUs int = 100_000_000
)

func sumStagesDuration(stages []Stage) (result time.Duration) {
for _, s := range stages {
result += s.Duration.TimeDuration()
Expand All @@ -33,6 +39,27 @@ func getStagesUnscaledMaxTarget(unscaledStartValue int64, stages []Stage) int64
return max
}

// validateTargetShifts validates the VU Target shifts.
// It will append an error for any VU target that is larger than the maximum value allowed.
// Each Stage needs a Target value. The stages array can be empty. The Targes could be negative.
func validateTargetShifts(startVUs int64, stages []Stage) []error {
var errors []error

if startVUs > int64(maxConcurrentVUs) {
errors = append(errors, fmt.Errorf(
"the startVUs exceed max limit of %d", maxConcurrentVUs))
}

for i := 0; i < len(stages); i++ {
if stages[i].Target.Int64 > int64(maxConcurrentVUs) {
errors = append(errors, fmt.Errorf(
"target for stage %d exceeds max limit of %d", i+1, maxConcurrentVUs))
}
}

return errors
}

// A helper function to avoid code duplication
func validateStages(stages []Stage) []error {
var errors []error
Expand Down
5 changes: 4 additions & 1 deletion lib/executor/ramping_vus.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,10 @@ func (vlvc RampingVUsConfig) Validate() []error {
errors = append(errors, fmt.Errorf("either startVUs or one of the stages' target values must be greater than 0"))
}

return append(errors, validateStages(vlvc.Stages)...)
errors = append(errors, validateStages(vlvc.Stages)...)
errors = append(errors, validateTargetShifts(vlvc.StartVUs.Int64, vlvc.Stages)...)

return errors
}

// getRawExecutionSteps calculates and returns as execution steps the number of
Expand Down
45 changes: 45 additions & 0 deletions lib/executor/ramping_vus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,51 @@ func TestRampingVUsConfigValidation(t *testing.T) {
errs = c.Validate()
require.NotEmpty(t, errs)
assert.Contains(t, errs[0].Error(), "greater than 0")

const maxConcurrentVUs = 100_000_000

t.Run("If startVUs are larger than maxConcurrentVUs, the validation should return an error", func(t *testing.T) {
t.Parallel()

c = NewRampingVUsConfig("stage")
c.StartVUs = null.IntFrom(maxConcurrentVUs + 1)
c.Stages = []Stage{
{Target: null.IntFrom(0), Duration: types.NullDurationFrom(1 * time.Second)},
}

errs = c.Validate()
require.NotEmpty(t, errs)
assert.Contains(t, errs[0].Error(), "the startVUs exceed max limit of")
})

t.Run("For multiple VU values larger than maxConcurrentVUs, multiple errors are returned", func(t *testing.T) {
t.Parallel()

c = NewRampingVUsConfig("stage")
c.StartVUs = null.IntFrom(maxConcurrentVUs + 1)
c.Stages = []Stage{
{Target: null.IntFrom(maxConcurrentVUs + 2), Duration: types.NullDurationFrom(1 * time.Second)},
}

errs = c.Validate()
require.Equal(t, 2, len(errs))
assert.Contains(t, errs[0].Error(), "the startVUs exceed max limit of")

assert.Contains(t, errs[1].Error(), "target for stage 1 exceeds max limit of")
})

t.Run("VU values below maxConcurrentVUs will pass validation", func(t *testing.T) {
t.Parallel()

c = NewRampingVUsConfig("stage")
c.StartVUs = null.IntFrom(0)
c.Stages = []Stage{
{Target: null.IntFrom(maxConcurrentVUs - 1), Duration: types.NullDurationFrom(1 * time.Second)},
}

errs = c.Validate()
require.Empty(t, errs)
})
}

func TestRampingVUsRun(t *testing.T) {
Expand Down

0 comments on commit b217bbf

Please sign in to comment.