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 copy 20import re 21import threading 22import time 23import json 24from enum import Enum 25 26from xdevice import LifeCycle 27from xdevice import IParser 28from xdevice import platform_logger 29from xdevice import Plugin 30from xdevice import check_pub_key_exist 31from xdevice import StateRecorder 32from xdevice import TestDescription 33from xdevice import ResultCode 34from xdevice import CommonParserType 35from xdevice import get_cst_time 36from xdevice import get_delta_time_ms 37 38__all__ = ["CppTestParser", "CppTestListParser", "JunitParser", "JSUnitParser", 39 "OHKernelTestParser", "OHJSUnitTestParser", 40 "OHJSUnitTestListParser", "_ACE_LOG_MARKER", "OHRustTestParser"] 41 42_INFORMATIONAL_MARKER = "[----------]" 43_START_TEST_RUN_MARKER = "[==========] Running" 44_TEST_RUN_MARKER = "[==========]" 45_GTEST_DRYRUN_MARKER = "Running main() " 46_START_TEST_MARKER = "[ RUN ]" 47_OK_TEST_MARKER = "[ OK ]" 48_SKIPPED_TEST_MARKER = "[ SKIPPED ]" 49_FAILED_TEST_MARKER = "[ FAILED ]" 50_ALT_OK_MARKER = "[ OK ]" 51_TIMEOUT_MARKER = "[ TIMEOUT ]" 52 53_START_JSUNIT_RUN_MARKER = "[start] start run suites" 54_START_JSUNIT_SUITE_RUN_MARKER = "[suite start]" 55_START_JSUNIT_SUITE_END_MARKER = "[suite end]" 56_END_JSUNIT_RUN_MARKER = "[end] run suites end" 57_PASS_JSUNIT_MARKER = "[pass]" 58_FAIL_JSUNIT_MARKER = "[fail]" 59_ERROR_JSUNIT_MARKER = "[error]" 60_ACE_LOG_MARKER = [" a0c0d0", " a03d00"] 61 62""" 63OpenHarmony Kernel Test 64""" 65RUNTEST_TEST = "runtest test" 66START_TO_TEST = "Start to test" 67FINISHED_TO_TEST = "Finished to test" 68TIMEOUT_TESTCASES = "Timeout testcases" 69FAIL_DOT = "FAIL." 70PASS_DOT = "PASS." 71ERROR_EXCLAMATION = "ERROR!!!" 72TIMEOUT_EXCLAMATION = "TIMEOUT!" 73 74 75LOG = platform_logger("Parser") 76 77 78@Plugin(type=Plugin.PARSER, id=CommonParserType.cpptest) 79class CppTestParser(IParser): 80 def __init__(self): 81 self.state_machine = StateRecorder() 82 self.suite_name = "" 83 self.listeners = [] 84 self.product_info = {} 85 self.is_params = False 86 self.start_time = get_cst_time() 87 self.suite_start_time = get_cst_time() 88 89 def get_suite_name(self): 90 return self.suite_name 91 92 def get_listeners(self): 93 return self.listeners 94 95 def __process__(self, lines): 96 if not self.state_machine.suites_is_started(): 97 self.state_machine.trace_logs.extend(lines) 98 for line in lines: 99 line = str(line).strip().rstrip("\r") 100 LOG.debug(line) 101 self.parse(line) 102 103 def __done__(self): 104 suite_result = self.state_machine.get_suites() 105 if not suite_result.suites_name: 106 return 107 for listener in self.get_listeners(): 108 suites = copy.copy(suite_result) 109 listener.__ended__(LifeCycle.TestSuites, test_result=suites, 110 suites_name=suites.suites_name, 111 product_info=suites.product_info) 112 self.state_machine.current_suites = None 113 114 def parse(self, line): 115 if self.state_machine.suites_is_started() or line.startswith( 116 _TEST_RUN_MARKER): 117 if line.startswith(_START_TEST_RUN_MARKER): 118 message = line[len(_TEST_RUN_MARKER):].strip() 119 self.handle_suites_started_tag(message) 120 elif line.startswith(_INFORMATIONAL_MARKER): 121 pattern = r"(.*) (\(\d+ ms total\))" 122 message = line[len(_INFORMATIONAL_MARKER):].strip() 123 if re.match(pattern, line.strip()): 124 self.handle_suite_ended_tag(message) 125 elif re.match(r'(\d+) test[s]? from (.*)', message): 126 self.handle_suite_started_tag(message) 127 elif line.startswith(_TEST_RUN_MARKER): 128 if not self.state_machine.suites_is_running(): 129 return 130 message = line[len(_TEST_RUN_MARKER):].strip() 131 self.handle_suites_ended_tag(message) 132 elif line.startswith(_START_TEST_MARKER): 133 # Individual test started 134 message = line[len(_START_TEST_MARKER):].strip() 135 self.handle_test_started_tag(message) 136 else: 137 self.process_test(line) 138 139 def process_test(self, line): 140 if _SKIPPED_TEST_MARKER in line: 141 message = line[line.index(_SKIPPED_TEST_MARKER) + len( 142 _SKIPPED_TEST_MARKER):].strip() 143 if not self.state_machine.test_is_running(): 144 LOG.error( 145 "Found {} without {} before, wrong GTest log format". 146 format(line, _START_TEST_MARKER)) 147 return 148 self.handle_test_ended_tag(message, ResultCode.SKIPPED) 149 elif _OK_TEST_MARKER in line: 150 message = line[line.index(_OK_TEST_MARKER) + len( 151 _OK_TEST_MARKER):].strip() 152 if not self.state_machine.test_is_running(): 153 LOG.error( 154 "Found {} without {} before, wrong GTest log format". 155 format(line, _START_TEST_MARKER)) 156 return 157 self.handle_test_ended_tag(message, ResultCode.PASSED) 158 elif _ALT_OK_MARKER in line: 159 message = line[line.index(_ALT_OK_MARKER) + len( 160 _ALT_OK_MARKER):].strip() 161 self.fake_run_marker(message) 162 self.handle_test_ended_tag(message, ResultCode.PASSED) 163 elif _FAILED_TEST_MARKER in line: 164 message = line[line.index(_FAILED_TEST_MARKER) + len( 165 _FAILED_TEST_MARKER):].strip() 166 if not self.state_machine.suite_is_running(): 167 return 168 if not self.state_machine.test_is_running(): 169 self.fake_run_marker(message) 170 self.handle_test_ended_tag(message, ResultCode.FAILED) 171 elif _TIMEOUT_MARKER in line: 172 message = line[line.index(_TIMEOUT_MARKER) + len( 173 _TIMEOUT_MARKER):].strip() 174 self.fake_run_marker(message) 175 self.handle_test_ended_tag(message, ResultCode.FAILED) 176 elif self.state_machine.test_is_running(): 177 self.append_test_output(line) 178 179 def handle_test_suite_failed(self, error_msg): 180 error_msg = "Unknown error" if error_msg is None else error_msg 181 LOG.info("Test run failed: {}".format(error_msg)) 182 if self.state_machine.test_is_running(): 183 self.state_machine.test().is_completed = True 184 for listener in self.get_listeners(): 185 test_result = copy.copy(self.currentTestResult) 186 listener.__failed__(LifeCycle.TestCase, test_result) 187 listener.__ended__(LifeCycle.TestCase, test_result) 188 self.state_machine.suite().stacktrace = error_msg 189 self.state_machine.suite().is_completed = True 190 for listener in self.get_listeners(): 191 suite_result = copy.copy(self.currentSuiteResult) 192 listener.__failed__(LifeCycle.TestSuite, suite_result) 193 listener.__ended__(LifeCycle.TestSuite, suite_result) 194 195 def handle_test_started_tag(self, message): 196 test_class, test_name, _ = self.parse_test_description( 197 message) 198 test_result = self.state_machine.test(reset=True) 199 test_result.test_class = test_class 200 test_result.test_name = test_name 201 self.start_time = get_cst_time() 202 for listener in self.get_listeners(): 203 test_result = copy.copy(test_result) 204 listener.__started__(LifeCycle.TestCase, test_result) 205 206 @classmethod 207 def parse_test_description(cls, message): 208 run_time = 0 209 matcher = re.match(r'(.*) \((\d+) ms\)', message) 210 if matcher: 211 test_class, test_name = matcher.group(1).rsplit(".", 1) 212 run_time = int(matcher.group(2)) 213 else: 214 test_class, test_name = message.rsplit(".", 1) 215 return test_class, test_name, run_time 216 217 def handle_test_ended_tag(self, message, test_status): 218 test_class, test_name, run_time = self.parse_test_description( 219 message) 220 test_result = self.state_machine.test() 221 test_result.run_time = get_delta_time_ms(self.start_time) 222 if test_result.run_time == 0 or test_result.run_time < run_time: 223 test_result.run_time = run_time 224 test_result.code = test_status.value 225 test_result.current = self.state_machine.running_test_index + 1 226 if not test_result.is_running(): 227 LOG.error( 228 "Test has no start tag when trying to end test: %s", message) 229 return 230 found_unexpected_test = False 231 if test_result.test_class != test_class: 232 LOG.error( 233 "Expected class: {} but got:{} ".format(test_result.test_class, 234 test_class)) 235 found_unexpected_test = True 236 if test_result.test_name != test_name: 237 LOG.error( 238 "Expected test: {} but got: {}".format(test_result.test_name, 239 test_name)) 240 found_unexpected_test = True 241 242 if found_unexpected_test or ResultCode.FAILED == test_status: 243 for listener in self.get_listeners(): 244 result = copy.copy(test_result) 245 listener.__failed__(LifeCycle.TestCase, result) 246 elif ResultCode.SKIPPED == test_status: 247 for listener in self.get_listeners(): 248 result = copy.copy(test_result) 249 listener.__skipped__(LifeCycle.TestCase, result) 250 251 self.state_machine.test().is_completed = True 252 for listener in self.get_listeners(): 253 result = copy.copy(test_result) 254 listener.__ended__(LifeCycle.TestCase, result) 255 self.state_machine.running_test_index += 1 256 257 def fake_run_marker(self, message): 258 fake_marker = re.compile(" +").split(message) 259 self.handle_test_started_tag(fake_marker) 260 261 def handle_suites_started_tag(self, message): 262 self.state_machine.get_suites(reset=True) 263 matcher = re.match(r'Running (\d+) test[s]? from .*', message) 264 expected_test_num = int(matcher.group(1)) if matcher else -1 265 if expected_test_num >= 0: 266 test_suites = self.state_machine.get_suites() 267 test_suites.suites_name = self.get_suite_name() 268 test_suites.test_num = expected_test_num 269 test_suites.product_info = self.product_info 270 for listener in self.get_listeners(): 271 suite_report = copy.copy(test_suites) 272 listener.__started__(LifeCycle.TestSuites, suite_report) 273 274 def handle_suite_started_tag(self, message): 275 self.state_machine.suite(reset=True) 276 matcher = re.match(r'(\d+) test[s]? from (.*)', message) 277 expected_test_num = int(matcher.group(1)) if matcher else -1 278 if expected_test_num >= 0: 279 test_suite = self.state_machine.suite() 280 test_suite.suite_name = matcher.group(2) 281 test_suite.test_num = expected_test_num 282 self.suite_start_time = get_cst_time() 283 for listener in self.get_listeners(): 284 suite_report = copy.copy(test_suite) 285 listener.__started__(LifeCycle.TestSuite, suite_report) 286 287 def handle_suite_ended_tag(self, message): 288 self.state_machine.running_test_index = 0 289 suite_result = self.state_machine.suite() 290 suite_result.run_time = get_delta_time_ms(self.suite_start_time) 291 matcher = re.match(r'.*\((\d+) ms total\)', message) 292 if matcher and suite_result.run_time == 0: 293 suite_result.run_time = int(matcher.group(1)) 294 suite_result.is_completed = True 295 for listener in self.get_listeners(): 296 suite = copy.copy(suite_result) 297 listener.__ended__(LifeCycle.TestSuite, suite, is_clear=True) 298 299 def handle_suites_ended_tag(self, message): 300 suites = self.state_machine.get_suites() 301 matcher = re.match(r'.*\((\d+) ms total\)', message) 302 if matcher: 303 suites.run_time = int(matcher.group(1)) 304 suites.is_completed = True 305 for listener in self.get_listeners(): 306 copy_suites = copy.copy(suites) 307 listener.__ended__(LifeCycle.TestSuites, test_result=copy_suites, 308 suites_name=suites.suites_name, 309 product_info=suites.product_info, 310 suite_report=True) 311 312 def append_test_output(self, message): 313 if self.state_machine.test().stacktrace: 314 self.state_machine.test().stacktrace += "\r\n" 315 self.state_machine.test().stacktrace += message 316 317 @staticmethod 318 def handle_test_run_failed(error_msg): 319 if not error_msg: 320 error_msg = "Unknown error" 321 if not check_pub_key_exist(): 322 LOG.debug("Error msg:%s" % error_msg) 323 324 def mark_test_as_blocked(self, test): 325 if not self.state_machine.current_suite and not test.class_name: 326 return 327 suites_result = self.state_machine.get_suites(reset=True) 328 suites_result.suites_name = self.get_suite_name() 329 suite_name = self.state_machine.current_suite.suite_name if \ 330 self.state_machine.current_suite else None 331 suite_result = self.state_machine.suite(reset=True) 332 test_result = self.state_machine.test(reset=True) 333 suite_result.suite_name = suite_name or test.class_name 334 suite_result.suite_num = 1 335 test_result.test_class = test.class_name 336 test_result.test_name = test.test_name 337 test_result.stacktrace = "error_msg: run crashed" 338 test_result.num_tests = 1 339 test_result.run_time = 0 340 test_result.code = ResultCode.BLOCKED.value 341 for listener in self.get_listeners(): 342 suite_report = copy.copy(suites_result) 343 listener.__started__(LifeCycle.TestSuites, suite_report) 344 for listener in self.get_listeners(): 345 suite_report = copy.copy(suite_result) 346 listener.__started__(LifeCycle.TestSuite, suite_report) 347 for listener in self.get_listeners(): 348 test_result = copy.copy(test_result) 349 listener.__started__(LifeCycle.TestCase, test_result) 350 for listener in self.get_listeners(): 351 test_result = copy.copy(test_result) 352 listener.__ended__(LifeCycle.TestCase, test_result) 353 for listener in self.get_listeners(): 354 suite_report = copy.copy(suite_result) 355 listener.__ended__(LifeCycle.TestSuite, suite_report, 356 is_clear=True) 357 self.__done__() 358 359 360@Plugin(type=Plugin.PARSER, id=CommonParserType.cpptest_list) 361class CppTestListParser(IParser): 362 def __init__(self): 363 self.last_test_class_name = None 364 self.tests = [] 365 self.result_data = "" 366 self.suites = dict() 367 368 def __process__(self, lines): 369 for line in lines: 370 if line.endswith("\r") or line.endswith("\n"): 371 line = str(line).replace("\r", "").replace("\n", "") 372 line = line.rstrip() 373 line = str(line).strip().rstrip("\r") 374 self.result_data = "{}{}\n".format(self.result_data, line) 375 self.parse(line) 376 377 def __done__(self): 378 LOG.debug("CppTestListParser data:") 379 LOG.debug(self.result_data) 380 self.result_data = "" 381 382 def parse(self, line): 383 class_matcher = re.match('^([a-zA-Z]+.*)\\.$', line) 384 method_matcher = re.match('\\s+([a-zA-Z_]+[\\S]*)(.*)?(\\s+.*)?$', 385 line) 386 if class_matcher: 387 self.last_test_class_name = class_matcher.group(1) 388 if self.last_test_class_name not in self.suites: 389 self.suites.setdefault(self.last_test_class_name, []) 390 elif method_matcher: 391 if not self.last_test_class_name: 392 LOG.error("Parsed new test case name %s but no test class name" 393 " has been set" % line) 394 else: 395 test_name = method_matcher.group(1) 396 if test_name not in self.suites.get(self.last_test_class_name, []): 397 test = TestDescription(self.last_test_class_name, 398 test_name) 399 self.tests.append(test) 400 self.suites.get(self.last_test_class_name, []).append(test_name) 401 else: 402 LOG.debug("[{}.{}] has already collect it, skip it.".format( 403 self.last_test_class_name, test_name)) 404 else: 405 if not check_pub_key_exist(): 406 LOG.debug("Line ignored: %s" % line) 407 408 409class StatusCodes(Enum): 410 FAILURE = -2 411 START = 1 412 ERROR = -1 413 SUCCESS = 0 414 IN_PROGRESS = 2 415 IGNORE = -3 416 BLOCKED = 3 417 418 419class Prefixes(Enum): 420 STATUS = "INSTRUMENTATION_STATUS: " 421 STATUS_CODE = "INSTRUMENTATION_STATUS_CODE: " 422 STATUS_FAILED = "INSTRUMENTATION_FAILED: " 423 CODE = "INSTRUMENTATION_CODE: " 424 RESULT = "INSTRUMENTATION_RESULT: " 425 TIME_REPORT = "Time: " 426 427 428@Plugin(type=Plugin.PARSER, id=CommonParserType.junit) 429class JunitParser(IParser): 430 def __init__(self): 431 self.state_machine = StateRecorder() 432 self.suite_name = "" 433 self.listeners = [] 434 self.current_key = None 435 self.current_value = None 436 self.start_time = get_cst_time() 437 self.test_time = 0 438 self.test_run_finished = False 439 440 def get_suite_name(self): 441 return self.suite_name 442 443 def get_listeners(self): 444 return self.listeners 445 446 def __process__(self, lines): 447 for line in lines: 448 if not check_pub_key_exist(): 449 LOG.debug(line) 450 self.parse(line) 451 452 def __done__(self): 453 suite_result = self.state_machine.suite() 454 suite_result.run_time = self.test_time 455 suite_result.is_completed = True 456 for listener in self.get_listeners(): 457 suite = copy.copy(suite_result) 458 listener.__ended__(LifeCycle.TestSuite, suite, 459 suite_report=True) 460 self.state_machine.current_suite = None 461 462 def parse(self, line): 463 if line.startswith(Prefixes.STATUS_CODE.value): 464 self.submit_current_key_value() 465 self.parse_status_code(line) 466 elif line.startswith(Prefixes.STATUS.value): 467 self.submit_current_key_value() 468 self.parse_key(line, len(Prefixes.STATUS.value)) 469 elif line.startswith(Prefixes.RESULT.value): 470 self.test_run_finished = True 471 elif line.startswith(Prefixes.STATUS_FAILED.value) or \ 472 line.startswith(Prefixes.CODE.value): 473 self.submit_current_key_value() 474 self.test_run_finished = True 475 elif line.startswith(Prefixes.TIME_REPORT.value): 476 self.parse_time(line) 477 else: 478 if self.current_key == "stack" and self.current_value: 479 self.current_value = self.current_value + r"\r\n" 480 self.current_value = self.current_value + line 481 elif line: 482 pass 483 484 def parse_key(self, line, key_start_pos): 485 key_value = line[key_start_pos:].split("=", 1) 486 if len(key_value) == 2: 487 self.current_key = key_value[0] 488 self.current_value = key_value[1] 489 490 def parse_time(self, line): 491 message = line[len(Prefixes.TIME_REPORT.value):] 492 self.test_time = float(message.replace(",", "")) * 1000 493 494 @staticmethod 495 def check_legality(name): 496 if not name or name == "null": 497 return False 498 return True 499 500 def parse_status_code(self, line): 501 value = line[len(Prefixes.STATUS_CODE.value):] 502 test_info = self.state_machine.test() 503 test_info.code = int(value) 504 if test_info.code != StatusCodes.IN_PROGRESS: 505 if self.check_legality(test_info.test_class) and \ 506 self.check_legality(test_info.test_name): 507 self.report_result(test_info) 508 self.clear_current_test_info() 509 510 def clear_current_test_info(self): 511 self.state_machine.current_test = None 512 513 def submit_current_key_value(self): 514 if self.current_key and self.current_value: 515 status_value = self.current_value 516 test_info = self.state_machine.test() 517 if self.current_key == "class": 518 test_info.test_class = status_value 519 elif self.current_key == "test": 520 test_info.test_name = status_value 521 elif self.current_key == "numtests": 522 test_info.num_tests = int(status_value) 523 elif self.current_key == "Error": 524 self.handle_test_run_failed(status_value) 525 elif self.current_key == "stack": 526 test_info.stacktrace = status_value 527 elif self.current_key == "stream": 528 pass 529 self.current_key = None 530 self.current_value = None 531 532 def report_result(self, test_info): 533 if not test_info.test_name or not test_info.test_class: 534 LOG.info("Invalid instrumentation status bundle") 535 return 536 test_info.is_completed = True 537 self.report_test_run_started(test_info) 538 if test_info.code == StatusCodes.START.value: 539 self.start_time = get_cst_time() 540 for listener in self.get_listeners(): 541 result = copy.copy(test_info) 542 listener.__started__(LifeCycle.TestCase, result) 543 elif test_info.code == StatusCodes.FAILURE.value: 544 self.state_machine.running_test_index += 1 545 test_info.current = self.state_machine.running_test_index 546 end_time = get_cst_time() 547 run_time = (end_time - self.start_time).total_seconds() 548 test_info.run_time = int(run_time * 1000) 549 for listener in self.get_listeners(): 550 result = copy.copy(test_info) 551 result.code = ResultCode.FAILED.value 552 listener.__ended__(LifeCycle.TestCase, result) 553 elif test_info.code == StatusCodes.ERROR.value: 554 self.state_machine.running_test_index += 1 555 test_info.current = self.state_machine.running_test_index 556 end_time = get_cst_time() 557 run_time = (end_time - self.start_time).total_seconds() 558 test_info.run_time = int(run_time * 1000) 559 for listener in self.get_listeners(): 560 result = copy.copy(test_info) 561 result.code = ResultCode.FAILED.value 562 listener.__ended__(LifeCycle.TestCase, result) 563 elif test_info.code == StatusCodes.SUCCESS.value: 564 self.state_machine.running_test_index += 1 565 test_info.current = self.state_machine.running_test_index 566 end_time = get_cst_time() 567 run_time = (end_time - self.start_time).total_seconds() 568 test_info.run_time = int(run_time * 1000) 569 for listener in self.get_listeners(): 570 result = copy.copy(test_info) 571 result.code = ResultCode.PASSED.value 572 listener.__ended__(LifeCycle.TestCase, result) 573 elif test_info.code == StatusCodes.IGNORE.value: 574 end_time = get_cst_time() 575 run_time = (end_time - self.start_time).total_seconds() 576 test_info.run_time = int(run_time * 1000) 577 for listener in self.get_listeners(): 578 result = copy.copy(test_info) 579 result.code = ResultCode.SKIPPED.value 580 listener.__skipped__(LifeCycle.TestCase, result) 581 elif test_info.code == StatusCodes.BLOCKED.value: 582 test_info.current = self.state_machine.running_test_index 583 end_time = get_cst_time() 584 run_time = (end_time - self.start_time).total_seconds() 585 test_info.run_time = int(run_time * 1000) 586 for listener in self.get_listeners(): 587 result = copy.copy(test_info) 588 result.code = ResultCode.BLOCKED.value 589 listener.__ended__(LifeCycle.TestCase, result) 590 591 self.output_stack_trace(test_info) 592 593 @classmethod 594 def output_stack_trace(cls, test_info): 595 if check_pub_key_exist(): 596 return 597 if test_info.stacktrace: 598 stack_lines = test_info.stacktrace.split(r"\r\n") 599 LOG.error("Stacktrace information is:") 600 for line in stack_lines: 601 line.strip() 602 if line: 603 LOG.error(line) 604 605 def report_test_run_started(self, test_result): 606 test_suite = self.state_machine.suite() 607 if not self.state_machine.suite().is_started: 608 if not test_suite.test_num or not test_suite.suite_name: 609 test_suite.suite_name = self.get_suite_name() 610 test_suite.test_num = test_result.num_tests 611 for listener in self.get_listeners(): 612 suite_report = copy.copy(test_suite) 613 listener.__started__(LifeCycle.TestSuite, suite_report) 614 615 @staticmethod 616 def handle_test_run_failed(error_msg): 617 if not error_msg: 618 error_msg = "Unknown error" 619 if not check_pub_key_exist(): 620 LOG.debug("Error msg:%s" % error_msg) 621 622 def mark_test_as_failed(self, test): 623 test_info = self.state_machine.test() 624 if test_info: 625 test_info.test_class = test.class_name 626 test_info.test_name = test.test_name 627 test_info.code = StatusCodes.START.value 628 self.report_result(test_info) 629 test_info.code = StatusCodes.FAILURE.value 630 self.report_result(test_info) 631 self.__done__() 632 633 def mark_test_as_blocked(self, test): 634 test_info = self.state_machine.test() 635 if test_info: 636 test_info.test_class = test.class_name 637 test_info.test_name = test.test_name 638 test_info.num_tests = 1 639 test_info.run_time = 0 640 test_info.code = StatusCodes.START.value 641 self.report_result(test_info) 642 test_info.code = StatusCodes.BLOCKED.value 643 self.report_result(test_info) 644 self.__done__() 645 646 647@Plugin(type=Plugin.PARSER, id=CommonParserType.jsunit) 648class JSUnitParser(IParser): 649 last_line = "" 650 pattern = r"(\d{1,2}-\d{1,2}\s\d{1,2}:\d{1,2}:\d{1,2}\.\d{3}) " 651 652 def __init__(self): 653 self.state_machine = StateRecorder() 654 self.suites_name = "" 655 self.listeners = [] 656 self.expect_tests_dict = dict() 657 self.marked_suite_set = set() 658 self.exclude_list = list() 659 self.ace_log_marker = "" 660 661 def get_listeners(self): 662 return self.listeners 663 664 def __process__(self, lines): 665 if not self.state_machine.suites_is_started(): 666 self.state_machine.trace_logs.extend(lines) 667 for line in lines: 668 self.parse(line) 669 670 def __done__(self): 671 pass 672 673 def parse(self, line): 674 if (self.state_machine.suites_is_started() or line.find( 675 _START_JSUNIT_RUN_MARKER) != -1) and \ 676 self._is_match_marker(line): 677 if line.find(_START_JSUNIT_RUN_MARKER) != -1: 678 self.handle_suites_started_tag() 679 elif line.endswith(_END_JSUNIT_RUN_MARKER): 680 self.handle_suites_ended_tag() 681 elif line.find(_START_JSUNIT_SUITE_RUN_MARKER) != -1: 682 self.handle_suite_started_tag(line.strip()) 683 elif line.endswith(_START_JSUNIT_SUITE_END_MARKER): 684 self.handle_suite_ended_tag() 685 elif _PASS_JSUNIT_MARKER in line or _FAIL_JSUNIT_MARKER \ 686 in line or _ERROR_JSUNIT_MARKER in line: 687 self.handle_one_test_tag(line.strip()) 688 self.last_line = line 689 690 def parse_test_description(self, message): 691 pattern = r".*\[(pass|fail|error)\]" 692 year = time.strftime("%Y") 693 filter_message = message 694 end_time = "%s-%s" % \ 695 (year, re.match(self.pattern, message).group().strip()) 696 start_time = "%s-%s" % \ 697 (year, re.match(self.pattern, 698 self.last_line.strip()).group().strip()) 699 start_timestamp = int(time.mktime( 700 time.strptime(start_time, "%Y-%m-%d %H:%M:%S.%f"))) * 1000 + int( 701 start_time.split(".")[-1]) 702 end_timestamp = int(time.mktime( 703 time.strptime(end_time, "%Y-%m-%d %H:%M:%S.%f"))) * 1000 + int( 704 end_time.split(".")[-1]) 705 run_time = end_timestamp - start_timestamp 706 match = re.match(pattern, filter_message) 707 _, status_end_index = match.span() 708 if " ;" in filter_message: 709 test_name = filter_message[status_end_index: 710 str(filter_message).find(" ;")] 711 else: 712 test_name = filter_message[status_end_index:] 713 status_dict = {"pass": ResultCode.PASSED, "fail": ResultCode.FAILED, 714 "ignore": ResultCode.SKIPPED, 715 "error": ResultCode.FAILED} 716 status = status_dict.get(match.group(1)) 717 return test_name.strip(), status, run_time 718 719 def handle_suites_started_tag(self): 720 self.state_machine.get_suites(reset=True) 721 test_suites = self.state_machine.get_suites() 722 test_suites.suites_name = self.suites_name 723 test_suites.test_num = 0 724 for listener in self.get_listeners(): 725 suite_report = copy.copy(test_suites) 726 listener.__started__(LifeCycle.TestSuites, suite_report) 727 728 def handle_suites_ended_tag(self): 729 self._mark_all_test_case() 730 suites = self.state_machine.get_suites() 731 suites.is_completed = True 732 733 for listener in self.get_listeners(): 734 listener.__ended__(LifeCycle.TestSuites, test_result=suites, 735 suites_name=suites.suites_name) 736 737 def handle_one_test_tag(self, message): 738 test_name, status, run_time = \ 739 self.parse_test_description(message) 740 test_suite = self.state_machine.suite() 741 if self.exclude_list: 742 qualified_name = "{}#{}".format(test_suite.suite_name, test_name) 743 if qualified_name in self.exclude_list: 744 LOG.debug("{} will be discard!".format(qualified_name)) 745 test_suite.test_num -= 1 746 return 747 test_result = self.state_machine.test(reset=True) 748 test_result.test_class = test_suite.suite_name 749 test_result.test_name = test_name 750 test_result.run_time = run_time 751 test_result.code = status.value 752 test_result.current = self.state_machine.running_test_index + 1 753 self.state_machine.suite().run_time += run_time 754 for listener in self.get_listeners(): 755 test_result = copy.copy(test_result) 756 listener.__started__(LifeCycle.TestCase, test_result) 757 758 test_suites = self.state_machine.get_suites() 759 found_unexpected_test = False 760 761 if found_unexpected_test or ResultCode.FAILED == status: 762 for listener in self.get_listeners(): 763 result = copy.copy(test_result) 764 listener.__failed__(LifeCycle.TestCase, result) 765 elif ResultCode.SKIPPED == status: 766 for listener in self.get_listeners(): 767 result = copy.copy(test_result) 768 listener.__skipped__(LifeCycle.TestCase, result) 769 770 self.state_machine.test().is_completed = True 771 if not hasattr(test_suite, "total_cases"): 772 test_suite.test_num += 1 773 test_suites.test_num += 1 774 for listener in self.get_listeners(): 775 result = copy.copy(test_result) 776 listener.__ended__(LifeCycle.TestCase, result) 777 self.state_machine.running_test_index += 1 778 779 def fake_run_marker(self, message): 780 fake_marker = re.compile(" +").split(message) 781 self.processTestStartedTag(fake_marker) 782 783 def handle_suite_started_tag(self, message): 784 self.state_machine.suite(reset=True) 785 self.state_machine.running_test_index = 0 786 test_suite = self.state_machine.suite() 787 if "total cases:" in message: 788 m_result = re.match(r".*\[suite start](.+), total cases: (\d+)", 789 message) 790 if m_result: 791 expect_test_num = m_result.group(2) 792 test_suite.suite_name = m_result.group(1) 793 test_suite.test_num = int(expect_test_num) 794 setattr(test_suite, "total_cases", True) 795 796 else: 797 if re.match(r".*\[suite start].*", message): 798 _, index = re.match(r".*\[suite start]", message).span() 799 if message[index:]: 800 test_suite.suite_name = message[index:] 801 else: 802 test_suite.suite_name = self.suite_name 803 test_suite.test_num = 0 804 for listener in self.get_listeners(): 805 suite_report = copy.copy(test_suite) 806 listener.__started__(LifeCycle.TestSuite, suite_report) 807 808 def handle_suite_ended_tag(self): 809 suite_result = self.state_machine.suite() 810 suites = self.state_machine.get_suites() 811 suite_result.run_time = suite_result.run_time 812 suites.run_time += suite_result.run_time 813 suite_result.is_completed = True 814 self._mark_test_case(suite_result, self.get_listeners()) 815 for listener in self.get_listeners(): 816 suite = copy.copy(suite_result) 817 listener.__ended__(LifeCycle.TestSuite, suite, is_clear=True) 818 819 def append_test_output(self, message): 820 if self.state_machine.test().stacktrace: 821 self.state_machine.test().stacktrace = \ 822 "%s\r\n" % self.state_machine.test().stacktrace 823 self.state_machine.test().stacktrace = \ 824 ''.join((self.state_machine.test().stacktrace, message)) 825 826 def _mark_test_case(self, suite, listeners): 827 if not self.expect_tests_dict: 828 return 829 tests_list = [] 830 for listener in listeners: 831 if listener.__class__.__name__ == "ReportListener": 832 tests_list.extend(listener.tests.values()) 833 break 834 test_name_list = [] 835 for item_test in tests_list: 836 test_name_list.append(item_test.test_name) 837 self.marked_suite_set.add(suite.suite_name) 838 test_in_cur = self.expect_tests_dict.get(suite.suite_name, []) 839 for test in test_in_cur: 840 if "{}#{}".format(suite.suite_name, test.test_name) \ 841 in self.exclude_list: 842 suite.test_num -= 1 843 continue 844 if test.test_name not in test_name_list: 845 self._mock_test_case_life_cycle(listeners, test) 846 847 def _mock_test_case_life_cycle(self, listeners, test): 848 test_result = self.state_machine.test(reset=True) 849 test_result.test_class = test.class_name 850 test_result.test_name = test.test_name 851 test_result.stacktrace = "error_msg: mark blocked" 852 test_result.num_tests = 1 853 test_result.run_time = 0 854 test_result.current = self.state_machine.running_test_index + 1 855 test_result.code = ResultCode.BLOCKED.value 856 test_result = copy.copy(test_result) 857 for listener in listeners: 858 listener.__started__(LifeCycle.TestCase, test_result) 859 test_result = copy.copy(test_result) 860 for listener in listeners: 861 listener.__ended__(LifeCycle.TestCase, test_result) 862 self.state_machine.running_test_index += 1 863 864 def _mark_all_test_case(self): 865 if not self.expect_tests_dict: 866 return 867 all_suite_set = set(self.expect_tests_dict.keys()) 868 un_suite_set = all_suite_set.difference(self.marked_suite_set) 869 for un_suite_name in un_suite_set: 870 test_list = self.expect_tests_dict.get(un_suite_name, []) 871 872 self.state_machine.suite(reset=True) 873 self.state_machine.running_test_index = 0 874 test_suite = self.state_machine.suite() 875 test_suite.suite_name = un_suite_name 876 test_suite.test_num = len(test_list) 877 for listener in self.get_listeners(): 878 suite_report = copy.copy(test_suite) 879 listener.__started__(LifeCycle.TestSuite, suite_report) 880 881 for test in test_list: 882 if "{}#{}".format(test_suite.suite_name, test.test_name) \ 883 in self.exclude_list: 884 test_suite.test_num -= 1 885 continue 886 self._mock_test_case_life_cycle(self.get_listeners(), test) 887 888 test_suite.is_completed = True 889 for listener in self.get_listeners(): 890 suite = copy.copy(test_suite) 891 listener.__ended__(LifeCycle.TestSuite, suite, is_clear=True) 892 893 def _is_match_marker(self, line): 894 if self.ace_log_marker: 895 return line.lower().find(self.ace_log_marker) != -1 896 else: 897 for mark_str in _ACE_LOG_MARKER: 898 if line.lower().find(mark_str) != -1: 899 self.ace_log_marker = mark_str 900 return True 901 return False 902 903 904@Plugin(type=Plugin.PARSER, id=CommonParserType.oh_kernel_test) 905class OHKernelTestParser(IParser): 906 907 def __init__(self): 908 self.state_machine = StateRecorder() 909 self.suites_name = "" 910 self.listeners = [] 911 912 def get_listeners(self): 913 return self.listeners 914 915 def __process__(self, lines): 916 if not self.state_machine.suites_is_started(): 917 self.state_machine.trace_logs.extend(lines) 918 for line in lines: 919 self.parse(line) 920 921 def __done__(self): 922 pass 923 924 def parse(self, line): 925 line = re.sub('\x1b.*?m', '', line) 926 if self.state_machine.suites_is_started() or RUNTEST_TEST in line: 927 if RUNTEST_TEST in line: 928 self.handle_suites_started_tag(line) 929 elif START_TO_TEST in line: 930 self.handle_suite_start_tag(line) 931 elif FINISHED_TO_TEST in line: 932 self.handle_suite_end_tag(line) 933 elif line.endswith(PASS_DOT) or line.endswith(FAIL_DOT): 934 self.handle_one_test_case_tag(line) 935 elif line.endswith(ERROR_EXCLAMATION) \ 936 or line.endswith(TIMEOUT_EXCLAMATION): 937 self.handle_test_case_error(line) 938 elif TIMEOUT_TESTCASES in line: 939 self.handle_suites_ended_tag(line) 940 941 def handle_suites_started_tag(self, line): 942 self.state_machine.get_suites(reset=True) 943 test_suites = self.state_machine.get_suites() 944 test_suites.suites_name = self.suites_name 945 test_suites.test_num = 0 946 for listener in self.get_listeners(): 947 suite_report = copy.copy(test_suites) 948 listener.__started__(LifeCycle.TestSuites, suite_report) 949 950 def handle_suites_ended_tag(self, line): 951 suites = self.state_machine.get_suites() 952 suites.is_completed = True 953 954 for listener in self.get_listeners(): 955 listener.__ended__(LifeCycle.TestSuites, test_result=suites, 956 suites_name=suites.suites_name) 957 958 def handle_suite_start_tag(self, line): 959 pattern = "^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}" \ 960 " Start to test (.+)$" 961 matcher = re.match(pattern, line) 962 if matcher and matcher.group(1): 963 self.state_machine.suite(reset=True) 964 test_suite = self.state_machine.suite() 965 test_suite.suite_name = matcher.group(1) 966 for listener in self.get_listeners(): 967 suite_report = copy.copy(test_suite) 968 listener.__started__(LifeCycle.TestSuite, suite_report) 969 970 def handle_suite_end_tag(self, line): 971 pattern = "^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}" \ 972 " Finished to test (.+)$" 973 matcher = re.match(pattern, line) 974 if matcher and matcher.group(1): 975 suite_result = self.state_machine.suite() 976 suites = self.state_machine.get_suites() 977 suite_result.run_time = suite_result.run_time 978 suites.run_time += suite_result.run_time 979 suite_result.is_completed = True 980 981 for listener in self.get_listeners(): 982 suite = copy.copy(suite_result) 983 listener.__ended__(LifeCycle.TestSuite, suite, is_clear=True) 984 985 def handle_one_test_case_tag(self, line): 986 pattern = "^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} (.+) " \ 987 "(PASS)\\.$" 988 matcher = re.match(pattern, line) 989 if not (matcher and matcher.group(1) and matcher.group(2)): 990 return 991 test_result = self.state_machine.test(reset=True) 992 test_suite = self.state_machine.suite() 993 test_result.test_class = test_suite.suite_name 994 test_result.test_name = matcher.group(1) 995 test_result.current = self.state_machine.running_test_index + 1 996 for listener in self.get_listeners(): 997 test_result = copy.copy(test_result) 998 listener.__started__(LifeCycle.TestCase, test_result) 999 1000 test_suites = self.state_machine.get_suites() 1001 if PASS_DOT in line: 1002 test_result.code = ResultCode.PASSED.value 1003 elif FAIL_DOT in line: 1004 test_result.code = ResultCode.FAILED.value 1005 for listener in self.get_listeners(): 1006 result = copy.copy(test_result) 1007 listener.__failed__(LifeCycle.TestCase, result) 1008 self.state_machine.test().is_completed = True 1009 test_suite.test_num += 1 1010 test_suites.test_num += 1 1011 for listener in self.get_listeners(): 1012 result = copy.copy(test_result) 1013 listener.__ended__(LifeCycle.TestCase, result) 1014 self.state_machine.running_test_index += 1 1015 1016 def handle_test_case_error(self, line): 1017 pattern = "^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} (.+) " \ 1018 "(ERROR!!!|TIMEOUT!)$" 1019 matcher = re.match(pattern, line) 1020 if not (matcher and matcher.group(1) and matcher.group(2)): 1021 return 1022 test_result = self.state_machine.test(reset=True) 1023 test_suite = self.state_machine.suite() 1024 test_result.test_class = test_suite.suite_name 1025 test_result.test_name = matcher.group(1) 1026 test_result.current = self.state_machine.running_test_index + 1 1027 for listener in self.get_listeners(): 1028 test_result = copy.copy(test_result) 1029 listener.__started__(LifeCycle.TestCase, test_result) 1030 1031 test_suites = self.state_machine.get_suites() 1032 if ERROR_EXCLAMATION in line: 1033 test_result.code = ResultCode.FAILED.value 1034 elif TIMEOUT_EXCLAMATION in line: 1035 test_result.code = ResultCode.BLOCKED.value 1036 1037 for listener in self.get_listeners(): 1038 result = copy.copy(test_result) 1039 listener.__failed__(LifeCycle.TestCase, result) 1040 self.state_machine.test().is_completed = True 1041 test_suite.test_num += 1 1042 test_suites.test_num += 1 1043 for listener in self.get_listeners(): 1044 result = copy.copy(test_result) 1045 listener.__ended__(LifeCycle.TestCase, result) 1046 self.state_machine.running_test_index += 1 1047 1048 1049class OHJSUnitPrefixes(Enum): 1050 SUM = "OHOS_REPORT_SUM: " 1051 STATUS = "OHOS_REPORT_STATUS: " 1052 STATUS_CODE = "OHOS_REPORT_STATUS_CODE: " 1053 RESULT = "OHOS_REPORT_RESULT: " 1054 CODE = "OHOS_REPORT_CODE: " 1055 TEST_FINISHED_RESULT_MSG = "TestFinished-ResultMsg: " 1056 1057 1058class OHJSUnitItemConstants(Enum): 1059 CLASS = "class" 1060 TEST = "test" 1061 NUM_TESTS = "numtests" 1062 STACK = "stack" 1063 STREAM = "stream" 1064 SUITE_CONSUMING = "suiteconsuming" 1065 CONSUMING = "consuming" 1066 APP_DIED = "App died" 1067 1068 1069@Plugin(type=Plugin.PARSER, id=CommonParserType.oh_jsunit) 1070class OHJSUnitTestParser(IParser): 1071 1072 def __init__(self): 1073 self.state_machine = StateRecorder() 1074 self.suites_name = "" 1075 self.listeners = [] 1076 self.current_key = None 1077 self.current_value = None 1078 self.start_time = get_cst_time() 1079 self.suite_start_time = get_cst_time() 1080 self.test_time = 0 1081 self.test_run_finished = False 1082 self.cur_sum = -1 1083 self.runner = None 1084 1085 def get_suite_name(self): 1086 return self.suites_name 1087 1088 def get_listeners(self): 1089 return self.listeners 1090 1091 def __process__(self, lines): 1092 for line in lines: 1093 line = str(line).strip().rstrip("\r") 1094 LOG.debug(line) 1095 self.parse(line) 1096 1097 def parse(self, line): 1098 if not str(line).strip(): 1099 return 1100 if line.startswith(OHJSUnitPrefixes.SUM.value): 1101 self.handle_sum_line(line) 1102 elif line.startswith(OHJSUnitPrefixes.STATUS.value): 1103 self.handle_status_line(line) 1104 elif line.startswith(OHJSUnitPrefixes.STATUS_CODE.value): 1105 self.submit_current_key_value() 1106 self.parse_status_code(line) 1107 elif line.startswith(OHJSUnitPrefixes.TEST_FINISHED_RESULT_MSG.value): 1108 self._handle_result_msg(line) 1109 1110 def handle_sum_line(self, line): 1111 value = line[len(OHJSUnitPrefixes.SUM.value):].split("=", 1)[0] 1112 self.cur_sum = int(value) 1113 1114 def handle_status_line(self, line): 1115 self.parse_key(line, len(OHJSUnitPrefixes.STATUS.value)) 1116 if self.cur_sum > 0 and \ 1117 self.current_key == OHJSUnitItemConstants.CLASS.value: 1118 if self.current_value not in self.runner.suite_recorder.keys(): 1119 current_suite = self.state_machine.suite(reset=True) 1120 current_suite.test_num = self.cur_sum 1121 current_suite.suite_name = self.current_value 1122 self.runner.suite_recorder.update({ 1123 self.current_value: 1124 [len(self.runner.suite_recorder.keys()), 1125 current_suite]}) 1126 else: 1127 current_suite = self.runner.suite_recorder.get( 1128 self.current_value)[1] 1129 self.state_machine.current_suite = current_suite 1130 self.cur_sum = -1 1131 self.current_key = None 1132 self.current_value = None 1133 self.state_machine.running_test_index = 0 1134 self.suite_start_time = get_cst_time() 1135 for listener in self.get_listeners(): 1136 suite = copy.copy(current_suite) 1137 listener.__started__(LifeCycle.TestSuite, suite) 1138 1139 else: 1140 if self.current_key == OHJSUnitItemConstants.SUITE_CONSUMING.value: 1141 self.test_time = int(self.current_value) 1142 self.handle_suite_end() 1143 elif self.current_key == OHJSUnitItemConstants.CONSUMING.value: 1144 self.test_time = int(self.current_value) 1145 self.handle_case_end() 1146 else: 1147 self.submit_current_key_value() 1148 self.parse_key(line, len(OHJSUnitPrefixes.STATUS.value)) 1149 1150 def submit_current_key_value(self): 1151 if self.current_key and self.current_value: 1152 status_value = self.current_value 1153 test_info = self.state_machine.test() 1154 if self.current_key == OHJSUnitItemConstants.CLASS.value: 1155 test_info.test_class = status_value 1156 elif self.current_key == OHJSUnitItemConstants.TEST.value: 1157 test_info.test_name = status_value 1158 elif self.current_key == OHJSUnitItemConstants.NUM_TESTS.value: 1159 test_info.num_tests = int(status_value) 1160 elif self.current_key == OHJSUnitItemConstants.STREAM.value: 1161 test_info.stacktrace = status_value 1162 self.current_key = None 1163 self.current_value = None 1164 1165 def parse_key(self, line, key_start_pos): 1166 key_value = line[key_start_pos:].split("=", 1) 1167 if len(key_value) == 2: 1168 self.current_key = key_value[0] 1169 self.current_value = key_value[1] 1170 1171 def parse_status_code(self, line): 1172 value = line[len(OHJSUnitPrefixes.STATUS_CODE.value):] 1173 test_info = self.state_machine.test() 1174 test_info.code = int(value) 1175 if test_info.code != StatusCodes.IN_PROGRESS: 1176 if self.check_legality(test_info.test_class) and \ 1177 self.check_legality(test_info.test_name): 1178 self.report_result(test_info) 1179 1180 def clear_current_test_info(self): 1181 self.state_machine.current_test = None 1182 1183 def report_result(self, test_info): 1184 if not test_info.test_name or not test_info.test_class: 1185 LOG.info("Invalid instrumentation status bundle") 1186 return 1187 if test_info.code == StatusCodes.START.value: 1188 self.start_time = get_cst_time() 1189 for listener in self.get_listeners(): 1190 result = copy.copy(test_info) 1191 listener.__started__(LifeCycle.TestCase, result) 1192 return 1193 if test_info.code == StatusCodes.FAILURE.value: 1194 self.state_machine.running_test_index += 1 1195 test_info.current = self.state_machine.running_test_index 1196 test_info.code = ResultCode.FAILED.value 1197 test_info.run_time = get_delta_time_ms(self.start_time) 1198 elif test_info.code == StatusCodes.ERROR.value: 1199 self.state_machine.running_test_index += 1 1200 test_info.current = self.state_machine.running_test_index 1201 test_info.code = ResultCode.FAILED.value 1202 test_info.run_time = get_delta_time_ms(self.start_time) 1203 elif test_info.code == StatusCodes.SUCCESS.value: 1204 self.state_machine.running_test_index += 1 1205 test_info.current = self.state_machine.running_test_index 1206 test_info.code = ResultCode.PASSED.value 1207 test_info.run_time = get_delta_time_ms(self.start_time) 1208 1209 @classmethod 1210 def output_stack_trace(cls, test_info): 1211 if check_pub_key_exist(): 1212 return 1213 if test_info.stacktrace: 1214 stack_lines = test_info.stacktrace.split(r"\r\n") 1215 LOG.error("Stacktrace information is:") 1216 for line in stack_lines: 1217 line.strip() 1218 if line: 1219 LOG.error(line) 1220 1221 @staticmethod 1222 def check_legality(name): 1223 if not name or name == "null": 1224 return False 1225 return True 1226 1227 def __done__(self): 1228 pass 1229 1230 def handle_case_end(self): 1231 test_info = self.state_machine.test() 1232 if not test_info.test_name or not test_info.test_class: 1233 LOG.warning("Test case name or class is invalid. test_name: {}, test_class: {}" 1234 .format(test_info.test_name, test_info.test_class)) 1235 return 1236 if test_info.run_time == 0 or test_info.run_time < self.test_time: 1237 test_info.run_time = self.test_time 1238 for listener in self.get_listeners(): 1239 result = copy.copy(test_info) 1240 result.code = test_info.code 1241 listener.__ended__(LifeCycle.TestCase, result) 1242 if listener.__class__.__name__ == "ReportListener" \ 1243 and self.runner.retry_times > 1: 1244 index = list(listener.tests.keys())[-1] 1245 listener.tests.pop(index) 1246 test_info.is_completed = True 1247 self.clear_current_test_info() 1248 1249 def handle_suite_end(self): 1250 suite_result = self.state_machine.suite() 1251 suite_result.run_time = get_delta_time_ms(self.suite_start_time) 1252 if suite_result.run_time == 0: 1253 suite_result.run_time = self.test_time 1254 suite_result.is_completed = True 1255 for listener in self.get_listeners(): 1256 suite = copy.copy(suite_result) 1257 listener.__ended__(LifeCycle.TestSuite, suite, is_clear=True) 1258 1259 def handle_suites_end(self): 1260 suite_result = self.state_machine.suite() 1261 if not suite_result.is_completed: 1262 self.handle_suite_end() 1263 for listener in self.get_listeners(): 1264 if listener.__class__.__name__ == "ReportListener": 1265 self._cal_result(listener) 1266 suite = copy.copy(suite_result) 1267 listener.__ended__(LifeCycle.TestSuites, suite, 1268 suites_name=self.suites_name) 1269 self.state_machine.current_suite = None 1270 1271 def _cal_result(self, report_listener): 1272 result_len = len(report_listener.result) 1273 suites_len = len(report_listener.suites) 1274 if result_len > suites_len: 1275 diff_result_tuple_list = report_listener.result[suites_len:] 1276 report_listener.result = report_listener.result[:suites_len] 1277 for diff_result_tuple in diff_result_tuple_list: 1278 suite, case_result_list = diff_result_tuple 1279 pos = self.runner.suite_recorder.get(suite.suite_name)[0] 1280 report_listener.result[pos][1].extend(case_result_list) 1281 self._handle_lacking_one_testcase(report_listener) 1282 self._handle_lacking_whole_suite(report_listener) 1283 1284 def _handle_lacking_one_testcase(self, report_listener): 1285 for suite in report_listener.suites.values(): 1286 test_des_list = self.runner.expect_tests_dict.get( 1287 suite.suite_name, []) 1288 pos = self.runner.suite_recorder.get(suite.suite_name)[0] 1289 if len(test_des_list) == len(report_listener.result[pos][1]): 1290 continue 1291 interval = len(test_des_list) - len(report_listener.result[pos][1]) 1292 if len(test_des_list) > 0: 1293 LOG.info("{} tests in {} had missed.".format( 1294 interval, suite.suite_name)) 1295 else: 1296 LOG.info("The count of tests in '{}' is incorrect! {} test " 1297 "form dry run and {} tests have run." 1298 "".format(suite.suite_name, len(test_des_list), 1299 len(report_listener.result[pos][1]))) 1300 for test_des in test_des_list: 1301 is_contain = False 1302 for case in report_listener.result[pos][1]: 1303 if case.test_name == test_des.test_name: 1304 is_contain = True 1305 break 1306 if not is_contain: 1307 test_result = self.state_machine.test(reset=True) 1308 test_result.test_class = test_des.class_name 1309 test_result.test_name = test_des.test_name 1310 test_result.stacktrace = "error_msg:mark blocked" 1311 test_result.num_tests = 1 1312 test_result.run_time = 0 1313 test_result.current = \ 1314 self.state_machine.running_test_index + 1 1315 test_result.code = ResultCode.BLOCKED.value 1316 report_listener.result[pos][1].append(test_result) 1317 LOG.debug("Add {}#{}".format(test_des.class_name, 1318 test_des.test_name)) 1319 1320 def _handle_lacking_whole_suite(self, report_listener): 1321 all_suite_set = set(self.runner.expect_tests_dict.keys()) 1322 un_suite_set = set() 1323 if len(all_suite_set) > len(report_listener.suites): 1324 suite_name_set = set() 1325 for suite in report_listener.suites.values(): 1326 suite_name_set.add(suite.suite_name) 1327 un_suite_set = all_suite_set.difference(suite_name_set) 1328 if un_suite_set: 1329 LOG.info("{} suites have missed.".format(len(un_suite_set))) 1330 for name in un_suite_set: 1331 self.state_machine.running_test_index = 0 1332 test_des_list = self.runner.expect_tests_dict.get( 1333 name, []) 1334 current_suite = self.state_machine.suite(reset=True) 1335 current_suite.test_num = len(test_des_list) 1336 current_suite.suite_name = name 1337 for listener in self.get_listeners(): 1338 suite = copy.copy(current_suite) 1339 listener.__started__(LifeCycle.TestSuite, suite) 1340 1341 for test in test_des_list: 1342 test_result = self.state_machine.test(reset=True) 1343 test_result.test_class = test.class_name 1344 test_result.test_name = test.test_name 1345 test_result.stacktrace = "error_msg:mark blocked" 1346 test_result.num_tests = 1 1347 test_result.run_time = 0 1348 test_result.current = self.state_machine.running_test_index + 1 1349 test_result.code = ResultCode.BLOCKED.value 1350 test_result = copy.copy(test_result) 1351 for listener in self.get_listeners(): 1352 listener.__started__(LifeCycle.TestCase, test_result) 1353 test_result = copy.copy(test_result) 1354 for listener in self.get_listeners(): 1355 listener.__ended__(LifeCycle.TestCase, test_result) 1356 self.state_machine.running_test_index += 1 1357 current_suite.run_time = self.test_time 1358 current_suite.is_completed = True 1359 for listener in self.get_listeners(): 1360 suite = copy.copy(current_suite) 1361 listener.__ended__(LifeCycle.TestSuite, suite, is_clear=True) 1362 1363 def notify_task_finished(self): 1364 self.handle_suites_end() 1365 1366 def _handle_result_msg(self, line): 1367 if OHJSUnitItemConstants.APP_DIED.value in line: 1368 test_result = self.state_machine.test() 1369 suite = self.state_machine.suite() 1370 if not test_result.is_completed: 1371 if self.check_legality(test_result.test_class) and \ 1372 self.check_legality(test_result.test_name): 1373 self.report_result(test_result) 1374 self.clear_current_test_info() 1375 if not suite.is_completed: 1376 self.handle_suite_end() 1377 1378 1379@Plugin(type=Plugin.PARSER, id=CommonParserType.oh_jsunit_list) 1380class OHJSUnitTestListParser(IParser): 1381 1382 def __init__(self): 1383 self.tests = [] 1384 self.json_str = "" 1385 self.tests_dict = dict() 1386 self.result_data = "" 1387 1388 def __process__(self, lines): 1389 for line in lines: 1390 line = str(line).strip().rstrip("\r") 1391 self.result_data = "{}{}".format(self.result_data, line) 1392 self.parse(line) 1393 1394 def __done__(self): 1395 LOG.debug("OHJSUnitTestListParser data:") 1396 LOG.debug(self.result_data) 1397 self.result_data = "" 1398 1399 def parse(self, line): 1400 if "{" in line or "}" in line: 1401 self.json_str = "%s%s" % (self.json_str, line) 1402 return 1403 if "dry run finished" in line: 1404 suite_dict_list = json.loads(self.json_str).get("suites", []) 1405 for suite_dict in suite_dict_list: 1406 for class_name, test_name_dict_list in suite_dict.items(): 1407 self.tests_dict.update({class_name.strip(): []}) 1408 for test_name_dict in test_name_dict_list: 1409 for test_name in test_name_dict.values(): 1410 test = TestDescription(class_name.strip(), 1411 test_name.strip()) 1412 self.tests_dict.get( 1413 class_name.strip()).append(test) 1414 self.tests.append(test) 1415 1416 1417@Plugin(type=Plugin.PARSER, id=CommonParserType.oh_rust) 1418class OHRustTestParser(IParser): 1419 1420 def __init__(self): 1421 self.test_pattern = "test (?:tests::)?(.+) ... (ok|FAILED)" 1422 self.stout_pattern = "---- tests::(.+) stdout ----" 1423 self.running_pattern = "running (\\d+) test|tests" 1424 self.test_result_pattern = "test result: (ok|FAILED)\\..+finished in (.+)s" 1425 self.suite_name = "" 1426 self.result_list = list() 1427 self.stdout_list = list() 1428 self.failures_stdout = list() 1429 self.cur_fail_case = "" 1430 self.state_machine = StateRecorder() 1431 self.listeners = [] 1432 1433 def get_listeners(self): 1434 return self.listeners 1435 1436 def __process__(self, lines): 1437 for line in lines: 1438 LOG.debug(line) 1439 self.parse(line) 1440 1441 def __done__(self): 1442 self.handle_suite_end() 1443 1444 def parse(self, line): 1445 if line.startswith("running"): 1446 matcher = re.match(self.running_pattern, line) 1447 if not (matcher and matcher.group(1)): 1448 return 1449 self.handle_suite_start(matcher) 1450 elif line.startswith("test result:"): 1451 matcher = re.match(self.test_result_pattern, line) 1452 if not (matcher and matcher.group(2)): 1453 return 1454 self.handle_case_lifecycle(matcher) 1455 1456 elif "..." in line: 1457 matcher = re.match(self.test_pattern, line) 1458 if not (matcher and matcher.group(1) and matcher.group(2)): 1459 return 1460 self.collect_case(matcher) 1461 elif line.startswith("---- tests::"): 1462 matcher = re.match(self.stout_pattern, line) 1463 if not (matcher and matcher.group(1)): 1464 return 1465 self.cur_fail_case = matcher.group(1) 1466 else: 1467 if self.cur_fail_case: 1468 self.handle_stdout(line) 1469 1470 def handle_case_lifecycle(self, matcher): 1471 cost_time = matcher.group(2) 1472 for test_result in self.result_list: 1473 if test_result.code == ResultCode.FAILED.value: 1474 if self.stdout_list and \ 1475 self.stdout_list[0][0] == test_result.test_name: 1476 test_result.stacktrace = self.stdout_list[0][1] 1477 self.stdout_list.pop(0) 1478 test_result.current = self.state_machine.running_test_index + 1 1479 for listener in self.get_listeners(): 1480 test_result = copy.copy(test_result) 1481 listener.__started__(LifeCycle.TestCase, test_result) 1482 for listener in self.get_listeners(): 1483 result = copy.copy(test_result) 1484 listener.__ended__(LifeCycle.TestCase, result) 1485 test_suite = self.state_machine.suite() 1486 test_suite.run_time = float(cost_time) * 1000 1487 1488 def handle_stdout(self, line): 1489 if line.strip(): 1490 self.failures_stdout.append(line.strip()) 1491 else: 1492 self.stdout_list.append((self.cur_fail_case, 1493 " ".join(self.failures_stdout))) 1494 self.cur_fail_case = "" 1495 self.failures_stdout.clear() 1496 1497 def collect_case(self, matcher): 1498 test_result = self.state_machine.test(reset=True) 1499 test_result.test_class = self.suite_name 1500 test_result.test_name = matcher.group(1) 1501 test_result.code = ResultCode.PASSED.value if \ 1502 matcher.group(2) == "ok" else ResultCode.FAILED.value 1503 self.result_list.append(test_result) 1504 1505 def handle_suite_start(self, matcher): 1506 self.state_machine.suite(reset=True) 1507 test_suite = self.state_machine.suite() 1508 test_suite.suite_name = self.suite_name 1509 test_suite.test_num = int(matcher.group(1)) 1510 for listener in self.get_listeners(): 1511 suite_report = copy.copy(test_suite) 1512 listener.__started__(LifeCycle.TestSuite, suite_report) 1513 1514 def handle_suite_end(self): 1515 suite_result = self.state_machine.suite() 1516 suite_result.run_time += suite_result.run_time 1517 suite_result.is_completed = True 1518 for listener in self.get_listeners(): 1519 suite = copy.copy(suite_result) 1520 listener.__ended__(LifeCycle.TestSuite, suite, suite_report=True) 1521 1522 1523@Plugin(type=Plugin.PARSER, id=CommonParserType.oh_yara) 1524class OHYaraTestParser(IParser): 1525 last_line = "" 1526 pattern = r"(\d{1,2}-\d{1,2}\s\d{1,2}:\d{1,2}:\d{1,2}\.\d{3}) " 1527 1528 def __init__(self): 1529 self.state_machine = StateRecorder() 1530 self.suites_name = "" 1531 self.vul_items = None 1532 self.listeners = [] 1533 1534 def get_listeners(self): 1535 return self.listeners 1536 1537 def __process__(self, lines): 1538 self.parse(lines) 1539 1540 def __done__(self): 1541 pass 1542 1543 def parse(self, lines): 1544 for line in lines: 1545 if line: 1546 self.handle_suites_started_tag() 1547 self.handle_suite_started_tag() 1548 self.handle_one_test_tag(line) 1549 self.handle_suite_ended_tag() 1550 self.handle_suites_ended_tag() 1551 1552 def handle_suites_started_tag(self): 1553 self.state_machine.get_suites(reset=True) 1554 test_suites = self.state_machine.get_suites() 1555 test_suites.suites_name = self.suites_name 1556 test_suites.test_num = len(self.vul_items) 1557 for listener in self.get_listeners(): 1558 suite_report = copy.copy(test_suites) 1559 listener.__started__(LifeCycle.TestSuites, suite_report) 1560 1561 def handle_suites_ended_tag(self): 1562 suites = self.state_machine.get_suites() 1563 suites.is_completed = True 1564 for listener in self.get_listeners(): 1565 listener.__ended__(LifeCycle.TestSuites, test_result=suites, 1566 suites_name=suites.suites_name) 1567 1568 def handle_one_test_tag(self, message): 1569 status_dict = {"pass": ResultCode.PASSED, "fail": ResultCode.FAILED, 1570 "block": ResultCode.BLOCKED} 1571 message = message.strip().split("|") 1572 test_name = message[0] 1573 status = status_dict.get(message[3]) 1574 trace = message[6] if message[3] else "" 1575 run_time = 0 1576 test_suite = self.state_machine.suite() 1577 test_result = self.state_machine.test(reset=True) 1578 test_result.test_class = test_suite.suite_name 1579 test_result.test_name = test_name 1580 test_result.run_time = run_time 1581 test_result.code = status.value 1582 test_result.stacktrace = trace 1583 test_result.current = self.state_machine.running_test_index + 1 1584 self.state_machine.suite().run_time += run_time 1585 for listener in self.get_listeners(): 1586 test_result = copy.copy(test_result) 1587 listener.__started__(LifeCycle.TestCase, test_result) 1588 1589 test_suites = self.state_machine.get_suites() 1590 self.state_machine.test().is_completed = True 1591 test_suites.test_num += 1 1592 for listener in self.get_listeners(): 1593 result = copy.copy(test_result) 1594 listener.__ended__(LifeCycle.TestCase, result) 1595 self.state_machine.running_test_index += 1 1596 1597 def handle_suite_started_tag(self): 1598 self.state_machine.suite(reset=True) 1599 self.state_machine.running_test_index = 0 1600 test_suite = self.state_machine.suite() 1601 test_suite.suite_name = self.suites_name 1602 test_suite.test_num = 1 1603 for listener in self.get_listeners(): 1604 suite_report = copy.copy(test_suite) 1605 listener.__started__(LifeCycle.TestSuite, suite_report) 1606 1607 def handle_suite_ended_tag(self): 1608 suite_result = self.state_machine.suite() 1609 suites = self.state_machine.get_suites() 1610 suite_result.run_time = suite_result.run_time 1611 suites.run_time += suite_result.run_time 1612 suite_result.is_completed = True 1613 for listener in self.get_listeners(): 1614 suite = copy.copy(suite_result) 1615 listener.__ended__(LifeCycle.TestSuite, suite, is_clear=True)