mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-06 20:32:44 +08:00
refactor: move tests
This commit is contained in:
4
build.go
4
build.go
@@ -10,11 +10,11 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/httprunner/funplugin/fungo"
|
||||
"github.com/httprunner/funplugin/myexec"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/httprunner/funplugin/fungo"
|
||||
"github.com/httprunner/funplugin/myexec"
|
||||
"github.com/httprunner/httprunner/v5/code"
|
||||
"github.com/httprunner/httprunner/v5/internal/builtin"
|
||||
"github.com/httprunner/httprunner/v5/internal/config"
|
||||
|
||||
141
build_test.go
141
build_test.go
@@ -1,141 +0,0 @@
|
||||
package hrp
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRun(t *testing.T) {
|
||||
err := BuildPlugin(tmpl("plugin/debugtalk.go"), "./debugtalk.bin")
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
genDebugTalkPyPath := filepath.Join(tmpl("plugin/"), PluginPySourceGenFile)
|
||||
err = BuildPlugin(tmpl("plugin/debugtalk.py"), genDebugTalkPyPath)
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
contentBytes, err := readFile(genDebugTalkPyPath)
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
content := string(contentBytes)
|
||||
if !assert.Contains(t, content, "import funppy") {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
if !assert.Contains(t, content, "funppy.register") {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
reg, _ := regexp.Compile(`funppy\.register`)
|
||||
matchedSlice := reg.FindAllStringSubmatch(content, -1)
|
||||
if !assert.Len(t, matchedSlice, 10) {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
|
||||
func TestFindAllPythonFunctionNames(t *testing.T) {
|
||||
content := `
|
||||
def test_1(): # exported function
|
||||
pass
|
||||
|
||||
def _test_2(): # exported function
|
||||
pass
|
||||
|
||||
def __test_3(): # private function
|
||||
pass
|
||||
|
||||
# def test_4(): # commented out function
|
||||
# pass
|
||||
|
||||
def Test5(): # exported function
|
||||
pass
|
||||
`
|
||||
names, err := regexPyFunctionName.findAllFunctionNames(content)
|
||||
if !assert.Nil(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.Contains(t, names, "test_1") {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.Contains(t, names, "Test5") {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.Contains(t, names, "_test_2") {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.NotContains(t, names, "__test_3") {
|
||||
t.FailNow()
|
||||
}
|
||||
// commented out function
|
||||
if !assert.NotContains(t, names, "test_4") {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func TestFindAllGoFunctionNames(t *testing.T) {
|
||||
content := `
|
||||
func Test1() { // exported function
|
||||
return
|
||||
}
|
||||
|
||||
func testFunc2() { // exported function
|
||||
return
|
||||
}
|
||||
|
||||
func init() { // private function
|
||||
return
|
||||
}
|
||||
|
||||
func _Test3() { // exported function
|
||||
return
|
||||
}
|
||||
|
||||
// func Test4() { // commented out function
|
||||
// return
|
||||
// }
|
||||
`
|
||||
names, err := regexGoFunctionName.findAllFunctionNames(content)
|
||||
if !assert.Nil(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.Contains(t, names, "Test1") {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.Contains(t, names, "testFunc2") {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.NotContains(t, names, "init") {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.Contains(t, names, "_Test3") {
|
||||
t.FailNow()
|
||||
}
|
||||
// commented out function
|
||||
if !assert.NotContains(t, names, "Test4") {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func TestFindAllGoFunctionNamesAbnormal(t *testing.T) {
|
||||
content := `
|
||||
func init() { // private function
|
||||
return
|
||||
}
|
||||
|
||||
func main() { // should not define main() function
|
||||
return
|
||||
}
|
||||
`
|
||||
_, err := regexGoFunctionName.findAllFunctionNames(content)
|
||||
if !assert.NotNil(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
24
config.go
24
config.go
@@ -80,7 +80,7 @@ func (c *TConfig) WithParameters(parameters map[string]interface{}) *TConfig {
|
||||
}
|
||||
|
||||
// SetThinkTime sets think time config for current testcase.
|
||||
func (c *TConfig) SetThinkTime(strategy thinkTimeStrategy, cfg interface{}, limit float64) *TConfig {
|
||||
func (c *TConfig) SetThinkTime(strategy ThinkTimeStrategy, cfg interface{}, limit float64) *TConfig {
|
||||
c.ThinkTimeSetting = &ThinkTimeConfig{strategy, cfg, limit}
|
||||
return c
|
||||
}
|
||||
@@ -194,7 +194,7 @@ func (c *TConfig) DisableAutoPopupHandler() *TConfig {
|
||||
}
|
||||
|
||||
type ThinkTimeConfig struct {
|
||||
Strategy thinkTimeStrategy `json:"strategy,omitempty" yaml:"strategy,omitempty"` // default、random、multiply、ignore
|
||||
Strategy ThinkTimeStrategy `json:"strategy,omitempty" yaml:"strategy,omitempty"` // default、random、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
|
||||
}
|
||||
@@ -205,10 +205,10 @@ func (ttc *ThinkTimeConfig) checkThinkTime() {
|
||||
}
|
||||
// unset strategy, set default strategy
|
||||
if ttc.Strategy == "" {
|
||||
ttc.Strategy = thinkTimeDefault
|
||||
ttc.Strategy = ThinkTimeDefault
|
||||
}
|
||||
// check think time
|
||||
if ttc.Strategy == thinkTimeRandomPercentage {
|
||||
if ttc.Strategy == ThinkTimeRandomPercentage {
|
||||
if ttc.Setting == nil || reflect.TypeOf(ttc.Setting).Kind() != reflect.Map {
|
||||
ttc.Setting = thinkTimeDefaultRandom
|
||||
return
|
||||
@@ -237,7 +237,7 @@ func (ttc *ThinkTimeConfig) checkThinkTime() {
|
||||
return
|
||||
}
|
||||
ttc.Setting = map[string]float64{"min_percentage": left, "max_percentage": right}
|
||||
} else if ttc.Strategy == thinkTimeMultiply {
|
||||
} else if ttc.Strategy == ThinkTimeMultiply {
|
||||
if ttc.Setting == nil {
|
||||
ttc.Setting = float64(0) // default
|
||||
return
|
||||
@@ -248,19 +248,19 @@ func (ttc *ThinkTimeConfig) checkThinkTime() {
|
||||
return
|
||||
}
|
||||
ttc.Setting = value
|
||||
} else if ttc.Strategy != thinkTimeIgnore {
|
||||
} else if ttc.Strategy != ThinkTimeIgnore {
|
||||
// unrecognized strategy, set default strategy
|
||||
ttc.Strategy = thinkTimeDefault
|
||||
ttc.Strategy = ThinkTimeDefault
|
||||
}
|
||||
}
|
||||
|
||||
type thinkTimeStrategy string
|
||||
type ThinkTimeStrategy string
|
||||
|
||||
const (
|
||||
thinkTimeDefault thinkTimeStrategy = "default" // as recorded
|
||||
thinkTimeRandomPercentage thinkTimeStrategy = "random_percentage" // use random percentage of recorded think time
|
||||
thinkTimeMultiply thinkTimeStrategy = "multiply" // multiply recorded think time
|
||||
thinkTimeIgnore thinkTimeStrategy = "ignore" // ignore recorded think time
|
||||
ThinkTimeDefault ThinkTimeStrategy = "default" // as recorded
|
||||
ThinkTimeRandomPercentage ThinkTimeStrategy = "random_percentage" // use random percentage of recorded think time
|
||||
ThinkTimeMultiply ThinkTimeStrategy = "multiply" // multiply recorded think time
|
||||
ThinkTimeIgnore ThinkTimeStrategy = "ignore" // ignore recorded think time
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -225,6 +225,22 @@ func InterfaceType(raw interface{}) string {
|
||||
return reflect.TypeOf(raw).String()
|
||||
}
|
||||
|
||||
func LoadFile(path string) ([]byte, error) {
|
||||
var err error
|
||||
path, err = filepath.Abs(path)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("path", path).Msg("convert absolute path failed")
|
||||
return nil, errors.Wrap(code.LoadFileError, err.Error())
|
||||
}
|
||||
|
||||
file, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("read file failed")
|
||||
return nil, errors.Wrap(code.LoadFileError, err.Error())
|
||||
}
|
||||
return file, nil
|
||||
}
|
||||
|
||||
func loadFromCSV(path string) []map[string]interface{} {
|
||||
log.Info().Str("path", path).Msg("load csv file")
|
||||
file, err := os.ReadFile(path)
|
||||
|
||||
@@ -1 +1 @@
|
||||
v5.0.0+2503051104
|
||||
v5.0.0+2503051147
|
||||
|
||||
19
loader.go
19
loader.go
@@ -12,6 +12,7 @@ import (
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/httprunner/httprunner/v5/code"
|
||||
"github.com/httprunner/httprunner/v5/internal/builtin"
|
||||
"github.com/httprunner/httprunner/v5/internal/json"
|
||||
)
|
||||
|
||||
@@ -85,7 +86,7 @@ func LoadTestCases(tests ...ITestCase) ([]*TestCase, error) {
|
||||
// LoadFileObject loads file content with file extension and assigns to structObj
|
||||
func LoadFileObject(path string, structObj interface{}) (err error) {
|
||||
log.Info().Str("path", path).Msg("load file")
|
||||
file, err := readFile(path)
|
||||
file, err := builtin.LoadFile(path)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "read file failed")
|
||||
}
|
||||
@@ -145,19 +146,3 @@ func parseEnvContent(file []byte, obj interface{}) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func readFile(path string) ([]byte, error) {
|
||||
var err error
|
||||
path, err = filepath.Abs(path)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("path", path).Msg("convert absolute path failed")
|
||||
return nil, errors.Wrap(code.LoadFileError, err.Error())
|
||||
}
|
||||
|
||||
file, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("read file failed")
|
||||
return nil, errors.Wrap(code.LoadFileError, err.Error())
|
||||
}
|
||||
return file, nil
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
|
||||
type TParamsConfig struct {
|
||||
PickOrder iteratorPickOrder `json:"pick_order,omitempty" yaml:"pick_order,omitempty"` // overall pick-order strategy
|
||||
Strategies map[string]iteratorStrategy `json:"strategies,omitempty" yaml:"strategies,omitempty"` // individual strategies for each parameters
|
||||
Strategies map[string]IteratorStrategy `json:"strategies,omitempty" yaml:"strategies,omitempty"` // individual strategies for each parameters
|
||||
Limit int `json:"limit,omitempty" yaml:"limit,omitempty"`
|
||||
}
|
||||
|
||||
@@ -35,13 +35,13 @@ const (
|
||||
*/
|
||||
type Parameters []map[string]interface{}
|
||||
|
||||
type iteratorStrategy struct {
|
||||
type IteratorStrategy struct {
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
PickOrder iteratorPickOrder `json:"pick_order,omitempty" yaml:"pick_order,omitempty"`
|
||||
}
|
||||
|
||||
func (p *Parser) initParametersIterator(cfg *TConfig) (*ParametersIterator, error) {
|
||||
parameters, err := p.loadParameters(cfg.Parameters, cfg.Variables)
|
||||
func (p *Parser) InitParametersIterator(cfg *TConfig) (*ParametersIterator, error) {
|
||||
parameters, err := p.LoadParameters(cfg.Parameters, cfg.Variables)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -57,13 +57,13 @@ func newParametersIterator(parameters map[string]Parameters, config *TParamsConf
|
||||
hasNext: true,
|
||||
sequentialParameters: nil,
|
||||
randomParameterNames: nil,
|
||||
limit: config.Limit,
|
||||
index: 0,
|
||||
Limit: config.Limit,
|
||||
Index: 0,
|
||||
}
|
||||
|
||||
if len(parameters) == 0 {
|
||||
iterator.data = map[string]Parameters{}
|
||||
iterator.limit = 1
|
||||
iterator.Limit = 1
|
||||
return iterator
|
||||
}
|
||||
|
||||
@@ -85,24 +85,24 @@ func newParametersIterator(parameters map[string]Parameters, config *TParamsConf
|
||||
}
|
||||
|
||||
// generate cartesian product for sequential parameters
|
||||
iterator.sequentialParameters = genCartesianProduct(parametersList)
|
||||
iterator.sequentialParameters = GenCartesianProduct(parametersList)
|
||||
|
||||
if iterator.limit < 0 {
|
||||
if iterator.Limit < 0 {
|
||||
log.Warn().Msg("parameters unlimited mode is only supported for load testing")
|
||||
iterator.limit = 0
|
||||
iterator.Limit = 0
|
||||
}
|
||||
if iterator.limit == 0 {
|
||||
if iterator.Limit == 0 {
|
||||
// limit not set
|
||||
if len(iterator.sequentialParameters) > 0 {
|
||||
// use cartesian product of sequential parameters size as limit
|
||||
iterator.limit = len(iterator.sequentialParameters)
|
||||
iterator.Limit = len(iterator.sequentialParameters)
|
||||
} else {
|
||||
// all parameters are selected by random
|
||||
// only run once
|
||||
iterator.limit = 1
|
||||
iterator.Limit = 1
|
||||
}
|
||||
} else { // limit > 0
|
||||
log.Info().Int("limit", iterator.limit).Msg("set limit for parameters")
|
||||
log.Info().Int("limit", iterator.Limit).Msg("set limit for parameters")
|
||||
}
|
||||
|
||||
return iterator
|
||||
@@ -114,14 +114,14 @@ type ParametersIterator struct {
|
||||
hasNext bool // cache query result
|
||||
sequentialParameters Parameters // cartesian product for sequential parameters
|
||||
randomParameterNames []string // value is parameter names
|
||||
limit int // limit count for iteration
|
||||
index int // current iteration index
|
||||
Limit int // limit count for iteration
|
||||
Index int // current iteration index
|
||||
}
|
||||
|
||||
// SetUnlimitedMode is used for load testing
|
||||
func (iter *ParametersIterator) SetUnlimitedMode() {
|
||||
log.Info().Msg("set parameters unlimited mode")
|
||||
iter.limit = -1
|
||||
iter.Limit = -1
|
||||
}
|
||||
|
||||
func (iter *ParametersIterator) HasNext() bool {
|
||||
@@ -130,12 +130,12 @@ func (iter *ParametersIterator) HasNext() bool {
|
||||
}
|
||||
|
||||
// unlimited mode
|
||||
if iter.limit == -1 {
|
||||
if iter.Limit == -1 {
|
||||
return true
|
||||
}
|
||||
|
||||
// reached limit
|
||||
if iter.index >= iter.limit {
|
||||
if iter.Index >= iter.Limit {
|
||||
// cache query result
|
||||
iter.hasNext = false
|
||||
return false
|
||||
@@ -155,11 +155,11 @@ func (iter *ParametersIterator) Next() map[string]interface{} {
|
||||
var selectedParameters map[string]interface{}
|
||||
if len(iter.sequentialParameters) == 0 {
|
||||
selectedParameters = make(map[string]interface{})
|
||||
} else if iter.index < len(iter.sequentialParameters) {
|
||||
selectedParameters = iter.sequentialParameters[iter.index]
|
||||
} else if iter.Index < len(iter.sequentialParameters) {
|
||||
selectedParameters = iter.sequentialParameters[iter.Index]
|
||||
} else {
|
||||
// loop back to the first sequential parameter
|
||||
index := iter.index % len(iter.sequentialParameters)
|
||||
index := iter.Index % len(iter.sequentialParameters)
|
||||
selectedParameters = iter.sequentialParameters[index]
|
||||
}
|
||||
|
||||
@@ -172,8 +172,8 @@ func (iter *ParametersIterator) Next() map[string]interface{} {
|
||||
}
|
||||
}
|
||||
|
||||
iter.index++
|
||||
if iter.limit > 0 && iter.index >= iter.limit {
|
||||
iter.Index++
|
||||
if iter.Limit > 0 && iter.Index >= iter.Limit {
|
||||
iter.hasNext = false
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ func (iter *ParametersIterator) Data() map[string]interface{} {
|
||||
return res
|
||||
}
|
||||
|
||||
func genCartesianProduct(multiParameters []Parameters) Parameters {
|
||||
func GenCartesianProduct(multiParameters []Parameters) Parameters {
|
||||
if len(multiParameters) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -208,7 +208,7 @@ func genCartesianProduct(multiParameters []Parameters) Parameters {
|
||||
}
|
||||
|
||||
/*
|
||||
loadParameters loads parameters from multiple sources.
|
||||
LoadParameters loads parameters from multiple sources.
|
||||
|
||||
parameter value may be in three types:
|
||||
|
||||
@@ -240,7 +240,7 @@ parameter value may be in three types:
|
||||
]
|
||||
}
|
||||
*/
|
||||
func (p *Parser) loadParameters(configParameters map[string]interface{}, variablesMapping map[string]interface{}) (
|
||||
func (p *Parser) LoadParameters(configParameters map[string]interface{}, variablesMapping map[string]interface{}) (
|
||||
map[string]Parameters, error) {
|
||||
|
||||
if len(configParameters) == 0 {
|
||||
@@ -291,7 +291,7 @@ func (p *Parser) loadParameters(configParameters map[string]interface{}, variabl
|
||||
return nil, errors.New("config parameters raw value format error")
|
||||
}
|
||||
|
||||
parameterSlice, err := convertParameters(k, parametersRawList)
|
||||
parameterSlice, err := ConvertParameters(k, parametersRawList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -320,7 +320,7 @@ case 3:
|
||||
key = "username-password"
|
||||
parametersRawList = [["test1", "111111"], ["test2", "222222"]]
|
||||
*/
|
||||
func convertParameters(key string, parametersRawList interface{}) (parameterSlice []map[string]interface{}, err error) {
|
||||
func ConvertParameters(key string, parametersRawList interface{}) (parameterSlice []map[string]interface{}, err error) {
|
||||
parametersRawSlice := reflect.ValueOf(parametersRawList)
|
||||
if parametersRawSlice.Kind() != reflect.Slice {
|
||||
return nil, errors.New("parameters raw value is not list")
|
||||
|
||||
@@ -10,17 +10,17 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/httprunner/funplugin"
|
||||
"github.com/httprunner/funplugin/fungo"
|
||||
"github.com/maja42/goval"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/httprunner/funplugin"
|
||||
"github.com/httprunner/funplugin/fungo"
|
||||
"github.com/httprunner/httprunner/v5/code"
|
||||
"github.com/httprunner/httprunner/v5/internal/builtin"
|
||||
)
|
||||
|
||||
func newParser() *Parser {
|
||||
func NewParser() *Parser {
|
||||
return &Parser{}
|
||||
}
|
||||
|
||||
|
||||
211
parser_test.go
211
parser_test.go
@@ -1,8 +1,11 @@
|
||||
package hrp
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -208,7 +211,7 @@ func TestParseDataStringWithVariables(t *testing.T) {
|
||||
{"abc$var_5", "abctrue"}, // "abcTrue"
|
||||
}
|
||||
|
||||
parser := newParser()
|
||||
parser := NewParser()
|
||||
for _, data := range testData {
|
||||
parsedData, err := parser.Parse(data.expr, variablesMapping)
|
||||
if !assert.NoError(t, err) {
|
||||
@@ -233,7 +236,7 @@ func TestParseDataStringWithUndefinedVariables(t *testing.T) {
|
||||
{"/api/$SECRET_KEY", "/api/$SECRET_KEY"}, // raise error
|
||||
}
|
||||
|
||||
parser := newParser()
|
||||
parser := NewParser()
|
||||
for _, data := range testData {
|
||||
parsedData, err := parser.Parse(data.expr, variablesMapping)
|
||||
if !assert.Error(t, err) {
|
||||
@@ -278,7 +281,7 @@ func TestParseDataStringWithVariablesAbnormal(t *testing.T) {
|
||||
{"ABC$var_1{}a", "ABCabc{}a"}, // {}
|
||||
}
|
||||
|
||||
parser := newParser()
|
||||
parser := NewParser()
|
||||
for _, data := range testData {
|
||||
parsedData, err := parser.Parse(data.expr, variablesMapping)
|
||||
if !assert.NoError(t, err) {
|
||||
@@ -309,7 +312,7 @@ func TestParseDataMapWithVariables(t *testing.T) {
|
||||
{map[string]interface{}{"$var2": "$val1"}, map[string]interface{}{"123": 200}},
|
||||
}
|
||||
|
||||
parser := newParser()
|
||||
parser := NewParser()
|
||||
for _, data := range testData {
|
||||
parsedData, err := parser.Parse(data.expr, variablesMapping)
|
||||
if !assert.NoError(t, err) {
|
||||
@@ -343,7 +346,7 @@ func TestParseHeaders(t *testing.T) {
|
||||
{map[string]string{"$var2": "$val2"}, map[string]string{"123": "<nil>"}},
|
||||
}
|
||||
|
||||
parser := newParser()
|
||||
parser := NewParser()
|
||||
for _, data := range testData {
|
||||
parsedHeaders, err := parser.ParseHeaders(data.rawHeaders, variablesMapping)
|
||||
if !assert.NoError(t, err) {
|
||||
@@ -488,7 +491,7 @@ func TestMergeValidators(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCallBuiltinFunction(t *testing.T) {
|
||||
parser := newParser()
|
||||
parser := NewParser()
|
||||
|
||||
// call function without arguments
|
||||
_, err := parser.callFunc("get_timestamp")
|
||||
@@ -601,7 +604,7 @@ func TestParseDataStringWithFunctions(t *testing.T) {
|
||||
{"123${gen_random_string($n)}abc", 11},
|
||||
}
|
||||
|
||||
parser := newParser()
|
||||
parser := NewParser()
|
||||
for _, data := range testData1 {
|
||||
value, err := parser.Parse(data.expr, variablesMapping)
|
||||
if !assert.NoError(t, err) {
|
||||
@@ -670,7 +673,7 @@ func TestParseVariables(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
parser := newParser()
|
||||
parser := NewParser()
|
||||
for _, data := range testData {
|
||||
value, err := parser.ParseVariables(data.rawVars)
|
||||
if !assert.NoError(t, err) {
|
||||
@@ -701,7 +704,7 @@ func TestParseVariablesAbnormal(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
parser := newParser()
|
||||
parser := NewParser()
|
||||
for _, data := range testData {
|
||||
value, err := parser.ParseVariables(data.rawVars)
|
||||
if !assert.Error(t, err) {
|
||||
@@ -784,3 +787,193 @@ func TestFindallVariables(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchJmespath(t *testing.T) {
|
||||
testText := `{"a": {"b": "foo"}, "c": "bar", "d": {"e": [{"f": "foo"}, {"f": "bar"}]}}`
|
||||
testData := []struct {
|
||||
raw string
|
||||
expected string
|
||||
}{
|
||||
{"body.a.b", "foo"},
|
||||
{"body.c", "bar"},
|
||||
{"body.d.e[0].f", "foo"},
|
||||
{"body.d.e[1].f", "bar"},
|
||||
}
|
||||
resp := http.Response{}
|
||||
resp.Body = io.NopCloser(strings.NewReader(testText))
|
||||
respObj, err := newHttpResponseObject(t, NewParser(), &resp)
|
||||
if err != nil {
|
||||
t.Fatal()
|
||||
}
|
||||
for _, data := range testData {
|
||||
if !assert.Equal(t, data.expected, respObj.searchJmespath(data.raw)) {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchRegexp(t *testing.T) {
|
||||
testText := `
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a href="/order/addToCart" style="color: white"><i class="fa fa-shopping-cart fa-2x"></i><span class="badge">0</span></a></li>
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#" style="color: white">
|
||||
Leo <i class="fa fa-cog fa-2x"></i><span class="caret"></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="/user/changePassword">Change Password</a></li>
|
||||
<li><a href="/user/addAddress">Shipping</a></li>
|
||||
<li><a href="/user/addCard">Payment</a></li>
|
||||
<li><a href="/order/orderHistory">Order History</a></li>
|
||||
<li><a href="/user/signOut">Sign Out</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li> </li>
|
||||
<li><a href="/user/signOut" style="color: white"><i class="fa fa-sign-out fa-2x"></i>
|
||||
Sign Out</a></li>
|
||||
</ul>
|
||||
`
|
||||
testData := []struct {
|
||||
raw string
|
||||
expected string
|
||||
}{
|
||||
{"/user/signOut\">(.*)</a></li>", "Sign Out"},
|
||||
{"<li><a href=\"/user/(.*)\" style", "signOut"},
|
||||
{" (.*) <i class=\"fa fa-cog fa-2x\"></i>", "Leo"},
|
||||
}
|
||||
// new response object
|
||||
resp := http.Response{}
|
||||
resp.Body = io.NopCloser(strings.NewReader(testText))
|
||||
respObj, err := newHttpResponseObject(t, NewParser(), &resp)
|
||||
if err != nil {
|
||||
t.Fatal()
|
||||
}
|
||||
for _, data := range testData {
|
||||
if !assert.Equal(t, data.expected, respObj.searchRegexp(data.raw)) {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertCheckExpr(t *testing.T) {
|
||||
exprs := []struct {
|
||||
before string
|
||||
after string
|
||||
}{
|
||||
// normal check expression
|
||||
{"a.b.c", "a.b.c"},
|
||||
{"a.\"b-c\".d", "a.\"b-c\".d"},
|
||||
{"a.b-c.d", "a.b-c.d"},
|
||||
{"body.args.a[-1]", "body.args.a[-1]"},
|
||||
// check expression using regex
|
||||
{"covering (.*) testing,", "covering (.*) testing,"},
|
||||
{" (.*) a-b-c", " (.*) a-b-c"},
|
||||
// abnormal check expression
|
||||
{"headers.Content-Type", "headers.\"Content-Type\""},
|
||||
{"headers.\"Content-Type", "headers.\"Content-Type\""},
|
||||
{"headers.Content-Type\"", "headers.\"Content-Type\""},
|
||||
{"headers.User-Agent", "headers.\"User-Agent\""},
|
||||
}
|
||||
for _, expr := range exprs {
|
||||
assert.Equal(t, expr.after, convertJmespathExpr(expr.before))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFindAllPythonFunctionNames(t *testing.T) {
|
||||
content := `
|
||||
def test_1(): # exported function
|
||||
pass
|
||||
|
||||
def _test_2(): # exported function
|
||||
pass
|
||||
|
||||
def __test_3(): # private function
|
||||
pass
|
||||
|
||||
# def test_4(): # commented out function
|
||||
# pass
|
||||
|
||||
def Test5(): # exported function
|
||||
pass
|
||||
`
|
||||
names, err := regexPyFunctionName.findAllFunctionNames(content)
|
||||
if !assert.Nil(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.Contains(t, names, "test_1") {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.Contains(t, names, "Test5") {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.Contains(t, names, "_test_2") {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.NotContains(t, names, "__test_3") {
|
||||
t.FailNow()
|
||||
}
|
||||
// commented out function
|
||||
if !assert.NotContains(t, names, "test_4") {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func TestFindAllGoFunctionNames(t *testing.T) {
|
||||
content := `
|
||||
func Test1() { // exported function
|
||||
return
|
||||
}
|
||||
|
||||
func testFunc2() { // exported function
|
||||
return
|
||||
}
|
||||
|
||||
func init() { // private function
|
||||
return
|
||||
}
|
||||
|
||||
func _Test3() { // exported function
|
||||
return
|
||||
}
|
||||
|
||||
// func Test4() { // commented out function
|
||||
// return
|
||||
// }
|
||||
`
|
||||
names, err := regexGoFunctionName.findAllFunctionNames(content)
|
||||
if !assert.Nil(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.Contains(t, names, "Test1") {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.Contains(t, names, "testFunc2") {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.NotContains(t, names, "init") {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.Contains(t, names, "_Test3") {
|
||||
t.FailNow()
|
||||
}
|
||||
// commented out function
|
||||
if !assert.NotContains(t, names, "Test4") {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func TestFindAllGoFunctionNamesAbnormal(t *testing.T) {
|
||||
content := `
|
||||
func init() { // private function
|
||||
return
|
||||
}
|
||||
|
||||
func main() { // should not define main() function
|
||||
return
|
||||
}
|
||||
`
|
||||
_, err := regexGoFunctionName.findAllFunctionNames(content)
|
||||
if !assert.NotNil(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
24
plugin.go
24
plugin.go
@@ -6,11 +6,11 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/httprunner/funplugin"
|
||||
"github.com/httprunner/funplugin/myexec"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/httprunner/funplugin"
|
||||
"github.com/httprunner/funplugin/myexec"
|
||||
"github.com/httprunner/httprunner/v5/code"
|
||||
"github.com/httprunner/httprunner/v5/internal/config"
|
||||
"github.com/httprunner/httprunner/v5/internal/sdk"
|
||||
@@ -39,7 +39,7 @@ func initPlugin(path, venv string, logOn bool) (plugin funplugin.IPlugin, err er
|
||||
if path == "" {
|
||||
return nil, nil
|
||||
}
|
||||
pluginPath, err := locatePlugin(path)
|
||||
pluginPath, err := LocatePlugin(path)
|
||||
if err != nil {
|
||||
log.Warn().Str("path", path).Msg("locate plugin failed")
|
||||
return nil, nil
|
||||
@@ -100,21 +100,21 @@ func initPlugin(path, venv string, logOn bool) (plugin funplugin.IPlugin, err er
|
||||
return
|
||||
}
|
||||
|
||||
func locatePlugin(path string) (pluginPath string, err error) {
|
||||
func LocatePlugin(path string) (pluginPath string, err error) {
|
||||
log.Info().Str("path", path).Msg("locate plugin")
|
||||
// priority: hashicorp plugin (debugtalk.bin > debugtalk.py) > go plugin (debugtalk.so)
|
||||
|
||||
pluginPath, err = locateFile(path, PluginHashicorpGoBuiltFile)
|
||||
pluginPath, err = LocateFile(path, PluginHashicorpGoBuiltFile)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
pluginPath, err = locateFile(path, PluginPySourceFile)
|
||||
pluginPath, err = LocateFile(path, PluginPySourceFile)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
pluginPath, err = locateFile(path, PluginGoBuiltFile)
|
||||
pluginPath, err = LocateFile(path, PluginGoBuiltFile)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
@@ -122,9 +122,9 @@ func locatePlugin(path string) (pluginPath string, err error) {
|
||||
return "", errors.New("plugin file not found")
|
||||
}
|
||||
|
||||
// locateFile searches destFile upward recursively until system root dir
|
||||
// LocateFile searches destFile upward recursively until system root dir
|
||||
// if not found, then searches in hrp executable dir
|
||||
func locateFile(startPath string, destFile string) (pluginPath string, err error) {
|
||||
func LocateFile(startPath string, destFile string) (pluginPath string, err error) {
|
||||
stat, err := os.Stat(startPath)
|
||||
if os.IsNotExist(err) {
|
||||
return "", errors.Wrap(err, "start path not exists")
|
||||
@@ -153,7 +153,7 @@ func locateFile(startPath string, destFile string) (pluginPath string, err error
|
||||
return "", errors.New("searched to system root dir, plugin file not found")
|
||||
}
|
||||
|
||||
return locateFile(parentDir, destFile)
|
||||
return LocateFile(parentDir, destFile)
|
||||
}
|
||||
|
||||
// locateExecutable finds destFile in hrp executable dir
|
||||
@@ -173,13 +173,13 @@ func locateExecutable(destFile string) (string, error) {
|
||||
}
|
||||
|
||||
func GetProjectRootDirPath(path string) (rootDir string, err error) {
|
||||
pluginPath, err := locatePlugin(path)
|
||||
pluginPath, err := LocatePlugin(path)
|
||||
if err == nil {
|
||||
rootDir = filepath.Dir(pluginPath)
|
||||
return
|
||||
}
|
||||
// fix: no debugtalk file in project but having proj.json created by startproject
|
||||
projPath, err := locateFile(path, projectInfoFile)
|
||||
projPath, err := LocateFile(path, projectInfoFile)
|
||||
if err == nil {
|
||||
rootDir = filepath.Dir(projPath)
|
||||
return
|
||||
|
||||
@@ -17,13 +17,14 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/httprunner/funplugin"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
"golang.org/x/net/http2"
|
||||
|
||||
"github.com/httprunner/funplugin"
|
||||
"github.com/httprunner/httprunner/v5/code"
|
||||
"github.com/httprunner/httprunner/v5/internal/builtin"
|
||||
"github.com/httprunner/httprunner/v5/internal/sdk"
|
||||
"github.com/httprunner/httprunner/v5/internal/version"
|
||||
"github.com/httprunner/httprunner/v5/uixt"
|
||||
@@ -281,7 +282,7 @@ func (r *HRPRunner) NewCaseRunner(testcase TestCase) (*CaseRunner, error) {
|
||||
caseRunner := &CaseRunner{
|
||||
TestCase: testcase,
|
||||
hrpRunner: r,
|
||||
parser: newParser(),
|
||||
parser: NewParser(),
|
||||
uixtDrivers: make(map[string]*uixt.XTDriver),
|
||||
}
|
||||
config := testcase.Config.Get()
|
||||
@@ -296,7 +297,7 @@ func (r *HRPRunner) NewCaseRunner(testcase TestCase) (*CaseRunner, error) {
|
||||
|
||||
// load plugin info to testcase config
|
||||
pluginPath := plugin.Path()
|
||||
pluginContent, err := readFile(pluginPath)
|
||||
pluginContent, err := builtin.LoadFile(pluginPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -407,7 +408,7 @@ func (r *CaseRunner) parseConfig() (parsedConfig *TConfig, err error) {
|
||||
parsedConfig.WebSocketSetting.checkWebSocket()
|
||||
|
||||
// parse testcase config parameters
|
||||
parametersIterator, err := r.parser.initParametersIterator(parsedConfig)
|
||||
parametersIterator, err := r.parser.InitParametersIterator(parsedConfig)
|
||||
if err != nil {
|
||||
log.Error().Err(err).
|
||||
Interface("parameters", parsedConfig.Parameters).
|
||||
|
||||
@@ -5,9 +5,10 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/httprunner/httprunner/v5/uixt"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/httprunner/httprunner/v5/uixt"
|
||||
)
|
||||
|
||||
// StepFunction implements IStep interface.
|
||||
|
||||
@@ -30,13 +30,13 @@ import (
|
||||
type HTTPMethod string
|
||||
|
||||
const (
|
||||
httpGET HTTPMethod = "GET"
|
||||
httpHEAD HTTPMethod = "HEAD"
|
||||
httpPOST HTTPMethod = "POST"
|
||||
httpPUT HTTPMethod = "PUT"
|
||||
httpDELETE HTTPMethod = "DELETE"
|
||||
httpOPTIONS HTTPMethod = "OPTIONS"
|
||||
httpPATCH HTTPMethod = "PATCH"
|
||||
HTTP_GET HTTPMethod = "GET"
|
||||
HTTP_HEAD HTTPMethod = "HEAD"
|
||||
HTTP_POST HTTPMethod = "POST"
|
||||
HTTP_PUT HTTPMethod = "PUT"
|
||||
HTTP_DELETE HTTPMethod = "DELETE"
|
||||
HTTP_OPTIONS HTTPMethod = "OPTIONS"
|
||||
HTTP_PATCH HTTPMethod = "PATCH"
|
||||
)
|
||||
|
||||
// Request represents HTTP request data structure.
|
||||
@@ -566,11 +566,11 @@ func (s *StepRequest) Loop(times int) *StepRequest {
|
||||
// GET makes a HTTP GET request.
|
||||
func (s *StepRequest) GET(url string) *StepRequestWithOptionalArgs {
|
||||
if s.Request != nil {
|
||||
s.Request.Method = httpGET
|
||||
s.Request.Method = HTTP_GET
|
||||
s.Request.URL = url
|
||||
} else {
|
||||
s.Request = &Request{
|
||||
Method: httpGET,
|
||||
Method: HTTP_GET,
|
||||
URL: url,
|
||||
}
|
||||
}
|
||||
@@ -582,11 +582,11 @@ func (s *StepRequest) GET(url string) *StepRequestWithOptionalArgs {
|
||||
// HEAD makes a HTTP HEAD request.
|
||||
func (s *StepRequest) HEAD(url string) *StepRequestWithOptionalArgs {
|
||||
if s.Request != nil {
|
||||
s.Request.Method = httpHEAD
|
||||
s.Request.Method = HTTP_HEAD
|
||||
s.Request.URL = url
|
||||
} else {
|
||||
s.Request = &Request{
|
||||
Method: httpHEAD,
|
||||
Method: HTTP_HEAD,
|
||||
URL: url,
|
||||
}
|
||||
}
|
||||
@@ -598,11 +598,11 @@ func (s *StepRequest) HEAD(url string) *StepRequestWithOptionalArgs {
|
||||
// POST makes a HTTP POST request.
|
||||
func (s *StepRequest) POST(url string) *StepRequestWithOptionalArgs {
|
||||
if s.Request != nil {
|
||||
s.Request.Method = httpPOST
|
||||
s.Request.Method = HTTP_POST
|
||||
s.Request.URL = url
|
||||
} else {
|
||||
s.Request = &Request{
|
||||
Method: httpPOST,
|
||||
Method: HTTP_POST,
|
||||
URL: url,
|
||||
}
|
||||
}
|
||||
@@ -614,11 +614,11 @@ func (s *StepRequest) POST(url string) *StepRequestWithOptionalArgs {
|
||||
// PUT makes a HTTP PUT request.
|
||||
func (s *StepRequest) PUT(url string) *StepRequestWithOptionalArgs {
|
||||
if s.Request != nil {
|
||||
s.Request.Method = httpPUT
|
||||
s.Request.Method = HTTP_PUT
|
||||
s.Request.URL = url
|
||||
} else {
|
||||
s.Request = &Request{
|
||||
Method: httpPUT,
|
||||
Method: HTTP_PUT,
|
||||
URL: url,
|
||||
}
|
||||
}
|
||||
@@ -630,11 +630,11 @@ func (s *StepRequest) PUT(url string) *StepRequestWithOptionalArgs {
|
||||
// DELETE makes a HTTP DELETE request.
|
||||
func (s *StepRequest) DELETE(url string) *StepRequestWithOptionalArgs {
|
||||
if s.Request != nil {
|
||||
s.Request.Method = httpDELETE
|
||||
s.Request.Method = HTTP_DELETE
|
||||
s.Request.URL = url
|
||||
} else {
|
||||
s.Request = &Request{
|
||||
Method: httpDELETE,
|
||||
Method: HTTP_DELETE,
|
||||
URL: url,
|
||||
}
|
||||
}
|
||||
@@ -646,11 +646,11 @@ func (s *StepRequest) DELETE(url string) *StepRequestWithOptionalArgs {
|
||||
// OPTIONS makes a HTTP OPTIONS request.
|
||||
func (s *StepRequest) OPTIONS(url string) *StepRequestWithOptionalArgs {
|
||||
if s.Request != nil {
|
||||
s.Request.Method = httpOPTIONS
|
||||
s.Request.Method = HTTP_OPTIONS
|
||||
s.Request.URL = url
|
||||
} else {
|
||||
s.Request = &Request{
|
||||
Method: httpOPTIONS,
|
||||
Method: HTTP_OPTIONS,
|
||||
URL: url,
|
||||
}
|
||||
}
|
||||
@@ -662,11 +662,11 @@ func (s *StepRequest) OPTIONS(url string) *StepRequestWithOptionalArgs {
|
||||
// PATCH makes a HTTP PATCH request.
|
||||
func (s *StepRequest) PATCH(url string) *StepRequestWithOptionalArgs {
|
||||
if s.Request != nil {
|
||||
s.Request.Method = httpPATCH
|
||||
s.Request.Method = HTTP_PATCH
|
||||
s.Request.URL = url
|
||||
} else {
|
||||
s.Request = &Request{
|
||||
Method: httpPATCH,
|
||||
Method: HTTP_PATCH,
|
||||
URL: url,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
package hrp
|
||||
@@ -42,14 +42,14 @@ func (s *StepThinkTime) Run(r *SessionRunner) (*StepResult, error) {
|
||||
|
||||
cfg := r.caseRunner.Config.Get().ThinkTimeSetting
|
||||
if cfg == nil {
|
||||
cfg = &ThinkTimeConfig{thinkTimeDefault, nil, 0}
|
||||
cfg = &ThinkTimeConfig{ThinkTimeDefault, nil, 0}
|
||||
}
|
||||
|
||||
var tt time.Duration
|
||||
switch cfg.Strategy {
|
||||
case thinkTimeDefault:
|
||||
case ThinkTimeDefault:
|
||||
tt = time.Duration(thinkTime.Time*1000) * time.Millisecond
|
||||
case thinkTimeRandomPercentage:
|
||||
case ThinkTimeRandomPercentage:
|
||||
// e.g. {"min_percentage": 0.5, "max_percentage": 1.5}
|
||||
m, ok := cfg.Setting.(map[string]float64)
|
||||
if !ok {
|
||||
@@ -58,13 +58,13 @@ func (s *StepThinkTime) Run(r *SessionRunner) (*StepResult, error) {
|
||||
}
|
||||
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:
|
||||
case ThinkTimeMultiply:
|
||||
value, ok := cfg.Setting.(float64) // e.g. 0.5
|
||||
if !ok || value <= 0 {
|
||||
value = thinkTimeDefaultMultiply
|
||||
}
|
||||
tt = time.Duration(thinkTime.Time*value*1000) * time.Millisecond
|
||||
case thinkTimeIgnore:
|
||||
case ThinkTimeIgnore:
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
|
||||
45
tests/build_test.go
Normal file
45
tests/build_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
hrp "github.com/httprunner/httprunner/v5"
|
||||
"github.com/httprunner/httprunner/v5/internal/builtin"
|
||||
)
|
||||
|
||||
func TestRun(t *testing.T) {
|
||||
err := hrp.BuildPlugin(tmpl("plugin/debugtalk.go"), "./debugtalk.bin")
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
genDebugTalkPyPath := filepath.Join(tmpl("plugin/"), hrp.PluginPySourceGenFile)
|
||||
err = hrp.BuildPlugin(tmpl("plugin/debugtalk.py"), genDebugTalkPyPath)
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
contentBytes, err := builtin.LoadFile(genDebugTalkPyPath)
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
content := string(contentBytes)
|
||||
if !assert.Contains(t, content, "import funppy") {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
if !assert.Contains(t, content, "funppy.register") {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
reg, _ := regexp.Compile(`funppy\.register`)
|
||||
matchedSlice := reg.FindAllStringSubmatch(content, -1)
|
||||
if !assert.Len(t, matchedSlice, 10) {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,17 @@
|
||||
package hrp
|
||||
package tests
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
hrp "github.com/httprunner/httprunner/v5"
|
||||
)
|
||||
|
||||
func TestLoadTestCases(t *testing.T) {
|
||||
// load test cases from folder path
|
||||
tc := TestCasePath("../examples/demo-with-py-plugin/testcases/")
|
||||
testCases, err := LoadTestCases(&tc)
|
||||
tc := hrp.TestCasePath("../examples/demo-with-py-plugin/testcases/")
|
||||
testCases, err := hrp.LoadTestCases(&tc)
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
@@ -18,8 +20,8 @@ func TestLoadTestCases(t *testing.T) {
|
||||
}
|
||||
|
||||
// load test cases from folder path, including sub folders
|
||||
tc = TestCasePath("../examples/demo-with-py-plugin/")
|
||||
testCases, err = LoadTestCases(&tc)
|
||||
tc = hrp.TestCasePath("../examples/demo-with-py-plugin/")
|
||||
testCases, err = hrp.LoadTestCases(&tc)
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
@@ -28,8 +30,8 @@ func TestLoadTestCases(t *testing.T) {
|
||||
}
|
||||
|
||||
// load test cases from single file path
|
||||
tc = TestCasePath(demoTestCaseWithPluginJSONPath)
|
||||
testCases, err = LoadTestCases(&tc)
|
||||
tc = hrp.TestCasePath(demoTestCaseWithPluginJSONPath)
|
||||
testCases, err = hrp.LoadTestCases(&tc)
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
@@ -38,10 +40,10 @@ func TestLoadTestCases(t *testing.T) {
|
||||
}
|
||||
|
||||
// load test cases from TestCase instance
|
||||
testcase := &TestCase{
|
||||
Config: NewConfig("TestCase").SetWeight(3),
|
||||
testcase := &hrp.TestCase{
|
||||
Config: hrp.NewConfig("TestCase").SetWeight(3),
|
||||
}
|
||||
testCases, err = LoadTestCases(testcase)
|
||||
testCases, err = hrp.LoadTestCases(testcase)
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
@@ -50,7 +52,7 @@ func TestLoadTestCases(t *testing.T) {
|
||||
}
|
||||
|
||||
// load test cases from TestCaseJSON
|
||||
testcaseJSON := TestCaseJSON(`
|
||||
testcaseJSON := hrp.TestCaseJSON(`
|
||||
{
|
||||
"config":{"name":"TestCaseJSON"},
|
||||
"teststeps":[
|
||||
@@ -58,7 +60,7 @@ func TestLoadTestCases(t *testing.T) {
|
||||
{"name": "step2", "shell":{"string": "ls -l"}}
|
||||
]
|
||||
}`)
|
||||
testCases, err = LoadTestCases(&testcaseJSON)
|
||||
testCases, err = hrp.LoadTestCases(&testcaseJSON)
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
@@ -68,13 +70,13 @@ func TestLoadTestCases(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoadCase(t *testing.T) {
|
||||
tcJSON := &TestCaseDef{}
|
||||
tcYAML := &TestCaseDef{}
|
||||
err := LoadFileObject(demoTestCaseWithPluginJSONPath, tcJSON)
|
||||
tcJSON := &hrp.TestCaseDef{}
|
||||
tcYAML := &hrp.TestCaseDef{}
|
||||
err := hrp.LoadFileObject(demoTestCaseWithPluginJSONPath, tcJSON)
|
||||
if !assert.NoError(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
err = LoadFileObject(demoTestCaseWithPluginYAMLPath, tcYAML)
|
||||
err = hrp.LoadFileObject(demoTestCaseWithPluginYAMLPath, tcYAML)
|
||||
if !assert.NoError(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
@@ -1,22 +1,24 @@
|
||||
package hrp
|
||||
package tests
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
hrp "github.com/httprunner/httprunner/v5"
|
||||
)
|
||||
|
||||
func TestLoadParameters(t *testing.T) {
|
||||
testData := []struct {
|
||||
configParameters map[string]interface{}
|
||||
loadedParameters map[string]Parameters
|
||||
loadedParameters map[string]hrp.Parameters
|
||||
}{
|
||||
{
|
||||
map[string]interface{}{
|
||||
"username-password": fmt.Sprintf("${parameterize(%s/$file)}", hrpExamplesDir),
|
||||
},
|
||||
map[string]Parameters{
|
||||
map[string]hrp.Parameters{
|
||||
"username-password": {
|
||||
{"username": "test1", "password": "111111"},
|
||||
{"username": "test2", "password": "222222"},
|
||||
@@ -33,7 +35,7 @@ func TestLoadParameters(t *testing.T) {
|
||||
"user_agent": []interface{}{"iOS/10.1", "iOS/10.2"},
|
||||
"app_version": []interface{}{4.0},
|
||||
},
|
||||
map[string]Parameters{
|
||||
map[string]hrp.Parameters{
|
||||
"username-password": {
|
||||
{"username": "test1", "password": "111111"},
|
||||
{"username": "test2", "password": "222222"},
|
||||
@@ -54,7 +56,7 @@ func TestLoadParameters(t *testing.T) {
|
||||
[]interface{}{"test2", "222222"},
|
||||
},
|
||||
},
|
||||
map[string]Parameters{
|
||||
map[string]hrp.Parameters{
|
||||
"username-password": {
|
||||
{"username": "test1", "password": "111111"},
|
||||
{"username": "test2", "password": "222222"},
|
||||
@@ -74,9 +76,9 @@ func TestLoadParameters(t *testing.T) {
|
||||
variablesMapping := map[string]interface{}{
|
||||
"file": "account.csv",
|
||||
}
|
||||
parser := newParser()
|
||||
parser := hrp.NewParser()
|
||||
for _, data := range testData {
|
||||
value, err := parser.loadParameters(data.configParameters, variablesMapping)
|
||||
value, err := parser.LoadParameters(data.configParameters, variablesMapping)
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
@@ -109,9 +111,9 @@ func TestLoadParametersError(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
parser := newParser()
|
||||
parser := hrp.NewParser()
|
||||
for _, data := range testData {
|
||||
_, err := parser.loadParameters(data.configParameters, map[string]interface{}{})
|
||||
_, err := parser.LoadParameters(data.configParameters, map[string]interface{}{})
|
||||
if !assert.Error(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
@@ -125,28 +127,28 @@ func TestInitParametersIteratorCount(t *testing.T) {
|
||||
"app_version": []interface{}{4.0}, // 1
|
||||
}
|
||||
testData := []struct {
|
||||
cfg *TConfig
|
||||
cfg *hrp.TConfig
|
||||
expectLimit int
|
||||
}{
|
||||
// default, no parameters setting
|
||||
{
|
||||
&TConfig{
|
||||
&hrp.TConfig{
|
||||
Parameters: configParameters,
|
||||
ParametersSetting: &TParamsConfig{},
|
||||
ParametersSetting: &hrp.TParamsConfig{},
|
||||
},
|
||||
6, // 3 * 2 * 1
|
||||
},
|
||||
{
|
||||
&TConfig{
|
||||
&hrp.TConfig{
|
||||
Parameters: configParameters,
|
||||
},
|
||||
6, // 3 * 2 * 1
|
||||
},
|
||||
// default equals to set overall parameters pick-order to "sequential"
|
||||
{
|
||||
&TConfig{
|
||||
&hrp.TConfig{
|
||||
Parameters: configParameters,
|
||||
ParametersSetting: &TParamsConfig{
|
||||
ParametersSetting: &hrp.TParamsConfig{
|
||||
PickOrder: "sequential",
|
||||
},
|
||||
},
|
||||
@@ -154,10 +156,10 @@ func TestInitParametersIteratorCount(t *testing.T) {
|
||||
},
|
||||
// default equals to set each individual parameters pick-order to "sequential"
|
||||
{
|
||||
&TConfig{
|
||||
&hrp.TConfig{
|
||||
Parameters: configParameters,
|
||||
ParametersSetting: &TParamsConfig{
|
||||
Strategies: map[string]iteratorStrategy{
|
||||
ParametersSetting: &hrp.TParamsConfig{
|
||||
Strategies: map[string]hrp.IteratorStrategy{
|
||||
"username-password": {Name: "user-info", PickOrder: "sequential"},
|
||||
"user_agent": {Name: "user-identity", PickOrder: "sequential"},
|
||||
"app_version": {Name: "app-version", PickOrder: "sequential"},
|
||||
@@ -167,10 +169,10 @@ func TestInitParametersIteratorCount(t *testing.T) {
|
||||
6, // 3 * 2 * 1
|
||||
},
|
||||
{
|
||||
&TConfig{
|
||||
&hrp.TConfig{
|
||||
Parameters: configParameters,
|
||||
ParametersSetting: &TParamsConfig{
|
||||
Strategies: map[string]iteratorStrategy{
|
||||
ParametersSetting: &hrp.TParamsConfig{
|
||||
Strategies: map[string]hrp.IteratorStrategy{
|
||||
"user_agent": {Name: "user-identity", PickOrder: "sequential"},
|
||||
"app_version": {Name: "app-version", PickOrder: "sequential"},
|
||||
},
|
||||
@@ -182,9 +184,9 @@ func TestInitParametersIteratorCount(t *testing.T) {
|
||||
// set overall parameters overall pick-order to "random"
|
||||
// each random parameters only select one item
|
||||
{
|
||||
&TConfig{
|
||||
&hrp.TConfig{
|
||||
Parameters: configParameters,
|
||||
ParametersSetting: &TParamsConfig{
|
||||
ParametersSetting: &hrp.TParamsConfig{
|
||||
PickOrder: "random",
|
||||
},
|
||||
},
|
||||
@@ -193,10 +195,10 @@ func TestInitParametersIteratorCount(t *testing.T) {
|
||||
// set some individual parameters pick-order to "random"
|
||||
// this will override overall strategy
|
||||
{
|
||||
&TConfig{
|
||||
&hrp.TConfig{
|
||||
Parameters: configParameters,
|
||||
ParametersSetting: &TParamsConfig{
|
||||
Strategies: map[string]iteratorStrategy{
|
||||
ParametersSetting: &hrp.TParamsConfig{
|
||||
Strategies: map[string]hrp.IteratorStrategy{
|
||||
"user_agent": {Name: "user-identity", PickOrder: "random"},
|
||||
},
|
||||
},
|
||||
@@ -204,10 +206,10 @@ func TestInitParametersIteratorCount(t *testing.T) {
|
||||
3, // 3 * 1 * 1
|
||||
},
|
||||
{
|
||||
&TConfig{
|
||||
&hrp.TConfig{
|
||||
Parameters: configParameters,
|
||||
ParametersSetting: &TParamsConfig{
|
||||
Strategies: map[string]iteratorStrategy{
|
||||
ParametersSetting: &hrp.TParamsConfig{
|
||||
Strategies: map[string]hrp.IteratorStrategy{
|
||||
"username-password": {Name: "user-info", PickOrder: "random"},
|
||||
},
|
||||
},
|
||||
@@ -217,18 +219,18 @@ func TestInitParametersIteratorCount(t *testing.T) {
|
||||
|
||||
// set limit for parameters
|
||||
{
|
||||
&TConfig{
|
||||
&hrp.TConfig{
|
||||
Parameters: configParameters, // total: 6 = 3 * 2 * 1
|
||||
ParametersSetting: &TParamsConfig{
|
||||
ParametersSetting: &hrp.TParamsConfig{
|
||||
Limit: 4, // limit could be less than total
|
||||
},
|
||||
},
|
||||
4,
|
||||
},
|
||||
{
|
||||
&TConfig{
|
||||
&hrp.TConfig{
|
||||
Parameters: configParameters, // total: 6 = 3 * 2 * 1
|
||||
ParametersSetting: &TParamsConfig{
|
||||
ParametersSetting: &hrp.TParamsConfig{
|
||||
Limit: 9, // limit could also be greater than total
|
||||
},
|
||||
},
|
||||
@@ -238,20 +240,20 @@ func TestInitParametersIteratorCount(t *testing.T) {
|
||||
// no parameters
|
||||
// also will generate one empty item
|
||||
{
|
||||
&TConfig{
|
||||
&hrp.TConfig{
|
||||
Parameters: nil,
|
||||
ParametersSetting: nil,
|
||||
},
|
||||
1,
|
||||
},
|
||||
}
|
||||
parser := newParser()
|
||||
parser := hrp.NewParser()
|
||||
for _, data := range testData {
|
||||
iterator, err := parser.initParametersIterator(data.cfg)
|
||||
iterator, err := parser.InitParametersIterator(data.cfg)
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
if !assert.Equal(t, data.expectLimit, iterator.limit) {
|
||||
if !assert.Equal(t, data.expectLimit, iterator.Limit) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
@@ -275,34 +277,34 @@ func TestInitParametersIteratorUnlimitedCount(t *testing.T) {
|
||||
"app_version": []interface{}{4.0}, // 1
|
||||
}
|
||||
testData := []struct {
|
||||
cfg *TConfig
|
||||
cfg *hrp.TConfig
|
||||
}{
|
||||
// default, no parameters setting
|
||||
{
|
||||
&TConfig{
|
||||
&hrp.TConfig{
|
||||
Parameters: configParameters,
|
||||
ParametersSetting: &TParamsConfig{},
|
||||
ParametersSetting: &hrp.TParamsConfig{},
|
||||
},
|
||||
},
|
||||
|
||||
// no parameters
|
||||
// also will generate one empty item
|
||||
{
|
||||
&TConfig{
|
||||
&hrp.TConfig{
|
||||
Parameters: nil,
|
||||
ParametersSetting: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
parser := newParser()
|
||||
parser := hrp.NewParser()
|
||||
for _, data := range testData {
|
||||
iterator, err := parser.initParametersIterator(data.cfg)
|
||||
iterator, err := parser.InitParametersIterator(data.cfg)
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
// set unlimited mode
|
||||
iterator.SetUnlimitedMode()
|
||||
if !assert.Equal(t, -1, iterator.limit) {
|
||||
if !assert.Equal(t, -1, iterator.Limit) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
@@ -312,7 +314,7 @@ func TestInitParametersIteratorUnlimitedCount(t *testing.T) {
|
||||
}
|
||||
iterator.Next() // consume next parameters
|
||||
}
|
||||
if !assert.Equal(t, 100, iterator.index) {
|
||||
if !assert.Equal(t, 100, iterator.Index) {
|
||||
t.Fatal()
|
||||
}
|
||||
// should also have next
|
||||
@@ -329,13 +331,13 @@ func TestInitParametersIteratorContent(t *testing.T) {
|
||||
"app_version": []interface{}{4.0}, // 1
|
||||
}
|
||||
testData := []struct {
|
||||
cfg *TConfig
|
||||
cfg *hrp.TConfig
|
||||
checkIndex int
|
||||
expectParameters map[string]interface{}
|
||||
}{
|
||||
// default, no parameters setting
|
||||
{
|
||||
&TConfig{
|
||||
&hrp.TConfig{
|
||||
Parameters: configParameters,
|
||||
},
|
||||
0, // check first item
|
||||
@@ -346,16 +348,16 @@ func TestInitParametersIteratorContent(t *testing.T) {
|
||||
|
||||
// set limit for parameters
|
||||
{
|
||||
&TConfig{
|
||||
&hrp.TConfig{
|
||||
Parameters: map[string]interface{}{
|
||||
"username-password": []map[string]interface{}{ // 1
|
||||
{"username": "test1", "password": 111111, "other": "111"},
|
||||
},
|
||||
"user_agent": []string{"iOS/10.1", "iOS/10.2"}, // 2
|
||||
},
|
||||
ParametersSetting: &TParamsConfig{
|
||||
ParametersSetting: &hrp.TParamsConfig{
|
||||
Limit: 5, // limit could also be greater than total
|
||||
Strategies: map[string]iteratorStrategy{
|
||||
Strategies: map[string]hrp.IteratorStrategy{
|
||||
"username-password": {Name: "user-info", PickOrder: "random"},
|
||||
},
|
||||
},
|
||||
@@ -369,7 +371,7 @@ func TestInitParametersIteratorContent(t *testing.T) {
|
||||
// no parameters
|
||||
// also will generate one empty item
|
||||
{
|
||||
&TConfig{
|
||||
&hrp.TConfig{
|
||||
Parameters: nil,
|
||||
ParametersSetting: nil,
|
||||
},
|
||||
@@ -377,9 +379,9 @@ func TestInitParametersIteratorContent(t *testing.T) {
|
||||
map[string]interface{}{},
|
||||
},
|
||||
}
|
||||
parser := newParser()
|
||||
parser := hrp.NewParser()
|
||||
for _, data := range testData {
|
||||
iterator, err := parser.initParametersIterator(data.cfg)
|
||||
iterator, err := parser.InitParametersIterator(data.cfg)
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
@@ -401,11 +403,11 @@ func TestInitParametersIteratorContent(t *testing.T) {
|
||||
|
||||
func TestGenCartesianProduct(t *testing.T) {
|
||||
testData := []struct {
|
||||
multiParameters []Parameters
|
||||
expect Parameters
|
||||
multiParameters []hrp.Parameters
|
||||
expect hrp.Parameters
|
||||
}{
|
||||
{
|
||||
[]Parameters{
|
||||
[]hrp.Parameters{
|
||||
{
|
||||
{"app_version": 4.0},
|
||||
},
|
||||
@@ -418,7 +420,7 @@ func TestGenCartesianProduct(t *testing.T) {
|
||||
{"user_agent": "iOS/10.2"},
|
||||
},
|
||||
},
|
||||
Parameters{
|
||||
hrp.Parameters{
|
||||
{"app_version": 4.0, "password": "111111", "user_agent": "iOS/10.1", "username": "test1"},
|
||||
{"app_version": 4.0, "password": "111111", "user_agent": "iOS/10.2", "username": "test1"},
|
||||
{"app_version": 4.0, "password": "222222", "user_agent": "iOS/10.1", "username": "test2"},
|
||||
@@ -430,13 +432,13 @@ func TestGenCartesianProduct(t *testing.T) {
|
||||
nil,
|
||||
},
|
||||
{
|
||||
[]Parameters{},
|
||||
[]hrp.Parameters{},
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, data := range testData {
|
||||
parameters := genCartesianProduct(data.multiParameters)
|
||||
parameters := hrp.GenCartesianProduct(data.multiParameters)
|
||||
if !assert.Equal(t, data.expect, parameters) {
|
||||
t.Fatal()
|
||||
}
|
||||
@@ -490,7 +492,7 @@ func TestConvertParameters(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, data := range testData {
|
||||
value, err := convertParameters(data.key, data.parametersRawList)
|
||||
value, err := hrp.ConvertParameters(data.key, data.parametersRawList)
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
@@ -530,7 +532,7 @@ func TestConvertParametersError(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, data := range testData {
|
||||
_, err := convertParameters(data.key, data.parametersRawList)
|
||||
_, err := hrp.ConvertParameters(data.key, data.parametersRawList)
|
||||
if !assert.Error(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
@@ -1,43 +1,45 @@
|
||||
package hrp
|
||||
package tests
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
hrp "github.com/httprunner/httprunner/v5"
|
||||
)
|
||||
|
||||
func TestLocateFile(t *testing.T) {
|
||||
// specify target file path
|
||||
_, err := locateFile(tmpl("plugin/debugtalk.go"), PluginGoSourceFile)
|
||||
_, err := hrp.LocateFile(tmpl("plugin/debugtalk.go"), hrp.PluginGoSourceFile)
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
// specify path with the same dir
|
||||
_, err = locateFile(tmpl("plugin/debugtalk.py"), PluginGoSourceFile)
|
||||
_, err = hrp.LocateFile(tmpl("plugin/debugtalk.py"), hrp.PluginGoSourceFile)
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
// specify target file path dir
|
||||
_, err = locateFile(tmpl("plugin/"), PluginGoSourceFile)
|
||||
_, err = hrp.LocateFile(tmpl("plugin/"), hrp.PluginGoSourceFile)
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
// specify wrong path
|
||||
_, err = locateFile(".", PluginGoSourceFile)
|
||||
_, err = hrp.LocateFile(".", hrp.PluginGoSourceFile)
|
||||
if !assert.Error(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
_, err = locateFile("/abc", PluginGoSourceFile)
|
||||
_, err = hrp.LocateFile("/abc", hrp.PluginGoSourceFile)
|
||||
if !assert.Error(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocatePythonPlugin(t *testing.T) {
|
||||
_, err := locatePlugin(tmpl("plugin/debugtalk.py"))
|
||||
_, err := hrp.LocatePlugin(tmpl("plugin/debugtalk.py"))
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
@@ -47,7 +49,7 @@ func TestLocateGoPlugin(t *testing.T) {
|
||||
buildHashicorpGoPlugin()
|
||||
defer removeHashicorpGoPlugin()
|
||||
|
||||
_, err := locatePlugin(tmpl("debugtalk.bin"))
|
||||
_, err := hrp.LocatePlugin(tmpl("debugtalk.bin"))
|
||||
if !assert.Nil(t, err) {
|
||||
t.Fatal()
|
||||
}
|
||||
@@ -1,22 +1,22 @@
|
||||
package hrp
|
||||
package tests
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
hrp "github.com/httprunner/httprunner/v5"
|
||||
"github.com/httprunner/httprunner/v5/code"
|
||||
)
|
||||
|
||||
func buildHashicorpGoPlugin() {
|
||||
log.Info().Msg("[init] build hashicorp go plugin")
|
||||
err := BuildPlugin(tmpl("plugin/debugtalk.go"), tmpl("debugtalk.bin"))
|
||||
err := hrp.BuildPlugin(tmpl("plugin/debugtalk.go"), tmpl("debugtalk.bin"))
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("build hashicorp go plugin failed")
|
||||
os.Exit(code.GetErrorCode(err))
|
||||
@@ -26,8 +26,6 @@ func buildHashicorpGoPlugin() {
|
||||
func removeHashicorpGoPlugin() {
|
||||
log.Info().Msg("[teardown] remove hashicorp go plugin")
|
||||
os.Remove(tmpl("debugtalk.bin"))
|
||||
pluginPath, _ := filepath.Abs(tmpl("debugtalk.bin"))
|
||||
pluginMap.Delete(pluginPath)
|
||||
}
|
||||
|
||||
func buildHashicorpPyPlugin() {
|
||||
@@ -43,8 +41,8 @@ func buildHashicorpPyPlugin() {
|
||||
func removeHashicorpPyPlugin() {
|
||||
log.Info().Msg("[teardown] remove hashicorp python plugin")
|
||||
// on v4.1^, running case will generate .debugtalk_gen.py used by python plugin
|
||||
os.Remove(tmpl(PluginPySourceFile))
|
||||
os.Remove(tmpl(PluginPySourceGenFile))
|
||||
os.Remove(tmpl(hrp.PluginPySourceFile))
|
||||
os.Remove(tmpl(hrp.PluginPySourceGenFile))
|
||||
}
|
||||
|
||||
func TestRunCaseWithGoPlugin(t *testing.T) {
|
||||
@@ -62,21 +60,21 @@ func TestRunCaseWithPythonPlugin(t *testing.T) {
|
||||
}
|
||||
|
||||
func assertRunTestCases(t *testing.T) {
|
||||
refCase := TestCasePath(demoTestCaseWithPluginJSONPath)
|
||||
testcase1 := &TestCase{
|
||||
Config: NewConfig("TestCase1").
|
||||
refCase := hrp.TestCasePath(demoTestCaseWithPluginJSONPath)
|
||||
testcase1 := &hrp.TestCase{
|
||||
Config: hrp.NewConfig("TestCase1").
|
||||
SetBaseURL("https://postman-echo.com"),
|
||||
TestSteps: []IStep{
|
||||
NewStep("testcase1-step1").
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("testcase1-step1").
|
||||
GET("/headers").
|
||||
Validate().
|
||||
AssertEqual("status_code", 200, "check status code").
|
||||
AssertEqual("headers.\"Content-Type\"", "application/json; charset=utf-8", "check http response Content-Type"),
|
||||
NewStep("testcase1-step2").CallRefCase(
|
||||
&TestCase{
|
||||
Config: NewConfig("testcase1-step3-ref-case").SetBaseURL("https://postman-echo.com"),
|
||||
TestSteps: []IStep{
|
||||
NewStep("ip").
|
||||
hrp.NewStep("testcase1-step2").CallRefCase(
|
||||
&hrp.TestCase{
|
||||
Config: hrp.NewConfig("testcase1-step3-ref-case").SetBaseURL("https://postman-echo.com"),
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("ip").
|
||||
GET("/ip").
|
||||
Validate().
|
||||
AssertEqual("status_code", 200, "check status code").
|
||||
@@ -84,14 +82,14 @@ func assertRunTestCases(t *testing.T) {
|
||||
},
|
||||
},
|
||||
),
|
||||
NewStep("testcase1-step3").CallRefCase(&refCase),
|
||||
hrp.NewStep("testcase1-step3").CallRefCase(&refCase),
|
||||
},
|
||||
}
|
||||
testcase2 := &TestCase{
|
||||
Config: NewConfig("TestCase2").SetWeight(3),
|
||||
testcase2 := &hrp.TestCase{
|
||||
Config: hrp.NewConfig("TestCase2").SetWeight(3),
|
||||
}
|
||||
|
||||
r := NewRunner(t)
|
||||
r := hrp.NewRunner(t)
|
||||
r.SetPluginLogOn()
|
||||
err := r.Run(testcase1, testcase2)
|
||||
if err != nil {
|
||||
@@ -103,46 +101,46 @@ func TestRunCaseWithThinkTime(t *testing.T) {
|
||||
buildHashicorpGoPlugin()
|
||||
defer removeHashicorpGoPlugin()
|
||||
|
||||
testcases := []*TestCase{
|
||||
testcases := []*hrp.TestCase{
|
||||
{
|
||||
Config: NewConfig("TestCase1"),
|
||||
TestSteps: []IStep{
|
||||
NewStep("thinkTime").SetThinkTime(2),
|
||||
Config: hrp.NewConfig("TestCase1"),
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("thinkTime").SetThinkTime(2),
|
||||
},
|
||||
},
|
||||
{
|
||||
Config: NewConfig("TestCase2").
|
||||
SetThinkTime(thinkTimeIgnore, nil, 0),
|
||||
TestSteps: []IStep{
|
||||
NewStep("thinkTime").SetThinkTime(0.5),
|
||||
Config: hrp.NewConfig("TestCase2").
|
||||
SetThinkTime(hrp.ThinkTimeIgnore, nil, 0),
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("thinkTime").SetThinkTime(0.5),
|
||||
},
|
||||
},
|
||||
{
|
||||
Config: NewConfig("TestCase3").
|
||||
SetThinkTime(thinkTimeRandomPercentage, nil, 0),
|
||||
TestSteps: []IStep{
|
||||
NewStep("thinkTime").SetThinkTime(1),
|
||||
Config: hrp.NewConfig("TestCase3").
|
||||
SetThinkTime(hrp.ThinkTimeRandomPercentage, nil, 0),
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.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: hrp.NewConfig("TestCase4").
|
||||
SetThinkTime(hrp.ThinkTimeRandomPercentage, map[string]interface{}{"min_percentage": 2, "max_percentage": 3}, 2.5),
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("thinkTime").SetThinkTime(1),
|
||||
},
|
||||
},
|
||||
{
|
||||
Config: NewConfig("TestCase5"),
|
||||
TestSteps: []IStep{
|
||||
Config: hrp.NewConfig("TestCase5"),
|
||||
TestSteps: []hrp.IStep{
|
||||
// think time: 3s, random pct: {"min_percentage":1, "max_percentage":1.5}, limit: 4s
|
||||
NewStep("thinkTime").CallRefCase(&demoTestCaseWithThinkTimePath),
|
||||
hrp.NewStep("thinkTime").CallRefCase(&demoTestCaseWithThinkTimePath),
|
||||
},
|
||||
},
|
||||
}
|
||||
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)
|
||||
r := hrp.NewRunner(t)
|
||||
startTime := time.Now()
|
||||
err := r.Run(testcase)
|
||||
if err != nil {
|
||||
@@ -158,20 +156,20 @@ func TestRunCaseWithThinkTime(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRunCaseWithShell(t *testing.T) {
|
||||
testcase1 := &TestCase{
|
||||
Config: NewConfig("complex shell with env variables").
|
||||
testcase1 := &hrp.TestCase{
|
||||
Config: hrp.NewConfig("complex shell with env variables").
|
||||
WithVariables(map[string]interface{}{
|
||||
"SS": "12345",
|
||||
"ABC": "$SS",
|
||||
}),
|
||||
TestSteps: []IStep{
|
||||
NewStep("shell21").Shell("echo hello world"),
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("shell21").Shell("echo hello world"),
|
||||
// NewStep("shell21").Shell("echo $ABC"),
|
||||
// NewStep("shell21").Shell("which hrp"),
|
||||
},
|
||||
}
|
||||
|
||||
r := NewRunner(t)
|
||||
r := hrp.NewRunner(t)
|
||||
err := r.Run(testcase1)
|
||||
if err != nil {
|
||||
t.Fatal()
|
||||
@@ -193,16 +191,16 @@ func TestRunCaseWithFunction(t *testing.T) {
|
||||
err3 = errors.New("func3 error")
|
||||
fmt.Println("call function3 with return value and error")
|
||||
}
|
||||
testcase1 := &TestCase{
|
||||
Config: NewConfig("call function"),
|
||||
TestSteps: []IStep{
|
||||
NewStep("fn1").Function(fn1),
|
||||
NewStep("fn2").Function(fn2),
|
||||
NewStep("fn3").Function(fn3),
|
||||
testcase1 := &hrp.TestCase{
|
||||
Config: hrp.NewConfig("call function"),
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("fn1").Function(fn1),
|
||||
hrp.NewStep("fn2").Function(fn2),
|
||||
hrp.NewStep("fn3").Function(fn3),
|
||||
},
|
||||
}
|
||||
|
||||
r := NewRunner(t)
|
||||
r := hrp.NewRunner(t)
|
||||
err := r.Run(testcase1)
|
||||
if err != nil {
|
||||
t.Fatal()
|
||||
@@ -220,8 +218,8 @@ func TestRunCaseWithPluginJSON(t *testing.T) {
|
||||
buildHashicorpGoPlugin()
|
||||
defer removeHashicorpGoPlugin()
|
||||
|
||||
testCase := TestCasePath(demoTestCaseWithPluginJSONPath)
|
||||
err := NewRunner(nil).Run(&testCase) // hrp.Run(testCase)
|
||||
testCase := hrp.TestCasePath(demoTestCaseWithPluginJSONPath)
|
||||
err := hrp.NewRunner(nil).Run(&testCase) // hrp.Run(testCase)
|
||||
if err != nil {
|
||||
t.Fatal()
|
||||
}
|
||||
@@ -243,22 +241,22 @@ func TestRunCaseWithRefAPI(t *testing.T) {
|
||||
buildHashicorpGoPlugin()
|
||||
defer removeHashicorpGoPlugin()
|
||||
|
||||
testCase := TestCasePath(demoTestCaseWithRefAPIPath)
|
||||
err := NewRunner(nil).Run(&testCase)
|
||||
testCase := hrp.TestCasePath(demoTestCaseWithRefAPIPath)
|
||||
err := hrp.NewRunner(nil).Run(&testCase)
|
||||
if err != nil {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
refAPI := APIPath(demoAPIGETPath)
|
||||
testcase := &TestCase{
|
||||
Config: NewConfig("TestCase").
|
||||
refAPI := hrp.APIPath(demoAPIGETPath)
|
||||
testcase := &hrp.TestCase{
|
||||
Config: hrp.NewConfig("TestCase").
|
||||
SetBaseURL("https://postman-echo.com"),
|
||||
TestSteps: []IStep{
|
||||
NewStep("run referenced api").CallRefAPI(&refAPI),
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("run referenced api").CallRefAPI(&refAPI),
|
||||
},
|
||||
}
|
||||
|
||||
r := NewRunner(t)
|
||||
r := hrp.NewRunner(t)
|
||||
err = r.Run(testcase)
|
||||
if err != nil {
|
||||
t.Fatal()
|
||||
@@ -266,15 +264,15 @@ func TestRunCaseWithRefAPI(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSessionRunner(t *testing.T) {
|
||||
testcase := TestCase{
|
||||
Config: NewConfig("TestCase").
|
||||
testcase := hrp.TestCase{
|
||||
Config: hrp.NewConfig("TestCase").
|
||||
WithVariables(map[string]interface{}{
|
||||
"a": 12.3,
|
||||
"b": 3.45,
|
||||
"varFoo": "${max($a, $b)}",
|
||||
}),
|
||||
TestSteps: []IStep{
|
||||
NewStep("check variables").
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("check variables").
|
||||
WithVariables(map[string]interface{}{
|
||||
"a": 12.3,
|
||||
"b": 34.5,
|
||||
@@ -287,7 +285,7 @@ func TestSessionRunner(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
caseRunner, _ := NewRunner(t).NewCaseRunner(testcase)
|
||||
caseRunner, _ := hrp.NewRunner(t).NewCaseRunner(testcase)
|
||||
sessionRunner := caseRunner.NewSession()
|
||||
step := testcase.TestSteps[0]
|
||||
if !assert.Equal(t, step.Config().Variables["varFoo"], "${max($a, $b)}") {
|
||||
@@ -1,40 +1,42 @@
|
||||
package hrp
|
||||
package tests
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
hrp "github.com/httprunner/httprunner/v5"
|
||||
)
|
||||
|
||||
func TestRunCaseWithRendezvous(t *testing.T) {
|
||||
rendezvousBoundaryTestcase := &TestCase{
|
||||
Config: NewConfig("run request with functions").
|
||||
rendezvousBoundaryTestcase := &hrp.TestCase{
|
||||
Config: hrp.NewConfig("run request with functions").
|
||||
SetBaseURL("https://postman-echo.com").
|
||||
WithVariables(map[string]interface{}{
|
||||
"n": 5,
|
||||
"a": 12.3,
|
||||
"b": 3.45,
|
||||
}),
|
||||
TestSteps: []IStep{
|
||||
NewStep("test negative number").
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("test negative number").
|
||||
SetRendezvous("test negative number").
|
||||
WithUserNumber(-1),
|
||||
NewStep("test overflow number").
|
||||
hrp.NewStep("test overflow number").
|
||||
SetRendezvous("test overflow number").
|
||||
WithUserNumber(1000000),
|
||||
NewStep("test negative percent").
|
||||
hrp.NewStep("test negative percent").
|
||||
SetRendezvous("test very low percent").
|
||||
WithUserPercent(-0.5),
|
||||
NewStep("test very low percent").
|
||||
hrp.NewStep("test very low percent").
|
||||
SetRendezvous("test very low percent").
|
||||
WithUserPercent(0.00001),
|
||||
NewStep("test overflow percent").
|
||||
hrp.NewStep("test overflow percent").
|
||||
SetRendezvous("test overflow percent").
|
||||
WithUserPercent(1.5),
|
||||
NewStep("test conflict params").
|
||||
hrp.NewStep("test conflict params").
|
||||
SetRendezvous("test conflict params").
|
||||
WithUserNumber(1).
|
||||
WithUserPercent(0.123),
|
||||
NewStep("test negative timeout").
|
||||
hrp.NewStep("test negative timeout").
|
||||
SetRendezvous("test negative timeout").
|
||||
WithTimeout(-1000),
|
||||
},
|
||||
@@ -55,7 +57,7 @@ func TestRunCaseWithRendezvous(t *testing.T) {
|
||||
{number: 100, percent: 1, timeout: 5000},
|
||||
}
|
||||
|
||||
rendezvousList := InitRendezvous(rendezvousBoundaryTestcase, 100)
|
||||
rendezvousList := hrp.InitRendezvous(rendezvousBoundaryTestcase, 100)
|
||||
|
||||
for i, r := range rendezvousList {
|
||||
if r.Number != expectedRendezvousParams[i].number {
|
||||
@@ -1,17 +1,15 @@
|
||||
package hrp
|
||||
package tests
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
hrp "github.com/httprunner/httprunner/v5"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
stepGET = NewStep("get with params").
|
||||
stepGET = hrp.NewStep("get with params").
|
||||
GET("/get").
|
||||
WithParams(map[string]interface{}{"foo1": "bar1", "foo2": "bar2"}).
|
||||
WithHeaders(map[string]string{"User-Agent": "HttpRunnerPlus"}).
|
||||
@@ -21,7 +19,7 @@ var (
|
||||
AssertEqual("headers.\"Content-Type\"", "application/json; charset=utf-8", "check header Content-Type").
|
||||
AssertEqual("body.args.foo1", "bar1", "check param foo1").
|
||||
AssertEqual("body.args.foo2", "bar2", "check param foo2")
|
||||
stepPOSTData = NewStep("post form data").
|
||||
stepPOSTData = hrp.NewStep("post form data").
|
||||
POST("/post").
|
||||
WithParams(map[string]interface{}{"foo1": "bar1", "foo2": "bar2"}).
|
||||
WithHeaders(map[string]string{"User-Agent": "HttpRunnerPlus", "Content-Type": "application/x-www-form-urlencoded"}).
|
||||
@@ -33,7 +31,7 @@ var (
|
||||
|
||||
func TestRunRequestGetToStruct(t *testing.T) {
|
||||
tStep := stepGET
|
||||
if tStep.Request.Method != httpGET {
|
||||
if tStep.Request.Method != hrp.HTTP_GET {
|
||||
t.Fatalf("tStep.Request.Method != GET")
|
||||
}
|
||||
if tStep.Request.URL != "/get" {
|
||||
@@ -48,7 +46,7 @@ func TestRunRequestGetToStruct(t *testing.T) {
|
||||
if tStep.Request.Cookies["user"] != "debugtalk" {
|
||||
t.Fatalf("tStep.Request.Cookies mismatch")
|
||||
}
|
||||
validator, ok := tStep.Validators[0].(Validator)
|
||||
validator, ok := tStep.Validators[0].(hrp.Validator)
|
||||
if !ok || validator.Check != "status_code" || validator.Expect != 200 {
|
||||
t.Fatalf("tStep.Validators mismatch")
|
||||
}
|
||||
@@ -56,7 +54,7 @@ func TestRunRequestGetToStruct(t *testing.T) {
|
||||
|
||||
func TestRunRequestPostDataToStruct(t *testing.T) {
|
||||
tStep := stepPOSTData
|
||||
if tStep.Request.Method != httpPOST {
|
||||
if tStep.Request.Method != hrp.HTTP_POST {
|
||||
t.Fatalf("tStep.Request.Method != POST")
|
||||
}
|
||||
if tStep.Request.URL != "/post" {
|
||||
@@ -74,18 +72,18 @@ func TestRunRequestPostDataToStruct(t *testing.T) {
|
||||
if tStep.Request.Body != "a=1&b=2" {
|
||||
t.Fatalf("tStep.Request.Data mismatch")
|
||||
}
|
||||
validator, ok := tStep.Validators[0].(Validator)
|
||||
validator, ok := tStep.Validators[0].(hrp.Validator)
|
||||
if !ok || validator.Check != "status_code" || validator.Expect != 200 {
|
||||
t.Fatalf("tStep.Validators mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunRequestStatOn(t *testing.T) {
|
||||
testcase := TestCase{
|
||||
Config: NewConfig("test").SetBaseURL("https://postman-echo.com"),
|
||||
TestSteps: []IStep{stepGET, stepPOSTData},
|
||||
testcase := hrp.TestCase{
|
||||
Config: hrp.NewConfig("test").SetBaseURL("https://postman-echo.com"),
|
||||
TestSteps: []hrp.IStep{stepGET, stepPOSTData},
|
||||
}
|
||||
caseRunner, _ := NewRunner(t).SetHTTPStatOn().NewCaseRunner(testcase)
|
||||
caseRunner, _ := hrp.NewRunner(t).SetHTTPStatOn().NewCaseRunner(testcase)
|
||||
sessionRunner := caseRunner.NewSession()
|
||||
summary, err := sessionRunner.Start(nil)
|
||||
if err != nil {
|
||||
@@ -162,15 +160,15 @@ func TestRunRequestStatOn(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRunCaseWithTimeout(t *testing.T) {
|
||||
r := NewRunner(t)
|
||||
r := hrp.NewRunner(t)
|
||||
|
||||
// global timeout
|
||||
testcase1 := &TestCase{
|
||||
Config: NewConfig("TestCase1").
|
||||
testcase1 := &hrp.TestCase{
|
||||
Config: hrp.NewConfig("TestCase1").
|
||||
SetRequestTimeout(10). // set global timeout to 10s
|
||||
SetBaseURL("https://postman-echo.com"),
|
||||
TestSteps: []IStep{
|
||||
NewStep("step1").
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("step1").
|
||||
GET("/delay/1").
|
||||
Validate().
|
||||
AssertEqual("status_code", 200, "check status code"),
|
||||
@@ -181,12 +179,12 @@ func TestRunCaseWithTimeout(t *testing.T) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
testcase2 := &TestCase{
|
||||
Config: NewConfig("TestCase2").
|
||||
testcase2 := &hrp.TestCase{
|
||||
Config: hrp.NewConfig("TestCase2").
|
||||
SetRequestTimeout(5). // set global timeout to 10s
|
||||
SetBaseURL("https://postman-echo.com"),
|
||||
TestSteps: []IStep{
|
||||
NewStep("step1").
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("step1").
|
||||
GET("/delay/10").
|
||||
Validate().
|
||||
AssertEqual("status_code", 200, "check status code"),
|
||||
@@ -198,12 +196,12 @@ func TestRunCaseWithTimeout(t *testing.T) {
|
||||
}
|
||||
|
||||
// step timeout
|
||||
testcase3 := &TestCase{
|
||||
Config: NewConfig("TestCase3").
|
||||
testcase3 := &hrp.TestCase{
|
||||
Config: hrp.NewConfig("TestCase3").
|
||||
SetRequestTimeout(10).
|
||||
SetBaseURL("https://postman-echo.com"),
|
||||
TestSteps: []IStep{
|
||||
NewStep("step2").
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("step2").
|
||||
GET("/delay/11").
|
||||
SetTimeout(15*time.Second). // set step timeout to 4s
|
||||
Validate().
|
||||
@@ -215,70 +213,3 @@ func TestRunCaseWithTimeout(t *testing.T) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchJmespath(t *testing.T) {
|
||||
testText := `{"a": {"b": "foo"}, "c": "bar", "d": {"e": [{"f": "foo"}, {"f": "bar"}]}}`
|
||||
testData := []struct {
|
||||
raw string
|
||||
expected string
|
||||
}{
|
||||
{"body.a.b", "foo"},
|
||||
{"body.c", "bar"},
|
||||
{"body.d.e[0].f", "foo"},
|
||||
{"body.d.e[1].f", "bar"},
|
||||
}
|
||||
resp := http.Response{}
|
||||
resp.Body = io.NopCloser(strings.NewReader(testText))
|
||||
respObj, err := newHttpResponseObject(t, newParser(), &resp)
|
||||
if err != nil {
|
||||
t.Fatal()
|
||||
}
|
||||
for _, data := range testData {
|
||||
if !assert.Equal(t, data.expected, respObj.searchJmespath(data.raw)) {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchRegexp(t *testing.T) {
|
||||
testText := `
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a href="/order/addToCart" style="color: white"><i class="fa fa-shopping-cart fa-2x"></i><span class="badge">0</span></a></li>
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#" style="color: white">
|
||||
Leo <i class="fa fa-cog fa-2x"></i><span class="caret"></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="/user/changePassword">Change Password</a></li>
|
||||
<li><a href="/user/addAddress">Shipping</a></li>
|
||||
<li><a href="/user/addCard">Payment</a></li>
|
||||
<li><a href="/order/orderHistory">Order History</a></li>
|
||||
<li><a href="/user/signOut">Sign Out</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li> </li>
|
||||
<li><a href="/user/signOut" style="color: white"><i class="fa fa-sign-out fa-2x"></i>
|
||||
Sign Out</a></li>
|
||||
</ul>
|
||||
`
|
||||
testData := []struct {
|
||||
raw string
|
||||
expected string
|
||||
}{
|
||||
{"/user/signOut\">(.*)</a></li>", "Sign Out"},
|
||||
{"<li><a href=\"/user/(.*)\" style", "signOut"},
|
||||
{" (.*) <i class=\"fa fa-cog fa-2x\"></i>", "Leo"},
|
||||
}
|
||||
// new response object
|
||||
resp := http.Response{}
|
||||
resp.Body = io.NopCloser(strings.NewReader(testText))
|
||||
respObj, err := newHttpResponseObject(t, newParser(), &resp)
|
||||
if err != nil {
|
||||
t.Fatal()
|
||||
}
|
||||
for _, data := range testData {
|
||||
if !assert.Equal(t, data.expected, respObj.searchRegexp(data.raw)) {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,87 +1,88 @@
|
||||
//go:build localtest
|
||||
|
||||
package hrp
|
||||
package tests
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
hrp "github.com/httprunner/httprunner/v5"
|
||||
"github.com/httprunner/httprunner/v5/uixt/option"
|
||||
)
|
||||
|
||||
func TestIOSSettingsAction(t *testing.T) {
|
||||
testCase := &TestCase{
|
||||
Config: NewConfig("ios ui action on Settings").
|
||||
testCase := &hrp.TestCase{
|
||||
Config: hrp.NewConfig("ios ui action on Settings").
|
||||
SetIOS(option.WithWDAPort(8700), option.WithWDAMjpegPort(8800)),
|
||||
TestSteps: []IStep{
|
||||
NewStep("launch Settings").
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("launch Settings").
|
||||
IOS().Home().TapByOCR("设置").
|
||||
Validate().
|
||||
AssertNameExists("飞行模式").
|
||||
AssertLabelExists("蓝牙").
|
||||
AssertOCRExists("个人热点"),
|
||||
NewStep("swipe up and down").
|
||||
hrp.NewStep("swipe up and down").
|
||||
IOS().SwipeUp().SwipeUp().SwipeDown(),
|
||||
},
|
||||
}
|
||||
err := NewRunner(t).Run(testCase)
|
||||
err := hrp.NewRunner(t).Run(testCase)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIOSSearchApp(t *testing.T) {
|
||||
testCase := &TestCase{
|
||||
Config: NewConfig("ios ui action on Search App 资源库"),
|
||||
TestSteps: []IStep{
|
||||
NewStep("进入 App 资源库 搜索框").
|
||||
testCase := &hrp.TestCase{
|
||||
Config: hrp.NewConfig("ios ui action on Search App 资源库"),
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("进入 App 资源库 搜索框").
|
||||
IOS().Home().SwipeLeft().SwipeLeft().TapByCV("dewey-search-field").
|
||||
Validate().
|
||||
AssertLabelExists("取消"),
|
||||
NewStep("搜索抖音").
|
||||
hrp.NewStep("搜索抖音").
|
||||
IOS().Input("抖音\n"),
|
||||
},
|
||||
}
|
||||
err := NewRunner(t).Run(testCase)
|
||||
err := hrp.NewRunner(t).Run(testCase)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIOSAppLaunch(t *testing.T) {
|
||||
testCase := &TestCase{
|
||||
Config: NewConfig("启动 & 关闭 App").
|
||||
testCase := &hrp.TestCase{
|
||||
Config: hrp.NewConfig("启动 & 关闭 App").
|
||||
SetIOS(option.WithWDAPort(8700), option.WithWDAMjpegPort(8800)),
|
||||
TestSteps: []IStep{
|
||||
NewStep("终止今日头条").
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("终止今日头条").
|
||||
IOS().AppTerminate("com.ss.iphone.article.News"),
|
||||
NewStep("启动今日头条").
|
||||
hrp.NewStep("启动今日头条").
|
||||
IOS().AppLaunch("com.ss.iphone.article.News"),
|
||||
NewStep("终止今日头条").
|
||||
hrp.NewStep("终止今日头条").
|
||||
IOS().AppTerminate("com.ss.iphone.article.News"),
|
||||
NewStep("启动今日头条").
|
||||
hrp.NewStep("启动今日头条").
|
||||
IOS().AppLaunch("com.ss.iphone.article.News"),
|
||||
},
|
||||
}
|
||||
err := NewRunner(t).Run(testCase)
|
||||
err := hrp.NewRunner(t).Run(testCase)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAndroidAction(t *testing.T) {
|
||||
testCase := &TestCase{
|
||||
Config: NewConfig("android ui action"),
|
||||
TestSteps: []IStep{
|
||||
NewStep("launch douyin").
|
||||
testCase := &hrp.TestCase{
|
||||
Config: hrp.NewConfig("android ui action"),
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("launch douyin").
|
||||
Android().Serial("xxx").TapByOCR("抖音").
|
||||
Validate().
|
||||
AssertNameExists("首页", "首页 tab 不存在").
|
||||
AssertNameExists("消息", "消息 tab 不存在"),
|
||||
NewStep("swipe up and down").
|
||||
hrp.NewStep("swipe up and down").
|
||||
Android().Serial("xxx").SwipeUp().SwipeUp().SwipeDown(),
|
||||
},
|
||||
}
|
||||
err := NewRunner(t).Run(testCase)
|
||||
err := hrp.NewRunner(t).Run(testCase)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1,23 +1,25 @@
|
||||
package hrp
|
||||
package tests
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
hrp "github.com/httprunner/httprunner/v5"
|
||||
)
|
||||
|
||||
func TestGenHTMLReport(t *testing.T) {
|
||||
summary := NewSummary()
|
||||
summary := hrp.NewSummary()
|
||||
|
||||
caseSummary1 := NewCaseSummary()
|
||||
stepResult1 := &StepResult{}
|
||||
caseSummary1 := hrp.NewCaseSummary()
|
||||
stepResult1 := &hrp.StepResult{}
|
||||
caseSummary1.AddStepResult(stepResult1)
|
||||
summary.AddCaseSummary(caseSummary1)
|
||||
|
||||
caseSummary2 := NewCaseSummary()
|
||||
stepResult2 := &StepResult{
|
||||
caseSummary2 := hrp.NewCaseSummary()
|
||||
stepResult2 := &hrp.StepResult{
|
||||
Name: "Test",
|
||||
StepType: StepTypeRequest,
|
||||
StepType: hrp.StepTypeRequest,
|
||||
Success: false,
|
||||
ContentSize: 0,
|
||||
Attachments: "err",
|
||||
@@ -37,22 +39,22 @@ func TestGenHTMLReport(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTestCaseSummary_AddStepResult(t *testing.T) {
|
||||
caseSummary := NewCaseSummary()
|
||||
stepResult1 := &StepResult{
|
||||
caseSummary := hrp.NewCaseSummary()
|
||||
stepResult1 := &hrp.StepResult{
|
||||
Name: "Test1",
|
||||
StepType: StepTypeRequest,
|
||||
StepType: hrp.StepTypeRequest,
|
||||
Success: true,
|
||||
ContentSize: 0,
|
||||
Attachments: "err",
|
||||
}
|
||||
caseSummary.AddStepResult(stepResult1)
|
||||
stepResult2 := &StepResult{
|
||||
stepResult2 := &hrp.StepResult{
|
||||
Name: "Test2",
|
||||
StepType: StepTypeTestCase,
|
||||
StepType: hrp.StepTypeTestCase,
|
||||
Success: false,
|
||||
ContentSize: 0,
|
||||
Attachments: "err",
|
||||
Data: []*StepResult{stepResult1},
|
||||
Data: []*hrp.StepResult{stepResult1},
|
||||
}
|
||||
caseSummary.AddStepResult(stepResult2)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package hrp
|
||||
package tests
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
hrp "github.com/httprunner/httprunner/v5"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -25,10 +25,10 @@ var (
|
||||
demoAPIGETPath = tmpl("/api/get.yml")
|
||||
)
|
||||
|
||||
var demoTestCaseWithThinkTimePath TestCasePath = hrpExamplesDir + "/think_time_test.json"
|
||||
var demoTestCaseWithThinkTimePath hrp.TestCasePath = hrpExamplesDir + "/think_time_test.json"
|
||||
|
||||
var demoTestCaseWithPlugin = &TestCase{
|
||||
Config: NewConfig("demo with complex mechanisms").
|
||||
var demoTestCaseWithPlugin = &hrp.TestCase{
|
||||
Config: hrp.NewConfig("demo with complex mechanisms").
|
||||
SetBaseURL("https://postman-echo.com").
|
||||
WithVariables(map[string]interface{}{ // global level variables
|
||||
"n": "${sum_ints(1, 2, 2)}",
|
||||
@@ -37,9 +37,9 @@ var demoTestCaseWithPlugin = &TestCase{
|
||||
"varFoo1": "${gen_random_string($n)}",
|
||||
"varFoo2": "${max($a, $b)}", // 12.3; eval with built-in function
|
||||
}),
|
||||
TestSteps: []IStep{
|
||||
NewStep("transaction 1 start").StartTransaction("tran1"), // start transaction
|
||||
NewStep("get with params").
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("transaction 1 start").StartTransaction("tran1"), // start transaction
|
||||
hrp.NewStep("get with params").
|
||||
WithVariables(map[string]interface{}{ // step level variables
|
||||
"n": 3, // inherit config level variables if not set in step level, a/varFoo1
|
||||
"b": 34.5, // override config level variable if existed, n/b/varFoo2
|
||||
@@ -59,8 +59,8 @@ var demoTestCaseWithPlugin = &TestCase{
|
||||
AssertLengthEqual("body.args.foo1", 5, "check args foo1"). // validate response body with jmespath
|
||||
AssertLengthEqual("$varFoo1", 5, "check args foo1"). // assert with extracted variable from current step
|
||||
AssertEqual("body.args.foo2", "34.5", "check args foo2"), // notice: request params value will be converted to string
|
||||
NewStep("transaction 1 end").EndTransaction("tran1"), // end transaction
|
||||
NewStep("post json data").
|
||||
hrp.NewStep("transaction 1 end").EndTransaction("tran1"), // end transaction
|
||||
hrp.NewStep("post json data").
|
||||
POST("/post").
|
||||
WithBody(map[string]interface{}{
|
||||
"foo1": "$varFoo1", // reference former extracted variable
|
||||
@@ -70,7 +70,7 @@ var demoTestCaseWithPlugin = &TestCase{
|
||||
AssertEqual("status_code", 200, "check status code").
|
||||
AssertLengthEqual("body.json.foo1", 5, "check args foo1").
|
||||
AssertEqual("body.json.foo2", 12.3, "check args foo2"),
|
||||
NewStep("post form data").
|
||||
hrp.NewStep("post form data").
|
||||
POST("/post").
|
||||
WithHeaders(map[string]string{"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}).
|
||||
WithBody(map[string]interface{}{
|
||||
@@ -84,15 +84,15 @@ var demoTestCaseWithPlugin = &TestCase{
|
||||
AssertEqual("status_code", 200, "check status code").
|
||||
AssertLengthEqual("body.form.foo1", 5, "check args foo1").
|
||||
AssertEqual("body.form.foo2", "12.3", "check args foo2"), // form data will be converted to string
|
||||
NewStep("get with timestamp").
|
||||
hrp.NewStep("get with timestamp").
|
||||
GET("/get").WithParams(map[string]interface{}{"time": "$varTime"}).
|
||||
Validate().
|
||||
AssertLengthEqual("body.args.time", 13, "check extracted var timestamp"),
|
||||
},
|
||||
}
|
||||
|
||||
var demoTestCaseWithoutPlugin = &TestCase{
|
||||
Config: NewConfig("demo without custom function plugin").
|
||||
var demoTestCaseWithoutPlugin = &hrp.TestCase{
|
||||
Config: hrp.NewConfig("demo without custom function plugin").
|
||||
SetBaseURL("https://postman-echo.com").
|
||||
WithVariables(map[string]interface{}{ // global level variables
|
||||
"n": 5,
|
||||
@@ -101,9 +101,9 @@ var demoTestCaseWithoutPlugin = &TestCase{
|
||||
"varFoo1": "${gen_random_string($n)}",
|
||||
"varFoo2": "${max($a, $b)}", // 12.3; eval with built-in function
|
||||
}),
|
||||
TestSteps: []IStep{
|
||||
NewStep("transaction 1 start").StartTransaction("tran1"), // start transaction
|
||||
NewStep("get with params").
|
||||
TestSteps: []hrp.IStep{
|
||||
hrp.NewStep("transaction 1 start").StartTransaction("tran1"), // start transaction
|
||||
hrp.NewStep("get with params").
|
||||
WithVariables(map[string]interface{}{ // step level variables
|
||||
"n": 3, // inherit config level variables if not set in step level, a/varFoo1
|
||||
"b": 34.5, // override config level variable if existed, n/b/varFoo2
|
||||
@@ -121,8 +121,8 @@ var demoTestCaseWithoutPlugin = &TestCase{
|
||||
AssertLengthEqual("body.args.foo1", 5, "check args foo1"). // validate response body with jmespath
|
||||
AssertLengthEqual("$varFoo1", 5, "check args foo1"). // assert with extracted variable from current step
|
||||
AssertEqual("body.args.foo2", "34.5", "check args foo2"), // notice: request params value will be converted to string
|
||||
NewStep("transaction 1 end").EndTransaction("tran1"), // end transaction
|
||||
NewStep("post json data").
|
||||
hrp.NewStep("transaction 1 end").EndTransaction("tran1"), // end transaction
|
||||
hrp.NewStep("post json data").
|
||||
POST("/post").
|
||||
WithBody(map[string]interface{}{
|
||||
"foo1": "$varFoo1", // reference former extracted variable
|
||||
@@ -132,7 +132,7 @@ var demoTestCaseWithoutPlugin = &TestCase{
|
||||
AssertEqual("status_code", 200, "check status code").
|
||||
AssertLengthEqual("body.json.foo1", 5, "check args foo1").
|
||||
AssertEqual("body.json.foo2", 12.3, "check args foo2"),
|
||||
NewStep("post form data").
|
||||
hrp.NewStep("post form data").
|
||||
POST("/post").
|
||||
WithHeaders(map[string]string{"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}).
|
||||
WithBody(map[string]interface{}{
|
||||
@@ -146,7 +146,7 @@ var demoTestCaseWithoutPlugin = &TestCase{
|
||||
AssertEqual("status_code", 200, "check status code").
|
||||
AssertLengthEqual("body.form.foo1", 5, "check args foo1").
|
||||
AssertEqual("body.form.foo2", "12.3", "check args foo2"), // form data will be converted to string
|
||||
NewStep("get with timestamp").
|
||||
hrp.NewStep("get with timestamp").
|
||||
GET("/get").WithParams(map[string]interface{}{"time": "$varTime"}).
|
||||
Validate().
|
||||
AssertLengthEqual("body.args.time", 13, "check extracted var timestamp"),
|
||||
@@ -172,29 +172,3 @@ func TestGenDemoTestCase(t *testing.T) {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertCheckExpr(t *testing.T) {
|
||||
exprs := []struct {
|
||||
before string
|
||||
after string
|
||||
}{
|
||||
// normal check expression
|
||||
{"a.b.c", "a.b.c"},
|
||||
{"a.\"b-c\".d", "a.\"b-c\".d"},
|
||||
{"a.b-c.d", "a.b-c.d"},
|
||||
{"body.args.a[-1]", "body.args.a[-1]"},
|
||||
// check expression using regex
|
||||
{"covering (.*) testing,", "covering (.*) testing,"},
|
||||
{" (.*) a-b-c", " (.*) a-b-c"},
|
||||
// abnormal check expression
|
||||
{"headers.Content-Type", "headers.\"Content-Type\""},
|
||||
{"headers.\"Content-Type", "headers.\"Content-Type\""},
|
||||
{"headers.Content-Type\"", "headers.\"Content-Type\""},
|
||||
{"headers.User-Agent", "headers.\"User-Agent\""},
|
||||
}
|
||||
for _, expr := range exprs {
|
||||
if !assert.Equal(t, expr.after, convertJmespathExpr(expr.before)) {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user