• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# coding: utf-8
3
4"""
5Copyright (c) 2023 Huawei Device Co., Ltd.
6Licensed under the Apache License, Version 2.0 (the "License");
7you may not use this file except in compliance with the License.
8You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing, software
13distributed under the License is distributed on an "AS IS" BASIS,
14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15See the License for the specific language governing permissions and
16limitations under the License.
17
18Description: output test results
19"""
20
21import copy
22import logging
23import os
24import time
25
26import pandas
27
28import options
29
30
31incremetal_compile_tests = ["no_change",
32                            "add_oneline",
33                            "add_file",
34                            "delete_file",
35                            "reverse_hap_mode",
36                            "change_module_name"
37                            ]
38
39other_tests = ["binary_consistency",
40               "break_continue_compile",
41               "compile_with_error",
42               "compile_with_exceed_length",
43               "ohos_test"
44               ]
45
46
47class TestResult:
48    def __init__(self):
49        self.passed = []
50        self.failed = []
51        self.time = 0.0
52
53
54def print_result(test_result, test_tasks):
55    logging.info("========================================")
56    logging.info("Test finished. The result is as following:")
57    logging.info("=====> Summary")
58    logging.info("Total test number: %s, took time: %.3f s",
59                 len(test_tasks), test_result.time)
60    logging.info("Passed test number: %s", len(test_result.passed))
61    logging.info("Failed test number: %s", len(test_result.failed))
62
63    logging.info("=====> Detail Information")
64    logging.info("-----")
65    idx = 1
66    for task in test_tasks:
67        logging.info("task index: %d", idx)
68        idx = idx + 1
69        logging.info("task name: %s", task.name)
70        logging.info("task type: %s", task.type)
71        # print full compile result
72        logging.info("--full compilation result:")
73        logging.info("debug: %s, abc_size(byte) %s, time(s) %s, error message: %s",
74                     task.full_compilation_info.debug_info.result,
75                     task.full_compilation_info.debug_info.abc_size,
76                     task.full_compilation_info.debug_info.time,
77                     task.full_compilation_info.debug_info.error_message)
78        logging.info("release: %s, abc_size(byte) %s, time(s) %s, error message: %s",
79                     task.full_compilation_info.release_info.result,
80                     task.full_compilation_info.release_info.abc_size,
81                     task.full_compilation_info.release_info.time,
82                     task.full_compilation_info.debug_info.error_message)
83
84        # print incremental compile result
85        logging.info("--incremental compilation result:")
86        for inc_task in task.incre_compilation_info.values():
87            logging.info("incre test: %s", inc_task.name)
88            logging.info("debug: %s, abc_size(byte) %s, time(s) %s, error message: %s",
89                         inc_task.debug_info.result,
90                         inc_task.debug_info.abc_size,
91                         inc_task.debug_info.time,
92                         inc_task.debug_info.error_message)
93            logging.info("release: %s, abc_size(byte) %s, time(s) %s, error message: %s",
94                         inc_task.release_info.result,
95                         inc_task.release_info.abc_size,
96                         inc_task.release_info.time,
97                         inc_task.release_info.error_message)
98
99        # print other tests result
100        for name, task_info in task.other_tests.items():
101            logging.info("--test name: %s", name)
102            logging.info("result: %s, error message: %s",
103                         task_info.result,
104                         task_info.error_message)
105
106        logging.info("-----")
107        logging.info("========================================")
108
109
110def is_full_compilation_passed(task_info):
111    if not options.arguments.compile_mode in ['all', 'full']:
112        return True
113
114    passed_debug = True
115    passed_release = True
116
117    if options.arguments.hap_mode in ['all', 'release']:
118        passed_release = task_info.release_info.result == options.TaskResult.passed
119    if options.arguments.hap_mode == ['all', 'debug']:
120        passed_debug = task_info.debug_info.result == options.TaskResult.passed
121
122    return passed_debug and passed_release
123
124
125def is_incremental_compilation_passed(task_info):
126    if not options.arguments.compile_mode in ['all', 'incremental']:
127        return True
128
129    if len(task_info) == 0:
130        return False
131
132    passed_debug = True
133    passed_release = True
134    for inc_task in task_info.values():
135        if options.arguments.hap_mode in ['all', 'release']:
136            passed_release = passed_release and inc_task.release_info.result == options.TaskResult.passed
137        if options.arguments.hap_mode == ['all', 'debug']:
138            passed_debug = passed_debug and inc_task.debug_info.result == options.TaskResult.passed
139
140    return passed_debug and passed_release
141
142
143def is_task_passed(task):
144    passed = is_full_compilation_passed(task.full_compilation_info) and \
145        is_incremental_compilation_passed(task.incre_compilation_info)
146
147    for test in task.other_tests.values():
148        passed = passed and (test.result == options.TaskResult.passed)
149
150    return passed
151
152
153def collect_result(test_result, test_tasks, start_time):
154    for task in test_tasks:
155        if not is_task_passed(task):
156            test_result.failed.append(task)
157        else:
158            test_result.passed.append(task)
159
160    end_time = time.time()
161    test_result.time = round(end_time - start_time, 3)
162
163
164def get_result_symbol(result_type):
165    if result_type == options.TaskResult.passed:
166        return '√'
167    elif result_type == options.TaskResult.failed:
168        return '×'
169    else:
170        return '-'
171
172
173def generate_summary_data(test_result, test_tasks):
174    # collect summary data
175    passed_task_name_list = []
176    for task in test_result.passed:
177        passed_task_name_list.append(task.name)
178    failed_task_name_list = []
179    for task in test_result.failed:
180        failed_task_name_list.append(task.name)
181
182    summary_data = {
183        'Total Test Number': len(test_tasks),
184        'Passed Test Number': len(test_result.passed),
185        'Failed Test Number': len(test_result.failed),
186        'Passed Tests': ','.join(passed_task_name_list),
187        'Failed Tests': ','.join(failed_task_name_list),
188        'Test Took Time(s)': test_result.time
189    }
190
191    return summary_data
192
193
194def generate_detail_data(test_tasks):
195    time_size_data = []
196    result_data = []
197
198    idx = 0
199    for task in test_tasks:
200        idx += 1
201        task_time_size_data = {
202            'Task Index': idx,
203            'Task Name': task.name
204        }
205        task_result_data = copy.deepcopy(task_time_size_data)
206        task_result_data['Task Type'] = ','.join(task.type)
207
208        full_compilation_debug = task.full_compilation_info.debug_info
209        full_compilation_release = task.full_compilation_info.release_info
210        task_time_size_data[
211            '[Full Compilation]\n[Debug]\n[Compilation Time(s)]'] = full_compilation_debug.time
212        task_time_size_data[
213            '[Full Compilation]\n[Release]\n[Compilation Time(s)]'] = full_compilation_release.time
214        task_result_data['[Debug]'] = get_result_symbol(
215            full_compilation_debug.result)
216        task_result_data['[Release]'] = get_result_symbol(
217            full_compilation_release.result)
218
219        for test in incremetal_compile_tests:
220            debug_result = options.TaskResult.undefind
221            release_result = options.TaskResult.undefind
222            if test in task.incre_compilation_info.keys():
223                inc_task_info = task.incre_compilation_info[test]
224                debug_result = inc_task_info.debug_info.result
225                release_result = inc_task_info.release_info.result
226            task_result_data[f'[Debug]\n{test}'] = get_result_symbol(
227                debug_result)
228            task_result_data[f'[Release]\n{test}'] = get_result_symbol(
229                release_result)
230
231            if test == 'add_oneline':
232                debug_test_time = 0
233                release_test_time = 0
234                if test in task.incre_compilation_info.keys():
235                    inc_task_info = task.incre_compilation_info[test]
236                    debug_test_time = inc_task_info.debug_info.time
237                    release_test_time = inc_task_info.release_info.time
238
239                task_time_size_data[
240                    '[Incremental Compilation]\n[Debug]\n[Compilation Time(s)]'] = debug_test_time
241                task_time_size_data[
242                    '[Incremental Compilation]\n[Release]\n[Compilation Time(s)]'] = release_test_time
243
244        for test in other_tests:
245            result = options.TaskResult.undefind
246            if test in task.other_tests.keys():
247                task_info = task.other_tests[test]
248                result = task_info.result
249            task_result_data[f'{test}'] = get_result_symbol(result)
250
251        task_time_size_data['[Abc Size(byte)]\n[Debug]'] = full_compilation_debug.abc_size
252        task_time_size_data['[Abc Size(byte)]\n[Release]'] = full_compilation_release.abc_size
253        time_size_data.append(task_time_size_data)
254        result_data.append(task_result_data)
255
256    detail_data = {
257        'result_data': result_data,
258        'time_size_data': time_size_data
259    }
260    return detail_data
261
262
263def generate_data_html(summary_data, detail_data):
264    # summary table
265    key_value_pairs = [
266        f'<tr><td>{key}</td><td>{value}</td></tr>' for key, value in summary_data.items()]
267    summary_table_content = ''.join(key_value_pairs)
268    summary_table = f'<table id=sdk>{summary_table_content}</table>'
269
270    # time and size table
271    time_size_data = detail_data.get('time_size_data')
272    time_size_df = pandas.DataFrame(time_size_data)
273
274    time_size_table_header = '<tr>' + \
275        ''.join(
276            [f'<th rowspan="2">{column}</th>' for column in time_size_df.columns[:2]])
277    time_size_table_header += '<th colspan="2">Full Compilation Time(s)</th>' + \
278        f'<th colspan="2">Incremental Compilation Time(s)</th>' + \
279        f'<th colspan="2">Abc Size(byte)</th></tr>'
280    time_size_table_sub_header = '<tr>' + \
281        f'<th>[Debug]</th><th>[Release]</th>' * 3 + '</tr>'
282
283    time_size_table_content = ''.join([
284        '<tr>' + ''.join([f'<td>{value}</td>' for _,
285                         value in row.items()]) + '</tr>'
286        for _, row in time_size_df.iterrows()
287    ])
288    time_size_table = f'<table id=sdk> \
289        {time_size_table_header}{time_size_table_sub_header}{time_size_table_content}</table>'
290
291    # result table
292    result_data = detail_data.get('result_data')
293    result_df = pandas.DataFrame(result_data)
294
295    result_table_header = '<tr>' + \
296        ''.join(
297            [f'<th rowspan="2">{column}</th>' for column in result_df.columns[:3]])
298    result_table_header += '<th colspan="2">Full Compilation</th>' + \
299        f'<th colspan={len(incremetal_compile_tests) * 2}>Incremental Compilation</th>' + \
300        f'<th colspan={len(other_tests)}>Other Tests</th></tr>'
301
302    result_table_sub_header = '<tr>' + \
303        ''.join(
304            [f'<th>{column}</th>' for column in result_df.columns[3:]]) + '</tr>'
305    result_table_content = ''.join([
306        '<tr>' + ''.join([f'<td>{value}</td>' for _,
307                         value in row.items()]) + '</tr>'
308        for _, row in result_df.iterrows()
309    ])
310    result_table = f'<table id=sdk> \
311        {result_table_header}{result_table_sub_header}{result_table_content}</table>'
312
313    return summary_table, time_size_table, result_table
314
315
316def generate_report_html(summary_data, detail_data):
317    [summary_table, time_size_table, result_table] = generate_data_html(
318        summary_data, detail_data)
319
320    html_content = f'''
321    <html>
322    <head>
323    <style>
324    #sdk body {{
325        font-family: Arial, sans-serif;
326        margin: 20px;
327    }}
328    #sdk h2 {{
329        color: #333;
330    }}
331    #sdk {{
332        border-collapse: collapse;
333        width: 100%;
334        margin-bottom: 20px;
335    }}
336    #sdk th, #sdk td {{
337        padding: 8px;
338        border: 1px solid #ddd;
339    }}
340    #sdk th {{
341        background-color: #f2f2f2;
342        font-weight: bold;
343    }}
344    #sdk tr:nth-child(odd) {{
345        background-color: #f9f9f9;
346    }}
347    </style>
348    </head>
349
350    <body>
351    <h2>SDK Test Results</h2>
352    <h3>Summary</h3>
353    {summary_table}
354    <h3>Detail Information</h3>
355    <h4>Test Result</h4>
356    {result_table}
357    <h4>Compilation Time And Abc Size</h4>
358    {time_size_table}
359    <p>
360    Notes:<br>
361    1. Incremental compilation time refers to add-one line incremental compile.<br>
362    2. For details compile output or error message during compile, please refer to attachment of log file.<br>
363    3. For sdk commit tags, please refer to attachment of manifest file(to be added).
364    </p>
365    </body>
366    </html>
367    '''
368
369    daily_report_file = options.configs.get('output_html_file')
370    with open(daily_report_file, 'w', encoding='utf-8') as report:
371        report.write(html_content)
372
373
374def generate_log_file():
375    logger = logging.getLogger()
376    if not hasattr(logger.handlers[0], 'baseFilename'):
377        return
378    log_file = logger.handlers[0].baseFilename
379    logger.handlers[0].close()
380    output_log_file = options.configs.get('log_file')
381    os.rename(log_file, output_log_file)
382
383
384def generate_result_reports(test_result, test_tasks):
385    summary_data = generate_summary_data(test_result, test_tasks)
386    detail_data = generate_detail_data(test_tasks)
387    generate_report_html(summary_data, detail_data)
388    generate_log_file()
389
390
391def process_test_result(test_tasks, start_time):
392    test_result = TestResult()
393
394    collect_result(test_result, test_tasks, start_time)
395    print_result(test_result, test_tasks)
396    generate_result_reports(test_result, test_tasks)
397