| #!/usr/bin/python | 
 | r""" | 
 | ############################################################# | 
 | #    @brief   Uses robot framework API to extract test result | 
 | #             data from output.xml generated by robot tests. | 
 | #             For more information on the Robot Framework API | 
 | #             http://robot-framework.readthedocs.io/en/3.0 | 
 | #             /autodoc/robot.result.html | 
 | ############################################################# | 
 | """ | 
 | import sys | 
 | import getopt | 
 | import csv | 
 | from datetime import datetime | 
 | import robot.errors | 
 | from robot.api import ExecutionResult | 
 | from robot.result.visitor import ResultVisitor | 
 | from xml.etree import ElementTree | 
 | import re | 
 |  | 
 |  | 
 | def parse_output_xml(xml_file_path, csv_dir_path): | 
 |     result = ExecutionResult(xml_file_path) | 
 |     result.configure(stat_config={'suite_stat_level': 2, | 
 |                                   'tag_stat_combine': 'tagANDanother'}) | 
 |  | 
 |     stats = result.statistics | 
 |     print "--------------------------------------" | 
 |     print "Total Test Count:\t",\ | 
 |           stats.total.critical.passed + stats.total.critical.failed | 
 |     print "Total Test Failed:\t", stats.total.critical.failed | 
 |     print "Total Test Passed:\t", stats.total.critical.passed | 
 |     print "Test Start Time:\t", result.suite.starttime | 
 |     print "Test End Time:\t\t", result.suite.endtime | 
 |     print "--------------------------------------" | 
 |  | 
 |     # Use ResultVisitor object and save off the test data info | 
 |     class TestResult(ResultVisitor): | 
 |         def __init__(self): | 
 |             self.testData = [] | 
 |  | 
 |         def visit_test(self, test): | 
 |             self.testData += [test] | 
 |  | 
 |     collectDataObj = TestResult() | 
 |     result.visit(collectDataObj) | 
 |  | 
 |     # Write the result statistics attributes to CSV file | 
 |     l_csvlist = [] | 
 |  | 
 |     # Default Test data | 
 |     l_subsys = 'OPENBMC' | 
 |     l_test_type = 'FTC' | 
 |     l_pse_rel = 'OBMC910' | 
 |     l_env = 'HW' | 
 |     l_proc = 'P9' | 
 |     l_platform_type = "" | 
 |     l_func_area = "" | 
 |  | 
 |     # System data from XML meta data | 
 |     l_system_info = get_system_details(xml_file_path) | 
 |     l_driver = l_system_info[0] | 
 |     if l_system_info[1]: | 
 |         l_platform_type = l_system_info[1] | 
 |     else: | 
 |         print "System model is not set" | 
 |         sys.exit() | 
 |  | 
 |     # Default header | 
 |     l_header = ['test_start', 'test_end', 'subsys', 'test_type', | 
 |                 'test_result', 'test_name', 'pse_rel', 'driver', | 
 |                 'env', 'proc', 'platform_type', 'test_func_area'] | 
 |  | 
 |     l_csvlist.append(l_header) | 
 |  | 
 |     # Generate CSV file onto the path with current time stamp | 
 |     l_base_dir = csv_dir_path | 
 |     l_timestamp = datetime.utcnow().strftime("%Y-%m-%d-%H-%M-%S") | 
 |     # Example: 2017-02-20-08-47-22_Witherspoon.csv | 
 |     l_csvfile = l_base_dir + l_timestamp + "_" + l_platform_type + ".csv" | 
 |  | 
 |     print "Writing data into csv file:", l_csvfile | 
 |  | 
 |     for testcase in collectDataObj.testData: | 
 |         # Functional Area: Suite Name | 
 |         # Test Name: Test Case Name | 
 |         l_func_area = str(testcase.parent).split(' ', 1)[1] | 
 |         l_test_name = str(testcase) | 
 |  | 
 |         # Test Result pass=0 fail=1 | 
 |         if testcase.status == 'PASS': | 
 |             l_test_result = 0 | 
 |         else: | 
 |             l_test_result = 1 | 
 |  | 
 |         # Format datetime from robot output.xml to "%Y-%m-%d-%H-%M-%S" | 
 |         l_stime = xml_to_csv_time(testcase.starttime) | 
 |         l_etime = xml_to_csv_time(testcase.endtime) | 
 |         # Data Sequence: test_start,test_end,subsys,test_type, | 
 |         #                test_result,test_name,pse_rel,driver, | 
 |         #                env,proc,platform_tyep,test_func_area, | 
 |         l_data = [l_stime, l_etime, l_subsys, l_test_type, l_test_result, | 
 |                   l_test_name, l_pse_rel, l_driver, l_env, l_proc, | 
 |                   l_platform_type, l_func_area] | 
 |         l_csvlist.append(l_data) | 
 |  | 
 |     # Open the file and write to the CSV file | 
 |     l_file = open(l_csvfile, "w") | 
 |     l_writer = csv.writer(l_file, lineterminator='\n') | 
 |     l_writer.writerows(l_csvlist) | 
 |     l_file.close() | 
 |  | 
 |  | 
 | def xml_to_csv_time(xml_datetime): | 
 |     r""" | 
 |     Convert the time from %Y%m%d %H:%M:%S.%f format to %Y-%m-%d-%H-%M-%S format | 
 |     and return it. | 
 |  | 
 |     Description of arguments: | 
 |         datetime  The date in the following format: %Y%m%d %H:%M:%S.%f | 
 |                   (This is the format typically found in an XML file.) | 
 |  | 
 |     The date returned will be in the following format: %Y-%m-%d-%H-%M-%S | 
 |     """ | 
 |     # 20170206 05:05:19.342 | 
 |     l_str = datetime.strptime(xml_datetime, "%Y%m%d %H:%M:%S.%f") | 
 |     # 2017-02-06-05-05-19 | 
 |     l_str = l_str.strftime("%Y-%m-%d-%H-%M-%S") | 
 |     return str(l_str) | 
 |  | 
 |  | 
 | def get_system_details(xml_file_path): | 
 |     r""" | 
 |     Get the system data from output.xml generated by robot and return it. | 
 |     The list returned will be in the following order: [driver,platform] | 
 |  | 
 |     Description of arguments: | 
 |         xml_file_path  The relative or absolute path to the output.xml file. | 
 |     """ | 
 |     bmc_version = "" | 
 |     bmc_platform = "" | 
 |     with open(xml_file_path, 'rt') as output: | 
 |         tree = ElementTree.parse(output) | 
 |  | 
 |     for node in tree.iter('msg'): | 
 |         # /etc/os-release output is logged in the XML as msg | 
 |         # Example: ${output} = VERSION_ID="v1.99.2-71-gbc49f79-dirty" | 
 |         if '${output} = VERSION_ID=' in node.text: | 
 |             # Get BMC version (e.g. v1.99.1-96-g2a46570-dirty) | 
 |             bmc_version = str(node.text.split("VERSION_ID=")[1])[1:-1] | 
 |  | 
 |         # Platform is logged in the XML as msg. | 
 |         # Example: ${bmc_model} = Witherspoon BMC | 
 |         if '${bmc_model} = ' in node.text: | 
 |             bmc_platform = node.text.split(" = ")[1] | 
 |  | 
 |     print "BMC Version:", bmc_version | 
 |     print "BMC Platform:", bmc_platform | 
 |     return [str(bmc_version), str(bmc_platform)] | 
 |  | 
 |  | 
 | def usage(): | 
 |     name = 'gen_csv_results.py' | 
 |     print 'Usage: ' | 
 |     print name, '-s <source path> -d <destination path>' | 
 |     print '\t-s | --source=  : output.xml robot test result file path' | 
 |     print '\t-d | --dest=    : Where the *.csv file will be generated' | 
 |     sys.exit() | 
 |  | 
 |  | 
 | def main(argv): | 
 |  | 
 |     source = '' | 
 |     dest = '' | 
 |     try: | 
 |         opts, args = getopt.getopt(argv, "h:s:d:", ["source=", "dest="]) | 
 |     except getopt.GetoptError: | 
 |         usage() | 
 |  | 
 |     for opt, arg in opts: | 
 |         if opt == '-h': | 
 |             usage() | 
 |         elif opt in ("-s", "--source"): | 
 |             source = arg | 
 |         elif opt in ("-d", "--dest"): | 
 |             dest = arg | 
 |  | 
 |     if source == '': | 
 |         usage() | 
 |         print 'ERROR: Provide input file path to robot generated output.xml ' | 
 |  | 
 |     if dest == '': | 
 |         usage() | 
 |         print 'ERROR: Destination directory where *.csv file will be generated' | 
 |  | 
 |     parse_output_xml(source, dest) | 
 |  | 
 | if __name__ == "__main__": | 
 |     main(sys.argv[1:]) |