• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# coding=utf-8
3
4#
5# Copyright (c) 2020-2021 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 time
22import datetime
23from queue import Queue
24
25from _core.interface import IParser
26from _core.plugin import Plugin
27from _core.constants import ParserType
28from _core.executor.listener import StateRecorder
29from _core.executor.listener import TestDescription
30from _core.interface import LifeCycle
31from _core.report.suite_reporter import ResultCode
32from _core.logger import platform_logger
33from _core.report.encrypt import check_pub_key_exist
34
35__all__ = ["CppTestListParserLite", "CTestParser", "OpenSourceParser",
36           "CppTestParserLite", "ShellHandler"]
37
38_INFORMATIONAL_START = "[----------]"
39_TEST_START_RUN_TAG = "[==========] Running"
40_TEST_RUN_TAG = "[==========]"
41_CPP_TEST_DRYRUN_TAG = "Running main() "
42_TEST_START_TAG = "[ RUN      ]"
43_TEST_OK_TAG = "[       OK ]"
44_TEST_SKIPPED_TAG = "[  SKIPPED ]"
45_TEST_FAILED_TAG = "[  FAILED  ]"
46_ALT_OK_TAG = "[    OK    ]"
47_TIMEOUT_TAG = "[ TIMEOUT  ]"
48
49_CTEST_START_TEST_RUN_TAG = "Framework inited."
50_CTEST_END_TEST_RUN_TAG = "Framework finished."
51_CTEST_SUITE_TEST_RUN_TAG = "Start to run test suite:"
52_CTEST_SUITE_TIME_RUN_TAG = "Run test suite "
53_CTEST_SETUP_TAG = "setup"
54_CTEST_RUN_TAG = "-----------------------"
55
56_TEST_PASSED_LOWER = "pass"
57
58_COMPILE_PASSED = "compile PASSED"
59_COMPILE_PARA = r"(.* compile .*)"
60
61_PRODUCT_PARA = r"(.*The .* is .*)"
62_PRODUCT_PARA_START = r"To Obtain Product Params Start"
63_PRODUCT_PARA_END = r"To Obtain Product Params End"
64
65_START_JSUNIT_RUN_MARKER = "[start] start run suites"
66_START_JSUNIT_SUITE_RUN_MARKER = "[suite start]"
67_START_JSUNIT_SUITE_END_MARKER = "[suite end]"
68_END_JSUNIT_RUN_MARKER = "[end] run suites end"
69_PASS_JSUNIT_MARKER = "[%s]" % "pass"
70_FAIL_JSUNIT_MARKER = "[fail]"
71_ACE_LOG_MARKER = "[Console Info]"
72
73LOG = platform_logger("ParserLite")
74
75
76@Plugin(type=Plugin.PARSER, id=ParserType.cpp_test_lite)
77class CppTestParserLite(IParser):
78    def __init__(self):
79        self.state_machine = StateRecorder()
80        self.suite_name = ""
81        self.listeners = []
82        self.product_info = {}
83        self.is_params = False
84
85    def get_suite_name(self):
86        return self.suite_name
87
88    def get_listeners(self):
89        return self.listeners
90
91    def __process__(self, lines):
92        if not self.state_machine.suites_is_started():
93            self.state_machine.trace_logs.extend(lines)
94        for line in lines:
95            if not check_pub_key_exist():
96                LOG.debug(line)
97            self.parse(line)
98
99    def __done__(self):
100        suite_result = self.state_machine.suite()
101        suite_result.is_completed = True
102        for listener in self.get_listeners():
103            suite = copy.copy(suite_result)
104            listener.__ended__(LifeCycle.TestSuite, suite, is_clear=True)
105        self.state_machine.running_test_index = 0
106
107        suites_result = self.state_machine.get_suites()
108        if not suites_result.suites_name:
109            return
110        for listener in self.get_listeners():
111            suites = copy.copy(suites_result)
112            listener.__ended__(LifeCycle.TestSuites, test_result=suites,
113                               suites_name=suites.suites_name,
114                               product_info=suites.product_info)
115        self.state_machine.current_suites = None
116
117    @staticmethod
118    def _is_test_run(line):
119        return True if _TEST_RUN_TAG in line else False
120
121    @staticmethod
122    def _is_test_start_run(line):
123        return True if _TEST_START_RUN_TAG in line else False
124
125    @staticmethod
126    def _is_informational_start(line):
127        return True if _INFORMATIONAL_START in line else False
128
129    @staticmethod
130    def _is_test_start(line):
131        return True if _TEST_START_TAG in line else False
132
133    def _process_informational_line(self, line):
134        pattern = r"(.*) (\(\d+ ms total\))"
135        message = line[len(_INFORMATIONAL_START):].strip()
136        if re.match(pattern, line.strip()):
137            self.handle_suite_ended_tag(message)
138        elif re.match(r'(\d+) test[s]? from (.*)', message):
139            self.handle_suite_started_tag(message)
140
141    def _process_test_run_line(self, line):
142        if not self.state_machine.suites_is_running():
143            return
144        message = line[len(_TEST_RUN_TAG):].strip()
145        self.handle_suites_ended_tag(message)
146
147    def parse(self, line):
148        if _PRODUCT_PARA_START in line:
149            self.is_params = True
150        elif _PRODUCT_PARA_END in line:
151            self.is_params = False
152        if re.match(_PRODUCT_PARA, line) and self.is_params:
153            handle_product_info(line, self.product_info)
154
155        if self.state_machine.suites_is_started() or self._is_test_run(line):
156            if self._is_test_start_run(line):
157                self.handle_suites_started_tag(line)
158            elif self._is_informational_start(line):
159                self._process_informational_line(line)
160            elif self._is_test_run(line):
161                self._process_test_run_line(line)
162            elif self._is_test_start(line):
163                message = line[line.index(_TEST_START_TAG) +
164                               len(_TEST_START_TAG):].strip()
165                self.handle_test_started_tag(message)
166            else:
167                self.process_test(line)
168
169    def process_test(self, line):
170        if _TEST_SKIPPED_TAG in line:
171            message = line[line.index(_TEST_SKIPPED_TAG) + len(
172                _TEST_SKIPPED_TAG):].strip()
173            if not self.state_machine.test_is_running():
174                LOG.error(
175                    "Found {} without {} before, wrong GTest log format".
176                        format(line, _TEST_START_TAG), error_no="00405")
177                return
178            self.handle_test_ended_tag(message, ResultCode.SKIPPED)
179        elif _TEST_OK_TAG in line:
180            message = line[line.index(_TEST_OK_TAG) + len(
181                _TEST_OK_TAG):].strip()
182            if not self.state_machine.test_is_running():
183                LOG.error(
184                    "Found {} without {} before, wrong GTest log format".
185                        format(line, _TEST_START_TAG), error_no="00405")
186                return
187            self.handle_test_ended_tag(message, ResultCode.PASSED)
188        elif _ALT_OK_TAG in line:
189            message = line[line.index(_ALT_OK_TAG) + len(
190                _ALT_OK_TAG):].strip()
191            self.fake_run_marker(message)
192            self.handle_test_ended_tag(message, ResultCode.PASSED)
193        elif _TEST_FAILED_TAG in line:
194            message = line[line.index(_TEST_FAILED_TAG) + len(
195                _TEST_FAILED_TAG):].strip()
196            if not self.state_machine.suite_is_running():
197                return
198            if not self.state_machine.test_is_running():
199                self.fake_run_marker(message)
200            self.handle_test_ended_tag(message, ResultCode.FAILED)
201        elif _TIMEOUT_TAG in line:
202            message = line[line.index(_TIMEOUT_TAG) + len(
203                _TIMEOUT_TAG):].strip()
204            self.fake_run_marker(message)
205            self.handle_test_ended_tag(message, ResultCode.FAILED)
206        elif self.state_machine.test_is_running():
207            self.append_test_output(line)
208
209    def handle_test_started_tag(self, message):
210        test_class, test_name, _ = self.parse_test_description(message)
211        test_result = self.state_machine.test(reset=True)
212        test_result.test_class = test_class
213        test_result.test_name = test_name
214        for listener in self.get_listeners():
215            test_result = copy.copy(test_result)
216            listener.__started__(LifeCycle.TestCase, test_result)
217
218    @classmethod
219    def parse_test_description(cls, message):
220        run_time = 0
221        matcher = re.match(r'(.*) \((\d+) ms\)(.*)', message)
222        if matcher:
223            test_class, test_name = matcher.group(1).rsplit(".", 1)
224            run_time = int(matcher.group(2))
225        else:
226            test_class, test_name = message.rsplit(".", 1)
227        return test_class.split(" ")[-1], test_name.split(" ")[0], run_time
228
229    def handle_test_ended_tag(self, message, test_status):
230        test_class, test_name, run_time = self.parse_test_description(
231            message)
232        test_result = self.state_machine.test()
233        test_result.run_time = int(run_time)
234        test_result.code = test_status.value
235        if not test_result.is_running():
236            LOG.error(
237                "Test has no start tag when trying to end test: %s", message,
238                error_no="00405")
239            return
240        found_unexpected_test = False
241        if test_result.test_class != test_class:
242            LOG.error(
243                "Expected class: {} but got:{} ".format(test_result.test_class,
244                                                        test_class),
245                error_no="00405")
246            found_unexpected_test = True
247        if test_result.test_name != test_name:
248            LOG.error(
249                "Expected test: {} but got: {}".format(test_result.test_name,
250                                                       test_name),
251                error_no="00405")
252            found_unexpected_test = True
253        test_result.current = self.state_machine.running_test_index + 1
254        self.state_machine.test().is_completed = True
255        if found_unexpected_test:
256            test_result.code = ResultCode.FAILED.value
257
258        for listener in self.get_listeners():
259            result = copy.copy(test_result)
260            listener.__ended__(LifeCycle.TestCase, result)
261        self.state_machine.running_test_index += 1
262
263    def fake_run_marker(self, message):
264        fake_marker = re.compile(" +").split(message)
265        self.handle_test_started_tag(fake_marker)
266
267    def handle_suites_started_tag(self, message):
268        self.state_machine.get_suites(reset=True)
269        matcher = re.match(r'.* Running (\d+) test[s]? from .*', message)
270        expected_test_num = int(matcher.group(1)) if matcher else -1
271        if expected_test_num >= 0:
272            test_suites = self.state_machine.get_suites()
273            test_suites.suites_name = self.get_suite_name()
274            test_suites.test_num = expected_test_num
275            test_suites.product_info = self.product_info
276            for listener in self.get_listeners():
277                suite_report = copy.copy(test_suites)
278                listener.__started__(LifeCycle.TestSuites, suite_report)
279
280    def handle_suite_started_tag(self, message):
281        self.state_machine.suite(reset=True)
282        matcher = re.match(r'(\d+) test[s]? from (.*)', message)
283        expected_test_num = int(matcher.group(1)) if matcher else -1
284        if expected_test_num >= 0:
285            test_suite = self.state_machine.suite()
286            test_suite.suite_name = matcher.group(2)
287            test_suite.test_num = expected_test_num
288            for listener in self.get_listeners():
289                suite_report = copy.copy(test_suite)
290                listener.__started__(LifeCycle.TestSuite, suite_report)
291
292    def handle_suite_ended_tag(self, message):
293        suite_result = self.state_machine.suite()
294        matcher = re.match(r'.*\((\d+) ms total\)', message)
295        if matcher:
296            suite_result.run_time = int(matcher.group(1))
297        suite_result.is_completed = True
298        for listener in self.get_listeners():
299            suite = copy.copy(suite_result)
300            listener.__ended__(LifeCycle.TestSuite, suite, is_clear=True)
301        self.state_machine.running_test_index = 0
302
303    def handle_suites_ended_tag(self, message):
304        suites = self.state_machine.get_suites()
305        matcher = re.match(r'.*\((\d+) ms total\)', message)
306        if matcher:
307            suites.run_time = int(matcher.group(1))
308        suites.is_completed = True
309        for listener in self.get_listeners():
310            copy_suites = copy.copy(suites)
311            listener.__ended__(LifeCycle.TestSuites, test_result=copy_suites,
312                               suites_name=suites.suites_name,
313                               product_info=suites.product_info)
314
315    def append_test_output(self, message):
316        if self.state_machine.test().stacktrace:
317            self.state_machine.test().stacktrace = "{}\r\n".format(
318                self.state_machine.test().stacktrace)
319        self.state_machine.test().stacktrace = "{}{}".format(
320            self.state_machine.test().stacktrace, message)
321
322    @staticmethod
323    def handle_test_run_failed(error_msg):
324        if not error_msg:
325            error_msg = "Unknown error"
326        if not check_pub_key_exist():
327            LOG.debug("Error msg:%s" % error_msg)
328
329    def mark_test_as_failed(self, test):
330        if not self.state_machine.current_suite and not test.class_name:
331            return
332        suites_result = self.state_machine.get_suites(reset=True)
333        suites_result.suites_name = self.get_suite_name()
334
335        suite_name = self.state_machine.current_suite.suite_name if \
336            self.state_machine.current_suite else None
337        suite_result = self.state_machine.suite(reset=True)
338        test_result = self.state_machine.test(reset=True)
339        suite_result.suite_name = suite_name or test.class_name
340        suite_result.suite_num = 1
341        test_result.test_class = test.class_name
342        test_result.test_name = test.test_name
343        test_result.stacktrace = "error_msg: Unknown error"
344        test_result.num_tests = 1
345        test_result.run_time = 0
346        test_result.code = ResultCode.FAILED.value
347        for listener in self.get_listeners():
348            suite_report = copy.copy(suites_result)
349            listener.__started__(LifeCycle.TestSuites, suite_report)
350        for listener in self.get_listeners():
351            suite_report = copy.copy(suite_result)
352            listener.__started__(LifeCycle.TestSuite, suite_report)
353        for listener in self.get_listeners():
354            test_result = copy.copy(test_result)
355            listener.__started__(LifeCycle.TestCase, test_result)
356        for listener in self.get_listeners():
357            test_result = copy.copy(test_result)
358            listener.__ended__(LifeCycle.TestCase, test_result)
359        for listener in self.get_listeners():
360            suite_report = copy.copy(suite_result)
361            listener.__ended__(LifeCycle.TestSuite, suite_report,
362                               is_clear=True)
363        self.__done__()
364
365
366@Plugin(type=Plugin.PARSER, id=ParserType.cpp_test_list_lite)
367class CppTestListParserLite(IParser):
368    def __init__(self):
369        self.last_test_class_name = None
370        self.state_machine = StateRecorder()
371        self.listeners = []
372        self.tests = []
373        self.suites_name = ""
374        self.class_result = None
375        self.method_result = None
376
377    def __process__(self, lines):
378        for line in lines:
379            if not check_pub_key_exist():
380                LOG.debug(line)
381            self.parse(line)
382
383    def get_suite_name(self):
384        return self.suites_name
385
386    def get_listeners(self):
387        return self.listeners
388
389    def __done__(self):
390        if self.state_machine.is_started():
391            self.handle_suite_ended_tag()
392        suites_result = self.state_machine.get_suites()
393        if not suites_result.suites_name:
394            return
395        for listener in self.get_listeners():
396            suites = copy.copy(suites_result)
397            listener.__ended__(LifeCycle.TestSuites, test_result=suites,
398                               suites_name=suites.suites_name)
399        self.state_machine.current_suites = None
400
401    def _is_class(self, line):
402        self.class_result = re.compile('^([a-zA-Z]+.*)\\.$').match(line)
403        return self.class_result
404
405    def _is_method(self, line):
406        self.method_result = re.compile(
407            '\\s+([a-zA-Z_]+[\\S]*)(.*)?(\\s+.*)?$').match(line)
408        return self.method_result
409
410    def _process_class_line(self, line):
411        del line
412        if not self.state_machine.suites_is_started():
413            self.handle_suites_started_tag()
414        self.last_test_class_name = self.class_result.group(1)
415        if self.state_machine.is_started():
416            self.handle_suite_ended_tag()
417        self.handle_suite_started_tag(self.class_result.group(1))
418
419    def _process_method_line(self, line):
420        if not self.last_test_class_name:
421            LOG.error(
422                "Parsed new test case name %s but no test class"
423                " name has been set" % line, error_no="00405")
424        else:
425            test = TestDescription(self.last_test_class_name,
426                                   self.method_result.group(1))
427            self.tests.append(test)
428            self.handle_test_tag(self.last_test_class_name,
429                                 self.method_result.group(1))
430
431    @staticmethod
432    def _is_cpp_test_dryrun(line):
433        return True if line.find(_CPP_TEST_DRYRUN_TAG) != -1 else False
434
435    def parse(self, line):
436        if self.state_machine.suites_is_started() or self._is_cpp_test_dryrun(
437                line):
438            if self._is_cpp_test_dryrun(line):
439                self.handle_suites_started_tag()
440            elif self._is_class(line):
441                self._process_class_line(line)
442            elif self._is_method(line):
443                self._process_method_line(line)
444            else:
445                if not check_pub_key_exist():
446                    LOG.debug("Line ignored: %s" % line)
447
448    def handle_test_tag(self, test_class, test_name):
449        test_result = self.state_machine.test(reset=True)
450        test_result.test_class = test_class
451        test_result.test_name = test_name
452        for listener in self.get_listeners():
453            test_result = copy.copy(test_result)
454            listener.__started__(LifeCycle.TestCase, test_result)
455        self.state_machine.test().is_completed = True
456        test_result.code = ResultCode.SKIPPED.value
457        for listener in self.get_listeners():
458            result = copy.copy(test_result)
459            listener.__ended__(LifeCycle.TestCase, result)
460        self.state_machine.running_test_index += 1
461        test_suites = self.state_machine.get_suites()
462        test_suite = self.state_machine.suite()
463        test_suites.test_num += 1
464        test_suite.test_num += 1
465
466    def handle_suites_started_tag(self):
467        self.state_machine.get_suites(reset=True)
468        test_suites = self.state_machine.get_suites()
469        test_suites.suites_name = self.get_suite_name()
470        test_suites.test_num = 0
471        for listener in self.get_listeners():
472            suite_report = copy.copy(test_suites)
473            listener.__started__(LifeCycle.TestSuites, suite_report)
474
475    def handle_suite_started_tag(self, class_name):
476        self.state_machine.suite(reset=True)
477        test_suite = self.state_machine.suite()
478        test_suite.suite_name = class_name
479        test_suite.test_num = 0
480        for listener in self.get_listeners():
481            test_suite_copy = copy.copy(test_suite)
482            listener.__started__(LifeCycle.TestSuite, test_suite_copy)
483
484    def handle_suite_ended_tag(self):
485        suite_result = self.state_machine.suite()
486        suite_result.is_completed = True
487        for listener in self.get_listeners():
488            suite = copy.copy(suite_result)
489            listener.__ended__(LifeCycle.TestSuite, suite)
490
491    def handle_suites_ended_tag(self):
492        suites = self.state_machine.get_suites()
493        suites.is_completed = True
494        for listener in self.get_listeners():
495            copy_suites = copy.copy(suites)
496            listener.__ended__(LifeCycle.TestSuites, test_result=copy_suites,
497                               suites_name=suites.suites_name)
498
499    def mark_test_as_failed(self, test):
500        if not self.state_machine.current_suite and not test.class_name:
501            return
502        suite_name = self.state_machine.current_suite.suite_name if \
503            self.state_machine.current_suite else None
504        suite_result = self.state_machine.suite(reset=True)
505        test_result = self.state_machine.test(reset=True)
506        suite_result.suite_name = suite_name or test.class_name
507        suite_result.suite_num = 1
508        test_result.test_class = test.class_name
509        test_result.test_name = test.test_name
510        test_result.stacktrace = "error_msg: Unknown error"
511        test_result.num_tests = 1
512        test_result.run_time = 0
513        test_result.code = ResultCode.FAILED.value
514        for listener in self.get_listeners():
515            suite_report = copy.copy(suite_result)
516            listener.__started__(LifeCycle.TestSuite, suite_report)
517        for listener in self.get_listeners():
518            test_result = copy.copy(test_result)
519            listener.__started__(LifeCycle.TestCase, test_result)
520        for listener in self.get_listeners():
521            test_result = copy.copy(test_result)
522            listener.__ended__(LifeCycle.TestCase, test_result)
523        self.__done__()
524
525
526@Plugin(type=Plugin.PARSER, id=ParserType.ctest_lite)
527class CTestParser(IParser):
528    last_line = ""
529    pattern = r"(\d{4}-\d{1,2}-\d{1,2}\s\d{1,2}:\d{1,2}:\d{1,2}\.\d{3}) "
530
531    def __init__(self):
532        self.state_machine = StateRecorder()
533        self.suites_name = ""
534        self.listeners = []
535        self.product_info = {}
536        self.is_params = False
537        self.result_lines = []
538
539    def get_suite_name(self):
540        return self.suites_name
541
542    def get_listeners(self):
543        return self.listeners
544
545    def __process__(self, lines):
546        if not self.state_machine.suites_is_started():
547            self.state_machine.trace_logs.extend(lines)
548        for line in lines:
549            self.parse(line)
550
551    def __done__(self):
552        suites = self.state_machine.get_suites()
553        suites.is_completed = True
554
555        for listener in self.get_listeners():
556            listener.__ended__(LifeCycle.TestSuites, test_result=suites,
557                               suites_name=suites.suites_name,
558                               product_info=suites.product_info)
559        self.state_machine.current_suites = None
560
561    @staticmethod
562    def _is_ctest_start_test_run(line):
563        return True if line.endswith(_CTEST_START_TEST_RUN_TAG) else False
564
565    @staticmethod
566    def _is_ctest_end_test_run(line):
567        return True if line.endswith(_CTEST_END_TEST_RUN_TAG) else False
568
569    @staticmethod
570    def _is_ctest_run(line):
571        return re.match(r".*(\d+ Tests \d+ Failures \d+ Ignored).*", line)
572
573    def _is_ctest_suite_test_run(self, line):
574        return re.match("{}{}".format(self.pattern, _CTEST_SUITE_TEST_RUN_TAG),
575                        line)
576
577    def is_ctest_suite_time_run(self, line):
578        return re.match("{}{}".format(self.pattern, _CTEST_SUITE_TIME_RUN_TAG),
579                        line)
580
581    def _process_ctest_suite_test_run_line(self, line):
582        _, message_index = re.match(
583            "{}{}".format(self.pattern, _CTEST_SUITE_TEST_RUN_TAG),
584            line).span()
585        self.handle_suite_started_tag(line[message_index:].strip())
586
587    @staticmethod
588    def _is_execute_result_line(line):
589        return re.match(
590            r"(.*" + "\\.c:" + "\\d+:.*:(PASS|FAIL|OK|IGNORE"")\\.*)",
591            line.strip())
592
593    @staticmethod
594    def _is_result_line(line):
595        return line.find("PASS") != -1 or line.find("FAIL") != -1 or line.find(
596            "IGNORE") != -1
597
598    def parse(self, line):
599        self._parse_product_info(line)
600
601        if self.state_machine.suites_is_started() or \
602                self._is_ctest_start_test_run(line):
603            try:
604                test_matcher = re.match(r".*(\d+ Tests).+", line)
605                other_matcher = \
606                    re.match(r".*(\d+ Failures \d+ Ignored).*",line)
607                if (test_matcher or other_matcher) and \
608                        not self._is_ctest_run(line):
609                    if test_matcher:
610                        self.result_lines.append(test_matcher.group(1))
611                    if other_matcher:
612                        self.result_lines.append(other_matcher.group(1))
613                        line = " ".join(self.result_lines)
614                        self.result_lines.clear()
615
616                if self._is_ctest_start_test_run(line):
617                    self.handle_suites_started_tag()
618                elif self._is_ctest_end_test_run(line):
619                    self.process_suites_ended_tag()
620                elif self._is_ctest_run(line):
621                    self.handle_suite_ended_tag(line)
622                elif self._is_ctest_suite_test_run(line) and \
623                        not self.state_machine.suite_is_running():
624                    self._process_ctest_suite_test_run_line(line)
625                elif self.is_ctest_suite_time_run(line) and \
626                        not self.state_machine.suite_is_running():
627                    self.handle_suite_started_tag(line)
628                elif self._is_result_line(line) and \
629                        self.state_machine.suite_is_running():
630                    if line.find(":") != -1 and line.count(
631                            ":") >= 3 and self._is_execute_result_line(line):
632                        self.handle_one_test_tag(line.strip(), False)
633                    else:
634                        self.handle_one_test_tag(line.strip(), True)
635            except AttributeError:
636                LOG.error("parsing log: %s failed" % (line.strip()),
637                          error_no="00405")
638            self.last_line = line
639
640    def _parse_product_info(self, line):
641        if _PRODUCT_PARA_START in line:
642            self.is_params = True
643        elif _PRODUCT_PARA_END in line:
644            self.is_params = False
645        if self.is_params and re.match(_PRODUCT_PARA, line):
646            handle_product_info(line, self.product_info)
647
648    def parse_error_test_description(self, message):
649        end_time = re.match(self.pattern, message).group().strip()
650        start_time = re.match(self.pattern,
651                              self.last_line.strip()).group().strip()
652        start_timestamp = int(time.mktime(
653            time.strptime(start_time, "%Y-%m-%d %H:%M:%S.%f"))) * 1000 + int(
654            start_time.split(".")[-1])
655        end_timestamp = int(time.mktime(
656            time.strptime(end_time, "%Y-%m-%d %H:%M:%S.%f"))) * 1000 + int(
657            end_time.split(".")[-1])
658        run_time = end_timestamp - start_timestamp
659        status_dict = {"PASS": ResultCode.PASSED, "FAIL": ResultCode.FAILED,
660                       "IGNORE": ResultCode.SKIPPED}
661        status = ""
662        if message.find("PASS") != -1:
663            status = "PASS"
664        elif message.find("FAIL") != -1:
665            status = "FAIL"
666        elif message.find("IGNORE") != -1:
667            status = "IGNORE"
668        status = status_dict.get(status)
669        return "", "", status, run_time
670
671    def parse_test_description(self, message):
672
673        test_class = message.split(".c:")[0].split(" ")[-1].split("/")[-1]
674        message_index = message.index(".c:")
675        end_time = re.match(self.pattern, message).group().strip()
676        start_time = re.match(self.pattern,
677                              self.last_line.strip()).group().strip()
678        start_timestamp = int(time.mktime(
679            time.strptime(start_time, "%Y-%m-%d %H:%M:%S.%f"))) * 1000 + int(
680            start_time.split(".")[-1])
681        end_timestamp = int(time.mktime(
682            time.strptime(end_time, "%Y-%m-%d %H:%M:%S.%f"))) * 1000 + int(
683            end_time.split(".")[-1])
684        run_time = end_timestamp - start_timestamp
685        message_list = message[message_index + 3:].split(":")
686        test_name, status = message_list[1].strip(), message_list[2].strip()
687        status_dict = {"PASS": ResultCode.PASSED, "FAIL": ResultCode.FAILED,
688                       "IGNORE": ResultCode.SKIPPED}
689        status = status_dict.get(status)
690        return test_class, test_name, status, run_time
691
692    def handle_one_test_tag(self, message, is_error):
693        if is_error:
694            test_class, test_name, status, run_time = \
695                self.parse_error_test_description(message)
696        else:
697            test_class, test_name, status, run_time = \
698                self.parse_test_description(message)
699        test_result = self.state_machine.test(reset=True)
700        test_result.test_class = test_class
701        test_result.test_name = test_name
702        test_result.run_time = run_time
703        self.state_machine.running_test_index += 1
704        test_result.current = self.state_machine.running_test_index
705        test_result.code = status.value
706        self.state_machine.suite().run_time += run_time
707        for listener in self.get_listeners():
708            test_result = copy.copy(test_result)
709            listener.__started__(LifeCycle.TestCase, test_result)
710
711        test_suite = self.state_machine.suite()
712        test_suites = self.state_machine.get_suites()
713
714        found_unexpected_test = False
715
716        if found_unexpected_test or ResultCode.FAILED == status:
717            if "FAIL:" in message and not message.endswith("FAIL:"):
718                test_result.stacktrace = message[
719                                         message.rindex("FAIL:") + len(
720                                             "FAIL:"):]
721            for listener in self.get_listeners():
722                result = copy.copy(test_result)
723                listener.__failed__(LifeCycle.TestCase, result)
724        elif ResultCode.SKIPPED == status:
725            for listener in self.get_listeners():
726                result = copy.copy(test_result)
727                listener.__failed__(LifeCycle.TestCase, result)
728
729        self.state_machine.test().is_completed = True
730        test_suite.test_num += 1
731        test_suites.test_num += 1
732
733        for listener in self.get_listeners():
734            result = copy.copy(test_result)
735            listener.__ended__(LifeCycle.TestCase, result)
736
737    def handle_suites_started_tag(self):
738        self.state_machine.get_suites(reset=True)
739        test_suites = self.state_machine.get_suites()
740        test_suites.suites_name = self.suites_name
741        test_suites.product_info = self.product_info
742        test_suites.test_num = 0
743        for listener in self.get_listeners():
744            suite_report = copy.copy(test_suites)
745            listener.__started__(LifeCycle.TestSuites, suite_report)
746
747    def handle_suite_started_tag(self, message):
748        if re.match("{}{}".format(self.pattern, _CTEST_SUITE_TIME_RUN_TAG),
749                    message.strip()):
750            message = self.state_machine.suite().suite_name
751        self.state_machine.suite(reset=True)
752        test_suite = self.state_machine.suite()
753        test_suite.suite_name = message
754        test_suite.test_num = 0
755        for listener in self.get_listeners():
756            suite_report = copy.copy(test_suite)
757            listener.__started__(LifeCycle.TestSuite, suite_report)
758
759    def handle_suite_ended_tag(self, line):
760        suite_result = self.state_machine.suite()
761        suites = self.state_machine.get_suites()
762        suite_result.run_time = suite_result.run_time
763        suites.run_time += suite_result.run_time
764        suite_result.is_completed = True
765
766        for listener in self.get_listeners():
767            suite = copy.copy(suite_result)
768            listener.__ended__(LifeCycle.TestSuite, suite, is_clear=True)
769        self.state_machine.running_test_index = 0
770
771    def process_suites_ended_tag(self):
772        suites = self.state_machine.get_suites()
773        suites.is_completed = True
774
775        for listener in self.get_listeners():
776            listener.__ended__(LifeCycle.TestSuites, test_result=suites,
777                               suites_name=suites.suites_name,
778                               product_info=suites.product_info)
779
780    def append_test_output(self, message):
781        if self.state_machine.test().stacktrace:
782            self.state_machine.test().stacktrace = "{}\r\n".format(
783                self.state_machine.test().stacktrace)
784        self.state_machine.test().stacktrace = "{}{}".format(
785            self.state_machine.test().stacktrace, message)
786
787
788@Plugin(type=Plugin.PARSER, id=ParserType.open_source_test)
789class OpenSourceParser(IParser):
790    def __init__(self):
791        self.state_machine = StateRecorder()
792        self.suite_name = ""
793        self.test_name = ""
794        self.test_num = 1
795        self.listeners = []
796        self.output = ""
797        self.lines = []
798        self.start_time = None
799
800    def get_suite_name(self):
801        return self.suite_name
802
803    def get_listeners(self):
804        return self.listeners
805
806    def __process__(self, lines):
807        if not self.start_time:
808            self.start_time = datetime.datetime.now()
809        self.lines.extend(lines)
810
811    def __done__(self):
812        if not self.state_machine.suites_is_started():
813            self.state_machine.trace_logs.extend(self.lines)
814        self.handle_suite_started_tag(self.test_num)
815
816        test_result = self.state_machine.test(reset=True,
817                                              test_index=self.test_name)
818        test_result.run_time = 0
819        test_result.test_class = self.suite_name
820        test_result.test_name = self.test_name
821        test_result.test_num = 1
822        test_result.current = 1
823        for listener in self.get_listeners():
824            result = copy.copy(test_result)
825            listener.__started__(LifeCycle.TestCase, result)
826        for line in self.lines:
827            self.output = "{}{}".format(self.output, line)
828            if _TEST_PASSED_LOWER in line.lower():
829                test_result.code = ResultCode.PASSED.value
830                if self.start_time:
831                    end_time = datetime.datetime.now()
832                    run_time = (end_time - self.start_time).total_seconds()
833                    test_result.run_time = int(run_time * 1000)
834                for listener in self.get_listeners():
835                    result = copy.copy(test_result)
836                    listener.__ended__(LifeCycle.TestCase, result)
837                break
838        else:
839            test_result.code = ResultCode.FAILED.value
840            test_result.stacktrace = "\\n".join(self.lines)
841            if self.start_time:
842                end_time = datetime.datetime.now()
843                run_time = (end_time - self.start_time).total_seconds()
844                test_result.run_time = int(run_time * 1000)
845            for listener in self.get_listeners():
846                result = copy.copy(test_result)
847                listener.__ended__(LifeCycle.TestCase, result)
848
849        self.state_machine.test().is_completed = True
850        self.handle_suite_ended_tag()
851
852    def handle_suite_started_tag(self, test_num):
853        test_suite = self.state_machine.suite()
854        if test_num >= 0:
855            test_suite.suite_name = self.suite_name
856            test_suite.test_num = test_num
857            for listener in self.get_listeners():
858                suite_report = copy.copy(test_suite)
859                listener.__started__(LifeCycle.TestSuite, suite_report)
860
861    def handle_suite_ended_tag(self):
862        suite_result = self.state_machine.suite()
863        for listener in self.get_listeners():
864            suite = copy.copy(suite_result)
865            listener.__ended__(LifeCycle.TestSuite, suite,
866                               suite_report=True)
867
868
869@Plugin(type=Plugin.PARSER, id=ParserType.build_only_test)
870class BuildOnlyParser(IParser):
871    def __init__(self):
872        self.state_machine = StateRecorder()
873        self.suite_name = ""
874        self.test_name = ""
875        self.test_num = 0
876        self.listeners = []
877        self.output = ""
878
879    def get_suite_name(self):
880        return self.suite_name
881
882    def get_listeners(self):
883        return self.listeners
884
885    def __process__(self, lines):
886        if not self.state_machine.suites_is_started():
887            self.state_machine.trace_logs.extend(lines)
888        self.handle_suite_started_tag(self.test_num)
889
890        self.state_machine.running_test_index = \
891            self.state_machine.running_test_index + 1
892
893        for line in lines:
894            if re.match(_COMPILE_PARA, line):
895                self.test_name = str(line).split('compile')[0].strip()
896                test_result = self.state_machine.test(reset=True)
897                test_result.run_time = 0
898                test_result.test_class = self.suite_name
899                test_result.test_name = self.test_name
900                for listener in self.get_listeners():
901                    result = copy.copy(test_result)
902                    listener.__started__(LifeCycle.TestCase, result)
903                if _COMPILE_PASSED in line:
904                    test_result.code = ResultCode.PASSED.value
905                    for listener in self.get_listeners():
906                        result = copy.copy(test_result)
907                        listener.__ended__(LifeCycle.TestCase, result)
908                else:
909                    test_result.code = ResultCode.FAILED.value
910                    for listener in self.get_listeners():
911                        result = copy.copy(test_result)
912                        listener.__failed__(LifeCycle.TestCase, result)
913        self.state_machine.test().is_completed = True
914
915    def __done__(self):
916        self.handle_suite_ended_tag()
917
918    def handle_suite_started_tag(self, test_num):
919        test_suite = self.state_machine.suite()
920        if test_num >= 0:
921            test_suite.suite_name = self.suite_name
922            test_suite.test_num = test_num
923            for listener in self.get_listeners():
924                suite_report = copy.copy(test_suite)
925                listener.__started__(LifeCycle.TestSuite, suite_report)
926
927    def handle_suite_ended_tag(self):
928        suite_result = self.state_machine.suite()
929        for listener in self.get_listeners():
930            suite = copy.copy(suite_result)
931            listener.__ended__(LifeCycle.TestSuite, suite,
932                               suite_report=True)
933
934
935@Plugin(type=Plugin.PARSER, id=ParserType.jsuit_test_lite)
936class JSUnitParserLite(IParser):
937    last_line = ""
938    pattern = r"(\d{1,2}-\d{1,2}\s\d{1,2}:\d{1,2}:\d{1,2}\.\d{3}) "
939
940    def __init__(self):
941        self.state_machine = StateRecorder()
942        self.suites_name = ""
943        self.listeners = []
944
945    def get_listeners(self):
946        return self.listeners
947
948    def __process__(self, lines):
949        if not self.state_machine.suites_is_started():
950            self.state_machine.trace_logs.extend(lines)
951        for line in lines:
952            self.parse(line)
953
954    def __done__(self):
955        pass
956
957    def parse(self, line):
958        if (self.state_machine.suites_is_started() or
959            line.find(_START_JSUNIT_RUN_MARKER) != -1) and \
960                line.find(_ACE_LOG_MARKER) != -1:
961            if line.find(_START_JSUNIT_RUN_MARKER) != -1:
962                self.handle_suites_started_tag()
963            elif line.endswith(_END_JSUNIT_RUN_MARKER):
964                self.handle_suites_ended_tag()
965            elif line.find(_START_JSUNIT_SUITE_RUN_MARKER) != -1:
966                self.handle_suite_started_tag(line.strip())
967            elif line.endswith(_START_JSUNIT_SUITE_END_MARKER):
968                self.handle_suite_ended_tag()
969            elif _PASS_JSUNIT_MARKER in line or _FAIL_JSUNIT_MARKER \
970                    in line:
971                self.handle_one_test_tag(line.strip())
972            self.last_line = line
973
974    def parse_test_description(self, message):
975        pattern = r"\[(pass|fail)\]"
976        year = time.strftime("%Y")
977        filter_message = message.split("[Console Info]")[1].strip()
978        end_time = "%s-%s" % \
979                   (year, re.match(self.pattern, message).group().strip())
980        start_time = "%s-%s" % \
981                     (year, re.match(self.pattern,
982                                     self.last_line.strip()).group().strip())
983        start_timestamp = int(time.mktime(
984            time.strptime(start_time, "%Y-%m-%d %H:%M:%S.%f"))) * 1000 + int(
985            start_time.split(".")[-1])
986        end_timestamp = int(time.mktime(
987            time.strptime(end_time, "%Y-%m-%d %H:%M:%S.%f"))) * 1000 + int(
988            end_time.split(".")[-1])
989        run_time = end_timestamp - start_timestamp
990        _, status_end_index = re.match(pattern, filter_message).span()
991        status = filter_message[:status_end_index]
992        test_name = filter_message[status_end_index:]
993        status_dict = {"pass": ResultCode.PASSED, "fail": ResultCode.FAILED,
994                       "ignore": ResultCode.SKIPPED}
995        status = status_dict.get(status[1:-1])
996        return test_name, status, run_time
997
998    def handle_suites_started_tag(self):
999        self.state_machine.get_suites(reset=True)
1000        test_suites = self.state_machine.get_suites()
1001        test_suites.suites_name = self.suites_name
1002        test_suites.test_num = 0
1003        for listener in self.get_listeners():
1004            suite_report = copy.copy(test_suites)
1005            listener.__started__(LifeCycle.TestSuites, suite_report)
1006
1007    def handle_suites_ended_tag(self):
1008        suites = self.state_machine.get_suites()
1009        suites.is_completed = True
1010
1011        for listener in self.get_listeners():
1012            listener.__ended__(LifeCycle.TestSuites, test_result=suites,
1013                               suites_name=suites.suites_name)
1014
1015    def handle_one_test_tag(self, message):
1016        test_name, status, run_time = \
1017            self.parse_test_description(message)
1018        test_result = self.state_machine.test(reset=True)
1019        test_suite = self.state_machine.suite()
1020        test_result.test_class = test_suite.suite_name
1021        test_result.test_name = test_name
1022        test_result.run_time = run_time
1023        test_result.code = status.value
1024        test_result.current = self.state_machine.running_test_index + 1
1025        self.state_machine.suite().run_time += run_time
1026        for listener in self.get_listeners():
1027            test_result = copy.copy(test_result)
1028            listener.__started__(LifeCycle.TestCase, test_result)
1029
1030        test_suites = self.state_machine.get_suites()
1031        found_unexpected_test = False
1032
1033        if found_unexpected_test or ResultCode.FAILED == status:
1034            for listener in self.get_listeners():
1035                result = copy.copy(test_result)
1036                listener.__failed__(LifeCycle.TestCase, result)
1037        elif ResultCode.SKIPPED == status:
1038            for listener in self.get_listeners():
1039                result = copy.copy(test_result)
1040                listener.__skipped__(LifeCycle.TestCase, result)
1041
1042        self.state_machine.test().is_completed = True
1043        test_suite.test_num += 1
1044        test_suites.test_num += 1
1045        for listener in self.get_listeners():
1046            result = copy.copy(test_result)
1047            listener.__ended__(LifeCycle.TestCase, result)
1048        self.state_machine.running_test_index += 1
1049
1050    def fake_run_marker(self, message):
1051        fake_marker = re.compile(" +").split(message)
1052        self.processTestStartedTag(fake_marker)
1053
1054    def handle_suite_started_tag(self, message):
1055        self.state_machine.suite(reset=True)
1056        test_suite = self.state_machine.suite()
1057        if re.match(r".*\[suite start\].*", message):
1058            _, index = re.match(r".*\[suite start\]", message).span()
1059        test_suite.suite_name = message[index:]
1060        test_suite.test_num = 0
1061        for listener in self.get_listeners():
1062            suite_report = copy.copy(test_suite)
1063            listener.__started__(LifeCycle.TestSuite, suite_report)
1064
1065    def handle_suite_ended_tag(self):
1066        suite_result = self.state_machine.suite()
1067        suites = self.state_machine.get_suites()
1068        suite_result.run_time = suite_result.run_time
1069        suites.run_time += suite_result.run_time
1070        suite_result.is_completed = True
1071
1072        for listener in self.get_listeners():
1073            suite = copy.copy(suite_result)
1074            listener.__ended__(LifeCycle.TestSuite, suite, is_clear=True)
1075
1076    def append_test_output(self, message):
1077        if self.state_machine.test().stacktrace:
1078            self.state_machine.test().stacktrace = \
1079                "%s\r\n" % self.state_machine.test().stacktrace
1080        self.state_machine.test().stacktrace = \
1081            ''.join((self.state_machine.test().stacktrace, message))
1082
1083
1084class ShellHandler:
1085    def __init__(self, parsers):
1086        self.parsers = []
1087        self.unfinished_line = ""
1088        self.output_queue = Queue()
1089        for parser in parsers:
1090            if isinstance(parser, IParser):
1091                self.parsers.append(parser)
1092            else:
1093                raise TypeError(
1094                    "Parser {} must implement IOutputParser interface.".format(
1095                        parser, ))
1096
1097    def _process_output(self, output, end_mark="\n"):
1098        content = output
1099        if self.unfinished_line:
1100            content = "".join((self.unfinished_line, content))
1101            self.unfinished_line = ""
1102        lines = content.split(end_mark)
1103        if content.endswith(end_mark):
1104            # get rid of the tail element of this list contains empty str
1105            return lines[:-1]
1106        else:
1107            self.unfinished_line = lines[-1]
1108            # not return the tail element of this list contains unfinished str,
1109            # so we set position -1
1110            return lines
1111
1112    def __read__(self, output):
1113        lines = self._process_output(output)
1114        for line in lines:
1115            for parser in self.parsers:
1116                try:
1117                    parser.__process__([line])
1118                except (ValueError, TypeError, SyntaxError, AttributeError) \
1119                        as error:
1120                    LOG.debug("Parse %s line error: %s" % (line, error))
1121
1122    def __error__(self, message):
1123        if message:
1124            for parser in self.parsers:
1125                parser.__process__([message])
1126
1127    def __done__(self, result_code="", message=""):
1128        msg_fmt = ""
1129        if message:
1130            msg_fmt = ", message is {}".format(message)
1131            for parser in self.parsers:
1132                parser.__process__([message])
1133        if not check_pub_key_exist():
1134            LOG.debug("result code is: {}{}".format(result_code, msg_fmt))
1135        for parser in self.parsers:
1136            parser.__done__()
1137
1138
1139def handle_product_info(message, product_info):
1140    message = message[message.index("The"):]
1141    items = message[len("The "):].split(" is ")
1142    product_info.setdefault(items[0].strip(),
1143                            items[1].strip().strip("[").strip("]"))
1144