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)
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)
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)
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))
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))
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)
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)
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)
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)
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)
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
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
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
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
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)