Back to home page

OSCL-LXR

 
 

    


0001 #!/usr/bin/env python3
0002 # SPDX-License-Identifier: GPL-2.0
0003 #
0004 # A collection of tests for tools/testing/kunit/kunit.py
0005 #
0006 # Copyright (C) 2019, Google LLC.
0007 # Author: Brendan Higgins <brendanhiggins@google.com>
0008 
0009 import unittest
0010 from unittest import mock
0011 
0012 import tempfile, shutil # Handling test_tmpdir
0013 
0014 import itertools
0015 import json
0016 import os
0017 import signal
0018 import subprocess
0019 from typing import Iterable
0020 
0021 import kunit_config
0022 import kunit_parser
0023 import kunit_kernel
0024 import kunit_json
0025 import kunit
0026 
0027 test_tmpdir = ''
0028 abs_test_data_dir = ''
0029 
0030 def setUpModule():
0031     global test_tmpdir, abs_test_data_dir
0032     test_tmpdir = tempfile.mkdtemp()
0033     abs_test_data_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), 'test_data'))
0034 
0035 def tearDownModule():
0036     shutil.rmtree(test_tmpdir)
0037 
0038 def test_data_path(path):
0039     return os.path.join(abs_test_data_dir, path)
0040 
0041 class KconfigTest(unittest.TestCase):
0042 
0043     def test_is_subset_of(self):
0044         kconfig0 = kunit_config.Kconfig()
0045         self.assertTrue(kconfig0.is_subset_of(kconfig0))
0046 
0047         kconfig1 = kunit_config.Kconfig()
0048         kconfig1.add_entry('TEST', 'y')
0049         self.assertTrue(kconfig1.is_subset_of(kconfig1))
0050         self.assertTrue(kconfig0.is_subset_of(kconfig1))
0051         self.assertFalse(kconfig1.is_subset_of(kconfig0))
0052 
0053     def test_read_from_file(self):
0054         kconfig_path = test_data_path('test_read_from_file.kconfig')
0055 
0056         kconfig = kunit_config.parse_file(kconfig_path)
0057 
0058         expected_kconfig = kunit_config.Kconfig()
0059         expected_kconfig.add_entry('UML', 'y')
0060         expected_kconfig.add_entry('MMU', 'y')
0061         expected_kconfig.add_entry('TEST', 'y')
0062         expected_kconfig.add_entry('EXAMPLE_TEST', 'y')
0063         expected_kconfig.add_entry('MK8', 'n')
0064 
0065         self.assertEqual(kconfig, expected_kconfig)
0066 
0067     def test_write_to_file(self):
0068         kconfig_path = os.path.join(test_tmpdir, '.config')
0069 
0070         expected_kconfig = kunit_config.Kconfig()
0071         expected_kconfig.add_entry('UML', 'y')
0072         expected_kconfig.add_entry('MMU', 'y')
0073         expected_kconfig.add_entry('TEST', 'y')
0074         expected_kconfig.add_entry('EXAMPLE_TEST', 'y')
0075         expected_kconfig.add_entry('MK8', 'n')
0076 
0077         expected_kconfig.write_to_file(kconfig_path)
0078 
0079         actual_kconfig = kunit_config.parse_file(kconfig_path)
0080         self.assertEqual(actual_kconfig, expected_kconfig)
0081 
0082 class KUnitParserTest(unittest.TestCase):
0083 
0084     def assertContains(self, needle: str, haystack: kunit_parser.LineStream):
0085         # Clone the iterator so we can print the contents on failure.
0086         copy, backup = itertools.tee(haystack)
0087         for line in copy:
0088             if needle in line:
0089                 return
0090         raise AssertionError(f'"{needle}" not found in {list(backup)}!')
0091 
0092     def test_output_isolated_correctly(self):
0093         log_path = test_data_path('test_output_isolated_correctly.log')
0094         with open(log_path) as file:
0095             result = kunit_parser.extract_tap_lines(file.readlines())
0096         self.assertContains('TAP version 14', result)
0097         self.assertContains('# Subtest: example', result)
0098         self.assertContains('1..2', result)
0099         self.assertContains('ok 1 - example_simple_test', result)
0100         self.assertContains('ok 2 - example_mock_test', result)
0101         self.assertContains('ok 1 - example', result)
0102 
0103     def test_output_with_prefix_isolated_correctly(self):
0104         log_path = test_data_path('test_pound_sign.log')
0105         with open(log_path) as file:
0106             result = kunit_parser.extract_tap_lines(file.readlines())
0107         self.assertContains('TAP version 14', result)
0108         self.assertContains('# Subtest: kunit-resource-test', result)
0109         self.assertContains('1..5', result)
0110         self.assertContains('ok 1 - kunit_resource_test_init_resources', result)
0111         self.assertContains('ok 2 - kunit_resource_test_alloc_resource', result)
0112         self.assertContains('ok 3 - kunit_resource_test_destroy_resource', result)
0113         self.assertContains('foo bar    #', result)
0114         self.assertContains('ok 4 - kunit_resource_test_cleanup_resources', result)
0115         self.assertContains('ok 5 - kunit_resource_test_proper_free_ordering', result)
0116         self.assertContains('ok 1 - kunit-resource-test', result)
0117         self.assertContains('foo bar    # non-kunit output', result)
0118         self.assertContains('# Subtest: kunit-try-catch-test', result)
0119         self.assertContains('1..2', result)
0120         self.assertContains('ok 1 - kunit_test_try_catch_successful_try_no_catch',
0121                     result)
0122         self.assertContains('ok 2 - kunit_test_try_catch_unsuccessful_try_does_catch',
0123                     result)
0124         self.assertContains('ok 2 - kunit-try-catch-test', result)
0125         self.assertContains('# Subtest: string-stream-test', result)
0126         self.assertContains('1..3', result)
0127         self.assertContains('ok 1 - string_stream_test_empty_on_creation', result)
0128         self.assertContains('ok 2 - string_stream_test_not_empty_after_add', result)
0129         self.assertContains('ok 3 - string_stream_test_get_string', result)
0130         self.assertContains('ok 3 - string-stream-test', result)
0131 
0132     def test_parse_successful_test_log(self):
0133         all_passed_log = test_data_path('test_is_test_passed-all_passed.log')
0134         with open(all_passed_log) as file:
0135             result = kunit_parser.parse_run_tests(file.readlines())
0136         self.assertEqual(
0137             kunit_parser.TestStatus.SUCCESS,
0138             result.status)
0139 
0140     def test_parse_successful_nested_tests_log(self):
0141         all_passed_log = test_data_path('test_is_test_passed-all_passed_nested.log')
0142         with open(all_passed_log) as file:
0143             result = kunit_parser.parse_run_tests(file.readlines())
0144         self.assertEqual(
0145             kunit_parser.TestStatus.SUCCESS,
0146             result.status)
0147 
0148     def test_kselftest_nested(self):
0149         kselftest_log = test_data_path('test_is_test_passed-kselftest.log')
0150         with open(kselftest_log) as file:
0151             result = kunit_parser.parse_run_tests(file.readlines())
0152             self.assertEqual(
0153                 kunit_parser.TestStatus.SUCCESS,
0154                 result.status)
0155 
0156     def test_parse_failed_test_log(self):
0157         failed_log = test_data_path('test_is_test_passed-failure.log')
0158         with open(failed_log) as file:
0159             result = kunit_parser.parse_run_tests(file.readlines())
0160         self.assertEqual(
0161             kunit_parser.TestStatus.FAILURE,
0162             result.status)
0163 
0164     def test_no_header(self):
0165         empty_log = test_data_path('test_is_test_passed-no_tests_run_no_header.log')
0166         with open(empty_log) as file:
0167             result = kunit_parser.parse_run_tests(
0168                 kunit_parser.extract_tap_lines(file.readlines()))
0169         self.assertEqual(0, len(result.subtests))
0170         self.assertEqual(
0171             kunit_parser.TestStatus.FAILURE_TO_PARSE_TESTS,
0172             result.status)
0173 
0174     def test_missing_test_plan(self):
0175         missing_plan_log = test_data_path('test_is_test_passed-'
0176             'missing_plan.log')
0177         with open(missing_plan_log) as file:
0178             result = kunit_parser.parse_run_tests(
0179                 kunit_parser.extract_tap_lines(
0180                 file.readlines()))
0181         # A missing test plan is not an error.
0182         self.assertEqual(0, result.counts.errors)
0183         # All tests should be accounted for.
0184         self.assertEqual(10, result.counts.total())
0185         self.assertEqual(
0186             kunit_parser.TestStatus.SUCCESS,
0187             result.status)
0188 
0189     def test_no_tests(self):
0190         header_log = test_data_path('test_is_test_passed-no_tests_run_with_header.log')
0191         with open(header_log) as file:
0192             result = kunit_parser.parse_run_tests(
0193                 kunit_parser.extract_tap_lines(file.readlines()))
0194         self.assertEqual(0, len(result.subtests))
0195         self.assertEqual(
0196             kunit_parser.TestStatus.NO_TESTS,
0197             result.status)
0198 
0199     def test_no_tests_no_plan(self):
0200         no_plan_log = test_data_path('test_is_test_passed-no_tests_no_plan.log')
0201         with open(no_plan_log) as file:
0202             result = kunit_parser.parse_run_tests(
0203                 kunit_parser.extract_tap_lines(file.readlines()))
0204         self.assertEqual(0, len(result.subtests[0].subtests[0].subtests))
0205         self.assertEqual(
0206             kunit_parser.TestStatus.NO_TESTS,
0207             result.subtests[0].subtests[0].status)
0208         self.assertEqual(1, result.counts.errors)
0209 
0210 
0211     def test_no_kunit_output(self):
0212         crash_log = test_data_path('test_insufficient_memory.log')
0213         print_mock = mock.patch('kunit_printer.Printer.print').start()
0214         with open(crash_log) as file:
0215             result = kunit_parser.parse_run_tests(
0216                 kunit_parser.extract_tap_lines(file.readlines()))
0217         print_mock.assert_any_call(StrContains('could not find any KTAP output!'))
0218         print_mock.stop()
0219         self.assertEqual(0, len(result.subtests))
0220 
0221     def test_skipped_test(self):
0222         skipped_log = test_data_path('test_skip_tests.log')
0223         with open(skipped_log) as file:
0224             result = kunit_parser.parse_run_tests(file.readlines())
0225 
0226         # A skipped test does not fail the whole suite.
0227         self.assertEqual(
0228             kunit_parser.TestStatus.SUCCESS,
0229             result.status)
0230 
0231     def test_skipped_all_tests(self):
0232         skipped_log = test_data_path('test_skip_all_tests.log')
0233         with open(skipped_log) as file:
0234             result = kunit_parser.parse_run_tests(file.readlines())
0235 
0236         self.assertEqual(
0237             kunit_parser.TestStatus.SKIPPED,
0238             result.status)
0239 
0240     def test_ignores_hyphen(self):
0241         hyphen_log = test_data_path('test_strip_hyphen.log')
0242         with open(hyphen_log) as file:
0243             result = kunit_parser.parse_run_tests(file.readlines())
0244 
0245         # A skipped test does not fail the whole suite.
0246         self.assertEqual(
0247             kunit_parser.TestStatus.SUCCESS,
0248             result.status)
0249         self.assertEqual(
0250             "sysctl_test",
0251             result.subtests[0].name)
0252         self.assertEqual(
0253             "example",
0254             result.subtests[1].name)
0255         file.close()
0256 
0257 
0258     def test_ignores_prefix_printk_time(self):
0259         prefix_log = test_data_path('test_config_printk_time.log')
0260         with open(prefix_log) as file:
0261             result = kunit_parser.parse_run_tests(file.readlines())
0262             self.assertEqual(
0263                 kunit_parser.TestStatus.SUCCESS,
0264                 result.status)
0265             self.assertEqual('kunit-resource-test', result.subtests[0].name)
0266 
0267     def test_ignores_multiple_prefixes(self):
0268         prefix_log = test_data_path('test_multiple_prefixes.log')
0269         with open(prefix_log) as file:
0270             result = kunit_parser.parse_run_tests(file.readlines())
0271             self.assertEqual(
0272                 kunit_parser.TestStatus.SUCCESS,
0273                 result.status)
0274             self.assertEqual('kunit-resource-test', result.subtests[0].name)
0275 
0276     def test_prefix_mixed_kernel_output(self):
0277         mixed_prefix_log = test_data_path('test_interrupted_tap_output.log')
0278         with open(mixed_prefix_log) as file:
0279             result = kunit_parser.parse_run_tests(file.readlines())
0280             self.assertEqual(
0281                 kunit_parser.TestStatus.SUCCESS,
0282                 result.status)
0283             self.assertEqual('kunit-resource-test', result.subtests[0].name)
0284 
0285     def test_prefix_poundsign(self):
0286         pound_log = test_data_path('test_pound_sign.log')
0287         with open(pound_log) as file:
0288             result = kunit_parser.parse_run_tests(file.readlines())
0289             self.assertEqual(
0290                 kunit_parser.TestStatus.SUCCESS,
0291                 result.status)
0292             self.assertEqual('kunit-resource-test', result.subtests[0].name)
0293 
0294     def test_kernel_panic_end(self):
0295         panic_log = test_data_path('test_kernel_panic_interrupt.log')
0296         with open(panic_log) as file:
0297             result = kunit_parser.parse_run_tests(file.readlines())
0298             self.assertEqual(
0299                 kunit_parser.TestStatus.TEST_CRASHED,
0300                 result.status)
0301             self.assertEqual('kunit-resource-test', result.subtests[0].name)
0302 
0303     def test_pound_no_prefix(self):
0304         pound_log = test_data_path('test_pound_no_prefix.log')
0305         with open(pound_log) as file:
0306             result = kunit_parser.parse_run_tests(file.readlines())
0307             self.assertEqual(
0308                 kunit_parser.TestStatus.SUCCESS,
0309                 result.status)
0310             self.assertEqual('kunit-resource-test', result.subtests[0].name)
0311 
0312 def line_stream_from_strs(strs: Iterable[str]) -> kunit_parser.LineStream:
0313     return kunit_parser.LineStream(enumerate(strs, start=1))
0314 
0315 class LineStreamTest(unittest.TestCase):
0316 
0317     def test_basic(self):
0318         stream = line_stream_from_strs(['hello', 'world'])
0319 
0320         self.assertTrue(stream, msg='Should be more input')
0321         self.assertEqual(stream.line_number(), 1)
0322         self.assertEqual(stream.peek(), 'hello')
0323         self.assertEqual(stream.pop(), 'hello')
0324 
0325         self.assertTrue(stream, msg='Should be more input')
0326         self.assertEqual(stream.line_number(), 2)
0327         self.assertEqual(stream.peek(), 'world')
0328         self.assertEqual(stream.pop(), 'world')
0329 
0330         self.assertFalse(stream, msg='Should be no more input')
0331         with self.assertRaisesRegex(ValueError, 'LineStream: going past EOF'):
0332             stream.pop()
0333 
0334     def test_is_lazy(self):
0335         called_times = 0
0336         def generator():
0337             nonlocal called_times
0338             for _ in range(1,5):
0339                 called_times += 1
0340                 yield called_times, str(called_times)
0341 
0342         stream = kunit_parser.LineStream(generator())
0343         self.assertEqual(called_times, 0)
0344 
0345         self.assertEqual(stream.pop(), '1')
0346         self.assertEqual(called_times, 1)
0347 
0348         self.assertEqual(stream.pop(), '2')
0349         self.assertEqual(called_times, 2)
0350 
0351 class LinuxSourceTreeTest(unittest.TestCase):
0352 
0353     def setUp(self):
0354         mock.patch.object(signal, 'signal').start()
0355         self.addCleanup(mock.patch.stopall)
0356 
0357     def test_invalid_kunitconfig(self):
0358         with self.assertRaisesRegex(kunit_kernel.ConfigError, 'nonexistent.* does not exist'):
0359             kunit_kernel.LinuxSourceTree('', kunitconfig_paths=['/nonexistent_file'])
0360 
0361     def test_valid_kunitconfig(self):
0362         with tempfile.NamedTemporaryFile('wt') as kunitconfig:
0363             kunit_kernel.LinuxSourceTree('', kunitconfig_paths=[kunitconfig.name])
0364 
0365     def test_dir_kunitconfig(self):
0366         with tempfile.TemporaryDirectory('') as dir:
0367             with open(os.path.join(dir, '.kunitconfig'), 'w'):
0368                 pass
0369             kunit_kernel.LinuxSourceTree('', kunitconfig_paths=[dir])
0370 
0371     def test_multiple_kunitconfig(self):
0372         want_kconfig = kunit_config.Kconfig()
0373         want_kconfig.add_entry('KUNIT', 'y')
0374         want_kconfig.add_entry('KUNIT_TEST', 'm')
0375 
0376         with tempfile.TemporaryDirectory('') as dir:
0377             other = os.path.join(dir, 'otherkunitconfig')
0378             with open(os.path.join(dir, '.kunitconfig'), 'w') as f:
0379                 f.write('CONFIG_KUNIT=y')
0380             with open(other, 'w') as f:
0381                 f.write('CONFIG_KUNIT_TEST=m')
0382                 pass
0383 
0384             tree = kunit_kernel.LinuxSourceTree('', kunitconfig_paths=[dir, other])
0385             self.assertTrue(want_kconfig.is_subset_of(tree._kconfig), msg=tree._kconfig)
0386 
0387 
0388     def test_multiple_kunitconfig_invalid(self):
0389         with tempfile.TemporaryDirectory('') as dir:
0390             other = os.path.join(dir, 'otherkunitconfig')
0391             with open(os.path.join(dir, '.kunitconfig'), 'w') as f:
0392                 f.write('CONFIG_KUNIT=y')
0393             with open(other, 'w') as f:
0394                 f.write('CONFIG_KUNIT=m')
0395 
0396             with self.assertRaisesRegex(kunit_kernel.ConfigError, '(?s)Multiple values.*CONFIG_KUNIT'):
0397                 kunit_kernel.LinuxSourceTree('', kunitconfig_paths=[dir, other])
0398 
0399 
0400     def test_kconfig_add(self):
0401         want_kconfig = kunit_config.Kconfig()
0402         want_kconfig.add_entry('NOT_REAL', 'y')
0403 
0404         tree = kunit_kernel.LinuxSourceTree('', kconfig_add=['CONFIG_NOT_REAL=y'])
0405         self.assertTrue(want_kconfig.is_subset_of(tree._kconfig), msg=tree._kconfig)
0406 
0407     def test_invalid_arch(self):
0408         with self.assertRaisesRegex(kunit_kernel.ConfigError, 'not a valid arch, options are.*x86_64'):
0409             kunit_kernel.LinuxSourceTree('', arch='invalid')
0410 
0411     def test_run_kernel_hits_exception(self):
0412         def fake_start(unused_args, unused_build_dir):
0413             return subprocess.Popen(['echo "hi\nbye"'], shell=True, text=True, stdout=subprocess.PIPE)
0414 
0415         with tempfile.TemporaryDirectory('') as build_dir:
0416             tree = kunit_kernel.LinuxSourceTree(build_dir)
0417             mock.patch.object(tree._ops, 'start', side_effect=fake_start).start()
0418 
0419             with self.assertRaises(ValueError):
0420                 for line in tree.run_kernel(build_dir=build_dir):
0421                     self.assertEqual(line, 'hi\n')
0422                     raise ValueError('uh oh, did not read all output')
0423 
0424             with open(kunit_kernel.get_outfile_path(build_dir), 'rt') as outfile:
0425                 self.assertEqual(outfile.read(), 'hi\nbye\n', msg='Missing some output')
0426 
0427     def test_build_reconfig_no_config(self):
0428         with tempfile.TemporaryDirectory('') as build_dir:
0429             with open(kunit_kernel.get_kunitconfig_path(build_dir), 'w') as f:
0430                 f.write('CONFIG_KUNIT=y')
0431 
0432             tree = kunit_kernel.LinuxSourceTree(build_dir)
0433             # Stub out the source tree operations, so we don't have
0434             # the defaults for any given architecture get in the
0435             # way.
0436             tree._ops = kunit_kernel.LinuxSourceTreeOperations('none', None)
0437             mock_build_config = mock.patch.object(tree, 'build_config').start()
0438 
0439             # Should generate the .config
0440             self.assertTrue(tree.build_reconfig(build_dir, make_options=[]))
0441             mock_build_config.assert_called_once_with(build_dir, [])
0442 
0443     def test_build_reconfig_existing_config(self):
0444         with tempfile.TemporaryDirectory('') as build_dir:
0445             # Existing .config is a superset, should not touch it
0446             with open(kunit_kernel.get_kunitconfig_path(build_dir), 'w') as f:
0447                 f.write('CONFIG_KUNIT=y')
0448             with open(kunit_kernel.get_old_kunitconfig_path(build_dir), 'w') as f:
0449                 f.write('CONFIG_KUNIT=y')
0450             with open(kunit_kernel.get_kconfig_path(build_dir), 'w') as f:
0451                 f.write('CONFIG_KUNIT=y\nCONFIG_KUNIT_TEST=y')
0452 
0453             tree = kunit_kernel.LinuxSourceTree(build_dir)
0454             # Stub out the source tree operations, so we don't have
0455             # the defaults for any given architecture get in the
0456             # way.
0457             tree._ops = kunit_kernel.LinuxSourceTreeOperations('none', None)
0458             mock_build_config = mock.patch.object(tree, 'build_config').start()
0459 
0460             self.assertTrue(tree.build_reconfig(build_dir, make_options=[]))
0461             self.assertEqual(mock_build_config.call_count, 0)
0462 
0463     def test_build_reconfig_remove_option(self):
0464         with tempfile.TemporaryDirectory('') as build_dir:
0465             # We removed CONFIG_KUNIT_TEST=y from our .kunitconfig...
0466             with open(kunit_kernel.get_kunitconfig_path(build_dir), 'w') as f:
0467                 f.write('CONFIG_KUNIT=y')
0468             with open(kunit_kernel.get_old_kunitconfig_path(build_dir), 'w') as f:
0469                 f.write('CONFIG_KUNIT=y\nCONFIG_KUNIT_TEST=y')
0470             with open(kunit_kernel.get_kconfig_path(build_dir), 'w') as f:
0471                 f.write('CONFIG_KUNIT=y\nCONFIG_KUNIT_TEST=y')
0472 
0473             tree = kunit_kernel.LinuxSourceTree(build_dir)
0474             # Stub out the source tree operations, so we don't have
0475             # the defaults for any given architecture get in the
0476             # way.
0477             tree._ops = kunit_kernel.LinuxSourceTreeOperations('none', None)
0478             mock_build_config = mock.patch.object(tree, 'build_config').start()
0479 
0480             # ... so we should trigger a call to build_config()
0481             self.assertTrue(tree.build_reconfig(build_dir, make_options=[]))
0482             mock_build_config.assert_called_once_with(build_dir, [])
0483 
0484     # TODO: add more test cases.
0485 
0486 
0487 class KUnitJsonTest(unittest.TestCase):
0488 
0489     def _json_for(self, log_file):
0490         with open(test_data_path(log_file)) as file:
0491             test_result = kunit_parser.parse_run_tests(file)
0492             json_obj = kunit_json.get_json_result(
0493                 test=test_result,
0494                 metadata=kunit_json.Metadata())
0495         return json.loads(json_obj)
0496 
0497     def test_failed_test_json(self):
0498         result = self._json_for('test_is_test_passed-failure.log')
0499         self.assertEqual(
0500             {'name': 'example_simple_test', 'status': 'FAIL'},
0501             result["sub_groups"][1]["test_cases"][0])
0502 
0503     def test_crashed_test_json(self):
0504         result = self._json_for('test_kernel_panic_interrupt.log')
0505         self.assertEqual(
0506             {'name': '', 'status': 'ERROR'},
0507             result["sub_groups"][2]["test_cases"][1])
0508 
0509     def test_skipped_test_json(self):
0510         result = self._json_for('test_skip_tests.log')
0511         self.assertEqual(
0512             {'name': 'example_skip_test', 'status': 'SKIP'},
0513             result["sub_groups"][1]["test_cases"][1])
0514 
0515     def test_no_tests_json(self):
0516         result = self._json_for('test_is_test_passed-no_tests_run_with_header.log')
0517         self.assertEqual(0, len(result['sub_groups']))
0518 
0519     def test_nested_json(self):
0520         result = self._json_for('test_is_test_passed-all_passed_nested.log')
0521         self.assertEqual(
0522             {'name': 'example_simple_test', 'status': 'PASS'},
0523             result["sub_groups"][0]["sub_groups"][0]["test_cases"][0])
0524 
0525 class StrContains(str):
0526     def __eq__(self, other):
0527         return self in other
0528 
0529 class KUnitMainTest(unittest.TestCase):
0530     def setUp(self):
0531         path = test_data_path('test_is_test_passed-all_passed.log')
0532         with open(path) as file:
0533             all_passed_log = file.readlines()
0534 
0535         self.print_mock = mock.patch('kunit_printer.Printer.print').start()
0536         self.addCleanup(mock.patch.stopall)
0537 
0538         self.mock_linux_init = mock.patch.object(kunit_kernel, 'LinuxSourceTree').start()
0539         self.linux_source_mock = self.mock_linux_init.return_value
0540         self.linux_source_mock.build_reconfig.return_value = True
0541         self.linux_source_mock.build_kernel.return_value = True
0542         self.linux_source_mock.run_kernel.return_value = all_passed_log
0543 
0544     def test_config_passes_args_pass(self):
0545         kunit.main(['config', '--build_dir=.kunit'])
0546         self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1)
0547         self.assertEqual(self.linux_source_mock.run_kernel.call_count, 0)
0548 
0549     def test_build_passes_args_pass(self):
0550         kunit.main(['build'])
0551         self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1)
0552         self.linux_source_mock.build_kernel.assert_called_once_with(False, kunit.get_default_jobs(), '.kunit', None)
0553         self.assertEqual(self.linux_source_mock.run_kernel.call_count, 0)
0554 
0555     def test_exec_passes_args_pass(self):
0556         kunit.main(['exec'])
0557         self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 0)
0558         self.assertEqual(self.linux_source_mock.run_kernel.call_count, 1)
0559         self.linux_source_mock.run_kernel.assert_called_once_with(
0560             args=None, build_dir='.kunit', filter_glob='', timeout=300)
0561         self.print_mock.assert_any_call(StrContains('Testing complete.'))
0562 
0563     def test_run_passes_args_pass(self):
0564         kunit.main(['run'])
0565         self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1)
0566         self.assertEqual(self.linux_source_mock.run_kernel.call_count, 1)
0567         self.linux_source_mock.run_kernel.assert_called_once_with(
0568             args=None, build_dir='.kunit', filter_glob='', timeout=300)
0569         self.print_mock.assert_any_call(StrContains('Testing complete.'))
0570 
0571     def test_exec_passes_args_fail(self):
0572         self.linux_source_mock.run_kernel = mock.Mock(return_value=[])
0573         with self.assertRaises(SystemExit) as e:
0574             kunit.main(['exec'])
0575         self.assertEqual(e.exception.code, 1)
0576 
0577     def test_run_passes_args_fail(self):
0578         self.linux_source_mock.run_kernel = mock.Mock(return_value=[])
0579         with self.assertRaises(SystemExit) as e:
0580             kunit.main(['run'])
0581         self.assertEqual(e.exception.code, 1)
0582         self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1)
0583         self.assertEqual(self.linux_source_mock.run_kernel.call_count, 1)
0584         self.print_mock.assert_any_call(StrContains('could not find any KTAP output!'))
0585 
0586     def test_exec_no_tests(self):
0587         self.linux_source_mock.run_kernel = mock.Mock(return_value=['TAP version 14', '1..0'])
0588         with self.assertRaises(SystemExit) as e:
0589             kunit.main(['run'])
0590         self.assertEqual(e.exception.code, 1)
0591         self.linux_source_mock.run_kernel.assert_called_once_with(
0592             args=None, build_dir='.kunit', filter_glob='', timeout=300)
0593         self.print_mock.assert_any_call(StrContains(' 0 tests run!'))
0594 
0595     def test_exec_raw_output(self):
0596         self.linux_source_mock.run_kernel = mock.Mock(return_value=[])
0597         kunit.main(['exec', '--raw_output'])
0598         self.assertEqual(self.linux_source_mock.run_kernel.call_count, 1)
0599         for call in self.print_mock.call_args_list:
0600             self.assertNotEqual(call, mock.call(StrContains('Testing complete.')))
0601             self.assertNotEqual(call, mock.call(StrContains(' 0 tests run!')))
0602 
0603     def test_run_raw_output(self):
0604         self.linux_source_mock.run_kernel = mock.Mock(return_value=[])
0605         kunit.main(['run', '--raw_output'])
0606         self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1)
0607         self.assertEqual(self.linux_source_mock.run_kernel.call_count, 1)
0608         for call in self.print_mock.call_args_list:
0609             self.assertNotEqual(call, mock.call(StrContains('Testing complete.')))
0610             self.assertNotEqual(call, mock.call(StrContains(' 0 tests run!')))
0611 
0612     def test_run_raw_output_kunit(self):
0613         self.linux_source_mock.run_kernel = mock.Mock(return_value=[])
0614         kunit.main(['run', '--raw_output=kunit'])
0615         self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1)
0616         self.assertEqual(self.linux_source_mock.run_kernel.call_count, 1)
0617         for call in self.print_mock.call_args_list:
0618             self.assertNotEqual(call, mock.call(StrContains('Testing complete.')))
0619             self.assertNotEqual(call, mock.call(StrContains(' 0 tests run')))
0620 
0621     def test_run_raw_output_invalid(self):
0622         self.linux_source_mock.run_kernel = mock.Mock(return_value=[])
0623         with self.assertRaises(SystemExit) as e:
0624             kunit.main(['run', '--raw_output=invalid'])
0625         self.assertNotEqual(e.exception.code, 0)
0626 
0627     def test_run_raw_output_does_not_take_positional_args(self):
0628         # --raw_output is a string flag, but we don't want it to consume
0629         # any positional arguments, only ones after an '='
0630         self.linux_source_mock.run_kernel = mock.Mock(return_value=[])
0631         kunit.main(['run', '--raw_output', 'filter_glob'])
0632         self.linux_source_mock.run_kernel.assert_called_once_with(
0633             args=None, build_dir='.kunit', filter_glob='filter_glob', timeout=300)
0634 
0635     def test_exec_timeout(self):
0636         timeout = 3453
0637         kunit.main(['exec', '--timeout', str(timeout)])
0638         self.linux_source_mock.run_kernel.assert_called_once_with(
0639             args=None, build_dir='.kunit', filter_glob='', timeout=timeout)
0640         self.print_mock.assert_any_call(StrContains('Testing complete.'))
0641 
0642     def test_run_timeout(self):
0643         timeout = 3453
0644         kunit.main(['run', '--timeout', str(timeout)])
0645         self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1)
0646         self.linux_source_mock.run_kernel.assert_called_once_with(
0647             args=None, build_dir='.kunit', filter_glob='', timeout=timeout)
0648         self.print_mock.assert_any_call(StrContains('Testing complete.'))
0649 
0650     def test_run_builddir(self):
0651         build_dir = '.kunit'
0652         kunit.main(['run', '--build_dir=.kunit'])
0653         self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1)
0654         self.linux_source_mock.run_kernel.assert_called_once_with(
0655             args=None, build_dir=build_dir, filter_glob='', timeout=300)
0656         self.print_mock.assert_any_call(StrContains('Testing complete.'))
0657 
0658     def test_config_builddir(self):
0659         build_dir = '.kunit'
0660         kunit.main(['config', '--build_dir', build_dir])
0661         self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1)
0662 
0663     def test_build_builddir(self):
0664         build_dir = '.kunit'
0665         jobs = kunit.get_default_jobs()
0666         kunit.main(['build', '--build_dir', build_dir])
0667         self.linux_source_mock.build_kernel.assert_called_once_with(False, jobs, build_dir, None)
0668 
0669     def test_exec_builddir(self):
0670         build_dir = '.kunit'
0671         kunit.main(['exec', '--build_dir', build_dir])
0672         self.linux_source_mock.run_kernel.assert_called_once_with(
0673             args=None, build_dir=build_dir, filter_glob='', timeout=300)
0674         self.print_mock.assert_any_call(StrContains('Testing complete.'))
0675 
0676     def test_run_kunitconfig(self):
0677         kunit.main(['run', '--kunitconfig=mykunitconfig'])
0678         # Just verify that we parsed and initialized it correctly here.
0679         self.mock_linux_init.assert_called_once_with('.kunit',
0680                         kunitconfig_paths=['mykunitconfig'],
0681                         kconfig_add=None,
0682                         arch='um',
0683                         cross_compile=None,
0684                         qemu_config_path=None,
0685                         extra_qemu_args=[])
0686 
0687     def test_config_kunitconfig(self):
0688         kunit.main(['config', '--kunitconfig=mykunitconfig'])
0689         # Just verify that we parsed and initialized it correctly here.
0690         self.mock_linux_init.assert_called_once_with('.kunit',
0691                         kunitconfig_paths=['mykunitconfig'],
0692                         kconfig_add=None,
0693                         arch='um',
0694                         cross_compile=None,
0695                         qemu_config_path=None,
0696                         extra_qemu_args=[])
0697 
0698     @mock.patch.object(kunit_kernel, 'LinuxSourceTree')
0699     def test_run_multiple_kunitconfig(self, mock_linux_init):
0700         mock_linux_init.return_value = self.linux_source_mock
0701         kunit.main(['run', '--kunitconfig=mykunitconfig', '--kunitconfig=other'])
0702         # Just verify that we parsed and initialized it correctly here.
0703         mock_linux_init.assert_called_once_with('.kunit',
0704                             kunitconfig_paths=['mykunitconfig', 'other'],
0705                             kconfig_add=None,
0706                             arch='um',
0707                             cross_compile=None,
0708                             qemu_config_path=None,
0709                             extra_qemu_args=[])
0710 
0711     def test_run_kconfig_add(self):
0712         kunit.main(['run', '--kconfig_add=CONFIG_KASAN=y', '--kconfig_add=CONFIG_KCSAN=y'])
0713         # Just verify that we parsed and initialized it correctly here.
0714         self.mock_linux_init.assert_called_once_with('.kunit',
0715                         kunitconfig_paths=None,
0716                         kconfig_add=['CONFIG_KASAN=y', 'CONFIG_KCSAN=y'],
0717                         arch='um',
0718                         cross_compile=None,
0719                         qemu_config_path=None,
0720                         extra_qemu_args=[])
0721 
0722     def test_run_qemu_args(self):
0723         kunit.main(['run', '--arch=x86_64', '--qemu_args', '-m 2048'])
0724         # Just verify that we parsed and initialized it correctly here.
0725         self.mock_linux_init.assert_called_once_with('.kunit',
0726                         kunitconfig_paths=None,
0727                         kconfig_add=None,
0728                         arch='x86_64',
0729                         cross_compile=None,
0730                         qemu_config_path=None,
0731                         extra_qemu_args=['-m', '2048'])
0732 
0733     def test_run_kernel_args(self):
0734         kunit.main(['run', '--kernel_args=a=1', '--kernel_args=b=2'])
0735         self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1)
0736         self.linux_source_mock.run_kernel.assert_called_once_with(
0737               args=['a=1','b=2'], build_dir='.kunit', filter_glob='', timeout=300)
0738         self.print_mock.assert_any_call(StrContains('Testing complete.'))
0739 
0740     def test_list_tests(self):
0741         want = ['suite.test1', 'suite.test2', 'suite2.test1']
0742         self.linux_source_mock.run_kernel.return_value = ['TAP version 14', 'init: random output'] + want
0743 
0744         got = kunit._list_tests(self.linux_source_mock,
0745                      kunit.KunitExecRequest(None, None, '.kunit', 300, False, 'suite*', None, 'suite'))
0746 
0747         self.assertEqual(got, want)
0748         # Should respect the user's filter glob when listing tests.
0749         self.linux_source_mock.run_kernel.assert_called_once_with(
0750             args=['kunit.action=list'], build_dir='.kunit', filter_glob='suite*', timeout=300)
0751 
0752 
0753     @mock.patch.object(kunit, '_list_tests')
0754     def test_run_isolated_by_suite(self, mock_tests):
0755         mock_tests.return_value = ['suite.test1', 'suite.test2', 'suite2.test1']
0756         kunit.main(['exec', '--run_isolated=suite', 'suite*.test*'])
0757 
0758         # Should respect the user's filter glob when listing tests.
0759         mock_tests.assert_called_once_with(mock.ANY,
0760                      kunit.KunitExecRequest(None, None, '.kunit', 300, False, 'suite*.test*', None, 'suite'))
0761         self.linux_source_mock.run_kernel.assert_has_calls([
0762             mock.call(args=None, build_dir='.kunit', filter_glob='suite.test*', timeout=300),
0763             mock.call(args=None, build_dir='.kunit', filter_glob='suite2.test*', timeout=300),
0764         ])
0765 
0766     @mock.patch.object(kunit, '_list_tests')
0767     def test_run_isolated_by_test(self, mock_tests):
0768         mock_tests.return_value = ['suite.test1', 'suite.test2', 'suite2.test1']
0769         kunit.main(['exec', '--run_isolated=test', 'suite*'])
0770 
0771         # Should respect the user's filter glob when listing tests.
0772         mock_tests.assert_called_once_with(mock.ANY,
0773                      kunit.KunitExecRequest(None, None, '.kunit', 300, False, 'suite*', None, 'test'))
0774         self.linux_source_mock.run_kernel.assert_has_calls([
0775             mock.call(args=None, build_dir='.kunit', filter_glob='suite.test1', timeout=300),
0776             mock.call(args=None, build_dir='.kunit', filter_glob='suite.test2', timeout=300),
0777             mock.call(args=None, build_dir='.kunit', filter_glob='suite2.test1', timeout=300),
0778         ])
0779 
0780 
0781 if __name__ == '__main__':
0782     unittest.main()