@@ -45,10 +45,11 @@ class TestStatus(Enum):
4545 FAILURE = auto ()
4646 TEST_CRASHED = auto ()
4747 NO_TESTS = auto ()
48+ FAILURE_TO_PARSE_TESTS = auto ()
4849
4950kunit_start_re = re .compile (r'TAP version [0-9]+$' )
5051kunit_end_re = re .compile ('(List of all partitions:|'
51- 'Kernel panic - not syncing: VFS:|reboot: System halted )' )
52+ 'Kernel panic - not syncing: VFS:)' )
5253
5354def isolate_kunit_output (kernel_output ):
5455 started = False
@@ -109,7 +110,7 @@ def save_non_diagnositic(lines: List[str], test_case: TestCase) -> None:
109110
110111OK_NOT_OK_SUBTEST = re .compile (r'^[\s]+(ok|not ok) [0-9]+ - (.*)$' )
111112
112- OK_NOT_OK_MODULE = re .compile (r'^(ok|not ok) [0-9]+ - (.*)$' )
113+ OK_NOT_OK_MODULE = re .compile (r'^(ok|not ok) ( [0-9]+) - (.*)$' )
113114
114115def parse_ok_not_ok_test_case (lines : List [str ], test_case : TestCase ) -> bool :
115116 save_non_diagnositic (lines , test_case )
@@ -197,7 +198,9 @@ def max_status(left: TestStatus, right: TestStatus) -> TestStatus:
197198 else :
198199 return TestStatus .SUCCESS
199200
200- def parse_ok_not_ok_test_suite (lines : List [str ], test_suite : TestSuite ) -> bool :
201+ def parse_ok_not_ok_test_suite (lines : List [str ],
202+ test_suite : TestSuite ,
203+ expected_suite_index : int ) -> bool :
201204 consume_non_diagnositic (lines )
202205 if not lines :
203206 test_suite .status = TestStatus .TEST_CRASHED
@@ -210,6 +213,12 @@ def parse_ok_not_ok_test_suite(lines: List[str], test_suite: TestSuite) -> bool:
210213 test_suite .status = TestStatus .SUCCESS
211214 else :
212215 test_suite .status = TestStatus .FAILURE
216+ suite_index = int (match .group (2 ))
217+ if suite_index != expected_suite_index :
218+ print_with_timestamp (
219+ red ('[ERROR] ' ) + 'expected_suite_index ' +
220+ str (expected_suite_index ) + ', but got ' +
221+ str (suite_index ))
213222 return True
214223 else :
215224 return False
@@ -222,7 +231,7 @@ def bubble_up_test_case_errors(test_suite: TestSuite) -> TestStatus:
222231 max_test_case_status = bubble_up_errors (lambda x : x .status , test_suite .cases )
223232 return max_status (max_test_case_status , test_suite .status )
224233
225- def parse_test_suite (lines : List [str ]) -> TestSuite :
234+ def parse_test_suite (lines : List [str ], expected_suite_index : int ) -> TestSuite :
226235 if not lines :
227236 return None
228237 consume_non_diagnositic (lines )
@@ -241,7 +250,7 @@ def parse_test_suite(lines: List[str]) -> TestSuite:
241250 break
242251 test_suite .cases .append (test_case )
243252 expected_test_case_num -= 1
244- if parse_ok_not_ok_test_suite (lines , test_suite ):
253+ if parse_ok_not_ok_test_suite (lines , test_suite , expected_suite_index ):
245254 test_suite .status = bubble_up_test_case_errors (test_suite )
246255 return test_suite
247256 elif not lines :
@@ -261,27 +270,51 @@ def parse_tap_header(lines: List[str]) -> bool:
261270 else :
262271 return False
263272
273+ TEST_PLAN = re .compile (r'[0-9]+\.\.([0-9]+)' )
274+
275+ def parse_test_plan (lines : List [str ]) -> int :
276+ consume_non_diagnositic (lines )
277+ match = TEST_PLAN .match (lines [0 ])
278+ if match :
279+ lines .pop (0 )
280+ return int (match .group (1 ))
281+ else :
282+ return None
283+
264284def bubble_up_suite_errors (test_suite_list : List [TestSuite ]) -> TestStatus :
265285 return bubble_up_errors (lambda x : x .status , test_suite_list )
266286
267287def parse_test_result (lines : List [str ]) -> TestResult :
268288 consume_non_diagnositic (lines )
269289 if not lines or not parse_tap_header (lines ):
270290 return TestResult (TestStatus .NO_TESTS , [], lines )
291+ expected_test_suite_num = parse_test_plan (lines )
292+ if not expected_test_suite_num :
293+ return TestResult (TestStatus .FAILURE_TO_PARSE_TESTS , [], lines )
271294 test_suites = []
272- test_suite = parse_test_suite (lines )
273- while test_suite :
274- test_suites .append (test_suite )
275- test_suite = parse_test_suite (lines )
276- return TestResult (bubble_up_suite_errors (test_suites ), test_suites , lines )
295+ for i in range (1 , expected_test_suite_num + 1 ):
296+ test_suite = parse_test_suite (lines , i )
297+ if test_suite :
298+ test_suites .append (test_suite )
299+ else :
300+ print_with_timestamp (
301+ red ('[ERROR] ' ) + ' expected ' +
302+ str (expected_test_suite_num ) +
303+ ' test suites, but got ' + str (i - 2 ))
304+ break
305+ test_suite = parse_test_suite (lines , - 1 )
306+ if test_suite :
307+ print_with_timestamp (red ('[ERROR] ' ) +
308+ 'got unexpected test suite: ' + test_suite .name )
309+ if test_suites :
310+ return TestResult (bubble_up_suite_errors (test_suites ), test_suites , lines )
311+ else :
312+ return TestResult (TestStatus .NO_TESTS , [], lines )
277313
278- def parse_run_tests ( kernel_output ) -> TestResult :
314+ def print_and_count_results ( test_result : TestResult ) -> None :
279315 total_tests = 0
280316 failed_tests = 0
281317 crashed_tests = 0
282- test_result = parse_test_result (list (isolate_kunit_output (kernel_output )))
283- if test_result .status == TestStatus .NO_TESTS :
284- print_with_timestamp (red ('[ERROR] ' ) + 'no kunit output detected' )
285318 for test_suite in test_result .suites :
286319 if test_suite .status == TestStatus .SUCCESS :
287320 print_suite_divider (green ('[PASSED] ' ) + test_suite .name )
@@ -303,6 +336,21 @@ def parse_run_tests(kernel_output) -> TestResult:
303336 print_with_timestamp (red ('[FAILED] ' ) + test_case .name )
304337 print_log (map (yellow , test_case .log ))
305338 print_with_timestamp ('' )
339+ return total_tests , failed_tests , crashed_tests
340+
341+ def parse_run_tests (kernel_output ) -> TestResult :
342+ total_tests = 0
343+ failed_tests = 0
344+ crashed_tests = 0
345+ test_result = parse_test_result (list (isolate_kunit_output (kernel_output )))
346+ if test_result .status == TestStatus .NO_TESTS :
347+ print (red ('[ERROR] ' ) + yellow ('no tests run!' ))
348+ elif test_result .status == TestStatus .FAILURE_TO_PARSE_TESTS :
349+ print (red ('[ERROR] ' ) + yellow ('could not parse test results!' ))
350+ else :
351+ (total_tests ,
352+ failed_tests ,
353+ crashed_tests ) = print_and_count_results (test_result )
306354 print_with_timestamp (DIVIDER )
307355 fmt = green if test_result .status == TestStatus .SUCCESS else red
308356 print_with_timestamp (
0 commit comments