fix compat convert, add unittest

This commit is contained in:
buyuxiang
2022-03-03 18:31:10 +08:00
parent 1613eb4724
commit a3fafd8c40
9 changed files with 305 additions and 26 deletions

View File

@@ -6,7 +6,6 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/rs/zerolog/log"
"gopkg.in/yaml.v3"
@@ -80,48 +79,40 @@ func convertCompatTestCase(tc *TCase) (err error) {
// 2. deal with validators compatible with HttpRunner
for i, iValidator := range step.Validators {
validatorMap := iValidator.(map[string]interface{})
// check priority: HRP > HttpRunner
validator := Validator{}
if len(validatorMap) == 4 || len(validatorMap) == 3 {
_, checkExisted := validatorMap["check"]
_, assertExisted := validatorMap["assert"]
_, expectExisted := validatorMap["expect"]
// check priority: HRP > HttpRunner
if checkExisted && assertExisted && expectExisted {
// HRP validator format
validator.Check = validatorMap["check"].(string)
validator.Assert = validatorMap["assert"].(string)
validator.Expect = validatorMap["expect"]
if msg, exist := validatorMap["msg"]; exist {
if msg, existed := validatorMap["msg"]; existed {
validator.Message = msg.(string)
}
convertCompatHeader(&validator)
step.Validators[i] = validator
} else if len(validatorMap) == 1 {
// HttpRunner validator format
for assertMethod, iValidatorContent := range validatorMap {
checkAndExpect := iValidatorContent.([]interface{})
if len(checkAndExpect) != 2 {
return fmt.Errorf("unexpected validator format: %v", validatorMap)
}
validator.Check = checkAndExpect[0].(string)
validator.Assert = assertMethod
validator.Expect = checkAndExpect[1]
}
convertCompatHeader(&validator)
step.Validators[i] = validator
} else {
log.Error().Msgf("[convert compat testcase] unexpected validator format: %v", validatorMap)
step.Validators[i] = validator
return fmt.Errorf("unexpected validator format: %v", validatorMap)
}
}
}
return err
}
// convertCompatHeader deals with headers format in HttpRunner
// e.g. headers.Content-Type => headers.\"Content-Type\"
func convertCompatHeader(validator *Validator) {
if strings.Contains(validator.Check, "headers.") &&
!strings.Contains(validator.Check, "\"") &&
strings.Contains(validator.Check, "-") {
replacedHeader := fmt.Sprintf("headers.\"%s\"", validator.Check[len("headers."):])
validator.Check = replacedHeader
}
}
func (tc *TCase) ToTestCase() (*TestCase, error) {
testCase := &TestCase{
Config: tc.Config,

View File

@@ -1,6 +1,6 @@
# Release History
## v0.6.3 (2022-02-22)
## v0.6.3 (2022-03-03)
- feat: support customized setup/teardown hooks (variable assignment not supported)
- compat: support testcase generated by HttpRunner

24
examples/compat_test.go Normal file
View File

@@ -0,0 +1,24 @@
package examples
import (
"testing"
"github.com/httprunner/hrp"
)
const demoHttpRunnerJSONPath = "../examples/demo_httprunner.json"
const demoHttpRunnerYAMLPath = "../examples/demo_httprunner.yaml"
func TestCompatTestCase(t *testing.T) {
testcaseFromJSON := &hrp.TestCasePath{Path: demoHttpRunnerJSONPath}
err := hrp.NewRunner(t).Run(testcaseFromJSON)
if err != nil {
t.Fatalf("run testcase error: %v", err)
}
testcaseFromYAML := &hrp.TestCasePath{Path: demoHttpRunnerYAMLPath}
err = hrp.NewRunner(t).Run(testcaseFromYAML)
if err != nil {
t.Fatalf("run testcase error: %v", err)
}
}

View File

@@ -0,0 +1,135 @@
{
"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"
]
}
]
}
]
}

View File

@@ -0,0 +1,81 @@
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

View File

@@ -1,10 +1,11 @@
package har2case
import (
"github.com/httprunner/hrp"
"testing"
"github.com/stretchr/testify/assert"
"github.com/httprunner/hrp"
)
var (
@@ -99,13 +100,16 @@ func TestMakeTestCase(t *testing.T) {
}
// make validators
if validator, ok := tCase.TestSteps[0].Validators[0].(hrp.Validator); !ok || !assert.Equal(t, "status_code", validator.Check) {
validator, ok := tCase.TestSteps[0].Validators[0].(hrp.Validator)
if !ok || !assert.Equal(t, "status_code", validator.Check) {
t.Fail()
}
if validator, ok := tCase.TestSteps[0].Validators[1].(hrp.Validator); !ok || !assert.Equal(t, "headers.\"Content-Type\"", validator.Check) {
validator, ok = tCase.TestSteps[0].Validators[1].(hrp.Validator)
if !ok || !assert.Equal(t, "headers.\"Content-Type\"", validator.Check) {
t.Fail()
}
if validator, ok := tCase.TestSteps[0].Validators[2].(hrp.Validator); !ok || !assert.Equal(t, "body.url", validator.Check) {
validator, ok = tCase.TestSteps[0].Validators[2].(hrp.Validator)
if !ok || !assert.Equal(t, "body.url", validator.Check) {
t.Fail()
}
}

View File

@@ -185,6 +185,7 @@ func (v *responseObject) Validate(iValidators []interface{}, variablesMapping ma
}
func (v *responseObject) searchJmespath(expr string) interface{} {
expr = convertJmespath(expr)
checkValue, err := jmespath.Search(expr, v.respObjMeta)
if err != nil {
log.Error().Str("expr", expr).Err(err).Msg("search jmespath failed")
@@ -200,6 +201,20 @@ func (v *responseObject) searchJmespath(expr string) interface{} {
return checkValue
}
// convertJmespath deals with check expression including hyphen
func convertJmespath(checkExpr string) string {
if strings.Contains(checkExpr, textExtractorSubRegexp) {
return checkExpr
}
checkItems := strings.Split(checkExpr, ".")
for i, checkItem := range checkItems {
if strings.Contains(checkItem, "-") && !strings.Contains(checkItem, "\"") {
checkItems[i] = fmt.Sprintf("\"%s\"", checkItem)
}
}
return strings.Join(checkItems, ".")
}
func (v *responseObject) searchRegexp(expr string) interface{} {
respMap, ok := v.respObjMeta.(map[string]interface{})
if !ok {

View File

@@ -33,3 +33,30 @@ func TestSearchRegexp(t *testing.T) {
}
}
}
func Test_convertJmespath(t *testing.T) {
exprs := []struct {
before string
after string
}{
// normal check expression
{"a.b.c", "a.b.c"},
{"headers.\"Content-Type\"", "headers.\"Content-Type\""},
// check expression using regex
{"covering (.*) testing,", "covering (.*) testing,"},
{" (.*) a-b-c", " (.*) a-b-c"},
// abnormal check expression
{"-", "\"-\""},
{"b-c", "\"b-c\""},
{"a.b-c.d", "a.\"b-c\".d"},
{"a-b.c-d", "\"a-b\".\"c-d\""},
{"\"a-b\".c-d", "\"a-b\".\"c-d\""},
{"headers.Content-Type", "headers.\"Content-Type\""},
{"body.I-am-a-Key.name", "body.\"I-am-a-Key\".name"},
}
for _, expr := range exprs {
if !assert.Equal(t, convertJmespath(expr.before), expr.after) {
t.Fail()
}
}
}

View File

@@ -42,7 +42,8 @@ func TestRunRequestGetToStruct(t *testing.T) {
if tStep.Request.Cookies["user"] != "debugtalk" {
t.Fatalf("tStep.Request.Cookies mismatch")
}
if validator, ok := tStep.Validators[0].(Validator); !ok || validator.Check != "status_code" || validator.Expect != 200 {
validator, ok := tStep.Validators[0].(Validator)
if !ok || validator.Check != "status_code" || validator.Expect != 200 {
t.Fatalf("tStep.Validators mismatch")
}
}
@@ -67,7 +68,8 @@ func TestRunRequestPostDataToStruct(t *testing.T) {
if tStep.Request.Body != "a=1&b=2" {
t.Fatalf("tStep.Request.Data mismatch")
}
if validator, ok := tStep.Validators[0].(Validator); !ok || validator.Check != "status_code" || validator.Expect != 200 {
validator, ok := tStep.Validators[0].(Validator)
if !ok || validator.Check != "status_code" || validator.Expect != 200 {
t.Fatalf("tStep.Validators mismatch")
}
}