Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

handling large vu shifts #3470

Merged
merged 17 commits into from
Feb 28, 2024
26 changes: 26 additions & 0 deletions lib/executor/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,32 @@ func getStagesUnscaledMaxTarget(unscaledStartValue int64, stages []Stage) int64
return max
}

func validateNumberOfVuShifts(startVus int64, stages []Stage) []error {
oleiade marked this conversation as resolved.
Show resolved Hide resolved
VincentSchmid marked this conversation as resolved.
Show resolved Hide resolved
const MaxRampingVUShift = 100000000
VincentSchmid marked this conversation as resolved.
Show resolved Hide resolved
oleiade marked this conversation as resolved.
Show resolved Hide resolved

var errors []error
totalShifts := big.NewInt(startVus)
prevNumVus := totalShifts

for _, s := range stages {
current := big.NewInt(s.Target.Int64)
vuDelta := new(big.Int).Sub(current, prevNumVus)
vuDelta.Abs(vuDelta)

totalShifts.Add(totalShifts, vuDelta)

prevNumVus = current
}

totalShifts.Add(totalShifts, prevNumVus)
oleiade marked this conversation as resolved.
Show resolved Hide resolved

if totalShifts.Cmp(big.NewInt(MaxRampingVUShift)) > 0 {
errors = append(errors, fmt.Errorf("total number of VU shifts is too large"))
}

return errors
}

// A helper function to avoid code duplication
func validateStages(stages []Stage) []error {
var errors []error
Expand Down
1 change: 1 addition & 0 deletions lib/executor/ramping_arrival_rate.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ func (varc *RampingArrivalRateConfig) Validate() []error {
errors = append(errors, fmt.Errorf("the timeUnit must be more than 0"))
}

errors = append(errors, validateNumberOfVuShifts(varc.StartRate.Int64, varc.Stages)...)
errors = append(errors, validateStages(varc.Stages)...)

if !varc.PreAllocatedVUs.Valid {
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, validateNumberOfVuShifts(vlvc.StartVUs.Int64, vlvc.Stages)...)
errors = append(errors, validateStages(vlvc.Stages)...)

return errors
}

// getRawExecutionSteps calculates and returns as execution steps the number of
Expand Down
29 changes: 29 additions & 0 deletions lib/executor/ramping_vus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
"math"
"math/big"
"math/rand"
"sync/atomic"
Expand Down Expand Up @@ -36,6 +37,34 @@ func TestRampingVUsConfigValidation(t *testing.T) {
errs = c.Validate()
require.NotEmpty(t, errs)
assert.Contains(t, errs[0].Error(), "greater than 0")

t.Run("validate large VU shifts should fail", func(t *testing.T) {
oleiade marked this conversation as resolved.
Show resolved Hide resolved
oleiade marked this conversation as resolved.
Show resolved Hide resolved
t.Parallel()

const MaxRampingVUShift = 100000000
const HalfMaxRampingVUShift = MaxRampingVUShift / 2
const HalfMaxInt = math.MaxInt64 / 2

c.StartVUs = null.IntFrom(MaxRampingVUShift)
errs = c.Validate()
require.NotEmpty(t, errs)
assert.Contains(t, errs[0].Error(), "number of VU shifts is too large")

c.StartVUs = null.IntFrom(0)
c.Stages = []Stage{
{Target: null.IntFrom(HalfMaxRampingVUShift + 1), Duration: types.NullDurationFrom(12 * time.Second)},
oleiade marked this conversation as resolved.
Show resolved Hide resolved
}
errs = c.Validate()
assert.Contains(t, errs[0].Error(), "number of VU shifts is too large")

// Integer overflow is correctly handled
c.StartVUs = null.IntFrom(0)
c.Stages = []Stage{
{Target: null.IntFrom(HalfMaxInt + 1), Duration: types.NullDurationFrom(12 * time.Second)},
VincentSchmid marked this conversation as resolved.
Show resolved Hide resolved
}
errs = c.Validate()
assert.Contains(t, errs[0].Error(), "number of VU shifts is too large")
})
}

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