def test_golden(self, steps, local_class, operating_system, display_only_failed=None, token=None, number=None): """Test step that finds any output named with _output.txt, and compares to similar named .py file.""" if token: folder_root = pathlib.Path( f"{operating_system}/{token}/{local_class.__name__}/cli/equal") else: folder_root = pathlib.Path( f"{operating_system}/{local_class.__name__}/cli/equal") # Get list of output files to parse and sort convert = lambda text: int(text) if text.isdigit() else text aph_key = lambda key: [convert(c) for c in re.split("([0-9]+)", key)] if number and not operating_system or not local_class: output_glob = sorted( glob.glob(f"{folder_root}/golden_output{number}_output.txt"), key=aph_key, ) else: output_glob = sorted(glob.glob(f"{folder_root}/*_output.txt"), key=aph_key) all_txt_glob = sorted(glob.glob(f"{folder_root}/*.txt"), key=aph_key) unacceptable_filenames = [ fil for fil in all_txt_glob if fil not in output_glob ] if len(output_glob) == 0: steps.failed( f"No files found in appropriate directory for {local_class}") # Look for any files ending with _output.txt, presume the user defined name from that (based # on truncating that _output.txt suffix) and obtaining expected results and potentially an arguments file for user_defined in output_glob: glo_values.parserTotal += 1 user_test = os.path.basename(user_defined[:-len("_output.txt")]) if token: msg = f"Gold -> {operating_system} -> Token {token} -> {local_class.__name__} -> {user_test}" else: msg = f"Gold -> {operating_system} -> {local_class.__name__} -> {user_test}" with steps.start(msg, continue_=True): golden_output_str = read_from_file( f"{folder_root}/{user_test}_output.txt") golden_output = { "execute.return_value": golden_output_str, "expect.return_value": golden_output_str, } golden_parsed_output = read_python_file( f"{folder_root}/{user_test}_expected.py") arguments = {} if os.path.exists(f"{folder_root}/{user_test}_arguments.json"): arguments = read_json_file( f"{folder_root}/{user_test}_arguments.json") device = Mock(**golden_output) obj = local_class(device=device) try: parsed_output = obj.parse(**arguments) except Exception as e: parsed_output = {} self.add_logger() log.error(traceback.format_exc(), extra={'colour': 'red'}) self.remove_logger() glo_values.parserErrored += 1 # Use Diff method to get the difference between # what is expected and the parsed output dd = Diff(parsed_output, golden_parsed_output) dd.findDiff() if parsed_output != golden_parsed_output: glo_values.parserFailed += 1 # if -f flag provided, then add the screen handler back into # the root.handlers to displayed failed tests. Decorator removes # screen handler from root.handlers after failed tests are displayed # to stdout if display_only_failed: self.add_logger() log.info(banner(msg)) # Format expected and parsed output in a nice format parsed_json_data = format_output(parsed_output) golden_parsed_output_json_data = format_output( golden_parsed_output) # Display device output, parsed output, and golden_output of failed tests log.info( f"\nThe following is the device output before it is parsed:\n{golden_output['execute.return_value']}\n\n", extra={'colour': 'yellow'}) log.info( f"The following is your device's parsed output:\n{parsed_json_data}\n", extra={'colour': 'yellow'}) log.info( f"The following is your expected output:\n{golden_parsed_output_json_data}\n", extra={'colour': 'yellow'}) log.info( "The following is the difference between the two outputs:\n", extra={'colour': 'yellow'}) # Display the diff between parsed output and golden_output log.info(str(dd), extra={'colour': 'yellow'}) if display_only_failed: self.remove_logger() raise AssertionError( "Device output and expected output do not match") else: glo_values.parserPassed += 1 # If tests pass, display the device output in debug mode # But first check if the screen handler is removed, if it is # put it back into the root otherwise just display to stdout if (self.temporary_screen_handler in log.root.handlers or self.temporary_screen_handler is None): logging.debug(banner(msg)) logging.debug( "\nThe following is the device output for the passed parser:\n{}\n" .format(golden_output['execute.return_value']), extra={'colour': 'yellow'}) else: self.add_logger() logging.debug(banner(msg)) logging.debug( "\nThe following is the device output for the passed parser:\n{}\n" .format(golden_output['execute.return_value']), extra={'colour': 'yellow'}) self.remove_logger() if unacceptable_filenames: for unacc_fil in unacceptable_filenames: unacc_fil_name = pathlib.Path(unacc_fil).name msg = f"{unacc_fil_name} does not follow the filename schema and will not be ran..." with steps.start(msg, continue_=True) as step: if (self.temporary_screen_handler in log.root.handlers or self.temporary_screen_handler is None): log.info( f"Filename should be `{unacc_fil_name.split('.')[0]}_expected.txt`", extra={'colour': 'yellow'}) else: self.add_logger() log.info(msg, extra={'colour': 'yellow'}) log.info( f"Filename should be `{unacc_fil_name.split('.')[0]}_expected.txt`", extra={'colour': 'yellow'}) self.remove_logger() step.failed()
def _pre_post_processors(self, testbed, processor, section, data, name, devices_connected, processor_targets, processor_type, pre_processor_result=Passed): """ execute pre/post processors and return if pre-processor runs and processor result Arguments: testbed (`obj`): testbed object processor (`obj`): Aetest Processor object section (`obj`): Aetest Section object data (`list`) : data of section name (`str`) : name of section in health yaml devices_connected (`list`) : list of connected devices processor_targets (`list`) : list of `processor_flag which ones will be run as pre/post processors processor_type (`str`) : processor type `pre` or `post` pre_processor_result (`ob`) : result object. Default to `Passed` Returns: pre_processor_run (`bool`) : if pre processor runs or not pre_processor_result (`obj`) : return processor result (Result obj) """ new_data_dict = {} selected_options = 0 list_of_args = [] # flag if health args are given to pyats command args_flag = False # flag if health args are defined under action in health yaml args_in_yaml_flag = False log.debug( 'data:\n{d}'.format(d=json.dumps(data, indent=2, sort_keys=True))) orig_data = copy.deepcopy(data) # check if health arguments are given to pyats command for arg_name in ['health_sections', 'health_uids', 'health_groups']: if getattr(runtime.args, arg_name): args_flag = True for item in self._get_actions(data): if Dq(item).contains( 'health_sections|health_uids|health_groups', regex=True): args_in_yaml_flag = True for arg_name in ['health_sections', 'health_uids', 'health_groups']: log.debug('Checking {an}'.format(an=arg_name)) selected = None selected_options = 0 for item in self._get_actions(data): # from argument arg_search_keyword = getattr(runtime.args, arg_name) if arg_search_keyword: args_flag = True selected = self._select_health( section, item, arg_search_keyword.split(' '), arg_name) selected_options += 1 list_of_args.append(arg_name) if selected: new_data_dict.setdefault(arg_name, {}).setdefault( selected_options, selected) if not args_flag: # from datafile search_keywords = [] search_keywords = getattr( runtime.args, arg_name) or Dq(item).get_values(arg_name) if not isinstance(search_keywords, list): search_keywords = [search_keywords] if search_keywords == []: # if args are given to one of actions, other actions # will run to all sections by default. To do so, # adding `.*` as search_keywords # ex.) # - api: # only section1 # function: func1 # health_sections: section1 # - api: # all sections # function: func2 if (args_in_yaml_flag and arg_name == 'health_sections' ) and (not Dq(item).get_values('health_sections') and not Dq(item).get_values('health_uids')): search_keywords = ['.*'] else: search_keywords = None log.debug( "arg_name, search_keywords: {sel_name}, {sel}".format( sel_name=arg_name, sel=search_keywords)) if search_keywords: selected_options += 1 list_of_args.append(arg_name) selected = self._select_health(section, item, search_keywords, arg_name) if selected: new_data_dict.setdefault(arg_name, {}).setdefault( selected_options, selected) if args_flag: # check for the case which multiple `arg_name`s given and check the same # among the `arg_name`s. if same between `arg_name`s, data will be overwittern # by one of new_data_dict value to execute selected ones new_data_flag = False if new_data_dict: value = '' log.debug( 'num of health args: {n}'.format(n=len(set(list_of_args)))) log.debug( 'num of new_data_dict: {n}'.format(n=len(new_data_dict))) if len(set(list_of_args)) == len(new_data_dict): for key, value_ in new_data_dict.items(): if value == value_: new_data_flag = True else: new_data_flag = False if not value: value = value_ if len(new_data_dict) == 1: new_data_flag = True else: new_data_flag = bool(new_data_dict) log.debug('new_data_flag: {f}'.format(f=new_data_flag)) log.debug('new_data_dict: {ndd}'.format( ndd=json.dumps(new_data_dict, indent=2, sort_keys=True))) if new_data_flag: temp_data = [] # override data because meeting criteria by `arg_name`s for key in new_data_dict: for idx in new_data_dict[key]: temp_data.append(new_data_dict[key][idx].pop()) data = temp_data else: if (not new_data_dict or len(set(list_of_args)) != len(new_data_dict)) and len(set(list_of_args)) != 0: data = [] # processor start message log.debug('{type}-processor {name} started'.format( name=name, type=processor_type.capitalize())) pre_processor_run = True # check if `processor` tag matches processor_targets and # if device for action is connected # create temp_data with matched actions and override data by temp_data temp_data = [] # list of checked devices. flag to ignore checked device device_checked = [] # None if no device is defined in any actions all_devices_connected = None for each_data in self._get_actions(data): for key in each_data: log.debug( 'processor_targets: {pt}'.format(pt=processor_targets)) log.debug('processor: {p}'.format( p=each_data[key].get('processor', 'both'))) if each_data[key].get('processor', 'both') in processor_targets: # check if device for action is connected all_devices_connected = None for uut in self._get_device_names(orig_data, each_data): if uut not in device_checked: device_checked.append(uut) if isinstance(uut, str): if (testbed.devices[uut].name in devices_connected) or ( testbed.devices[uut].alias in devices_connected): all_devices_connected = True else: all_devices_connected = False log.info( 'Device {d} is not connected.'.format( d=testbed.devices[uut].name)) break else: if (uut.name in devices_connected) or ( uut.alias in devices_connected): all_devices_connected = True else: all_devices_connected = False log.info( 'Device {d} is not connected.'.format( d=testbed.devices[uut].name)) break if (all_devices_connected == True or all_devices_connected is None): temp_data.append(each_data) # until here, data contains only actions # for cases like `parallel`, `loop`, need to put the headers # from original data `orig_data` if 'actions' in orig_data: data = copy.deepcopy(orig_data) if temp_data: data['actions'] = temp_data data = [{'loop': data}] else: data = [] elif isinstance(orig_data, list): if len(orig_data) > 0 and 'parallel' in orig_data[0]: data = copy.deepcopy(orig_data)[0] if temp_data: data['parallel'] = temp_data data = [data] else: data = [] else: data = temp_data else: data = temp_data # remove section if no data if not data: processor.reporter.remove_section(id_list=processor.uid.list) # if any device is not connected, processor will be skipped if devices_connected: # instantiate Steps() to reset step number steps = Steps() # execute dispatcher in Blitz result = self.dispatcher(steps, testbed, section, data, name) try: log.debug('Blitz section return:\n{result}'.format( result=json.dumps(result, indent=2, sort_keys=True))) except TypeError: log.debug('Blitz section return:\n{result}'.format( result=format_output(result))) # check section result log.debug('section result: {section_result}'.format( section_result=section.result.name)) log.debug('steps result: {steps_result}'.format( steps_result=steps.result.name)) if processor_type == 'pre' and steps.result != Passed and steps.result != Passx: log.info( "Pre-processor pyATS Health {name} was failed, but continue section and Post-processor" .format(name=name)) # save pre-processor result pre_processor_result = steps.result return pre_processor_run, pre_processor_result elif processor_type == 'post': # refrect processor results to section processor.result += steps.result section.result = section.result + processor.result + self.pre_processor_result return pre_processor_run, pre_processor_result else: if processor_type == 'pre': pre_processor_run = False # processor is skipped. but call passed to move forward for this case log.info( "Pre-processor pyATS Health '{name}' is skipped because devices are not connected." .format(name=name)) return pre_processor_run, pre_processor_result elif processor_type == 'post': # for the case only pre-processors runs if section.result == pre_processor_result: log.info('Only Pre-processor runs. Section result and ' 'Pre-processor result are different.Reflecting ' 'Post-processor result to Section.') # reflect processor results to section section.result = section.result + processor.result + self.pre_processor_result log.info( "Post-processor pyATS Health '{name}' was skipped because devices are not connected." .format(name=name)) return pre_processor_run, pre_processor_result return pre_processor_run, pre_processor_result
def _pre_post_processors(self, testbed, processor, section, data, name, devices_connected, processor_flag, processor_targets, processor_type, pre_processor_result=Passed): """ execute pre/post processors and return if pre-processor runs and processor result Arguments: testbed (`obj`): testbed object processor (`obj`): Aetest Processor object section (`obj`): Aetest Section object data (`list`) : data of section name (`str`) : name of section in health yaml devices_connected (`bool`) : if devices are connected, or not processor_flag (`str`) : `pre`, `post`, `both` and etc processor_targets (`list`) : list of `processor_flag which ones will be run as pre/post processors processor_type (`str`) : processor type `pre` or `post` pre_processor_result (`ob`) : result object. Default to `Passed` Returns: pre_processor_run (`bool`) : if pre processor runs or not pre_processor_result (`obj`) : return processor result (Result obj) """ new_data_dict = {} selected_options = 0 list_of_args = [] args_flag = False # check if health arguments are given to pyats command for arg_name in ['health_sections', 'health_uids', 'health_groups']: if getattr(runtime.args, arg_name): args_flag = True for arg_name in ['health_sections', 'health_uids', 'health_groups']: log.debug('Checking {an}'.format(an=arg_name)) selected = None selected_options = 0 for item in data: # from argument arg_search_keyword = getattr(runtime.args, arg_name) if arg_search_keyword: args_flag = True selected = self._select_health( section, item, arg_search_keyword.split(' '), arg_name) selected_options += 1 list_of_args.append(arg_name) if selected: new_data_dict.setdefault(arg_name, {}).setdefault( selected_options, selected) if not args_flag: # from datafile search_keywords = [] search_keywords = getattr( runtime.args, arg_name) or Dq(item).get_values(arg_name) if not isinstance(search_keywords, list): search_keywords = [search_keywords] if search_keywords == []: search_keywords = None log.debug( "arg_name, search_keywords: {sel_name}, {sel}".format( sel_name=arg_name, sel=search_keywords)) if search_keywords: selected_options += 1 list_of_args.append(arg_name) selected = self._select_health(section, item, search_keywords, arg_name) if selected: new_data_dict.setdefault(arg_name, {}).setdefault( selected_options, selected) # check for the case which multiple `arg_name`s given and check the same # among the `arg_name`s. if same between `arg_name`s, data will be overwittern # by one of new_data_dict value to execute selected ones new_data_flag = False if new_data_dict: value = '' log.debug( 'num of health args: {n}'.format(n=len(set(list_of_args)))) log.debug('num of new_data_dict: {n}'.format(n=len(new_data_dict))) if len(set(list_of_args)) == len(new_data_dict): for key, value_ in new_data_dict.items(): if value == value_: new_data_flag = True else: new_data_flag = False if not value: value = new_data_dict[key] if len(new_data_dict) == 1: new_data_flag = True log.debug('new_data_flag: {f}'.format(f=new_data_flag)) log.debug('new_data_dict: {ndd}'.format(ndd=new_data_dict)) if new_data_flag: data2 = [] # override data because meeting criteria by `arg_name`s for key in new_data_dict: for idx in new_data_dict[key]: data2.append(new_data_dict[key][idx].pop()) data = data2 else: # remove report based on conditions # - no found data based on search # - devices are not connected # - number of given arguments and found data are not equal # - number of given arguments is not 0 if (not new_data_dict or not devices_connected or len(set(list_of_args)) != len(new_data_dict)) and len( set(list_of_args)) != 0: processor.reporter.remove_section(id_list=processor.uid.list) if (not new_data_dict or len(set(list_of_args)) != len(new_data_dict)) and len(set(list_of_args)) != 0: data = [] # if devices are not connected, delete processor from reporter if not devices_connected and data: processor.reporter.remove_section(id_list=processor.uid.list) # processor start message log.debug('{type}-processor {name} started'.format( name=name, type=processor_type.capitalize())) pre_processor_run = True # check `processor` to control if processor_flag in processor_targets: # if any device is not connected, processor will be skipped if devices_connected: # instantiate Steps() to reset step number steps = Steps() result = self.dispatcher(steps, testbed, section, data, name) log.debug('Blitz section return:\n{result}'.format( result=format_output(result))) # check section result log.debug('section result: {section_result}'.format( section_result=section.result.name)) log.debug('steps result: {steps_result}'.format( steps_result=steps.result.name)) if processor_type == 'pre' and steps.result != Passed and steps.result != Passx: log.info( "Pre-processor pyATS Health {name} was failed, but continue section and Post-processor" .format(name=name)) # save pre-processor result pre_processor_result = steps.result return pre_processor_run, pre_processor_result elif processor_type == 'post': # refrect result to section getattr( section, str(steps.result + steps.result + self.pre_processor_result))() return pre_processor_run, pre_processor_result else: if processor_type == 'pre': pre_processor_run = False # processor is skipped. but call passed to move forward for this case log.info( "Pre-processor pyATS Health '{name}' is skipped because devices are not connected." .format(name=name)) return pre_processor_run, pre_processor_result elif processor_type == 'post': # for the case only pre-processors runs if section.result == pre_processor_result: log.info( 'Only Pre-processor runs. Section result and Pre-processor result are different. Reflecting Post-processor result to Section.' ) getattr(section, str(section.result + pre_processor_result))() log.info( "Post-processor pyATS Health '{name}' was skipped because devices are not connected." .format(name=name)) return pre_processor_run, pre_processor_result else: log.info('Skipped because {name} is not {type}-processor'.format( name=name, type=processor_type.capitalize())) return pre_processor_run, pre_processor_result return pre_processor_run, pre_processor_result
def _pre_post_processors(self, testbed, processor, section, data, name, reconnect, processor_targets, processor_type, pre_processor_result=Passed, health_settings=None): """ execute pre/post processors and return if pre-processor runs and processor result Arguments: testbed (`obj`): testbed object processor (`obj`): Aetest Processor object section (`obj`): Aetest Section object data (`list`) : data of section name (`str`) : name of section in health yaml reconnect (`dict` or None) : parameters for reconnect processor_targets (`list`) : list of `processor_flag which ones will be run as pre/post processors processor_type (`str`) : processor type `pre` or `post` pre_processor_result (`ob`) : result object. Default to `Passed` Returns: pre_processor_run (`bool`) : if pre processor runs or not pre_processor_result (`obj`) : return processor result (Result obj) """ devices_connected = [] new_data_dict = {} selected_options = 0 list_of_args = [] # store reasons why processor is skipped reasons = [] # flag if health args are given to pyats command args_flag = False # flag if health args are defined under action in health yaml args_in_yaml_flag = False log.debug( 'data:\n{d}'.format(d=json.dumps(data, indent=2, sort_keys=True))) orig_data = copy.deepcopy(data) # check if health arguments are given to pyats command for arg_name in [ 'health_tc_sections', 'health_tc_uids', 'health_tc_groups', 'health_sections', 'health_uids', 'health_groups' ]: if getattr(runtime.args, arg_name): args_flag = True for item in self._get_actions(data, processor_targets): if Dq(item).contains( 'health_tc_sections|health_tc_uids|health_tc_groups|health_sections|health_uids|health_groups', regex=True): args_in_yaml_flag = True for arg_name in [ 'health_tc_sections', 'health_tc_uids', 'health_tc_groups', 'health_sections', 'health_uids', 'health_groups' ]: log.debug('Checking {an}'.format(an=arg_name)) selected = None selected_options = 0 for item in self._get_actions(data, processor_targets): # from argument arg_search_keyword = getattr(runtime.args, arg_name) if arg_search_keyword: args_flag = True selected = self._select_health( section, item, arg_search_keyword.split(' '), arg_name) selected_options += 1 list_of_args.append(arg_name) if selected: new_data_dict.setdefault(arg_name, {}).setdefault( selected_options, selected) if not args_flag: # from datafile search_keywords = [] search_keywords = getattr( runtime.args, arg_name) or Dq(item).get_values(arg_name) if not isinstance(search_keywords, list): search_keywords = [search_keywords] if search_keywords == []: # if args are given to one of actions, other actions # will run to all sections by default. To do so, # adding `.*` as search_keywords # ex.) # - api: # only section1 # function: func1 # health_tc_sections: section1 # - api: # all sections # function: func2 if (args_in_yaml_flag and arg_name in ['health_tc_sections', 'health_sections'] and ((not Dq(item).get_values('health_tc_sections') or not Dq(item).get_values('health_sections')) and (not Dq(item).get_values('health_tc_uids') or not Dq(item).get_values('health_uids')))): search_keywords = ['.*'] else: search_keywords = None log.debug( "arg_name, search_keywords: {sel_name}, {sel}".format( sel_name=arg_name, sel=search_keywords)) if search_keywords: selected_options += 1 list_of_args.append(arg_name) selected = self._select_health(section, item, search_keywords, arg_name) if selected: new_data_dict.setdefault(arg_name, {}).setdefault( selected_options, selected) if args_flag: # check for the case which multiple `arg_name`s given and check the same # among the `arg_name`s. if same between `arg_name`s, data will be overwittern # by one of new_data_dict value to execute selected ones new_data_flag = False if new_data_dict: value = '' log.debug( 'num of health args: {n}'.format(n=len(set(list_of_args)))) log.debug( 'num of new_data_dict: {n}'.format(n=len(new_data_dict))) if len(set(list_of_args)) == len(new_data_dict): for key, value_ in new_data_dict.items(): if value == value_: new_data_flag = True else: new_data_flag = False if not value: value = value_ if len(new_data_dict) == 1: new_data_flag = True else: new_data_flag = len(set(list_of_args)) == len(new_data_dict) log.debug('new_data_flag: {f}'.format(f=new_data_flag)) log.debug('new_data_dict: {ndd}'.format( ndd=json.dumps(new_data_dict, indent=2, sort_keys=True))) if new_data_flag: temp_data = [] # override data because meeting criteria by `arg_name`s for key, value__ in new_data_dict.items(): for idx in value__: # data from each health arg should be same # so remove redundant data by overwriting temp_data = [new_data_dict[key][idx].pop()] data = temp_data elif (not new_data_dict or len(set(list_of_args)) != len(new_data_dict) ) and len(set(list_of_args)) != 0: reasons.append( f"health arg {set(list_of_args)-set(new_data_dict.keys())} does not meet criteria" ) data = [] # processor start message log.debug('{type}-processor {name} started'.format( name=name, type=processor_type.capitalize())) pre_processor_run = True # check if `processor` tag matches processor_targets and # if device for action is connected # create temp_data with matched actions and override data by temp_data temp_data = [] # list of checked devices. flag to ignore checked device device_checked = [] # None if no device is defined in any actions all_devices_connected = None common_api = False if new_data_dict and new_data_flag: # get connected devices list devices_connected = self._check_all_devices_connected( testbed, data, reconnect) devices_connected = [dev for dev in devices_connected if dev != ''] actions = self._get_actions(data, processor_targets) if not actions: # check processor in action and put in proc_in_action proc_in_action = [] if isinstance(data, list): for each_data in data: for each_proc in Dq(each_data).get_values('processor'): proc_in_action.append(each_proc) else: for each_proc in Dq(data).get_values('processor'): proc_in_action.append(each_proc) proc_in_action = set(proc_in_action) if proc_in_action: reasons.append( f"processor {proc_in_action} does not meet criteria {processor_targets}" ) for each_data in actions: for key in each_data: # get processor key from action. by default, `both` each_data_dq = Dq(each_data) processor_from_yaml = each_data_dq.contains(key).get_values( 'processor', 0) if not processor_from_yaml: processor_from_yaml = 'both' log.debug( 'processor_targets: {pt}'.format(pt=processor_targets)) log.debug('processor: {p}'.format(p=processor_from_yaml)) # find `common_api` key and return True/False common_api = any(each_data_dq.get_values('common_api')) if processor_from_yaml in processor_targets: # check if device for action is connected all_devices_connected = None devices_not_connected = [] for uut in self._get_device_names(orig_data, each_data): if uut not in device_checked: device_checked.append(uut) if isinstance(uut, str): if (testbed.devices[uut].name in devices_connected) or ( testbed.devices[uut].alias in devices_connected): all_devices_connected = True else: all_devices_connected = False devices_not_connected.append(uut) elif (uut.name in devices_connected) or ( uut.alias in devices_connected): all_devices_connected = True else: all_devices_connected = False devices_not_connected.append(uut) if devices_not_connected: log.warning("devices are not connected: {}".format( devices_not_connected)) force_all_connected = health_settings.get( 'force_all_connected', True) if device_checked and not force_all_connected and devices_connected: log.warning( "force_all_connected is False. Executing even though some of devices might not be connected." ) # data will be created if all devices are connected or # if force_all_connected == False and one of devices is connected if (all_devices_connected == True or all_devices_connected is None) or (force_all_connected == False and devices_connected): temp_data.append(each_data) else: log.warning( 'health check is blocked due to force_all_connected is True.' ) # until here, data contains only actions # for cases like `parallel`, `loop`, need to put the headers # from original data `orig_data` if 'actions' in orig_data and data and temp_data: data = copy.deepcopy(orig_data) if temp_data: data['actions'] = temp_data data = [{'loop': data}] else: data = [] elif isinstance(orig_data, list): if len(orig_data ) > 0 and 'parallel' in orig_data[0] and data and temp_data: data = copy.deepcopy(orig_data)[0] if temp_data: data['parallel'] = temp_data data = [data] else: data = [] elif len(orig_data) > 0 and 'run_condition' in orig_data[ 0] and data and temp_data: data = copy.deepcopy(orig_data)[0] data = [data] else: data = temp_data else: data = temp_data # remove section if no data removed_section = False # set reason in case device is not connected if (not devices_connected and not common_api) and not reasons: reasons.append('Device is not connected') if not data or reasons: processor.result = Skipped processor.reporter.remove_section(id_list=processor.uid.list) removed_section = True # if any device is not connected, processor will be skipped # if common_api is True, will execute if devices_connected or common_api: # instantiate Steps() to reset step number steps = Steps() # execute dispatcher in Blitz result = self.dispatcher(steps, testbed, section, data, name) if isinstance(data, list): hide_processor = any( Dq(data[0]).get_values('hide_processor', 0) == True for each_data in data) else: hide_processor = Dq(data[0]).get_values('hide_processor', 0) if hide_processor and not removed_section: removed_section = self._remove_section(processor) try: log.debug('Blitz section return:\n{result}'.format( result=json.dumps(result, indent=2, sort_keys=True))) except TypeError: log.debug('Blitz section return:\n{result}'.format( result=format_output(result))) # check section result log.debug('section result: {section_result}'.format( section_result=section.result.name)) log.debug('steps result: {steps_result}'.format( steps_result=steps.result.name)) # if section is skipped by run_condition, remove section if (isinstance(result, dict) and 'run_condition_skipped' in result and not removed_section and result['run_condition_skipped'] == True): processor.result = Skipped removed_section = self._remove_section(processor) if processor_type == 'pre' and steps.result != Passed and steps.result != Passx: log.info( "Pre-processor pyATS Health {name} was failed, but continue section and Post-processor" .format(name=name)) # save pre-processor result pre_processor_result = steps.result return pre_processor_run, pre_processor_result elif processor_type == 'post': # refrect processor results to section processor.result += steps.result section.result = section.result + processor.result + self.pre_processor_result # return processor.result to raise the result # at end of context post processor return pre_processor_run, processor.result elif processor_type == 'pre': pre_processor_run = False # processor is skipped log.info( f"Pre-processor pyATS Health '{name}' is skipped due to: {reasons}" ) if pre_processor_result == Passed: # processor.skipped() pre_processor_result = Skipped return pre_processor_run, pre_processor_result elif processor_type == 'post': # for the case only pre-processors runs if section.result == pre_processor_result: log.info('Only Pre-processor runs. Section result and ' 'Pre-processor result are different.Reflecting ' 'Post-processor result to Section.') # reflect processor results to section section.result = section.result + processor.result + self.pre_processor_result # processor is skipped log.info( f"Post-processor pyATS Health '{name}' was skipped due to: {reasons}" ) if pre_processor_result == Passed: # processor.skipped() pre_processor_result = Skipped # return processor.result to raise the result # at end of context post processor return pre_processor_run, processor.result return pre_processor_run, pre_processor_result
def _pre_post_processors(self, testbed, section, data, name, devices_connected, processor_flag, processors, processor_type, pre_processor_result=Passed): # processor start message # import remote_pdb; remote_pdb.set_trace() log.debug('{type}-processor {name} started'.format( name=name, type=processor_type.capitalize())) pre_processor_run = True # check `processor` to control if processor_flag in processors: # if any device is not connected, processor will be skipped if devices_connected: # instantiate Steps() to reset step number steps = Steps() result = self.dispatcher(steps, testbed, section, data, name) log.debug('Blitz section return:\n{result}'.format( result=format_output(result))) # check section result log.debug('section result: {section_result}'.format( section_result=section.result.name)) log.debug('steps result: {steps_result}'.format( steps_result=steps.result.name)) if processor_type == 'pre' and steps.result != Passed and steps.result != Passx: log.info( "Pre-processor pyATS Health {name} was failed, but continue section and Post-processor" .format(name=name)) # save pre-processor result pre_processor_result = steps.result return pre_processor_run, pre_processor_result elif processor_type == 'post': # refrect result to section getattr( section, str(steps.result + steps.result + self.pre_processor_result))() return pre_processor_run, pre_processor_result else: if processor_type == 'pre': pre_processor_run = False # processor is skipped. but call passed to move forward for this case log.info( "Pre-processor pyATS Health '{name}' is skipped because devices are not connected." .format(name=name)) return pre_processor_run, pre_processor_result elif processor_type == 'post': # for the case only pre-processors runs if section.result == pre_processor_result: log.info( 'Only Pre-processor runs. Section result and Pre-processor result are different. Reflecting Post-processor result to Section.' ) getattr(section, str(section.result + pre_processor_result))() log.info( "Post-processor pyATS Health '{name}' was skipped because devices are not connected." .format(name=name)) return pre_processor_run, pre_processor_result else: log.info('Skipped because {name} is not {type}-processor'.format( name=name, type=processor_type.capitalize())) return pre_processor_run, pre_processor_result return pre_processor_run, pre_processor_result