• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
20from xml.dom import minidom
21from xml.etree import ElementTree
22
23from xdevice import get_cst_time, FilePermission
24from devicetest.core.constants import RunResult
25from devicetest.core.exception import DeviceTestError
26from devicetest.error import ErrorMessage
27from devicetest.log.logger import DeviceTestLog as Log
28
29
30class ReportConstants:
31    time_format = "%Y-%m-%d %H:%M:%S"
32    report_xml = "report.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            root = ElementTree.parse(self.report_path).getroot()
44            return self.report_path, ElementTree.tostring(root).decode()
45        try:
46            Log.info("start generate test report.")
47            test_results = _test_results or test_runner.test_results
48
49            start_time = test_runner.start_time
50
51            testsuites = ElementTree.Element('testsuites')
52
53            test_name = test_runner.configs.get("test_name")
54            if test_name is not None:
55                testsuites.set("name", test_name)
56            else:
57                testsuites.set("name", ReportConstants.report_xml)
58
59            if report_type == "xts":
60                tests_total, tests_error = self.report_xts_type(testsuites, test_results)
61            else:
62                tests_total, tests_error = self.report_normal_type(testsuites, test_results, test_name)
63
64            testsuites.set("tests", str(tests_total))
65            testsuites.set("failures", str(tests_error))
66            testsuites.set("disabled", '')
67            testsuites.set("errors", "")
68            testsuites.set("starttime", self.get_strftime(start_time))
69            testsuites.set("endtime", self.get_now_strftime())
70            testsuites.set("report_version", "1.0")
71
72            os.makedirs(os.path.dirname(self.report_path), exist_ok=True)
73            xml_content = ElementTree.tostring(testsuites).decode()
74            xml_pretty = minidom.parseString(xml_content).toprettyxml(indent="  ")
75
76            result_fd = os.open(self.report_path, os.O_CREAT | os.O_WRONLY | os.O_TRUNC, FilePermission.mode_644)
77            with os.fdopen(result_fd, mode="w", encoding="utf-8") as result_file:
78                result_file.write(xml_pretty)
79            return self.report_path, xml_content
80
81        except Exception as error:
82            err_msg = ErrorMessage.Common.Code_0201003
83            Log.error(err_msg, is_traceback=True)
84            raise DeviceTestError(err_msg) from error
85
86        finally:
87            Log.info("exit generate test report.")
88
89    def get_strftime(self, stamp_time):
90        return stamp_time.strftime(ReportConstants.time_format)
91
92    def get_now_strftime(self):
93        return get_cst_time().strftime(ReportConstants.time_format)
94
95    def report_normal_type(self, testsuites, test_results, test_name):
96        tests_total = 0
97        tests_error = 0
98        for result_info in test_results:
99
100            tests_total += 1
101            case_error = 0
102            case_result = "true"
103            result = result_info.get('result')
104            if result != RunResult.PASSED:
105                tests_error += 1
106                case_error += 1
107                case_result = "false"
108            case_name = result_info.get('case_name')
109            case_start_time = result_info.get('start_time').timestamp()
110            case_end_time = result_info.get('end_time').timestamp()
111            error = result_info.get('error')
112            report = result_info.get("report", "")
113            case_time = case_end_time - case_start_time
114
115            testcase = ElementTree.Element('testcase')
116            testcase.set("name", case_name)
117            testcase.set("status", 'run')
118            testcase.set("classname", case_name)
119            testcase.set("level", "")
120            testcase.set("result", case_result)
121            testcase.set("result_kind", result)
122            testcase.set("message", error)
123            testcase.set("report", report)
124            # 用例测试结果的拓展内容
125            result_content = result_info.get('result_content')
126            if result_content:
127                testcase.set("result_content", f"<![CDATA[{result_content}]]>")
128
129            testsuite = ElementTree.Element('testsuite')
130            testsuite.set("modulename", test_name)
131            testsuite.set("name", case_name)
132            testsuite.set("tests", str(1))
133            testsuite.set("failures", str(case_error))
134            testsuite.set("disabled", '0')
135            testsuite.set("time", "{:.2f}".format(case_time))
136            testsuite.set("result", case_result)
137            testsuite.set("result_kind", result)
138            testsuite.set("report", report)
139
140            testsuite.append(testcase)
141            testsuites.append(testsuite)
142        return tests_total, tests_error
143
144    def report_xts_type(self, testsuites, test_results):
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            testcase = ElementTree.Element('testcase')
168            testcase.set("name", case_name)
169            testcase.set("status", 'run')
170            testcase.set("classname", module_name)
171            testcase.set("level", "")
172            testcase.set("result", case_result)
173            testcase.set("result_kind", result)
174            testcase.set("message", error)
175            testcase.set("report", report)
176
177            testsuite = ElementTree.Element('testsuite')
178            testsuite.set("modulename", module_name)
179            testsuite.set("name", module_name)
180            testsuite.set("tests", str(1))
181            testsuite.set("disabled", '0')
182            testsuite.set("time", "{:.2f}".format(case_time))
183            testsuite.set("report", report)
184            if module_name not in test_suites:
185                test_suites[module_name] = {"test_suite": testsuite, "tests": 0, "failures": 0}
186                testsuites.append(testsuite)
187            test_suites[module_name]["test_suite"].append(testcase)
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"].set("tests", str(tests))
194            test_suites[module_name]["test_suite"].set("failures", str(failures))
195        return tests_total, tests_error
196