Example #1
0
    def test_variable_binding(self):
        """ Test that tests successfully bind variables """
        element = 3
        test_config = [{
            "url": "/ping"
        }, {
            "name": "cheese"
        }, {
            "expected_status": ["200", 204, "202"]
        }, {
            "variable_binds": {
                'var': 'value'
            }
        }]
        context = Context()
        test = TestCase('', None, context)
        test.parse(test_config)
        binds = test.variable_binds
        self.assertEqual(1, len(binds))
        self.assertEqual('value', binds['var'])

        # Test that updates context correctly

        test.pre_update(context)
        self.assertEqual('value', context.get_value('var'))
 def test_parse_content_template_unicode(self):
     """ Unicode parsing tests """
     node = {'template': u'myval 😽 $var'}
     handler = ContentHandler.parse_content(node)
     context = Context()
     context.bind_variable('var', 'cheese')
     self.assertEqual(u'myval 😽 cheese', handler.get_content(context))
Example #3
0
    def test_parse_validator_comparator(self):
        """ Test parsing a comparator validator """
        test_config = {
            'name':
            'Default',
            'url':
            '/api',
            'validators': [{
                'comparator': {
                    'jsonpath_mini': 'id',
                    'comparator': 'eq',
                    'expected': {
                        'template': '$id'
                    }
                }
            }]
        }
        test = TestCase('', None, None)
        test.parse(test_config)
        self.assertTrue(test.validators)
        self.assertEqual(1, len(test.validators))

        context = Context()
        context.bind_variable('id', 3)

        myjson = '{"id": "3"}'
        failure = test.validators[0].validate(myjson, context=context)
        self.assertTrue(test.validators[0].validate(myjson, context=context))
        self.assertFalse(test.validators[0].validate(myjson))
Example #4
0
    def test_parse_test_templated_headers(self):
        """ Test parsing with templated headers """

        heads = {"Accept": "Application/json", "$AuthHeader": "$AuthString"}
        templated_heads = {
            "Accept": "Application/json",
            "apikey": "magic_passWord"
        }
        context = Context()
        context.bind_variables({
            'AuthHeader': 'apikey',
            'AuthString': 'magic_passWord'
        })

        # If this doesn't throw errors we have silent failures
        input_invalid = {
            "url": "/ping",
            "method": "DELETE",
            "NAME": "foo",
            "group": "bar",
            "body": "<xml>input</xml>",
            "headers": 'goat'
        }
        try:
            test = TestCase('', None, context)
            test.parse(input_invalid)
            fail("Expected error not thrown")
        except ValidatorError:
            pass
Example #5
0
    def test_invalid_gen_type(self):
        c = Context()
        with self.assertRaises(ValueError) as context:
            c.add_generator('example', [1, 2, 3])

        self.assertTrue('Cannot add generator' in str(context.exception))

        self.assertRaises(ValueError, c.add_generator, 'example', [1, 2, 3])
Example #6
0
 def test_url_templating(self):
     context = Context()
     test = TestCase('', None, None, context)
     test.url = {'template': "$cheese"}
     self.assertTrue(test.is_dynamic())
     self.assertEqual({'template': '$cheese'}, test.url)
     self.assertTrue(test.templates['url'])
     context.bind_variable('cheese', 'liquid_cheese')
     self.assertEqual('liquid_cheese', test.url)
Example #7
0
    def test_header_templating(self):
        context = Context()
        test = TestCase('', None, None, context)
        head_templated = {'x': {'template': "$val"}}

        context.bind_variables({'val': 'gouda'})
        # No templating applied
        test.headers = head_templated
        self.assertEqual(1, len(test.headers))
        self.assertEqual('gouda', test.headers['x'])
Example #8
0
 def test_test_content_templating(self):
     context = Context()
     test = TestCase('', None, None, context)
     handler = ContentHandler()
     handler.is_template_content = True
     handler.content = '{"first_name": "Gaius","id": "$id","last_name": "Baltar","login": "******"}'
     context.bind_variables({'id': 9, 'login': '******'})
     test.body = handler
     test.pre_update(context=context)
     self.assertEqual(
         string.Template(handler.content).safe_substitute(
             context.get_values()), test.body)
 def test_parse_content_templated(self):
     """ Test parsing of templated content """
     node = {'template': 'myval $var'}
     handler = ContentHandler.parse_content(node)
     context = Context()
     context.bind_variable('var', 'cheese')
     self.assertEqual(node['template'], handler.content)
     self.assertEqual('myval cheese', handler.get_content(context))
     self.assertTrue(handler.is_dynamic())
     self.assertFalse(handler.is_file)
     self.assertFalse(handler.is_template_path)
     self.assertTrue(handler.is_template_content)
Example #10
0
 def test_mixing_binds(self):
     """ Ensure that variables are set correctly when mixing explicit declaration and variables """
     context = Context()
     context.add_generator('gen', count_gen())
     context.bind_variable('foo', '100')
     self.assertEqual(1, context.mod_count)
     context.bind_generator_next('foo', 'gen')
     self.assertEqual(1, context.get_value('foo'))
     self.assertEqual(2, context.mod_count)
Example #11
0
    def test_variables(self):
        """ Test bind/return of variables """

        context = Context()
        self.assertTrue(context.get_value('foo') is None)
        self.assertEqual(0, context.mod_count)

        context.bind_variable('foo', 'bar')
        self.assertEqual('bar', context.get_value('foo'))
        self.assertEqual('bar', context.get_values()['foo'])
        self.assertEqual(1, context.mod_count)

        context.bind_variable('foo', 'bar2')
        self.assertEqual('bar2', context.get_value('foo'))
        self.assertEqual(2, context.mod_count)
Example #12
0
    def test_generator_bind(self):
        """ Test generator setting to variables """
        context = Context()
        self.assertEqual(0, len(context.get_generators()))
        my_gen = count_gen()
        context.add_generator('gen', my_gen)

        context.bind_generator_next('foo', 'gen')
        self.assertEqual(1, context.mod_count)
        self.assertEqual(1, context.get_value('foo'))
        self.assertTrue(2, next(context.get_generator('gen')))
        self.assertTrue(3, next(my_gen))
Example #13
0
 def test_parse_extractor_bind(self):
     """ Test parsing of extractors """
     test_config = {
         "url": '/api',
         'extract_binds': {
             'id': {
                 'jsonpath_mini': 'idfield'
             },
             'name': {
                 'jsonpath_mini': 'firstname'
             }
         }
     }
     context = Context()
     test = TestCase('', None, None, context)
     test.parse(test_config)
     test.pre_update(context)
     self.assertTrue(test.extract_binds)
     self.assertEqual(2, len(test.extract_binds))
     self.assertTrue('id' in test.extract_binds)
     self.assertTrue('name' in test.extract_binds)
     #
     # Test extractors config'd correctly for extraction
     myjson = '{"idfield": 3, "firstname": "bob"}'
     extracted = test.extract_binds['id'].extract(myjson)
     self.assertEqual(3, extracted)
     #
     extracted = test.extract_binds['name'].extract(myjson)
     self.assertEqual('bob', extracted)
Example #14
0
    def test_abstract_extractor_templating(self):
        """ Test that abstract extractors template the query """

        class A(validators.AbstractExtractor):
            def extract_internal(self, query=None, body=None, headers=None, args=None):
                ...

        ext = A()
        ext.query = '$val.vee'
        ext.is_templated = True
        context = Context()
        context.bind_variable('val', 'foo')
        self.assertEqual('$val.vee', ext.templated_query())
        self.assertEqual('foo.vee', ext.templated_query(context=context))

        ext._is_templated = False
        self.assertEqual('$val.vee', ext.templated_query(context=context))
    def test_content_templating(self):
        """ Test content and templating of it """
        handler = ContentHandler()
        body = '$variable value'
        templated_body = 'bar value'
        context = Context()
        context.bind_variable('variable', 'bar')

        # No templating
        handler.setup(body, is_template_content=False)
        self.assertEqual(body, handler.get_content())
        self.assertEqual(body, handler.get_content(context))
        self.assertRaises(TypeError, handler.setup, [])
        # Templating
        handler.setup(body, is_template_content=True)
        self.assertEqual(body, handler.get_content())
        self.assertEqual(templated_body, handler.get_content(context))
Example #16
0
    def test_generator(self):
        """ Test adding a generator """
        context = Context()
        self.assertEqual(0, len(context.get_generators()))
        my_gen = count_gen()
        context.add_generator('gen', my_gen)

        self.assertEqual(1, len(context.get_generators()))
        self.assertTrue('gen' in context.get_generators())
        self.assertTrue(context.get_generator('gen') is not None)
Example #17
0
    def test_abstract_extractor_readableconfig(self):
        """ Test human-readable extractor config string output """
        config = 'key.val'
        extractor = validators.parse_extractor('jsonpath_mini', config)
        expected_string = 'Extractor Type: jsonpath_mini,  Query: "key.val", Templated?: False'
        self.assertEqual(expected_string, extractor.get_readable_config())

        # Check empty context & args uses okay
        context = Context()
        self.assertEqual(
            expected_string, extractor.get_readable_config(context=context))
        context.bind_variable('foo', 'bar')
        self.assertEqual(
            expected_string, extractor.get_readable_config(context=context))
        extractor.args = dict()
        self.assertEqual(
            expected_string, extractor.get_readable_config(context=context))

        # Check args output is handled correctly
        extractor.args = {'caseSensitive': True}
        self.assertEqual(expected_string + ", Args: " + str(extractor.args),
                         extractor.get_readable_config(context=context))

        # Check template handling is okay
        config = {'template': 'key.$templated'}
        context.bind_variable('templated', 'val')
        extractor = validators.parse_extractor('jsonpath_mini', config)
        expected_string = 'Extractor Type: jsonpath_mini,  Query: "key.val", Templated?: True'
        self.assertEqual(
            expected_string, extractor.get_readable_config(context=context))
Example #18
0
    def __init__(self,
                 base_url,
                 extract_binds,
                 variable_binds,
                 context=None,
                 config=None):
        self.__base_url = base_url
        self.__url = None
        self.__body = None
        self.__config = config if config else TestCaseConfig()
        self.__auth_username = None
        self.__auth_password = None
        self.__delay = 0
        self.__verbose = False
        self.__ssl_insecure = False
        self.__response_headers = None
        self.__response_code = None
        self.__passed = False
        self.__failure_list = []
        self.__abs_url = False

        self.__header_dict = {}
        self.__http_method = EnumHttpMethod.GET.name
        self.__group = TestCaseGroup.DEFAULT_GROUP
        self.__name = TestCase.DEFAULT_NAME
        self._should_stop_on_failure = False
        self._test_run_delay = 0
        self._auth_type = AuthType.BASIC
        self._curl_options = None
        self.__variable_binds_dict = variable_binds if variable_binds else {}
        self.__generator_binds_dict = {}
        self.__extract_binds_dict = extract_binds if extract_binds else {}
        self.__validator_list = []

        self.__expected_http_status_code_list = [200]
        self.__context = Context() if context is None else context

        self.templates = {}
        self.result = None
        self.config = config
Example #19
0
    def test_parse_extractor_minijson(self):
        config = 'key.val'
        extractor = validators.MiniJsonExtractor.parse(config)
        myjson = '{"key": {"val": 3}}'
        context = Context()
        context.bind_variable('node', 'val')

        extracted = extractor.extract(body=myjson)
        self.assertEqual(3, extracted)
        self.assertEqual(extracted, extractor.extract(
            body=myjson, context=context))

        try:
            val = extractor.extract(body='[31{]')
            self.fail("Should throw exception on invalid JSON")
        except ValueError:
            pass

        # Templating
        config = {'template': 'key.$node'}
        extract = validators.MiniJsonExtractor.parse(config)
        self.assertEqual(3, extract.extract(myjson, context=context))
Example #20
0
 def test_update_context_variables(self):
     variable_binds = {'foo': 'correct', 'test': 'value'}
     context = Context()
     test = TestCase('', None, variable_binds, context=context)
     context.bind_variable('foo', 'broken')
     test.pre_update(context)
     self.assertEqual('correct', context.get_value('foo'))
     self.assertEqual('value', context.get_value('test'))
Example #21
0
 def test_parse_extractor_bind(self):
     """ Test parsing of extractors """
     test_config = {
         "url": '/api',
         'extract_binds': {
             'id': {
                 'jsonpath_mini': 'idfield'
             },
             'name': {
                 'jsonpath_mini': 'firstname'
             }
         }
     }
     context = Context()
     test = TestCase('', None, None, context)
     test.parse(test_config)
     test.pre_update(context)
Example #22
0
    def __init__(self,
                 name,
                 context=None,
                 extract_binds=None,
                 variable_binds=None,
                 config=None):
        self.__testcase_list = []
        self.__benchmark_list = []
        self.__config = None

        self.__name = name
        self.__testcase_file = set()
        self.__context = context if context else Context()
        self.__extract_binds = extract_binds if extract_binds else {}
        self.__variable_binds = variable_binds if variable_binds else {}
        self.__is_global = None

        self.config = config
Example #23
0
    def test_parse_validator(self):
        """ Test basic parsing using registry """
        config = {
            'jsonpath_mini': 'key.val',
            'comparator': 'eq',
            'expected': 3
        }
        validator = validators.parse_validator('comparator', config)
        myjson = '{"key": {"val": 3}}'
        comp = validator.validate(body=myjson)
        self.assertTrue(comp)

        validator = validators.parse_validator('comparator', config)
        my_body_str = '<html></html>'
        comp = validator.validate(body=my_body_str)
        self.assertEqual(comp.message, 'Extractor threw exception')

        validator = validators.parse_validator('comparator', config)
        myjson_1 = '{"key": {"val": 4}}'
        comp = validator.validate(body=myjson_1)
        self.assertFalse(comp)

        # Try it with templating
        # Try it with templating
        config['jsonpath_mini'] = {'template': 'key.$node'}
        validator = validators.parse_validator('comparator', config)
        context = Context()
        context.bind_variable('node', 'val')
        comp = validator.validate(myjson, context=context)
        self.assertTrue(comp)

        # Try it with templating
        del config['jsonpath_mini']
        config['jmespath'] = {'template': 'key.$node'}
        validator = validators.parse_validator('comparator', config)
        context = Context()
        context.bind_variable('node', 'val')
        comp = validator.validate(myjson, context=context)
        self.assertTrue(comp)
    def test_unicode_templating(self):
        """ A couple combination of templating using Unicode data """
        handler = ContentHandler()
        context = Context()

        # ASCII body, unicode data
        body = '$variable value'
        context.bind_variable('variable', u'😽')
        handler.setup(body, is_template_content=True)
        self.assertEqual(body, handler.get_content())
        self.assertEqual(u'😽 value', handler.get_content(context))

        # Unicode body, ASCII data
        context.bind_variable('variable', u'string')
        body = u'$variable 😽 value'
        handler.setup(body, is_template_content=True)
        self.assertEqual(u'$variable 😽 value', handler.get_content())
        self.assertEqual(u'string 😽 value', handler.get_content(context))

        # All the Unicodes, all the times!
        context.bind_variable('variable', u'😽')
        body = u'$variable 😽 value'
        handler.setup(body, is_template_content=True)
        self.assertEqual(u'😽 😽 value', handler.get_content(context))
Example #25
0
    def test_validator_comparator_templating(self):
        """ Try templating comparator validator """
        config = {
            'jsonpath_mini': {'template': 'key.$node'},
            'comparator': 'eq',
            'expected': 3
        }
        context = Context()
        context.bind_variable('node', 'val')
        myjson_pass = '******'
        myjson_fail = '{"id": 3, "key": {"val": 4}}'
        comp = validators.ComparatorValidator.parse(config)

        self.assertTrue(comp.validate(body=myjson_pass, context=context))
        self.assertFalse(comp.validate(body=myjson_fail, context=context))

        # Template expected
        config['expected'] = {'template': '$id'}
        context.bind_variable('id', 3)
        self.assertTrue(comp.validate(body=myjson_pass, context=context))
        self.assertFalse(comp.validate(body=myjson_fail, context=context))
Example #26
0
    def test_content_file_template(self):
        """ Test file read and templating of read files in this directory """
        variables = {'id': 1, 'login': '******'}
        context = Context()

        file_path = os.path.dirname(os.path.realpath(__file__))
        file_path = os.path.join(file_path, 'person_body_template.json')

        file_content = None
        with open(file_path, 'r') as f:
            file_content = f.read()

        # Test basic read
        handler = ContentHandler()
        handler.setup(file_path, is_file=True)
        self.assertEqual(file_content, handler.get_content())

        # Test templating of read content
        handler.setup(file_path, is_file=True, is_template_content=True)
        self.assertEqual(file_content, handler.get_content())
        self.assertEqual(file_content,
                         handler.get_content(context))  # No substitution
        substituted = string.Template(file_content).safe_substitute(variables)
        context.bind_variables(variables)
        self.assertEqual(substituted, handler.get_content(context))

        # Test path templating
        templated_file_path = '$filepath'
        context.bind_variable('filepath', file_path)
        handler.setup(file_path, is_file=True, is_template_path=True)
        self.assertEqual(file_content, handler.get_content(context))

        # Test double templating with files
        handler.setup(file_path,
                      is_file=True,
                      is_template_path=True,
                      is_template_content=True)
        self.assertEqual(substituted, handler.get_content(context=context))
Example #27
0
 def __init__(self):
     self.__context = Context()
     self.__extract_binds = {}
     self.__variable_binds = {}
     self.config = TestCaseConfig()
Example #28
0
class TestCase:
    DEFAULT_NAME = "NO NAME"

    KEYWORD_DICT = {
        k: v
        for k, v in TestCaseKeywords.__dict__.items() if not k.startswith('__')
    }

    def __init__(self,
                 base_url,
                 extract_binds,
                 variable_binds,
                 context=None,
                 config=None):
        self.__base_url = base_url
        self.__url = None
        self.__body = None
        self.__config = config if config else TestCaseConfig()
        self.__auth_username = None
        self.__auth_password = None
        self.__delay = 0
        self.__verbose = False
        self.__ssl_insecure = False
        self.__response_headers = None
        self.__response_code = None
        self.__passed = False
        self.__failure_list = []
        self.__abs_url = False

        self.__header_dict = {}
        self.__http_method = EnumHttpMethod.GET.name
        self.__group = TestCaseGroup.DEFAULT_GROUP
        self.__name = TestCase.DEFAULT_NAME
        self._should_stop_on_failure = False
        self._test_run_delay = 0
        self._auth_type = AuthType.BASIC
        self._curl_options = None
        self.__variable_binds_dict = variable_binds if variable_binds else {}
        self.__generator_binds_dict = {}
        self.__extract_binds_dict = extract_binds if extract_binds else {}
        self.__validator_list = []

        self.__expected_http_status_code_list = [200]
        self.__context = Context() if context is None else context

        self.templates = {}
        self.result = None
        self.config = config

    def __str__(self):
        return json.dumps(self, default=Parser.safe_to_json)

    @property
    def config(self) -> Optional[TestCaseConfig]:
        return self.__config

    @config.setter
    def config(self, config_object: TestCaseConfig):
        if config_object:
            self.variable_binds.update(config_object.variable_binds)
            self.generator_binds.update(config_object.generators)

    @property
    def auth_username(self):
        return self.__auth_username

    @auth_username.setter
    def auth_username(self, username):
        self.__auth_username = Parser.coerce_string_to_ascii(username)

    @property
    def auth_password(self):
        return self.__auth_password

    @auth_password.setter
    def auth_password(self, password):
        self.__auth_password = Parser.coerce_string_to_ascii(password)

    @property
    def http_method(self):
        return self.__http_method

    @http_method.setter
    def http_method(self, method: str):
        __method = ["GET", "PUT", "POST", "DELETE", "PATCH"]
        if method.upper() not in __method:
            raise HttpMethodError("Method %s is not supported." % method)
        self.__http_method = method.upper()

    @property
    def name(self):
        return self.__name

    @property
    def group(self):
        return self.__group

    @property
    def is_passed(self):
        return bool(self.__passed)

    @property
    def url(self):
        val = self.realize_template("url", self.__context)
        if val is None:
            val = self.__url
        if not self.__abs_url:
            val = urljoin(self.__base_url, val)
        if isinstance(val, dict):
            logger.warning("URL is not applied template values.")
        return val

    @url.setter
    def url(self, value):

        if isinstance(value, dict):
            # this is the templated url , we need to convert it into actual URL
            template_str = Parser.lowercase_keys(value)['template']
            self.set_template("url", Parser.coerce_to_string(template_str))
            self.__url = value
        else:
            self.__url = value

    @property
    def generator_binds(self):
        return self.__generator_binds_dict

    @property
    def delay(self):
        return self.__delay

    @generator_binds.setter
    def generator_binds(self, value: Dict):
        binds_dict = Parser.flatten_dictionaries(value)
        __binds_dict = {str(k): str(v) for k, v in binds_dict.items()}
        self.__generator_binds_dict.update(__binds_dict)

    @property
    def variable_binds(self):
        return self.__variable_binds_dict

    @property
    def extract_binds(self):
        return self.__extract_binds_dict

    @extract_binds.setter
    def extract_binds(self, bind_dict):

        bind_dict = Parser.flatten_dictionaries(bind_dict)

        for variable_name, extractor in bind_dict.items():

            if not isinstance(extractor, dict) or len(extractor) == 0:
                raise BindError(
                    "Extractors must be defined as maps of extractorType:{configs} with 1 entry"
                )
            if len(extractor) > 1:
                raise BindError(
                    "Cannot define multiple extractors for given variable name"
                )
            for extractor_type, extractor_config in extractor.items():
                self.__extract_binds_dict[variable_name] = parse_extractor(
                    extractor_type, extractor_config)

    @property
    def expected_http_status_code_list(self):
        return [int(x) for x in self.__expected_http_status_code_list]

    @expected_http_status_code_list.setter
    def expected_http_status_code_list(self, value):
        self.__expected_http_status_code_list = value

    @property
    def validators(self):
        return self.__validator_list

    @validators.setter
    def validators(self, validator_list):
        if not isinstance(validator_list, list):
            raise ValidatorError(
                'Misconfigured validator section, must be a list of validators'
            )
        for validator in validator_list:
            if not isinstance(validator, dict):
                raise ValidatorError(
                    "Validators must be defined as validatorType:{configs} ")
            for validator_type, validator_config in validator.items():
                validator = parse_validator(validator_type, validator_config)
                self.__validator_list.append(validator)

    @property
    def headers(self) -> Dict:
        # if not self.templates.get('headers'):
        #     return self.__header_dict
        context_values = self.__context.get_values()
        header_dict = {}
        for key, header in self.__header_dict.items():
            if isinstance(header, dict):
                if key == 'template':
                    for k, v in header.items():
                        templated_string = string.Template(v).safe_substitute(
                            context_values)
                        header_dict[k] = templated_string
                    continue
                templated_value = header.get('template')
                if templated_value:
                    templated_string = string.Template(
                        templated_value).safe_substitute(context_values)
                    header_dict[key] = templated_string
                else:
                    logger.warning(
                        "Skipping the header: %s. We don't support mapping as header"
                        % header)
            else:
                header_dict[key] = header

        return header_dict

    @headers.setter
    def headers(self, headers):
        config_value = Parser.flatten_dictionaries(headers)
        if isinstance(config_value, dict):
            for key, value in config_value.items():
                if isinstance(value, dict):
                    if value.get('template'):
                        self.set_template("headers", value.get('template'))
            self.__header_dict.update(config_value)
        else:
            raise ValidatorError(
                "Illegal header type: headers must be a dictionary or list of dictionary keys"
            )

    def set_template(self, variable_name, template_string):
        self.templates[variable_name] = string.Template(str(template_string))

    @property
    def body(self):
        if isinstance(self.__body, str) or self.__body is None:
            return self.__body
        return self.__body.get_content(context=self.__context)

    @body.setter
    def body(self, value):
        if value:
            if isinstance(value, bytes):
                self.__body = ContentHandler.parse_content(value.decode())
            elif isinstance(value, str):
                self.__body = ContentHandler.parse_content(value)
            else:
                self.__body = value
        else:
            self.__body = value

    @property
    def failures(self):
        return self.__failure_list

    def realize_template(self, variable_name, context):
        if (context or self.templates) is None or (variable_name
                                                   not in self.templates):
            return None
        if not context.get_values():
            return None
        val = self.templates[variable_name].safe_substitute(
            context.get_values())
        return val

    def parse(self, testcase_dict):
        testcase_dict = Parser.flatten_lowercase_keys_dict(testcase_dict)

        for keyword in TestCase.KEYWORD_DICT.keys():
            value = testcase_dict.get(keyword)
            if value is None:
                continue

            if keyword == TestCaseKeywords.auth_username:
                self.auth_username = value
            elif keyword == TestCaseKeywords.auth_password:
                self.auth_password = value
            elif keyword == TestCaseKeywords.method:
                self.http_method = value
            elif keyword == TestCaseKeywords.delay:
                self.__delay = int(value)
            elif keyword == TestCaseKeywords.group:
                self.__group = value
            elif keyword == TestCaseKeywords.name:
                self.__name = value
            elif keyword == TestCaseKeywords.url:
                self.url = value
            elif keyword == TestCaseKeywords.extract_binds:
                self.extract_binds = value
            elif keyword == TestCaseKeywords.validators:
                self.validators = value
            elif keyword == TestCaseKeywords.headers:
                self.headers = value
            elif keyword == TestCaseKeywords.variable_binds:
                self.__variable_binds_dict = Parser.flatten_dictionaries(value)
            elif keyword == TestCaseKeywords.generator_binds:
                self.__generator_binds_dict = {
                    str(k): str(v)
                    for k, v in Parser.flatten_dictionaries(value)
                }
            elif keyword == TestCaseKeywords.options:
                raise NotImplementedError("Yet to Support")
            elif keyword == TestCaseKeywords.body:
                self.body = value
            elif keyword == TestCaseKeywords.absolute_urls:
                self.__abs_url = Parser.safe_to_bool(value)

        expected_status = testcase_dict.get(TestCaseKeywords.expected_status,
                                            [])
        if expected_status:
            self.expected_http_status_code_list = expected_status
        else:
            if self.http_method in ["POST", "PUT", "DELETE"]:
                self.expected_http_status_code_list = [200, 201, 204]

    def pre_update(self, context):
        if self.variable_binds:
            context.bind_variables(self.variable_binds)
        if self.generator_binds:
            for key, value in self.generator_binds.items():
                context.bind_generator_next(key, value)

    def post_update(self, context):
        if self.extract_binds:
            for key, value in self.extract_binds.items():
                result = value.extract(body=self.body,
                                       headers=self.headers,
                                       context=context)
                if result:
                    context.bind_variable(key, result)

    def is_dynamic(self):
        if self.templates or (isinstance(self.__body, ContentHandler)
                              and self.__body.is_dynamic()):
            return True
        return False

    def render(self):
        if self.is_dynamic() or self.__context is not None:
            if isinstance(self.__body, ContentHandler):
                self.__body = self.__body.get_content(self.__context)

    def __perform_validation(self) -> List:

        failure_list = []
        for validator in self.validators:
            logger.debug("Running validator: %s" % validator.name)
            validate_result = validator.validate(body=self.body,
                                                 headers=self.headers,
                                                 context=self.__context)
            if not validate_result:
                self.__passed = False
            if hasattr(validate_result, 'details'):
                failure_list.append(validate_result)

        return failure_list

    def run(self, context=None, timeout=None, curl_handler=None):

        if context is None:
            context = self.__context

        self.pre_update(context)
        self.render()
        if timeout is None:
            timeout = DEFAULT_TIMEOUT

        if curl_handler:

            try:  # Check the curl handle isn't closed, and reuse it if possible
                curl_handler.getinfo(curl_handler.HTTP_CODE)
                # Below clears the cookies & curl options for clean run
                # But retains the DNS cache and connection pool
                curl_handler.reset()
                curl_handler.setopt(curl_handler.COOKIELIST, "ALL")
            except pycurl.error:
                curl_handler = pycurl.Curl()
        else:
            curl_handler = pycurl.Curl()

        body_byte, header_byte = self.__default_curl_config(
            curl_handler, timeout)
        if self.config.timeout:
            curl_handler.setopt(pycurl.CONNECTTIMEOUT, self.config.timeout)

        if self.__ssl_insecure:
            curl_handler.setopt(pycurl.SSL_VERIFYPEER, 0)
            curl_handler.setopt(pycurl.SSL_VERIFYHOST, 0)

        if self.body:
            logger.debug("Request body %s" % self.body)
            curl_handler.setopt(curl_handler.READFUNCTION,
                                BytesIO(bytes(self.body, 'utf-8')).read)

        if self.auth_username and self.auth_password:
            curl_handler.setopt(pycurl.USERPWD,
                                self.auth_username + ':' + self.auth_password)

        self.__configure_curl_method(curl_handler)

        head = self.headers
        self.__configure_curl_headers(curl_handler, head)

        if self.__delay:
            time.sleep(self.__delay)
        try:
            logger.info("Hitting %s" % self.url)
            curl_handler.perform()
        except pycurl.error as e:
            logger.error("Unknown Exception", exc_info=True)
            self.__passed = False
            curl_handler.close()
            trace = traceback.format_exc()
            self.__failure_list.append(
                Failure(message="Curl Exception: {0}".format(e),
                        details=trace,
                        failure_type=FAILURE_CURL_EXCEPTION))
            return
        self.body = body_byte.getvalue()
        body_byte.close()
        response_code = curl_handler.getinfo(pycurl.RESPONSE_CODE)
        self.__response_code = int(response_code)
        if self.config.print_bodies:
            print(self.body)
        try:
            response_headers = Parser.parse_headers(header_byte.getvalue())
            self.__response_headers = response_headers
            logger.debug("RESPONSE HEADERS: %s" % self.__response_headers)
            header_byte.close()

        except Exception as e:  # Need to catch the expected exception
            trace = traceback.format_exc()
            self.__failure_list.append(
                Failure(message="Header parsing exception: {0}".format(e),
                        details=trace,
                        failure_type=FAILURE_TEST_EXCEPTION))
            self.__passed = False
            curl_handler.close()
            return

        if self.__response_code in self.expected_http_status_code_list:
            self.__passed = True
            self.__failure_list.extend(self.__perform_validation())
            self.post_update(context)
        else:
            self.__passed = False
            failure_message = "Invalid HTTP response code: response code {0} not in expected codes {1}".format(
                self.__response_code, self.expected_http_status_code_list)
            self.__failure_list.append(
                Failure(message=failure_message,
                        details=None,
                        failure_type=FAILURE_INVALID_RESPONSE))
        curl_handler.close()

    @staticmethod
    def __configure_curl_headers(curl_handler, head):
        if head.get('content-type'):
            content_type = head['content-type']
            head[u'content-type'] = '%s ; charset=UTF-8' % content_type
        headers = [
            "%s:%s" % (header_name, header_value)
            for header_name, header_value in head.items()
        ]
        headers.append("Expect:")
        headers.append("Connection: close")
        logger.debug("Request headers %s " % head)
        curl_handler.setopt(curl_handler.HTTPHEADER, headers)

    def __configure_curl_method(self, curl_handler):
        body_length = len(self.body) if self.body else 0
        if self.http_method == EnumHttpMethod.POST.name:
            curl_handler.setopt(EnumHttpMethod.POST.value, 1)
            curl_handler.setopt(pycurl.POSTFIELDSIZE, body_length)

        elif self.http_method == EnumHttpMethod.PUT.name:
            curl_handler.setopt(EnumHttpMethod.PUT.value, 1)
            curl_handler.setopt(pycurl.INFILESIZE, body_length)

        elif self.http_method == EnumHttpMethod.PATCH.name:
            curl_handler.setopt(EnumHttpMethod.PATCH.value,
                                EnumHttpMethod.PATCH.name)
            curl_handler.setopt(pycurl.POSTFIELDS, self.body)

        elif self.http_method == EnumHttpMethod.DELETE.name:
            curl_handler.setopt(EnumHttpMethod.DELETE.value,
                                EnumHttpMethod.DELETE.name)
            if self.body:
                curl_handler.setopt(pycurl.POSTFIELDS, self.body)
                curl_handler.setopt(pycurl.POSTFIELDSIZE, body_length)

        elif self.http_method == EnumHttpMethod.HEAD.name:
            curl_handler.setopt(pycurl.NOBODY, 1)
            curl_handler.setopt(EnumHttpMethod.HEAD.value,
                                EnumHttpMethod.HEAD.name)
        else:
            curl_handler.setopt(pycurl.CUSTOMREQUEST, self.http_method.upper())
            if self.body:
                curl_handler.setopt(pycurl.POSTFIELDS, self.body)
                curl_handler.setopt(pycurl.POSTFIELDSIZE, body_length)

    def __default_curl_config(self, curl_handler, timeout):
        body_byte = BytesIO()
        header_byte = BytesIO()
        curl_handler.setopt(curl_handler.URL, str(self.url))
        curl_handler.setopt(curl_handler.TIMEOUT, timeout)
        curl_handler.setopt(pycurl.WRITEFUNCTION, body_byte.write)
        curl_handler.setopt(pycurl.HEADERFUNCTION, header_byte.write)
        curl_handler.setopt(pycurl.VERBOSE, self.__verbose)
        return body_byte, header_byte
Example #29
0
 def test_update_context_generators(self):
     """ Test updating context variables using generator """
     variable_binds = {'foo': 'initial_value'}
     generator_binds = {'foo': 'gen'}
     context = Context()
     test = TestCase('', None, variable_binds, context=context)
     test.generator_binds = generator_binds
     context.bind_variable('foo', 'broken')
     context.add_generator('gen', generators.generator_basic_ids())
     context.bind_generator_next('foo', 'gen')
     self.assertEqual(1, context.get_value('foo'))
     context.bind_generator_next('foo', 'gen')
     self.assertEqual(2, context.get_value('foo'))
Example #30
0
    def test_basic_ids(self):
        """ Test starting ids """
        ids1 = generators.generator_basic_ids()
        ids2 = generators.generator_basic_ids()
        self.generator_repeat_test(ids1)
        self.generator_repeat_test(ids2)
        self.assertEqual(next(ids1), next(ids2))

        c = Context()
        c.variables = {'x': '$x'}
        x = generators.factory_generate_ids(1, increment=0)()
        c.add_generator('x', x)

        self.assertEqual(c.bind_generator_next('x', 'x'), c.bind_generator_next('x', 'x'))

        c.bind_variable('x', 1)
        var1 = c.get_value('x')
        c.bind_variable('x', 1)
        var2 = c.get_value('x')
        self.assertEqual(var1, var2)