Created new lib/boot_data.py module.
Includes the following:
- create_boot_table
- create_valid_boot_list
- read_boot_lists
- valid_boot_list
- boot_results class.
Change-Id: Id1a0b95a5aad93bc8541963430d67c6423125aab
Signed-off-by: Michael Walsh <micwalsh@us.ibm.com>
diff --git a/lib/boot_data.py b/lib/boot_data.py
new file mode 100755
index 0000000..c036dc8
--- /dev/null
+++ b/lib/boot_data.py
@@ -0,0 +1,308 @@
+#!/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())
+
+###############################################################################