1bf215546Sopenharmony_ciimport re
2bf215546Sopenharmony_cifrom dataclasses import dataclass
3bf215546Sopenharmony_cifrom datetime import timedelta
4bf215546Sopenharmony_cifrom enum import Enum, auto
5bf215546Sopenharmony_cifrom typing import Optional, Pattern, Union
6bf215546Sopenharmony_ci
7bf215546Sopenharmony_cifrom lava.utils.gitlab_section import GitlabSection
8bf215546Sopenharmony_ci
9bf215546Sopenharmony_ci
10bf215546Sopenharmony_ciclass LogSectionType(Enum):
11bf215546Sopenharmony_ci    UNKNOWN = auto()
12bf215546Sopenharmony_ci    LAVA_BOOT = auto()
13bf215546Sopenharmony_ci    TEST_SUITE = auto()
14bf215546Sopenharmony_ci    TEST_CASE = auto()
15bf215546Sopenharmony_ci    LAVA_POST_PROCESSING = auto()
16bf215546Sopenharmony_ci
17bf215546Sopenharmony_ci
18bf215546Sopenharmony_ciFALLBACK_GITLAB_SECTION_TIMEOUT = timedelta(minutes=10)
19bf215546Sopenharmony_ciDEFAULT_GITLAB_SECTION_TIMEOUTS = {
20bf215546Sopenharmony_ci    # Empirically, successful device boot in LAVA time takes less than 3
21bf215546Sopenharmony_ci    # minutes.
22bf215546Sopenharmony_ci    # LAVA itself is configured to attempt thrice to boot the device,
23bf215546Sopenharmony_ci    # summing up to 9 minutes.
24bf215546Sopenharmony_ci    # It is better to retry the boot than cancel the job and re-submit to avoid
25bf215546Sopenharmony_ci    # the enqueue delay.
26bf215546Sopenharmony_ci    LogSectionType.LAVA_BOOT: timedelta(minutes=9),
27bf215546Sopenharmony_ci    # Test suite phase is where the initialization happens.
28bf215546Sopenharmony_ci    LogSectionType.TEST_SUITE: timedelta(minutes=5),
29bf215546Sopenharmony_ci    # Test cases may take a long time, this script has no right to interrupt
30bf215546Sopenharmony_ci    # them. But if the test case takes almost 1h, it will never succeed due to
31bf215546Sopenharmony_ci    # Gitlab job timeout.
32bf215546Sopenharmony_ci    LogSectionType.TEST_CASE: timedelta(minutes=60),
33bf215546Sopenharmony_ci    # LAVA post processing may refer to a test suite teardown, or the
34bf215546Sopenharmony_ci    # adjustments to start the next test_case
35bf215546Sopenharmony_ci    LogSectionType.LAVA_POST_PROCESSING: timedelta(minutes=5),
36bf215546Sopenharmony_ci}
37bf215546Sopenharmony_ci
38bf215546Sopenharmony_ci
39bf215546Sopenharmony_ci@dataclass(frozen=True)
40bf215546Sopenharmony_ciclass LogSection:
41bf215546Sopenharmony_ci    regex: Union[Pattern, str]
42bf215546Sopenharmony_ci    levels: tuple[str]
43bf215546Sopenharmony_ci    section_id: str
44bf215546Sopenharmony_ci    section_header: str
45bf215546Sopenharmony_ci    section_type: LogSectionType
46bf215546Sopenharmony_ci    collapsed: bool = False
47bf215546Sopenharmony_ci
48bf215546Sopenharmony_ci    def from_log_line_to_section(
49bf215546Sopenharmony_ci        self, lava_log_line: dict[str, str]
50bf215546Sopenharmony_ci    ) -> Optional[GitlabSection]:
51bf215546Sopenharmony_ci        if lava_log_line["lvl"] not in self.levels:
52bf215546Sopenharmony_ci            return
53bf215546Sopenharmony_ci
54bf215546Sopenharmony_ci        if match := re.search(self.regex, lava_log_line["msg"]):
55bf215546Sopenharmony_ci            section_id = self.section_id.format(*match.groups())
56bf215546Sopenharmony_ci            section_header = self.section_header.format(*match.groups())
57bf215546Sopenharmony_ci            return GitlabSection(
58bf215546Sopenharmony_ci                id=section_id,
59bf215546Sopenharmony_ci                header=section_header,
60bf215546Sopenharmony_ci                type=self.section_type,
61bf215546Sopenharmony_ci                start_collapsed=self.collapsed,
62bf215546Sopenharmony_ci            )
63bf215546Sopenharmony_ci
64bf215546Sopenharmony_ci
65bf215546Sopenharmony_ciLOG_SECTIONS = (
66bf215546Sopenharmony_ci    LogSection(
67bf215546Sopenharmony_ci        regex=re.compile(r"<?STARTTC>? ([^>]*)"),
68bf215546Sopenharmony_ci        levels=("target", "debug"),
69bf215546Sopenharmony_ci        section_id="{}",
70bf215546Sopenharmony_ci        section_header="test_case {}",
71bf215546Sopenharmony_ci        section_type=LogSectionType.TEST_CASE,
72bf215546Sopenharmony_ci    ),
73bf215546Sopenharmony_ci    LogSection(
74bf215546Sopenharmony_ci        regex=re.compile(r"<?STARTRUN>? ([^>]*)"),
75bf215546Sopenharmony_ci        levels=("target", "debug"),
76bf215546Sopenharmony_ci        section_id="{}",
77bf215546Sopenharmony_ci        section_header="test_suite {}",
78bf215546Sopenharmony_ci        section_type=LogSectionType.TEST_SUITE,
79bf215546Sopenharmony_ci    ),
80bf215546Sopenharmony_ci    LogSection(
81bf215546Sopenharmony_ci        regex=re.compile(r"ENDTC>? ([^>]+)"),
82bf215546Sopenharmony_ci        levels=("target", "debug"),
83bf215546Sopenharmony_ci        section_id="post-{}",
84bf215546Sopenharmony_ci        section_header="Post test_case {}",
85bf215546Sopenharmony_ci        collapsed=True,
86bf215546Sopenharmony_ci        section_type=LogSectionType.LAVA_POST_PROCESSING,
87bf215546Sopenharmony_ci    ),
88bf215546Sopenharmony_ci)
89