Lines Matching full:test

3 # Parses KTAP test results from a kernel dmesg log and incrementally prints
4 # results with reader-friendly format. Stores and returns test results in a
5 # Test object.
22 class Test: class
24 A class to represent a test parsed from KTAP results. All KTAP
25 results within a test log are stored in a main Test object as
29 status : TestStatus - status of the test
30 name : str - name of the test
32 test case and None if unknown expected number of subtests)
33 subtests : List[Test] - list of subtests
34 log : List[str] - log of KTAP lines that correspond to the test
35 counts : TestCounts - counts of the test statuses and errors of
36 subtests or of the test itself if the test is a single
37 test case.
40 """Creates Test object with default attributes."""
44 self.subtests = [] # type: List[Test]
49 """Returns string representation of a Test class object."""
50 return (f'Test({self.status}, {self.name}, {self.expected_count}, '
54 """Returns string representation of a Test class object."""
58 """Records an error that occurred while parsing this test."""
60 stdout.print_with_timestamp(stdout.red('[ERROR]') + f' Test: {self.name}: {error_message}')
67 """An enumeration class to represent the status of a test."""
78 Tracks the counts of statuses of all test cases and any errors within
79 a Test.
96 """Returns the total number of test cases within a test
97 object, where a test case is a test with no subtests.
106 parent test.
119 """Returns the aggregated status of a Test using test
254 version_type: str, test: Test) -> None: argument
256 Adds error to test object if version number is too high or too
265 test - Test object for current test being parsed
268 test.add_error(f'{version_type} version lower than expected!')
270 test.add_error(f'{version_type} version higer than expected!')
272 def parse_ktap_header(lines: LineStream, test: Test) -> bool: argument
283 test - Test object for current test being parsed
292 check_version(version_num, KTAP_VERSIONS, 'KTAP', test)
295 check_version(version_num, TAP_VERSIONS, 'TAP', test)
303 def parse_test_header(lines: LineStream, test: Test) -> bool: argument
305 Parses test header and stores test name in test object.
306 Returns False if fails to parse test header line.
309 - '# Subtest: [test name]'
313 test - Test object for current test being parsed
316 True if successfully parsed test header line
321 test.name = match.group(1)
327 def parse_test_plan(lines: LineStream, test: Test) -> bool: argument
329 Parses test plan line and stores the expected number of subtests in
330 test object. Reports an error if expected count is 0.
331 Returns False and sets expected_count to None if there is no valid test
339 test - Test object for current test being parsed
342 True if successfully parsed test plan line
346 test.expected_count = None
349 test.expected_count = expected_count
357 def peek_test_name_match(lines: LineStream, test: Test) -> bool: argument
359 Matches current line with the format of a test result line and checks
360 if the name matches the name of the current test.
364 - '[ok|not ok] [test number] [-] [test name] [optional skip
369 test - Test object for current test being parsed
372 True if matched a test result line and the name matching the
373 expected test name
380 return name == test.name
382 def parse_test_result(lines: LineStream, test: Test, argument
385 Parses test result line and stores the status and name in the test
386 object. Reports an error if the test number does not match expected
387 test number.
388 Returns False if fails to parse test result line.
394 - '[ok|not ok] [test number] [-] [test name] [optional skip
399 test - Test object for current test being parsed
400 expected_num - expected test number for current test
403 True if successfully parsed a test result line.
409 # Check if line matches test result line format
414 # Set name of test object
416 test.name = skip_match.group(4)
418 test.name = match.group(4)
420 # Check test num
423 test.add_error(f'Expected test number {expected_num} but found {num}')
425 # Set status of test object
428 test.status = TestStatus.SKIPPED
430 test.status = TestStatus.SUCCESS
432 test.status = TestStatus.FAILURE
437 Parse lines that do not match the format of a test result line or
438 test header line and returns them in list.
441 - '# Subtest: [test name]'
442 - '[ok|not ok] [test number] [-] [test name] [optional skip
489 def print_test_header(test: Test) -> None: argument
491 Prints test header with test name and optionally the expected number
498 test - Test object representing current test being printed
500 message = test.name
502 # Add a leading space before the subtest counts only if a test name
505 if test.expected_count:
506 if test.expected_count == 1:
509 message += f'({test.expected_count} subtests)'
513 """Prints all strings in saved log for test in yellow."""
518 def format_test_result(test: Test) -> str: argument
520 Returns string with formatted test result with colored status and test
527 test - Test object representing current test being printed
530 String containing formatted test result
532 if test.status == TestStatus.SUCCESS:
533 return stdout.green('[PASSED] ') + test.name
534 if test.status == TestStatus.SKIPPED:
535 return stdout.yellow('[SKIPPED] ') + test.name
536 if test.status == TestStatus.NO_TESTS:
537 return stdout.yellow('[NO TESTS RUN] ') + test.name
538 if test.status == TestStatus.TEST_CRASHED:
539 print_log(test.log)
540 return stdout.red('[CRASHED] ') + test.name
541 print_log(test.log)
542 return stdout.red('[FAILED] ') + test.name
544 def print_test_result(test: Test) -> None: argument
546 Prints result line with status of test.
552 test - Test object representing current test being printed
554 stdout.print_with_timestamp(format_test_result(test))
556 def print_test_footer(test: Test) -> None: argument
558 Prints test footer with status of test.
564 test - Test object representing current test being printed
566 message = format_test_result(test)
572 def _summarize_failed_tests(test: Test) -> str: argument
573 """Tries to summarize all the failing subtests in `test`."""
575 def failed_names(test: Test, parent_name: str) -> List[str]: argument
576 # Note: we use 'main' internally for the top-level test.
578 full_name = test.name
580 full_name = parent_name + '.' + test.name
582 if not test.subtests: # this is a leaf node
586 # Don't summarize it down "the top-level test failed", though.
587 failed_subtests = [sub for sub in test.subtests if not sub.ok_status()]
588 if parent_name and len(failed_subtests) == len(test.subtests):
596 failures = failed_names(test, '')
604 def print_summary_line(test: Test) -> None: argument
606 Prints summary line of test object. Color of line is dependent on
607 status of test. Color is green if test passes, yellow if test is
608 skipped, and red if the test fails or crashes. Summary line contains
609 counts of the statuses of the tests subtests or the test itself if it
616 test - Test object representing current test being printed
618 if test.status == TestStatus.SUCCESS:
620 elif test.status in (TestStatus.SKIPPED, TestStatus.NO_TESTS):
624 stdout.print_with_timestamp(color(f'Testing complete. {test.counts}'))
628 if test.ok_status() or test.counts.total() < 100:
630 summarized = _summarize_failed_tests(test)
637 def bubble_up_test_results(test: Test) -> None: argument
639 If the test has subtests, add the test counts of the subtests to the
640 test and check if any of the tests crashed and if so set the test
641 status to crashed. Otherwise if the test has no subtests add the
642 status of the test to the test counts.
645 test - Test object for current test being parsed
647 subtests = test.subtests
648 counts = test.counts
649 status = test.status
654 elif test.counts.get_status() == TestStatus.TEST_CRASHED:
655 test.status = TestStatus.TEST_CRASHED
657 def parse_test(lines: LineStream, expected_num: int, log: List[str], is_subtest: bool) -> Test:
659 Finds next test to parse in LineStream, creates new Test object,
660 parses any subtests of the test, populates Test object with all
661 information (status, name) about the test and the Test objects for
662 any subtests, and then returns the Test object. The method accepts
665 Accepted test formats:
701 - Test result line
705 ok 1 - test
709 expected_num - expected test number for test to be parsed
711 corresponding to the current test
712 is_subtest - boolean indicating whether test is a subtest
715 Test object populated with characteristics and any subtests
717 test = Test()
718 test.log.extend(log)
722 test.log.extend(err_log)
725 # If parsing the main/top-level test, parse KTAP version line and
726 # test plan
727 test.name = "main"
728 ktap_line = parse_ktap_header(lines, test)
729 parse_test_plan(lines, test)
732 # If not the main test, attempt to parse a test header containing
734 ktap_line = parse_ktap_header(lines, test)
735 subtest_line = parse_test_header(lines, test)
739 # to parse test plan and print test header
740 parse_test_plan(lines, test)
741 print_test_header(test)
742 expected_count = test.expected_count
748 # if expected number of tests is unknown break when test
752 sub_test = Test()
753 if not lines or (peek_test_name_match(lines, test) and
756 # If parser reaches end of test before
759 test.add_error('missing expected subtest!')
761 test.counts.add_status(
765 test.log.extend(sub_log)
771 test.subtests = subtests
773 # If not main test, look for test result line
774 test.log.extend(parse_diagnostic(lines))
775 if test.name != "" and not peek_test_name_match(lines, test):
776 test.add_error('missing subtest result line!')
778 parse_test_result(lines, test, expected_num)
780 # Check for there being no subtests within parent test
782 # Don't override a bad status if this test had one reported.
783 # Assumption: no subtests means CRASHED is from Test.__init__()
784 if test.status in (TestStatus.TEST_CRASHED, TestStatus.SUCCESS):
785 print_log(test.log)
786 test.status = TestStatus.NO_TESTS
787 test.add_error('0 tests run!')
789 # Add statuses to TestCounts attribute in Test object
790 bubble_up_test_results(test)
792 # If test has subtests and is not the main test object, print
794 print_test_footer(test)
796 print_test_result(test)
797 return test
799 def parse_run_tests(kernel_output: Iterable[str]) -> Test:
801 Using kernel output, extract KTAP lines, parse the lines for test
802 results and print condensed test results and summary line.
808 Test - the main test object with all subtests.
812 test = Test()
814 test.name = '<missing>'
815 test.add_error('Could not find any KTAP output. Did any KUnit tests run?')
816 test.status = TestStatus.FAILURE_TO_PARSE_TESTS
818 test = parse_test(lines, 0, [], False)
819 if test.status != TestStatus.NO_TESTS:
820 test.status = test.counts.get_status()
822 print_summary_line(test)
823 return test