def query_json(json_content, query, delimiter='.'): """ Do an xpath-like query with json_content. @param (json_content) json_content json_content = { "ids": [1, 2, 3, 4], "person": { "name": { "first_name": "Leo", "last_name": "Lee", }, "age": 29, "cities": ["Guangzhou", "Shenzhen"] } } @param (str) query "person.name.first_name" => "Leo" "person.cities.0" => "Guangzhou" @return queried result """ if json_content == "": raise exception.ResponseError("response content is empty!") try: for key in query.split(delimiter): if isinstance(json_content, list): json_content = json_content[int(key)] elif isinstance(json_content, (dict, CaseInsensitiveDict)): json_content = json_content[key] else: raise exception.ParseResponseError( "response content is in text format! failed to query key {}!".format(key)) except (KeyError, ValueError, IndexError): raise exception.ParseResponseError("failed to query json when extracting response!") return json_content
def validate(self, validators, variables_mapping): """ Bind named validators to value within the context. @param (list) validators [ {"check": "status_code", "comparator": "eq", "expect": 201}, {"check": "resp_body_success", "comparator": "eq", "expect": True} ] @param (dict) variables_mapping { "resp_body_success": True } @return (list) content differences [ { "check": "status_code", "comparator": "eq", "expect": 201, "value": 200 } ] """ for validator_dict in validators: check_item = validator_dict.get("check") if not check_item: raise exception.ParamsError( "check item invalid: {}".format(check_item)) if "expect" in validator_dict: expect_value = validator_dict.get("expect") elif "expected" in validator_dict: expect_value = validator_dict.get("expected") else: raise exception.ParamsError( "expected value missed in testcase validator!") comparator = validator_dict.get("comparator", "eq") if check_item in variables_mapping: validator_dict["actual_value"] = variables_mapping[check_item] else: try: validator_dict["actual_value"] = self.extract_field( check_item) except exception.ParseResponseError: raise exception.ParseResponseError( "failed to extract check item in response!") utils.match_expected(validator_dict["actual_value"], expect_value, comparator, check_item) return True
def eval_check_item(self, validator, resp_obj): """ evaluate check item in validator @param (dict) validator {"check": "status_code", "comparator": "eq", "expect": 201} {"check": "$resp_body_success", "comparator": "eq", "expect": True} @param (object) resp_obj @return (dict) validator info { "check": "status_code", "check_value": 200, "expect": 201, "comparator": "eq" } """ check_item = validator["check"] # check_item should only be the following 5 formats: # 1, variable reference, e.g. $token # 2, function reference, e.g. ${is_status_code_200($status_code)} # 3, dict or list, maybe containing variable/function reference, e.g. {"var": "$abc"} # 4, string joined by delimiter. e.g. "status_code", "headers.content-type" # 5, regex string, e.g. "LB[\d]*(.*)RB[\d]*" if isinstance(check_item, (dict, list)) \ or testcase.extract_variables(check_item) \ or testcase.extract_functions(check_item): # format 1/2/3 check_value = self.eval_content(check_item) else: try: # format 4/5 check_value = resp_obj.extract_field(check_item) except exception.ParseResponseError: msg = "failed to extract check item from response!\n" msg += "response content: {}".format(resp_obj.content) raise exception.ParseResponseError(msg) validator["check_value"] = check_value # expect_value should only be in 2 types: # 1, variable reference, e.g. $expect_status_code # 2, actual value, e.g. 200 expect_value = self.eval_content(validator["expect"]) validator["expect"] = expect_value validator["check_result"] = "unchecked" return validator
def eval_check_item(self, validator, resp_obj): """ evaluate check item in validator @param (dict) validator {"check": "status_code", "comparator": "eq", "expect": 201} {"check": "$resp_body_success", "comparator": "eq", "expect": True} @param (object) resp_obj @return (dict) validator info { "check": "status_code", "check_value": 200, "expect": 201, "comparator": "eq" } """ check_item = validator["check"] # check_item should only be in 3 types: # 1, variable reference, e.g. $token # 2, string joined by delimiter. e.g. "status_code", "headers.content-type" # 3, regex string, e.g. "LB[\d]*(.*)RB[\d]*" if testcase.extract_variables(check_item): # type 1 check_value = self.testcase_parser.eval_content_variables( check_item) else: try: # type 2 or type 3 check_value = resp_obj.extract_field(check_item) except exception.ParseResponseError: raise exception.ParseResponseError( "failed to extract check item in response!") validator["check_value"] = check_value # expect_value should only be in 2 types: # 1, variable reference, e.g. $expect_status_code # 2, actual value, e.g. 200 expect_value = self.testcase_parser.eval_content_variables( validator["expect"]) validator["expect"] = expect_value return validator
def parse_validator(self, validator, resp_obj): """ parse validator, validator maybe in two format @param (dict) validator 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]} @param (object) resp_obj @return (dict) validator info { "check_item": check_item, "check_value": check_value, "expect_value": expect_value, "comparator": comparator } """ if not isinstance(validator, dict): raise exception.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 exception.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 exception.ParamsError( "invalid validator: {}".format(validator)) check_item, expect_value = compare_values else: raise exception.ParamsError( "invalid validator: {}".format(validator)) # check_item should only be in 3 type: # 1, variable reference, e.g. $token # 2, string joined by delimiter. e.g. "status_code", "headers.content-type" # 3, regex string, e.g. "LB[\d]*(.*)RB[\d]*" if testcase.extract_variables(check_item): # type 1 check_value = self.testcase_parser.eval_content_variables( check_item) else: try: # type 2 or type 3 check_value = resp_obj.extract_field(check_item) except exception.ParseResponseError: raise exception.ParseResponseError( "failed to extract check item in response!") expect_value = self.testcase_parser.eval_content_variables( expect_value) validator_dict = { "check_item": check_item, "check_value": check_value, "expect_value": expect_value, "comparator": comparator } return validator_dict