From b9db874f38b3f2d72ebcd58d0cf67c6e8c83d721 Mon Sep 17 00:00:00 2001 From: "lilong.129" Date: Wed, 5 Mar 2025 11:45:59 +0800 Subject: [PATCH] refactor: move tests --- build.go | 4 +- build_test.go | 141 ------------ config.go | 24 +- internal/builtin/utils.go | 16 ++ internal/version/VERSION | 2 +- loader.go | 19 +- parameters.go | 58 ++--- parser.go | 6 +- parser_test.go | 211 +++++++++++++++++- plugin.go | 24 +- runner.go | 9 +- step_function.go | 3 +- step_request.go | 42 ++-- step_request_response_test.go | 1 - step_thinktime.go | 10 +- tests/build_test.go | 45 ++++ loader_test.go => tests/loader_test.go | 34 +-- .../parameters_test.go | 124 +++++----- plugin_test.go => tests/plugin_test.go | 18 +- runner_test.go => tests/runner_test.go | 134 ++++++----- .../step_rendezvous_test.go | 26 ++- .../step_request_test.go | 119 +++------- step_ui_test.go => tests/step_ui_test.go | 55 ++--- summary_test.go => tests/summary_test.go | 28 +-- testcase_test.go => tests/testcase_test.go | 68 ++---- 25 files changed, 617 insertions(+), 604 deletions(-) delete mode 100644 build_test.go delete mode 100644 step_request_response_test.go create mode 100644 tests/build_test.go rename loader_test.go => tests/loader_test.go (65%) rename parameters_test.go => tests/parameters_test.go (83%) rename plugin_test.go => tests/plugin_test.go (57%) rename runner_test.go => tests/runner_test.go (65%) rename step_rendezvous_test.go => tests/step_rendezvous_test.go (77%) rename step_request_test.go => tests/step_request_test.go (64%) rename step_ui_test.go => tests/step_ui_test.go (57%) rename summary_test.go => tests/summary_test.go (65%) rename testcase_test.go => tests/testcase_test.go (80%) diff --git a/build.go b/build.go index 974d0906..0ce77a56 100644 --- a/build.go +++ b/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" diff --git a/build_test.go b/build_test.go deleted file mode 100644 index 4b22b9ea..00000000 --- a/build_test.go +++ /dev/null @@ -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() - } -} diff --git a/config.go b/config.go index b6b1b6a8..d5dd7139 100644 --- a/config.go +++ b/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 ( diff --git a/internal/builtin/utils.go b/internal/builtin/utils.go index 5a8e23a7..3e49f202 100644 --- a/internal/builtin/utils.go +++ b/internal/builtin/utils.go @@ -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) diff --git a/internal/version/VERSION b/internal/version/VERSION index 89f028e2..6dc6201d 100644 --- a/internal/version/VERSION +++ b/internal/version/VERSION @@ -1 +1 @@ -v5.0.0+2503051104 +v5.0.0+2503051147 diff --git a/loader.go b/loader.go index e592c68d..2e25212e 100644 --- a/loader.go +++ b/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 -} diff --git a/parameters.go b/parameters.go index f57c338e..1de3d21c 100644 --- a/parameters.go +++ b/parameters.go @@ -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") diff --git a/parser.go b/parser.go index 317f6352..8a5cee32 100644 --- a/parser.go +++ b/parser.go @@ -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{} } diff --git a/parser_test.go b/parser_test.go index b007c5e6..b7cc49f7 100644 --- a/parser_test.go +++ b/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": ""}}, } - 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 := ` + +` + testData := []struct { + raw string + expected string + }{ + {"/user/signOut\">(.*)", "Sign Out"}, + {"
  • ", "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() + } +} diff --git a/plugin.go b/plugin.go index a941486b..30875888 100644 --- a/plugin.go +++ b/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 diff --git a/runner.go b/runner.go index 13cddccd..f850ebae 100644 --- a/runner.go +++ b/runner.go @@ -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). diff --git a/step_function.go b/step_function.go index 23407ecd..5436957a 100644 --- a/step_function.go +++ b/step_function.go @@ -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. diff --git a/step_request.go b/step_request.go index 5bd0212c..4a06ac6d 100644 --- a/step_request.go +++ b/step_request.go @@ -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, } } diff --git a/step_request_response_test.go b/step_request_response_test.go deleted file mode 100644 index d10a1454..00000000 --- a/step_request_response_test.go +++ /dev/null @@ -1 +0,0 @@ -package hrp diff --git a/step_thinktime.go b/step_thinktime.go index bfb986c3..596ad676 100644 --- a/step_thinktime.go +++ b/step_thinktime.go @@ -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 } diff --git a/tests/build_test.go b/tests/build_test.go new file mode 100644 index 00000000..010dd23a --- /dev/null +++ b/tests/build_test.go @@ -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() + } +} diff --git a/loader_test.go b/tests/loader_test.go similarity index 65% rename from loader_test.go rename to tests/loader_test.go index a870217a..31f678cb 100644 --- a/loader_test.go +++ b/tests/loader_test.go @@ -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() } diff --git a/parameters_test.go b/tests/parameters_test.go similarity index 83% rename from parameters_test.go rename to tests/parameters_test.go index 4d2781f2..2f4a927f 100644 --- a/parameters_test.go +++ b/tests/parameters_test.go @@ -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() } diff --git a/plugin_test.go b/tests/plugin_test.go similarity index 57% rename from plugin_test.go rename to tests/plugin_test.go index 27cbaa77..8aedd8b9 100644 --- a/plugin_test.go +++ b/tests/plugin_test.go @@ -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() } diff --git a/runner_test.go b/tests/runner_test.go similarity index 65% rename from runner_test.go rename to tests/runner_test.go index 4cdf4edd..c246f076 100644 --- a/runner_test.go +++ b/tests/runner_test.go @@ -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)}") { diff --git a/step_rendezvous_test.go b/tests/step_rendezvous_test.go similarity index 77% rename from step_rendezvous_test.go rename to tests/step_rendezvous_test.go index 220719ef..75e1d881 100644 --- a/step_rendezvous_test.go +++ b/tests/step_rendezvous_test.go @@ -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 { diff --git a/step_request_test.go b/tests/step_request_test.go similarity index 64% rename from step_request_test.go rename to tests/step_request_test.go index 4648d0a8..daeba0ad 100644 --- a/step_request_test.go +++ b/tests/step_request_test.go @@ -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 := ` - -` - testData := []struct { - raw string - expected string - }{ - {"/user/signOut\">(.*)
  • ", "Sign Out"}, - {"
  • ", "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() - } - } -} diff --git a/step_ui_test.go b/tests/step_ui_test.go similarity index 57% rename from step_ui_test.go rename to tests/step_ui_test.go index a316f5b0..2d8514bb 100644 --- a/step_ui_test.go +++ b/tests/step_ui_test.go @@ -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) } diff --git a/summary_test.go b/tests/summary_test.go similarity index 65% rename from summary_test.go rename to tests/summary_test.go index e055daf9..951fbc33 100644 --- a/summary_test.go +++ b/tests/summary_test.go @@ -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) diff --git a/testcase_test.go b/tests/testcase_test.go similarity index 80% rename from testcase_test.go rename to tests/testcase_test.go index b0c15dbb..019cd486 100644 --- a/testcase_test.go +++ b/tests/testcase_test.go @@ -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() - } - } -}