| #!/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,platfrom] |
| |
| 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).strip("-dirty"), str(bmc_platform).strip(" BMC")] |
| |
| |
| 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:]) |