Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'linux_kselftest-kunit-6.13-rc1-fixed' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest

Pull kunit updates from Shuah Khan:

- fix user-after-free (UAF) bug in kunit_init_suite()

- add option to kunit tool to print just the summary of test results

- add option to kunit tool to print just the failed test results

- fix kunit_zalloc_skb() to use user passed in gfp value instead of
hardcoding GFP_KERNEL

- fixe kunit_zalloc_skb() kernel doc to include allocation flags
variable

- update KUnit email address for Brendan Higgins

- add LoongArch config to qemu_configs

- allow overriding the shutdown mode from qemu config

- enable shutdown in loongarch qemu_config

- fix potential null dereference in kunit_device_driver_test()

- fix debugfs to use IS_ERR() for alloc_string_stream() error check

* tag 'linux_kselftest-kunit-6.13-rc1-fixed' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest:
kunit: qemu_configs: loongarch: Enable shutdown
kunit: tool: Allow overriding the shutdown mode from qemu config
kunit: qemu_configs: Add LoongArch config
kunit: debugfs: Use IS_ERR() for alloc_string_stream() error check
kunit: Fix potential null dereference in kunit_device_driver_test()
MAINTAINERS: Update KUnit email address for Brendan Higgins
kunit: string-stream: Fix a UAF bug in kunit_init_suite()
kunit: tool: print failed tests only
kunit: tool: Only print the summary
kunit: skb: add gfp to kernel doc for kunit_zalloc_skb()
kunit: skb: use "gfp" variable instead of hardcoding GFP_KERNEL

+183 -91
+1 -1
MAINTAINERS
··· 12473 12473 F: fs/smb/server/ 12474 12474 12475 12475 KERNEL UNIT TESTING FRAMEWORK (KUnit) 12476 - M: Brendan Higgins <brendanhiggins@google.com> 12476 + M: Brendan Higgins <brendan.higgins@linux.dev> 12477 12477 M: David Gow <davidgow@google.com> 12478 12478 R: Rae Moar <rmoar@google.com> 12479 12479 L: linux-kselftest@vger.kernel.org
+3 -2
include/kunit/skbuff.h
··· 20 20 * kunit_zalloc_skb() - Allocate and initialize a resource managed skb. 21 21 * @test: The test case to which the skb belongs 22 22 * @len: size to allocate 23 + * @gfp: allocation flags 23 24 * 24 - * Allocate a new struct sk_buff with GFP_KERNEL, zero fill the give length 25 + * Allocate a new struct sk_buff with gfp flags, zero fill the given length 25 26 * and add it as a resource to the kunit test for automatic cleanup. 26 27 * 27 28 * Returns: newly allocated SKB, or %NULL on error ··· 30 29 static inline struct sk_buff *kunit_zalloc_skb(struct kunit *test, int len, 31 30 gfp_t gfp) 32 31 { 33 - struct sk_buff *res = alloc_skb(len, GFP_KERNEL); 32 + struct sk_buff *res = alloc_skb(len, gfp); 34 33 35 34 if (!res || skb_pad(res, len)) 36 35 return NULL;
+6 -3
lib/kunit/debugfs.c
··· 181 181 * successfully. 182 182 */ 183 183 stream = alloc_string_stream(GFP_KERNEL); 184 - if (IS_ERR_OR_NULL(stream)) 184 + if (IS_ERR(stream)) 185 185 return; 186 186 187 187 string_stream_set_append_newlines(stream, true); ··· 189 189 190 190 kunit_suite_for_each_test_case(suite, test_case) { 191 191 stream = alloc_string_stream(GFP_KERNEL); 192 - if (IS_ERR_OR_NULL(stream)) 192 + if (IS_ERR(stream)) 193 193 goto err; 194 194 195 195 string_stream_set_append_newlines(stream, true); ··· 212 212 213 213 err: 214 214 string_stream_destroy(suite->log); 215 - kunit_suite_for_each_test_case(suite, test_case) 215 + suite->log = NULL; 216 + kunit_suite_for_each_test_case(suite, test_case) { 216 217 string_stream_destroy(test_case->log); 218 + test_case->log = NULL; 219 + } 217 220 } 218 221 219 222 void kunit_debugfs_destroy_suite(struct kunit_suite *suite)
+2
lib/kunit/kunit-test.c
··· 805 805 struct device *test_device; 806 806 struct driver_test_state *test_state = kunit_kzalloc(test, sizeof(*test_state), GFP_KERNEL); 807 807 808 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_state); 809 + 808 810 test->priv = test_state; 809 811 test_driver = kunit_driver_create(test, "my_driver"); 810 812
+25 -3
tools/testing/kunit/kunit.py
··· 23 23 import kunit_json 24 24 import kunit_kernel 25 25 import kunit_parser 26 - from kunit_printer import stdout 26 + from kunit_printer import stdout, null_printer 27 27 28 28 class KunitStatus(Enum): 29 29 SUCCESS = auto() ··· 49 49 class KunitParseRequest: 50 50 raw_output: Optional[str] 51 51 json: Optional[str] 52 + summary: bool 53 + failed: bool 52 54 53 55 @dataclass 54 56 class KunitExecRequest(KunitParseRequest): ··· 237 235 parse_time = time.time() - parse_start 238 236 return KunitResult(KunitStatus.SUCCESS, parse_time), fake_test 239 237 238 + default_printer = stdout 239 + if request.summary or request.failed: 240 + default_printer = null_printer 240 241 241 242 # Actually parse the test results. 242 - test = kunit_parser.parse_run_tests(input_data) 243 + test = kunit_parser.parse_run_tests(input_data, default_printer) 243 244 parse_time = time.time() - parse_start 245 + 246 + if request.failed: 247 + kunit_parser.print_test(test, request.failed, stdout) 248 + kunit_parser.print_summary_line(test, stdout) 244 249 245 250 if request.json: 246 251 json_str = kunit_json.get_json_result( ··· 422 413 help='Prints parsed test results as JSON to stdout or a file if ' 423 414 'a filename is specified. Does nothing if --raw_output is set.', 424 415 type=str, const='stdout', default=None, metavar='FILE') 416 + parser.add_argument('--summary', 417 + help='Prints only the summary line for parsed test results.' 418 + 'Does nothing if --raw_output is set.', 419 + action='store_true') 420 + parser.add_argument('--failed', 421 + help='Prints only the failed parsed test results and summary line.' 422 + 'Does nothing if --raw_output is set.', 423 + action='store_true') 425 424 426 425 427 426 def tree_from_args(cli_args: argparse.Namespace) -> kunit_kernel.LinuxSourceTree: ··· 465 448 jobs=cli_args.jobs, 466 449 raw_output=cli_args.raw_output, 467 450 json=cli_args.json, 451 + summary=cli_args.summary, 452 + failed=cli_args.failed, 468 453 timeout=cli_args.timeout, 469 454 filter_glob=cli_args.filter_glob, 470 455 filter=cli_args.filter, ··· 514 495 exec_request = KunitExecRequest(raw_output=cli_args.raw_output, 515 496 build_dir=cli_args.build_dir, 516 497 json=cli_args.json, 498 + summary=cli_args.summary, 499 + failed=cli_args.failed, 517 500 timeout=cli_args.timeout, 518 501 filter_glob=cli_args.filter_glob, 519 502 filter=cli_args.filter, ··· 541 520 # We know nothing about how the result was created! 542 521 metadata = kunit_json.Metadata() 543 522 request = KunitParseRequest(raw_output=cli_args.raw_output, 544 - json=cli_args.json) 523 + json=cli_args.json, summary=cli_args.summary, 524 + failed=cli_args.failed) 545 525 result, _ = parse_tests(request, metadata, kunit_output) 546 526 if result.status != KunitStatus.SUCCESS: 547 527 sys.exit(1)
+3 -1
tools/testing/kunit/kunit_kernel.py
··· 105 105 self._kconfig = qemu_arch_params.kconfig 106 106 self._qemu_arch = qemu_arch_params.qemu_arch 107 107 self._kernel_path = qemu_arch_params.kernel_path 108 - self._kernel_command_line = qemu_arch_params.kernel_command_line + ' kunit_shutdown=reboot' 108 + self._kernel_command_line = qemu_arch_params.kernel_command_line 109 + if 'kunit_shutdown=' not in self._kernel_command_line: 110 + self._kernel_command_line += ' kunit_shutdown=reboot' 109 111 self._extra_qemu_params = qemu_arch_params.extra_qemu_params 110 112 self._serial = qemu_arch_params.serial 111 113
+84 -50
tools/testing/kunit/kunit_parser.py
··· 17 17 from enum import Enum, auto 18 18 from typing import Iterable, Iterator, List, Optional, Tuple 19 19 20 - from kunit_printer import stdout 20 + from kunit_printer import Printer, stdout 21 21 22 22 class Test: 23 23 """ ··· 54 54 """Returns string representation of a Test class object.""" 55 55 return str(self) 56 56 57 - def add_error(self, error_message: str) -> None: 57 + def add_error(self, printer: Printer, error_message: str) -> None: 58 58 """Records an error that occurred while parsing this test.""" 59 59 self.counts.errors += 1 60 - stdout.print_with_timestamp(stdout.red('[ERROR]') + f' Test: {self.name}: {error_message}') 60 + printer.print_with_timestamp(stdout.red('[ERROR]') + f' Test: {self.name}: {error_message}') 61 61 62 62 def ok_status(self) -> bool: 63 63 """Returns true if the status was ok, i.e. passed or skipped.""" ··· 251 251 TAP_VERSIONS = [13, 14] 252 252 253 253 def check_version(version_num: int, accepted_versions: List[int], 254 - version_type: str, test: Test) -> None: 254 + version_type: str, test: Test, printer: Printer) -> None: 255 255 """ 256 256 Adds error to test object if version number is too high or too 257 257 low. ··· 263 263 version_type - 'KTAP' or 'TAP' depending on the type of 264 264 version line. 265 265 test - Test object for current test being parsed 266 + printer - Printer object to output error 266 267 """ 267 268 if version_num < min(accepted_versions): 268 - test.add_error(f'{version_type} version lower than expected!') 269 + test.add_error(printer, f'{version_type} version lower than expected!') 269 270 elif version_num > max(accepted_versions): 270 - test.add_error(f'{version_type} version higer than expected!') 271 + test.add_error(printer, f'{version_type} version higer than expected!') 271 272 272 - def parse_ktap_header(lines: LineStream, test: Test) -> bool: 273 + def parse_ktap_header(lines: LineStream, test: Test, printer: Printer) -> bool: 273 274 """ 274 275 Parses KTAP/TAP header line and checks version number. 275 276 Returns False if fails to parse KTAP/TAP header line. ··· 282 281 Parameters: 283 282 lines - LineStream of KTAP output to parse 284 283 test - Test object for current test being parsed 284 + printer - Printer object to output results 285 285 286 286 Return: 287 287 True if successfully parsed KTAP/TAP header line ··· 291 289 tap_match = TAP_START.match(lines.peek()) 292 290 if ktap_match: 293 291 version_num = int(ktap_match.group(1)) 294 - check_version(version_num, KTAP_VERSIONS, 'KTAP', test) 292 + check_version(version_num, KTAP_VERSIONS, 'KTAP', test, printer) 295 293 elif tap_match: 296 294 version_num = int(tap_match.group(1)) 297 - check_version(version_num, TAP_VERSIONS, 'TAP', test) 295 + check_version(version_num, TAP_VERSIONS, 'TAP', test, printer) 298 296 else: 299 297 return False 300 298 lines.pop() ··· 382 380 return name == test.name 383 381 384 382 def parse_test_result(lines: LineStream, test: Test, 385 - expected_num: int) -> bool: 383 + expected_num: int, printer: Printer) -> bool: 386 384 """ 387 385 Parses test result line and stores the status and name in the test 388 386 object. Reports an error if the test number does not match expected ··· 400 398 lines - LineStream of KTAP output to parse 401 399 test - Test object for current test being parsed 402 400 expected_num - expected test number for current test 401 + printer - Printer object to output results 403 402 404 403 Return: 405 404 True if successfully parsed a test result line. ··· 423 420 # Check test num 424 421 num = int(match.group(2)) 425 422 if num != expected_num: 426 - test.add_error(f'Expected test number {expected_num} but found {num}') 423 + test.add_error(printer, f'Expected test number {expected_num} but found {num}') 427 424 428 425 # Set status of test object 429 426 status = match.group(1) ··· 489 486 len_2 = difference - len_1 490 487 return ('=' * len_1) + f' {message} ' + ('=' * len_2) 491 488 492 - def print_test_header(test: Test) -> None: 489 + def print_test_header(test: Test, printer: Printer) -> None: 493 490 """ 494 491 Prints test header with test name and optionally the expected number 495 492 of subtests. ··· 499 496 500 497 Parameters: 501 498 test - Test object representing current test being printed 499 + printer - Printer object to output results 502 500 """ 503 501 message = test.name 504 502 if message != "": ··· 511 507 message += '(1 subtest)' 512 508 else: 513 509 message += f'({test.expected_count} subtests)' 514 - stdout.print_with_timestamp(format_test_divider(message, len(message))) 510 + printer.print_with_timestamp(format_test_divider(message, len(message))) 515 511 516 - def print_log(log: Iterable[str]) -> None: 512 + def print_log(log: Iterable[str], printer: Printer) -> None: 517 513 """Prints all strings in saved log for test in yellow.""" 518 514 formatted = textwrap.dedent('\n'.join(log)) 519 515 for line in formatted.splitlines(): 520 - stdout.print_with_timestamp(stdout.yellow(line)) 516 + printer.print_with_timestamp(printer.yellow(line)) 521 517 522 - def format_test_result(test: Test) -> str: 518 + def format_test_result(test: Test, printer: Printer) -> str: 523 519 """ 524 520 Returns string with formatted test result with colored status and test 525 521 name. ··· 529 525 530 526 Parameters: 531 527 test - Test object representing current test being printed 528 + printer - Printer object to output results 532 529 533 530 Return: 534 531 String containing formatted test result 535 532 """ 536 533 if test.status == TestStatus.SUCCESS: 537 - return stdout.green('[PASSED] ') + test.name 534 + return printer.green('[PASSED] ') + test.name 538 535 if test.status == TestStatus.SKIPPED: 539 - return stdout.yellow('[SKIPPED] ') + test.name 536 + return printer.yellow('[SKIPPED] ') + test.name 540 537 if test.status == TestStatus.NO_TESTS: 541 - return stdout.yellow('[NO TESTS RUN] ') + test.name 538 + return printer.yellow('[NO TESTS RUN] ') + test.name 542 539 if test.status == TestStatus.TEST_CRASHED: 543 - print_log(test.log) 540 + print_log(test.log, printer) 544 541 return stdout.red('[CRASHED] ') + test.name 545 - print_log(test.log) 546 - return stdout.red('[FAILED] ') + test.name 542 + print_log(test.log, printer) 543 + return printer.red('[FAILED] ') + test.name 547 544 548 - def print_test_result(test: Test) -> None: 545 + def print_test_result(test: Test, printer: Printer) -> None: 549 546 """ 550 547 Prints result line with status of test. 551 548 ··· 555 550 556 551 Parameters: 557 552 test - Test object representing current test being printed 553 + printer - Printer object 558 554 """ 559 - stdout.print_with_timestamp(format_test_result(test)) 555 + printer.print_with_timestamp(format_test_result(test, printer)) 560 556 561 - def print_test_footer(test: Test) -> None: 557 + def print_test_footer(test: Test, printer: Printer) -> None: 562 558 """ 563 559 Prints test footer with status of test. 564 560 ··· 568 562 569 563 Parameters: 570 564 test - Test object representing current test being printed 565 + printer - Printer object to output results 571 566 """ 572 - message = format_test_result(test) 573 - stdout.print_with_timestamp(format_test_divider(message, 574 - len(message) - stdout.color_len())) 567 + message = format_test_result(test, printer) 568 + printer.print_with_timestamp(format_test_divider(message, 569 + len(message) - printer.color_len())) 575 570 571 + def print_test(test: Test, failed_only: bool, printer: Printer) -> None: 572 + """ 573 + Prints Test object to given printer. For a child test, the result line is 574 + printed. For a parent test, the test header, all child test results, and 575 + the test footer are all printed. If failed_only is true, only failed/crashed 576 + tests will be printed. 576 577 578 + Parameters: 579 + test - Test object to print 580 + failed_only - True if only failed/crashed tests should be printed. 581 + printer - Printer object to output results 582 + """ 583 + if test.name == "main": 584 + printer.print_with_timestamp(DIVIDER) 585 + for subtest in test.subtests: 586 + print_test(subtest, failed_only, printer) 587 + printer.print_with_timestamp(DIVIDER) 588 + elif test.subtests != []: 589 + if not failed_only or not test.ok_status(): 590 + print_test_header(test, printer) 591 + for subtest in test.subtests: 592 + print_test(subtest, failed_only, printer) 593 + print_test_footer(test, printer) 594 + else: 595 + if not failed_only or not test.ok_status(): 596 + print_test_result(test, printer) 577 597 578 598 def _summarize_failed_tests(test: Test) -> str: 579 599 """Tries to summarize all the failing subtests in `test`.""" ··· 633 601 return 'Failures: ' + ', '.join(failures) 634 602 635 603 636 - def print_summary_line(test: Test) -> None: 604 + def print_summary_line(test: Test, printer: Printer) -> None: 637 605 """ 638 606 Prints summary line of test object. Color of line is dependent on 639 607 status of test. Color is green if test passes, yellow if test is ··· 646 614 Errors: 0" 647 615 648 616 test - Test object representing current test being printed 617 + printer - Printer object to output results 649 618 """ 650 619 if test.status == TestStatus.SUCCESS: 651 620 color = stdout.green ··· 654 621 color = stdout.yellow 655 622 else: 656 623 color = stdout.red 657 - stdout.print_with_timestamp(color(f'Testing complete. {test.counts}')) 624 + printer.print_with_timestamp(color(f'Testing complete. {test.counts}')) 658 625 659 626 # Summarize failures that might have gone off-screen since we had a lot 660 627 # of tests (arbitrarily defined as >=100 for now). ··· 663 630 summarized = _summarize_failed_tests(test) 664 631 if not summarized: 665 632 return 666 - stdout.print_with_timestamp(color(summarized)) 633 + printer.print_with_timestamp(color(summarized)) 667 634 668 635 # Other methods: 669 636 ··· 687 654 elif test.counts.get_status() == TestStatus.TEST_CRASHED: 688 655 test.status = TestStatus.TEST_CRASHED 689 656 690 - def parse_test(lines: LineStream, expected_num: int, log: List[str], is_subtest: bool) -> Test: 657 + def parse_test(lines: LineStream, expected_num: int, log: List[str], is_subtest: bool, printer: Printer) -> Test: 691 658 """ 692 659 Finds next test to parse in LineStream, creates new Test object, 693 660 parses any subtests of the test, populates Test object with all ··· 743 710 log - list of strings containing any preceding diagnostic lines 744 711 corresponding to the current test 745 712 is_subtest - boolean indicating whether test is a subtest 713 + printer - Printer object to output results 746 714 747 715 Return: 748 716 Test object populated with characteristics and any subtests ··· 759 725 # If parsing the main/top-level test, parse KTAP version line and 760 726 # test plan 761 727 test.name = "main" 762 - ktap_line = parse_ktap_header(lines, test) 728 + ktap_line = parse_ktap_header(lines, test, printer) 763 729 test.log.extend(parse_diagnostic(lines)) 764 730 parse_test_plan(lines, test) 765 731 parent_test = True 766 732 else: 767 733 # If not the main test, attempt to parse a test header containing 768 734 # the KTAP version line and/or subtest header line 769 - ktap_line = parse_ktap_header(lines, test) 735 + ktap_line = parse_ktap_header(lines, test, printer) 770 736 subtest_line = parse_test_header(lines, test) 771 737 parent_test = (ktap_line or subtest_line) 772 738 if parent_test: ··· 774 740 # to parse test plan and print test header 775 741 test.log.extend(parse_diagnostic(lines)) 776 742 parse_test_plan(lines, test) 777 - print_test_header(test) 743 + print_test_header(test, printer) 778 744 expected_count = test.expected_count 779 745 subtests = [] 780 746 test_num = 1 ··· 792 758 # If parser reaches end of test before 793 759 # parsing expected number of subtests, print 794 760 # crashed subtest and record error 795 - test.add_error('missing expected subtest!') 761 + test.add_error(printer, 'missing expected subtest!') 796 762 sub_test.log.extend(sub_log) 797 763 test.counts.add_status( 798 764 TestStatus.TEST_CRASHED) 799 - print_test_result(sub_test) 765 + print_test_result(sub_test, printer) 800 766 else: 801 767 test.log.extend(sub_log) 802 768 break 803 769 else: 804 - sub_test = parse_test(lines, test_num, sub_log, True) 770 + sub_test = parse_test(lines, test_num, sub_log, True, printer) 805 771 subtests.append(sub_test) 806 772 test_num += 1 807 773 test.subtests = subtests ··· 809 775 # If not main test, look for test result line 810 776 test.log.extend(parse_diagnostic(lines)) 811 777 if test.name != "" and not peek_test_name_match(lines, test): 812 - test.add_error('missing subtest result line!') 778 + test.add_error(printer, 'missing subtest result line!') 813 779 else: 814 - parse_test_result(lines, test, expected_num) 780 + parse_test_result(lines, test, expected_num, printer) 815 781 816 782 # Check for there being no subtests within parent test 817 783 if parent_test and len(subtests) == 0: 818 784 # Don't override a bad status if this test had one reported. 819 785 # Assumption: no subtests means CRASHED is from Test.__init__() 820 786 if test.status in (TestStatus.TEST_CRASHED, TestStatus.SUCCESS): 821 - print_log(test.log) 787 + print_log(test.log, printer) 822 788 test.status = TestStatus.NO_TESTS 823 - test.add_error('0 tests run!') 789 + test.add_error(printer, '0 tests run!') 824 790 825 791 # Add statuses to TestCounts attribute in Test object 826 792 bubble_up_test_results(test) 827 793 if parent_test and is_subtest: 828 794 # If test has subtests and is not the main test object, print 829 795 # footer. 830 - print_test_footer(test) 796 + print_test_footer(test, printer) 831 797 elif is_subtest: 832 - print_test_result(test) 798 + print_test_result(test, printer) 833 799 return test 834 800 835 - def parse_run_tests(kernel_output: Iterable[str]) -> Test: 801 + def parse_run_tests(kernel_output: Iterable[str], printer: Printer) -> Test: 836 802 """ 837 803 Using kernel output, extract KTAP lines, parse the lines for test 838 804 results and print condensed test results and summary line. 839 805 840 806 Parameters: 841 807 kernel_output - Iterable object contains lines of kernel output 808 + printer - Printer object to output results 842 809 843 810 Return: 844 811 Test - the main test object with all subtests. 845 812 """ 846 - stdout.print_with_timestamp(DIVIDER) 813 + printer.print_with_timestamp(DIVIDER) 847 814 lines = extract_tap_lines(kernel_output) 848 815 test = Test() 849 816 if not lines: 850 817 test.name = '<missing>' 851 - test.add_error('Could not find any KTAP output. Did any KUnit tests run?') 818 + test.add_error(printer, 'Could not find any KTAP output. Did any KUnit tests run?') 852 819 test.status = TestStatus.FAILURE_TO_PARSE_TESTS 853 820 else: 854 - test = parse_test(lines, 0, [], False) 821 + test = parse_test(lines, 0, [], False, printer) 855 822 if test.status != TestStatus.NO_TESTS: 856 823 test.status = test.counts.get_status() 857 - stdout.print_with_timestamp(DIVIDER) 858 - print_summary_line(test) 824 + printer.print_with_timestamp(DIVIDER) 859 825 return test
+10 -4
tools/testing/kunit/kunit_printer.py
··· 15 15 class Printer: 16 16 """Wraps a file object, providing utilities for coloring output, etc.""" 17 17 18 - def __init__(self, output: typing.IO[str]): 18 + def __init__(self, print: bool=True, output: typing.IO[str]=sys.stdout): 19 19 self._output = output 20 - self._use_color = output.isatty() 20 + self._print = print 21 + if print: 22 + self._use_color = output.isatty() 23 + else: 24 + self._use_color = False 21 25 22 26 def print(self, message: str) -> None: 23 - print(message, file=self._output) 27 + if self._print: 28 + print(message, file=self._output) 24 29 25 30 def print_with_timestamp(self, message: str) -> None: 26 31 ts = datetime.datetime.now().strftime('%H:%M:%S') ··· 50 45 return len(self.red('')) 51 46 52 47 # Provides a default instance that prints to stdout 53 - stdout = Printer(sys.stdout) 48 + stdout = Printer() 49 + null_printer = Printer(print=False)
+28 -27
tools/testing/kunit/kunit_tool_test.py
··· 23 23 import kunit_kernel 24 24 import kunit_json 25 25 import kunit 26 + from kunit_printer import stdout 26 27 27 28 test_tmpdir = '' 28 29 abs_test_data_dir = '' ··· 140 139 def test_parse_successful_test_log(self): 141 140 all_passed_log = test_data_path('test_is_test_passed-all_passed.log') 142 141 with open(all_passed_log) as file: 143 - result = kunit_parser.parse_run_tests(file.readlines()) 142 + result = kunit_parser.parse_run_tests(file.readlines(), stdout) 144 143 self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status) 145 144 self.assertEqual(result.counts.errors, 0) 146 145 147 146 def test_parse_successful_nested_tests_log(self): 148 147 all_passed_log = test_data_path('test_is_test_passed-all_passed_nested.log') 149 148 with open(all_passed_log) as file: 150 - result = kunit_parser.parse_run_tests(file.readlines()) 149 + result = kunit_parser.parse_run_tests(file.readlines(), stdout) 151 150 self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status) 152 151 self.assertEqual(result.counts.errors, 0) 153 152 154 153 def test_kselftest_nested(self): 155 154 kselftest_log = test_data_path('test_is_test_passed-kselftest.log') 156 155 with open(kselftest_log) as file: 157 - result = kunit_parser.parse_run_tests(file.readlines()) 156 + result = kunit_parser.parse_run_tests(file.readlines(), stdout) 158 157 self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status) 159 158 self.assertEqual(result.counts.errors, 0) 160 159 161 160 def test_parse_failed_test_log(self): 162 161 failed_log = test_data_path('test_is_test_passed-failure.log') 163 162 with open(failed_log) as file: 164 - result = kunit_parser.parse_run_tests(file.readlines()) 163 + result = kunit_parser.parse_run_tests(file.readlines(), stdout) 165 164 self.assertEqual(kunit_parser.TestStatus.FAILURE, result.status) 166 165 self.assertEqual(result.counts.errors, 0) 167 166 ··· 169 168 empty_log = test_data_path('test_is_test_passed-no_tests_run_no_header.log') 170 169 with open(empty_log) as file: 171 170 result = kunit_parser.parse_run_tests( 172 - kunit_parser.extract_tap_lines(file.readlines())) 171 + kunit_parser.extract_tap_lines(file.readlines()), stdout) 173 172 self.assertEqual(0, len(result.subtests)) 174 173 self.assertEqual(kunit_parser.TestStatus.FAILURE_TO_PARSE_TESTS, result.status) 175 174 self.assertEqual(result.counts.errors, 1) ··· 180 179 with open(missing_plan_log) as file: 181 180 result = kunit_parser.parse_run_tests( 182 181 kunit_parser.extract_tap_lines( 183 - file.readlines())) 182 + file.readlines()), stdout) 184 183 # A missing test plan is not an error. 185 184 self.assertEqual(result.counts, kunit_parser.TestCounts(passed=10, errors=0)) 186 185 self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status) ··· 189 188 header_log = test_data_path('test_is_test_passed-no_tests_run_with_header.log') 190 189 with open(header_log) as file: 191 190 result = kunit_parser.parse_run_tests( 192 - kunit_parser.extract_tap_lines(file.readlines())) 191 + kunit_parser.extract_tap_lines(file.readlines()), stdout) 193 192 self.assertEqual(0, len(result.subtests)) 194 193 self.assertEqual(kunit_parser.TestStatus.NO_TESTS, result.status) 195 194 self.assertEqual(result.counts.errors, 1) ··· 198 197 no_plan_log = test_data_path('test_is_test_passed-no_tests_no_plan.log') 199 198 with open(no_plan_log) as file: 200 199 result = kunit_parser.parse_run_tests( 201 - kunit_parser.extract_tap_lines(file.readlines())) 200 + kunit_parser.extract_tap_lines(file.readlines()), stdout) 202 201 self.assertEqual(0, len(result.subtests[0].subtests[0].subtests)) 203 202 self.assertEqual( 204 203 kunit_parser.TestStatus.NO_TESTS, ··· 211 210 print_mock = mock.patch('kunit_printer.Printer.print').start() 212 211 with open(crash_log) as file: 213 212 result = kunit_parser.parse_run_tests( 214 - kunit_parser.extract_tap_lines(file.readlines())) 213 + kunit_parser.extract_tap_lines(file.readlines()), stdout) 215 214 print_mock.assert_any_call(StrContains('Could not find any KTAP output.')) 216 215 print_mock.stop() 217 216 self.assertEqual(0, len(result.subtests)) ··· 220 219 def test_skipped_test(self): 221 220 skipped_log = test_data_path('test_skip_tests.log') 222 221 with open(skipped_log) as file: 223 - result = kunit_parser.parse_run_tests(file.readlines()) 222 + result = kunit_parser.parse_run_tests(file.readlines(), stdout) 224 223 225 224 # A skipped test does not fail the whole suite. 226 225 self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status) ··· 229 228 def test_skipped_all_tests(self): 230 229 skipped_log = test_data_path('test_skip_all_tests.log') 231 230 with open(skipped_log) as file: 232 - result = kunit_parser.parse_run_tests(file.readlines()) 231 + result = kunit_parser.parse_run_tests(file.readlines(), stdout) 233 232 234 233 self.assertEqual(kunit_parser.TestStatus.SKIPPED, result.status) 235 234 self.assertEqual(result.counts, kunit_parser.TestCounts(skipped=5)) ··· 237 236 def test_ignores_hyphen(self): 238 237 hyphen_log = test_data_path('test_strip_hyphen.log') 239 238 with open(hyphen_log) as file: 240 - result = kunit_parser.parse_run_tests(file.readlines()) 239 + result = kunit_parser.parse_run_tests(file.readlines(), stdout) 241 240 242 241 # A skipped test does not fail the whole suite. 243 242 self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status) ··· 251 250 def test_ignores_prefix_printk_time(self): 252 251 prefix_log = test_data_path('test_config_printk_time.log') 253 252 with open(prefix_log) as file: 254 - result = kunit_parser.parse_run_tests(file.readlines()) 253 + result = kunit_parser.parse_run_tests(file.readlines(), stdout) 255 254 self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status) 256 255 self.assertEqual('kunit-resource-test', result.subtests[0].name) 257 256 self.assertEqual(result.counts.errors, 0) ··· 259 258 def test_ignores_multiple_prefixes(self): 260 259 prefix_log = test_data_path('test_multiple_prefixes.log') 261 260 with open(prefix_log) as file: 262 - result = kunit_parser.parse_run_tests(file.readlines()) 261 + result = kunit_parser.parse_run_tests(file.readlines(), stdout) 263 262 self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status) 264 263 self.assertEqual('kunit-resource-test', result.subtests[0].name) 265 264 self.assertEqual(result.counts.errors, 0) ··· 267 266 def test_prefix_mixed_kernel_output(self): 268 267 mixed_prefix_log = test_data_path('test_interrupted_tap_output.log') 269 268 with open(mixed_prefix_log) as file: 270 - result = kunit_parser.parse_run_tests(file.readlines()) 269 + result = kunit_parser.parse_run_tests(file.readlines(), stdout) 271 270 self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status) 272 271 self.assertEqual('kunit-resource-test', result.subtests[0].name) 273 272 self.assertEqual(result.counts.errors, 0) ··· 275 274 def test_prefix_poundsign(self): 276 275 pound_log = test_data_path('test_pound_sign.log') 277 276 with open(pound_log) as file: 278 - result = kunit_parser.parse_run_tests(file.readlines()) 277 + result = kunit_parser.parse_run_tests(file.readlines(), stdout) 279 278 self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status) 280 279 self.assertEqual('kunit-resource-test', result.subtests[0].name) 281 280 self.assertEqual(result.counts.errors, 0) ··· 283 282 def test_kernel_panic_end(self): 284 283 panic_log = test_data_path('test_kernel_panic_interrupt.log') 285 284 with open(panic_log) as file: 286 - result = kunit_parser.parse_run_tests(file.readlines()) 285 + result = kunit_parser.parse_run_tests(file.readlines(), stdout) 287 286 self.assertEqual(kunit_parser.TestStatus.TEST_CRASHED, result.status) 288 287 self.assertEqual('kunit-resource-test', result.subtests[0].name) 289 288 self.assertGreaterEqual(result.counts.errors, 1) ··· 291 290 def test_pound_no_prefix(self): 292 291 pound_log = test_data_path('test_pound_no_prefix.log') 293 292 with open(pound_log) as file: 294 - result = kunit_parser.parse_run_tests(file.readlines()) 293 + result = kunit_parser.parse_run_tests(file.readlines(), stdout) 295 294 self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status) 296 295 self.assertEqual('kunit-resource-test', result.subtests[0].name) 297 296 self.assertEqual(result.counts.errors, 0) ··· 311 310 not ok 2 - test2 312 311 not ok 1 - some_failed_suite 313 312 """ 314 - result = kunit_parser.parse_run_tests(output.splitlines()) 313 + result = kunit_parser.parse_run_tests(output.splitlines(), stdout) 315 314 self.assertEqual(kunit_parser.TestStatus.FAILURE, result.status) 316 315 317 316 self.assertEqual(kunit_parser._summarize_failed_tests(result), ··· 320 319 def test_ktap_format(self): 321 320 ktap_log = test_data_path('test_parse_ktap_output.log') 322 321 with open(ktap_log) as file: 323 - result = kunit_parser.parse_run_tests(file.readlines()) 322 + result = kunit_parser.parse_run_tests(file.readlines(), stdout) 324 323 self.assertEqual(result.counts, kunit_parser.TestCounts(passed=3)) 325 324 self.assertEqual('suite', result.subtests[0].name) 326 325 self.assertEqual('case_1', result.subtests[0].subtests[0].name) ··· 329 328 def test_parse_subtest_header(self): 330 329 ktap_log = test_data_path('test_parse_subtest_header.log') 331 330 with open(ktap_log) as file: 332 - kunit_parser.parse_run_tests(file.readlines()) 331 + kunit_parser.parse_run_tests(file.readlines(), stdout) 333 332 self.print_mock.assert_any_call(StrContains('suite (1 subtest)')) 334 333 335 334 def test_parse_attributes(self): 336 335 ktap_log = test_data_path('test_parse_attributes.log') 337 336 with open(ktap_log) as file: 338 - result = kunit_parser.parse_run_tests(file.readlines()) 337 + result = kunit_parser.parse_run_tests(file.readlines(), stdout) 339 338 340 339 # Test should pass with no errors 341 340 self.assertEqual(result.counts, kunit_parser.TestCounts(passed=1, errors=0)) ··· 356 355 Indented more. 357 356 not ok 1 test1 358 357 """ 359 - result = kunit_parser.parse_run_tests(output.splitlines()) 358 + result = kunit_parser.parse_run_tests(output.splitlines(), stdout) 360 359 self.assertEqual(kunit_parser.TestStatus.FAILURE, result.status) 361 360 362 361 self.print_mock.assert_any_call(StrContains('Test output.')) ··· 545 544 546 545 def _json_for(self, log_file): 547 546 with open(test_data_path(log_file)) as file: 548 - test_result = kunit_parser.parse_run_tests(file) 547 + test_result = kunit_parser.parse_run_tests(file, stdout) 549 548 json_obj = kunit_json.get_json_result( 550 549 test=test_result, 551 550 metadata=kunit_json.Metadata()) ··· 811 810 self.linux_source_mock.run_kernel.return_value = ['TAP version 14', 'init: random output'] + want 812 811 813 812 got = kunit._list_tests(self.linux_source_mock, 814 - kunit.KunitExecRequest(None, None, '.kunit', 300, 'suite*', '', None, None, 'suite', False, False)) 813 + kunit.KunitExecRequest(None, None, False, False, '.kunit', 300, 'suite*', '', None, None, 'suite', False, False)) 815 814 self.assertEqual(got, want) 816 815 # Should respect the user's filter glob when listing tests. 817 816 self.linux_source_mock.run_kernel.assert_called_once_with( ··· 824 823 825 824 # Should respect the user's filter glob when listing tests. 826 825 mock_tests.assert_called_once_with(mock.ANY, 827 - kunit.KunitExecRequest(None, None, '.kunit', 300, 'suite*.test*', '', None, None, 'suite', False, False)) 826 + kunit.KunitExecRequest(None, None, False, False, '.kunit', 300, 'suite*.test*', '', None, None, 'suite', False, False)) 828 827 self.linux_source_mock.run_kernel.assert_has_calls([ 829 828 mock.call(args=None, build_dir='.kunit', filter_glob='suite.test*', filter='', filter_action=None, timeout=300), 830 829 mock.call(args=None, build_dir='.kunit', filter_glob='suite2.test*', filter='', filter_action=None, timeout=300), ··· 837 836 838 837 # Should respect the user's filter glob when listing tests. 839 838 mock_tests.assert_called_once_with(mock.ANY, 840 - kunit.KunitExecRequest(None, None, '.kunit', 300, 'suite*', '', None, None, 'test', False, False)) 839 + kunit.KunitExecRequest(None, None, False, False, '.kunit', 300, 'suite*', '', None, None, 'test', False, False)) 841 840 self.linux_source_mock.run_kernel.assert_has_calls([ 842 841 mock.call(args=None, build_dir='.kunit', filter_glob='suite.test1', filter='', filter_action=None, timeout=300), 843 842 mock.call(args=None, build_dir='.kunit', filter_glob='suite.test2', filter='', filter_action=None, timeout=300),
+21
tools/testing/kunit/qemu_configs/loongarch.py
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + 3 + from ..qemu_config import QemuArchParams 4 + 5 + QEMU_ARCH = QemuArchParams(linux_arch='loongarch', 6 + kconfig=''' 7 + CONFIG_EFI_STUB=n 8 + CONFIG_PCI_HOST_GENERIC=y 9 + CONFIG_PVPANIC=y 10 + CONFIG_PVPANIC_PCI=y 11 + CONFIG_SERIAL_8250=y 12 + CONFIG_SERIAL_8250_CONSOLE=y 13 + CONFIG_SERIAL_OF_PLATFORM=y 14 + ''', 15 + qemu_arch='loongarch64', 16 + kernel_path='arch/loongarch/boot/vmlinux.elf', 17 + kernel_command_line='console=ttyS0 kunit_shutdown=poweroff', 18 + extra_qemu_params=[ 19 + '-machine', 'virt', 20 + '-device', 'pvpanic-pci', 21 + '-cpu', 'max',])