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 = "jsapp" 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 LOG.debug(line) 100 self.parse(line) 101 102 def __done__(self): 103 suite_result = self.state_machine.get_suites() 104 if not suite_result.suites_name: 105 return 106 for listener in self.get_listeners(): 107 suites = copy.copy(suite_result) 108 listener.__ended__(LifeCycle.TestSuites, test_result=suites, 109 suites_name=suites.suites_name, 110 product_info=suites.product_info) 111 self.state_machine.current_suites = None 112 113 def parse(self, line): 114 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 self.result_data = "{}{}\n".format(self.result_data, line) 371 self.parse(line) 372 373 def __done__(self): 374 LOG.debug("CppTestListParser data:") 375 LOG.debug(self.result_data) 376 self.result_data = "" 377 378 def parse(self, line): 379 class_matcher = re.match('^([a-zA-Z]+.*)\\.$', line) 380 method_matcher = re.match('\\s+([a-zA-Z_]+[\\S]*)(.*)?(\\s+.*)?$', 381 line) 382 if class_matcher: 383 self.last_test_class_name = class_matcher.group(1) 384 if self.last_test_class_name not in self.suites: 385 self.suites.setdefault(self.last_test_class_name, []) 386 elif method_matcher: 387 if not self.last_test_class_name: 388 LOG.error("Parsed new test case name %s but no test class name" 389 " has been set" % line) 390 else: 391 test_name = method_matcher.group(1) 392 if test_name not in self.suites.get(self.last_test_class_name, []): 393 test = TestDescription(self.last_test_class_name, 394 test_name) 395 self.tests.append(test) 396 self.suites.get(self.last_test_class_name, []).append(test_name) 397 else: 398 LOG.debug("[{}.{}] has already collect it, skip it.".format( 399 self.last_test_class_name, test_name)) 400 else: 401 if not check_pub_key_exist(): 402 LOG.debug("Line ignored: %s" % line) 403 404 405class StatusCodes(Enum): 406 FAILURE = -2 407 START = 1 408 ERROR = -1 409 SUCCESS = 0 410 IN_PROGRESS = 2 411 IGNORE = -3 412 BLOCKED = 3 413 414 415class Prefixes(Enum): 416 STATUS = "INSTRUMENTATION_STATUS: " 417 STATUS_CODE = "INSTRUMENTATION_STATUS_CODE: " 418 STATUS_FAILED = "INSTRUMENTATION_FAILED: " 419 CODE = "INSTRUMENTATION_CODE: " 420 RESULT = "INSTRUMENTATION_RESULT: " 421 TIME_REPORT = "Time: " 422 423 424@Plugin(type=Plugin.PARSER, id=CommonParserType.junit) 425class JunitParser(IParser): 426 def __init__(self): 427 self.state_machine = StateRecorder() 428 self.suite_name = "" 429 self.listeners = [] 430 self.current_key = None 431 self.current_value = None 432 self.start_time = get_cst_time() 433 self.test_time = 0 434 self.test_run_finished = False 435 436 def get_suite_name(self): 437 return self.suite_name 438 439 def get_listeners(self): 440 return self.listeners 441 442 def __process__(self, lines): 443 for line in lines: 444 if not check_pub_key_exist(): 445 LOG.debug(line) 446 self.parse(line) 447 448 def __done__(self): 449 suite_result = self.state_machine.suite() 450 suite_result.run_time = self.test_time 451 suite_result.is_completed = True 452 for listener in self.get_listeners(): 453 suite = copy.copy(suite_result) 454 listener.__ended__(LifeCycle.TestSuite, suite, 455 suite_report=True) 456 self.state_machine.current_suite = None 457 458 def parse(self, line): 459 if line.startswith(Prefixes.STATUS_CODE.value): 460 self.submit_current_key_value() 461 self.parse_status_code(line) 462 elif line.startswith(Prefixes.STATUS.value): 463 self.submit_current_key_value() 464 self.parse_key(line, len(Prefixes.STATUS.value)) 465 elif line.startswith(Prefixes.RESULT.value): 466 self.test_run_finished = True 467 elif line.startswith(Prefixes.STATUS_FAILED.value) or \ 468 line.startswith(Prefixes.CODE.value): 469 self.submit_current_key_value() 470 self.test_run_finished = True 471 elif line.startswith(Prefixes.TIME_REPORT.value): 472 self.parse_time(line) 473 else: 474 if self.current_key == "stack" and self.current_value: 475 self.current_value = self.current_value + r"\r\n" 476 self.current_value = self.current_value + line 477 elif line: 478 pass 479 480 def parse_key(self, line, key_start_pos): 481 key_value = line[key_start_pos:].split("=", 1) 482 if len(key_value) == 2: 483 self.current_key = key_value[0] 484 self.current_value = key_value[1] 485 486 def parse_time(self, line): 487 message = line[len(Prefixes.TIME_REPORT.value):] 488 self.test_time = float(message.replace(",", "")) * 1000 489 490 @staticmethod 491 def check_legality(name): 492 if not name or name == "null": 493 return False 494 return True 495 496 def parse_status_code(self, line): 497 value = line[len(Prefixes.STATUS_CODE.value):] 498 test_info = self.state_machine.test() 499 test_info.code = int(value) 500 if test_info.code != StatusCodes.IN_PROGRESS: 501 if self.check_legality(test_info.test_class) and \ 502 self.check_legality(test_info.test_name): 503 self.report_result(test_info) 504 self.clear_current_test_info() 505 506 def clear_current_test_info(self): 507 self.state_machine.current_test = None 508 509 def submit_current_key_value(self): 510 if self.current_key and self.current_value: 511 status_value = self.current_value 512 test_info = self.state_machine.test() 513 if self.current_key == "class": 514 test_info.test_class = status_value 515 elif self.current_key == "test": 516 test_info.test_name = status_value 517 elif self.current_key == "numtests": 518 test_info.num_tests = int(status_value) 519 elif self.current_key == "Error": 520 self.handle_test_run_failed(status_value) 521 elif self.current_key == "stack": 522 test_info.stacktrace = status_value 523 elif self.current_key == "stream": 524 pass 525 self.current_key = None 526 self.current_value = None 527 528 def report_result(self, test_info): 529 if not test_info.test_name or not test_info.test_class: 530 LOG.info("Invalid instrumentation status bundle") 531 return 532 test_info.is_completed = True 533 self.report_test_run_started(test_info) 534 if test_info.code == StatusCodes.START.value: 535 self.start_time = get_cst_time() 536 for listener in self.get_listeners(): 537 result = copy.copy(test_info) 538 listener.__started__(LifeCycle.TestCase, result) 539 elif test_info.code == StatusCodes.FAILURE.value: 540 self.state_machine.running_test_index += 1 541 test_info.current = self.state_machine.running_test_index 542 end_time = get_cst_time() 543 run_time = (end_time - self.start_time).total_seconds() 544 test_info.run_time = int(run_time * 1000) 545 for listener in self.get_listeners(): 546 result = copy.copy(test_info) 547 result.code = ResultCode.FAILED.value 548 listener.__ended__(LifeCycle.TestCase, result) 549 elif test_info.code == StatusCodes.ERROR.value: 550 self.state_machine.running_test_index += 1 551 test_info.current = self.state_machine.running_test_index 552 end_time = get_cst_time() 553 run_time = (end_time - self.start_time).total_seconds() 554 test_info.run_time = int(run_time * 1000) 555 for listener in self.get_listeners(): 556 result = copy.copy(test_info) 557 result.code = ResultCode.FAILED.value 558 listener.__ended__(LifeCycle.TestCase, result) 559 elif test_info.code == StatusCodes.SUCCESS.value: 560 self.state_machine.running_test_index += 1 561 test_info.current = self.state_machine.running_test_index 562 end_time = get_cst_time() 563 run_time = (end_time - self.start_time).total_seconds() 564 test_info.run_time = int(run_time * 1000) 565 for listener in self.get_listeners(): 566 result = copy.copy(test_info) 567 result.code = ResultCode.PASSED.value 568 listener.__ended__(LifeCycle.TestCase, result) 569 elif test_info.code == StatusCodes.IGNORE.value: 570 end_time = get_cst_time() 571 run_time = (end_time - self.start_time).total_seconds() 572 test_info.run_time = int(run_time * 1000) 573 for listener in self.get_listeners(): 574 result = copy.copy(test_info) 575 result.code = ResultCode.SKIPPED.value 576 listener.__skipped__(LifeCycle.TestCase, result) 577 elif test_info.code == StatusCodes.BLOCKED.value: 578 test_info.current = self.state_machine.running_test_index 579 end_time = get_cst_time() 580 run_time = (end_time - self.start_time).total_seconds() 581 test_info.run_time = int(run_time * 1000) 582 for listener in self.get_listeners(): 583 result = copy.copy(test_info) 584 result.code = ResultCode.BLOCKED.value 585 listener.__ended__(LifeCycle.TestCase, result) 586 587 self.output_stack_trace(test_info) 588 589 @classmethod 590 def output_stack_trace(cls, test_info): 591 if check_pub_key_exist(): 592 return 593 if test_info.stacktrace: 594 stack_lines = test_info.stacktrace.split(r"\r\n") 595 LOG.error("Stacktrace information is:") 596 for line in stack_lines: 597 line.strip() 598 if line: 599 LOG.error(line) 600 601 def report_test_run_started(self, test_result): 602 test_suite = self.state_machine.suite() 603 if not self.state_machine.suite().is_started: 604 if not test_suite.test_num or not test_suite.suite_name: 605 test_suite.suite_name = self.get_suite_name() 606 test_suite.test_num = test_result.num_tests 607 for listener in self.get_listeners(): 608 suite_report = copy.copy(test_suite) 609 listener.__started__(LifeCycle.TestSuite, suite_report) 610 611 @staticmethod 612 def handle_test_run_failed(error_msg): 613 if not error_msg: 614 error_msg = "Unknown error" 615 if not check_pub_key_exist(): 616 LOG.debug("Error msg:%s" % error_msg) 617 618 def mark_test_as_failed(self, test): 619 test_info = self.state_machine.test() 620 if test_info: 621 test_info.test_class = test.class_name 622 test_info.test_name = test.test_name 623 test_info.code = StatusCodes.START.value 624 self.report_result(test_info) 625 test_info.code = StatusCodes.FAILURE.value 626 self.report_result(test_info) 627 self.__done__() 628 629 def mark_test_as_blocked(self, test): 630 test_info = self.state_machine.test() 631 if test_info: 632 test_info.test_class = test.class_name 633 test_info.test_name = test.test_name 634 test_info.num_tests = 1 635 test_info.run_time = 0 636 test_info.code = StatusCodes.START.value 637 self.report_result(test_info) 638 test_info.code = StatusCodes.BLOCKED.value 639 self.report_result(test_info) 640 self.__done__() 641 642 643@Plugin(type=Plugin.PARSER, id=CommonParserType.jsunit) 644class JSUnitParser(IParser): 645 last_line = "" 646 pattern = r"(\d{1,2}-\d{1,2}\s\d{1,2}:\d{1,2}:\d{1,2}\.\d{3}) " 647 648 def __init__(self): 649 self.state_machine = StateRecorder() 650 self.suites_name = "" 651 self.listeners = [] 652 self.expect_tests_dict = dict() 653 self.marked_suite_set = set() 654 self.exclude_list = list() 655 656 def get_listeners(self): 657 return self.listeners 658 659 def __process__(self, lines): 660 if not self.state_machine.suites_is_started(): 661 self.state_machine.trace_logs.extend(lines) 662 for line in lines: 663 self.parse(line) 664 665 def __done__(self): 666 pass 667 668 def parse(self, line): 669 if (self.state_machine.suites_is_started() or line.find( 670 _START_JSUNIT_RUN_MARKER) != -1) and \ 671 line.lower().find(_ACE_LOG_MARKER) != -1: 672 if line.find(_START_JSUNIT_RUN_MARKER) != -1: 673 self.handle_suites_started_tag() 674 elif line.endswith(_END_JSUNIT_RUN_MARKER): 675 self.handle_suites_ended_tag() 676 elif line.find(_START_JSUNIT_SUITE_RUN_MARKER) != -1: 677 self.handle_suite_started_tag(line.strip()) 678 elif line.endswith(_START_JSUNIT_SUITE_END_MARKER): 679 self.handle_suite_ended_tag() 680 elif _PASS_JSUNIT_MARKER in line or _FAIL_JSUNIT_MARKER \ 681 in line or _ERROR_JSUNIT_MARKER in line: 682 self.handle_one_test_tag(line.strip()) 683 self.last_line = line 684 685 def parse_test_description(self, message): 686 pattern = r".*\[(pass|fail|error)\]" 687 year = time.strftime("%Y") 688 match_list = ["app Log:", "JSApp:", "JsApp:", "JSAPP:"] 689 filter_message = "" 690 for keyword in match_list: 691 if keyword in message: 692 filter_message = \ 693 message.split(r"{0}".format(keyword))[1].strip() 694 break 695 end_time = "%s-%s" % \ 696 (year, re.match(self.pattern, message).group().strip()) 697 start_time = "%s-%s" % \ 698 (year, re.match(self.pattern, 699 self.last_line.strip()).group().strip()) 700 start_timestamp = int(time.mktime( 701 time.strptime(start_time, "%Y-%m-%d %H:%M:%S.%f"))) * 1000 + int( 702 start_time.split(".")[-1]) 703 end_timestamp = int(time.mktime( 704 time.strptime(end_time, "%Y-%m-%d %H:%M:%S.%f"))) * 1000 + int( 705 end_time.split(".")[-1]) 706 run_time = end_timestamp - start_timestamp 707 match = re.match(pattern, filter_message) 708 _, status_end_index = match.span() 709 if " ;" in filter_message: 710 test_name = filter_message[status_end_index: 711 str(filter_message).find(" ;")] 712 else: 713 test_name = filter_message[status_end_index:] 714 status_dict = {"pass": ResultCode.PASSED, "fail": ResultCode.FAILED, 715 "ignore": ResultCode.SKIPPED, 716 "error": ResultCode.FAILED} 717 status = status_dict.get(match.group(1)) 718 return test_name.strip(), status, run_time 719 720 def handle_suites_started_tag(self): 721 self.state_machine.get_suites(reset=True) 722 test_suites = self.state_machine.get_suites() 723 test_suites.suites_name = self.suites_name 724 test_suites.test_num = 0 725 for listener in self.get_listeners(): 726 suite_report = copy.copy(test_suites) 727 listener.__started__(LifeCycle.TestSuites, suite_report) 728 729 def handle_suites_ended_tag(self): 730 self._mark_all_test_case() 731 suites = self.state_machine.get_suites() 732 suites.is_completed = True 733 734 for listener in self.get_listeners(): 735 listener.__ended__(LifeCycle.TestSuites, test_result=suites, 736 suites_name=suites.suites_name) 737 738 def handle_one_test_tag(self, message): 739 test_name, status, run_time = \ 740 self.parse_test_description(message) 741 test_suite = self.state_machine.suite() 742 if self.exclude_list: 743 qualified_name = "{}#{}".format(test_suite.suite_name, test_name) 744 if qualified_name in self.exclude_list: 745 LOG.debug("{} will be discard!".format(qualified_name)) 746 test_suite.test_num -= 1 747 return 748 test_result = self.state_machine.test(reset=True) 749 test_result.test_class = test_suite.suite_name 750 test_result.test_name = test_name 751 test_result.run_time = run_time 752 test_result.code = status.value 753 test_result.current = self.state_machine.running_test_index + 1 754 self.state_machine.suite().run_time += run_time 755 for listener in self.get_listeners(): 756 test_result = copy.copy(test_result) 757 listener.__started__(LifeCycle.TestCase, test_result) 758 759 test_suites = self.state_machine.get_suites() 760 found_unexpected_test = False 761 762 if found_unexpected_test or ResultCode.FAILED == status: 763 for listener in self.get_listeners(): 764 result = copy.copy(test_result) 765 listener.__failed__(LifeCycle.TestCase, result) 766 elif ResultCode.SKIPPED == status: 767 for listener in self.get_listeners(): 768 result = copy.copy(test_result) 769 listener.__skipped__(LifeCycle.TestCase, result) 770 771 self.state_machine.test().is_completed = True 772 if not hasattr(test_suite, "total_cases"): 773 test_suite.test_num += 1 774 test_suites.test_num += 1 775 for listener in self.get_listeners(): 776 result = copy.copy(test_result) 777 listener.__ended__(LifeCycle.TestCase, result) 778 self.state_machine.running_test_index += 1 779 780 def fake_run_marker(self, message): 781 fake_marker = re.compile(" +").split(message) 782 self.processTestStartedTag(fake_marker) 783 784 def handle_suite_started_tag(self, message): 785 self.state_machine.suite(reset=True) 786 self.state_machine.running_test_index = 0 787 test_suite = self.state_machine.suite() 788 if "total cases:" in message: 789 m_result = re.match(r".*\[suite start](.+), total cases: (\d+)", 790 message) 791 if m_result: 792 expect_test_num = m_result.group(2) 793 test_suite.suite_name = m_result.group(1) 794 test_suite.test_num = int(expect_test_num) 795 setattr(test_suite, "total_cases", True) 796 797 else: 798 if re.match(r".*\[suite start].*", message): 799 _, index = re.match(r".*\[suite start]", message).span() 800 if message[index:]: 801 test_suite.suite_name = message[index:] 802 else: 803 test_suite.suite_name = self.suite_name 804 test_suite.test_num = 0 805 for listener in self.get_listeners(): 806 suite_report = copy.copy(test_suite) 807 listener.__started__(LifeCycle.TestSuite, suite_report) 808 809 def handle_suite_ended_tag(self): 810 suite_result = self.state_machine.suite() 811 suites = self.state_machine.get_suites() 812 suite_result.run_time = suite_result.run_time 813 suites.run_time += suite_result.run_time 814 suite_result.is_completed = True 815 self._mark_test_case(suite_result, self.get_listeners()) 816 for listener in self.get_listeners(): 817 suite = copy.copy(suite_result) 818 listener.__ended__(LifeCycle.TestSuite, suite, is_clear=True) 819 820 def append_test_output(self, message): 821 if self.state_machine.test().stacktrace: 822 self.state_machine.test().stacktrace = \ 823 "%s\r\n" % self.state_machine.test().stacktrace 824 self.state_machine.test().stacktrace = \ 825 ''.join((self.state_machine.test().stacktrace, message)) 826 827 def _mark_test_case(self, suite, listeners): 828 if not self.expect_tests_dict: 829 return 830 tests_list = [] 831 for listener in listeners: 832 if listener.__class__.__name__ == "ReportListener": 833 tests_list.extend(listener.tests.values()) 834 break 835 test_name_list = [] 836 for item_test in tests_list: 837 test_name_list.append(item_test.test_name) 838 self.marked_suite_set.add(suite.suite_name) 839 test_in_cur = self.expect_tests_dict.get(suite.suite_name, []) 840 for test in test_in_cur: 841 if "{}#{}".format(suite.suite_name, test.test_name) \ 842 in self.exclude_list: 843 suite.test_num -= 1 844 continue 845 if test.test_name not in test_name_list: 846 self._mock_test_case_life_cycle(listeners, test) 847 848 def _mock_test_case_life_cycle(self, listeners, test): 849 test_result = self.state_machine.test(reset=True) 850 test_result.test_class = test.class_name 851 test_result.test_name = test.test_name 852 test_result.stacktrace = "error_msg: mark blocked" 853 test_result.num_tests = 1 854 test_result.run_time = 0 855 test_result.current = self.state_machine.running_test_index + 1 856 test_result.code = ResultCode.BLOCKED.value 857 test_result = copy.copy(test_result) 858 for listener in listeners: 859 listener.__started__(LifeCycle.TestCase, test_result) 860 test_result = copy.copy(test_result) 861 for listener in listeners: 862 listener.__ended__(LifeCycle.TestCase, test_result) 863 self.state_machine.running_test_index += 1 864 865 def _mark_all_test_case(self): 866 if not self.expect_tests_dict: 867 return 868 all_suite_set = set(self.expect_tests_dict.keys()) 869 un_suite_set = all_suite_set.difference(self.marked_suite_set) 870 for un_suite_name in un_suite_set: 871 test_list = self.expect_tests_dict.get(un_suite_name, []) 872 873 self.state_machine.suite(reset=True) 874 self.state_machine.running_test_index = 0 875 test_suite = self.state_machine.suite() 876 test_suite.suite_name = un_suite_name 877 test_suite.test_num = len(test_list) 878 for listener in self.get_listeners(): 879 suite_report = copy.copy(test_suite) 880 listener.__started__(LifeCycle.TestSuite, suite_report) 881 882 for test in test_list: 883 if "{}#{}".format(test_suite.suite_name, test.test_name) \ 884 in self.exclude_list: 885 test_suite.test_num -= 1 886 continue 887 self._mock_test_case_life_cycle(self.get_listeners(), test) 888 889 test_suite.is_completed = True 890 for listener in self.get_listeners(): 891 suite = copy.copy(test_suite) 892 listener.__ended__(LifeCycle.TestSuite, suite, is_clear=True) 893 894 895@Plugin(type=Plugin.PARSER, id=CommonParserType.oh_kernel_test) 896class OHKernelTestParser(IParser): 897 898 def __init__(self): 899 self.state_machine = StateRecorder() 900 self.suites_name = "" 901 self.listeners = [] 902 903 def get_listeners(self): 904 return self.listeners 905 906 def __process__(self, lines): 907 if not self.state_machine.suites_is_started(): 908 self.state_machine.trace_logs.extend(lines) 909 for line in lines: 910 self.parse(line) 911 912 def __done__(self): 913 pass 914 915 def parse(self, line): 916 line = re.sub('\x1b.*?m', '', line) 917 if self.state_machine.suites_is_started() or RUNTEST_TEST in line: 918 if RUNTEST_TEST in line: 919 self.handle_suites_started_tag(line) 920 elif START_TO_TEST in line: 921 self.handle_suite_start_tag(line) 922 elif FINISHED_TO_TEST in line: 923 self.handle_suite_end_tag(line) 924 elif line.endswith(PASS_DOT) or line.endswith(FAIL_DOT): 925 self.handle_one_test_case_tag(line) 926 elif line.endswith(ERROR_EXCLAMATION) \ 927 or line.endswith(TIMEOUT_EXCLAMATION): 928 self.handle_test_case_error(line) 929 elif TIMEOUT_TESTCASES in line: 930 self.handle_suites_ended_tag(line) 931 932 def handle_suites_started_tag(self, line): 933 self.state_machine.get_suites(reset=True) 934 test_suites = self.state_machine.get_suites() 935 test_suites.suites_name = self.suites_name 936 test_suites.test_num = 0 937 for listener in self.get_listeners(): 938 suite_report = copy.copy(test_suites) 939 listener.__started__(LifeCycle.TestSuites, suite_report) 940 941 def handle_suites_ended_tag(self, line): 942 suites = self.state_machine.get_suites() 943 suites.is_completed = True 944 945 for listener in self.get_listeners(): 946 listener.__ended__(LifeCycle.TestSuites, test_result=suites, 947 suites_name=suites.suites_name) 948 949 def handle_suite_start_tag(self, line): 950 pattern = "^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}" \ 951 " Start to test (.+)$" 952 matcher = re.match(pattern, line) 953 if matcher and matcher.group(1): 954 self.state_machine.suite(reset=True) 955 test_suite = self.state_machine.suite() 956 test_suite.suite_name = matcher.group(1) 957 for listener in self.get_listeners(): 958 suite_report = copy.copy(test_suite) 959 listener.__started__(LifeCycle.TestSuite, suite_report) 960 961 def handle_suite_end_tag(self, line): 962 pattern = "^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}" \ 963 " Finished to test (.+)$" 964 matcher = re.match(pattern, line) 965 if matcher and matcher.group(1): 966 suite_result = self.state_machine.suite() 967 suites = self.state_machine.get_suites() 968 suite_result.run_time = suite_result.run_time 969 suites.run_time += suite_result.run_time 970 suite_result.is_completed = True 971 972 for listener in self.get_listeners(): 973 suite = copy.copy(suite_result) 974 listener.__ended__(LifeCycle.TestSuite, suite, is_clear=True) 975 976 def handle_one_test_case_tag(self, line): 977 pattern = "^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} (.+) " \ 978 "(PASS)\\.$" 979 matcher = re.match(pattern, line) 980 if not (matcher and matcher.group(1) and matcher.group(2)): 981 return 982 test_result = self.state_machine.test(reset=True) 983 test_suite = self.state_machine.suite() 984 test_result.test_class = test_suite.suite_name 985 test_result.test_name = matcher.group(1) 986 test_result.current = self.state_machine.running_test_index + 1 987 for listener in self.get_listeners(): 988 test_result = copy.copy(test_result) 989 listener.__started__(LifeCycle.TestCase, test_result) 990 991 test_suites = self.state_machine.get_suites() 992 if PASS_DOT in line: 993 test_result.code = ResultCode.PASSED.value 994 elif FAIL_DOT in line: 995 test_result.code = ResultCode.FAILED.value 996 for listener in self.get_listeners(): 997 result = copy.copy(test_result) 998 listener.__failed__(LifeCycle.TestCase, result) 999 self.state_machine.test().is_completed = True 1000 test_suite.test_num += 1 1001 test_suites.test_num += 1 1002 for listener in self.get_listeners(): 1003 result = copy.copy(test_result) 1004 listener.__ended__(LifeCycle.TestCase, result) 1005 self.state_machine.running_test_index += 1 1006 1007 def handle_test_case_error(self, line): 1008 pattern = "^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} (.+) " \ 1009 "(ERROR!!!|TIMEOUT!)$" 1010 matcher = re.match(pattern, line) 1011 if not (matcher and matcher.group(1) and matcher.group(2)): 1012 return 1013 test_result = self.state_machine.test(reset=True) 1014 test_suite = self.state_machine.suite() 1015 test_result.test_class = test_suite.suite_name 1016 test_result.test_name = matcher.group(1) 1017 test_result.current = self.state_machine.running_test_index + 1 1018 for listener in self.get_listeners(): 1019 test_result = copy.copy(test_result) 1020 listener.__started__(LifeCycle.TestCase, test_result) 1021 1022 test_suites = self.state_machine.get_suites() 1023 if ERROR_EXCLAMATION in line: 1024 test_result.code = ResultCode.FAILED.value 1025 elif TIMEOUT_EXCLAMATION in line: 1026 test_result.code = ResultCode.BLOCKED.value 1027 1028 for listener in self.get_listeners(): 1029 result = copy.copy(test_result) 1030 listener.__failed__(LifeCycle.TestCase, result) 1031 self.state_machine.test().is_completed = True 1032 test_suite.test_num += 1 1033 test_suites.test_num += 1 1034 for listener in self.get_listeners(): 1035 result = copy.copy(test_result) 1036 listener.__ended__(LifeCycle.TestCase, result) 1037 self.state_machine.running_test_index += 1 1038 1039 1040class OHJSUnitPrefixes(Enum): 1041 SUM = "OHOS_REPORT_SUM: " 1042 STATUS = "OHOS_REPORT_STATUS: " 1043 STATUS_CODE = "OHOS_REPORT_STATUS_CODE: " 1044 RESULT = "OHOS_REPORT_RESULT: " 1045 CODE = "OHOS_REPORT_CODE: " 1046 TEST_FINISHED_RESULT_MSG = "TestFinished-ResultMsg: " 1047 1048 1049class OHJSUnitItemConstants(Enum): 1050 CLASS = "class" 1051 TEST = "test" 1052 NUM_TESTS = "numtests" 1053 STACK = "stack" 1054 STREAM = "stream" 1055 SUITE_CONSUMING = "suiteconsuming" 1056 CONSUMING = "consuming" 1057 APP_DIED = "App died" 1058 1059 1060@Plugin(type=Plugin.PARSER, id=CommonParserType.oh_jsunit) 1061class OHJSUnitTestParser(IParser): 1062 1063 def __init__(self): 1064 self.state_machine = StateRecorder() 1065 self.suites_name = "" 1066 self.listeners = [] 1067 self.current_key = None 1068 self.current_value = None 1069 self.start_time = get_cst_time() 1070 self.suite_start_time = get_cst_time() 1071 self.test_time = 0 1072 self.test_run_finished = False 1073 self.cur_sum = -1 1074 self.runner = None 1075 1076 def get_suite_name(self): 1077 return self.suites_name 1078 1079 def get_listeners(self): 1080 return self.listeners 1081 1082 def __process__(self, lines): 1083 for line in lines: 1084 LOG.debug(line) 1085 self.parse(line) 1086 1087 def parse(self, line): 1088 if not str(line).strip(): 1089 return 1090 if line.startswith(OHJSUnitPrefixes.SUM.value): 1091 self.handle_sum_line(line) 1092 elif line.startswith(OHJSUnitPrefixes.STATUS.value): 1093 self.handle_status_line(line) 1094 elif line.startswith(OHJSUnitPrefixes.STATUS_CODE.value): 1095 self.submit_current_key_value() 1096 self.parse_status_code(line) 1097 elif line.startswith(OHJSUnitPrefixes.TEST_FINISHED_RESULT_MSG.value): 1098 self._handle_result_msg(line) 1099 1100 def handle_sum_line(self, line): 1101 value = line[len(OHJSUnitPrefixes.SUM.value):].split("=", 1)[0] 1102 self.cur_sum = int(value) 1103 1104 def handle_status_line(self, line): 1105 self.parse_key(line, len(OHJSUnitPrefixes.STATUS.value)) 1106 if self.cur_sum > 0 and \ 1107 self.current_key == OHJSUnitItemConstants.CLASS.value: 1108 if self.current_value not in self.runner.suite_recorder.keys(): 1109 current_suite = self.state_machine.suite(reset=True) 1110 current_suite.test_num = self.cur_sum 1111 current_suite.suite_name = self.current_value 1112 self.runner.suite_recorder.update({ 1113 self.current_value: 1114 [len(self.runner.suite_recorder.keys()), 1115 current_suite]}) 1116 else: 1117 current_suite = self.runner.suite_recorder.get( 1118 self.current_value)[1] 1119 self.state_machine.current_suite = current_suite 1120 self.cur_sum = -1 1121 self.current_key = None 1122 self.current_value = None 1123 self.state_machine.running_test_index = 0 1124 self.suite_start_time = get_cst_time() 1125 for listener in self.get_listeners(): 1126 suite = copy.copy(current_suite) 1127 listener.__started__(LifeCycle.TestSuite, suite) 1128 1129 else: 1130 if self.current_key == OHJSUnitItemConstants.SUITE_CONSUMING.value: 1131 self.test_time = int(self.current_value) 1132 self.handle_suite_end() 1133 elif self.current_key == OHJSUnitItemConstants.CONSUMING.value: 1134 self.test_time = int(self.current_value) 1135 self.handle_case_end() 1136 else: 1137 self.submit_current_key_value() 1138 self.parse_key(line, len(OHJSUnitPrefixes.STATUS.value)) 1139 1140 def submit_current_key_value(self): 1141 if self.current_key and self.current_value: 1142 status_value = self.current_value 1143 test_info = self.state_machine.test() 1144 if self.current_key == OHJSUnitItemConstants.CLASS.value: 1145 test_info.test_class = status_value 1146 elif self.current_key == OHJSUnitItemConstants.TEST.value: 1147 test_info.test_name = status_value 1148 elif self.current_key == OHJSUnitItemConstants.NUM_TESTS.value: 1149 test_info.num_tests = int(status_value) 1150 elif self.current_key == OHJSUnitItemConstants.STREAM.value: 1151 test_info.stacktrace = status_value 1152 self.current_key = None 1153 self.current_value = None 1154 1155 def parse_key(self, line, key_start_pos): 1156 key_value = line[key_start_pos:].split("=", 1) 1157 if len(key_value) == 2: 1158 self.current_key = key_value[0] 1159 self.current_value = key_value[1] 1160 1161 def parse_status_code(self, line): 1162 value = line[len(OHJSUnitPrefixes.STATUS_CODE.value):] 1163 test_info = self.state_machine.test() 1164 test_info.code = int(value) 1165 if test_info.code != StatusCodes.IN_PROGRESS: 1166 if self.check_legality(test_info.test_class) and \ 1167 self.check_legality(test_info.test_name): 1168 self.report_result(test_info) 1169 1170 def clear_current_test_info(self): 1171 self.state_machine.current_test = None 1172 1173 def report_result(self, test_info): 1174 if not test_info.test_name or not test_info.test_class: 1175 LOG.info("Invalid instrumentation status bundle") 1176 return 1177 if test_info.code == StatusCodes.START.value: 1178 self.start_time = get_cst_time() 1179 for listener in self.get_listeners(): 1180 result = copy.copy(test_info) 1181 listener.__started__(LifeCycle.TestCase, result) 1182 return 1183 if test_info.code == StatusCodes.FAILURE.value: 1184 self.state_machine.running_test_index += 1 1185 test_info.current = self.state_machine.running_test_index 1186 test_info.code = ResultCode.FAILED.value 1187 test_info.run_time = get_delta_time_ms(self.start_time) 1188 elif test_info.code == StatusCodes.ERROR.value: 1189 self.state_machine.running_test_index += 1 1190 test_info.current = self.state_machine.running_test_index 1191 test_info.code = ResultCode.FAILED.value 1192 test_info.run_time = get_delta_time_ms(self.start_time) 1193 elif test_info.code == StatusCodes.SUCCESS.value: 1194 self.state_machine.running_test_index += 1 1195 test_info.current = self.state_machine.running_test_index 1196 test_info.code = ResultCode.PASSED.value 1197 test_info.run_time = get_delta_time_ms(self.start_time) 1198 1199 @classmethod 1200 def output_stack_trace(cls, test_info): 1201 if check_pub_key_exist(): 1202 return 1203 if test_info.stacktrace: 1204 stack_lines = test_info.stacktrace.split(r"\r\n") 1205 LOG.error("Stacktrace information is:") 1206 for line in stack_lines: 1207 line.strip() 1208 if line: 1209 LOG.error(line) 1210 1211 @staticmethod 1212 def check_legality(name): 1213 if not name or name == "null": 1214 return False 1215 return True 1216 1217 def __done__(self): 1218 pass 1219 1220 def handle_case_end(self): 1221 test_info = self.state_machine.test() 1222 if test_info.run_time == 0 or test_info.run_time < self.test_time: 1223 test_info.run_time = self.test_time 1224 for listener in self.get_listeners(): 1225 result = copy.copy(test_info) 1226 result.code = test_info.code 1227 listener.__ended__(LifeCycle.TestCase, result) 1228 if listener.__class__.__name__ == "ReportListener" \ 1229 and self.runner.retry_times > 1: 1230 index = list(listener.tests.keys())[-1] 1231 listener.tests.pop(index) 1232 test_info.is_completed = True 1233 self.clear_current_test_info() 1234 1235 def handle_suite_end(self): 1236 suite_result = self.state_machine.suite() 1237 suite_result.run_time = get_delta_time_ms(self.suite_start_time) 1238 if suite_result.run_time == 0: 1239 suite_result.run_time = self.test_time 1240 suite_result.is_completed = True 1241 for listener in self.get_listeners(): 1242 suite = copy.copy(suite_result) 1243 listener.__ended__(LifeCycle.TestSuite, suite, is_clear=True) 1244 1245 def handle_suites_end(self): 1246 suite_result = self.state_machine.suite() 1247 if not suite_result.is_completed: 1248 self.handle_suite_end() 1249 for listener in self.get_listeners(): 1250 if listener.__class__.__name__ == "ReportListener": 1251 self._cal_result(listener) 1252 suite = copy.copy(suite_result) 1253 listener.__ended__(LifeCycle.TestSuites, suite, 1254 suites_name=self.suites_name) 1255 self.state_machine.current_suite = None 1256 1257 def _cal_result(self, report_listener): 1258 result_len = len(report_listener.result) 1259 suites_len = len(report_listener.suites) 1260 if result_len > suites_len: 1261 diff_result_tuple_list = report_listener.result[suites_len:] 1262 report_listener.result = report_listener.result[:suites_len] 1263 for diff_result_tuple in diff_result_tuple_list: 1264 suite, case_result_list = diff_result_tuple 1265 pos = self.runner.suite_recorder.get(suite.suite_name)[0] 1266 report_listener.result[pos][1].extend(case_result_list) 1267 self._handle_lacking_one_testcase(report_listener) 1268 self._handle_lacking_whole_suite(report_listener) 1269 1270 def _handle_lacking_one_testcase(self, report_listener): 1271 for suite in report_listener.suites.values(): 1272 test_des_list = self.runner.expect_tests_dict.get( 1273 suite.suite_name, []) 1274 pos = self.runner.suite_recorder.get(suite.suite_name)[0] 1275 if len(test_des_list) == len(report_listener.result[pos][1]): 1276 continue 1277 interval = len(test_des_list) - len(report_listener.result[pos][1]) 1278 if len(test_des_list) > 0: 1279 LOG.info("{} tests in {} had missed.".format( 1280 interval, suite.suite_name)) 1281 else: 1282 LOG.info("The count of tests in '{}' is incorrect! {} test " 1283 "form dry run and {} tests have run." 1284 "".format(suite.suite_name, len(test_des_list), 1285 len(report_listener.result[pos][1]))) 1286 for test_des in test_des_list: 1287 is_contain = False 1288 for case in report_listener.result[pos][1]: 1289 if case.test_name == test_des.test_name: 1290 is_contain = True 1291 break 1292 if not is_contain: 1293 test_result = self.state_machine.test(reset=True) 1294 test_result.test_class = test_des.class_name 1295 test_result.test_name = test_des.test_name 1296 test_result.stacktrace = "error_msg:mark blocked" 1297 test_result.num_tests = 1 1298 test_result.run_time = 0 1299 test_result.current = \ 1300 self.state_machine.running_test_index + 1 1301 test_result.code = ResultCode.BLOCKED.value 1302 report_listener.result[pos][1].append(test_result) 1303 LOG.debug("Add {}#{}".format(test_des.class_name, 1304 test_des.test_name)) 1305 1306 def _handle_lacking_whole_suite(self, report_listener): 1307 all_suite_set = set(self.runner.expect_tests_dict.keys()) 1308 un_suite_set = set() 1309 if len(all_suite_set) > len(report_listener.suites): 1310 suite_name_set = set() 1311 for suite in report_listener.suites.values(): 1312 suite_name_set.add(suite.suite_name) 1313 un_suite_set = all_suite_set.difference(suite_name_set) 1314 if un_suite_set: 1315 LOG.info("{} suites have missed.".format(len(un_suite_set))) 1316 for name in un_suite_set: 1317 self.state_machine.running_test_index = 0 1318 test_des_list = self.runner.expect_tests_dict.get( 1319 name, []) 1320 current_suite = self.state_machine.suite(reset=True) 1321 current_suite.test_num = len(test_des_list) 1322 current_suite.suite_name = name 1323 for listener in self.get_listeners(): 1324 suite = copy.copy(current_suite) 1325 listener.__started__(LifeCycle.TestSuite, suite) 1326 1327 for test in test_des_list: 1328 test_result = self.state_machine.test(reset=True) 1329 test_result.test_class = test.class_name 1330 test_result.test_name = test.test_name 1331 test_result.stacktrace = "error_msg:mark blocked" 1332 test_result.num_tests = 1 1333 test_result.run_time = 0 1334 test_result.current = self.state_machine.running_test_index + 1 1335 test_result.code = ResultCode.BLOCKED.value 1336 test_result = copy.copy(test_result) 1337 for listener in self.get_listeners(): 1338 listener.__started__(LifeCycle.TestCase, test_result) 1339 test_result = copy.copy(test_result) 1340 for listener in self.get_listeners(): 1341 listener.__ended__(LifeCycle.TestCase, test_result) 1342 self.state_machine.running_test_index += 1 1343 current_suite.run_time = self.test_time 1344 current_suite.is_completed = True 1345 for listener in self.get_listeners(): 1346 suite = copy.copy(current_suite) 1347 listener.__ended__(LifeCycle.TestSuite, suite, is_clear=True) 1348 1349 def notify_task_finished(self): 1350 self.handle_suites_end() 1351 1352 def _handle_result_msg(self, line): 1353 if OHJSUnitItemConstants.APP_DIED.value in line: 1354 test_result = self.state_machine.test() 1355 suite = self.state_machine.suite() 1356 if not test_result.is_completed: 1357 if self.check_legality(test_result.test_class) and \ 1358 self.check_legality(test_result.test_name): 1359 self.report_result(test_result) 1360 self.clear_current_test_info() 1361 if not suite.is_completed: 1362 self.handle_suite_end() 1363 1364 1365@Plugin(type=Plugin.PARSER, id=CommonParserType.oh_jsunit_list) 1366class OHJSUnitTestListParser(IParser): 1367 1368 def __init__(self): 1369 self.tests = [] 1370 self.json_str = "" 1371 self.tests_dict = dict() 1372 self.result_data = "" 1373 1374 def __process__(self, lines): 1375 for line in lines: 1376 self.result_data = "{}{}".format(self.result_data, line) 1377 self.parse(line) 1378 1379 def __done__(self): 1380 LOG.debug("OHJSUnitTestListParser data:") 1381 LOG.debug(self.result_data) 1382 self.result_data = "" 1383 1384 def parse(self, line): 1385 if "{" in line or "}" in line: 1386 self.json_str = "%s%s" % (self.json_str, line) 1387 return 1388 if "dry run finished" in line: 1389 suite_dict_list = json.loads(self.json_str).get("suites", []) 1390 for suite_dict in suite_dict_list: 1391 for class_name, test_name_dict_list in suite_dict.items(): 1392 self.tests_dict.update({class_name.strip(): []}) 1393 for test_name_dict in test_name_dict_list: 1394 for test_name in test_name_dict.values(): 1395 test = TestDescription(class_name.strip(), 1396 test_name.strip()) 1397 self.tests_dict.get( 1398 class_name.strip()).append(test) 1399 self.tests.append(test) 1400 1401 1402@Plugin(type=Plugin.PARSER, id=CommonParserType.oh_rust) 1403class OHRustTestParser(IParser): 1404 1405 def __init__(self): 1406 self.test_pattern = "test (?:tests::)?(.+) ... (ok|FAILED)" 1407 self.stout_pattern = "---- tests::(.+) stdout ----" 1408 self.running_pattern = "running (\\d+) test|tests" 1409 self.test_result_pattern = "test result: (ok|FAILED)\\..+finished in (.+)s" 1410 self.suite_name = "" 1411 self.result_list = list() 1412 self.stdout_list = list() 1413 self.failures_stdout = list() 1414 self.cur_fail_case = "" 1415 self.state_machine = StateRecorder() 1416 self.listeners = [] 1417 1418 def get_listeners(self): 1419 return self.listeners 1420 1421 def __process__(self, lines): 1422 for line in lines: 1423 LOG.debug(line) 1424 self.parse(line) 1425 1426 def __done__(self): 1427 self.handle_suite_end() 1428 1429 def parse(self, line): 1430 if line.startswith("running"): 1431 matcher = re.match(self.running_pattern, line) 1432 if not (matcher and matcher.group(1)): 1433 return 1434 self.handle_suite_start(matcher) 1435 elif line.startswith("test result:"): 1436 matcher = re.match(self.test_result_pattern, line) 1437 if not (matcher and matcher.group(2)): 1438 return 1439 self.handle_case_lifecycle(matcher) 1440 1441 elif "..." in line: 1442 matcher = re.match(self.test_pattern, line) 1443 if not (matcher and matcher.group(1) and matcher.group(2)): 1444 return 1445 self.collect_case(matcher) 1446 elif line.startswith("---- tests::"): 1447 matcher = re.match(self.stout_pattern, line) 1448 if not (matcher and matcher.group(1)): 1449 return 1450 self.cur_fail_case = matcher.group(1) 1451 else: 1452 if self.cur_fail_case: 1453 self.handle_stdout(line) 1454 1455 def handle_case_lifecycle(self, matcher): 1456 cost_time = matcher.group(2) 1457 for test_result in self.result_list: 1458 if test_result.code == ResultCode.FAILED.value: 1459 if self.stdout_list and \ 1460 self.stdout_list[0][0] == test_result.test_name: 1461 test_result.stacktrace = self.stdout_list[0][1] 1462 self.stdout_list.pop(0) 1463 test_result.current = self.state_machine.running_test_index + 1 1464 for listener in self.get_listeners(): 1465 test_result = copy.copy(test_result) 1466 listener.__started__(LifeCycle.TestCase, test_result) 1467 for listener in self.get_listeners(): 1468 result = copy.copy(test_result) 1469 listener.__ended__(LifeCycle.TestCase, result) 1470 test_suite = self.state_machine.suite() 1471 test_suite.run_time = float(cost_time) * 1000 1472 1473 def handle_stdout(self, line): 1474 if line.strip(): 1475 self.failures_stdout.append(line.strip()) 1476 else: 1477 self.stdout_list.append((self.cur_fail_case, 1478 " ".join(self.failures_stdout))) 1479 self.cur_fail_case = "" 1480 self.failures_stdout.clear() 1481 1482 def collect_case(self, matcher): 1483 test_result = self.state_machine.test(reset=True) 1484 test_result.test_class = self.suite_name 1485 test_result.test_name = matcher.group(1) 1486 test_result.code = ResultCode.PASSED.value if \ 1487 matcher.group(2) == "ok" else ResultCode.FAILED.value 1488 self.result_list.append(test_result) 1489 1490 def handle_suite_start(self, matcher): 1491 self.state_machine.suite(reset=True) 1492 test_suite = self.state_machine.suite() 1493 test_suite.suite_name = self.suite_name 1494 test_suite.test_num = int(matcher.group(1)) 1495 for listener in self.get_listeners(): 1496 suite_report = copy.copy(test_suite) 1497 listener.__started__(LifeCycle.TestSuite, suite_report) 1498 1499 def handle_suite_end(self): 1500 suite_result = self.state_machine.suite() 1501 suite_result.run_time += suite_result.run_time 1502 suite_result.is_completed = True 1503 for listener in self.get_listeners(): 1504 suite = copy.copy(suite_result) 1505 listener.__ended__(LifeCycle.TestSuite, suite, suite_report=True) 1506 1507 1508@Plugin(type=Plugin.PARSER, id=CommonParserType.oh_yara) 1509class OHYaraTestParser(IParser): 1510 last_line = "" 1511 pattern = r"(\d{1,2}-\d{1,2}\s\d{1,2}:\d{1,2}:\d{1,2}\.\d{3}) " 1512 1513 def __init__(self): 1514 self.state_machine = StateRecorder() 1515 self.suites_name = "" 1516 self.vul_items = None 1517 self.listeners = [] 1518 1519 def get_listeners(self): 1520 return self.listeners 1521 1522 def __process__(self, lines): 1523 self.parse(lines) 1524 1525 def __done__(self): 1526 pass 1527 1528 def parse(self, lines): 1529 for line in lines: 1530 if line: 1531 self.handle_suites_started_tag() 1532 self.handle_suite_started_tag() 1533 self.handle_one_test_tag(line) 1534 self.handle_suite_ended_tag() 1535 self.handle_suites_ended_tag() 1536 1537 def handle_suites_started_tag(self): 1538 self.state_machine.get_suites(reset=True) 1539 test_suites = self.state_machine.get_suites() 1540 test_suites.suites_name = self.suites_name 1541 test_suites.test_num = len(self.vul_items) 1542 for listener in self.get_listeners(): 1543 suite_report = copy.copy(test_suites) 1544 listener.__started__(LifeCycle.TestSuites, suite_report) 1545 1546 def handle_suites_ended_tag(self): 1547 suites = self.state_machine.get_suites() 1548 suites.is_completed = True 1549 for listener in self.get_listeners(): 1550 listener.__ended__(LifeCycle.TestSuites, test_result=suites, 1551 suites_name=suites.suites_name) 1552 1553 def handle_one_test_tag(self, message): 1554 status_dict = {"pass": ResultCode.PASSED, "fail": ResultCode.FAILED, 1555 "block": ResultCode.BLOCKED} 1556 message = message.strip().split("|") 1557 test_name = message[0] 1558 status = status_dict.get(message[3]) 1559 trace = message[6] if message[3] else "" 1560 run_time = 0 1561 test_suite = self.state_machine.suite() 1562 test_result = self.state_machine.test(reset=True) 1563 test_result.test_class = test_suite.suite_name 1564 test_result.test_name = test_name 1565 test_result.run_time = run_time 1566 test_result.code = status.value 1567 test_result.stacktrace = trace 1568 test_result.current = self.state_machine.running_test_index + 1 1569 self.state_machine.suite().run_time += run_time 1570 for listener in self.get_listeners(): 1571 test_result = copy.copy(test_result) 1572 listener.__started__(LifeCycle.TestCase, test_result) 1573 1574 test_suites = self.state_machine.get_suites() 1575 self.state_machine.test().is_completed = True 1576 test_suites.test_num += 1 1577 for listener in self.get_listeners(): 1578 result = copy.copy(test_result) 1579 listener.__ended__(LifeCycle.TestCase, result) 1580 self.state_machine.running_test_index += 1 1581 1582 def handle_suite_started_tag(self): 1583 self.state_machine.suite(reset=True) 1584 self.state_machine.running_test_index = 0 1585 test_suite = self.state_machine.suite() 1586 test_suite.suite_name = self.suites_name 1587 test_suite.test_num = 1 1588 for listener in self.get_listeners(): 1589 suite_report = copy.copy(test_suite) 1590 listener.__started__(LifeCycle.TestSuite, suite_report) 1591 1592 def handle_suite_ended_tag(self): 1593 suite_result = self.state_machine.suite() 1594 suites = self.state_machine.get_suites() 1595 suite_result.run_time = suite_result.run_time 1596 suites.run_time += suite_result.run_time 1597 suite_result.is_completed = True 1598 for listener in self.get_listeners(): 1599 suite = copy.copy(suite_result) 1600 listener.__ended__(LifeCycle.TestSuite, suite, is_clear=True)