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