1#!/usr/bin/env python3 2# coding=utf-8 3 4# 5# Copyright (c) 2022 Huawei Device Co., Ltd. 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18 19import os 20import xml.dom.minidom 21from xdevice import get_cst_time 22from devicetest.core.constants import RunResult 23from devicetest.core.error_message import ErrorMessage 24from devicetest.core.exception import DeviceTestError 25from devicetest.log.logger import DeviceTestLog as log 26 27 28class ReportConstants: 29 _STRIP_FORMAT_TIME = "%Y-%m-%d-%H-%M-%S-%f" 30 _STRF_TIME_FORMAT = "%Y-%m-%d %H:%M:%S" 31 _XML_NAME = "report.xml" 32 _FILE_FARMAT = ".xml" 33 34 35class ReportHandler: 36 37 def __init__(self, report_path): 38 self.report_path = report_path 39 self.test_results = [] 40 41 def generate_test_report(self, test_runner, _test_results=None, report_type="normal"): 42 if os.path.exists(self.report_path): 43 dom = xml.dom.minidom.parse(self.report_path) 44 result_node = dom.documentElement 45 return self.report_path, result_node.toxml() 46 try: 47 log.info("start generate test report.") 48 test_results = _test_results or test_runner.test_results 49 50 start_time = test_runner.start_time 51 52 impl = xml.dom.minidom.getDOMImplementation() 53 dom = impl.createDocument(None, 'testsuites', None) 54 result_node = dom.documentElement 55 56 test_name = test_runner.configs.get("test_name") 57 if test_name is not None: 58 result_node.setAttribute("name", test_name) 59 else: 60 result_node.setAttribute("name", ReportConstants._XML_NAME) 61 62 result_node.setAttribute("report_version", "1.0") 63 64 if report_type == "xts": 65 tests_total, tests_error = self.report_xts_type(test_results, dom, result_node) 66 else: 67 tests_total, tests_error = self.report_normal_type(test_results, dom, test_name, result_node) 68 69 result_node.setAttribute("tests", str(tests_total)) 70 result_node.setAttribute("failures", str(tests_error)) 71 result_node.setAttribute("disabled", '') 72 result_node.setAttribute("errors", "") 73 result_node.setAttribute("starttime", 74 self.get_strftime(start_time)) 75 result_node.setAttribute("endtime", self.get_now_strftime()) 76 77 if not os.path.exists(os.path.dirname(self.report_path)): 78 os.makedirs(os.path.dirname(self.report_path)) 79 with open(self.report_path, mode='w', 80 encoding='utf-8') as fre: 81 dom.writexml(fre, addindent='\t', newl='\n', 82 encoding="utf-8") 83 return self.report_path, result_node.toxml() 84 85 except Exception as error: 86 log.error(ErrorMessage.Error_01207.Message.en, 87 error_no=ErrorMessage.Error_01207.Code, 88 is_traceback=True) 89 raise DeviceTestError(ErrorMessage.Error_01207.Topic) from error 90 91 finally: 92 log.info("exit generate test report.") 93 94 def get_strftime(self, stamp_time): 95 return stamp_time.strftime(ReportConstants._STRF_TIME_FORMAT) 96 97 def get_now_strftime(self): 98 return get_cst_time().strftime(ReportConstants._STRF_TIME_FORMAT) 99 100 def report_normal_type(self, test_results, dom, test_name, result_node): 101 tests_total = 0 102 tests_error = 0 103 for result_info in test_results: 104 105 tests_total += 1 106 case_error = 0 107 case_result = "true" 108 result = result_info.get('result') 109 if result != RunResult.PASSED: 110 tests_error += 1 111 case_error += 1 112 case_result = "false" 113 case_name = result_info.get('case_name') 114 case_start_time = result_info.get('start_time').timestamp() 115 case_end_time = result_info.get('end_time').timestamp() 116 error = result_info.get('error') 117 report = result_info.get("report", "") 118 case_time = case_end_time - case_start_time 119 120 test_case = dom.createElement("testcase") 121 test_case.setAttribute("name", case_name) 122 test_case.setAttribute("status", 'run') 123 test_case.setAttribute("classname", case_name) 124 test_case.setAttribute("level", None) 125 test_case.setAttribute("result", case_result) 126 test_case.setAttribute("result_kind", result) 127 test_case.setAttribute("message", error) 128 test_case.setAttribute("report", report) 129 130 test_suite = dom.createElement("testsuite") 131 test_suite.setAttribute("modulename", test_name) 132 test_suite.setAttribute("name", case_name) 133 test_suite.setAttribute("tests", str(1)) 134 test_suite.setAttribute("failures", str(case_error)) 135 test_suite.setAttribute("disabled", '0') 136 test_suite.setAttribute("time", "{:.2f}".format(case_time)) 137 test_suite.setAttribute("result", case_result) 138 test_suite.setAttribute("result_kind", result) 139 test_suite.setAttribute("report", report) 140 test_suite.appendChild(test_case) 141 result_node.appendChild(test_suite) 142 return tests_total, tests_error 143 144 def report_xts_type(self, test_results, dom, result_node): 145 tests_total = 0 146 tests_error = 0 147 test_suites = {} 148 for result_info in test_results: 149 150 tests_total += 1 151 case_error = 0 152 case_result = "true" 153 result = result_info.get('result') 154 if result != RunResult.PASSED: 155 tests_error += 1 156 case_error += 1 157 case_result = "false" 158 case_info = result_info.get('case_name').split("#") 159 case_name = case_info[1] 160 module_name = case_info[0] 161 case_start_time = result_info.get('start_time').timestamp() 162 case_end_time = result_info.get('end_time').timestamp() 163 error = result_info.get('error') 164 report = result_info.get("report", "") 165 case_time = case_end_time - case_start_time 166 167 test_case = dom.createElement("testcase") 168 test_case.setAttribute("name", case_name) 169 test_case.setAttribute("status", 'run') 170 test_case.setAttribute("classname", module_name) 171 test_case.setAttribute("level", None) 172 test_case.setAttribute("result", case_result) 173 test_case.setAttribute("result_kind", result) 174 test_case.setAttribute("message", error) 175 test_case.setAttribute("report", report) 176 177 test_suite = dom.createElement("testsuite") 178 test_suite.setAttribute("modulename", module_name) 179 test_suite.setAttribute("name", module_name) 180 test_suite.setAttribute("tests", str(1)) 181 test_suite.setAttribute("disabled", '0') 182 test_suite.setAttribute("time", "{:.2f}".format(case_time)) 183 test_suite.setAttribute("report", report) 184 if module_name not in test_suites: 185 test_suites[module_name] = {"test_suite": test_suite, "tests": 0, "failures": 0} 186 result_node.appendChild(test_suite) 187 test_suites[module_name]["test_suite"].appendChild(test_case) 188 test_suites[module_name]["tests"] += 1 189 tests = test_suites[module_name]["tests"] 190 if case_result == "false": 191 test_suites[module_name]["failures"] += 1 192 failures = test_suites[module_name]["failures"] 193 test_suites[module_name]["test_suite"].setAttribute("tests", str(tests)) 194 test_suites[module_name]["test_suite"].setAttribute("failures", str(failures)) 195 return tests_total, tests_error 196