def parse_mysql_query_generator(config, variable_binds): """ Parses configuration options for a mysql_query generator """ mysql_config = config.get('config') sql = config.get('query') return_dict_list = config.get('return_dict_list', False) mysql_config = templated_var(mysql_config, variable_binds) if isinstance(mysql_config, str): mysql_config = json.loads(mysql_config) sql = templated_var(sql) if isinstance(return_dict_list, str): return_dict_list = True if return_dict_list.lower( ) == 'true' else False try: with MysqlClient(mysql_config) as cli: r = None if return_dict_list is False: res = cli.query(sql) r = list() for i in res: if isinstance(i, tuple): i = i[0] r.append(i) else: r = cli.query(sql, return_dict_list=return_dict_list) if len(r) == 0: raise Exception( "No data queried in MySQL by '{}'!".format(sql)) return generators.factory_fixed_sequence(r)() except Exception as e: logger.error(str(e)) raise ValueError("Invalid query: " + sql + " : " + str(e))
def realize(self, context=None): if not context: context = self.context if self.url.startswith('/'): self.url = "$default_base_url" + self.url self.url = templated_var(self.url, context) self.method = templated_var(self.method, context) self.body = templated_var(self.body, context) self.headers = templated_var(self.headers, context)
def mysql_upsert(config, context=None): print("Run mysql_upsert") assert isinstance(config, dict) assert "config" in config assert "sql" in config sql = templated_var(config['sql'], context) mysql_config = templated_var(config['config'], context) mysql_config = json.loads(mysql_config) with MysqlClient(mysql_config) as cli: cli.execute(sql)
def extract_internal(self, body=None, headers=None, context=None): self.query = templated_var(self.query, context) self.mysql_config = templated_var(self.mysql_config, context) self.mysql_config = json.loads(self.mysql_config) try: with MysqlClient(self.mysql_config) as cli: res = cli.query(self.query) if len(res) == 0: raise Exception("No data queried in MySQL by '{}'!".format( self.query)) res = res[0] if isinstance(res, tuple): res = res[0] return res except Exception as e: raise ValueError("Invalid query: '" + self.query + "' : " + str(e))
def parse_configuration(node, base_config=None): """ Parse input config to configuration information """ test_config = base_config if not test_config: test_config = TestSetConfig() node = lowercase_keys(flatten_dictionaries(node)) # Make it usable if "testset" in node: test_config.testset_name = node['testset'] # ahead process variable_binds, other key can use it in template if not test_config.variable_binds: test_config.variable_binds = dict() if 'variable_binds' in node: value = node['variable_binds'] test_config.variable_binds.update(flatten_dictionaries(value)) # set default_base_url to global variable_binds if 'default_base_url' in node: value = node['default_base_url'] default_base_url = templated_var(value, test_config.variable_binds) test_config.variable_binds['default_base_url'] = default_base_url for key, value in node.items(): if key == 'timeout': test_config.timeout = int(value) elif key == 'retries': test_config.retries = int(value) elif key == 'collect_import_result': if isinstance(value, str): value = True if value.lower() == 'true' else False test_config.collect_import_result = value elif key == 'variable_binds': pass elif key == 'request_client': test_config.request_client = str(value) elif key == 'generators': flat = flatten_dictionaries(value) gen_map = dict() for generator_name, generator_config in flat.items(): gen = parse_generator( configuration=generator_config, variable_binds={ **test_config.variable_binds, 'working_directory': test_config.working_directory }) gen_map[str(generator_name)] = gen test_config.generators = gen_map if 'data_driven' in node: value = node['data_driven'] generator_name = value.get('generator', None) generator_obj = test_config.generators[generator_name] test_config.data_driven_generator = generator_obj test_config.data_driven_generator_name = generator_name return test_config
def print_operation(config, context=None): print("Run print_operation") assert isinstance(config, dict) assert "print" in config pr = config['print'] pr = templated_var(pr, context) print(pr) print('')
def sleep_operation(config, context=None): print("Run sleep_operation") assert isinstance(config, dict) assert "seconds" in config s = config['seconds'] s = templated_var(s, context) print("Sleep {} s".format(s)) time.sleep(int(s)) print()
def validate(self, body=None, headers=None, context=None): try: extracted_val = self.extractor.extract(body=body, headers=headers, context=context) except Exception as e: trace = traceback.format_exc() return Failure(message="Extractor threw exception", details=trace, validator=self, failure_type=FAILURE_EXTRACTOR_EXCEPTION) # Compute expected output, either templating or using expected value expected_val = None if isinstance(self.expected, AbstractExtractor): try: expected_val = self.expected.extract(body=body, headers=headers, context=context) except Exception as e: trace = traceback.format_exc() return Failure( message="Expected value extractor threw exception", details=trace, validator=self, failure_type=FAILURE_EXTRACTOR_EXCEPTION) elif context: expected_val = templated_var(self.expected, context) else: expected_val = self.expected # Handle a bytes-based body and a unicode expected value seamlessly if isinstance(extracted_val, bytes) and isinstance(expected_val, str): expected_val = expected_val.encode('utf-8') comparison = self.comparator(extracted_val, expected_val) if not comparison: failure = Failure(validator=self) failure.message = "Comparison failed, evaluating {0}({1}, {2}) returned False".format( self.comparator_name, extracted_val, expected_val) failure.details = self.get_readable_config(context=context) failure.failure_type = FAILURE_VALIDATOR_FAILED return failure else: return True
def get_readable_config(self, context=None): """ Print a human-readable version of the configuration """ query = templated_var(data=self.query, context=context) output = 'Extractor Type: {0}, Query: "{1}"'.format( self.extractor_type, query) return output
def extract(self, body=None, headers=None, context=None): """ Extract data """ self.query = templated_var(data=self.query, context=context) return self.extract_internal(body=body, headers=headers, context=context)
def run_testset(testset, request_handle=None, test_results=None): mytests = testset.tests myconfig = testset.config context = Context() if test_results is None: test_results = list() # Bind variables & add generators if pertinent if myconfig.variable_binds: context.bind_variables(myconfig.variable_binds) if myconfig.generators: for key, value in myconfig.generators.items(): context.add_generator(key, value) # Make sure we actually have tests to execute if not mytests: # no tests in this test set, probably just imports.. skip to next # test set return def none_generator(): yield None data_driven_generator = None if myconfig.data_driven_generator: data_driven_generator = myconfig.data_driven_generator else: data_driven_generator = none_generator() for ddt_data in data_driven_generator: if ddt_data: if not isinstance(ddt_data, dict): raise Exception("Data Driven Generator must return a dict, not {}".format(type(ddt_data))) logger.info("*************************") logger.info("Data Driven: {}".format(ddt_data)) context.bind_variables(ddt_data) # Run tests, collecting statistics as needed index = 0 loop_count = 0 while index < len(mytests) and loop_count < 100: test = mytests[index] if hasattr(test.testset_config, "loop_interval"): loop_interval = test.testset_config.loop_interval else: loop_interval = 2 result = None if test.test_type == "operation": logger.info("do operation {}, config:{}".format( test.config.get('type'), test.config )) result = TestResult() # result.test_type = "operation" result.testset_name = testset.name result.test_obj = test try: opt_name = test.config.get('type') opt_func = get_operation_function(opt_name) opt_func(test.config, context) result.passed = True except Exception as e: result.passed = False test_results.append(result) elif test.test_type == "testset": logger.info("call subtestset {}".format(test.file_path)) file_path = test.file_path input = test.input extract = test.extract subtestset = testset.subtestsets.get(file_path) result = TestResult() # result.test_type = "testset" result.test_obj = test result.testset_name = testset.name if subtestset: input = templated_var(input, context) if input: if not subtestset.config.variable_binds: subtestset.config.variable_binds = input else: subtestset.config.variable_binds.update(input) if myconfig.collect_import_result is True: sub_test_results_list = test_results else: sub_test_results_list = None _, extract_data = run_testset( subtestset, request_handle, test_results=sub_test_results_list) if extract_data: context.variables.update(extract_data) result.passed = True else: result.passed = False test_results.append(result) else: logger.debug("Run {}".format(test.test_type)) test.reload() result = test.run_test(test_config=myconfig, context=context, handler=request_handle) result.testset_name = testset.name result.data_driven_fields = ddt_data result.test_obj = test if not result.passed: # Print failure, increase failure counts for that test group error_info = result.to_str(verbose=True) logger.error(error_info) # Print test failure reasons if result.failures: for failure in result.failures: log_failure(failure, context=context, test_config=myconfig) else: # Test passed, print results logger.info(result.to_str(verbose=False)) # Add results to the resultset if result.loop is False: test_results.append(result) # handle stop_on_failure flag if not result.passed and test.stop_on_failure is not None and test.stop_on_failure: logger.info( 'STOP ON FAILURE! stopping test set execution, continuing with other test sets') break if result and result.loop is True: loop_count += 1 time.sleep(loop_interval) continue else: index += 1 continue extract_data = dict() if testset.config.extract: for key in testset.config.extract: if key in context.variables: extract_data[key] = context.variables.get(key) else: raise Exception("Error Extract Var {} in Context".format(key)) return test_results, extract_data
def get_body(self, context=None): """ Read body from file, applying template if pertinent """ if self.http_body is None: return None else: return templated_var(self.http_body, context)