class VariableBindsUnittest(unittest.TestCase): def setUp(self): self.context = Context() testcase_file_path = os.path.join(os.getcwd(), 'tests/data/demo_binds.yml') self.testcases = utils.load_testcases(testcase_file_path) def test_context_bind_testset_variables(self): # testcase in JSON format testcase1 = { "variable_binds": [{ "GLOBAL_TOKEN": "debugtalk" }, { "token": "$GLOBAL_TOKEN" }] } # testcase in YAML format testcase2 = self.testcases["bind_variables"] for testcase in [testcase1, testcase2]: variable_binds = testcase['variable_binds'] self.context.bind_variables(variable_binds, level="testset") testset_variables = self.context.testset_shared_variables_mapping testcase_variables = self.context.get_testcase_variables_mapping() self.assertIn("GLOBAL_TOKEN", testset_variables) self.assertIn("GLOBAL_TOKEN", testcase_variables) self.assertEqual(testset_variables["GLOBAL_TOKEN"], "debugtalk") self.assertIn("token", testset_variables) self.assertIn("token", testcase_variables) self.assertEqual(testset_variables["token"], "debugtalk") def test_context_bind_testcase_variables(self): testcase1 = { "variable_binds": [{ "GLOBAL_TOKEN": "debugtalk" }, { "token": "$GLOBAL_TOKEN" }] } testcase2 = self.testcases["bind_variables"] for testcase in [testcase1, testcase2]: variable_binds = testcase['variable_binds'] self.context.bind_variables(variable_binds) testset_variables = self.context.testset_shared_variables_mapping testcase_variables = self.context.get_testcase_variables_mapping() self.assertNotIn("GLOBAL_TOKEN", testset_variables) self.assertIn("GLOBAL_TOKEN", testcase_variables) self.assertEqual(testcase_variables["GLOBAL_TOKEN"], "debugtalk") self.assertNotIn("token", testset_variables) self.assertIn("token", testcase_variables) self.assertEqual(testcase_variables["token"], "debugtalk") def test_context_bind_lambda_functions(self): testcase1 = { "function_binds": { "add_one": lambda x: x + 1, "add_two_nums": lambda x, y: x + y }, "variable_binds": [{ "add1": "${add_one(2)}" }, { "sum2nums": "${add_two_nums(2,3)}" }] } testcase2 = self.testcases["bind_lambda_functions"] for testcase in [testcase1, testcase2]: function_binds = testcase.get('function_binds', {}) self.context.bind_functions(function_binds) variable_binds = testcase['variable_binds'] self.context.bind_variables(variable_binds) context_variables = self.context.get_testcase_variables_mapping() self.assertIn("add1", context_variables) self.assertEqual(context_variables["add1"], 3) self.assertIn("sum2nums", context_variables) self.assertEqual(context_variables["sum2nums"], 5) def test_context_bind_lambda_functions_with_import(self): testcase1 = { "requires": ["random", "string", "hashlib"], "function_binds": { "gen_random_string": "lambda str_len: ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(str_len))", "gen_md5": "lambda *str_args: hashlib.md5(''.join(str_args).encode('utf-8')).hexdigest()" }, "variable_binds": [{ "TOKEN": "debugtalk" }, { "random": "${gen_random_string(5)}" }, { "data": '{"name": "user", "password": "******"}' }, { "authorization": "${gen_md5($TOKEN, $data, $random)}" }] } testcase2 = self.testcases["bind_lambda_functions_with_import"] for testcase in [testcase1, testcase2]: requires = testcase.get('requires', []) self.context.import_requires(requires) function_binds = testcase.get('function_binds', {}) self.context.bind_functions(function_binds) variable_binds = testcase['variable_binds'] self.context.bind_variables(variable_binds) context_variables = self.context.get_testcase_variables_mapping() self.assertIn("TOKEN", context_variables) TOKEN = context_variables["TOKEN"] self.assertEqual(TOKEN, "debugtalk") self.assertIn("random", context_variables) self.assertIsInstance(context_variables["random"], str) self.assertEqual(len(context_variables["random"]), 5) random = context_variables["random"] self.assertIn("data", context_variables) data = context_variables["data"] self.assertIn("authorization", context_variables) self.assertEqual(len(context_variables["authorization"]), 32) authorization = context_variables["authorization"] self.assertEqual(utils.gen_md5(TOKEN, data, random), authorization) def test_import_module_functions(self): testcase1 = { "import_module_functions": ["tests.data.custom_functions"], "variable_binds": [{ "TOKEN": "debugtalk" }, { "random": "${gen_random_string(5)}" }, { "data": '{"name": "user", "password": "******"}' }, { "authorization": "${gen_md5($TOKEN, $data, $random)}" }] } testcase2 = self.testcases["bind_module_functions"] for testcase in [testcase1, testcase2]: module_functions = testcase.get('import_module_functions', []) self.context.import_module_functions(module_functions) variable_binds = testcase['variable_binds'] self.context.bind_variables(variable_binds) context_variables = self.context.get_testcase_variables_mapping() self.assertIn("TOKEN", context_variables) TOKEN = context_variables["TOKEN"] self.assertEqual(TOKEN, "debugtalk") self.assertIn("random", context_variables) self.assertIsInstance(context_variables["random"], str) self.assertEqual(len(context_variables["random"]), 5) random = context_variables["random"] self.assertIn("data", context_variables) data = context_variables["data"] self.assertIn("authorization", context_variables) self.assertEqual(len(context_variables["authorization"]), 32) authorization = context_variables["authorization"] self.assertEqual(utils.gen_md5(TOKEN, data, random), authorization) def test_get_parsed_request(self): test_runner = runner.Runner() testcase = { "import_module_functions": ["tests.data.custom_functions"], "variable_binds": [{ "TOKEN": "debugtalk" }, { "random": "${gen_random_string(5)}" }, { "data": '{"name": "user", "password": "******"}' }, { "authorization": "${gen_md5($TOKEN, $data, $random)}" }], "request": { "url": "http://127.0.0.1:5000/api/users/1000", "method": "POST", "headers": { "Content-Type": "application/json", "authorization": "$authorization", "random": "$random" }, "data": "$data" } } test_runner.init_config(testcase, level="testcase") parsed_request = test_runner.context.get_parsed_request() self.assertIn("authorization", parsed_request["headers"]) self.assertEqual(len(parsed_request["headers"]["authorization"]), 32) self.assertIn("random", parsed_request["headers"]) self.assertEqual(len(parsed_request["headers"]["random"]), 5) self.assertIn("data", parsed_request) self.assertEqual(parsed_request["data"], testcase["variable_binds"][2]["data"])
class Runner(object): def __init__(self, http_client_session=None): self.http_client_session = http_client_session self.context = Context() def init_config(self, config_dict, level): """ create/update context variables binds @param (dict) config_dict { "name": "description content", "requires": ["random", "hashlib"], "function_binds": { "gen_random_string": \ "lambda str_len: ''.join(random.choice(string.ascii_letters + \ string.digits) for _ in range(str_len))", "gen_md5": \ "lambda *str_args: hashlib.md5(''.join(str_args).\ encode('utf-8')).hexdigest()" }, "import_module_functions": ["test.data.custom_functions"], "variable_binds": [ {"TOKEN": "debugtalk"}, {"random": "${gen_random_string(5)}"}, ] } @param (str) context level, testcase or testset """ self.context.init_context(level) requires = config_dict.get('requires', []) self.context.import_requires(requires) function_binds = config_dict.get('function_binds', {}) self.context.bind_functions(function_binds, level) module_functions = config_dict.get('import_module_functions', []) self.context.import_module_functions(module_functions, level) variable_binds = config_dict.get('variable_binds', []) self.context.bind_variables(variable_binds, level) request_config = config_dict.get('request', {}) if level == "testset": base_url = request_config.pop("base_url", None) self.http_client_session = self.http_client_session or HttpSession( base_url) else: # testcase self.http_client_session = self.http_client_session or requests.Session( ) self.context.register_request(request_config, level) def run_test(self, testcase): """ run single testcase. @param (dict) testcase { "name": "testcase description", "times": 3, "requires": [], # optional, override "function_binds": {}, # optional, override "variable_binds": {}, # optional, override "request": { "url": "http://127.0.0.1:5000/api/users/1000", "method": "POST", "headers": { "Content-Type": "application/json", "authorization": "$authorization", "random": "$random" }, "body": '{"name": "user", "password": "******"}' }, "extract_binds": {}, # optional "validators": [] # optional } @return True or raise exception during test """ self.init_config(testcase, level="testcase") parsed_request = self.context.get_parsed_request() try: url = parsed_request.pop('url') method = parsed_request.pop('method') except KeyError: raise exception.ParamsError("URL or METHOD missed!") run_times = int(testcase.get("times", 1)) extract_binds = testcase.get("extract_binds", {}) validators = testcase.get("validators", []) for _ in range(run_times): resp = self.http_client_session.request(url=url, method=method, **parsed_request) resp_obj = response.ResponseObject(resp) extracted_variables_mapping_list = resp_obj.extract_response( extract_binds) self.context.bind_variables(extracted_variables_mapping_list, level="testset") resp_obj.validate(validators, self.context.get_testcase_variables_mapping()) return True def run_testset(self, testset): """ run single testset, including one or several testcases. @param (dict) testset { "name": "testset description", "config": { "name": "testset description", "requires": [], "function_binds": {}, "variable_binds": [], "request": {} }, "testcases": [ { "name": "testcase description", "variable_binds": {}, # optional, override "request": {}, "extract_binds": {}, # optional "validators": {} # optional }, testcase12 ] } @return (list) test results of testcases [ (success, diff_content), # testcase1 (success, diff_content) # testcase2 ] """ results = [] config_dict = testset.get("config", {}) self.init_config(config_dict, level="testset") testcases = testset.get("testcases", []) for testcase in testcases: result = self.run_test(testcase) results.append(result) return results def run_testsets(self, testsets): """ run testsets, including one or several testsets. @param testsets [ testset1, testset2, ] @return (list) test results of testsets [ [ # testset1 (success, diff_content), # testcase11 (success, diff_content) # testcase12 ], [ # testset2 (success, diff_content), # testcase21 (success, diff_content) # testcase22 ] ] """ return [self.run_testset(testset) for testset in testsets]
class VariableBindsUnittest(unittest.TestCase): def setUp(self): self.context = Context() testcase_file_path = os.path.join(os.getcwd(), 'tests/data/demo_binds.yml') self.testcases = utils.load_testcases(testcase_file_path) def test_context_init_functions(self): self.assertIn("get_timestamp", self.context.testset_functions_config) self.assertIn("gen_random_string", self.context.testset_functions_config) variable_binds = [ {"random": "${gen_random_string(5)}"}, {"timestamp10": "${get_timestamp(10)}"} ] self.context.bind_variables(variable_binds) context_variables = self.context.get_testcase_variables_mapping() self.assertEqual(len(context_variables["random"]), 5) self.assertEqual(len(context_variables["timestamp10"]), 10) def test_context_bind_testset_variables(self): # testcase in JSON format testcase1 = { "variable_binds": [ {"GLOBAL_TOKEN": "debugtalk"}, {"token": "$GLOBAL_TOKEN"} ] } # testcase in YAML format testcase2 = self.testcases["bind_variables"] for testcase in [testcase1, testcase2]: variable_binds = testcase['variable_binds'] self.context.bind_variables(variable_binds, level="testset") testset_variables = self.context.testset_shared_variables_mapping testcase_variables = self.context.get_testcase_variables_mapping() self.assertIn("GLOBAL_TOKEN", testset_variables) self.assertIn("GLOBAL_TOKEN", testcase_variables) self.assertEqual(testset_variables["GLOBAL_TOKEN"], "debugtalk") self.assertIn("token", testset_variables) self.assertIn("token", testcase_variables) self.assertEqual(testset_variables["token"], "debugtalk") def test_context_bind_testcase_variables(self): testcase1 = { "variable_binds": [ {"GLOBAL_TOKEN": "debugtalk"}, {"token": "$GLOBAL_TOKEN"} ] } testcase2 = self.testcases["bind_variables"] for testcase in [testcase1, testcase2]: variable_binds = testcase['variable_binds'] self.context.bind_variables(variable_binds) testset_variables = self.context.testset_shared_variables_mapping testcase_variables = self.context.get_testcase_variables_mapping() self.assertNotIn("GLOBAL_TOKEN", testset_variables) self.assertIn("GLOBAL_TOKEN", testcase_variables) self.assertEqual(testcase_variables["GLOBAL_TOKEN"], "debugtalk") self.assertNotIn("token", testset_variables) self.assertIn("token", testcase_variables) self.assertEqual(testcase_variables["token"], "debugtalk") def test_context_bind_lambda_functions(self): testcase1 = { "function_binds": { "add_one": lambda x: x + 1, "add_two_nums": lambda x, y: x + y }, "variable_binds": [ {"add1": "${add_one(2)}"}, {"sum2nums": "${add_two_nums(2,3)}"} ] } testcase2 = self.testcases["bind_lambda_functions"] for testcase in [testcase1, testcase2]: function_binds = testcase.get('function_binds', {}) self.context.bind_functions(function_binds) variable_binds = testcase['variable_binds'] self.context.bind_variables(variable_binds) context_variables = self.context.get_testcase_variables_mapping() self.assertIn("add1", context_variables) self.assertEqual(context_variables["add1"], 3) self.assertIn("sum2nums", context_variables) self.assertEqual(context_variables["sum2nums"], 5) def test_context_bind_lambda_functions_with_import(self): testcase1 = { "requires": ["random", "string", "hashlib"], "function_binds": { "gen_random_string": "lambda str_len: ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(str_len))", "gen_md5": "lambda *str_args: hashlib.md5(''.join(str_args).encode('utf-8')).hexdigest()" }, "variable_binds": [ {"TOKEN": "debugtalk"}, {"random": "${gen_random_string(5)}"}, {"data": '{"name": "user", "password": "******"}'}, {"authorization": "${gen_md5($TOKEN, $data, $random)}"} ] } testcase2 = self.testcases["bind_lambda_functions_with_import"] for testcase in [testcase1, testcase2]: requires = testcase.get('requires', []) self.context.import_requires(requires) function_binds = testcase.get('function_binds', {}) self.context.bind_functions(function_binds) variable_binds = testcase['variable_binds'] self.context.bind_variables(variable_binds) context_variables = self.context.get_testcase_variables_mapping() self.assertIn("TOKEN", context_variables) TOKEN = context_variables["TOKEN"] self.assertEqual(TOKEN, "debugtalk") self.assertIn("random", context_variables) self.assertIsInstance(context_variables["random"], str) self.assertEqual(len(context_variables["random"]), 5) random = context_variables["random"] self.assertIn("data", context_variables) data = context_variables["data"] self.assertIn("authorization", context_variables) self.assertEqual(len(context_variables["authorization"]), 32) authorization = context_variables["authorization"] self.assertEqual(utils.gen_md5(TOKEN, data, random), authorization) def test_import_module_items(self): testcase1 = { "import_module_items": ["tests.data.debugtalk"], "variable_binds": [ {"TOKEN": "debugtalk"}, {"random": "${gen_random_string(5)}"}, {"data": '{"name": "user", "password": "******"}'}, {"authorization": "${gen_md5($TOKEN, $data, $random)}"} ] } testcase2 = self.testcases["bind_module_functions"] for testcase in [testcase1, testcase2]: module_items = testcase.get('import_module_items', []) self.context.import_module_items(module_items) variable_binds = testcase['variable_binds'] self.context.bind_variables(variable_binds) context_variables = self.context.get_testcase_variables_mapping() self.assertIn("TOKEN", context_variables) TOKEN = context_variables["TOKEN"] self.assertEqual(TOKEN, "debugtalk") self.assertIn("random", context_variables) self.assertIsInstance(context_variables["random"], str) self.assertEqual(len(context_variables["random"]), 5) random = context_variables["random"] self.assertIn("data", context_variables) data = context_variables["data"] self.assertIn("authorization", context_variables) self.assertEqual(len(context_variables["authorization"]), 32) authorization = context_variables["authorization"] self.assertEqual(utils.gen_md5(TOKEN, data, random), authorization) self.assertIn("SECRET_KEY", context_variables) SECRET_KEY = context_variables["SECRET_KEY"] self.assertEqual(SECRET_KEY, "DebugTalk") def test_register_request(self): request_dict = { "url": "http://debugtalk.com", "method": "GET", "headers": { "Content-Type": "application/json", "USER-AGENT": "ios/10.3" } } self.context.register_request(request_dict) parsed_request = self.context.get_parsed_request() self.assertIn("content-type", parsed_request["headers"]) self.assertIn("user-agent", parsed_request["headers"]) request_dict = { "headers": "invalid headers" } with self.assertRaises(ParamsError): self.context.register_request(request_dict) def test_get_parsed_request(self): test_runner = runner.Runner() testcase = { "import_module_items": ["tests.data.debugtalk"], "variable_binds": [ {"TOKEN": "debugtalk"}, {"random": "${gen_random_string(5)}"}, {"data": '{"name": "user", "password": "******"}'}, {"authorization": "${gen_md5($TOKEN, $data, $random)}"} ], "request": { "url": "http://127.0.0.1:5000/api/users/1000", "method": "POST", "headers": { "Content-Type": "application/json", "authorization": "$authorization", "random": "$random", "SECRET_KEY": "$SECRET_KEY" }, "data": "$data" } } test_runner.init_config(testcase, level="testcase") parsed_request = test_runner.context.get_parsed_request() self.assertIn("authorization", parsed_request["headers"]) self.assertEqual(len(parsed_request["headers"]["authorization"]), 32) self.assertIn("random", parsed_request["headers"]) self.assertEqual(len(parsed_request["headers"]["random"]), 5) self.assertIn("data", parsed_request) self.assertEqual(parsed_request["data"], testcase["variable_binds"][2]["data"]) self.assertEqual(parsed_request["headers"]["secret_key"], "DebugTalk") def test_exec_content_functions(self): test_runner = runner.Runner() content = "${sleep(1)}" start_time = time.time() test_runner.context.exec_content_functions(content) end_time = time.time() elapsed_time = end_time - start_time self.assertGreater(elapsed_time, 1)
class VariableBindsUnittest(unittest.TestCase): def setUp(self): self.context = Context() testcase_file_path = os.path.join(os.getcwd(), 'test/data/demo_binds.yml') self.testcases = utils.load_testcases(testcase_file_path) def test_context_variable_string(self): # testcase in JSON format testcase1 = {"variable_binds": [{"TOKEN": "debugtalk"}]} # testcase in YAML format testcase2 = self.testcases[0] for testcase in [testcase1, testcase2]: variable_binds = testcase['variable_binds'] self.context.bind_variables(variable_binds) context_variables = self.context.variables self.assertIn("TOKEN", context_variables) self.assertEqual(context_variables["TOKEN"], "debugtalk") def test_context_variable_list(self): testcase1 = {"variable_binds": [{"var": [1, 2, 3]}]} testcase2 = self.testcases[1] for testcase in [testcase1, testcase2]: variable_binds = testcase['variable_binds'] self.context.bind_variables(variable_binds) context_variables = self.context.variables self.assertIn("var", context_variables) self.assertEqual(context_variables["var"], [1, 2, 3]) def test_context_variable_json(self): testcase1 = { "variable_binds": [{ "data": { 'name': 'user', 'password': '******' } }] } testcase2 = self.testcases[2] for testcase in [testcase1, testcase2]: variable_binds = testcase['variable_binds'] self.context.bind_variables(variable_binds) context_variables = self.context.variables self.assertIn("data", context_variables) self.assertEqual(context_variables["data"], { 'name': 'user', 'password': '******' }) def test_context_variable_variable(self): testcase1 = { "variable_binds": [{ "GLOBAL_TOKEN": "debugtalk" }, { "token": "${GLOBAL_TOKEN}" }] } testcase2 = self.testcases[3] for testcase in [testcase1, testcase2]: variable_binds = testcase['variable_binds'] self.context.bind_variables(variable_binds) context_variables = self.context.variables self.assertIn("GLOBAL_TOKEN", context_variables) self.assertEqual(context_variables["GLOBAL_TOKEN"], "debugtalk") self.assertIn("token", context_variables) self.assertEqual(context_variables["token"], "debugtalk") def test_context_variable_function_lambda(self): testcase1 = { "function_binds": { "add_one": lambda x: x + 1, "add_two_nums": lambda x, y: x + y }, "variable_binds": [{ "add1": { "func": "add_one", "args": [2] } }, { "sum2nums": { "func": "add_two_nums", "args": [2, 3] } }] } testcase2 = self.testcases[4] for testcase in [testcase1, testcase2]: function_binds = testcase.get('function_binds', {}) self.context.bind_functions(function_binds) variable_binds = testcase['variable_binds'] self.context.bind_variables(variable_binds) context_variables = self.context.variables self.assertIn("add1", context_variables) self.assertEqual(context_variables["add1"], 3) self.assertIn("sum2nums", context_variables) self.assertEqual(context_variables["sum2nums"], 5) def test_context_variable_function_lambda_with_import(self): testcase1 = { "requires": ["random", "string", "hashlib"], "function_binds": { "gen_random_string": "lambda str_len: ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(str_len))", "gen_md5": "lambda *str_args: hashlib.md5(''.join(str_args).encode('utf-8')).hexdigest()" }, "variable_binds": [{ "TOKEN": "debugtalk" }, { "random": { "func": "gen_random_string", "args": [5] } }, { "data": "{'name': 'user', 'password': '******'}" }, { "md5": { "func": "gen_md5", "args": ["$TOKEN", "$data", "$random"] } }] } testcase2 = self.testcases[5] for testcase in [testcase1, testcase2]: requires = testcase.get('requires', []) self.context.import_requires(requires) function_binds = testcase.get('function_binds', {}) self.context.bind_functions(function_binds) variable_binds = testcase['variable_binds'] self.context.bind_variables(variable_binds) context_variables = self.context.variables self.assertIn("random", context_variables) self.assertIsInstance(context_variables["random"], str) self.assertEqual(len(context_variables["random"]), 5) self.assertIn("md5", context_variables) self.assertEqual(len(context_variables["md5"]), 32)
class TestRunner(object): def __init__(self): self.client = requests.Session() self.context = Context() def update_context(self, config_dict): """ create/update context variables binds @param config_dict { "name": "description content", "requires": ["random", "hashlib"], "function_binds": { "gen_random_string": \ "lambda str_len: ''.join(random.choice(string.ascii_letters + \ string.digits) for _ in range(str_len))", "gen_md5": \ "lambda *str_args: hashlib.md5(''.join(str_args).\ encode('utf-8')).hexdigest()" }, "variable_binds": [ {"TOKEN": "debugtalk"}, {"random": {"func": "gen_random_string", "args": [5]}}, ] } """ requires = config_dict.get('requires', []) self.context.import_requires(requires) function_binds = config_dict.get('function_binds', {}) self.context.bind_functions(function_binds) variable_binds = config_dict.get('variable_binds', []) self.context.bind_variables(variable_binds) def run_test(self, testcase): """ run single testcase. @param (dict) testcase { "name": "testcase description", "requires": [], # optional, override "function_binds": {}, # optional, override "variable_binds": {}, # optional, override "request": { "url": "http://127.0.0.1:5000/api/users/1000", "method": "POST", "headers": { "Content-Type": "application/json", "authorization": "${authorization}", "random": "${random}" }, "body": '{"name": "user", "password": "******"}' }, "extract_binds": {}, "validators": {} } @return (tuple) test result of single testcase (success, diff_content) """ self.update_context(testcase) parsed_request = parse_template(testcase["request"], self.context.variables) try: url = parsed_request.pop('url') method = parsed_request.pop('method') except KeyError: raise exception.ParamsError("URL or METHOD missed!") resp = self.client.request(url=url, method=method, **parsed_request) resp_obj = response.ResponseObject(resp) extract_binds = testcase.get("extract_binds", {}) extract_binds_dict = resp_obj.extract_response(extract_binds) self.context.update_variables(extract_binds_dict) validators = testcase.get("validators", {}) diff_content_dict = resp_obj.validate(validators, self.context.variables) return resp_obj.success, diff_content_dict def run_testset(self, testset): """ run single testset, including one or several testcases. @param (dict) testset { "name": "testset description", "config": { "name": "testset description", "requires": [], "function_binds": {}, "variable_binds": [] }, "testcases": [ { "name": "testcase description", "variable_binds": {}, # override "request": {}, "extract_binds": {}, "validators": {} }, testcase12 ] } @return (list) test results of testcases [ (success, diff_content), # testcase1 (success, diff_content) # testcase2 ] """ results = [] config_dict = testset.get("config", {}) self.update_context(config_dict) testcases = testset.get("testcases", []) for testcase in testcases: result = self.run_test(testcase) results.append(result) return results def run_testsets(self, testsets): """ run testsets, including one or several testsets. @param testsets [ testset1, testset2, ] @return (list) test results of testsets [ [ # testset1 (success, diff_content), # testcase11 (success, diff_content) # testcase12 ], [ # testset2 (success, diff_content), # testcase21 (success, diff_content) # testcase22 ] ] """ return [self.run_testset(testset) for testset in testsets]
class VariableBindsUnittest(unittest.TestCase): def setUp(self): self.context = Context() testcase_file_path = os.path.join(os.getcwd(), 'tests/data/demo_binds.yml') self.testcases = utils.load_testcases(testcase_file_path) def test_context_bind_testset_variables(self): # testcase in JSON format testcase1 = { "variable_binds": [ {"GLOBAL_TOKEN": "debugtalk"}, {"token": "$GLOBAL_TOKEN"} ] } # testcase in YAML format testcase2 = self.testcases["bind_variables"] for testcase in [testcase1, testcase2]: variable_binds = testcase['variable_binds'] self.context.bind_variables(variable_binds, level="testset") testset_variables = self.context.testset_shared_variables_mapping testcase_variables = self.context.get_testcase_variables_mapping() self.assertIn("GLOBAL_TOKEN", testset_variables) self.assertIn("GLOBAL_TOKEN", testcase_variables) self.assertEqual(testset_variables["GLOBAL_TOKEN"], "debugtalk") self.assertIn("token", testset_variables) self.assertIn("token", testcase_variables) self.assertEqual(testset_variables["token"], "debugtalk") def test_context_bind_testcase_variables(self): testcase1 = { "variable_binds": [ {"GLOBAL_TOKEN": "debugtalk"}, {"token": "$GLOBAL_TOKEN"} ] } testcase2 = self.testcases["bind_variables"] for testcase in [testcase1, testcase2]: variable_binds = testcase['variable_binds'] self.context.bind_variables(variable_binds) testset_variables = self.context.testset_shared_variables_mapping testcase_variables = self.context.get_testcase_variables_mapping() self.assertNotIn("GLOBAL_TOKEN", testset_variables) self.assertIn("GLOBAL_TOKEN", testcase_variables) self.assertEqual(testcase_variables["GLOBAL_TOKEN"], "debugtalk") self.assertNotIn("token", testset_variables) self.assertIn("token", testcase_variables) self.assertEqual(testcase_variables["token"], "debugtalk") def test_context_bind_lambda_functions(self): testcase1 = { "function_binds": { "add_one": lambda x: x + 1, "add_two_nums": lambda x, y: x + y }, "variable_binds": [ {"add1": "${add_one(2)}"}, {"sum2nums": "${add_two_nums(2,3)}"} ] } testcase2 = self.testcases["bind_lambda_functions"] for testcase in [testcase1, testcase2]: function_binds = testcase.get('function_binds', {}) self.context.bind_functions(function_binds) variable_binds = testcase['variable_binds'] self.context.bind_variables(variable_binds) context_variables = self.context.get_testcase_variables_mapping() self.assertIn("add1", context_variables) self.assertEqual(context_variables["add1"], 3) self.assertIn("sum2nums", context_variables) self.assertEqual(context_variables["sum2nums"], 5) def test_context_bind_lambda_functions_with_import(self): testcase1 = { "requires": ["random", "string", "hashlib"], "function_binds": { "gen_random_string": "lambda str_len: ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(str_len))", "gen_md5": "lambda *str_args: hashlib.md5(''.join(str_args).encode('utf-8')).hexdigest()" }, "variable_binds": [ {"TOKEN": "debugtalk"}, {"random": "${gen_random_string(5)}"}, {"data": '{"name": "user", "password": "******"}'}, {"authorization": "${gen_md5($TOKEN, $data, $random)}"} ] } testcase2 = self.testcases["bind_lambda_functions_with_import"] for testcase in [testcase1, testcase2]: requires = testcase.get('requires', []) self.context.import_requires(requires) function_binds = testcase.get('function_binds', {}) self.context.bind_functions(function_binds) variable_binds = testcase['variable_binds'] self.context.bind_variables(variable_binds) context_variables = self.context.get_testcase_variables_mapping() self.assertIn("TOKEN", context_variables) TOKEN = context_variables["TOKEN"] self.assertEqual(TOKEN, "debugtalk") self.assertIn("random", context_variables) self.assertIsInstance(context_variables["random"], str) self.assertEqual(len(context_variables["random"]), 5) random = context_variables["random"] self.assertIn("data", context_variables) data = context_variables["data"] self.assertIn("authorization", context_variables) self.assertEqual(len(context_variables["authorization"]), 32) authorization = context_variables["authorization"] self.assertEqual(utils.gen_md5(TOKEN, data, random), authorization) def test_import_module_functions(self): testcase1 = { "import_module_functions": ["tests.data.custom_functions"], "variable_binds": [ {"TOKEN": "debugtalk"}, {"random": "${gen_random_string(5)}"}, {"data": '{"name": "user", "password": "******"}'}, {"authorization": "${gen_md5($TOKEN, $data, $random)}"} ] } testcase2 = self.testcases["bind_module_functions"] for testcase in [testcase1, testcase2]: module_functions = testcase.get('import_module_functions', []) self.context.import_module_functions(module_functions) variable_binds = testcase['variable_binds'] self.context.bind_variables(variable_binds) context_variables = self.context.get_testcase_variables_mapping() self.assertIn("TOKEN", context_variables) TOKEN = context_variables["TOKEN"] self.assertEqual(TOKEN, "debugtalk") self.assertIn("random", context_variables) self.assertIsInstance(context_variables["random"], str) self.assertEqual(len(context_variables["random"]), 5) random = context_variables["random"] self.assertIn("data", context_variables) data = context_variables["data"] self.assertIn("authorization", context_variables) self.assertEqual(len(context_variables["authorization"]), 32) authorization = context_variables["authorization"] self.assertEqual(utils.gen_md5(TOKEN, data, random), authorization) def test_get_parsed_request(self): test_runner = runner.Runner() testcase = { "import_module_functions": ["tests.data.custom_functions"], "variable_binds": [ {"TOKEN": "debugtalk"}, {"random": "${gen_random_string(5)}"}, {"data": '{"name": "user", "password": "******"}'}, {"authorization": "${gen_md5($TOKEN, $data, $random)}"} ], "request": { "url": "http://127.0.0.1:5000/api/users/1000", "method": "POST", "headers": { "Content-Type": "application/json", "authorization": "$authorization", "random": "$random" }, "data": "$data" } } test_runner.init_config(testcase, level="testcase") parsed_request = test_runner.context.get_parsed_request() self.assertIn("authorization", parsed_request["headers"]) self.assertEqual(len(parsed_request["headers"]["authorization"]), 32) self.assertIn("random", parsed_request["headers"]) self.assertEqual(len(parsed_request["headers"]["random"]), 5) self.assertIn("data", parsed_request) self.assertEqual(parsed_request["data"], testcase["variable_binds"][2]["data"])
class Runner(object): def __init__(self, http_client_session=None): self.http_client_session = http_client_session self.context = Context() def init_config(self, config_dict, level): """ create/update context variables binds @param (dict) config_dict { "name": "description content", "requires": ["random", "hashlib"], "function_binds": { "gen_random_string": \ "lambda str_len: ''.join(random.choice(string.ascii_letters + \ string.digits) for _ in range(str_len))", "gen_md5": \ "lambda *str_args: hashlib.md5(''.join(str_args).\ encode('utf-8')).hexdigest()" }, "import_module_functions": ["test.data.custom_functions"], "variable_binds": [ {"TOKEN": "debugtalk"}, {"random": "${gen_random_string(5)}"}, ] } @param (str) context level, testcase or testset """ self.context.init_context(level) requires = config_dict.get('requires', []) self.context.import_requires(requires) function_binds = config_dict.get('function_binds', {}) self.context.bind_functions(function_binds, level) module_functions = config_dict.get('import_module_functions', []) self.context.import_module_functions(module_functions, level) variable_binds = config_dict.get('variable_binds', []) self.context.bind_variables(variable_binds, level) request_config = config_dict.get('request', {}) if level == "testset": base_url = request_config.pop("base_url", None) self.http_client_session = self.http_client_session or HttpSession(base_url) else: # testcase self.http_client_session = self.http_client_session or requests.Session() self.context.register_request(request_config, level) def run_test(self, testcase): """ run single testcase. @param (dict) testcase { "name": "testcase description", "times": 3, "requires": [], # optional, override "function_binds": {}, # optional, override "variable_binds": {}, # optional, override "request": { "url": "http://127.0.0.1:5000/api/users/1000", "method": "POST", "headers": { "Content-Type": "application/json", "authorization": "$authorization", "random": "$random" }, "body": '{"name": "user", "password": "******"}' }, "extract_binds": {}, # optional "validators": [] # optional } @return (tuple) test result of single testcase (success, diff_content_list) """ self.init_config(testcase, level="testcase") parsed_request = self.context.get_parsed_request() try: url = parsed_request.pop('url') method = parsed_request.pop('method') except KeyError: raise exception.ParamsError("URL or METHOD missed!") run_times = int(testcase.get("times", 1)) extract_binds = testcase.get("extract_binds", {}) validators = testcase.get("validators", []) for _ in range(run_times): resp = self.http_client_session.request(url=url, method=method, **parsed_request) resp_obj = response.ResponseObject(resp) extracted_variables_mapping_list = resp_obj.extract_response(extract_binds) self.context.bind_variables(extracted_variables_mapping_list, level="testset") resp_obj.validate(validators, self.context.get_testcase_variables_mapping()) return True def run_testset(self, testset): """ run single testset, including one or several testcases. @param (dict) testset { "name": "testset description", "config": { "name": "testset description", "requires": [], "function_binds": {}, "variable_binds": [], "request": {} }, "testcases": [ { "name": "testcase description", "variable_binds": {}, # optional, override "request": {}, "extract_binds": {}, # optional "validators": {} # optional }, testcase12 ] } @return (list) test results of testcases [ (success, diff_content), # testcase1 (success, diff_content) # testcase2 ] """ results = [] config_dict = testset.get("config", {}) self.init_config(config_dict, level="testset") testcases = testset.get("testcases", []) for testcase in testcases: result = self.run_test(testcase) results.append(result) return results def run_testsets(self, testsets): """ run testsets, including one or several testsets. @param testsets [ testset1, testset2, ] @return (list) test results of testsets [ [ # testset1 (success, diff_content), # testcase11 (success, diff_content) # testcase12 ], [ # testset2 (success, diff_content), # testcase21 (success, diff_content) # testcase22 ] ] """ return [self.run_testset(testset) for testset in testsets]
class TestRunner(object): def __init__(self): self.client = requests.Session() self.context = Context() self.testcase_parser = TestcaseParser() def pre_config(self, config_dict): """ create/update variables binds @param config_dict { "name": "description content", "requires": ["random", "hashlib"], "function_binds": { "gen_random_string": \ "lambda str_len: ''.join(random.choice(string.ascii_letters + \ string.digits) for _ in range(str_len))", "gen_md5": \ "lambda *str_args: hashlib.md5(''.join(str_args).\ encode('utf-8')).hexdigest()" }, "variable_binds": [ {"TOKEN": "debugtalk"}, {"random": {"func": "gen_random_string", "args": [5]}}, ] } """ requires = config_dict.get('requires', []) self.context.import_requires(requires) function_binds = config_dict.get('function_binds', {}) self.context.bind_functions(function_binds) variable_binds = config_dict.get('variable_binds', []) self.context.bind_variables(variable_binds) extract_binds = config_dict.get('extract_binds', {}) self.context.bind_extractors(extract_binds) self.testcase_parser.update_variables_binds(self.context.variables) def parse_testcase(self, testcase): """ parse testcase with variables binds if it is a template. @param (dict) testcase { "name": "testcase description", "requires": [], # optional, override "function_binds": {}, # optional, override "variable_binds": {}, # optional, override "request": {}, "response": {} } @return (dict) parsed testcase with bind values { "request": { "url": "http://127.0.0.1:5000/api/users/1000", "method": "POST", "headers": { "Content-Type": "application/json", "authorization": "a83de0ff8d2e896dbd8efb81ba14e17d", "random": "A2dEx" }, "body": '{"name": "user", "password": "******"}' }, "response": { "status_code": 201 } } """ self.pre_config(testcase) parsed_testcase = self.testcase_parser.parse(testcase) return parsed_testcase def run_test(self, testcase): """ run single testcase. @param (dict) testcase { "name": "testcase description", "requires": [], # optional, override "function_binds": {}, # optional, override "variable_binds": {}, # optional, override "request": {}, "response": {} } @return (tuple) test result of single testcase (success, diff_content) """ testcase = self.parse_testcase(testcase) req_kwargs = testcase['request'] try: url = req_kwargs.pop('url') method = req_kwargs.pop('method') except KeyError: raise exception.ParamsError("URL or METHOD missed!") resp_obj = self.client.request(url=url, method=method, **req_kwargs) response.extract_response(resp_obj, self.context) diff_content = response.diff_response(resp_obj, testcase['response']) success = False if diff_content else True return success, diff_content def run_testset(self, testset): """ run single testset, including one or several testcases. @param (dict) testset { "name": "testset description", "config": { "name": "testset description", "requires": [], "function_binds": {}, "variable_binds": [] }, "testcases": [ { "name": "testcase description", "variable_binds": {}, # override "request": {}, "response": {} }, testcase12 ] } @return (list) test results of testcases [ (success, diff_content), # testcase1 (success, diff_content) # testcase2 ] """ results = [] config_dict = testset.get("config", {}) self.pre_config(config_dict) testcases = testset.get("testcases", []) for testcase in testcases: result = self.run_test(testcase) results.append(result) return results def run_testsets(self, testsets): """ run testsets, including one or several testsets. @param testsets [ testset1, testset2, ] @return (list) test results of testsets [ [ # testset1 (success, diff_content), # testcase11 (success, diff_content) # testcase12 ], [ # testset2 (success, diff_content), # testcase21 (success, diff_content) # testcase22 ] ] """ return [self.run_testset(testset) for testset in testsets]