amd-debug-tools 0.2.0__py3-none-any.whl → 0.2.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
test_installer.py ADDED
@@ -0,0 +1,281 @@
1
+ #!/usr/bin/python3
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ """
5
+ This module contains unit tests for the installer functions in the amd-debug-tools package.
6
+ """
7
+ from unittest.mock import patch, mock_open
8
+
9
+ import logging
10
+ import unittest
11
+
12
+ from amd_debug.installer import Installer
13
+
14
+
15
+ class TestInstaller(unittest.TestCase):
16
+ """Test installer functions"""
17
+
18
+ @classmethod
19
+ def setUpClass(cls):
20
+ logging.basicConfig(filename="/dev/null", level=logging.DEBUG)
21
+
22
+ def setUp(self):
23
+ self.installer = Installer(tool_debug=False)
24
+
25
+ @patch("builtins.print")
26
+ @patch("shutil.copy", return_value=None)
27
+ @patch("os.chmod", return_value=None)
28
+ @patch("builtins.open")
29
+ @patch("subprocess.call", return_value=0)
30
+ @patch("os.makedirs", return_value=None)
31
+ def test_install_hook(
32
+ self,
33
+ _mock_mkdir,
34
+ _mock_call,
35
+ _mock_open,
36
+ _mock_chmod,
37
+ _mock_shutil,
38
+ _mock_print,
39
+ ):
40
+ """Test install hook function"""
41
+ self.installer.install()
42
+
43
+ @patch("builtins.print")
44
+ @patch("shutil.copy", return_value=None)
45
+ @patch("os.chmod", return_value=None)
46
+ @patch("builtins.open")
47
+ @patch("subprocess.call", return_value=0)
48
+ @patch("os.makedirs", return_value=None)
49
+ def test_install_hook_missing_path(
50
+ self,
51
+ _mock_mkdir,
52
+ _mock_call,
53
+ _mock_open,
54
+ _mock_chmod,
55
+ _mock_shutil,
56
+ _mock_print,
57
+ ):
58
+ """Test install hook function, but some paths are missing"""
59
+ with patch("os.path.exists", return_value=False):
60
+ self.installer.install()
61
+
62
+ @patch("builtins.print")
63
+ @patch("os.remove", return_value=None)
64
+ @patch("builtins.open")
65
+ @patch("amd_debug.installer.get_distro", return_value="ubuntu")
66
+ @patch("subprocess.call", return_value=0)
67
+ def test_remove_hook(
68
+ self, _mock_call, _mock_get_distro, _mock_open, _mock_remove, _mock_print
69
+ ):
70
+ """Test remove hook function"""
71
+ with patch("os.path.exists", return_value=True):
72
+ self.installer.remove()
73
+
74
+ @patch("builtins.print")
75
+ @patch("os.path.exists", return_value=False)
76
+ @patch("subprocess.call", return_value=0)
77
+ def test_remove_hook_missing_path(self, _mock_call, _mock_exists, _mock_print):
78
+ """Test remove hook function when the file is missing"""
79
+ self.installer.remove()
80
+
81
+ @patch("builtins.print")
82
+ @patch("subprocess.call", return_value=0)
83
+ def test_already_installed_iasl(self, _mock_call, _mock_print):
84
+ """Test that an already installed iasl is found"""
85
+ self.installer.set_requirements("iasl")
86
+ ret = self.installer.install_dependencies()
87
+ self.assertTrue(ret)
88
+
89
+ @patch("builtins.print")
90
+ @patch("amd_debug.installer.get_distro", return_value="ubuntu")
91
+ @patch("os.execvp", return_value=None)
92
+ @patch("subprocess.check_call", return_value=0)
93
+ @patch("subprocess.call", return_value=1)
94
+ def test_install_iasl_ubuntu(
95
+ self, _mock_call, _mock_check_call, _mock_distro, _fake_sudo, _mock_print
96
+ ):
97
+ """Test install requirements function"""
98
+ self.installer.set_requirements("iasl")
99
+ ret = self.installer.install_dependencies()
100
+ _mock_check_call.assert_called_once_with(["apt", "install", "acpica-tools"])
101
+ self.assertTrue(ret)
102
+
103
+ @patch("builtins.print")
104
+ @patch("amd_debug.installer.get_distro", return_value="fedora")
105
+ @patch(
106
+ "builtins.open", new_callable=mock_open, read_data="VARIANT_ID=workstation\n"
107
+ )
108
+ @patch("os.execvp", return_value=None)
109
+ @patch("subprocess.check_call", return_value=0)
110
+ @patch("subprocess.call", return_value=1)
111
+ def test_install_iasl_fedora(
112
+ self,
113
+ _mock_call,
114
+ _mock_check_call,
115
+ _mock_variant,
116
+ _mock_distro,
117
+ _fake_sudo,
118
+ _mock_print,
119
+ ):
120
+ """Test install requirements function"""
121
+ self.installer.set_requirements("iasl")
122
+ ret = self.installer.install_dependencies()
123
+ _mock_check_call.assert_called_once_with(
124
+ ["dnf", "install", "-y", "acpica-tools"]
125
+ )
126
+ self.assertTrue(ret)
127
+
128
+ @patch("builtins.print")
129
+ @patch("amd_debug.installer.get_distro", return_value="ubuntu")
130
+ @patch("os.execvp", return_value=None)
131
+ @patch("subprocess.check_call", return_value=0)
132
+ @patch("subprocess.call", return_value=1)
133
+ def test_install_ethtool_ubuntu(
134
+ self, _mock_call, _mock_check_call, _mock_distro, _fake_sudo, _mock_print
135
+ ):
136
+ """Test install requirements function"""
137
+ self.installer.set_requirements("ethtool")
138
+ ret = self.installer.install_dependencies()
139
+ _mock_check_call.assert_called_once_with(["apt", "install", "ethtool"])
140
+ self.assertTrue(ret)
141
+
142
+ @patch("builtins.print")
143
+ @patch("amd_debug.installer.get_distro", return_value="fedora")
144
+ @patch(
145
+ "builtins.open", new_callable=mock_open, read_data="VARIANT_ID=workstation\n"
146
+ )
147
+ @patch("os.execvp", return_value=None)
148
+ @patch("subprocess.check_call", return_value=0)
149
+ @patch("subprocess.call", return_value=1)
150
+ def test_install_ethtool_fedora(
151
+ self,
152
+ _mock_call,
153
+ _mock_check_call,
154
+ _mock_variant,
155
+ _mock_distro,
156
+ _fake_sudo,
157
+ _mock_print,
158
+ ):
159
+ """Test install requirements function"""
160
+ self.installer.set_requirements("ethtool")
161
+ ret = self.installer.install_dependencies()
162
+ _mock_check_call.assert_called_once_with(["dnf", "install", "-y", "ethtool"])
163
+ self.assertTrue(ret)
164
+
165
+ @patch("builtins.print")
166
+ @patch("amd_debug.installer.get_distro", return_value="arch")
167
+ @patch("os.execvp", return_value=None)
168
+ @patch("subprocess.check_call", return_value=0)
169
+ @patch("subprocess.call", return_value=1)
170
+ def test_install_ethtool_arch(
171
+ self,
172
+ _mock_call,
173
+ _mock_check_call,
174
+ _mock_distro,
175
+ _fake_sudo,
176
+ _mock_print,
177
+ ):
178
+ """Test install requirements function"""
179
+ self.installer.set_requirements("ethtool")
180
+ ret = self.installer.install_dependencies()
181
+ _mock_check_call.assert_called_once_with(["pacman", "-Sy", "ethtool"])
182
+ self.assertTrue(ret)
183
+
184
+ @patch("builtins.print")
185
+ @patch("os.path.exists", return_value=False)
186
+ @patch("os.execvp", return_value=None)
187
+ @patch("amd_debug.installer.get_distro", return_value="gentoo")
188
+ @patch("subprocess.call", return_value=1)
189
+ def test_install_iasl_gentoo(
190
+ self, _mock_call, _mock_distro, _fake_sudo, _mock_exists, _mock_print
191
+ ):
192
+ """Test install requirements function"""
193
+ self.installer.set_requirements("iasl", "ethtool")
194
+ ret = self.installer.install_dependencies()
195
+ self.assertTrue(ret)
196
+
197
+ @patch("builtins.print")
198
+ @patch("amd_debug.installer.get_distro", return_value="ubuntu")
199
+ @patch("os.execvp", return_value=None)
200
+ @patch("subprocess.check_call", return_value=0)
201
+ @patch("subprocess.call", return_value=1)
202
+ def test_install_edid_decode_ubuntu(
203
+ self, _mock_call, _mock_check_call, _mock_distro, _fake_sudo, _mock_print
204
+ ):
205
+ """Test install requirements function for edid-decode on Ubuntu"""
206
+ self.installer.set_requirements("edid-decode")
207
+ ret = self.installer.install_dependencies()
208
+ _mock_check_call.assert_called_once_with(
209
+ ["apt", "install", "libdisplay-info-bin"]
210
+ )
211
+ self.assertTrue(ret)
212
+
213
+ @patch("builtins.print")
214
+ @patch("amd_debug.installer.get_distro", return_value="fedora")
215
+ @patch(
216
+ "builtins.open", new_callable=mock_open, read_data="VARIANT_ID=workstation\n"
217
+ )
218
+ @patch("os.execvp", return_value=None)
219
+ @patch("subprocess.check_call", return_value=0)
220
+ @patch("subprocess.call", return_value=1)
221
+ def test_install_edid_decode_fedora(
222
+ self,
223
+ _mock_call,
224
+ _mock_check_call,
225
+ _mock_variant,
226
+ _mock_distro,
227
+ _fake_sudo,
228
+ _mock_print,
229
+ ):
230
+ """Test install requirements function for edid-decode on Fedora"""
231
+ self.installer.set_requirements("edid-decode")
232
+ ret = self.installer.install_dependencies()
233
+ _mock_check_call.assert_called_once_with(
234
+ ["dnf", "install", "-y", "libdisplay-info"]
235
+ )
236
+ self.assertTrue(ret)
237
+
238
+ @patch("builtins.print")
239
+ @patch("amd_debug.installer.get_distro", return_value="arch")
240
+ @patch("os.execvp", return_value=None)
241
+ @patch("subprocess.check_call", return_value=0)
242
+ @patch("subprocess.call", return_value=1)
243
+ def test_install_edid_decode_arch(
244
+ self,
245
+ _mock_call,
246
+ _mock_check_call,
247
+ _mock_distro,
248
+ _fake_sudo,
249
+ _mock_print,
250
+ ):
251
+ """Test install requirements function for edid-decode on Arch"""
252
+ self.installer.set_requirements("edid-decode")
253
+ ret = self.installer.install_dependencies()
254
+ _mock_check_call.assert_called_once_with(["pacman", "-Sy", "libdisplay-info"])
255
+ self.assertTrue(ret)
256
+
257
+ @patch("builtins.print")
258
+ @patch("os.path.exists", return_value=False)
259
+ @patch("os.execvp", return_value=None)
260
+ @patch("amd_debug.installer.get_distro", return_value="gentoo")
261
+ @patch("subprocess.call", return_value=1)
262
+ def test_install_edid_decode_gentoo(
263
+ self, _mock_call, _mock_distro, _fake_sudo, _mock_exists, _mock_print
264
+ ):
265
+ """Test install requirements function for edid-decode on unsupported distro"""
266
+ self.installer.set_requirements("edid-decode")
267
+ ret = self.installer.install_dependencies()
268
+ self.assertTrue(ret)
269
+
270
+ @patch("builtins.print")
271
+ @patch("os.path.exists", return_value=False)
272
+ @patch("os.execvp", return_value=None)
273
+ @patch("amd_debug.installer.get_distro", return_value="gentoo")
274
+ @patch("subprocess.call", return_value=255)
275
+ def test_install_edid_decode_present(
276
+ self, _mock_call, _mock_distro, _fake_sudo, _mock_exists, _mock_print
277
+ ):
278
+ """Test install requirements function for edid-decode on unsupported distro"""
279
+ self.installer.set_requirements("edid-decode")
280
+ ret = self.installer.install_dependencies()
281
+ self.assertTrue(ret)
test_kernel.py ADDED
@@ -0,0 +1,205 @@
1
+ #!/usr/bin/python3
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ """
5
+ This module contains unit tests for the kernel log functions in the amd-debug-tools package.
6
+ """
7
+ from unittest.mock import patch, mock_open
8
+
9
+ import unittest
10
+ import logging
11
+
12
+ from amd_debug.kernel import sscanf_bios_args, get_kernel_command_line, DmesgLogger
13
+
14
+
15
+ class TestKernelLog(unittest.TestCase):
16
+ """Test Common kernel scan functions"""
17
+
18
+ @classmethod
19
+ def setUpClass(cls):
20
+ logging.basicConfig(filename="/dev/null", level=logging.DEBUG)
21
+
22
+ def test_get_kernel_command_line(self):
23
+ """Test get_kernel_command_line function"""
24
+
25
+ # Test case with a valid kernel command line that is fully filtered
26
+ kernel_cmdline = "quiet splash"
27
+ expected_output = ""
28
+ with patch(
29
+ "builtins.open", new_callable=mock_open, read_data=kernel_cmdline
30
+ ) as _mock_file:
31
+ result = get_kernel_command_line()
32
+ self.assertEqual(result, expected_output)
33
+
34
+ # Test case with an empty kernel command line
35
+ kernel_cmdline = ""
36
+ expected_output = ""
37
+ with patch(
38
+ "builtins.open", new_callable=mock_open, read_data=kernel_cmdline
39
+ ) as _mock_file:
40
+ result = get_kernel_command_line()
41
+ self.assertEqual(result, expected_output)
42
+
43
+ # Test case with a kernel command line containing special characters
44
+ kernel_cmdline = "quiet splash --debug=1"
45
+ expected_output = "--debug=1"
46
+ with patch(
47
+ "builtins.open", new_callable=mock_open, read_data=kernel_cmdline
48
+ ) as _mock_file:
49
+ result = get_kernel_command_line()
50
+ self.assertEqual(result, expected_output)
51
+
52
+ # Test case with a kernel command line containing special characters
53
+ kernel_cmdline = "quiet splash initrd=foo modprobe.blacklist=foo"
54
+ expected_output = "modprobe.blacklist=foo"
55
+ with patch(
56
+ "builtins.open", new_callable=mock_open, read_data=kernel_cmdline
57
+ ) as _mock_file:
58
+ result = get_kernel_command_line()
59
+ self.assertEqual(result, expected_output)
60
+
61
+ def test_sscanf_bios_args(self):
62
+ """Test sscanf_bios_args function"""
63
+
64
+ # Test case with a valid line
65
+ line = 'ex_trace_args: "format_string", 0x1234, 0x5678'
66
+ expected_output = "format_string"
67
+ result = sscanf_bios_args(line)
68
+ self.assertEqual(result, expected_output)
69
+
70
+ # Test case with an invalid line
71
+ line = 'invalid_line: "format_string", 0x1234, 0x5678'
72
+ result = sscanf_bios_args(line)
73
+ self.assertIsNone(result)
74
+
75
+ # Test case with a line containing "Unknown"
76
+ line = 'ex_trace_args: "format_string", Unknown, 0x5678'
77
+ expected_output = "format_string"
78
+ result = sscanf_bios_args(line)
79
+ self.assertEqual(result, expected_output)
80
+
81
+ # make sure that lines with ex_trace_point are not parsed
82
+ line = 'ex_trace_point: "format_string", 0x1234, 0x5678'
83
+ result = sscanf_bios_args(line)
84
+ self.assertTrue(result)
85
+
86
+ # test a real post code line
87
+ line = 'ex_trace_args: " POST CODE: %X ACPI TIMER: %X TIME: %d.%d ms\\n", b0003f33, 83528798, 0, 77, 0, 0'
88
+ expected_output = "POST CODE: B0003F33 ACPI TIMER: 83528798 TIME: 0.77 ms"
89
+ result = sscanf_bios_args(line)
90
+ self.assertEqual(result, expected_output)
91
+
92
+ # test a real _REG print
93
+ line = 'ex_trace_args: " OEM-ASL-PCIe Address (0x%X)._REG (%d %d) PCSA = %d\\n", ec303000, 2, 0, 0, 0, 0'
94
+ expected_output = "OEM-ASL-PCIe Address (0xEC303000)._REG (2 0) PCSA = 0"
95
+ result = sscanf_bios_args(line)
96
+ self.assertEqual(result, expected_output)
97
+
98
+ # test case of too may arguments
99
+ line = 'ex_trace_args : " APGE = %d\\n", 1, 0, 0, 0, 0, 0'
100
+ expected_output = "APGE = 1"
101
+ result = sscanf_bios_args(line)
102
+ self.assertEqual(result, expected_output)
103
+
104
+ # test case for Dispatch notify
105
+ line = "evmisc-0132 ev_queue_notify_reques: Dispatching Notify on [UBTC] (Device) Value 0x80 (Status Change) Node 00000000851b15c1"
106
+ expected_output = (
107
+ "Dispatching Notify on [UBTC] (Device) Value 0x80 (Status Change)"
108
+ )
109
+ result = sscanf_bios_args(line)
110
+ self.assertEqual(result, expected_output)
111
+
112
+
113
+ class TestDmesgLogger(unittest.TestCase):
114
+ """Test Dmesg logger functions"""
115
+
116
+ @classmethod
117
+ def setUpClass(cls):
118
+ logging.basicConfig(filename="/dev/null", level=logging.DEBUG)
119
+
120
+ def test_dmesg_logger_initialization(self):
121
+ """Test initialization of DmesgLogger"""
122
+
123
+ with patch("subprocess.run") as mock_run:
124
+ # Mock the subprocess output for dmesg -h
125
+ mock_run.return_value.stdout = b"--since supported\n"
126
+ mock_run.return_value.returncode = 0
127
+
128
+ logger = DmesgLogger()
129
+ self.assertTrue(logger.since_support)
130
+ self.assertEqual(logger.command, ["dmesg", "-t", "-k"])
131
+
132
+ def test_dmesg_logger_refresh_head(self):
133
+ """Test _refresh_head method of DmesgLogger"""
134
+
135
+ with patch("subprocess.run") as mock_run:
136
+ # Mock the subprocess output for dmesg
137
+ mock_run.return_value.stdout = b"line1\nline2\n"
138
+ mock_run.return_value.returncode = 0
139
+
140
+ logger = DmesgLogger()
141
+ logger._refresh_head() # pylint: disable=protected-access
142
+ self.assertEqual(logger.buffer, "line1\nline2\n")
143
+
144
+ def test_dmesg_logger_seek_tail(self):
145
+ """Test seek_tail method of DmesgLogger"""
146
+
147
+ with patch("subprocess.run") as mock_run:
148
+ # Mock the subprocess output for dmesg
149
+ mock_run.return_value.stdout = b"line1\nline2\n"
150
+ mock_run.return_value.returncode = 0
151
+
152
+ logger = DmesgLogger()
153
+ logger.seek_tail()
154
+ self.assertEqual(logger.buffer, "line1\nline2\n")
155
+
156
+ def test_dmesg_logger_process_callback(self):
157
+ """Test process_callback method of DmesgLogger"""
158
+
159
+ with patch("subprocess.run") as mock_run:
160
+ # Mock the subprocess output for dmesg
161
+ mock_run.return_value.stdout = b"line1\nline2\n"
162
+ mock_run.return_value.returncode = 0
163
+
164
+ logger = DmesgLogger()
165
+ logger._refresh_head() # pylint: disable=protected-access
166
+
167
+ mock_callback = unittest.mock.Mock()
168
+ logger.process_callback(mock_callback)
169
+
170
+ mock_callback.assert_any_call("line1", None)
171
+ mock_callback.assert_any_call("line2", None)
172
+
173
+ def test_dmesg_logger_match_line(self):
174
+ """Test match_line method of DmesgLogger"""
175
+
176
+ with patch("subprocess.run") as mock_run:
177
+ # Mock the subprocess output for dmesg
178
+ mock_run.return_value.stdout = b"line1\nline2\n"
179
+ mock_run.return_value.returncode = 0
180
+
181
+ logger = DmesgLogger()
182
+ logger._refresh_head() # pylint: disable=protected-access
183
+
184
+ result = logger.match_line(["line1"])
185
+ self.assertEqual(result, "line1")
186
+
187
+ result = logger.match_line(["nonexistent"])
188
+ self.assertEqual(result, "")
189
+
190
+ def test_dmesg_logger_match_pattern(self):
191
+ """Test match_pattern method of DmesgLogger"""
192
+
193
+ with patch("subprocess.run") as mock_run:
194
+ # Mock the subprocess output for dmesg
195
+ mock_run.return_value.stdout = b"line1\nline2\n"
196
+ mock_run.return_value.returncode = 0
197
+
198
+ logger = DmesgLogger()
199
+ logger._refresh_head() # pylint: disable=protected-access
200
+
201
+ result = logger.match_pattern(r"line\d")
202
+ self.assertEqual(result, "line1")
203
+
204
+ result = logger.match_pattern(r"nonexistent")
205
+ self.assertEqual(result, "")
test_launcher.py ADDED
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/python3
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ """
5
+ This module contains unit tests for the launcher in the amd-debug-tools package.
6
+ """
7
+ from unittest.mock import patch
8
+
9
+ import logging
10
+ import unittest
11
+
12
+ import amd_debug
13
+
14
+
15
+ class TestLauncher(unittest.TestCase):
16
+ """Test launcher functions"""
17
+
18
+ @classmethod
19
+ def setUpClass(cls):
20
+ logging.basicConfig(filename="/dev/null", level=logging.DEBUG)
21
+
22
+ def setUp(self):
23
+ launcher = None
24
+
25
+ def test_launcher_unknown(self):
26
+ """Test launching as unknown exe"""
27
+
28
+ with patch("builtins.print") as mock_print:
29
+ amd_debug.launch_tool("unknown_exe.py")
30
+ mock_print.assert_called_once_with(
31
+ "\033[91mUnknown exe: unknown_exe.py\033[0m"
32
+ )
33
+
34
+ def test_launcher_amd_s2idle(self):
35
+ """Test launching amd_s2idle"""
36
+
37
+ with patch("amd_debug.s2idle.main") as mock_main:
38
+ amd_debug.launch_tool("amd_s2idle.py")
39
+ mock_main.assert_called_once()
40
+
41
+ def test_launcher_amd_bios(self):
42
+ """Test launching amd_bios"""
43
+
44
+ with patch("amd_debug.bios.main") as mock_main:
45
+ amd_debug.launch_tool("amd_bios.py")
46
+ mock_main.assert_called_once()
47
+
48
+ def test_launcher_amd_pstate(self):
49
+ """Test launching amd_pstate"""
50
+
51
+ with patch("amd_debug.pstate.main") as mock_main:
52
+ amd_debug.launch_tool("amd_pstate.py")
53
+ mock_main.assert_called_once()