From 822a20b7649c2692e88a7b43df339363d94f036e Mon Sep 17 00:00:00 2001 From: alexv Date: Tue, 15 Dec 2015 19:26:02 +0900 Subject: [PATCH] made prevoty/xss.json test work with jsonpickle. --- rester/__init__.py | 2 +- rester/examples/prevoty/test_suite.json | 1 + rester/examples/prevoty/tests/xss.json | 106 +++++++++++++----------- rester/exc.py | 8 +- rester/loader.py | 87 +++++++++++++++---- rester/manifest.py | 12 +-- rester/testcase.py | 10 ++- setup.py | 2 +- 8 files changed, 149 insertions(+), 79 deletions(-) diff --git a/rester/__init__.py b/rester/__init__.py index 59cd959..05a8ba7 100644 --- a/rester/__init__.py +++ b/rester/__init__.py @@ -1 +1 @@ -from . import apirunner \ No newline at end of file +from . import apirunner diff --git a/rester/examples/prevoty/test_suite.json b/rester/examples/prevoty/test_suite.json index 87cb75d..cec1382 100755 --- a/rester/examples/prevoty/test_suite.json +++ b/rester/examples/prevoty/test_suite.json @@ -1,3 +1,4 @@ { + "py/object":"rester.TestSuite", "test_cases":["tests/weather.json"] } diff --git a/rester/examples/prevoty/tests/xss.json b/rester/examples/prevoty/tests/xss.json index 68bcebf..3361382 100755 --- a/rester/examples/prevoty/tests/xss.json +++ b/rester/examples/prevoty/tests/xss.json @@ -1,52 +1,62 @@ { - "name":"Prevoty XSS", - "globals":{ - "variables":{ - "baseApiUrl":"https://api.prevoty.com", - "api_key":"82ddb7e2-883c-4290-83f7-d15a8ba4aa7e", - "rule_key":"108ee29a-a2cb-49ec-b053-2e82f198ce08", - "expected_value":2 - } - }, - "testSteps":[ - { - "name":"Prevoty Key Verification", - "dumpResponse":true, - "skip":false, - "apiUrl":"{baseApiUrl}/1/key/verify?api_key={api_key}", - "assertMap": { - "payLoad":{ - "verified":true, - "message":"api_key is valid" - } + "py/object":"rester.loader.TestCase", + "py/state": { + "name": "Prevoty XSS", + "variables": { + "py/object": "rester.manifest.Variables", + "variables": { + "baseApiUrl": "https://api.prevoty.com", + "api_key": "82ddb7e2-883c-4290-83f7-d15a8ba4aa7e", + "rule_key": "108ee29a-a2cb-49ec-b053-2e82f198ce08", + "expected_value": 2 + } + }, + "testSteps": [ + { + "py/object": "rester.loader.TestStep", + "py/state": { + "name": "Prevoty Key Verification", + "dumpResponse": true, + "skip": false, + "apiUrl": "{baseApiUrl}/1/key/verify?api_key={api_key}", + "assertMap": { + "payLoad": { + "verified": true, + "message": "api_key is valid" + } + } } - }, - { - "name":"XSS Basic test", - "apiUrl":"{baseApiUrl}/1/xss/filter", - "headers":{ - "content-type":"application/json;" - }, - "method":"post", - "params":{ - "api_key":"{api_key}", - "input":"", - "rule_key":"{rule_key}" - }, - "assertMap":{ - "headers":{ - "content-type":"application/json; charset=utf-8" - }, - "payLoad":{ - "message":"", - "output":"Hello World!", - "output":"String", - "statistics.javascript_tags":"-ge {expected_value}", - "statistics.transformations":"int", - "statistics.transformations":"-gt 3", - "statistics.prevoty_link_metadata":"Object" - } + }, + { + "py/object": "rester.loader.TestStep", + "py/state": { + "name": "XSS Basic test", + "apiUrl": "{baseApiUrl}/1/xss/filter", + "headers": { + "content-type": "application/json;" + }, + "method": "post", + "params": { + "api_key": "{api_key}", + "input": "", + "rule_key": "{rule_key}" + }, + "assertMap": { + "headers": { + "content-type": "application/json; charset=utf-8" + }, + "payLoad": { + "message": "", + "output": "Hello World!", + "output": "String", + "statistics.javascript_tags": "-ge {expected_value}", + "statistics.transformations": "int", + "statistics.transformations": "-gt 3", + "statistics.prevoty_link_metadata": "Object" + } + } } - } - ] + } + ] + } } diff --git a/rester/exc.py b/rester/exc.py index 5f3c7d7..e69bd0d 100644 --- a/rester/exc.py +++ b/rester/exc.py @@ -26,7 +26,7 @@ def __call__(self): for step in self.case.steps: self.logger.debug('Test Step Name : %s', step.name) - if step.get('skip', False): + if step.skip: self.logger.info('\n=======> Skipping test case : ' + step.name) self.skipped.append(step) continue @@ -61,7 +61,7 @@ def _format_logs(self, lc): def _build_param_dict(self, test_step): params = {} if hasattr(test_step, 'params') and test_step.params is not None: - for key, value in test_step.params.items().items(): + for key, value in test_step.params.iteritems(): params[key] = self.case.variables.expand(value) return params @@ -77,7 +77,7 @@ def _execute_test_step(self, test_step): headers = {} if hasattr(test_step, 'headers') and test_step.headers is not None: self.logger.debug('Found Headers') - for key, value in test_step.headers.items().items(): + for key, value in test_step.headers.iteritems(): headers[key] = self.case.variables.expand(value) # process and set up params @@ -139,7 +139,7 @@ def _assert_element_list(self, section, failures, test_step, response, assert_li if value in json_types: self.logger.info('Found json type : %s ', value) - if type(json_eval_expr) == DictWrapper: + if type(json_eval_expr) == dict: value = 'Object' json_eval_expr = {} diff --git a/rester/loader.py b/rester/loader.py index 29715a9..2213ad5 100644 --- a/rester/loader.py +++ b/rester/loader.py @@ -1,3 +1,5 @@ +import jsonpickle + from rester.struct import DictWrapper import json import os @@ -23,38 +25,87 @@ def _load(self, data): filename = os.path.join(os.path.dirname(self.filename), case) self.test_cases.append(TestCase(self, filename)) + def __getstate__(self): + state = self.__dict__.copy() + # del elements of state you don't want to pickle here + return state + + def __setstate__(self, state): + """ + behavior for unpickling. setting default values here + :param state: + :return: + """ + # Manipulate state here before assigning it to our instance + + self.__dict__.update(state) + class TestCase(object): - def __init__(self, suite, filename): - self.filename = filename - self.data = None + def __init__(self, suite): + """ + generate a TestCase + :param suite: none if not part of a suite. + """ self.variables = Variables() if suite: self.variables.update(suite.variables) - self.load() - def __getattr__(self, key): - return getattr(self.data, key) + self.testSteps = [] @property def steps(self): - return self.data.testSteps + return self.testSteps @property def request_opts(self): return self.variables.get('request_opts', {}) - def load(self): - with open(self.filename) as fh: - data = load(self.filename, fh) - self._load(data) + def __getstate__(self): + state = self.__dict__.copy() + # del elements of state you don't want to pickle here + return state - def _load(self, data): - self.data = DictWrapper(data) - self.variables.update(data.get('globals', {}).get('variables', {}).items()) + def __setstate__(self, state): + """ + behavior for unpickling. setting default values here + :param state: + :return: + """ + # Manipulate state here before assigning it to our instance + + self.__dict__.update(state) + + +class TestStep(object): + def __init__(self): + """ + Initializing a default TestStep. Not used usually but here in case we need a default object to serialize. + :return: + """ + self.name = "" + self.skip = False + self.apiUrl = "" + self.dumpResponse = True + self.assertMap = {} + self.headers = {} + self.params = {} + self.method = "get" + + def __getstate__(self): + state = self.__dict__.copy() + # del elements of state you don't want to pickle here + return state + + def __setstate__(self, state): + """ + behavior for unpickling. setting default values here + :param state: + :return: + """ + # Manipulate state here before assigning it to our instance + if not hasattr(state, 'skip'): + state['skip'] = False + self.__dict__.update(state) -def load(filename, fh): - if filename.endswith(".yaml"): - return yaml.load(fh.read()) - return json.load(fh) diff --git a/rester/manifest.py b/rester/manifest.py index 0efeb0c..89a05a9 100644 --- a/rester/manifest.py +++ b/rester/manifest.py @@ -13,23 +13,23 @@ class Variables(object): _pattern = re.compile(r'\{(\w+)\}') def __init__(self, variables=None): - self._variables = variables or {} + self.variables = variables or {} def __iter__(self): - for k, v in self._variables.iteritems(): + for k, v in self.variables.iteritems(): yield k, v def get(self, k, default): - return self._variables.get(k, default) + return self.variables.get(k, default) def update(self, values): for k, v in values: self.add_variable(k, v) def add_variable(self, key, value): - if self._variables.get(key, ''): + if self.variables.get(key, ''): self.logger.warn('WARN!!! Variable : %s Already defined!!!', key) - self._variables[key] = self.expand(value) + self.variables[key] = self.expand(value) def expand(self, expression): """Expands logical constructions.""" @@ -37,7 +37,7 @@ def expand(self, expression): if not is_string(expression): return expression - result = self._pattern.sub(lambda var: str(self._variables[var.group(1)]), expression) + result = self._pattern.sub(lambda var: str(self.variables[var.group(1)]), expression) result = result.strip() self.logger.debug('expand : %s - result : %s', expression, result) diff --git a/rester/testcase.py b/rester/testcase.py index c9c002a..f7c51a2 100644 --- a/rester/testcase.py +++ b/rester/testcase.py @@ -3,6 +3,7 @@ from rester.http import HttpClient from rester.loader import TestSuite, TestCase import yaml +import jsonpickle class bcolors: HEADER = '\033[95m' @@ -26,7 +27,14 @@ def run_test_suite(self, test_suite_file_name): self._run_case(test_case) def run_test_case(self, test_case_file): - case = TestCase(None, test_case_file) + tc = TestCase(None) + tcenc = jsonpickle.encode(tc) + with open(test_case_file) as fh: + if test_case_file.endswith(".yaml"): + # TODO : probably need to replace that with a custom backend for json pickle since YAML is JSON + return yaml.load(fh.read()) + case = jsonpickle.decode(fh.read()) + case.filename = test_case_file self._run_case(case) def _run_case(self, case): diff --git a/setup.py b/setup.py index de88f82..b4abc1a 100644 --- a/setup.py +++ b/setup.py @@ -13,5 +13,5 @@ test_suite="test", description='Rest API Testing', long_description=open('README.md').read(), - install_requires=["requests", "testfixtures", "PyYAML>=3.9"], + install_requires=["requests", "testfixtures", "PyYAML>=3.9", "jsonpickle"], )