simplify jmespath compatibility conversion

This commit is contained in:
buyuxiang
2022-06-27 18:08:23 +08:00
parent 2d105248fb
commit 3f8aa2dc03
5 changed files with 39 additions and 66 deletions
@@ -52,7 +52,7 @@
"msg": "check status_code" "msg": "check status_code"
}, },
{ {
"check": "body.headers.postman-token", "check": "body.headers.\"postman-token\"",
"assert": "equal", "assert": "equal",
"expect": "ea19464c-ddd4-4724-abe9-5e2b254c2723", "expect": "ea19464c-ddd4-4724-abe9-5e2b254c2723",
"msg": "check body.headers.postman-token" "msg": "check body.headers.postman-token"
+11 -6
View File
@@ -199,6 +199,9 @@ func (tc *TCase) MakeCompat() (err error) {
func convertCompatRequestBody(request *Request) { func convertCompatRequestBody(request *Request) {
if request != nil && request.Body == nil { if request != nil && request.Body == nil {
if request.Json != nil { if request.Json != nil {
if request.Headers == nil {
request.Headers = make(map[string]string)
}
request.Headers["Content-Type"] = "application/json; charset=utf-8" request.Headers["Content-Type"] = "application/json; charset=utf-8"
request.Body = request.Json request.Body = request.Json
request.Json = nil request.Json = nil
@@ -228,7 +231,7 @@ func convertCompatValidator(Validators []interface{}) (err error) {
if iMsg, msgExisted := validatorMap["msg"]; msgExisted { if iMsg, msgExisted := validatorMap["msg"]; msgExisted {
validator.Message = iMsg.(string) validator.Message = iMsg.(string)
} }
validator.Check = convertCheckExpr(validator.Check) validator.Check = convertJmespathExpr(validator.Check)
Validators[i] = validator Validators[i] = validator
continue continue
} }
@@ -246,7 +249,7 @@ func convertCompatValidator(Validators []interface{}) (err error) {
validator.Message = validatorContent[2].(string) validator.Message = validatorContent[2].(string)
} }
} }
validator.Check = convertCheckExpr(validator.Check) validator.Check = convertJmespathExpr(validator.Check)
Validators[i] = validator Validators[i] = validator
continue continue
} }
@@ -258,18 +261,20 @@ func convertCompatValidator(Validators []interface{}) (err error) {
// convertExtract deals with extract expr including hyphen // convertExtract deals with extract expr including hyphen
func convertExtract(extract map[string]string) { func convertExtract(extract map[string]string) {
for key, value := range extract { for key, value := range extract {
extract[key] = convertCheckExpr(value) extract[key] = convertJmespathExpr(value)
} }
} }
// convertCheckExpr deals with check expression including hyphen // convertJmespathExpr deals with limited jmespath expression conversion
func convertCheckExpr(checkExpr string) string { func convertJmespathExpr(checkExpr string) string {
if strings.Contains(checkExpr, textExtractorSubRegexp) { if strings.Contains(checkExpr, textExtractorSubRegexp) {
return checkExpr return checkExpr
} }
checkItems := strings.Split(checkExpr, ".") checkItems := strings.Split(checkExpr, ".")
for i, checkItem := range checkItems { for i, checkItem := range checkItems {
if strings.Contains(checkItem, "-") && !strings.Contains(checkItem, "\"") { checkItem = strings.Trim(checkItem, "\"")
lowerItem := strings.ToLower(checkItem)
if strings.HasPrefix(lowerItem, "content-") || lowerItem == "user-agent" {
checkItems[i] = fmt.Sprintf("\"%s\"", checkItem) checkItems[i] = fmt.Sprintf("\"%s\"", checkItem)
} }
} }
+7 -8
View File
@@ -210,21 +210,20 @@ func TestConvertCheckExpr(t *testing.T) {
}{ }{
// normal check expression // normal check expression
{"a.b.c", "a.b.c"}, {"a.b.c", "a.b.c"},
{"headers.\"Content-Type\"", "headers.\"Content-Type\""}, {"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 // check expression using regex
{"covering (.*) testing,", "covering (.*) testing,"}, {"covering (.*) testing,", "covering (.*) testing,"},
{" (.*) a-b-c", " (.*) a-b-c"}, {" (.*) a-b-c", " (.*) a-b-c"},
// abnormal check expression // 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\""}, {"headers.Content-Type", "headers.\"Content-Type\""},
{"body.I-am-a-Key.name", "body.\"I-am-a-Key\".name"}, {"headers.\"Content-Type", "headers.\"Content-Type\""},
{"headers.Content-Type\"", "headers.\"Content-Type\""},
{"headers.User-Agent", "headers.\"User-Agent\""},
} }
for _, expr := range exprs { for _, expr := range exprs {
if !assert.Equal(t, convertCheckExpr(expr.before), expr.after) { if !assert.Equal(t, expr.after, convertJmespathExpr(expr.before)) {
t.Fatal() t.Fatal()
} }
} }
+5 -16
View File
@@ -14,7 +14,7 @@ from httprunner.utils import sort_dict_by_custom_order
def convert_variables( def convert_variables(
raw_variables: Union[Dict, Text], test_path: Text raw_variables: Union[Dict, Text], test_path: Text
) -> Dict[Text, Any]: ) -> Dict[Text, Any]:
if isinstance(raw_variables, Dict): if isinstance(raw_variables, Dict):
return raw_variables return raw_variables
@@ -54,24 +54,13 @@ def _convert_jmespath(raw: Text) -> Text:
elif raw.startswith("json"): elif raw.startswith("json"):
raw = f"body{raw[len('json'):]}" raw = f"body{raw[len('json'):]}"
raw_list = [] raw_list = raw.split(".")
for item in raw.split("."): for i, item in enumerate(raw_list):
item = item.strip('"')
if item.lower().startswith("content-") or item.lower() in ["user-agent"]: if item.lower().startswith("content-") or item.lower() in ["user-agent"]:
# add quotes for some field in white list # add quotes for some field in white list
# e.g. headers.Content-Type => headers."Content-Type" # e.g. headers.Content-Type => headers."Content-Type"
item = item.strip('"') raw_list[i] = f'"{item}"'
raw_list.append(f'"{item}"')
elif item.isdigit():
# convert lst.0.name to lst[0].name
if len(raw_list) == 0:
logger.error(f"Invalid jmespath: {raw}")
sys.exit(1)
last_item = raw_list.pop()
item = f"{last_item}[{item}]"
raw_list.append(item)
else:
raw_list.append(item)
return ".".join(raw_list) return ".".join(raw_list)
+15 -35
View File
@@ -30,47 +30,33 @@ class TestCompat(unittest.TestCase):
request_with_json_body = { request_with_json_body = {
"method": "POST", "method": "POST",
"url": "https://postman-echo.com/post", "url": "https://postman-echo.com/post",
"headers": { "headers": {"Content-Type": "application/json"},
"Content-Type": "application/json" "body": {"k1": "v1", "k2": "v2"},
},
"body": {
"k1": "v1",
"k2": "v2"
}
} }
self.assertEqual( self.assertEqual(
compat._convert_request(request_with_json_body), compat._convert_request(request_with_json_body),
{ {
"method": "POST", "method": "POST",
"url": "https://postman-echo.com/post", "url": "https://postman-echo.com/post",
"headers": { "headers": {"Content-Type": "application/json"},
"Content-Type": "application/json" "json": {"k1": "v1", "k2": "v2"},
}, },
"json": {
"k1": "v1",
"k2": "v2"
}
}
) )
request_with_text_body = { request_with_text_body = {
"method": "POST", "method": "POST",
"url": "https://postman-echo.com/post", "url": "https://postman-echo.com/post",
"headers": { "headers": {"Content-Type": "text/plain"},
"Content-Type": "text/plain" "body": "have a nice day",
},
"body": "have a nice day"
} }
self.assertEqual( self.assertEqual(
compat._convert_request(request_with_text_body), compat._convert_request(request_with_text_body),
{ {
"method": "POST", "method": "POST",
"url": "https://postman-echo.com/post", "url": "https://postman-echo.com/post",
"headers": { "headers": {"Content-Type": "text/plain"},
"Content-Type": "text/plain" "data": "have a nice day",
}, },
"data": "have a nice day"
}
) )
def test_convert_jmespath(self): def test_convert_jmespath(self):
@@ -85,10 +71,6 @@ class TestCompat(unittest.TestCase):
self.assertEqual( self.assertEqual(
compat._convert_jmespath('headers."Content-Type"'), 'headers."Content-Type"' compat._convert_jmespath('headers."Content-Type"'), 'headers."Content-Type"'
) )
self.assertEqual(
compat._convert_jmespath("body.data.buildings.0.building_id"),
"body.data.buildings[0].building_id",
)
self.assertEqual( self.assertEqual(
compat._convert_jmespath("body.users[-1]"), compat._convert_jmespath("body.users[-1]"),
"body.users[-1]", "body.users[-1]",
@@ -97,8 +79,6 @@ class TestCompat(unittest.TestCase):
compat._convert_jmespath("body.result.WorkNode_-1"), compat._convert_jmespath("body.result.WorkNode_-1"),
"body.result.WorkNode_-1", "body.result.WorkNode_-1",
) )
with self.assertRaises(SystemExit):
compat._convert_jmespath("2.buildings.0.building_id")
def test_convert_extractors(self): def test_convert_extractors(self):
self.assertEqual( self.assertEqual(
@@ -108,11 +88,11 @@ class TestCompat(unittest.TestCase):
{"varA": "body.varA", "varB": "body.varB"}, {"varA": "body.varA", "varB": "body.varB"},
) )
self.assertEqual( self.assertEqual(
compat._convert_extractors([{"varA": "content.0.varA"}]), compat._convert_extractors([{"varA": "content[0].varA"}]),
{"varA": "body[0].varA"}, {"varA": "body[0].varA"},
) )
self.assertEqual( self.assertEqual(
compat._convert_extractors({"varA": "content.0.varA"}), compat._convert_extractors({"varA": "content[0].varA"}),
{"varA": "body[0].varA"}, {"varA": "body[0].varA"},
) )
@@ -128,7 +108,7 @@ class TestCompat(unittest.TestCase):
[{"eq": ["body.abc", 201]}], [{"eq": ["body.abc", 201]}],
) )
self.assertEqual( self.assertEqual(
compat._convert_validators([{"eq": ["content.0.name", 201]}]), compat._convert_validators([{"eq": ["content[0].name", 201]}]),
[{"eq": ["body[0].name", 201]}], [{"eq": ["body[0].name", 201]}],
) )
@@ -142,7 +122,7 @@ class TestCompat(unittest.TestCase):
"headers": {"User-Agent": "HttpRunner/3.0"}, "headers": {"User-Agent": "HttpRunner/3.0"},
}, },
"extract": [{"varA": "content.varA"}, {"user_agent": "headers.User-Agent"}], "extract": [{"varA": "content.varA"}, {"user_agent": "headers.User-Agent"}],
"validate": [{"eq": ["content.varB", 200]}, {"lt": ["json.0.varC", 0]}], "validate": [{"eq": ["content.varB", 200]}, {"lt": ["json[0].varC", 0]}],
} }
self.assertEqual( self.assertEqual(
compat.ensure_testcase_v4_api(api_content), compat.ensure_testcase_v4_api(api_content),
@@ -191,7 +171,7 @@ class TestCompat(unittest.TestCase):
], ],
"validate": [ "validate": [
{"eq": ["content.varB", 200]}, {"eq": ["content.varB", 200]},
{"lt": ["json.0.varC", 0]}, {"lt": ["json[0].varC", 0]},
], ],
} }
], ],