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))
def test_raw_body_extractor(self): query = '' extractor = validators.parse_extractor('raw_body', None) extractor = validators.parse_extractor('raw_body', query) self.assertTrue(isinstance(extractor, validators.RawBodyExtractor)) self.assertTrue(extractor.is_body_extractor) self.assertFalse(extractor.is_header_extractor) bod = 'j1j21io312j3' val = extractor.extract(body=bod, headers='') self.assertEqual(bod, val)
def test_parse_extractor(self): """ Test parsing an extractor using the registry """ config = 'key.val' myjson = '{"key": {"val": 3}}' extractor = validators.parse_extractor('jsonpath_mini', config) self.assertTrue(isinstance(extractor, validators.AbstractExtractor)) self.assertEqual(3, extractor.extract(body=myjson))
def test_parse_header_extractor(self): query = 'content-type' extractor = validators.parse_extractor('header', query) self.assertTrue(isinstance(extractor, validators.HeaderExtractor)) self.assertTrue(extractor.is_header_extractor) self.assertFalse(extractor.is_body_extractor)
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_workflow(cls, base_url,node,input_workflow=None, test_path=None , global_gen=None): myworkflow = input_workflow if not myworkflow: myworkflow = WorkFlow() # 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'name': [coerce_string_to_ascii], u'tests': [coerce_list_of_strings], u'body': [ContentHandler.parse_content], u'group': [coerce_to_string] # Test group name } 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 """Fuction mapping""" functions_case={'setvalue_body':[WorkFlow.setvalue_body],'setvalue_headers':[WorkFlow.setvalue_headers],'setvalue_auth_password':[WorkFlow.setvalue_auth_password],'setvalue_auth_username': [WorkFlow.setvalue_auth_username],'setvalue_url':[WorkFlow.setvalue_url],'setvalue_method':[WorkFlow.setvalue_method],'setvalue_expected_status':[WorkFlow.setvalue_expected_status]} # Copy/convert input elements into appropriate form for a test object for configelement, configvalue in node.items(): if use_config_parser(myworkflow, configelement, configvalue): continue elif configelement == u'name': myworkflow.name = str(configvalue) elif configelement == u'extract_binds': # Add a list of extractors, of format: # {variable_name: {extractor_type: extractor_config}, ... } binds = flatten_dictionaries(configvalue) if myworkflow.extract_binds is None: myworkflow.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(): myworkflow.extract_binds[variable_name] = validators.parse_extractor(extractor_type, extractor_config) mytest.variable_binds= validators.parse_extractor(extractor_type, extractor_config) elif configelement == u'params': params_flag=1 dict_params=dict() dict_templated_params=dict() for p in range(len(configvalue)): for key1,value1 in configvalue[p].items(): list_params=list() list_templated_params=list() for q in range(len(value1)): for key2,value2 in value1[q].items(): if(key2 == "name"): raise Exception("Cannot overwrite name attribute of original test case") if(key2 == "group"): raise Exception("Cannot overwrite group attribute of original test case") if(key2=="body"): assert isinstance(value2, dict) myparsing = CONFIG_ELEMENTS.get(key2) converted = myparsing[0](value2) myworkflow.setvalue_body(converted,list_params) continue if(key2=="generator_binds"): assert isinstance(value2, dict) atrr_dict=dict() atrr_dict[key2]=value2 list_params.append(atrr_dict) continue if(key2=="delay" or key2 == "retries" or key2 == "repeat"): assert isinstance(value2, int) atrr_dict=dict() atrr_dict[key2]=value2 list_params.append(atrr_dict) continue if(key2=="extract_binds"): temp_dict=dict() atrr_dict=dict() for index in range(len(value2)): for variable_name, extractor in value2[index].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(): temp_dict[variable_name] = validators.parse_extractor(extractor_type, extractor_config) atrr_dict[key2]=temp_dict list_params.append(atrr_dict) continue var_func="setvalue_"+key2 if isinstance(value2, dict): output = flatten_dictionaries(value2) else: output = value2 #output={'template': {'license': {'name': 'randhir', 'properties': '$var22'}}} if isinstance(output, dict): filterfunc = lambda x: str(x[0]).lower() == 'template' # Templated items templates = [x for x in ifilter(filterfunc, output.items())]#output_items=[('template', {'license': {'name': 'randhir', 'properties': '$var22'}})] else: templates = None if templates: list_templated_params.append(key2) if(var_func=='setvalue_auth_username'): functions_case[var_func][0](myworkflow,templates[0][1],list_params,isTemplate=True) if(var_func=='setvalue_auth_password'): functions_case[var_func][0](myworkflow,templates[0][1],list_params,isTemplate=True) if(var_func=='setvalue_headers'): functions_case[var_func][0](myworkflow,templates[0][1],list_params,isTemplate=True) if(var_func=='setvalue_url'): temp=urlparse.urljoin(base_url,coerce_to_string(templates[0][1])) functions_case[var_func][0](myworkflow,temp,list_params,isTemplate=True) if(var_func=='setvalue_method'): functions_case[var_func][0](myworkflow,templates[0][1],list_params,isTemplate=True) if(var_func=='setvalue_expected_status'): functions_case[var_func][0](myworkflow,templates[0][1],list_params,isTemplate=True) else: if(var_func=='setvalue_auth_username'): functions_case[var_func][0](myworkflow,output,list_params) if(var_func=='setvalue_auth_password'): functions_case[var_func][0](myworkflow,output,list_params) if(var_func=='setvalue_headers'): functions_case[var_func][0](myworkflow,output,list_params) if(var_func=='setvalue_url'): temp=urlparse.urljoin(base_url,coerce_to_string(output)) functions_case[var_func][0](myworkflow,temp,list_params) if(var_func=='setvalue_method'): functions_case[var_func][0](myworkflow,output,list_params) if(var_func=='setvalue_expected_status'): functions_case[var_func][0](myworkflow,output,list_params) dict_params[str(key1)]=list_params dict_templated_params[str(key1)]=list_templated_params myworkflow.params=dict_params myworkflow.params_templated=dict_templated_params elif configelement == 'variable_binds': myworkflow.variable_binds = flatten_dictionaries(configvalue) return myworkflow
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_workflow(cls, base_url, node, input_workflow=None, test_path=None, global_gen=None): myworkflow = input_workflow if not myworkflow: myworkflow = WorkFlow() # 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'name': [coerce_string_to_ascii], u'tests': [coerce_list_of_strings], u'body': [ContentHandler.parse_content], u'group': [coerce_to_string] # Test group name } 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 """Fuction mapping""" functions_case = { 'setvalue_body': [WorkFlow.setvalue_body], 'setvalue_headers': [WorkFlow.setvalue_headers], 'setvalue_auth_password': [WorkFlow.setvalue_auth_password], 'setvalue_auth_username': [WorkFlow.setvalue_auth_username], 'setvalue_url': [WorkFlow.setvalue_url], 'setvalue_method': [WorkFlow.setvalue_method], 'setvalue_expected_status': [WorkFlow.setvalue_expected_status] } # Copy/convert input elements into appropriate form for a test object for configelement, configvalue in node.items(): if use_config_parser(myworkflow, configelement, configvalue): continue elif configelement == u'name': myworkflow.name = str(configvalue) elif configelement == u'extract_binds': # Add a list of extractors, of format: # {variable_name: {extractor_type: extractor_config}, ... } binds = flatten_dictionaries(configvalue) if myworkflow.extract_binds is None: myworkflow.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(): myworkflow.extract_binds[ variable_name] = validators.parse_extractor( extractor_type, extractor_config) mytest.variable_binds = validators.parse_extractor( extractor_type, extractor_config) elif configelement == u'params': params_flag = 1 dict_params = dict() dict_templated_params = dict() for p in range(len(configvalue)): for key1, value1 in configvalue[p].items(): list_params = list() list_templated_params = list() for q in range(len(value1)): for key2, value2 in value1[q].items(): if (key2 == "name"): raise Exception( "Cannot overwrite name attribute of original test case" ) if (key2 == "group"): raise Exception( "Cannot overwrite group attribute of original test case" ) if (key2 == "body"): assert isinstance(value2, dict) myparsing = CONFIG_ELEMENTS.get(key2) converted = myparsing[0](value2) myworkflow.setvalue_body( converted, list_params) continue if (key2 == "generator_binds"): assert isinstance(value2, dict) atrr_dict = dict() atrr_dict[key2] = value2 list_params.append(atrr_dict) continue if (key2 == "delay" or key2 == "retries" or key2 == "repeat"): assert isinstance(value2, int) atrr_dict = dict() atrr_dict[key2] = value2 list_params.append(atrr_dict) continue if (key2 == "extract_binds"): temp_dict = dict() atrr_dict = dict() for index in range(len(value2)): for variable_name, extractor in value2[ index].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( ): temp_dict[ variable_name] = validators.parse_extractor( extractor_type, extractor_config) atrr_dict[key2] = temp_dict list_params.append(atrr_dict) continue var_func = "setvalue_" + key2 if isinstance(value2, dict): output = flatten_dictionaries(value2) else: output = value2 #output={'template': {'license': {'name': 'randhir', 'properties': '$var22'}}} if isinstance(output, dict): filterfunc = lambda x: str(x[0]).lower( ) == 'template' # Templated items templates = [ x for x in ifilter( filterfunc, output.items()) ] #output_items=[('template', {'license': {'name': 'randhir', 'properties': '$var22'}})] else: templates = None if templates: list_templated_params.append(key2) if (var_func == 'setvalue_auth_username'): functions_case[var_func][0]( myworkflow, templates[0][1], list_params, isTemplate=True) if (var_func == 'setvalue_auth_password'): functions_case[var_func][0]( myworkflow, templates[0][1], list_params, isTemplate=True) if (var_func == 'setvalue_headers'): functions_case[var_func][0]( myworkflow, templates[0][1], list_params, isTemplate=True) if (var_func == 'setvalue_url'): temp = urlparse.urljoin( base_url, coerce_to_string(templates[0][1])) functions_case[var_func][0]( myworkflow, temp, list_params, isTemplate=True) if (var_func == 'setvalue_method'): functions_case[var_func][0]( myworkflow, templates[0][1], list_params, isTemplate=True) if (var_func == 'setvalue_expected_status' ): functions_case[var_func][0]( myworkflow, templates[0][1], list_params, isTemplate=True) else: if (var_func == 'setvalue_auth_username'): functions_case[var_func][0]( myworkflow, output, list_params) if (var_func == 'setvalue_auth_password'): functions_case[var_func][0]( myworkflow, output, list_params) if (var_func == 'setvalue_headers'): functions_case[var_func][0]( myworkflow, output, list_params) if (var_func == 'setvalue_url'): temp = urlparse.urljoin( base_url, coerce_to_string(output)) functions_case[var_func][0]( myworkflow, temp, list_params) if (var_func == 'setvalue_method'): functions_case[var_func][0]( myworkflow, output, list_params) if (var_func == 'setvalue_expected_status' ): functions_case[var_func][0]( myworkflow, output, list_params) dict_params[str(key1)] = list_params dict_templated_params[str( key1)] = list_templated_params myworkflow.params = dict_params myworkflow.params_templated = dict_templated_params elif configelement == 'variable_binds': myworkflow.variable_binds = flatten_dictionaries(configvalue) return myworkflow
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