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