From 7b438e5cec8c967a76b8102312acce68aa8c2a8d Mon Sep 17 00:00:00 2001 From: "lilong.129" Date: Mon, 19 Aug 2024 19:42:20 +0800 Subject: [PATCH] refactor: merge TestCase with TCase, fix converters --- hrp/pkg/convert/from_curl.go | 6 +++--- hrp/pkg/convert/from_curl_test.go | 26 ++++++++++++------------ hrp/pkg/convert/from_har.go | 16 +++++++-------- hrp/pkg/convert/from_har_test.go | 28 +++++++++++++------------- hrp/pkg/convert/from_json.go | 6 +++--- hrp/pkg/convert/from_postman.go | 14 ++++++------- hrp/pkg/convert/from_postman_test.go | 28 +++++++++++++------------- hrp/pkg/convert/from_swagger.go | 2 +- hrp/pkg/convert/from_yaml.go | 4 ++-- hrp/pkg/convert/main.go | 4 ++-- hrp/pkg/convert/main_test.go | 20 +++++++++---------- hrp/testcase.go | 30 ++++++++++++++++++++++++++++ 12 files changed, 107 insertions(+), 77 deletions(-) diff --git a/hrp/pkg/convert/from_curl.go b/hrp/pkg/convert/from_curl.go index 4ec2c81e..434087a4 100644 --- a/hrp/pkg/convert/from_curl.go +++ b/hrp/pkg/convert/from_curl.go @@ -94,12 +94,12 @@ func init() { } // LoadCurlCase loads testcase from one or more curl commands in .txt file -func LoadCurlCase(path string) (*hrp.TCase, error) { +func LoadCurlCase(path string) (*hrp.TestCase, error) { cmds, err := readFileLines(path) if err != nil { return nil, err } - tCase := &hrp.TCase{ + tCase := &hrp.TestCase{ Config: &hrp.TConfig{ Name: "testcase converted from curl command", }, @@ -109,7 +109,7 @@ func LoadCurlCase(path string) (*hrp.TCase, error) { if err != nil { return nil, err } - tCase.TestSteps = append(tCase.TestSteps, tSteps...) + tCase.TSteps = append(tCase.TSteps, tSteps...) } err = tCase.MakeCompat() if err != nil { diff --git a/hrp/pkg/convert/from_curl_test.go b/hrp/pkg/convert/from_curl_test.go index a9b5f4f2..6fb8a92f 100644 --- a/hrp/pkg/convert/from_curl_test.go +++ b/hrp/pkg/convert/from_curl_test.go @@ -13,29 +13,29 @@ func TestLoadCurlCase(t *testing.T) { if !assert.NoError(t, err) { t.Fatal(err) } - if !assert.Equal(t, 6, len(tCase.TestSteps)) { + if !assert.Equal(t, 6, len(tCase.TSteps)) { t.Fatal() } // curl httpbin.org - if !assert.Equal(t, "curl httpbin.org", tCase.TestSteps[0].Name) { + if !assert.Equal(t, "curl httpbin.org", tCase.TSteps[0].Name) { t.Fatal() } - if !assert.EqualValues(t, "GET", tCase.TestSteps[0].Request.Method) { + if !assert.EqualValues(t, "GET", tCase.TSteps[0].Request.Method) { t.Fatal() } - if !assert.Equal(t, "http://httpbin.org", tCase.TestSteps[0].Request.URL) { + if !assert.Equal(t, "http://httpbin.org", tCase.TSteps[0].Request.URL) { t.Fatal() } // curl https://httpbin.org/get?key1=value1&key2=value2 - if !assert.Equal(t, "https://httpbin.org/get", tCase.TestSteps[1].Request.URL) { + if !assert.Equal(t, "https://httpbin.org/get", tCase.TSteps[1].Request.URL) { t.Fatal() } if !assert.Equal(t, map[string]interface{}{ "key1": "value1", "key2": "value2", - }, tCase.TestSteps[1].Request.Params) { + }, tCase.TSteps[1].Request.Params) { t.Fatal() } @@ -43,13 +43,13 @@ func TestLoadCurlCase(t *testing.T) { // -H "Authorization: Bearer b7d03a6947b217efb6f3ec3bd3504582" \ // -d '{"type":"A","name":"www","data":"162.10.66.0","priority":null,"port":null,"weight":null}' \ // "https://httpbin.org/post" - if !assert.EqualValues(t, "POST", tCase.TestSteps[2].Request.Method) { + if !assert.EqualValues(t, "POST", tCase.TSteps[2].Request.Method) { t.Fatal() } if !assert.Equal(t, map[string]string{ "Authorization": "Bearer b7d03a6947b217efb6f3ec3bd3504582", "Content-Type": "application/json", - }, tCase.TestSteps[2].Request.Headers) { + }, tCase.TSteps[2].Request.Headers) { t.Fatal() } if !assert.Equal(t, map[string]interface{}{ @@ -59,7 +59,7 @@ func TestLoadCurlCase(t *testing.T) { "priority": nil, "type": "A", "weight": nil, - }, tCase.TestSteps[2].Request.Body) { + }, tCase.TSteps[2].Request.Body) { t.Fatal() } @@ -68,7 +68,7 @@ func TestLoadCurlCase(t *testing.T) { "dummyName": "dummyFile", "file1": "@file1.txt", "file2": "@file2.txt", - }, tCase.TestSteps[3].Request.Upload) { + }, tCase.TSteps[3].Request.Upload) { t.Fatal() } @@ -84,7 +84,7 @@ func TestLoadCurlCase(t *testing.T) { "shipment[is_return]": "true", "shipment[parcel][id]": "prcl_WDv2VzHp", "shipment[to_address][id]": "adr_HrBKVA85", - }, tCase.TestSteps[4].Request.Body) { + }, tCase.TSteps[4].Request.Body) { t.Fatal() } @@ -92,13 +92,13 @@ func TestLoadCurlCase(t *testing.T) { // --data "key1=value+1&key2=value%3A2" if !assert.Equal(t, map[string]string{ "Content-Type": "application/x-www-form-urlencoded", - }, tCase.TestSteps[5].Request.Headers) { + }, tCase.TSteps[5].Request.Headers) { t.Fatal() } if !assert.Equal(t, map[string]interface{}{ "key1": "value 1", "key2": "value:2", - }, tCase.TestSteps[5].Request.Body) { + }, tCase.TSteps[5].Request.Body) { t.Fatal() } } diff --git a/hrp/pkg/convert/from_har.go b/hrp/pkg/convert/from_har.go index 7d004dbf..12122007 100644 --- a/hrp/pkg/convert/from_har.go +++ b/hrp/pkg/convert/from_har.go @@ -358,15 +358,15 @@ type TestResult struct { // ==================== model definition ends here ==================== -func LoadHARCase(path string) (*hrp.TCase, error) { +func LoadHARCase(path string) (*hrp.TestCase, error) { // load har file caseHAR, err := loadCaseHAR(path) if err != nil { return nil, err } - // convert to TCase format - return caseHAR.ToTCase() + // convert to TestCase format + return caseHAR.ToTestCase() } func loadCaseHAR(path string) (*CaseHar, error) { @@ -381,16 +381,16 @@ func loadCaseHAR(path string) (*CaseHar, error) { return caseHAR, nil } -// convert CaseHar to TCase format -func (c *CaseHar) ToTCase() (*hrp.TCase, error) { +// convert CaseHar to TestCase format +func (c *CaseHar) ToTestCase() (*hrp.TestCase, error) { teststeps, err := c.prepareTestSteps() if err != nil { return nil, err } - tCase := &hrp.TCase{ - Config: c.prepareConfig(), - TestSteps: teststeps, + tCase := &hrp.TestCase{ + Config: c.prepareConfig(), + TSteps: teststeps, } err = tCase.MakeCompat() if err != nil { diff --git a/hrp/pkg/convert/from_har_test.go b/hrp/pkg/convert/from_har_test.go index bd3fccd7..d9a34524 100644 --- a/hrp/pkg/convert/from_har_test.go +++ b/hrp/pkg/convert/from_har_test.go @@ -36,60 +36,60 @@ func TestLoadTCaseFromHAR(t *testing.T) { } // make request method - if !assert.EqualValues(t, "GET", tCase.TestSteps[0].Request.Method) { + if !assert.EqualValues(t, "GET", tCase.TSteps[0].Request.Method) { t.Fatal() } - if !assert.EqualValues(t, "POST", tCase.TestSteps[1].Request.Method) { + if !assert.EqualValues(t, "POST", tCase.TSteps[1].Request.Method) { t.Fatal() } // make request url - if !assert.Equal(t, "https://postman-echo.com/get", tCase.TestSteps[0].Request.URL) { + if !assert.Equal(t, "https://postman-echo.com/get", tCase.TSteps[0].Request.URL) { t.Fatal() } - if !assert.Equal(t, "https://postman-echo.com/post", tCase.TestSteps[1].Request.URL) { + if !assert.Equal(t, "https://postman-echo.com/post", tCase.TSteps[1].Request.URL) { t.Fatal() } // make request params - if !assert.Equal(t, "HDnY8", tCase.TestSteps[0].Request.Params["foo1"]) { + if !assert.Equal(t, "HDnY8", tCase.TSteps[0].Request.Params["foo1"]) { t.Fatal() } // make request cookies - if !assert.NotEmpty(t, tCase.TestSteps[1].Request.Cookies["sails.sid"]) { + if !assert.NotEmpty(t, tCase.TSteps[1].Request.Cookies["sails.sid"]) { t.Fatal() } // make request headers - if !assert.Equal(t, "HttpRunnerPlus", tCase.TestSteps[0].Request.Headers["User-Agent"]) { + if !assert.Equal(t, "HttpRunnerPlus", tCase.TSteps[0].Request.Headers["User-Agent"]) { t.Fatal() } - if !assert.Equal(t, "postman-echo.com", tCase.TestSteps[0].Request.Headers["Host"]) { + if !assert.Equal(t, "postman-echo.com", tCase.TSteps[0].Request.Headers["Host"]) { t.Fatal() } // make request data - if !assert.Equal(t, nil, tCase.TestSteps[0].Request.Body) { + if !assert.Equal(t, nil, tCase.TSteps[0].Request.Body) { t.Fatal() } - if !assert.Equal(t, map[string]interface{}{"foo1": "HDnY8", "foo2": 12.3}, tCase.TestSteps[1].Request.Body) { + if !assert.Equal(t, map[string]interface{}{"foo1": "HDnY8", "foo2": 12.3}, tCase.TSteps[1].Request.Body) { t.Fatal() } - if !assert.Equal(t, map[string]string{"foo1": "HDnY8", "foo2": "12.3"}, tCase.TestSteps[2].Request.Body) { + if !assert.Equal(t, map[string]string{"foo1": "HDnY8", "foo2": "12.3"}, tCase.TSteps[2].Request.Body) { t.Fatal() } // make validators - validator, ok := tCase.TestSteps[0].Validators[0].(hrp.Validator) + validator, ok := tCase.TSteps[0].Validators[0].(hrp.Validator) if !ok || !assert.Equal(t, "status_code", validator.Check) { t.Fatal() } - validator, ok = tCase.TestSteps[0].Validators[1].(hrp.Validator) + validator, ok = tCase.TSteps[0].Validators[1].(hrp.Validator) if !ok || !assert.Equal(t, "headers.\"Content-Type\"", validator.Check) { t.Fatal() } - validator, ok = tCase.TestSteps[0].Validators[2].(hrp.Validator) + validator, ok = tCase.TSteps[0].Validators[2].(hrp.Validator) if !ok || !assert.Equal(t, "body.url", validator.Check) { t.Fatal() } diff --git a/hrp/pkg/convert/from_json.go b/hrp/pkg/convert/from_json.go index b1c05ac5..96c7fdc3 100644 --- a/hrp/pkg/convert/from_json.go +++ b/hrp/pkg/convert/from_json.go @@ -8,15 +8,15 @@ import ( "github.com/httprunner/httprunner/v4/hrp/internal/builtin" ) -func LoadJSONCase(path string) (*hrp.TCase, error) { +func LoadJSONCase(path string) (*hrp.TestCase, error) { log.Info().Str("path", path).Msg("load json case file") - caseJSON := new(hrp.TCase) + caseJSON := new(hrp.TestCase) err := builtin.LoadFile(path, caseJSON) if err != nil { return nil, errors.Wrap(err, "load json file failed") } - if caseJSON.TestSteps == nil { + if caseJSON.TSteps == nil { return nil, errors.New("invalid json case file, missing teststeps") } diff --git a/hrp/pkg/convert/from_postman.go b/hrp/pkg/convert/from_postman.go index 8518789b..f6464aaa 100644 --- a/hrp/pkg/convert/from_postman.go +++ b/hrp/pkg/convert/from_postman.go @@ -112,15 +112,15 @@ var contentTypeMap = map[string]string{ "xml": "application/xml", } -func LoadPostmanCase(path string) (*hrp.TCase, error) { +func LoadPostmanCase(path string) (*hrp.TestCase, error) { log.Info().Str("path", path).Msg("load postman case file") casePostman, err := loadCasePostman(path) if err != nil { return nil, err } - // convert to TCase format - return casePostman.ToTCase() + // convert to TestCase format + return casePostman.ToTestCase() } func loadCasePostman(path string) (*CasePostman, error) { @@ -136,14 +136,14 @@ func loadCasePostman(path string) (*CasePostman, error) { return casePostman, nil } -func (c *CasePostman) ToTCase() (*hrp.TCase, error) { +func (c *CasePostman) ToTestCase() (*hrp.TestCase, error) { teststeps, err := c.prepareTestSteps() if err != nil { return nil, err } - tCase := &hrp.TCase{ - Config: c.prepareConfig(), - TestSteps: teststeps, + tCase := &hrp.TestCase{ + Config: c.prepareConfig(), + TSteps: teststeps, } err = tCase.MakeCompat() if err != nil { diff --git a/hrp/pkg/convert/from_postman_test.go b/hrp/pkg/convert/from_postman_test.go index 00e8a5d0..0683ac22 100644 --- a/hrp/pkg/convert/from_postman_test.go +++ b/hrp/pkg/convert/from_postman_test.go @@ -28,51 +28,51 @@ func TestMakeTestCaseFromCollection(t *testing.T) { t.Fatal() } // check method - if !assert.EqualValues(t, "GET", tCase.TestSteps[0].Request.Method) { + if !assert.EqualValues(t, "GET", tCase.TSteps[0].Request.Method) { t.Fatal() } - if !assert.EqualValues(t, "POST", tCase.TestSteps[1].Request.Method) { + if !assert.EqualValues(t, "POST", tCase.TSteps[1].Request.Method) { t.Fatal() } // check url - if !assert.Equal(t, "https://postman-echo.com/get", tCase.TestSteps[0].Request.URL) { + if !assert.Equal(t, "https://postman-echo.com/get", tCase.TSteps[0].Request.URL) { t.Fatal() } - if !assert.Equal(t, "https://postman-echo.com/post", tCase.TestSteps[1].Request.URL) { + if !assert.Equal(t, "https://postman-echo.com/post", tCase.TSteps[1].Request.URL) { t.Fatal() } // check params - if !assert.Equal(t, "v1", tCase.TestSteps[0].Request.Params["k1"]) { + if !assert.Equal(t, "v1", tCase.TSteps[0].Request.Params["k1"]) { t.Fatal() } // check cookies (pass, postman collection doesn't contain cookies) // check headers - if !assert.Equal(t, "application/x-www-form-urlencoded", tCase.TestSteps[2].Request.Headers["Content-Type"]) { + if !assert.Equal(t, "application/x-www-form-urlencoded", tCase.TSteps[2].Request.Headers["Content-Type"]) { t.Fatal() } - if !assert.Equal(t, "application/json", tCase.TestSteps[3].Request.Headers["Content-Type"]) { + if !assert.Equal(t, "application/json", tCase.TSteps[3].Request.Headers["Content-Type"]) { t.Fatal() } - if !assert.Equal(t, "text/plain", tCase.TestSteps[4].Request.Headers["Content-Type"]) { + if !assert.Equal(t, "text/plain", tCase.TSteps[4].Request.Headers["Content-Type"]) { t.Fatal() } - if !assert.Equal(t, "HttpRunner", tCase.TestSteps[5].Request.Headers["User-Agent"]) { + if !assert.Equal(t, "HttpRunner", tCase.TSteps[5].Request.Headers["User-Agent"]) { t.Fatal() } // check body - if !assert.Equal(t, nil, tCase.TestSteps[0].Request.Body) { + if !assert.Equal(t, nil, tCase.TSteps[0].Request.Body) { t.Fatal() } - if !assert.Equal(t, map[string]string{"k1": "v1", "k2": "v2"}, tCase.TestSteps[2].Request.Body) { + if !assert.Equal(t, map[string]string{"k1": "v1", "k2": "v2"}, tCase.TSteps[2].Request.Body) { t.Fatal() } - if !assert.Equal(t, map[string]interface{}{"k1": "v1", "k2": "v2"}, tCase.TestSteps[3].Request.Body) { + if !assert.Equal(t, map[string]interface{}{"k1": "v1", "k2": "v2"}, tCase.TSteps[3].Request.Body) { t.Fatal() } - if !assert.Equal(t, "have a nice day", tCase.TestSteps[4].Request.Body) { + if !assert.Equal(t, "have a nice day", tCase.TSteps[4].Request.Body) { t.Fatal() } - if !assert.Equal(t, nil, tCase.TestSteps[5].Request.Body) { + if !assert.Equal(t, nil, tCase.TSteps[5].Request.Body) { t.Fatal() } } diff --git a/hrp/pkg/convert/from_swagger.go b/hrp/pkg/convert/from_swagger.go index b4f5ad5f..7ec80cfc 100644 --- a/hrp/pkg/convert/from_swagger.go +++ b/hrp/pkg/convert/from_swagger.go @@ -8,7 +8,7 @@ import ( "github.com/httprunner/httprunner/v4/hrp/internal/builtin" ) -func LoadSwaggerCase(path string) (*hrp.TCase, error) { +func LoadSwaggerCase(path string) (*hrp.TestCase, error) { // load swagger file caseSwagger := new(spec.Swagger) err := builtin.LoadFile(path, caseSwagger) diff --git a/hrp/pkg/convert/from_yaml.go b/hrp/pkg/convert/from_yaml.go index b96f0a2d..b9095851 100644 --- a/hrp/pkg/convert/from_yaml.go +++ b/hrp/pkg/convert/from_yaml.go @@ -9,9 +9,9 @@ import ( "github.com/httprunner/httprunner/v4/hrp/internal/builtin" ) -func LoadYAMLCase(path string) (*hrp.TCase, error) { +func LoadYAMLCase(path string) (*hrp.TestCase, error) { // load yaml case file - caseJSON := new(hrp.TCase) + caseJSON := new(hrp.TestCase) err := builtin.LoadFile(path, caseJSON) if err != nil { return nil, errors.Wrap(err, "load yaml file failed") diff --git a/hrp/pkg/convert/main.go b/hrp/pkg/convert/main.go index 8e226e10..a0f1a4cf 100644 --- a/hrp/pkg/convert/main.go +++ b/hrp/pkg/convert/main.go @@ -114,7 +114,7 @@ type TCaseConverter struct { fromFile string profilePath string outputDir string - tCase *hrp.TCase + tCase *hrp.TestCase } // LoadCase loads source file and convert to TCase type @@ -206,7 +206,7 @@ func (c *TCaseConverter) overrideWithProfile(path string) error { } log.Info().Interface("profile", profile).Msg("override with profile") - for _, step := range c.tCase.TestSteps { + for _, step := range c.tCase.TSteps { // override original headers and cookies if profile.Override { step.Request.Headers = make(map[string]string) diff --git a/hrp/pkg/convert/main_test.go b/hrp/pkg/convert/main_test.go index 9ed3e432..5d0d46af 100644 --- a/hrp/pkg/convert/main_test.go +++ b/hrp/pkg/convert/main_test.go @@ -47,12 +47,12 @@ func TestLoadHARWithProfileOverride(t *testing.T) { for i := 0; i < 3; i++ { if !assert.Equal(t, map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - converter.tCase.TestSteps[i].Request.Headers) { + converter.tCase.TSteps[i].Request.Headers) { t.FailNow() } if !assert.Equal(t, map[string]string{"UserName": "debugtalk"}, - converter.tCase.TestSteps[i].Request.Cookies) { + converter.tCase.TSteps[i].Request.Cookies) { t.FailNow() } } @@ -60,8 +60,8 @@ func TestLoadHARWithProfileOverride(t *testing.T) { func TestMakeRequestWithProfile(t *testing.T) { caseConverter := &TCaseConverter{ - tCase: &hrp.TCase{ - TestSteps: []*hrp.TStep{ + tCase: &hrp.TestCase{ + TSteps: []*hrp.TStep{ { Request: &hrp.Request{ Method: hrp.HTTPMethod("POST"), @@ -89,20 +89,20 @@ func TestMakeRequestWithProfile(t *testing.T) { if !assert.Equal(t, map[string]string{ "Content-Type": "application/x-www-form-urlencoded", "User-Agent": "hrp", - }, caseConverter.tCase.TestSteps[0].Request.Headers) { + }, caseConverter.tCase.TSteps[0].Request.Headers) { t.Fatal() } if !assert.Equal(t, map[string]string{ "UserName": "debugtalk", "abc": "123", - }, caseConverter.tCase.TestSteps[0].Request.Cookies) { + }, caseConverter.tCase.TSteps[0].Request.Cookies) { t.Fatal() } } func TestMakeRequestWithProfileOverride(t *testing.T) { caseConverter := &TCaseConverter{ - tCase: &hrp.TCase{ - TestSteps: []*hrp.TStep{ + tCase: &hrp.TestCase{ + TSteps: []*hrp.TStep{ { Request: &hrp.Request{ Method: hrp.HTTPMethod("POST"), @@ -131,12 +131,12 @@ func TestMakeRequestWithProfileOverride(t *testing.T) { if !assert.Equal(t, map[string]string{ "Content-Type": "application/x-www-form-urlencoded", - }, caseConverter.tCase.TestSteps[0].Request.Headers) { + }, caseConverter.tCase.TSteps[0].Request.Headers) { t.Fatal() } if !assert.Equal(t, map[string]string{ "UserName": "debugtalk", - }, caseConverter.tCase.TestSteps[0].Request.Cookies) { + }, caseConverter.tCase.TSteps[0].Request.Cookies) { t.Fatal() } } diff --git a/hrp/testcase.go b/hrp/testcase.go index eb44464f..5b47225d 100644 --- a/hrp/testcase.go +++ b/hrp/testcase.go @@ -49,6 +49,36 @@ func (tc *TestCase) loadStruct() { } } +// MakeCompat converts TestCase compatible with Golang engine style +func (tc *TestCase) MakeCompat() (err error) { + defer func() { + if p := recover(); p != nil { + err = fmt.Errorf("[MakeCompat] convert compat testcase error: %v", p) + } + }() + for _, step := range tc.TSteps { + // 1. deal with request body compatibility + convertCompatRequestBody(step.Request) + + // 2. deal with validators compatibility + err = convertCompatValidator(step.Validators) + if err != nil { + return err + } + + // 3. deal with extract expr including hyphen + convertExtract(step.Extract) + + // 4. deal with mobile step compatibility + if step.Android != nil { + convertCompatMobileStep(step.Android) + } else if step.IOS != nil { + convertCompatMobileStep(step.IOS) + } + } + return nil +} + func (tc *TestCase) Dump2JSON(targetPath string) error { tc.loadStruct() err := builtin.Dump2JSON(tc, targetPath)