From 6b2623b95fd8deda4223315973a53676f054ca75 Mon Sep 17 00:00:00 2001 From: debugtalk Date: Sun, 27 Mar 2022 13:05:20 +0800 Subject: [PATCH] fix: call referenced api/testcase with relative path --- .github/workflows/hrp-scaffold.yml | 16 ++- docs/CHANGELOG.md | 2 +- examples/hrp/demo_httprunner.json | 135 ------------------ examples/hrp/demo_httprunner.yaml | 81 ----------- examples/hrp/ref_api_test.yaml | 47 ------ examples/hrp/ref_testcase_test.json | 18 --- examples/hrp/ref_testcase_test.yaml | 11 -- examples/hrp/think_time_test.yaml | 40 ------ hrp/convert.go | 46 +++++- hrp/convert_test.go | 46 ++---- hrp/internal/builtin/utils.go | 12 +- .../internal/scaffold/templates}/api/get.json | 0 .../internal/scaffold/templates}/api/get.yml | 0 .../scaffold/templates}/api/post.json | 0 .../internal/scaffold/templates}/api/post.yml | 0 .../internal/scaffold/templates}/api/put.json | 0 .../internal/scaffold/templates}/api/put.yml | 0 .../templates/testcases/demo_ref_api.json | 0 hrp/models.go | 17 ++- hrp/parser_test.go | 9 +- hrp/runner_test.go | 80 ++++++++--- hrp/step.go | 21 ++- hrp/tests/compat_test.go | 25 ---- 23 files changed, 170 insertions(+), 436 deletions(-) delete mode 100644 examples/hrp/demo_httprunner.json delete mode 100644 examples/hrp/demo_httprunner.yaml delete mode 100644 examples/hrp/ref_api_test.yaml delete mode 100644 examples/hrp/ref_testcase_test.json delete mode 100644 examples/hrp/ref_testcase_test.yaml delete mode 100644 examples/hrp/think_time_test.yaml rename {examples/hrp => hrp/internal/scaffold/templates}/api/get.json (100%) rename {examples/hrp => hrp/internal/scaffold/templates}/api/get.yml (100%) rename {examples/hrp => hrp/internal/scaffold/templates}/api/post.json (100%) rename {examples/hrp => hrp/internal/scaffold/templates}/api/post.yml (100%) rename {examples/hrp => hrp/internal/scaffold/templates}/api/put.json (100%) rename {examples/hrp => hrp/internal/scaffold/templates}/api/put.yml (100%) rename examples/hrp/ref_api_test.json => hrp/internal/scaffold/templates/testcases/demo_ref_api.json (100%) delete mode 100644 hrp/tests/compat_test.go diff --git a/.github/workflows/hrp-scaffold.yml b/.github/workflows/hrp-scaffold.yml index de829199..0bf56c20 100644 --- a/.github/workflows/hrp-scaffold.yml +++ b/.github/workflows/hrp-scaffold.yml @@ -25,8 +25,11 @@ jobs: run: make build - name: Run start project run: ./output/hrp startproject demo - - name: Run demo tests + - name: Run generated demo tests run: ./output/hrp run demo/testcases/demo_with_funplugin.json demo/testcases/demo_requests.yml demo/testcases/demo_ref_testcase.yml + - name: Run demo in examples + run: | + ./output/hrp run examples/demo-with-py-plugin/testcases/demo_with_funplugin.json scaffold-with-go-plugin: strategy: @@ -47,8 +50,12 @@ jobs: run: make build - name: Run start project run: ./output/hrp startproject demo --go - - name: Run demo tests + - name: Run generated demo tests run: ./output/hrp run demo/testcases/demo_with_funplugin.json demo/testcases/demo_requests.yml demo/testcases/demo_ref_testcase.yml + - name: Run demo in examples + run: | + go build -o examples/demo-with-go-plugin/debugtalk.bin examples/demo-with-go-plugin/plugin/debugtalk.go + ./output/hrp run examples/demo-with-go-plugin/testcases/demo_with_funplugin.json scaffold-without-custom-plugin: strategy: @@ -69,5 +76,8 @@ jobs: run: make build - name: Run start project run: ./output/hrp startproject demo --ignore-plugin - - name: Run demo tests + - name: Run generated demo tests run: ./output/hrp run demo/testcases/demo_without_funplugin.json + - name: Run demo in examples + run: | + ./output/hrp run examples/demo-without-plugin/testcases/demo_without_funplugin.json diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 36731be9..c726e78b 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,6 +1,6 @@ # Release History -## 4.0.0 +## v4.0.0-alpha - refactor: merge [hrp] into httprunner v4, which will include golang and python dual engine diff --git a/examples/hrp/demo_httprunner.json b/examples/hrp/demo_httprunner.json deleted file mode 100644 index de017c96..00000000 --- a/examples/hrp/demo_httprunner.json +++ /dev/null @@ -1,135 +0,0 @@ -{ - "config": { - "name": "testcase description", - "variables": {}, - "verify": false - }, - "teststeps": [ - { - "name": "/get", - "request": { - "url": "https://postman-echo.com/get", - "params": { - "foo1": "HDnY8", - "foo2": "34.5" - }, - "method": "GET", - "headers": { - "Host": "postman-echo.com", - "User-Agent": "HttpRunnerPlus", - "Accept-Encoding": "gzip" - } - }, - "validate": [ - { - "eq": [ - "status_code", - 200 - ] - }, - { - "eq": [ - "headers.Content-Type", - "application/json; charset=utf-8" - ] - }, - { - "eq": [ - "body.url", - "https://postman-echo.com/get?foo1=HDnY8&foo2=34.5" - ] - } - ] - }, - { - "name": "/post", - "request": { - "url": "https://postman-echo.com/post", - "method": "POST", - "cookies": { - "sails.sid": "s%3Az_LpglkKxTvJ_eHVUH6V67drKp0AGWW-.PidabaXOnatLRP47hVyqqepl6BdrpEQzRlJQXtbIiwk" - }, - "headers": { - "Host": "postman-echo.com", - "User-Agent": "Go-http-client/1.1", - "Content-Length": "28", - "Content-Type": "application/json; charset=UTF-8", - "Cookie": "sails.sid=s%3Az_LpglkKxTvJ_eHVUH6V67drKp0AGWW-.PidabaXOnatLRP47hVyqqepl6BdrpEQzRlJQXtbIiwk", - "Accept-Encoding": "gzip" - }, - "json": { - "foo1": "HDnY8", - "foo2": 12.3 - } - }, - "validate": [ - { - "eq": [ - "status_code", - 200 - ] - }, - { - "eq": [ - "headers.Content-Type", - "application/json; charset=utf-8" - ] - }, - { - "eq": [ - "body.url", - "https://postman-echo.com/post" - ] - } - ] - }, - { - "name": "/post", - "request": { - "url": "https://postman-echo.com/post", - "method": "POST", - "cookies": { - "sails.sid": "s%3AS5e7w0zQ0xAsCwh9L8T6R7QLYCO7_gtD.r8%2B2w9IWqEIfuVkrZjnxzm2xADIk34zKAWXRPapr%2FAw" - }, - "headers": { - "Host": "postman-echo.com", - "User-Agent": "Go-http-client/1.1", - "Content-Length": "20", - "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", - "Cookie": "sails.sid=s%3AS5e7w0zQ0xAsCwh9L8T6R7QLYCO7_gtD.r8%2B2w9IWqEIfuVkrZjnxzm2xADIk34zKAWXRPapr%2FAw", - "Accept-Encoding": "gzip" - }, - "data": { - "foo1": "HDnY8", - "foo2": "12.3" - } - }, - "validate": [ - { - "eq": [ - "status_code", - 200 - ] - }, - { - "eq": [ - "headers.Content-Type", - "application/json; charset=utf-8" - ] - }, - { - "eq": [ - "body.data", - "" - ] - }, - { - "eq": [ - "body.url", - "https://postman-echo.com/post" - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/examples/hrp/demo_httprunner.yaml b/examples/hrp/demo_httprunner.yaml deleted file mode 100644 index 0f39723f..00000000 --- a/examples/hrp/demo_httprunner.yaml +++ /dev/null @@ -1,81 +0,0 @@ -config: - name: testcase description - variables: {} - verify: false -teststeps: -- name: /get - request: - headers: - Accept-Encoding: gzip - Host: postman-echo.com - User-Agent: HttpRunnerPlus - method: GET - params: - foo1: HDnY8 - foo2: '34.5' - url: https://postman-echo.com/get - validate: - - eq: - - status_code - - 200 - - eq: - - headers.Content-Type - - application/json; charset=utf-8 - - eq: - - body.url - - https://postman-echo.com/get?foo1=HDnY8&foo2=34.5 -- name: /post - request: - cookies: - sails.sid: s%3Az_LpglkKxTvJ_eHVUH6V67drKp0AGWW-.PidabaXOnatLRP47hVyqqepl6BdrpEQzRlJQXtbIiwk - headers: - Accept-Encoding: gzip - Content-Length: '28' - Content-Type: application/json; charset=UTF-8 - Cookie: sails.sid=s%3Az_LpglkKxTvJ_eHVUH6V67drKp0AGWW-.PidabaXOnatLRP47hVyqqepl6BdrpEQzRlJQXtbIiwk - Host: postman-echo.com - User-Agent: Go-http-client/1.1 - json: - foo1: HDnY8 - foo2: 12.3 - method: POST - url: https://postman-echo.com/post - validate: - - eq: - - status_code - - 200 - - eq: - - headers.Content-Type - - application/json; charset=utf-8 - - eq: - - body.url - - https://postman-echo.com/post -- name: /post - request: - cookies: - sails.sid: s%3AS5e7w0zQ0xAsCwh9L8T6R7QLYCO7_gtD.r8%2B2w9IWqEIfuVkrZjnxzm2xADIk34zKAWXRPapr%2FAw - data: - foo1: HDnY8 - foo2: '12.3' - headers: - Accept-Encoding: gzip - Content-Length: '20' - Content-Type: application/x-www-form-urlencoded; charset=UTF-8 - Cookie: sails.sid=s%3AS5e7w0zQ0xAsCwh9L8T6R7QLYCO7_gtD.r8%2B2w9IWqEIfuVkrZjnxzm2xADIk34zKAWXRPapr%2FAw - Host: postman-echo.com - User-Agent: Go-http-client/1.1 - method: POST - url: https://postman-echo.com/post - validate: - - eq: - - status_code - - 200 - - eq: - - headers.Content-Type - - application/json; charset=utf-8 - - eq: - - body.data - - '' - - eq: - - body.url - - https://postman-echo.com/post diff --git a/examples/hrp/ref_api_test.yaml b/examples/hrp/ref_api_test.yaml deleted file mode 100644 index c920aae0..00000000 --- a/examples/hrp/ref_api_test.yaml +++ /dev/null @@ -1,47 +0,0 @@ -config: - name: 'api test demo' - variables: - user_agent: iOS/10.3 - device_sn: TESTCASE_SETUP_XXX - os_platform: ios - app_version: 2.8.6 - base_url: 'https://postman-echo.com' - herader: - - Accept: '*/*' - Accept-Encoding: 'gzip, deflate, br' - Cache-Control: no-cache - Connection: keep-alive - Host: postman-echo.com - User-Agent: PostmanRuntime/7.28.4 - verify: false - export: - - session_token -teststeps: - - name: 'test api /get' - api: api/get.json - variables: - user_agent: iOS/10.4 - device_sn: $device_sn - os_platform: ios - app_version: 2.8.7 - extract: - session_token: 'body.headers."postman-token"' - - name: 'test api /post' - api: api/post.json - variables: - user_agent: iOS/10.5 - device_sn: $device_sn - os_platform: ios - app_version: 2.8.9 - validate: - - { eq: [ status_code, 200 ] } - - { eq: [ body.headers.postman-token, ea19464c-ddd4-4724-abe9-5e2b254c2723 ] } - - name: 'test api /put' - api: api/put.json - variables: - user_agent: iOS/10.6 - device_sn: $device_sn - os_platform: ios - app_version: 2.8.10 - extract: - session_token: 'body.headers."postman-token"' diff --git a/examples/hrp/ref_testcase_test.json b/examples/hrp/ref_testcase_test.json deleted file mode 100644 index 39bc01d6..00000000 --- a/examples/hrp/ref_testcase_test.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "config": { - "name": "reference testcase test", - "base_url": "https://postman-echo.com", - "variables": { - "os_platform": "ios" - } - }, - "teststeps": [ - { - "name": "run demo_httprunner.json", - "testcase": "demo_httprunner.json", - "variables": { - "os_platform": "$os_platform" - } - } - ] -} diff --git a/examples/hrp/ref_testcase_test.yaml b/examples/hrp/ref_testcase_test.yaml deleted file mode 100644 index f3811e1f..00000000 --- a/examples/hrp/ref_testcase_test.yaml +++ /dev/null @@ -1,11 +0,0 @@ -config: - name: "reference testcase test" - base_url: "https://postman-echo.com" - variables: - os_platform: 'ios' - -teststeps: - - name: run demo_httprunner.yaml - testcase: demo_httprunner.yaml - variables: - os_platform: $os_platform \ No newline at end of file diff --git a/examples/hrp/think_time_test.yaml b/examples/hrp/think_time_test.yaml deleted file mode 100644 index 9f2f5129..00000000 --- a/examples/hrp/think_time_test.yaml +++ /dev/null @@ -1,40 +0,0 @@ -config: - name: "think time test demo" - variables: - app_version: v1 - user_agent: iOS/10.3 - base_url: "https://postman-echo.com" - think_time: - strategy: random_percentage - setting: - min_percentage: 1.0 - max_percentage: 1.5 - limit: 4 - verify: False - -teststeps: - - name: get with params - request: - method: GET - url: /get - headers: - User-Agent: $user_agent,$app_version - validate: - - check: status_code - assert: equals - expect: 200 - msg: check status code - - name: think time 1 - think_time: - time: 3 - - name: post with params - request: - method: POST - url: /post - headers: - User-Agent: $user_agent,$app_version - validate: - - check: status_code - assert: equals - expect: 200 - msg: check status code \ No newline at end of file diff --git a/hrp/convert.go b/hrp/convert.go index 68297e04..3148ab56 100644 --- a/hrp/convert.go +++ b/hrp/convert.go @@ -2,9 +2,11 @@ package hrp import ( "fmt" + "os" "path/filepath" "strings" + "github.com/pkg/errors" "github.com/rs/zerolog/log" "github.com/httprunner/httprunner/hrp/internal/builtin" @@ -92,9 +94,21 @@ func (tc *TCase) ToTestCase() (*TestCase, error) { testCase := &TestCase{ Config: tc.Config, } + + // locate project root dir by plugin path + projectRootDir, err := getProjectRootDirPath(testCase.Config.Path) + if err != nil { + return nil, errors.Wrap(err, "failed to get project root dir") + } + log.Info().Str("dir", projectRootDir).Msg("located project root dir") + for _, step := range tc.TestSteps { if step.APIPath != "" { - path := filepath.Join(filepath.Dir(testCase.Config.Path), step.APIPath) + path := filepath.Join(projectRootDir, step.APIPath) + if !builtin.IsFilePathExists(path) { + return nil, errors.New("referenced api file not found: " + path) + } + refAPI := APIPath(path) step.APIContent = &refAPI apiContent, err := step.APIContent.ToAPI() @@ -106,7 +120,11 @@ func (tc *TCase) ToTestCase() (*TestCase, error) { step: step, }) } else if step.TestCasePath != "" { - path := filepath.Join(filepath.Dir(testCase.Config.Path), step.TestCasePath) + path := filepath.Join(projectRootDir, step.TestCasePath) + if !builtin.IsFilePathExists(path) { + return nil, errors.New("referenced testcase file not found: " + path) + } + refTestCase := TestCasePath(path) step.TestCaseContent = &refTestCase tc, err := step.TestCaseContent.ToTestCase() @@ -140,16 +158,29 @@ func (tc *TCase) ToTestCase() (*TestCase, error) { return testCase, nil } +func getProjectRootDirPath(path string) (rootDir string, err error) { + pluginPath, err := locatePlugin(path) + if err == nil { + rootDir = filepath.Dir(pluginPath) + return + } + + // failed to locate project root dir + // maybe project plugin debugtalk.xx is not exist + // use current dir instead + return os.Getwd() +} + // APIPath implements IAPI interface. type APIPath string -func (path *APIPath) ToString() string { +func (path *APIPath) GetPath() string { return fmt.Sprintf("%v", *path) } func (path *APIPath) ToAPI() (*API, error) { api := &API{} - apiPath := path.ToString() + apiPath := path.GetPath() err := builtin.LoadFile(apiPath, api) if err != nil { return nil, err @@ -161,22 +192,23 @@ func (path *APIPath) ToAPI() (*API, error) { // TestCasePath implements ITestCase interface. type TestCasePath string -func (path *TestCasePath) ToString() string { +func (path *TestCasePath) GetPath() string { return fmt.Sprintf("%v", *path) } func (path *TestCasePath) ToTestCase() (*TestCase, error) { tc := &TCase{} - casePath := path.ToString() + casePath := path.GetPath() err := builtin.LoadFile(casePath, tc) if err != nil { return nil, err } + err = convertCompatTestCase(tc) if err != nil { return nil, err } - tc.Config.Path = path.ToString() + tc.Config.Path = casePath testcase, err := tc.ToTestCase() if err != nil { return nil, err diff --git a/hrp/convert_test.go b/hrp/convert_test.go index 351aedf0..6c2d619b 100644 --- a/hrp/convert_test.go +++ b/hrp/convert_test.go @@ -8,20 +8,22 @@ import ( "github.com/httprunner/httprunner/hrp/internal/builtin" ) -const templatesDir = "internal/scaffold/templates/" +const ( + templatesDir = "internal/scaffold/templates/" + hrpExamplesDir = "../examples/hrp" +) var ( demoTestCaseWithPluginJSONPath TestCasePath = templatesDir + "testcases/demo_with_funplugin.json" demoTestCaseWithPluginYAMLPath TestCasePath = templatesDir + "testcases/demo_with_funplugin.yaml" demoTestCaseWithoutPluginJSONPath TestCasePath = templatesDir + "testcases/demo_without_funplugin.json" demoTestCaseWithoutPluginYAMLPath TestCasePath = templatesDir + "testcases/demo_without_funplugin.yaml" + demoTestCaseWithRefAPIPath TestCasePath = templatesDir + "testcases/demo_ref_api.json" + demoAPIGETPath APIPath = templatesDir + "/api/get.yml" ) var ( - demoRefAPIYAMLPath TestCasePath = "../examples/hrp/ref_api_test.yaml" - demoRefTestCaseJSONPath TestCasePath = "../examples/hrp/ref_testcase_test.json" - demoThinkTimeJsonPath TestCasePath = "../examples/hrp/think_time_test.json" - demoAPIYAMLPath APIPath = "../examples/hrp/api/put.yml" + demoTestCaseWithThinkTimePath TestCasePath = hrpExamplesDir + "/think_time_test.json" ) var demoTestCaseWithPlugin = &TestCase{ @@ -152,41 +154,21 @@ var demoTestCaseWithoutPlugin = &TestCase{ func TestGenDemoTestCase(t *testing.T) { tCase, _ := demoTestCaseWithPlugin.ToTCase() - err := builtin.Dump2JSON(tCase, demoTestCaseWithPluginJSONPath.ToString()) + err := builtin.Dump2JSON(tCase, demoTestCaseWithPluginJSONPath.GetPath()) if err != nil { t.Fail() } - err = builtin.Dump2YAML(tCase, demoTestCaseWithPluginYAMLPath.ToString()) + err = builtin.Dump2YAML(tCase, demoTestCaseWithPluginYAMLPath.GetPath()) if err != nil { t.Fail() } tCase, _ = demoTestCaseWithoutPlugin.ToTCase() - err = builtin.Dump2JSON(tCase, demoTestCaseWithoutPluginJSONPath.ToString()) + err = builtin.Dump2JSON(tCase, demoTestCaseWithoutPluginJSONPath.GetPath()) if err != nil { t.Fail() } - err = builtin.Dump2YAML(tCase, demoTestCaseWithoutPluginYAMLPath.ToString()) - if err != nil { - t.Fail() - } -} - -func TestJsonDemoWithPlugin(t *testing.T) { - buildHashicorpGoPlugin() - defer removeHashicorpGoPlugin() - - err := NewRunner(nil).Run(&demoTestCaseWithPluginJSONPath) // hrp.Run(testCase) - if err != nil { - t.Fail() - } -} - -func TestYamlDemoWithPlugin(t *testing.T) { - buildHashicorpGoPlugin() - defer removeHashicorpGoPlugin() - - err := NewRunner(nil).Run(&demoTestCaseWithPluginYAMLPath) // hrp.Run(testCase) + err = builtin.Dump2YAML(tCase, demoTestCaseWithoutPluginYAMLPath.GetPath()) if err != nil { t.Fail() } @@ -195,11 +177,11 @@ func TestYamlDemoWithPlugin(t *testing.T) { func TestLoadCase(t *testing.T) { tcJSON := &TCase{} tcYAML := &TCase{} - err := builtin.LoadFile(demoTestCaseWithPluginJSONPath.ToString(), tcJSON) + err := builtin.LoadFile(demoTestCaseWithPluginJSONPath.GetPath(), tcJSON) if !assert.NoError(t, err) { t.Fail() } - err = builtin.LoadFile(demoTestCaseWithPluginYAMLPath.ToString(), tcYAML) + err = builtin.LoadFile(demoTestCaseWithPluginYAMLPath.GetPath(), tcYAML) if !assert.NoError(t, err) { t.Fail() } @@ -218,7 +200,7 @@ func TestLoadCase(t *testing.T) { } } -func Test_convertCheckExpr(t *testing.T) { +func TestConvertCheckExpr(t *testing.T) { exprs := []struct { before string after string diff --git a/hrp/internal/builtin/utils.go b/hrp/internal/builtin/utils.go index 7d9bd4a8..d1701bb2 100644 --- a/hrp/internal/builtin/utils.go +++ b/hrp/internal/builtin/utils.go @@ -108,16 +108,16 @@ func CreateFile(filePath string, data string) error { return nil } -// isFilePathExists returns true if path exists, whether path is file or dir -func isPathExists(path string) bool { +// IsPathExists returns true if path exists, whether path is file or dir +func IsPathExists(path string) bool { if _, err := os.Stat(path); os.IsNotExist(err) { return false } return true } -// isFilePathExists returns true if path exists and path is file -func isFilePathExists(path string) bool { +// IsFilePathExists returns true if path exists and path is file +func IsFilePathExists(path string) bool { info, err := os.Stat(path) if err != nil { // path not exists @@ -133,10 +133,10 @@ func isFilePathExists(path string) bool { } func EnsureFolderExists(folderPath string) error { - if !isPathExists(folderPath) { + if !IsPathExists(folderPath) { err := CreateFolder(folderPath) return err - } else if isFilePathExists(folderPath) { + } else if IsFilePathExists(folderPath) { return fmt.Errorf("path %v should be directory", folderPath) } return nil diff --git a/examples/hrp/api/get.json b/hrp/internal/scaffold/templates/api/get.json similarity index 100% rename from examples/hrp/api/get.json rename to hrp/internal/scaffold/templates/api/get.json diff --git a/examples/hrp/api/get.yml b/hrp/internal/scaffold/templates/api/get.yml similarity index 100% rename from examples/hrp/api/get.yml rename to hrp/internal/scaffold/templates/api/get.yml diff --git a/examples/hrp/api/post.json b/hrp/internal/scaffold/templates/api/post.json similarity index 100% rename from examples/hrp/api/post.json rename to hrp/internal/scaffold/templates/api/post.json diff --git a/examples/hrp/api/post.yml b/hrp/internal/scaffold/templates/api/post.yml similarity index 100% rename from examples/hrp/api/post.yml rename to hrp/internal/scaffold/templates/api/post.yml diff --git a/examples/hrp/api/put.json b/hrp/internal/scaffold/templates/api/put.json similarity index 100% rename from examples/hrp/api/put.json rename to hrp/internal/scaffold/templates/api/put.json diff --git a/examples/hrp/api/put.yml b/hrp/internal/scaffold/templates/api/put.yml similarity index 100% rename from examples/hrp/api/put.yml rename to hrp/internal/scaffold/templates/api/put.yml diff --git a/examples/hrp/ref_api_test.json b/hrp/internal/scaffold/templates/testcases/demo_ref_api.json similarity index 100% rename from examples/hrp/ref_api_test.json rename to hrp/internal/scaffold/templates/testcases/demo_ref_api.json diff --git a/hrp/models.go b/hrp/models.go index 49398429..4b5068cc 100644 --- a/hrp/models.go +++ b/hrp/models.go @@ -193,6 +193,11 @@ type API struct { Extract map[string]string `json:"extract,omitempty" yaml:"extract,omitempty"` Validators []interface{} `json:"validate,omitempty" yaml:"validate,omitempty"` Export []string `json:"export,omitempty" yaml:"export,omitempty"` + Path string +} + +func (api *API) GetPath() string { + return api.Path } func (api *API) ToAPI() (*API, error) { @@ -210,6 +215,7 @@ type Validator struct { // IAPI represents interface for api, // includes API and APIPath. type IAPI interface { + GetPath() string ToAPI() (*API, error) } @@ -219,8 +225,8 @@ type TStep struct { Name string `json:"name" yaml:"name"` // required Request *Request `json:"request,omitempty" yaml:"request,omitempty"` APIPath string `json:"api,omitempty" yaml:"api,omitempty"` - TestCasePath string `json:"testcase,omitempty" yaml:"testcase,omitempty"` APIContent IAPI `json:"api_content,omitempty" yaml:"api_content,omitempty"` + TestCasePath string `json:"testcase,omitempty" yaml:"testcase,omitempty"` TestCaseContent ITestCase `json:"testcase_content,omitempty" yaml:"testcase_content,omitempty"` Transaction *Transaction `json:"transaction,omitempty" yaml:"transaction,omitempty"` Rendezvous *Rendezvous `json:"rendezvous,omitempty" yaml:"rendezvous,omitempty"` @@ -287,6 +293,10 @@ type TCase struct { TestSteps []*TStep `json:"teststeps" yaml:"teststeps"` } +func (tc *TCase) Path() string { + return tc.Config.Path +} + // IStep represents interface for all types for teststeps, includes: // StepRequest, StepRequestWithOptionalArgs, StepRequestValidation, StepRequestExtraction, // StepTestCaseWithOptionalArgs, @@ -300,6 +310,7 @@ type IStep interface { // ITestCase represents interface for testcases, // includes TestCase and TestCasePath. type ITestCase interface { + GetPath() string ToTestCase() (*TestCase, error) ToTCase() (*TCase, error) } @@ -311,6 +322,10 @@ type TestCase struct { TestSteps []IStep } +func (tc *TestCase) GetPath() string { + return tc.Config.Path +} + func (tc *TestCase) ToTestCase() (*TestCase, error) { return tc, nil } diff --git a/hrp/parser_test.go b/hrp/parser_test.go index 73a7bbd7..3ad0a2b4 100644 --- a/hrp/parser_test.go +++ b/hrp/parser_test.go @@ -1,6 +1,7 @@ package hrp import ( + "fmt" "sort" "testing" "time" @@ -742,7 +743,7 @@ func TestParseParameters(t *testing.T) { }{ { map[string]interface{}{ - "username-password": "${parameterize(../examples/hrp/account.csv)}", + "username-password": fmt.Sprintf("${parameterize(%s/account.csv)}", hrpExamplesDir), "user_agent": []interface{}{"IOS/10.1", "IOS/10.2"}}, 6, }, @@ -782,17 +783,17 @@ func TestParseParametersError(t *testing.T) { }{ { map[string]interface{}{ - "username_password": "${parameterize(../examples/hrp/account.csv)}", + "username_password": fmt.Sprintf("${parameterize(%s/account.csv)}", hrpExamplesDir), "user_agent": []interface{}{"IOS/10.1", "IOS/10.2"}}, }, { map[string]interface{}{ - "username-password": "${parameterize(../examples/hrp/account.csv)}", + "username-password": fmt.Sprintf("${parameterize(%s/account.csv)}", hrpExamplesDir), "user-agent": []interface{}{"IOS/10.1", "IOS/10.2"}}, }, { map[string]interface{}{ - "username-password": "${param(../examples/hrp/account.csv)}", + "username-password": fmt.Sprintf("${param(%s/account.csv)}", hrpExamplesDir), "user_agent": []interface{}{"IOS/10.1", "IOS/10.2"}}, }, } diff --git a/hrp/runner_test.go b/hrp/runner_test.go index b753ebf9..dcab96c5 100644 --- a/hrp/runner_test.go +++ b/hrp/runner_test.go @@ -40,14 +40,14 @@ func removeHashicorpPyPlugin() { os.Remove(templatesDir + "debugtalk.py") } -func TestHttpRunnerWithGoPlugin(t *testing.T) { +func TestRunCaseWithGoPlugin(t *testing.T) { buildHashicorpGoPlugin() defer removeHashicorpGoPlugin() assertRunTestCases(t) } -func TestHttpRunnerWithPythonPlugin(t *testing.T) { +func TestRunCaseWithPythonPlugin(t *testing.T) { buildHashicorpPyPlugin() defer removeHashicorpPyPlugin() @@ -59,19 +59,19 @@ func assertRunTestCases(t *testing.T) { Config: NewConfig("TestCase1"). SetBaseURL("http://httpbin.org"), TestSteps: []IStep{ - NewStep("headers"). + NewStep("testcase1-step1"). GET("/headers"). Validate(). AssertEqual("status_code", 200, "check status code"). AssertEqual("headers.\"Content-Type\"", "application/json", "check http response Content-Type"), - NewStep("user-agent"). + NewStep("testcase1-step2"). GET("/user-agent"). Validate(). AssertEqual("status_code", 200, "check status code"). AssertEqual("headers.\"Content-Type\"", "application/json", "check http response Content-Type"), - NewStep("TestCase3").CallRefCase( + NewStep("testcase1-step3").CallRefCase( &TestCase{ - Config: NewConfig("TestCase3").SetBaseURL("http://httpbin.org"), + Config: NewConfig("testcase1-step3-ref-case").SetBaseURL("http://httpbin.org"), TestSteps: []IStep{ NewStep("ip"). GET("/ip"). @@ -81,32 +81,23 @@ func assertRunTestCases(t *testing.T) { }, }, ), - NewStep("TestCase4").CallRefCase(&demoRefAPIYAMLPath), - NewStep("TestCase5").CallRefCase(&demoTestCaseWithPluginJSONPath), + NewStep("testcase1-step4").CallRefCase(&demoTestCaseWithPluginJSONPath), }, } testcase2 := &TestCase{ Config: NewConfig("TestCase2").SetWeight(3), } - testcase3 := &TestCase{ - Config: NewConfig("TestCase1"). - SetBaseURL("https://postman-echo.com"), - TestSteps: []IStep{ - NewStep("TestCase5").CallRefAPI(&demoAPIYAMLPath), - }, - } - testcase4 := &demoRefTestCaseJSONPath r := NewRunner(t) r.SetPluginLogOn() - err := r.Run(testcase1, testcase2, testcase3, testcase4) + err := r.Run(testcase1, testcase2) if err != nil { t.Fatalf("run testcase error: %v", err) } } -func TestInitRendezvous(t *testing.T) { - rendezvousBonudaryTestcase := &TestCase{ +func TestRunCaseWithRendezvous(t *testing.T) { + rendezvousBoundaryTestcase := &TestCase{ Config: NewConfig("run request with functions"). SetBaseURL("https://postman-echo.com"). WithVariables(map[string]interface{}{ @@ -155,7 +146,7 @@ func TestInitRendezvous(t *testing.T) { {number: 100, percent: 1, timeout: 5000}, } - rendezvousList := initRendezvous(rendezvousBonudaryTestcase, 100) + rendezvousList := initRendezvous(rendezvousBoundaryTestcase, 100) for i, r := range rendezvousList { if r.Number != expectedRendezvousParams[i].number { @@ -170,7 +161,7 @@ func TestInitRendezvous(t *testing.T) { } } -func TestThinkTime(t *testing.T) { +func TestRunCaseWithThinkTime(t *testing.T) { buildHashicorpGoPlugin() defer removeHashicorpGoPlugin() @@ -205,7 +196,8 @@ func TestThinkTime(t *testing.T) { { Config: NewConfig("TestCase5"), TestSteps: []IStep{ - NewStep("thinkTime").CallRefCase(&demoThinkTimeJsonPath), // think time: 3s, random pct: {"min_percentage":1, "max_percentage":1.5}, limit: 4s + // think time: 3s, random pct: {"min_percentage":1, "max_percentage":1.5}, limit: 4s + NewStep("thinkTime").CallRefCase(&demoTestCaseWithThinkTimePath), }, }, } @@ -247,3 +239,47 @@ func TestGenHTMLReport(t *testing.T) { t.Error(err) } } + +func TestRunCaseWithPluginJSON(t *testing.T) { + buildHashicorpGoPlugin() + defer removeHashicorpGoPlugin() + + err := NewRunner(nil).Run(&demoTestCaseWithPluginJSONPath) // hrp.Run(testCase) + if err != nil { + t.Fail() + } +} + +func TestRunCaseWithPluginYAML(t *testing.T) { + buildHashicorpGoPlugin() + defer removeHashicorpGoPlugin() + + err := NewRunner(nil).Run(&demoTestCaseWithPluginYAMLPath) // hrp.Run(testCase) + if err != nil { + t.Fail() + } +} + +func TestRunCaseWithRefAPI(t *testing.T) { + buildHashicorpGoPlugin() + defer removeHashicorpGoPlugin() + + err := NewRunner(nil).Run(&demoTestCaseWithRefAPIPath) + if err != nil { + t.Fail() + } + + testcase := &TestCase{ + Config: NewConfig("TestCase"). + SetBaseURL("https://postman-echo.com"), + TestSteps: []IStep{ + NewStep("run referenced api").CallRefAPI(&demoAPIGETPath), + }, + } + + r := NewRunner(t) + err = r.Run(testcase) + if err != nil { + t.Fail() + } +} diff --git a/hrp/step.go b/hrp/step.go index 829e9aad..f0dd63f9 100644 --- a/hrp/step.go +++ b/hrp/step.go @@ -1,6 +1,11 @@ package hrp -import "fmt" +import ( + "fmt" + "os" + + "github.com/rs/zerolog/log" +) // NewConfig returns a new constructed testcase config with specified testcase name. func NewConfig(name string) *TConfig { @@ -163,7 +168,12 @@ func (s *StepRequest) PATCH(url string) *StepRequestWithOptionalArgs { // CallRefCase calls a referenced testcase. func (s *StepRequest) CallRefCase(tc ITestCase) *StepTestCaseWithOptionalArgs { - s.step.TestCaseContent, _ = tc.ToTestCase() + var err error + s.step.TestCaseContent, err = tc.ToTestCase() + if err != nil { + log.Error().Err(err).Msg("failed to load testcase") + os.Exit(1) + } return &StepTestCaseWithOptionalArgs{ step: s.step, } @@ -171,7 +181,12 @@ func (s *StepRequest) CallRefCase(tc ITestCase) *StepTestCaseWithOptionalArgs { // CallRefAPI calls a referenced api. func (s *StepRequest) CallRefAPI(api IAPI) *StepAPIWithOptionalArgs { - s.step.APIContent, _ = api.ToAPI() + var err error + s.step.APIContent, err = api.ToAPI() + if err != nil { + log.Error().Err(err).Msg("failed to load api") + os.Exit(1) + } return &StepAPIWithOptionalArgs{ step: s.step, } diff --git a/hrp/tests/compat_test.go b/hrp/tests/compat_test.go deleted file mode 100644 index 74dc5fe0..00000000 --- a/hrp/tests/compat_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package tests - -import ( - "testing" - - "github.com/httprunner/httprunner/hrp" -) - -// generated by examples/data/har/demo.har using HttpRunner v3.1.6 -var ( - demoHttpRunnerJSONPath hrp.TestCasePath = "../../examples/hrp/demo_httprunner.json" - demoHttpRunnerYAMLPath hrp.TestCasePath = "../../examples/hrp/demo_httprunner.yaml" -) - -func TestCompatTestCase(t *testing.T) { - err := hrp.NewRunner(t).Run(&demoHttpRunnerJSONPath) - if err != nil { - t.Fatalf("run testcase error: %v", err) - } - - err = hrp.NewRunner(t).Run(&demoHttpRunnerYAMLPath) - if err != nil { - t.Fatalf("run testcase error: %v", err) - } -}