| #!/usr/bin/env python | 
 |  | 
 | r""" | 
 | This module has functions to support various data structures such as the | 
 | boot_table, valid_boot_list and boot_results_table. | 
 | """ | 
 |  | 
 | import os | 
 | import tempfile | 
 | import json | 
 | from tally_sheet import * | 
 |  | 
 | from robot.libraries.BuiltIn import BuiltIn | 
 | try: | 
 |     from robot.utils import DotDict | 
 | except ImportError: | 
 |     import collections | 
 |  | 
 | import gen_print as gp | 
 | import gen_robot_print as grp | 
 | import gen_valid as gv | 
 | import gen_misc as gm | 
 | import gen_cmd as gc | 
 |  | 
 | # The code base directory will be one level up from the directory containing | 
 | # this module. | 
 | code_base_dir_path = os.path.dirname(os.path.dirname(__file__)) + os.sep | 
 |  | 
 |  | 
 | ############################################################################### | 
 | def create_boot_table(file_path=None): | 
 |  | 
 |     r""" | 
 |     Read the boot table JSON file, convert it to an object and return it. | 
 |  | 
 |     Note that if the user is running without a global OS_HOST robot variable | 
 |     specified, this function will remove all of the "os_" start and end state | 
 |     requirements from the JSON data. | 
 |  | 
 |     Description of arguments: | 
 |     file_path  The path to the boot_table file.  If this value is not | 
 |                specified, it will be obtained from the "BOOT_TABLE_PATH" | 
 |                environment variable, if set.  Otherwise, it will default to | 
 |                "data/boot_table.json".  If this value is a relative path, | 
 |                this function will use the code_base_dir_path as the base | 
 |                directory (see definition above). | 
 |     """ | 
 |     if file_path is None: | 
 |         file_path = os.environ.get('BOOT_TABLE_PATH', 'data/boot_table.json') | 
 |  | 
 |     if not file_path.startswith("/"): | 
 |         file_path = code_base_dir_path + file_path | 
 |  | 
 |     # Pre-process the file by removing blank lines and comment lines. | 
 |     temp = tempfile.NamedTemporaryFile() | 
 |     temp_file_path = temp.name | 
 |  | 
 |     cmd_buf = "egrep -v '^[ ]*$|^[ ]*#' " + file_path + " > " + temp_file_path | 
 |     gc.cmd_fnc_u(cmd_buf, quiet=1) | 
 |  | 
 |     boot_file = open(temp_file_path) | 
 |     boot_table = json.load(boot_file, object_hook=DotDict) | 
 |  | 
 |     # If the user is running without an OS_HOST, we remove os starting and | 
 |     # ending state requirements from the boot entries. | 
 |     os_host = BuiltIn().get_variable_value("${OS_HOST}", default="") | 
 |     if os_host == "": | 
 |         for boot in boot_table: | 
 |             state_keys = ['start', 'end'] | 
 |             for state_key in state_keys: | 
 |                 for sub_state in boot_table[boot][state_key]: | 
 |                     if sub_state.startswith("os_"): | 
 |                         boot_table[boot][state_key].pop(sub_state, None) | 
 |  | 
 |     return boot_table | 
 |  | 
 | ############################################################################### | 
 |  | 
 |  | 
 | ############################################################################### | 
 | def create_valid_boot_list(boot_table): | 
 |  | 
 |     r""" | 
 |     Return a list of all of the valid boot types (e.g. ['BMC Power On', | 
 |     'BMC Power Off', ....] | 
 |  | 
 |     Description of arguments: | 
 |     boot_table  A boot table such as is returned by the create_boot_table | 
 |     function. | 
 |     """ | 
 |  | 
 |     return list(boot_table.keys()) | 
 |  | 
 | ############################################################################### | 
 |  | 
 |  | 
 | ############################################################################### | 
 | def read_boot_lists(dir_path="data/boot_lists/"): | 
 |  | 
 |     r""" | 
 |     Read the contents of all the boot lists files found in the given boot lists | 
 |     directory and return dictionary of the lists. | 
 |  | 
 |     Boot lists are simply files containing a boot test name on each line. | 
 |     These files are useful for categorizing and organizing boot tests.  For | 
 |     example, there may be a "Power_on" list, a "Power_off" list, etc. | 
 |  | 
 |     The names of the boot list files will be the keys to the top level | 
 |     dictionary.  Each dictionary entry is a list of all the boot tests found | 
 |     in the corresponding file. | 
 |  | 
 |     Here is an abbreviated look at the resulting boot_lists dictionary. | 
 |  | 
 |     boot_lists: | 
 |       boot_lists[All]: | 
 |         boot_lists[All][0]:                           BMC Power On | 
 |         boot_lists[All][1]:                           BMC Power Off | 
 |     ... | 
 |       boot_lists[Code_update]: | 
 |         boot_lists[Code_update][0]:                   BMC oob hpm | 
 |         boot_lists[Code_update][1]:                   BMC ib hpm | 
 |     ... | 
 |  | 
 |     Description of arguments: | 
 |     dir_path  The path to the directory containing the boot list files.  If | 
 |               this value is a relative path, this function will use the | 
 |               code_base_dir_path as the base directory (see definition above). | 
 |     """ | 
 |  | 
 |     if not dir_path.startswith("/"): | 
 |         # Dir path is relative. | 
 |         dir_path = code_base_dir_path + dir_path | 
 |  | 
 |     # Get a list of all file names in the directory. | 
 |     boot_file_names = os.listdir(dir_path) | 
 |  | 
 |     boot_lists = DotDict() | 
 |     for boot_category in boot_file_names: | 
 |         file_path = gm.which(dir_path + boot_category) | 
 |         boot_list = gm.file_to_list(file_path, newlines=0, comments=0, trim=1) | 
 |         boot_lists[boot_category] = boot_list | 
 |  | 
 |     return boot_lists | 
 |  | 
 | ############################################################################### | 
 |  | 
 |  | 
 | ############################################################################### | 
 | def valid_boot_list(boot_list, | 
 |                     valid_boot_types): | 
 |  | 
 |     r""" | 
 |     Verify that each entry in boot_list is a supported boot test. | 
 |  | 
 |     Description of arguments: | 
 |     boot_list         An array (i.e. list) of boot test types | 
 |                       (e.g. "BMC Power On"). | 
 |     valid_boot_types  A list of valid boot types such as that returned by | 
 |                       create_valid_boot_list. | 
 |     """ | 
 |  | 
 |     for boot_name in boot_list: | 
 |         boot_name = boot_name.strip(" ") | 
 |         error_message = gv.svalid_value(boot_name, | 
 |                                         valid_values=valid_boot_types, | 
 |                                         var_name="boot_name") | 
 |         if error_message != "": | 
 |             BuiltIn().fail(gp.sprint_error(error_message)) | 
 |  | 
 | ############################################################################### | 
 |  | 
 |  | 
 | ############################################################################### | 
 | class boot_results: | 
 |  | 
 |     r""" | 
 |     This class defines a boot_results table. | 
 |     """ | 
 |  | 
 |     def __init__(self, | 
 |                  boot_table, | 
 |                  boot_pass=0, | 
 |                  boot_fail=0, | 
 |                  obj_name='boot_results'): | 
 |  | 
 |         r""" | 
 |         Initialize the boot results object. | 
 |  | 
 |         Description of arguments: | 
 |         boot_table  Boot table object (see definition above).  The boot table | 
 |                     contains all of the valid boot test types.  It can be | 
 |                     created with the create_boot_table function. | 
 |         boot_pass   An initial boot_pass value.  This program may be called | 
 |                     as part of a larger test suite.  As such there may already | 
 |                     have been some successful boot tests that we need to | 
 |                     keep track of. | 
 |         boot_fail   An initial boot_fail value.  This program may be called | 
 |                     as part of a larger test suite.  As such there may already | 
 |                     have been some unsuccessful boot tests that we need to | 
 |                     keep track of. | 
 |         obj_name    The name of this object. | 
 |         """ | 
 |  | 
 |         # Store the method parms as class data. | 
 |         self.__obj_name = obj_name | 
 |         self.__initial_boot_pass = boot_pass | 
 |         self.__initial_boot_fail = boot_fail | 
 |  | 
 |         # Create boot_results_fields for use in creating boot_results table. | 
 |         boot_results_fields = DotDict([('total', 0), ('pass', 0), ('fail', 0)]) | 
 |         # Create boot_results table. | 
 |         self.__boot_results = tally_sheet('boot type', | 
 |                                           boot_results_fields, | 
 |                                           'boot_test_results') | 
 |         self.__boot_results.set_sum_fields(['total', 'pass', 'fail']) | 
 |         self.__boot_results.set_calc_fields(['total=pass+fail']) | 
 |         # Create one row in the result table for each kind of boot test | 
 |         # in the boot_table (i.e. for all supported boot tests). | 
 |         for boot_name in list(boot_table.keys()): | 
 |             self.__boot_results.add_row(boot_name) | 
 |  | 
 |     def return_total_pass_fail(self): | 
 |  | 
 |         r""" | 
 |         Return the total boot_pass and boot_fail values.  This information is | 
 |         comprised of the pass/fail values from the table plus the initial | 
 |         pass/fail values. | 
 |         """ | 
 |  | 
 |         totals_line = self.__boot_results.calc() | 
 |         return totals_line['pass'] + self.__initial_boot_pass,\ | 
 |             totals_line['fail'] + self.__initial_boot_fail | 
 |  | 
 |     def update(self, | 
 |                boot_type, | 
 |                boot_status): | 
 |  | 
 |         r""" | 
 |         Update our boot_results_table.  This includes: | 
 |         - Updating the record for the given boot_type by incrementing the pass | 
 |           or fail field. | 
 |         - Calling the calc method to have the totals calculated. | 
 |  | 
 |         Description of arguments: | 
 |         boot_type    The type of boot test just done (e.g. "BMC Power On"). | 
 |         boot_status  The status of the boot just done.  This should be equal to | 
 |                      either "pass" or "fail" (case-insensitive). | 
 |         """ | 
 |  | 
 |         self.__boot_results.inc_row_field(boot_type, boot_status.lower()) | 
 |  | 
 |     def sprint_report(self, | 
 |                       header_footer="\n"): | 
 |  | 
 |         r""" | 
 |         String-print the formatted boot_resuls_table and return them. | 
 |  | 
 |         Description of arguments: | 
 |         header_footer  This indicates whether a header and footer are to be | 
 |                        included in the report. | 
 |         """ | 
 |  | 
 |         buffer = "" | 
 |  | 
 |         buffer += gp.sprint(header_footer) | 
 |         buffer += self.__boot_results.sprint_report() | 
 |         buffer += gp.sprint(header_footer) | 
 |  | 
 |         return buffer | 
 |  | 
 |     def print_report(self, | 
 |                      header_footer="\n"): | 
 |  | 
 |         r""" | 
 |         Print the formatted boot_resuls_table to the console. | 
 |  | 
 |         See sprint_report for details. | 
 |         """ | 
 |  | 
 |         grp.rqprint(self.sprint_report(header_footer)) | 
 |  | 
 |     def sprint_obj(self): | 
 |  | 
 |         r""" | 
 |         sprint the fields of this object.  This would normally be for debug | 
 |         purposes only. | 
 |         """ | 
 |  | 
 |         buffer = "" | 
 |  | 
 |         buffer += "class name: " + self.__class__.__name__ + "\n" | 
 |         buffer += gp.sprint_var(self.__obj_name) | 
 |         buffer += self.__boot_results.sprint_obj() | 
 |         buffer += gp.sprint_var(self.__initial_boot_pass) | 
 |         buffer += gp.sprint_var(self.__initial_boot_fail) | 
 |  | 
 |         return buffer | 
 |  | 
 |     def print_obj(self): | 
 |  | 
 |         r""" | 
 |         Print the fields of this object to stdout.  This would normally be for | 
 |         debug purposes. | 
 |         """ | 
 |  | 
 |         grp.rprint(self.sprint_obj()) | 
 |  | 
 | ############################################################################### |