mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-28 20:09:36 +08:00
Merge pull request #140 from xucong053/support-think-time
feat: support think time for load testing #120
This commit is contained in:
@@ -150,6 +150,10 @@ func (b *HRPBoomer) convertBoomerTask(testcase *TestCase, rendezvousList []*Rend
|
|||||||
}
|
}
|
||||||
} else if stepData.StepType == stepTypeRendezvous {
|
} else if stepData.StepType == stepTypeRendezvous {
|
||||||
// rendezvous
|
// rendezvous
|
||||||
|
// TODO: implement rendezvous in boomer
|
||||||
|
} else if stepData.StepType == stepTypeThinkTime {
|
||||||
|
// think time
|
||||||
|
// no record required
|
||||||
} else {
|
} else {
|
||||||
// request or testcase step
|
// request or testcase step
|
||||||
b.RecordSuccess(step.Type(), step.Name(), stepData.Elapsed, stepData.ContentSize)
|
b.RecordSuccess(step.Type(), step.Name(), stepData.Elapsed, stepData.ContentSize)
|
||||||
|
|||||||
@@ -156,6 +156,10 @@ func (tc *TCase) ToTestCase() (*TestCase, error) {
|
|||||||
testCase.TestSteps = append(testCase.TestSteps, &StepTestCaseWithOptionalArgs{
|
testCase.TestSteps = append(testCase.TestSteps, &StepTestCaseWithOptionalArgs{
|
||||||
step: step,
|
step: step,
|
||||||
})
|
})
|
||||||
|
} else if step.ThinkTime != nil {
|
||||||
|
testCase.TestSteps = append(testCase.TestSteps, &StepThinkTime{
|
||||||
|
step: step,
|
||||||
|
})
|
||||||
} else if step.Request != nil {
|
} else if step.Request != nil {
|
||||||
testCase.TestSteps = append(testCase.TestSteps, &StepRequestWithOptionalArgs{
|
testCase.TestSteps = append(testCase.TestSteps, &StepRequestWithOptionalArgs{
|
||||||
step: step,
|
step: step,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ var (
|
|||||||
demoTestCaseYAMLPath TestCasePath = "examples/demo.yaml"
|
demoTestCaseYAMLPath TestCasePath = "examples/demo.yaml"
|
||||||
demoRefAPIYAMLPath TestCasePath = "examples/ref_api_test.yaml"
|
demoRefAPIYAMLPath TestCasePath = "examples/ref_api_test.yaml"
|
||||||
demoRefTestCaseJSONPath TestCasePath = "examples/ref_testcase_test.json"
|
demoRefTestCaseJSONPath TestCasePath = "examples/ref_testcase_test.json"
|
||||||
|
demoThinkTimeJsonPath TestCasePath = "examples/think_time_test.json"
|
||||||
demoAPIYAMLPath APIPath = "examples/api/put.yml"
|
demoAPIYAMLPath APIPath = "examples/api/put.yml"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
63
examples/think_time_test.json
Normal file
63
examples/think_time_test.json
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"name": "think time test demo",
|
||||||
|
"variables": {
|
||||||
|
"app_version": "v1",
|
||||||
|
"user_agent": "iOS/10.3"
|
||||||
|
},
|
||||||
|
"base_url": "https://postman-echo.com",
|
||||||
|
"think_time": {
|
||||||
|
"strategy": "random_percentage",
|
||||||
|
"setting": {
|
||||||
|
"min_percentage": 1,
|
||||||
|
"max_percentage": 1.5
|
||||||
|
},
|
||||||
|
"limit": 4
|
||||||
|
},
|
||||||
|
"verify": false
|
||||||
|
},
|
||||||
|
"teststeps": [
|
||||||
|
{
|
||||||
|
"name": "get with params",
|
||||||
|
"request": {
|
||||||
|
"method": "GET",
|
||||||
|
"url": "/get",
|
||||||
|
"headers": {
|
||||||
|
"User-Agent": "$user_agent,$app_version"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"validate": [
|
||||||
|
{
|
||||||
|
"check": "status_code",
|
||||||
|
"assert": "equals",
|
||||||
|
"expect": 200,
|
||||||
|
"msg": "check status code"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "think time 1",
|
||||||
|
"think_time": {
|
||||||
|
"time": 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "post with params",
|
||||||
|
"request": {
|
||||||
|
"method": "POST",
|
||||||
|
"url": "/post",
|
||||||
|
"headers": {
|
||||||
|
"User-Agent": "$user_agent,$app_version"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"validate": [
|
||||||
|
{
|
||||||
|
"check": "status_code",
|
||||||
|
"assert": "equals",
|
||||||
|
"expect": 200,
|
||||||
|
"msg": "check status code"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
40
examples/think_time_test.yaml
Normal file
40
examples/think_time_test.yaml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
config:
|
||||||
|
name: "think time test demo"
|
||||||
|
variables:
|
||||||
|
app_version: v1
|
||||||
|
user_agent: iOS/10.3
|
||||||
|
base_url: "https://postman-echo.com"
|
||||||
|
think_time:
|
||||||
|
strategy: random_percentage
|
||||||
|
setting:
|
||||||
|
min_percentage: 1.0
|
||||||
|
max_percentage: 1.5
|
||||||
|
limit: 4
|
||||||
|
verify: False
|
||||||
|
|
||||||
|
teststeps:
|
||||||
|
- name: get with params
|
||||||
|
request:
|
||||||
|
method: GET
|
||||||
|
url: /get
|
||||||
|
headers:
|
||||||
|
User-Agent: $user_agent,$app_version
|
||||||
|
validate:
|
||||||
|
- check: status_code
|
||||||
|
assert: equals
|
||||||
|
expect: 200
|
||||||
|
msg: check status code
|
||||||
|
- name: think time 1
|
||||||
|
think_time:
|
||||||
|
time: 3
|
||||||
|
- name: post with params
|
||||||
|
request:
|
||||||
|
method: POST
|
||||||
|
url: /post
|
||||||
|
headers:
|
||||||
|
User-Agent: $user_agent,$app_version
|
||||||
|
validate:
|
||||||
|
- check: status_code
|
||||||
|
assert: equals
|
||||||
|
expect: 200
|
||||||
|
msg: check status code
|
||||||
@@ -5,12 +5,15 @@ import (
|
|||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/csv"
|
"encoding/csv"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
builtinJSON "encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -220,3 +223,38 @@ func Contains(s []string, e string) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetRandomNumber(min, max int) int {
|
||||||
|
if min > max {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
r := rand.Intn(max - min + 1)
|
||||||
|
return min + r
|
||||||
|
}
|
||||||
|
|
||||||
|
func Interface2Float64(i interface{}) (float64, error) {
|
||||||
|
switch i.(type) {
|
||||||
|
case int:
|
||||||
|
return float64(i.(int)), nil
|
||||||
|
case int32:
|
||||||
|
return float64(i.(int32)), nil
|
||||||
|
case int64:
|
||||||
|
return float64(i.(int64)), nil
|
||||||
|
case float32:
|
||||||
|
return float64(i.(float32)), nil
|
||||||
|
case float64:
|
||||||
|
return i.(float64), nil
|
||||||
|
case string:
|
||||||
|
intVar, err := strconv.Atoi(i.(string))
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return float64(intVar), err
|
||||||
|
}
|
||||||
|
// json.Number
|
||||||
|
value, ok := i.(builtinJSON.Number)
|
||||||
|
if ok {
|
||||||
|
return value.Float64()
|
||||||
|
}
|
||||||
|
return 0, errors.New("failed to convert interface to float64")
|
||||||
|
}
|
||||||
|
|||||||
87
models.go
87
models.go
@@ -3,10 +3,12 @@ package hrp
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/httprunner/hrp/internal/builtin"
|
||||||
"github.com/httprunner/hrp/internal/version"
|
"github.com/httprunner/hrp/internal/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,13 +32,14 @@ type TConfig struct {
|
|||||||
Variables map[string]interface{} `json:"variables,omitempty" yaml:"variables,omitempty"`
|
Variables map[string]interface{} `json:"variables,omitempty" yaml:"variables,omitempty"`
|
||||||
Parameters map[string]interface{} `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
Parameters map[string]interface{} `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
||||||
ParametersSetting *TParamsConfig `json:"parameters_setting,omitempty" yaml:"parameters_setting,omitempty"`
|
ParametersSetting *TParamsConfig `json:"parameters_setting,omitempty" yaml:"parameters_setting,omitempty"`
|
||||||
|
ThinkTime *ThinkTimeConfig `json:"think_time,omitempty" yaml:"think_time,omitempty"`
|
||||||
Export []string `json:"export,omitempty" yaml:"export,omitempty"`
|
Export []string `json:"export,omitempty" yaml:"export,omitempty"`
|
||||||
Weight int `json:"weight,omitempty" yaml:"weight,omitempty"`
|
Weight int `json:"weight,omitempty" yaml:"weight,omitempty"`
|
||||||
Path string `json:"path,omitempty" yaml:"path,omitempty"` // testcase file path
|
Path string `json:"path,omitempty" yaml:"path,omitempty"` // testcase file path
|
||||||
}
|
}
|
||||||
|
|
||||||
type TParamsConfig struct {
|
type TParamsConfig struct {
|
||||||
Strategy interface{} `json:"strategy,omitempty" yaml:"strategy,omitempty"`
|
Strategy interface{} `json:"strategy,omitempty" yaml:"strategy,omitempty"` // map[string]string、string
|
||||||
Iteration int `json:"iteration,omitempty" yaml:"iteration,omitempty"`
|
Iteration int `json:"iteration,omitempty" yaml:"iteration,omitempty"`
|
||||||
Iterators []*Iterator `json:"parameterIterator,omitempty" yaml:"parameterIterator,omitempty"` // 保存参数的迭代器
|
Iterators []*Iterator `json:"parameterIterator,omitempty" yaml:"parameterIterator,omitempty"` // 保存参数的迭代器
|
||||||
}
|
}
|
||||||
@@ -46,6 +49,82 @@ const (
|
|||||||
strategySequential string = "Sequential"
|
strategySequential string = "Sequential"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ThinkTimeConfig struct {
|
||||||
|
Strategy string `json:"strategy,omitempty" yaml:"strategy,omitempty"` // default、random、limit、multiply、ignore
|
||||||
|
Setting interface{} `json:"setting,omitempty" yaml:"setting,omitempty"` // random(map): {"min_percentage": 0.5, "max_percentage": 1.5}; 10、multiply(float64): 1.5
|
||||||
|
Limit float64 `json:"limit,omitempty" yaml:"limit,omitempty"` // limit think time no more than specific time, ignore if value <= 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
thinkTimeDefault string = "default" // as recorded
|
||||||
|
thinkTimeRandomPercentage string = "random_percentage" // use random percentage of recorded think time
|
||||||
|
thinkTimeMultiply string = "multiply" // multiply recorded think time
|
||||||
|
thinkTimeIgnore string = "ignore" // ignore recorded think time
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
thinkTimeDefaultMultiply = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
thinkTimeDefaultRandom = map[string]float64{"min_percentage": 0.5, "max_percentage": 1.5}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (ttc *ThinkTimeConfig) checkThinkTime() {
|
||||||
|
if ttc == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// unset strategy, set default strategy
|
||||||
|
if ttc.Strategy == "" {
|
||||||
|
ttc.Strategy = thinkTimeDefault
|
||||||
|
}
|
||||||
|
// check think time
|
||||||
|
if ttc.Strategy == thinkTimeRandomPercentage {
|
||||||
|
if ttc.Setting == nil || reflect.TypeOf(ttc.Setting).Kind() != reflect.Map {
|
||||||
|
ttc.Setting = thinkTimeDefaultRandom
|
||||||
|
return
|
||||||
|
}
|
||||||
|
value, ok := ttc.Setting.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
ttc.Setting = thinkTimeDefaultRandom
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, ok := value["min_percentage"]; !ok {
|
||||||
|
ttc.Setting = thinkTimeDefaultRandom
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, ok := value["max_percentage"]; !ok {
|
||||||
|
ttc.Setting = thinkTimeDefaultRandom
|
||||||
|
return
|
||||||
|
}
|
||||||
|
left, err := builtin.Interface2Float64(value["min_percentage"])
|
||||||
|
if err != nil {
|
||||||
|
ttc.Setting = thinkTimeDefaultRandom
|
||||||
|
return
|
||||||
|
}
|
||||||
|
right, err := builtin.Interface2Float64(value["max_percentage"])
|
||||||
|
if err != nil {
|
||||||
|
ttc.Setting = thinkTimeDefaultRandom
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ttc.Setting = map[string]float64{"min_percentage": left, "max_percentage": right}
|
||||||
|
} else if ttc.Strategy == thinkTimeMultiply {
|
||||||
|
if ttc.Setting == nil {
|
||||||
|
ttc.Setting = float64(0) // default
|
||||||
|
return
|
||||||
|
}
|
||||||
|
value, err := builtin.Interface2Float64(ttc.Setting)
|
||||||
|
if err != nil {
|
||||||
|
ttc.Setting = float64(0) // default
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ttc.Setting = value
|
||||||
|
} else if ttc.Strategy != thinkTimeIgnore {
|
||||||
|
// unrecognized strategy, set default strategy
|
||||||
|
ttc.Strategy = thinkTimeDefault
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type paramsType []map[string]interface{}
|
type paramsType []map[string]interface{}
|
||||||
|
|
||||||
type Iterator struct {
|
type Iterator struct {
|
||||||
@@ -145,6 +224,7 @@ type TStep struct {
|
|||||||
TestCaseContent ITestCase `json:"testcase_content,omitempty" yaml:"testcase_content,omitempty"`
|
TestCaseContent ITestCase `json:"testcase_content,omitempty" yaml:"testcase_content,omitempty"`
|
||||||
Transaction *Transaction `json:"transaction,omitempty" yaml:"transaction,omitempty"`
|
Transaction *Transaction `json:"transaction,omitempty" yaml:"transaction,omitempty"`
|
||||||
Rendezvous *Rendezvous `json:"rendezvous,omitempty" yaml:"rendezvous,omitempty"`
|
Rendezvous *Rendezvous `json:"rendezvous,omitempty" yaml:"rendezvous,omitempty"`
|
||||||
|
ThinkTime *ThinkTime `json:"think_time,omitempty" yaml:"think_time,omitempty"`
|
||||||
Variables map[string]interface{} `json:"variables,omitempty" yaml:"variables,omitempty"`
|
Variables map[string]interface{} `json:"variables,omitempty" yaml:"variables,omitempty"`
|
||||||
SetupHooks []string `json:"setup_hooks,omitempty" yaml:"setup_hooks,omitempty"`
|
SetupHooks []string `json:"setup_hooks,omitempty" yaml:"setup_hooks,omitempty"`
|
||||||
TeardownHooks []string `json:"teardown_hooks,omitempty" yaml:"teardown_hooks,omitempty"`
|
TeardownHooks []string `json:"teardown_hooks,omitempty" yaml:"teardown_hooks,omitempty"`
|
||||||
@@ -160,8 +240,13 @@ const (
|
|||||||
stepTypeTestCase stepType = "testcase"
|
stepTypeTestCase stepType = "testcase"
|
||||||
stepTypeTransaction stepType = "transaction"
|
stepTypeTransaction stepType = "transaction"
|
||||||
stepTypeRendezvous stepType = "rendezvous"
|
stepTypeRendezvous stepType = "rendezvous"
|
||||||
|
stepTypeThinkTime stepType = "thinktime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ThinkTime struct {
|
||||||
|
Time float64 `json:"time" yaml:"time"`
|
||||||
|
}
|
||||||
|
|
||||||
type transactionType string
|
type transactionType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ func initPlugin(path string, logOn bool) (plugin funplugin.IPlugin, err error) {
|
|||||||
go func() {
|
go func() {
|
||||||
<-c
|
<-c
|
||||||
plugin.Quit()
|
plugin.Quit()
|
||||||
os.Exit(0)
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// report event for initializing plugin
|
// report event for initializing plugin
|
||||||
|
|||||||
54
runner.go
54
runner.go
@@ -297,13 +297,16 @@ func (r *caseRunner) run() error {
|
|||||||
func (r *caseRunner) runStep(index int, caseConfig *TConfig) (stepResult *stepData, err error) {
|
func (r *caseRunner) runStep(index int, caseConfig *TConfig) (stepResult *stepData, err error) {
|
||||||
step := r.TestCase.TestSteps[index]
|
step := r.TestCase.TestSteps[index]
|
||||||
|
|
||||||
// step type priority order: transaction > rendezvous > testcase > request
|
// step type priority order: transaction > rendezvous > thinktime > testcase > request
|
||||||
if stepTran, ok := step.(*StepTransaction); ok {
|
if stepTran, ok := step.(*StepTransaction); ok {
|
||||||
// transaction step
|
// transaction step
|
||||||
return r.runStepTransaction(stepTran.step.Transaction)
|
return r.runStepTransaction(stepTran.step.Transaction)
|
||||||
} else if stepRend, ok := step.(*StepRendezvous); ok {
|
} else if stepRend, ok := step.(*StepRendezvous); ok {
|
||||||
// rendezvous step
|
// rendezvous step
|
||||||
return r.runStepRendezvous(stepRend.step.Rendezvous)
|
return r.runStepRendezvous(stepRend.step.Rendezvous)
|
||||||
|
} else if stepThink, ok := step.(*StepThinkTime); ok {
|
||||||
|
// think time step
|
||||||
|
return r.runStepThinkTime(stepThink.step, caseConfig.ThinkTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info().Str("step", step.Name()).Msg("run step start")
|
log.Info().Str("step", step.Name()).Msg("run step start")
|
||||||
@@ -377,6 +380,52 @@ func (r *caseRunner) runStep(index int, caseConfig *TConfig) (stepResult *stepDa
|
|||||||
return stepResult, err
|
return stepResult, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *caseRunner) runStepThinkTime(step *TStep, ttc *ThinkTimeConfig) (stepResult *stepData, err error) {
|
||||||
|
thinkTime := step.ThinkTime
|
||||||
|
log.Info().
|
||||||
|
Str("name", step.Name).
|
||||||
|
Float64("time", thinkTime.Time).
|
||||||
|
Msg("think time")
|
||||||
|
stepResult = &stepData{
|
||||||
|
Name: step.Name,
|
||||||
|
StepType: stepTypeThinkTime,
|
||||||
|
Success: true,
|
||||||
|
}
|
||||||
|
if ttc == nil {
|
||||||
|
ttc = &ThinkTimeConfig{thinkTimeDefault, nil, 0}
|
||||||
|
}
|
||||||
|
var tt time.Duration
|
||||||
|
switch ttc.Strategy {
|
||||||
|
case thinkTimeDefault:
|
||||||
|
tt = time.Duration(thinkTime.Time*1000) * time.Millisecond
|
||||||
|
case thinkTimeRandomPercentage:
|
||||||
|
m, ok := ttc.Setting.(map[string]float64) // e.g. {"min_percentage": 0.5, "max_percentage": 1.5}
|
||||||
|
if !ok {
|
||||||
|
tt = time.Duration(thinkTime.Time*1000) * time.Millisecond
|
||||||
|
break
|
||||||
|
}
|
||||||
|
res := builtin.GetRandomNumber(int(thinkTime.Time*m["min_percentage"]*1000), int(thinkTime.Time*m["max_percentage"]*1000))
|
||||||
|
tt = time.Duration(res) * time.Millisecond
|
||||||
|
case thinkTimeMultiply:
|
||||||
|
value, ok := ttc.Setting.(float64) // e.g. 0.5
|
||||||
|
if !ok || value <= 0 {
|
||||||
|
value = thinkTimeDefaultMultiply
|
||||||
|
}
|
||||||
|
tt = time.Duration(thinkTime.Time*value*1000) * time.Millisecond
|
||||||
|
case thinkTimeIgnore:
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
// no more than limit
|
||||||
|
if ttc.Limit > 0 {
|
||||||
|
limit := time.Duration(ttc.Limit*1000) * time.Millisecond
|
||||||
|
if limit < tt {
|
||||||
|
tt = limit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
time.Sleep(tt)
|
||||||
|
return stepResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *caseRunner) runStepTransaction(transaction *Transaction) (stepResult *stepData, err error) {
|
func (r *caseRunner) runStepTransaction(transaction *Transaction) (stepResult *stepData, err error) {
|
||||||
log.Info().
|
log.Info().
|
||||||
Str("name", transaction.Name).
|
Str("name", transaction.Name).
|
||||||
@@ -966,6 +1015,9 @@ func (r *caseRunner) parseConfig(cfg *TConfig) error {
|
|||||||
}
|
}
|
||||||
cfg.BaseURL = convertString(parsedBaseURL)
|
cfg.BaseURL = convertString(parsedBaseURL)
|
||||||
|
|
||||||
|
// ensure correction of think time config
|
||||||
|
cfg.ThinkTime.checkThinkTime()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
@@ -146,6 +147,63 @@ func TestInitRendezvous(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestThinkTime(t *testing.T) {
|
||||||
|
buildHashicorpPlugin()
|
||||||
|
defer removeHashicorpPlugin()
|
||||||
|
|
||||||
|
testcases := []*TestCase{
|
||||||
|
{
|
||||||
|
Config: NewConfig("TestCase1"),
|
||||||
|
TestSteps: []IStep{
|
||||||
|
NewStep("thinkTime").SetThinkTime(2),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Config: NewConfig("TestCase2").
|
||||||
|
SetThinkTime(thinkTimeIgnore, nil, 0),
|
||||||
|
TestSteps: []IStep{
|
||||||
|
NewStep("thinkTime").SetThinkTime(0.5),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Config: NewConfig("TestCase3").
|
||||||
|
SetThinkTime(thinkTimeRandomPercentage, nil, 0),
|
||||||
|
TestSteps: []IStep{
|
||||||
|
NewStep("thinkTime").SetThinkTime(1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Config: NewConfig("TestCase4").
|
||||||
|
SetThinkTime(thinkTimeRandomPercentage, map[string]interface{}{"min_percentage": 2, "max_percentage": 3}, 2.5),
|
||||||
|
TestSteps: []IStep{
|
||||||
|
NewStep("thinkTime").SetThinkTime(1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Config: NewConfig("TestCase5"),
|
||||||
|
TestSteps: []IStep{
|
||||||
|
NewStep("thinkTime").CallRefCase(&demoThinkTimeJsonPath), // think time: 3s, random pct: {"min_percentage":1, "max_percentage":1.5}, limit: 4s
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
expectedMinValue := []float64{2, 0, 0.5, 2, 3}
|
||||||
|
expectedMaxValue := []float64{2.5, 0.5, 2, 3, 10}
|
||||||
|
for idx, testcase := range testcases {
|
||||||
|
r := NewRunner(t)
|
||||||
|
startTime := time.Now()
|
||||||
|
err := r.Run(testcase)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("run testcase error: %v", err)
|
||||||
|
}
|
||||||
|
duration := time.Since(startTime)
|
||||||
|
minValue := time.Duration(expectedMinValue[idx]*1000) * time.Millisecond
|
||||||
|
maxValue := time.Duration(expectedMaxValue[idx]*1000) * time.Millisecond
|
||||||
|
if duration < minValue || duration > maxValue {
|
||||||
|
t.Fatalf("failed to test think time, expect value: [%v, %v], actual value: %v", minValue, maxValue, duration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGenHTMLReport(t *testing.T) {
|
func TestGenHTMLReport(t *testing.T) {
|
||||||
summary := newOutSummary()
|
summary := newOutSummary()
|
||||||
caseSummary1 := newSummary()
|
caseSummary1 := newSummary()
|
||||||
|
|||||||
33
step.go
33
step.go
@@ -40,6 +40,12 @@ func (c *TConfig) WithParameters(parameters map[string]interface{}) *TConfig {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetThinkTime sets think time config for current testcase.
|
||||||
|
func (c *TConfig) SetThinkTime(strategy string, cfg interface{}, limit float64) *TConfig {
|
||||||
|
c.ThinkTime = &ThinkTimeConfig{strategy, cfg, limit}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
// ExportVars specifies variable names to export for current testcase.
|
// ExportVars specifies variable names to export for current testcase.
|
||||||
func (c *TConfig) ExportVars(vars ...string) *TConfig {
|
func (c *TConfig) ExportVars(vars ...string) *TConfig {
|
||||||
c.Export = vars
|
c.Export = vars
|
||||||
@@ -193,6 +199,16 @@ func (s *StepRequest) EndTransaction(name string) *StepTransaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetThinkTime sets think time.
|
||||||
|
func (s *StepRequest) SetThinkTime(time float64) *StepThinkTime {
|
||||||
|
s.step.ThinkTime = &ThinkTime{
|
||||||
|
Time: time,
|
||||||
|
}
|
||||||
|
return &StepThinkTime{
|
||||||
|
step: s.step,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// StepRequestWithOptionalArgs implements IStep interface.
|
// StepRequestWithOptionalArgs implements IStep interface.
|
||||||
type StepRequestWithOptionalArgs struct {
|
type StepRequestWithOptionalArgs struct {
|
||||||
step *TStep
|
step *TStep
|
||||||
@@ -355,6 +371,23 @@ func (s *StepTestCaseWithOptionalArgs) ToStruct() *TStep {
|
|||||||
return s.step
|
return s.step
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StepThinkTime implements IStep interface.
|
||||||
|
type StepThinkTime struct {
|
||||||
|
step *TStep
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepThinkTime) Name() string {
|
||||||
|
return s.step.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepThinkTime) Type() string {
|
||||||
|
return "thinktime"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepThinkTime) ToStruct() *TStep {
|
||||||
|
return s.step
|
||||||
|
}
|
||||||
|
|
||||||
// StepTransaction implements IStep interface.
|
// StepTransaction implements IStep interface.
|
||||||
type StepTransaction struct {
|
type StepTransaction struct {
|
||||||
step *TStep
|
step *TStep
|
||||||
|
|||||||
Reference in New Issue
Block a user