1#!/usr/bin/python3 2# SPDX-License-Identifier: GPL-2.0 3# 4# A collection of tests for tools/testing/kunit/kunit.py 5# 6# Copyright (C) 2019, Google LLC. 7# Author: Brendan Higgins <brendanhiggins@google.com> 8 9import unittest 10from unittest import mock 11 12import tempfile, shutil # Handling test_tmpdir 13 14import os 15 16import kunit_config 17import kunit_parser 18import kunit_kernel 19import kunit 20 21test_tmpdir = '' 22 23def setUpModule(): 24 global test_tmpdir 25 test_tmpdir = tempfile.mkdtemp() 26 27def tearDownModule(): 28 shutil.rmtree(test_tmpdir) 29 30def get_absolute_path(path): 31 return os.path.join(os.path.dirname(__file__), path) 32 33class KconfigTest(unittest.TestCase): 34 35 def test_is_subset_of(self): 36 kconfig0 = kunit_config.Kconfig() 37 self.assertTrue(kconfig0.is_subset_of(kconfig0)) 38 39 kconfig1 = kunit_config.Kconfig() 40 kconfig1.add_entry(kunit_config.KconfigEntry('TEST', 'y')) 41 self.assertTrue(kconfig1.is_subset_of(kconfig1)) 42 self.assertTrue(kconfig0.is_subset_of(kconfig1)) 43 self.assertFalse(kconfig1.is_subset_of(kconfig0)) 44 45 def test_read_from_file(self): 46 kconfig = kunit_config.Kconfig() 47 kconfig_path = get_absolute_path( 48 'test_data/test_read_from_file.kconfig') 49 50 kconfig.read_from_file(kconfig_path) 51 52 expected_kconfig = kunit_config.Kconfig() 53 expected_kconfig.add_entry( 54 kunit_config.KconfigEntry('UML', 'y')) 55 expected_kconfig.add_entry( 56 kunit_config.KconfigEntry('MMU', 'y')) 57 expected_kconfig.add_entry( 58 kunit_config.KconfigEntry('TEST', 'y')) 59 expected_kconfig.add_entry( 60 kunit_config.KconfigEntry('EXAMPLE_TEST', 'y')) 61 expected_kconfig.add_entry( 62 kunit_config.KconfigEntry('MK8', 'n')) 63 64 self.assertEqual(kconfig.entries(), expected_kconfig.entries()) 65 66 def test_write_to_file(self): 67 kconfig_path = os.path.join(test_tmpdir, '.config') 68 69 expected_kconfig = kunit_config.Kconfig() 70 expected_kconfig.add_entry( 71 kunit_config.KconfigEntry('UML', 'y')) 72 expected_kconfig.add_entry( 73 kunit_config.KconfigEntry('MMU', 'y')) 74 expected_kconfig.add_entry( 75 kunit_config.KconfigEntry('TEST', 'y')) 76 expected_kconfig.add_entry( 77 kunit_config.KconfigEntry('EXAMPLE_TEST', 'y')) 78 expected_kconfig.add_entry( 79 kunit_config.KconfigEntry('MK8', 'n')) 80 81 expected_kconfig.write_to_file(kconfig_path) 82 83 actual_kconfig = kunit_config.Kconfig() 84 actual_kconfig.read_from_file(kconfig_path) 85 86 self.assertEqual(actual_kconfig.entries(), 87 expected_kconfig.entries()) 88 89class KUnitParserTest(unittest.TestCase): 90 91 def assertContains(self, needle, haystack): 92 for line in haystack: 93 if needle in line: 94 return 95 raise AssertionError('"' + 96 str(needle) + '" not found in "' + str(haystack) + '"!') 97 98 def test_output_isolated_correctly(self): 99 log_path = get_absolute_path( 100 'test_data/test_output_isolated_correctly.log') 101 file = open(log_path) 102 result = kunit_parser.isolate_kunit_output(file.readlines()) 103 self.assertContains('TAP version 14\n', result) 104 self.assertContains(' # Subtest: example', result) 105 self.assertContains(' 1..2', result) 106 self.assertContains(' ok 1 - example_simple_test', result) 107 self.assertContains(' ok 2 - example_mock_test', result) 108 self.assertContains('ok 1 - example', result) 109 file.close() 110 111 def test_output_with_prefix_isolated_correctly(self): 112 log_path = get_absolute_path( 113 'test_data/test_pound_sign.log') 114 with open(log_path) as file: 115 result = kunit_parser.isolate_kunit_output(file.readlines()) 116 self.assertContains('TAP version 14\n', result) 117 self.assertContains(' # Subtest: kunit-resource-test', result) 118 self.assertContains(' 1..5', result) 119 self.assertContains(' ok 1 - kunit_resource_test_init_resources', result) 120 self.assertContains(' ok 2 - kunit_resource_test_alloc_resource', result) 121 self.assertContains(' ok 3 - kunit_resource_test_destroy_resource', result) 122 self.assertContains(' foo bar #', result) 123 self.assertContains(' ok 4 - kunit_resource_test_cleanup_resources', result) 124 self.assertContains(' ok 5 - kunit_resource_test_proper_free_ordering', result) 125 self.assertContains('ok 1 - kunit-resource-test', result) 126 self.assertContains(' foo bar # non-kunit output', result) 127 self.assertContains(' # Subtest: kunit-try-catch-test', result) 128 self.assertContains(' 1..2', result) 129 self.assertContains(' ok 1 - kunit_test_try_catch_successful_try_no_catch', 130 result) 131 self.assertContains(' ok 2 - kunit_test_try_catch_unsuccessful_try_does_catch', 132 result) 133 self.assertContains('ok 2 - kunit-try-catch-test', result) 134 self.assertContains(' # Subtest: string-stream-test', result) 135 self.assertContains(' 1..3', result) 136 self.assertContains(' ok 1 - string_stream_test_empty_on_creation', result) 137 self.assertContains(' ok 2 - string_stream_test_not_empty_after_add', result) 138 self.assertContains(' ok 3 - string_stream_test_get_string', result) 139 self.assertContains('ok 3 - string-stream-test', result) 140 141 def test_parse_successful_test_log(self): 142 all_passed_log = get_absolute_path( 143 'test_data/test_is_test_passed-all_passed.log') 144 file = open(all_passed_log) 145 result = kunit_parser.parse_run_tests(file.readlines()) 146 self.assertEqual( 147 kunit_parser.TestStatus.SUCCESS, 148 result.status) 149 file.close() 150 151 def test_parse_failed_test_log(self): 152 failed_log = get_absolute_path( 153 'test_data/test_is_test_passed-failure.log') 154 file = open(failed_log) 155 result = kunit_parser.parse_run_tests(file.readlines()) 156 self.assertEqual( 157 kunit_parser.TestStatus.FAILURE, 158 result.status) 159 file.close() 160 161 def test_no_tests(self): 162 empty_log = get_absolute_path( 163 'test_data/test_is_test_passed-no_tests_run.log') 164 file = open(empty_log) 165 result = kunit_parser.parse_run_tests( 166 kunit_parser.isolate_kunit_output(file.readlines())) 167 self.assertEqual(0, len(result.suites)) 168 self.assertEqual( 169 kunit_parser.TestStatus.NO_TESTS, 170 result.status) 171 file.close() 172 173 def test_no_kunit_output(self): 174 crash_log = get_absolute_path( 175 'test_data/test_insufficient_memory.log') 176 file = open(crash_log) 177 print_mock = mock.patch('builtins.print').start() 178 result = kunit_parser.parse_run_tests( 179 kunit_parser.isolate_kunit_output(file.readlines())) 180 print_mock.assert_any_call(StrContains("no kunit output detected")) 181 print_mock.stop() 182 file.close() 183 184 def test_crashed_test(self): 185 crashed_log = get_absolute_path( 186 'test_data/test_is_test_passed-crash.log') 187 file = open(crashed_log) 188 result = kunit_parser.parse_run_tests(file.readlines()) 189 self.assertEqual( 190 kunit_parser.TestStatus.TEST_CRASHED, 191 result.status) 192 file.close() 193 194 def test_ignores_prefix_printk_time(self): 195 prefix_log = get_absolute_path( 196 'test_data/test_config_printk_time.log') 197 with open(prefix_log) as file: 198 result = kunit_parser.parse_run_tests(file.readlines()) 199 self.assertEqual('kunit-resource-test', result.suites[0].name) 200 201 def test_ignores_multiple_prefixes(self): 202 prefix_log = get_absolute_path( 203 'test_data/test_multiple_prefixes.log') 204 with open(prefix_log) as file: 205 result = kunit_parser.parse_run_tests(file.readlines()) 206 self.assertEqual('kunit-resource-test', result.suites[0].name) 207 208 def test_prefix_mixed_kernel_output(self): 209 mixed_prefix_log = get_absolute_path( 210 'test_data/test_interrupted_tap_output.log') 211 with open(mixed_prefix_log) as file: 212 result = kunit_parser.parse_run_tests(file.readlines()) 213 self.assertEqual('kunit-resource-test', result.suites[0].name) 214 215 def test_prefix_poundsign(self): 216 pound_log = get_absolute_path('test_data/test_pound_sign.log') 217 with open(pound_log) as file: 218 result = kunit_parser.parse_run_tests(file.readlines()) 219 self.assertEqual('kunit-resource-test', result.suites[0].name) 220 221 def test_kernel_panic_end(self): 222 panic_log = get_absolute_path('test_data/test_kernel_panic_interrupt.log') 223 with open(panic_log) as file: 224 result = kunit_parser.parse_run_tests(file.readlines()) 225 self.assertEqual('kunit-resource-test', result.suites[0].name) 226 227 def test_pound_no_prefix(self): 228 pound_log = get_absolute_path('test_data/test_pound_no_prefix.log') 229 with open(pound_log) as file: 230 result = kunit_parser.parse_run_tests(file.readlines()) 231 self.assertEqual('kunit-resource-test', result.suites[0].name) 232 233class StrContains(str): 234 def __eq__(self, other): 235 return self in other 236 237class KUnitMainTest(unittest.TestCase): 238 def setUp(self): 239 path = get_absolute_path('test_data/test_is_test_passed-all_passed.log') 240 file = open(path) 241 all_passed_log = file.readlines() 242 self.print_patch = mock.patch('builtins.print') 243 self.print_mock = self.print_patch.start() 244 self.linux_source_mock = mock.Mock() 245 self.linux_source_mock.build_reconfig = mock.Mock(return_value=True) 246 self.linux_source_mock.build_um_kernel = mock.Mock(return_value=True) 247 self.linux_source_mock.run_kernel = mock.Mock(return_value=all_passed_log) 248 249 def tearDown(self): 250 self.print_patch.stop() 251 pass 252 253 def test_config_passes_args_pass(self): 254 kunit.main(['config', '--build_dir=.kunit'], self.linux_source_mock) 255 assert self.linux_source_mock.build_reconfig.call_count == 1 256 assert self.linux_source_mock.run_kernel.call_count == 0 257 258 def test_build_passes_args_pass(self): 259 kunit.main(['build'], self.linux_source_mock) 260 assert self.linux_source_mock.build_reconfig.call_count == 0 261 self.linux_source_mock.build_um_kernel.assert_called_once_with(False, 8, '.kunit', None) 262 assert self.linux_source_mock.run_kernel.call_count == 0 263 264 def test_exec_passes_args_pass(self): 265 kunit.main(['exec'], self.linux_source_mock) 266 assert self.linux_source_mock.build_reconfig.call_count == 0 267 assert self.linux_source_mock.run_kernel.call_count == 1 268 self.linux_source_mock.run_kernel.assert_called_once_with(build_dir='.kunit', timeout=300) 269 self.print_mock.assert_any_call(StrContains('Testing complete.')) 270 271 def test_run_passes_args_pass(self): 272 kunit.main(['run'], self.linux_source_mock) 273 assert self.linux_source_mock.build_reconfig.call_count == 1 274 assert self.linux_source_mock.run_kernel.call_count == 1 275 self.linux_source_mock.run_kernel.assert_called_once_with( 276 build_dir='.kunit', timeout=300) 277 self.print_mock.assert_any_call(StrContains('Testing complete.')) 278 279 def test_exec_passes_args_fail(self): 280 self.linux_source_mock.run_kernel = mock.Mock(return_value=[]) 281 with self.assertRaises(SystemExit) as e: 282 kunit.main(['exec'], self.linux_source_mock) 283 assert type(e.exception) == SystemExit 284 assert e.exception.code == 1 285 286 def test_run_passes_args_fail(self): 287 self.linux_source_mock.run_kernel = mock.Mock(return_value=[]) 288 with self.assertRaises(SystemExit) as e: 289 kunit.main(['run'], self.linux_source_mock) 290 assert type(e.exception) == SystemExit 291 assert e.exception.code == 1 292 assert self.linux_source_mock.build_reconfig.call_count == 1 293 assert self.linux_source_mock.run_kernel.call_count == 1 294 self.print_mock.assert_any_call(StrContains(' 0 tests run')) 295 296 def test_exec_raw_output(self): 297 self.linux_source_mock.run_kernel = mock.Mock(return_value=[]) 298 kunit.main(['exec', '--raw_output'], self.linux_source_mock) 299 assert self.linux_source_mock.run_kernel.call_count == 1 300 for kall in self.print_mock.call_args_list: 301 assert kall != mock.call(StrContains('Testing complete.')) 302 assert kall != mock.call(StrContains(' 0 tests run')) 303 304 def test_run_raw_output(self): 305 self.linux_source_mock.run_kernel = mock.Mock(return_value=[]) 306 kunit.main(['run', '--raw_output'], self.linux_source_mock) 307 assert self.linux_source_mock.build_reconfig.call_count == 1 308 assert self.linux_source_mock.run_kernel.call_count == 1 309 for kall in self.print_mock.call_args_list: 310 assert kall != mock.call(StrContains('Testing complete.')) 311 assert kall != mock.call(StrContains(' 0 tests run')) 312 313 def test_exec_timeout(self): 314 timeout = 3453 315 kunit.main(['exec', '--timeout', str(timeout)], self.linux_source_mock) 316 self.linux_source_mock.run_kernel.assert_called_once_with(build_dir='.kunit', timeout=timeout) 317 self.print_mock.assert_any_call(StrContains('Testing complete.')) 318 319 def test_run_timeout(self): 320 timeout = 3453 321 kunit.main(['run', '--timeout', str(timeout)], self.linux_source_mock) 322 assert self.linux_source_mock.build_reconfig.call_count == 1 323 self.linux_source_mock.run_kernel.assert_called_once_with( 324 build_dir='.kunit', timeout=timeout) 325 self.print_mock.assert_any_call(StrContains('Testing complete.')) 326 327 def test_run_builddir(self): 328 build_dir = '.kunit' 329 kunit.main(['run', '--build_dir=.kunit'], self.linux_source_mock) 330 assert self.linux_source_mock.build_reconfig.call_count == 1 331 self.linux_source_mock.run_kernel.assert_called_once_with( 332 build_dir=build_dir, timeout=300) 333 self.print_mock.assert_any_call(StrContains('Testing complete.')) 334 335 def test_config_builddir(self): 336 build_dir = '.kunit' 337 kunit.main(['config', '--build_dir', build_dir], self.linux_source_mock) 338 assert self.linux_source_mock.build_reconfig.call_count == 1 339 340 def test_build_builddir(self): 341 build_dir = '.kunit' 342 kunit.main(['build', '--build_dir', build_dir], self.linux_source_mock) 343 self.linux_source_mock.build_um_kernel.assert_called_once_with(False, 8, build_dir, None) 344 345 def test_exec_builddir(self): 346 build_dir = '.kunit' 347 kunit.main(['exec', '--build_dir', build_dir], self.linux_source_mock) 348 self.linux_source_mock.run_kernel.assert_called_once_with(build_dir=build_dir, timeout=300) 349 self.print_mock.assert_any_call(StrContains('Testing complete.')) 350 351if __name__ == '__main__': 352 unittest.main() 353