Exemplo n.º 1
0
    def test_get_validators(self):
        """ Test that validators work correctly """
        test = Test()
        test.url = self.prefix + "/api/person/"

        # Validators need library calls to configure them
        test.validators = list()
        cfg_exists = {"jsonpath_mini": "objects.0", "test": "exists"}
        test.validators.append(validators.parse_validator("extract_test", cfg_exists))
        cfg_exists_0 = {"jsonpath_mini": "meta.offset", "test": "exists"}
        test.validators.append(validators.parse_validator("extract_test", cfg_exists_0))
        cfg_not_exists = {"jsonpath_mini": "objects.100", "test": "not_exists"}
        test.validators.append(validators.parse_validator("extract_test", cfg_not_exists))
        cfg_compare_login = {"jsonpath_mini": "objects.0.login", "expected": "gbaltar"}
        test.validators.append(validators.parse_validator("compare", cfg_compare_login))
        cfg_compare_id = {"jsonpath_mini": "objects.1.id", "comparator": "gt", "expected": -1}
        test.validators.append(validators.parse_validator("compare", cfg_compare_id))

        test_response = resttest.run_test(test)
        for failure in test_response.failures:
            print("REAL FAILURE")
            print("Test Failure, failure type: {0}, Reason: {1}".format(failure.failure_type, failure.message))
            if failure.details:
                print("Validator/Error details: " + str(failure.details))
        self.assertFalse(test_response.failures)
        self.assertTrue(test_response.passed)
Exemplo n.º 2
0
    def test_get_validators(self):
        """ Test that validators work correctly """
        test = Test()
        test.url = self.prefix + '/api/person/'
        
        # Validators need library calls to configure them
        test.validators = list()
        cfg_exists = {'jsonpath_mini': "objects.0", 'test':'exists'}
        test.validators.append(validators.parse_validator('extract_test', cfg_exists))
        cfg_exists_0 = {'jsonpath_mini': "meta.offset", 'test':'exists'}
        test.validators.append(validators.parse_validator('extract_test', cfg_exists_0))
        cfg_not_exists = {'jsonpath_mini': "objects.100", 'test':'not_exists'}
        test.validators.append(validators.parse_validator('extract_test', cfg_not_exists))
        cfg_compare_login = {'jsonpath_mini': 'objects.0.login', 'expected': 'gbaltar'}
        test.validators.append(validators.parse_validator('compare', cfg_compare_login))
        cfg_compare_id = {'jsonpath_mini': 'objects.1.id', 'comparator':'gt', 'expected': -1}
        test.validators.append(validators.parse_validator('compare', cfg_compare_id))

        test_response = resttest.run_test(test)
        for failure in test_response.failures:
            print "REAL FAILURE"
            print "Test Failure, failure type: {0}, Reason: {1}".format(failure.failure_type, failure.message)
            if failure.details:
                print "Validator/Error details: "+str(failure.details)
        self.assertFalse(test_response.failures)
        self.assertTrue(test_response.passed)
Exemplo n.º 3
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)

        # 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)
Exemplo n.º 4
0
 def test_get_validators_fail(self):
     """ Test validators that should fail """
     test = Test()
     test.url = self.prefix + "/api/person/"
     test.validators = list()
     cfg_exists = {"jsonpath_mini": "objects.500", "test": "exists"}
     test.validators.append(validators.parse_validator("extract_test", cfg_exists))
     cfg_not_exists = {"jsonpath_mini": "objects.1", "test": "not_exists"}
     test.validators.append(validators.parse_validator("extract_test", cfg_not_exists))
     cfg_compare = {"jsonpath_mini": "objects.1.last_name", "expected": "NotJenkins"}
     test.validators.append(validators.parse_validator("compare", cfg_compare))
     test_response = resttest.run_test(test)
     self.assertFalse(test_response.passed)
     self.assertTrue(test_response.failures)
     self.assertEqual(3, len(test_response.failures))
Exemplo n.º 5
0
 def test_get_validators_fail(self):
     """ Test validators that should fail """
     test = Test()
     test.url = self.prefix + '/api/person/'
     test.validators = list()
     cfg_exists = {'jsonpath_mini': "objects.500", 'test':'exists'}
     test.validators.append(validators.parse_validator('extract_test', cfg_exists))
     cfg_not_exists = {'jsonpath_mini': "objects.1", 'test':'not_exists'}
     test.validators.append(validators.parse_validator('extract_test', cfg_not_exists))
     cfg_compare = {'jsonpath_mini': "objects.1.last_name", 'expected':'NotJenkins'}
     test.validators.append(validators.parse_validator('compare', cfg_compare))
     test_response = resttest.run_test(test)
     self.assertFalse(test_response.passed)
     self.assertTrue(test_response.failures)
     self.assertEqual(3, len(test_response.failures))
Exemplo n.º 6
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)

        # 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)
Exemplo n.º 7
0
 def test_parse_validator_nocomparator(self):
     """ Test that comparator validator with no comparator defaults to eq """
     config = {
         'jsonpath_mini': 'key.val',
         'expected': 3
     }
     validator = validators.parse_validator('assertEqual', config)
     self.assertEqual('eq', validator.comparator_name)
     self.assertEqual(validators.COMPARATORS['eq'], validator.comparator)
Exemplo n.º 8
0
    def test_header_validators(self):
        test = Test()
        test.url = self.prefix + "/api/person/1/"
        config = {"header": "server", "comparator": "contains", "expected": "WSGI"}
        test.validators = list()
        test.validators.append(validators.parse_validator("comparator", config))
        result = resttest.run_test(test)

        if result.failures:
            for fail in result.failures:
                print(fail)
        self.assertTrue(result.passed)
Exemplo n.º 9
0
    def test_header_validators(self):
        test = Test()
        test.url = self.prefix + '/api/person/1/'
        config = {
            'header': 'server',
            'comparator': 'contains',
            'expected': 'WSGI'
        }
        test.validators = list()
        test.validators.append(validators.parse_validator(
            'comparator', config))
        result = resttest.run_test(test)

        if result.failures:
            for fail in result.failures:
                print(fail)
        self.assertTrue(result.passed)
Exemplo n.º 10
0
    def test_header_validators(self):
        test = Test()
        test.url = self.prefix + '/api/person/1/'
        config = {
            'header': 'server',
            'comparator': 'contains',
            'expected': 'WSGI'
        }
        test.validators = list()
        test.validators.append(
            validators.parse_validator('comparator', config))
        result = resttest.run_test(test)

        if result.failures:
            for fail in result.failures:
                print(fail)
        self.assertTrue(result.passed)
Exemplo n.º 11
0
    def parse_test(cls, base_url, node, input_test = None, test_path=None):
        """ Create or modify a test, input_test, using configuration in node, and base_url
        If no input_test is given, creates a new one

        Test_path gives path to test file, used for setting working directory in setting up input bodies

        Uses explicitly specified elements from the test input structure
        to make life *extra* fun, we need to handle list <-- > dict transformations.

        This is to say: list(dict(),dict()) or dict(key,value) -->  dict() for some elements

        Accepted structure must be a single dictionary of key-value pairs for test configuration """

        mytest = input_test
        if not mytest:
            mytest = Test()

        node = lowercase_keys(flatten_dictionaries(node)) #Clean up for easy parsing

        #Copy/convert input elements into appropriate form for a test object
        for configelement, configvalue in node.items():
            #Configure test using configuration elements
            if configelement == u'url':
                temp = configvalue
                if isinstance(configvalue, dict):
                    # Template is used for URL
                    val = lowercase_keys(configvalue)[u'template']
                    assert isinstance(val,str) or isinstance(val,unicode) or isinstance(val,int)
                    url = base_url + unicode(val,'UTF-8').encode('ascii','ignore')
                    mytest.set_url(url, isTemplate=True)
                else:
                    assert isinstance(configvalue,str) or isinstance(configvalue,unicode) or isinstance(configvalue,int)
                    mytest.url = base_url + unicode(configvalue,'UTF-8').encode('ascii','ignore')
            elif configelement == u'auth_username':
                assert isinstance(configvalue,str) or isinstance(configvalue,unicode)
                mytest.auth_username = unicode(configvalue,'UTF-8').encode('ascii','ignore')
            elif configelement == u'auth_password':
                assert isinstance(configvalue,str) or isinstance(configvalue,unicode)
                mytest.auth_password = unicode(configvalue,'UTF-8').encode('ascii','ignore')
            elif configelement == u'method': #Http method, converted to uppercase string
                var = unicode(configvalue,'UTF-8').upper()
                assert var in HTTP_METHODS
                mytest.method = var
            elif configelement == u'group': #Test group
                assert isinstance(configvalue,str) or isinstance(configvalue,unicode) or isinstance(configvalue,int)
                mytest.group = unicode(configvalue,'UTF-8')
            elif configelement == u'name': #Test name
                assert isinstance(configvalue,str) or isinstance(configvalue,unicode) or isinstance(configvalue,int)
                mytest.name = unicode(configvalue,'UTF-8')
            elif configelement == u'extract_binds':
                # Add a list of extractors, of format:
                # {variable_name: {extractor_type: extractor_config}, ... }
                binds = flatten_dictionaries(configvalue)
                if mytest.extract_binds is None:
                    mytest.extract_binds = dict()

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

            elif configelement == u'validators':
                # Add a list of validators
                if not isinstance(configvalue, list):
                    raise Exception('Misconfigured validator section, must be a list of validators')
                if mytest.validators is None:
                    mytest.validators = list()

                # create validator and add to list of validators
                for var in configvalue:
                    if not isinstance(var, dict):
                        raise TypeError("Validators must be defined as validatorType:{configs} ")
                    for validator_type, validator_config in var.items():
                        validator = validators.parse_validator(validator_type, validator_config)
                        mytest.validators.append(validator)

            elif configelement == u'body': #Read request body, as a ContentHandler
                # Note: os.path.expandirs removed
                mytest.body = ContentHandler.parse_content(configvalue)
            elif configelement == 'headers': #HTTP headers to use, flattened to a single string-string dictionary
                mytest.headers
                configvalue = flatten_dictionaries(configvalue)

                if isinstance(configvalue, dict):
                    templates = filter(lambda x: str(x[0]).lower() == 'template', configvalue.items())
                else:
                    templates = None

                if templates:
                    # Should have single entry in dictionary keys
                    mytest.set_headers(templates[0][1], isTemplate=True)
                elif isinstance(configvalue, dict):
                    mytest.headers = configvalue
                else:
                    raise TypeError("Illegal header type: headers must be a dictionary or list of dictionary keys")

            elif configelement == 'expected_status': #List of accepted HTTP response codes, as integers
                expected = list()
                #If item is a single item, convert to integer and make a list of 1
                #Otherwise, assume item is a list and convert to a list of integers
                if isinstance(configvalue,list):
                    for item in configvalue:
                        expected.append(int(item))
                else:
                    expected.append(int(configvalue))
                mytest.expected_status = expected
            elif configelement == 'variable_binds':
                mytest.variable_binds = flatten_dictionaries(configvalue)
            elif configelement == 'generator_binds':
                output = flatten_dictionaries(configvalue)
                output2 = dict()
                for key, value in output.items():
                    output2[str(key)] = str(value)
                mytest.generator_binds = output2
            elif configelement == 'stop_on_failure':
                mytest.stop_on_failure = safe_to_bool(configvalue)

        #Next, we adjust defaults to be reasonable, if the user does not specify them

        #For non-GET requests, accept additional response codes indicating success
        # (but only if not expected statuses are not explicitly specified)
        #  this is per HTTP spec: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5
        if 'expected_status' not in node.keys():
            if mytest.method == 'POST':
                mytest.expected_status = [200,201,204]
            elif mytest.method == 'PUT':
                mytest.expected_status = [200,201,204]
            elif mytest.method == 'DELETE':
                mytest.expected_status = [200,202,204]
        return mytest
Exemplo n.º 12
0
    def parse_test(cls, base_url, node, input_test=None, test_path=None):
        """ Create or modify a test, input_test, using configuration in node, and base_url
        If no input_test is given, creates a new one

        Test_path gives path to test file, used for setting working directory in setting up input bodies

        Uses explicitly specified elements from the test input structure
        to make life *extra* fun, we need to handle list <-- > dict transformations.

        This is to say: list(dict(),dict()) or dict(key,value) -->  dict() for some elements

        Accepted structure must be a single dictionary of key-value pairs for test configuration """

        mytest = input_test
        if not mytest:
            mytest = Test()

        node = lowercase_keys(
            flatten_dictionaries(node))  #Clean up for easy parsing

        #Copy/convert input elements into appropriate form for a test object
        for configelement, configvalue in node.items():
            #Configure test using configuration elements
            if configelement == u'url':
                temp = configvalue
                if isinstance(configvalue, dict):
                    # Template is used for URL
                    val = lowercase_keys(configvalue)[u'template']
                    assert isinstance(val, str) or isinstance(
                        val, unicode) or isinstance(val, int)
                    url = base_url + unicode(val, 'UTF-8').encode(
                        'ascii', 'ignore')
                    mytest.set_url(url, isTemplate=True)
                else:
                    assert isinstance(configvalue, str) or isinstance(
                        configvalue, unicode) or isinstance(configvalue, int)
                    mytest.url = base_url + unicode(
                        configvalue, 'UTF-8').encode('ascii', 'ignore')
            elif configelement == u'auth_username':
                assert isinstance(configvalue, str) or isinstance(
                    configvalue, unicode)
                mytest.auth_username = unicode(configvalue, 'UTF-8').encode(
                    'ascii', 'ignore')
            elif configelement == u'auth_password':
                assert isinstance(configvalue, str) or isinstance(
                    configvalue, unicode)
                mytest.auth_password = unicode(configvalue, 'UTF-8').encode(
                    'ascii', 'ignore')
            elif configelement == u'method':  #Http method, converted to uppercase string
                var = unicode(configvalue, 'UTF-8').upper()
                assert var in HTTP_METHODS
                mytest.method = var
            elif configelement == u'group':  #Test group
                assert isinstance(configvalue, str) or isinstance(
                    configvalue, unicode) or isinstance(configvalue, int)
                mytest.group = unicode(configvalue, 'UTF-8')
            elif configelement == u'name':  #Test name
                assert isinstance(configvalue, str) or isinstance(
                    configvalue, unicode) or isinstance(configvalue, int)
                mytest.name = unicode(configvalue, 'UTF-8')
            elif configelement == u'extract_binds':
                # Add a list of extractors, of format:
                # {variable_name: {extractor_type: extractor_config}, ... }
                binds = flatten_dictionaries(configvalue)
                if mytest.extract_binds is None:
                    mytest.extract_binds = dict()

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

            elif configelement == u'validators':
                # Add a list of validators
                if not isinstance(configvalue, list):
                    raise Exception(
                        'Misconfigured validator section, must be a list of validators'
                    )
                if mytest.validators is None:
                    mytest.validators = list()

                # create validator and add to list of validators
                for var in configvalue:
                    if not isinstance(var, dict):
                        raise TypeError(
                            "Validators must be defined as validatorType:{configs} "
                        )
                    for validator_type, validator_config in var.items():
                        validator = validators.parse_validator(
                            validator_type, validator_config)
                        mytest.validators.append(validator)

            elif configelement == u'body':  #Read request body, as a ContentHandler
                # Note: os.path.expandirs removed
                mytest.body = ContentHandler.parse_content(configvalue)
            elif configelement == 'headers':  #HTTP headers to use, flattened to a single string-string dictionary
                mytest.headers
                configvalue = flatten_dictionaries(configvalue)

                if isinstance(configvalue, dict):
                    templates = filter(
                        lambda x: str(x[0]).lower() == 'template',
                        configvalue.items())
                else:
                    templates = None

                if templates:
                    # Should have single entry in dictionary keys
                    mytest.set_headers(templates[0][1], isTemplate=True)
                elif isinstance(configvalue, dict):
                    mytest.headers = configvalue
                else:
                    raise TypeError(
                        "Illegal header type: headers must be a dictionary or list of dictionary keys"
                    )

            elif configelement == 'expected_status':  #List of accepted HTTP response codes, as integers
                expected = list()
                #If item is a single item, convert to integer and make a list of 1
                #Otherwise, assume item is a list and convert to a list of integers
                if isinstance(configvalue, list):
                    for item in configvalue:
                        expected.append(int(item))
                else:
                    expected.append(int(configvalue))
                mytest.expected_status = expected
            elif configelement == 'variable_binds':
                mytest.variable_binds = flatten_dictionaries(configvalue)
            elif configelement == 'generator_binds':
                output = flatten_dictionaries(configvalue)
                output2 = dict()
                for key, value in output.items():
                    output2[str(key)] = str(value)
                mytest.generator_binds = output2
            elif configelement == 'stop_on_failure':
                mytest.stop_on_failure = safe_to_bool(configvalue)

        #Next, we adjust defaults to be reasonable, if the user does not specify them

        #For non-GET requests, accept additional response codes indicating success
        # (but only if not expected statuses are not explicitly specified)
        #  this is per HTTP spec: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5
        if 'expected_status' not in node.keys():
            if mytest.method == 'POST':
                mytest.expected_status = [200, 201, 204]
            elif mytest.method == 'PUT':
                mytest.expected_status = [200, 201, 204]
            elif mytest.method == 'DELETE':
                mytest.expected_status = [200, 202, 204]
        return mytest
Exemplo n.º 13
0
    def parse_test(cls, base_url, node, input_test=None, test_path=None):
        """ Create or modify a test, input_test, using configuration in node, and base_url
        If no input_test is given, creates a new one

        Test_path gives path to test file, used for setting working directory in setting up input bodies

        Uses explicitly specified elements from the test input structure
        to make life *extra* fun, we need to handle list <-- > dict transformations.

        This is to say: list(dict(),dict()) or dict(key,value) -->  dict() for some elements

        Accepted structure must be a single dictionary of key-value pairs for test configuration """
        
        
        mytest = input_test
        if not mytest:
            mytest = Test()

        # Clean up for easy parsing
        node = lowercase_keys(flatten_dictionaries(node))
        


        # Simple table of variable name, coerce function, and optionally special store function
        CONFIG_ELEMENTS = {
            # Simple variables
           # u'auth_username': [coerce_string_to_ascii],
           # u'auth_password': [coerce_string_to_ascii],
           # u'method': [coerce_http_method], # HTTP METHOD
            u'delay': [lambda x: int(x)], # Delay before running
            u'group': [coerce_to_string], # Test group name
            u'name': [coerce_to_string],  # Test name
           # u'expected_status': [coerce_list_of_ints],
            u'delay': [lambda x: int(x)],
            u'stop_on_failure': [safe_to_bool],
            u'retries': [lambda x: int(x)],
            u'depends_on': [coerce_list_of_strings],

            # Templated / special handling
            #u'url': [coerce_templatable, set_templated],  # TODO: special handling for templated content, sigh
            u'body': [ContentHandler.parse_content]
            #u'headers': [],

            # COMPLEX PARSE OPTIONS
            #u'extract_binds':[],  # Context variable-to-extractor output binding
            #u'variable_binds': [],  # Context variable to value binding
            #u'generator_binds': [],  # Context variable to generator output binding
            #u'validators': [],  # Validation functions to run
        }

        def use_config_parser(configobject, configelement, configvalue):
            """ Try to use parser bindings to find an option for parsing and storing config element
                :configobject: Object to store configuration
                :configelement: Configuratione element name
                :configvalue: Value to use to set configuration
                :returns: True if found match for config element, False if didn't
            """
            
            myparsing = CONFIG_ELEMENTS.get(configelement)
            if myparsing:
                converted = myparsing[0](configvalue)
                setattr(configobject, configelement, converted)
                return True
            return False

        # Copy/convert input elements into appropriate form for a test object
        for configelement, configvalue in node.items():
            if use_config_parser(mytest, configelement, configvalue):
                continue
            
            # Configure test using configuration elements
            if configelement == u'url':
                temp = configvalue
                if isinstance(configvalue, dict):
                    # Template is used for URL
                    val = lowercase_keys(configvalue)[u'template']
                    assert isinstance(val, basestring) or isinstance(val, int)
                    url = urlparse.urljoin(base_url, coerce_to_string(val))
                    mytest.set_url(url, isTemplate=True)
                else:
                    assert isinstance(configvalue, basestring) or isinstance(
                        configvalue, int)
                    mytest.url = urlparse.urljoin(base_url, coerce_to_string(configvalue))


            if configelement == u'display_name':
                 temp = configvalue
                 if isinstance(configvalue, dict):
                     # Template is used for Disply Name
                     val = lowercase_keys(configvalue)[u'template']
                     assert isinstance(val, basestring) or isinstance(val, int)
                     mytest.set_display_name(val, isTemplate=True)
                 else:
                     assert isinstance(configvalue, basestring) or isinstance(
                         configvalue, int)
                     mytest.display_name = urlparse.urljoin(base_url, coerce_to_string(configvalue)) 
                    

            if configelement == u'auth_password':
                temp = configvalue
                
                if isinstance(configvalue, basestring):
                    
                    val = lowercase_keys(configvalue)
                    assert isinstance(val, basestring) or isinstance(val, int)
                    
                    mytest.set_auth_password(val)
            
            if configelement == u'auth_username':
                temp = configvalue
                
                if isinstance(configvalue, basestring):
                    val = lowercase_keys(configvalue)
                    assert isinstance(val, basestring) or isinstance(val, int)
                    
                    mytest.set_auth_username(val)
            

            if configelement == u'method':
                val = configvalue
                
                if isinstance(configvalue, basestring) or isinstance(val, list):
                    assert isinstance(val, basestring) or isinstance(val, list)
                    mytest.set_method(val)

            
            if configelement == u'expected_status':
                val = configvalue               
                assert isinstance(val, basestring) or isinstance(val, list)
                mytest.set_expected_status(val)


            if configelement == u'extract_binds':
                # Add a list of extractors, of format:
                # {variable_name: {extractor_type: extractor_config}, ... }
                
                binds = flatten_dictionaries(configvalue)
                if mytest.extract_binds is None:
                    mytest.extract_binds = dict()
 		
                for variable_name, extractor in binds.items():
                    if not isinstance(extractor, dict) or len(extractor) == 0:
                        raise TypeError(
                            "Extractors must be defined as maps of extractorType:{configs} with 1 entry")
                    if len(extractor) > 1:
                        raise ValueError(
                            "Cannot define multiple extractors for given variable name")

                    # Safe because length can only be 1
                    for extractor_type, extractor_config in extractor.items():
                        
                        mytest.extract_binds[variable_name] = validators.parse_extractor(extractor_type, extractor_config)
            

            if configelement == u'validators':
                # Add a list of validators
                if not isinstance(configvalue, list):
                    raise Exception(
                        'Misconfigured validator section, must be a list of validators')
                if mytest.validators is None:
                    mytest.validators = list()

                # create validator and add to list iof validators
                for var in configvalue:
                    if not isinstance(var, dict):
                        raise TypeError(
                            "Validators must be defined as validatorType:{configs} ")
                    for validator_type, validator_config in var.items():
                        validator = validators.parse_validator(
                            validator_type, validator_config)
                        mytest.validators.append(validator)

            if configelement == 'headers':  # HTTP headers to use, flattened to a single string-string dictionary
                mytest.headers
                configvalue = flatten_dictionaries(configvalue)
                
                if isinstance(configvalue, dict):
                    filterfunc  = lambda x: str(x[0]).lower() == 'template'  # Templated items
                    templates = [x for x in ifilter(filterfunc, configvalue.items())]
                else:
                    templates = None
                
                if templates:
                    
                    # Should have single entry in dictionary keys
                    mytest.set_headers(templates[0][1], isTemplate=True)
                elif isinstance(configvalue, dict):
                   
                    mytest.headers = configvalue
                else:
                    raise TypeError(
                        "Illegal header type: headers must be a dictionary or list of dictionary keys")
            if configelement == 'variable_binds':
                mytest.variable_binds = flatten_dictionaries(configvalue)
            if configelement == 'generator_binds':
                
                if(True):
                    output = flatten_dictionaries(configvalue)
                    output2 = dict()
                    for key, value in output.items():
                        output2[str(key)] = str(value)
                    mytest.generator_binds = output2
            if configelement.startswith('curl_option_'):
                curlopt = configelement[12:].upper()
                if hasattr(BASECURL, curlopt):
                    if not mytest.curl_options:
                        mytest.curl_options = dict()
                    mytest.curl_options[curlopt] = configvalue
                else:
                    raise ValueError(
                        "Illegal curl option: {0}".format(curlopt))

        # For non-GET requests, accept additional response codes indicating success
        # (but only if not expected statuses are not explicitly specified)
        # this is per HTTP spec:
        # http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5
        
        if 'expected_status' not in node.keys():
            if mytest.method == 'POST':
                mytest.expected_status = [200, 201, 204]
            elif mytest.method == 'PUT':
                mytest.expected_status = [200, 201, 204]
            elif mytest.method == 'DELETE':
                mytest.expected_status = [200, 202, 204]
            # Fallthrough default is simply [200]
        return mytest
Exemplo n.º 14
0
    def parse_test(cls, base_url, node, input_test=None, test_path=None):
        """ Create or modify a test, input_test, using configuration in node, and base_url
        If no input_test is given, creates a new one

        Test_path gives path to test file, used for setting working directory in setting up input bodies

        Uses explicitly specified elements from the test input structure
        to make life *extra* fun, we need to handle list <-- > dict transformations.

        This is to say: list(dict(),dict()) or dict(key,value) -->  dict() for some elements

        Accepted structure must be a single dictionary of key-value pairs for test configuration """

        mytest = input_test
        if not mytest:
            mytest = Test()

        # Clean up for easy parsing
        node = lowercase_keys(flatten_dictionaries(node))

        # Simple table of variable name, coerce function, and optionally special store function
        CONFIG_ELEMENTS = {
            # Simple variables
            # u'auth_username': [coerce_string_to_ascii],
            # u'auth_password': [coerce_string_to_ascii],
            # u'method': [coerce_http_method], # HTTP METHOD
            u'delay': [lambda x: int(x)],  # Delay before running
            u'group': [coerce_to_string],  # Test group name
            u'name': [coerce_to_string],  # Test name
            # u'expected_status': [coerce_list_of_ints],
            u'delay': [lambda x: int(x)],
            u'stop_on_failure': [safe_to_bool],
            u'retries': [lambda x: int(x)],
            u'depends_on': [coerce_list_of_strings],

            # Templated / special handling
            #u'url': [coerce_templatable, set_templated],  # TODO: special handling for templated content, sigh
            u'body': [ContentHandler.parse_content]
            #u'headers': [],

            # COMPLEX PARSE OPTIONS
            #u'extract_binds':[],  # Context variable-to-extractor output binding
            #u'variable_binds': [],  # Context variable to value binding
            #u'generator_binds': [],  # Context variable to generator output binding
            #u'validators': [],  # Validation functions to run
        }

        def use_config_parser(configobject, configelement, configvalue):
            """ Try to use parser bindings to find an option for parsing and storing config element
                :configobject: Object to store configuration
                :configelement: Configuratione element name
                :configvalue: Value to use to set configuration
                :returns: True if found match for config element, False if didn't
            """

            myparsing = CONFIG_ELEMENTS.get(configelement)
            if myparsing:
                converted = myparsing[0](configvalue)
                setattr(configobject, configelement, converted)
                return True
            return False

        # Copy/convert input elements into appropriate form for a test object
        for configelement, configvalue in node.items():
            if use_config_parser(mytest, configelement, configvalue):
                continue

            # Configure test using configuration elements
            if configelement == u'url':
                temp = configvalue
                if isinstance(configvalue, dict):
                    # Template is used for URL
                    val = lowercase_keys(configvalue)[u'template']
                    assert isinstance(val, basestring) or isinstance(val, int)
                    url = urlparse.urljoin(base_url, coerce_to_string(val))
                    mytest.set_url(url, isTemplate=True)
                else:
                    assert isinstance(configvalue, basestring) or isinstance(
                        configvalue, int)
                    mytest.url = urlparse.urljoin(
                        base_url, coerce_to_string(configvalue))

            if configelement == u'display_name':
                temp = configvalue
                if isinstance(configvalue, dict):
                    # Template is used for Disply Name
                    val = lowercase_keys(configvalue)[u'template']
                    assert isinstance(val, basestring) or isinstance(val, int)
                    mytest.set_display_name(val, isTemplate=True)
                else:
                    assert isinstance(configvalue, basestring) or isinstance(
                        configvalue, int)
                    mytest.display_name = urlparse.urljoin(
                        base_url, coerce_to_string(configvalue))

            if configelement == u'auth_password':
                temp = configvalue

                if isinstance(configvalue, basestring):

                    val = lowercase_keys(configvalue)
                    assert isinstance(val, basestring) or isinstance(val, int)

                    mytest.set_auth_password(val)

            if configelement == u'auth_username':
                temp = configvalue

                if isinstance(configvalue, basestring):
                    val = lowercase_keys(configvalue)
                    assert isinstance(val, basestring) or isinstance(val, int)

                    mytest.set_auth_username(val)

            if configelement == u'method':
                val = configvalue

                if isinstance(configvalue, basestring) or isinstance(
                        val, list):
                    assert isinstance(val, basestring) or isinstance(val, list)
                    mytest.set_method(val)

            if configelement == u'expected_status':
                val = configvalue
                assert isinstance(val, basestring) or isinstance(val, list)
                mytest.set_expected_status(val)

            if configelement == u'extract_binds':
                # Add a list of extractors, of format:
                # {variable_name: {extractor_type: extractor_config}, ... }

                binds = flatten_dictionaries(configvalue)
                if mytest.extract_binds is None:
                    mytest.extract_binds = dict()

                for variable_name, extractor in binds.items():
                    if not isinstance(extractor, dict) or len(extractor) == 0:
                        raise TypeError(
                            "Extractors must be defined as maps of extractorType:{configs} with 1 entry"
                        )
                    if len(extractor) > 1:
                        raise ValueError(
                            "Cannot define multiple extractors for given variable name"
                        )

                    # Safe because length can only be 1
                    for extractor_type, extractor_config in extractor.items():

                        mytest.extract_binds[
                            variable_name] = validators.parse_extractor(
                                extractor_type, extractor_config)

            if configelement == u'validators':
                # Add a list of validators
                if not isinstance(configvalue, list):
                    raise Exception(
                        'Misconfigured validator section, must be a list of validators'
                    )
                if mytest.validators is None:
                    mytest.validators = list()

                # create validator and add to list iof validators
                for var in configvalue:
                    if not isinstance(var, dict):
                        raise TypeError(
                            "Validators must be defined as validatorType:{configs} "
                        )
                    for validator_type, validator_config in var.items():
                        validator = validators.parse_validator(
                            validator_type, validator_config)
                        mytest.validators.append(validator)

            if configelement == 'headers':  # HTTP headers to use, flattened to a single string-string dictionary
                mytest.headers
                configvalue = flatten_dictionaries(configvalue)

                if isinstance(configvalue, dict):
                    filterfunc = lambda x: str(x[0]).lower(
                    ) == 'template'  # Templated items
                    templates = [
                        x for x in ifilter(filterfunc, configvalue.items())
                    ]
                else:
                    templates = None

                if templates:

                    # Should have single entry in dictionary keys
                    mytest.set_headers(templates[0][1], isTemplate=True)
                elif isinstance(configvalue, dict):

                    mytest.headers = configvalue
                else:
                    raise TypeError(
                        "Illegal header type: headers must be a dictionary or list of dictionary keys"
                    )
            if configelement == 'variable_binds':
                mytest.variable_binds = flatten_dictionaries(configvalue)
            if configelement == 'generator_binds':

                if (True):
                    output = flatten_dictionaries(configvalue)
                    output2 = dict()
                    for key, value in output.items():
                        output2[str(key)] = str(value)
                    mytest.generator_binds = output2
            if configelement.startswith('curl_option_'):
                curlopt = configelement[12:].upper()
                if hasattr(BASECURL, curlopt):
                    if not mytest.curl_options:
                        mytest.curl_options = dict()
                    mytest.curl_options[curlopt] = configvalue
                else:
                    raise ValueError(
                        "Illegal curl option: {0}".format(curlopt))

        # For non-GET requests, accept additional response codes indicating success
        # (but only if not expected statuses are not explicitly specified)
        # this is per HTTP spec:
        # http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5

        if 'expected_status' not in node.keys():
            if mytest.method == 'POST':
                mytest.expected_status = [200, 201, 204]
            elif mytest.method == 'PUT':
                mytest.expected_status = [200, 201, 204]
            elif mytest.method == 'DELETE':
                mytest.expected_status = [200, 202, 204]
            # Fallthrough default is simply [200]
        return mytest
Exemplo n.º 15
0
 def test_parse_validator_nocomparator(self):
     """ Test that comparator validator with no comparator defaults to eq """
     config = {"jsonpath_mini": "key.val", "expected": 3}
     validator = validators.parse_validator("assertEqual", config)
     self.assertEqual("eq", validator.comparator_name)
     self.assertEqual(validators.COMPARATORS["eq"], validator.comparator)