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('CONFIG_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('CONFIG_UML=y'))
55		expected_kconfig.add_entry(
56			kunit_config.KconfigEntry('CONFIG_MMU=y'))
57		expected_kconfig.add_entry(
58			kunit_config.KconfigEntry('CONFIG_TEST=y'))
59		expected_kconfig.add_entry(
60			kunit_config.KconfigEntry('CONFIG_EXAMPLE_TEST=y'))
61		expected_kconfig.add_entry(
62			kunit_config.KconfigEntry('# CONFIG_MK8 is not set'))
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('CONFIG_UML=y'))
72		expected_kconfig.add_entry(
73			kunit_config.KconfigEntry('CONFIG_MMU=y'))
74		expected_kconfig.add_entry(
75			kunit_config.KconfigEntry('CONFIG_TEST=y'))
76		expected_kconfig.add_entry(
77			kunit_config.KconfigEntry('CONFIG_EXAMPLE_TEST=y'))
78		expected_kconfig.add_entry(
79			kunit_config.KconfigEntry('# CONFIG_MK8 is not set'))
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_parse_successful_test_log(self):
112		all_passed_log = get_absolute_path(
113			'test_data/test_is_test_passed-all_passed.log')
114		file = open(all_passed_log)
115		result = kunit_parser.parse_run_tests(file.readlines())
116		self.assertEqual(
117			kunit_parser.TestStatus.SUCCESS,
118			result.status)
119		file.close()
120
121	def test_parse_failed_test_log(self):
122		failed_log = get_absolute_path(
123			'test_data/test_is_test_passed-failure.log')
124		file = open(failed_log)
125		result = kunit_parser.parse_run_tests(file.readlines())
126		self.assertEqual(
127			kunit_parser.TestStatus.FAILURE,
128			result.status)
129		file.close()
130
131	def test_no_tests(self):
132		empty_log = get_absolute_path(
133			'test_data/test_is_test_passed-no_tests_run.log')
134		file = open(empty_log)
135		result = kunit_parser.parse_run_tests(
136			kunit_parser.isolate_kunit_output(file.readlines()))
137		self.assertEqual(0, len(result.suites))
138		self.assertEqual(
139			kunit_parser.TestStatus.NO_TESTS,
140			result.status)
141		file.close()
142
143	def test_crashed_test(self):
144		crashed_log = get_absolute_path(
145			'test_data/test_is_test_passed-crash.log')
146		file = open(crashed_log)
147		result = kunit_parser.parse_run_tests(file.readlines())
148		self.assertEqual(
149			kunit_parser.TestStatus.TEST_CRASHED,
150			result.status)
151		file.close()
152
153class StrContains(str):
154	def __eq__(self, other):
155		return self in other
156
157class KUnitMainTest(unittest.TestCase):
158	def setUp(self):
159		path = get_absolute_path('test_data/test_is_test_passed-all_passed.log')
160		file = open(path)
161		all_passed_log = file.readlines()
162		self.print_patch = mock.patch('builtins.print')
163		self.print_mock = self.print_patch.start()
164		self.linux_source_mock = mock.Mock()
165		self.linux_source_mock.build_reconfig = mock.Mock(return_value=True)
166		self.linux_source_mock.build_um_kernel = mock.Mock(return_value=True)
167		self.linux_source_mock.run_kernel = mock.Mock(return_value=all_passed_log)
168
169	def tearDown(self):
170		self.print_patch.stop()
171		pass
172
173	def test_run_passes_args_pass(self):
174		kunit.main(['run'], self.linux_source_mock)
175		assert self.linux_source_mock.build_reconfig.call_count == 1
176		assert self.linux_source_mock.run_kernel.call_count == 1
177		self.linux_source_mock.run_kernel.assert_called_once_with(build_dir='', timeout=300)
178		self.print_mock.assert_any_call(StrContains('Testing complete.'))
179
180	def test_run_passes_args_fail(self):
181		self.linux_source_mock.run_kernel = mock.Mock(return_value=[])
182		with self.assertRaises(SystemExit) as e:
183			kunit.main(['run'], self.linux_source_mock)
184		assert type(e.exception) == SystemExit
185		assert e.exception.code == 1
186		assert self.linux_source_mock.build_reconfig.call_count == 1
187		assert self.linux_source_mock.run_kernel.call_count == 1
188		self.print_mock.assert_any_call(StrContains(' 0 tests run'))
189
190	def test_run_raw_output(self):
191		self.linux_source_mock.run_kernel = mock.Mock(return_value=[])
192		kunit.main(['run', '--raw_output'], self.linux_source_mock)
193		assert self.linux_source_mock.build_reconfig.call_count == 1
194		assert self.linux_source_mock.run_kernel.call_count == 1
195		for kall in self.print_mock.call_args_list:
196			assert kall != mock.call(StrContains('Testing complete.'))
197			assert kall != mock.call(StrContains(' 0 tests run'))
198
199	def test_run_timeout(self):
200		timeout = 3453
201		kunit.main(['run', '--timeout', str(timeout)], self.linux_source_mock)
202		assert self.linux_source_mock.build_reconfig.call_count == 1
203		self.linux_source_mock.run_kernel.assert_called_once_with(build_dir='', timeout=timeout)
204		self.print_mock.assert_any_call(StrContains('Testing complete.'))
205
206	def test_run_builddir(self):
207		build_dir = '.kunit'
208		kunit.main(['run', '--build_dir', build_dir], self.linux_source_mock)
209		assert self.linux_source_mock.build_reconfig.call_count == 1
210		self.linux_source_mock.run_kernel.assert_called_once_with(build_dir=build_dir, timeout=300)
211		self.print_mock.assert_any_call(StrContains('Testing complete.'))
212
213if __name__ == '__main__':
214	unittest.main()
215