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