• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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