feat: implement lazy parser for validators

This commit is contained in:
debugtalk
2019-04-08 12:12:09 +08:00
parent 0e663d19cb
commit 3d1c7f368c
15 changed files with 760 additions and 704 deletions

View File

@@ -4,7 +4,7 @@ import ast
import os
import re
from httprunner import exceptions, utils
from httprunner import exceptions, utils, validator
from httprunner.compat import basestring, builtin_str, numeric_types, str
# TODO: change variable notation from $var to {{var}}
@@ -105,65 +105,6 @@ def regex_findall_functions(content):
return []
def parse_validator(validator):
""" parse validator
Args:
validator (dict): validator maybe in two formats:
format1: this is kept for compatiblity with the previous versions.
{"check": "status_code", "comparator": "eq", "expect": 201}
{"check": "$resp_body_success", "comparator": "eq", "expect": True}
format2: recommended new version
{'eq': ['status_code', 201]}
{'eq': ['$resp_body_success', True]}
Returns
dict: validator info
{
"check": "status_code",
"expect": 201,
"comparator": "eq"
}
"""
if not isinstance(validator, dict):
raise exceptions.ParamsError("invalid validator: {}".format(validator))
if "check" in validator and len(validator) > 1:
# format1
check_item = validator.get("check")
if "expect" in validator:
expect_value = validator.get("expect")
elif "expected" in validator:
expect_value = validator.get("expected")
else:
raise exceptions.ParamsError("invalid validator: {}".format(validator))
comparator = validator.get("comparator", "eq")
elif len(validator) == 1:
# format2
comparator = list(validator.keys())[0]
compare_values = validator[comparator]
if not isinstance(compare_values, list) or len(compare_values) != 2:
raise exceptions.ParamsError("invalid validator: {}".format(validator))
check_item, expect_value = compare_values
else:
raise exceptions.ParamsError("invalid validator: {}".format(validator))
return {
"check": check_item,
"expect": expect_value,
"comparator": comparator
}
def parse_parameters(parameters, variables_mapping=None, functions_mapping=None):
""" parse parameters and generate cartesian product.
@@ -738,12 +679,9 @@ def _extend_with_api(test_dict, api_def_dict):
""" extend test with api definition, test will merge and override api definition.
Args:
test_dict (dict): test block
test_dict (dict): test block, this will override api_def_dict
api_def_dict (dict): api definition
Returns:
dict: extended test dict.
Examples:
>>> api_def_dict = {
"name": "get token 1",
@@ -756,6 +694,7 @@ def _extend_with_api(test_dict, api_def_dict):
"validate": [{'eq': ['status_code', 201]}, {'len_eq': ['content.token', 16]}]
}
>>> _extend_with_api(test_dict, api_def_dict)
>>> print(test_dict)
{
"name": "get token 2",
"request": {...},
@@ -764,9 +703,8 @@ def _extend_with_api(test_dict, api_def_dict):
}
"""
# override name
api_def_name = api_def_dict.pop("name", "")
test_dict["name"] = test_dict.get("name") or api_def_name
# override api name
test_dict.setdefault("name", api_def_dict.pop("name", ""))
# override variables
def_variables = api_def_dict.pop("variables", [])
@@ -777,16 +715,12 @@ def _extend_with_api(test_dict, api_def_dict):
# merge & override validators TODO: relocate
def_raw_validators = api_def_dict.pop("validate", [])
ref_raw_validators = test_dict.get("validate", [])
def_validators = [
parse_validator(validator)
for validator in def_raw_validators
validator.uniform_validator(_validator)
for _validator in def_raw_validators
]
ref_validators = [
parse_validator(validator)
for validator in ref_raw_validators
]
test_dict["validate"] = utils.extend_validators(
ref_validators = test_dict.pop("validate", [])
test_dict["validate"] = validator.extend_validators(
def_validators,
ref_validators
)
@@ -798,7 +732,7 @@ def _extend_with_api(test_dict, api_def_dict):
test_dict.get("extract", {})
)
# TODO: merge & override request
# merge & override request
test_dict["request"] = api_def_dict.pop("request", {})
# base_url & verify: priority api_def_dict > test_dict
@@ -824,8 +758,6 @@ def _extend_with_api(test_dict, api_def_dict):
# TODO: extend with other api definition items, e.g. times
test_dict.update(api_def_dict)
return test_dict
def _extend_with_testcase(test_dict, testcase_def_dict):
""" extend test with testcase definition
@@ -923,6 +855,14 @@ def __prepare_testcase_tests(tests, config, project_mapping):
if (not test_dict.get("base_url")) and config_base_url:
test_dict["base_url"] = config_base_url
# unify validators' format
if "validate" in test_dict:
ref_raw_validators = test_dict.pop("validate", [])
test_dict["validate"] = [
validator.uniform_validator(_validator)
for _validator in ref_raw_validators
]
if "testcase_def" in test_dict:
# test_dict is nested testcase
@@ -954,6 +894,27 @@ def __prepare_testcase_tests(tests, config, project_mapping):
check_variables_set = set(test_dict_variables.keys()) \
| set(session_variables.keys()) | {"request", "response"}
# convert validators to lazy function
validators = test_dict.pop("validate", [])
prepared_validators = []
for _validator in validators:
function_meta = {
"func_name": _validator["comparator"],
"args": [
_validator["check"],
_validator["expect"]
],
"kwargs": {}
}
prepared_validators.append(
LazyFunction(
function_meta,
functions,
check_variables_set
)
)
test_dict["validate"] = prepared_validators
# convert variables and functions to lazy object.
# raises VariableNotFound if undefined variable exists in test_dict
prepared_test_dict = prepare_lazy_data(