def extract_response(self, extractors): """ extract value from requests.Response and store in OrderedDict. Args: extractors (list): [ {"resp_status_code": "status_code"}, {"resp_headers_content_type": "headers.content-type"}, {"resp_content": "content"}, {"resp_content_person_first_name": "content.person.name.first_name"} ] Returns: OrderDict: variable binds ordered dict """ if not extractors: return {} logger.log_debug("start to extract from response object.") extracted_variables_mapping = OrderedDict() extract_binds_order_dict = utils.ensure_mapping_format(extractors) for key, field in extract_binds_order_dict.items(): extracted_variables_mapping[key] = self.extract_field(field) return extracted_variables_mapping
def parse_lazy_data(content, variables_mapping=None): """ parse lazy data with evaluated variables mapping. Notice: variables_mapping should not contain any variable or function. """ # TODO: refactor type check if content is None or isinstance(content, (numeric_types, bool, type)): return content elif isinstance(content, LazyString): variables_mapping = utils.ensure_mapping_format(variables_mapping or {}) return content.to_value(variables_mapping) elif isinstance(content, (list, set, tuple)): return [parse_lazy_data(item, variables_mapping) for item in content] elif isinstance(content, dict): parsed_content = {} for key, value in content.items(): parsed_key = parse_lazy_data(key, variables_mapping) parsed_value = parse_lazy_data(value, variables_mapping) parsed_content[parsed_key] = parsed_value return parsed_content return content
def update_session_variables(self, variables_mapping): """ update session with extracted variables mapping. these variables are valid in the whole running session. """ variables_mapping = utils.ensure_mapping_format(variables_mapping) self.session_variables_mapping.update(variables_mapping) self.test_variables_mapping.update(self.session_variables_mapping)
def _extend_with_testcase(test_dict, testcase_def_dict): """ extend test with testcase definition test will merge and override testcase config definition. Args: test_dict (dict): test block testcase_def_dict (dict): testcase definition Returns: dict: extended test dict. """ # override testcase config variables testcase_def_dict["config"].setdefault("variables", {}) testcase_def_variables = utils.ensure_mapping_format( testcase_def_dict["config"].get("variables", {})) testcase_def_variables.update(test_dict.pop("variables", {})) testcase_def_dict["config"]["variables"] = testcase_def_variables # override base_url, verify # priority: testcase config > testsuite tests test_base_url = test_dict.pop("base_url", "") if not testcase_def_dict["config"].get("base_url"): testcase_def_dict["config"]["base_url"] = test_base_url # override name test_name = test_dict.pop("name", None) \ or testcase_def_dict["config"].pop("name", None) \ or "testcase name undefined" # merge & override setup_hooks and teardown_hooks def_teardown_hooks = testcase_def_dict["config"].pop("teardown_hooks", []) ref_teardown_hooks = test_dict.pop("teardown_hooks", []) extended_teardown_hooks = def_teardown_hooks + ref_teardown_hooks if extended_teardown_hooks: testcase_def_dict["config"]["teardown_hooks"] = extended_teardown_hooks def_setup_hooks = testcase_def_dict["config"].pop("setup_hooks", []) ref_setup_hooks = test_dict.pop("setup_hooks", []) extended_setup_hooks = ref_setup_hooks + def_setup_hooks if extended_setup_hooks: testcase_def_dict["config"]["setup_hooks"] = extended_setup_hooks # override testcase config name, output, etc. testcase_def_dict["config"].update(test_dict) testcase_def_dict["config"]["name"] = test_name test_dict.clear() test_dict.update(testcase_def_dict)
def __prepare_config(config, project_mapping, session_variables_set=None): """ parse testcase/testsuite config. """ # get config variables raw_config_variables = config.pop("variables", {}) raw_config_variables_mapping = utils.ensure_mapping_format( raw_config_variables) override_variables = utils.deepcopy_dict(project_mapping.get("env", {})) functions = project_mapping.get("functions", {}) # override config variables with passed in variables raw_config_variables_mapping.update(override_variables) if raw_config_variables_mapping: config["variables"] = raw_config_variables_mapping check_variables_set = set(raw_config_variables_mapping.keys()) check_variables_set |= (session_variables_set or set()) prepared_config = prepare_lazy_data(config, functions, check_variables_set, cached=True) return prepared_config
def init_test_variables(self, variables_mapping=None): """ init test variables, called when each test(api) starts. variables_mapping will be evaluated first. Args: variables_mapping (dict) { "random": "${gen_random_string(5)}", "authorization": "${gen_md5($TOKEN, $data, $random)}", "data": '{"name": "user", "password": "******"}', "TOKEN": "debugtalk", } """ variables_mapping = variables_mapping or {} variables_mapping = utils.ensure_mapping_format(variables_mapping) variables_mapping.update(self.session_variables_mapping) parsed_variables_mapping = parser.parse_variables_mapping( variables_mapping) self.test_variables_mapping = {} # priority: extracted variable > teststep variable self.test_variables_mapping.update(parsed_variables_mapping) self.test_variables_mapping.update(self.session_variables_mapping)
def __prepare_testcase_tests(tests, config, project_mapping, session_variables_set=None): """ override tests with testcase config variables, base_url and verify. test maybe nested testcase. variables priority: testcase config > testcase test > testcase_def config > testcase_def test > api base_url priority: testcase test > testcase config > testsuite test > testsuite config > api verify priority: testcase teststep (api) > testcase config > testsuite config Args: tests (list): config (dict): project_mapping (dict): """ global temp_extracted_set config_variables = config.get("variables", {}) config_base_url = config.get("base_url", "") config_verify = config.get("verify", True) functions = project_mapping.get("functions", {}) prepared_testcase_tests = [] session_variables_set = set(config_variables.keys()) | ( session_variables_set or set()) | temp_extracted_set for test_dict in tests: teststep_variables_set = {"request", "response"} # 1, testcase config => testcase tests # override test_dict variables config_variables_tmp = utils.deepcopy_dict(config_variables) test_dict_variables = utils.extend_variables( config_variables_tmp, test_dict.pop("variables", {})) test_dict["variables"] = test_dict_variables # base_url & verify: priority test_dict > config 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 if "output" in test_dict: session_variables_set |= set(test_dict["output"]) # 2, testcase test_dict => testcase_def config testcase_def = test_dict.pop("testcase_def") _extend_with_testcase(test_dict, testcase_def) # verify priority: nested testcase config > testcase config test_dict["config"].setdefault("verify", config_verify) # 3, testcase_def config => testcase_def test_dict test_dict = _parse_testcase(test_dict, project_mapping, session_variables_set) elif "api_def" in test_dict: # test_dict has API reference # 2, test_dict => api api_def_dict = test_dict.pop("api_def") _extend_with_api(test_dict, api_def_dict) # current teststep variables teststep_variables_set |= set(test_dict.get("variables", {}).keys()) # verify priority: testcase teststep > testcase config if "request" in test_dict and "verify" not in test_dict["request"]: test_dict["request"]["verify"] = config_verify # move extracted variable to session variables if test_dict.get("extract", {}): extract_mapping = utils.ensure_mapping_format(test_dict["extract"]) session_variables_set |= set(extract_mapping.keys()) temp_extracted_set |= session_variables_set session_variables_set |= temp_extracted_set teststep_variables_set |= session_variables_set # 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, teststep_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(test_dict, functions, teststep_variables_set) prepared_testcase_tests.append(prepared_test_dict) return prepared_testcase_tests
def parse_parameters(parameters, variables_mapping=None, functions_mapping=None): """ parse parameters and generate cartesian product. Args: parameters (list) parameters: parameter name and value in list parameter value may be in three types: (1) data list, e.g. ["iOS/10.1", "iOS/10.2", "iOS/10.3"] (2) call built-in parameterize function, "${parameterize(account.csv)}" (3) call custom function in debugtalk.py, "${gen_app_version()}" variables_mapping (dict): variables mapping loaded from testcase config functions_mapping (dict): functions mapping loaded from debugtalk.py Returns: list: cartesian product list Examples: >>> parameters = [ {"user_agent": ["iOS/10.1", "iOS/10.2", "iOS/10.3"]}, {"username-password": "******"}, {"app_version": "${gen_app_version()}"} ] >>> parse_parameters(parameters) """ variables_mapping = variables_mapping or {} functions_mapping = functions_mapping or {} parsed_parameters_list = [] parameters = utils.ensure_mapping_format(parameters) cartesian = parameters.pop('cartesian', None) for parameter_name, parameter_content in parameters.items(): parameter_name_list = parameter_name.split("-") if isinstance(parameter_content, list): # (1) data list # e.g. {"app_version": ["2.8.5", "2.8.6"]} # => [{"app_version": "2.8.5", "app_version": "2.8.6"}] # e.g. {"username-password": [["user1", "111111"], ["test2", "222222"]} # => [{"username": "******", "password": "******"}, {"username": "******", "password": "******"}] parameter_content_list = [] for parameter_item in parameter_content: if not isinstance(parameter_item, (list, tuple)): # "2.8.5" => ["2.8.5"] parameter_item = [parameter_item] # ["app_version"], ["2.8.5"] => {"app_version": "2.8.5"} # ["username", "password"], ["user1", "111111"] => {"username": "******", "password": "******"} parameter_content_dict = dict( zip(parameter_name_list, parameter_item)) parameter_content_list.append(parameter_content_dict) else: # (2) & (3) parsed_variables_mapping = parse_variables_mapping( variables_mapping) parsed_parameter_content = eval_lazy_data( parameter_content, parsed_variables_mapping, functions_mapping) if not isinstance(parsed_parameter_content, list): raise exceptions.ParamsError("parameters syntax error!") parameter_content_list = [] for parameter_item in parsed_parameter_content: if isinstance(parameter_item, dict): # get subset by parameter name # {"app_version": "${gen_app_version()}"} # gen_app_version() => [{'app_version': '2.8.5'}, {'app_version': '2.8.6'}] # {"username-password": "******"} # get_account() => [ # {"username": "******", "password": "******"}, # {"username": "******", "password": "******"} # ] parameter_dict = { key: parameter_item[key] for key in parameter_name_list } elif isinstance(parameter_item, (list, tuple)): # {"username-password": "******"} # get_account() => [("user1", "111111"), ("user2", "222222")] parameter_dict = dict( zip(parameter_name_list, parameter_item)) elif len(parameter_name_list) == 1: # {"user_agent": "${get_user_agent()}"} # get_user_agent() => ["iOS/10.1", "iOS/10.2"] parameter_dict = {parameter_name_list[0]: parameter_item} parameter_content_list.append(parameter_dict) parsed_parameters_list.append(parameter_content_list) if cartesian: return utils.gen_cartesian_product(*parsed_parameters_list) else: return utils.gen_dict_from_zip(*parsed_parameters_list)
def __init__(self, variables=None): variables_mapping = utils.ensure_mapping_format(variables or {}) self.session_variables_mapping = parser.parse_variables_mapping( variables_mapping) self.init_test_variables() self.validation_results = []
def test_ensure_mapping_format(self): map_list = [{"a": 1}, {"b": 2}] ordered_dict = utils.ensure_mapping_format(map_list) self.assertIsInstance(ordered_dict, dict) self.assertIn("a", ordered_dict)