From 29b660b3db67824779f34c273d740ea2f6050255 Mon Sep 17 00:00:00 2001 From: debugtalk Date: Tue, 4 Jul 2017 16:45:01 +0800 Subject: [PATCH] change variable marker and function marker: 1, variable marker: ${var} => $var; 2, function marker: {'func': 'gen_random_string', 'args': [5]} => ${gen_random_string(5). --- ate/context.py | 54 ++++++++++++++++------------ ate/runner.py | 6 ++-- ate/testcase.py | 36 ++++++++++++++----- ate/utils.py | 20 ----------- test/data/demo_binds.yml | 14 ++++---- test/data/demo_import_functions.yml | 18 +++++----- test/data/demo_template_separate.yml | 20 +++++------ test/data/demo_template_sets.yml | 16 ++++----- test/test_context.py | 40 +++++++++++---------- test/test_testcase.py | 44 +++++++++++++++++------ test/test_utils.py | 22 ------------ 11 files changed, 152 insertions(+), 138 deletions(-) diff --git a/ate/context.py b/ate/context.py index 042ad094..01e07461 100644 --- a/ate/context.py +++ b/ate/context.py @@ -78,9 +78,9 @@ class Context(object): e.g. [ {"TOKEN": "debugtalk"}, - {"random": {"func": "gen_random_string", "args": [5]}}, + {"random": "${gen_random_string(5)}"}, {"json": {'name': 'user', 'password': '123456'}}, - {"md5": {"func": "gen_md5", "args": ["${TOKEN}", "${json}", "${random}"]}} + {"md5": "${gen_md5($TOKEN, $json, $random)}"} ] """ if level == "testset": @@ -148,29 +148,39 @@ class Context(object): def get_eval_value(self, data): """ evaluate data recursively, each variable in data will be evaluated. - variables marker: ${variable}. """ - if isinstance(data, str): - return utils.parse_content_with_variables(data, self.testcase_variables_mapping) - - if isinstance(data, list): + if isinstance(data, (list, tuple)): return [self.get_eval_value(item) for item in data] if isinstance(data, dict): - if "func" in data: - # this is a function, e.g. {"func": "gen_random_string", "args": [5]} - # function marker: "func" key in dict - # the function will be called, and its return value will be binded - # to the testcase context variable. - func_name = data['func'] - args = self.get_eval_value(data.get('args', [])) - kargs = self.get_eval_value(data.get('kargs', {})) - return self.testcase_config["functions"][func_name](*args, **kargs) - else: - evaluated_data = {} - for key, value in data.items(): - evaluated_data[key] = self.get_eval_value(value) + evaluated_data = {} + for key, value in data.items(): + evaluated_data[key] = self.get_eval_value(value) - return evaluated_data + return evaluated_data - return data + if isinstance(data, (int, float)): + return data + + # data is in string format here + data = data.strip() + if utils.is_variable(data): + # variable marker: $var + variable_name = utils.parse_variable(data) + value = self.testcase_variables_mapping.get(variable_name) + if value is None: + raise exception.ParamsError( + "%s is not defined in bind variables!" % variable_name) + return value + + elif utils.is_functon(data): + # function marker: ${func(1, 2, a=3, b=4)} + fuction_meta = utils.parse_function(data) + func_name = fuction_meta['func_name'] + args = fuction_meta.get('args', []) + kargs = fuction_meta.get('kargs', {}) + args = self.get_eval_value(args) + kargs = self.get_eval_value(kargs) + return self.testcase_config["functions"][func_name](*args, **kargs) + else: + return data diff --git a/ate/runner.py b/ate/runner.py index 309dbb0b..7cfde2a9 100644 --- a/ate/runner.py +++ b/ate/runner.py @@ -26,7 +26,7 @@ class Runner(object): "import_module_functions": ["test.data.custom_functions"], "variable_binds": [ {"TOKEN": "debugtalk"}, - {"random": {"func": "gen_random_string", "args": [5]}}, + {"random": "${gen_random_string(5)}"}, ] } @param (str) context level, testcase or testset @@ -62,8 +62,8 @@ class Runner(object): "method": "POST", "headers": { "Content-Type": "application/json", - "authorization": "${authorization}", - "random": "${random}" + "authorization": "$authorization", + "random": "$random" }, "body": '{"name": "user", "password": "123456"}' }, diff --git a/ate/testcase.py b/ate/testcase.py index 884edbf5..3ba54bc7 100644 --- a/ate/testcase.py +++ b/ate/testcase.py @@ -1,19 +1,40 @@ -from ate import utils +import re +from ate.exception import ParamsError +def parse_content_with_variables(content, variables_binds): + """ replace variables with bind value + """ + # check if content includes $variable + matched = re.match(r"^(.*)\$(\w+)(.*)$", content) + if matched: + # this is a variable, and will replace with its bind value + variable_name = matched.group(2) + value = variables_binds.get(variable_name) + if value is None: + raise ParamsError( + "%s is not defined in bind variables!" % variable_name) + if matched.group(1) or matched.group(3): + # e.g. /api/users/$uid + return content.replace("$%s" % variable_name, value) + + return value + + return content + def parse_template(testcase_template, variables_binds): """ parse testcase_template, replace all variables with bind value. - variables marker: ${variable}. + variables marker: $variable. @param (dict) testcase_template { - "url": "http://127.0.0.1:5000/api/users/${uid}", + "url": "http://127.0.0.1:5000/api/users/$uid", "method": "POST", "headers": { "Content-Type": "application/json", - "authorization": "${authorization}", - "random": "${random}" + "authorization": "$authorization", + "random": "$random" }, - "body": "${data}" + "body": "$data" } @param (dict) variables binds mapping { @@ -36,10 +57,9 @@ def parse_template(testcase_template, variables_binds): def substitute(content): """ substitute content recursively, each variable will be replaced with bind value. - variables marker: ${variable}. """ if isinstance(content, str): - return utils.parse_content_with_variables(content, variables_binds) + return parse_content_with_variables(content, variables_binds) if isinstance(content, list): return [substitute(item) for item in content] diff --git a/ate/utils.py b/ate/utils.py index cc721445..31d96f7d 100644 --- a/ate/utils.py +++ b/ate/utils.py @@ -214,26 +214,6 @@ def parse_function(content): return function_meta -def parse_content_with_variables(content, variables_binds): - """ replace variables with bind value - """ - # check if content includes ${variable} - matched = re.match(r"(.*)\$\{(.*)\}(.*)", content) - if matched: - # this is a variable, and will replace with its bind value - variable_name = matched.group(2) - value = variables_binds.get(variable_name) - if value is None: - raise ParamsError( - "%s is not defined in bind variables!" % variable_name) - if matched.group(1) or matched.group(3): - # e.g. /api/users/${uid} - return re.sub(r"\$\{.*\}", value, content) - - return value - - return content - def query_json(json_content, query, delimiter='.'): """ Do an xpath-like query with json_content. @param (json_content) json_content diff --git a/test/data/demo_binds.yml b/test/data/demo_binds.yml index 20d497b1..3977f37a 100644 --- a/test/data/demo_binds.yml +++ b/test/data/demo_binds.yml @@ -7,15 +7,15 @@ register_variables: register_template_variables: variable_binds: - TOKEN: "debugtalk" - - token: ${TOKEN} + - token: $TOKEN bind_lambda_functions: 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]} + - add1: ${add_one(2)} + - sum2nums: ${add_two_nums(2, 3)} bind_lambda_functions_with_import: requires: @@ -27,9 +27,9 @@ bind_lambda_functions_with_import: 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]} + - random: ${gen_random_string(5)} - data: "{'name': 'user', 'password': '123456'}" - - authorization: {"func": "gen_md5", "args": ["${TOKEN}", "${data}", "${random}"]} + - authorization: ${gen_md5($TOKEN, $data, $random)} bind_module_functions: function_binds: @@ -37,6 +37,6 @@ bind_module_functions: - test.data.custom_functions variable_binds: - TOKEN: debugtalk - - random: {"func": "gen_random_string", "args": [5]} + - random: ${gen_random_string(5)} - data: "{'name': 'user', 'password': '123456'}" - - authorization: {"func": "gen_md5", "args": ["${TOKEN}", "${data}", "${random}"]} + - authorization: ${gen_md5($TOKEN, $data, $random)} diff --git a/test/data/demo_import_functions.yml b/test/data/demo_import_functions.yml index e48b5f69..25d2ea11 100644 --- a/test/data/demo_import_functions.yml +++ b/test/data/demo_import_functions.yml @@ -4,9 +4,9 @@ - test.data.custom_functions variable_binds: - TOKEN: debugtalk - - json: {"name": "user", "password": "123456"} - - random: {"func": "gen_random_string", "args": [5]} - - authorization: {"func": "gen_md5", "args": ["${TOKEN}", "${json}", "${random}"]} + - json: {} + - random: ${gen_random_string(5)} + - authorization: ${gen_md5($TOKEN, $json, $random)} - test: name: create user which does not exist @@ -17,9 +17,9 @@ method: POST headers: Content-Type: application/json - authorization: "${authorization}" - random: "${random}" - json: "${json}" + authorization: $authorization + random: $random + json: $json validators: - {"check": "status_code", "comparator": "eq", "expected": 201} - {"check": "content.success", "comparator": "eq", "expected": true} @@ -33,9 +33,9 @@ method: POST headers: Content-Type: application/json - authorization: "${authorization}" - random: "${random}" - json: "${json}" + authorization: $authorization + random: $random + json: $json validators: - {"check": "status_code", "comparator": "eq", "expected": 500} - {"check": "content.success", "comparator": "eq", "expected": false} diff --git a/test/data/demo_template_separate.yml b/test/data/demo_template_separate.yml index cc0cd8ea..75e52d84 100644 --- a/test/data/demo_template_separate.yml +++ b/test/data/demo_template_separate.yml @@ -10,17 +10,17 @@ 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]} + - random: ${gen_random_string(5)} - data: '{"name": "user", "password": "123456"}' - - authorization: {"func": "gen_md5", "args": ["${TOKEN}", "${data}", "${random}"]} + - 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}" + authorization: $authorization + random: $random + data: $data validators: - {"check": "status_code", "comparator": "eq", "expected": 201} - {"check": "content.success", "comparator": "eq", "expected": true} @@ -36,17 +36,17 @@ 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]} + - random: ${gen_random_string(5)} - data: '{"name": "user", "password": "123456"}' - - authorization: {"func": "gen_md5", "args": ["${TOKEN}", "${data}", "${random}"]} + - 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}" + authorization: $authorization + random: $random + data: $data validators: - {"check": "status_code", "comparator": "eq", "expected": 500} - {"check": "content.success", "comparator": "eq", "expected": false} diff --git a/test/data/demo_template_sets.yml b/test/data/demo_template_sets.yml index 3625c579..4296541f 100644 --- a/test/data/demo_template_sets.yml +++ b/test/data/demo_template_sets.yml @@ -10,8 +10,8 @@ variable_binds: - TOKEN: debugtalk - data: "" - - random: {"func": "gen_random_string", "args": [5]} - - authorization: {"func": "gen_md5", "args": ["${TOKEN}", "${data}", "${random}"]} + - random: ${gen_random_string(5)} + - authorization: ${gen_md5($TOKEN, $data, $random)} request: base_url: http://127.0.0.1:5000 @@ -24,9 +24,9 @@ method: POST headers: Content-Type: application/json - authorization: "${authorization}" - random: "${random}" - data: "${data}" + authorization: $authorization + random: $random + data: $data validators: - {"check": "status_code", "comparator": "eq", "expected": 201} - {"check": "content.success", "comparator": "eq", "expected": true} @@ -41,9 +41,9 @@ method: POST headers: Content-Type: application/json - authorization: "${authorization}" - random: "${random}" - data: "${data}" + authorization: $authorization + random: $random + data: $data validators: - {"check": "status_code", "comparator": "eq", "expected": 500} - {"check": "content.success", "comparator": "eq", "expected": false} diff --git a/test/test_context.py b/test/test_context.py index cd6b89d5..c091a8bc 100644 --- a/test/test_context.py +++ b/test/test_context.py @@ -43,7 +43,7 @@ class VariableBindsUnittest(unittest.TestCase): testcase1 = { "variable_binds": [ {"GLOBAL_TOKEN": "debugtalk"}, - {"token": "${GLOBAL_TOKEN}"} + {"token": "$GLOBAL_TOKEN"} ] } testcase2 = self.testcases["register_template_variables"] @@ -65,8 +65,8 @@ class VariableBindsUnittest(unittest.TestCase): "add_two_nums": lambda x, y: x + y }, "variable_binds": [ - {"add1": {"func": "add_one", "args": [2]}}, - {"sum2nums": {"func": "add_two_nums", "args": [2, 3]}} + {"add1": "${add_one(2)}"}, + {"sum2nums": "${add_two_nums(2,3)}"} ] } testcase2 = self.testcases["bind_lambda_functions"] @@ -93,9 +93,9 @@ class VariableBindsUnittest(unittest.TestCase): }, "variable_binds": [ {"TOKEN": "debugtalk"}, - {"random": {"func": "gen_random_string", "args": [5]}}, + {"random": "${gen_random_string(5)}"}, {"data": '{"name": "user", "password": "123456"}'}, - {"authorization": {"func": "gen_md5", "args": ["${TOKEN}", "${data}", "${random}"]}} + {"authorization": "${gen_md5($TOKEN, $data, $random)}"} ] } testcase2 = self.testcases["bind_lambda_functions_with_import"] @@ -130,9 +130,9 @@ class VariableBindsUnittest(unittest.TestCase): "import_module_functions": ["test.data.custom_functions"], "variable_binds": [ {"TOKEN": "debugtalk"}, - {"random": {"func": "gen_random_string", "args": [5]}}, + {"random": "${gen_random_string(5)}"}, {"data": '{"name": "user", "password": "123456"}'}, - {"authorization": {"func": "gen_md5", "args": ["${TOKEN}", "${data}", "${random}"]}} + {"authorization": "${gen_md5($TOKEN, $data, $random)}"} ] } testcase2 = self.testcases["bind_module_functions"] @@ -165,19 +165,19 @@ class VariableBindsUnittest(unittest.TestCase): "import_module_functions": ["test.data.custom_functions"], "variable_binds": [ {"TOKEN": "debugtalk"}, - {"random": {"func": "gen_random_string", "args": [5]}}, + {"random": "${gen_random_string(5)}"}, {"data": '{"name": "user", "password": "123456"}'}, - {"authorization": {"func": "gen_md5", "args": ["${TOKEN}", "${data}", "${random}"]}} + {"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}" + "authorization": "$authorization", + "random": "$random" }, - "data": "${data}" + "data": "$data" } } test_runner.init_config(testcase, level="testcase") @@ -194,14 +194,14 @@ class VariableBindsUnittest(unittest.TestCase): "str_1": "str_value1", "str_2": "str_value2" } - self.assertEqual(self.context.get_eval_value("${str_1}"), "str_value1") - self.assertEqual(self.context.get_eval_value("${str_2}"), "str_value2") + self.assertEqual(self.context.get_eval_value("$str_1"), "str_value1") + self.assertEqual(self.context.get_eval_value("$str_2"), "str_value2") self.assertEqual( - self.context.get_eval_value(["${str_1}", "str3"]), + self.context.get_eval_value(["$str_1", "str3"]), ["str_value1", "str3"] ) self.assertEqual( - self.context.get_eval_value({"key": "${str_1}"}), + self.context.get_eval_value({"key": "$str_1"}), {"key": "str_value1"} ) @@ -209,6 +209,10 @@ class VariableBindsUnittest(unittest.TestCase): self.context.testcase_config["functions"]["gen_random_string"] = \ lambda str_len: ''.join(random.choice(string.ascii_letters + string.digits) \ for _ in range(str_len)) - result = self.context.get_eval_value( - {"func": "gen_random_string", "args": [5]}) + result = self.context.get_eval_value("${gen_random_string(5)}") self.assertEqual(len(result), 5) + + add_two_nums = lambda a, b=1: a + b + self.context.testcase_config["functions"]["add_two_nums"] = add_two_nums + self.assertEqual(self.context.get_eval_value("${add_two_nums(1)}"), 2) + self.assertEqual(self.context.get_eval_value("${add_two_nums(1, 2)}"), 3) diff --git a/test/test_testcase.py b/test/test_testcase.py index a91c284f..d32c9a3e 100644 --- a/test/test_testcase.py +++ b/test/test_testcase.py @@ -1,6 +1,6 @@ import unittest -from ate.testcase import parse_template +from ate.testcase import parse_template, parse_content_with_variables from ate import exception @@ -22,22 +22,22 @@ class TestcaseParserUnittest(unittest.TestCase): def test_parse_testcase_template(self): testcase = { "request": { - "url": "http://127.0.0.1:5000/api/users/${uid}", + "url": "http://127.0.0.1:5000/api/users/$uid", "method": "POST", "headers": { "Content-Type": "application/json", - "authorization": "${authorization}", - "random": "${random}" + "authorization": "$authorization", + "random": "$random" }, - "body": "${json}" + "body": "$json" }, "response": { - "status_code": "${expected_status}", + "status_code": "$expected_status", "headers": { "Content-Type": "application/json" }, "body": { - "success": "${expected_success}", + "success": "$expected_success", "msg": "user created successfully." } } @@ -72,8 +72,8 @@ class TestcaseParserUnittest(unittest.TestCase): def test_parse_testcase_template_miss_bind_variable(self): testcase = { "request": { - "url": "http://127.0.0.1:5000/api/users/${uid}", - "method": "${method}" + "url": "http://127.0.0.1:5000/api/users/$uid", + "method": "$method" } } with self.assertRaises(exception.ParamsError): @@ -82,8 +82,8 @@ class TestcaseParserUnittest(unittest.TestCase): def test_parse_testcase_with_new_variable_binds(self): testcase = { "request": { - "url": "http://127.0.0.1:5000/api/users/${uid}", - "method": "${method}" + "url": "http://127.0.0.1:5000/api/users/$uid", + "method": "$method" } } new_variable_binds = { @@ -96,3 +96,25 @@ class TestcaseParserUnittest(unittest.TestCase): parsed_testcase["request"]["method"], new_variable_binds["method"] ) + + def test_parse_content_with_variables(self): + content = "$var" + variables_binds = { + "var": "abc" + } + result = parse_content_with_variables(content, variables_binds) + self.assertEqual(result, "abc") + + content = "123$var/456" + variables_binds = { + "var": "abc" + } + result = parse_content_with_variables(content, variables_binds) + self.assertEqual(result, "123abc/456") + + content = "$var1" + variables_binds = { + "var2": "abc" + } + with self.assertRaises(exception.ParamsError): + parse_content_with_variables(content, variables_binds) diff --git a/test/test_utils.py b/test/test_utils.py index c20da35d..da701d30 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -115,28 +115,6 @@ class TestUtils(ApiServerUnittest): testset_list_3 = utils.load_testcases_by_path(path) self.assertEqual(testset_list_3, []) - def test_parse_content_with_variables(self): - content = "${var}" - variables_binds = { - "var": "abc" - } - result = utils.parse_content_with_variables(content, variables_binds) - self.assertEqual(result, "abc") - - content = "123${var}456" - variables_binds = { - "var": "abc" - } - result = utils.parse_content_with_variables(content, variables_binds) - self.assertEqual(result, "123abc456") - - content = "${var1}" - variables_binds = { - "var2": "abc" - } - with self.assertRaises(exception.ParamsError): - utils.parse_content_with_variables(content, variables_binds) - def test_is_variable(self): content = "$var" self.assertTrue(utils.is_variable(content))