amd-debug-tools 0.2.2__py3-none-any.whl → 0.2.12__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.
- amd_debug/__init__.py +10 -3
- amd_debug/acpi.py +0 -1
- amd_debug/battery.py +0 -1
- amd_debug/bios.py +8 -5
- amd_debug/common.py +70 -3
- amd_debug/database.py +22 -5
- amd_debug/display.py +2 -3
- amd_debug/failures.py +44 -3
- amd_debug/installer.py +7 -6
- amd_debug/kernel.py +20 -17
- amd_debug/prerequisites.py +166 -61
- amd_debug/pstate.py +9 -6
- amd_debug/s2idle.py +53 -44
- amd_debug/sleep_report.py +129 -87
- amd_debug/templates/html +4 -2
- amd_debug/ttm.py +157 -0
- amd_debug/validator.py +61 -34
- amd_debug/wake.py +0 -1
- amd_debug_tools-0.2.12.dist-info/METADATA +75 -0
- amd_debug_tools-0.2.12.dist-info/RECORD +47 -0
- {amd_debug_tools-0.2.2.dist-info → amd_debug_tools-0.2.12.dist-info}/entry_points.txt +1 -0
- {amd_debug_tools-0.2.2.dist-info → amd_debug_tools-0.2.12.dist-info}/top_level.txt +1 -0
- launcher.py +0 -1
- test_acpi.py +1 -1
- test_bios.py +30 -12
- test_common.py +117 -1
- test_database.py +1 -1
- test_display.py +6 -6
- test_installer.py +68 -1
- test_kernel.py +7 -6
- test_launcher.py +9 -1
- test_prerequisites.py +629 -26
- test_s2idle.py +66 -19
- test_sleep_report.py +29 -0
- test_ttm.py +276 -0
- test_validator.py +187 -16
- amd_debug_tools-0.2.2.dist-info/METADATA +0 -181
- amd_debug_tools-0.2.2.dist-info/RECORD +0 -45
- {amd_debug_tools-0.2.2.dist-info → amd_debug_tools-0.2.12.dist-info}/WHEEL +0 -0
- {amd_debug_tools-0.2.2.dist-info → amd_debug_tools-0.2.12.dist-info}/licenses/LICENSE +0 -0
test_s2idle.py
CHANGED
|
@@ -117,9 +117,9 @@ class TestParseArgs(unittest.TestCase):
|
|
|
117
117
|
|
|
118
118
|
def test_version_command(self):
|
|
119
119
|
"""Test parse_args with version command"""
|
|
120
|
-
sys.argv = ["s2idle.py", "version"]
|
|
120
|
+
sys.argv = ["s2idle.py", "--version"]
|
|
121
121
|
args = parse_args()
|
|
122
|
-
self.
|
|
122
|
+
self.assertTrue(args.version)
|
|
123
123
|
|
|
124
124
|
|
|
125
125
|
class TestMainFunction(unittest.TestCase):
|
|
@@ -180,7 +180,7 @@ class TestMainFunction(unittest.TestCase):
|
|
|
180
180
|
mock_report.assert_called_once_with(
|
|
181
181
|
"2023-01-01", "2023-02-01", None, "html", False, False
|
|
182
182
|
)
|
|
183
|
-
self.
|
|
183
|
+
self.assertIsNone(result)
|
|
184
184
|
|
|
185
185
|
@patch("amd_debug.s2idle.relaunch_sudo")
|
|
186
186
|
@patch("amd_debug.s2idle.run_test_cycle")
|
|
@@ -207,26 +207,28 @@ class TestMainFunction(unittest.TestCase):
|
|
|
207
207
|
mock_test.assert_called_once_with(
|
|
208
208
|
None, None, "5", "txt", None, False, False, False, False, False
|
|
209
209
|
)
|
|
210
|
-
self.
|
|
210
|
+
self.assertIsNone(result)
|
|
211
211
|
|
|
212
212
|
@patch("amd_debug.s2idle.version")
|
|
213
213
|
def test_main_version(self, mock_version):
|
|
214
214
|
"""Test main function with version action"""
|
|
215
215
|
sys.argv = ["s2idle.py", "version"]
|
|
216
216
|
with patch("amd_debug.s2idle.parse_args") as mock_parse_args:
|
|
217
|
-
mock_parse_args.return_value = argparse.Namespace(action=
|
|
217
|
+
mock_parse_args.return_value = argparse.Namespace(version=True, action=None)
|
|
218
218
|
mock_version.return_value = "1.0.0"
|
|
219
219
|
with patch("builtins.print") as mock_print:
|
|
220
220
|
result = main()
|
|
221
221
|
mock_version.assert_called_once()
|
|
222
222
|
mock_print.assert_called_once_with("1.0.0")
|
|
223
|
-
self.
|
|
223
|
+
self.assertIsNone(result)
|
|
224
224
|
|
|
225
225
|
def test_main_no_action(self):
|
|
226
226
|
"""Test main function with no action specified"""
|
|
227
227
|
sys.argv = ["s2idle.py"]
|
|
228
228
|
with patch("amd_debug.s2idle.parse_args") as mock_parse_args:
|
|
229
|
-
mock_parse_args.return_value = argparse.Namespace(
|
|
229
|
+
mock_parse_args.return_value = argparse.Namespace(
|
|
230
|
+
version=False, action=None
|
|
231
|
+
)
|
|
230
232
|
with self.assertRaises(SystemExit) as cm:
|
|
231
233
|
main()
|
|
232
234
|
self.assertEqual(cm.exception.code, "no action specified")
|
|
@@ -358,8 +360,10 @@ class TestTestFunction(unittest.TestCase):
|
|
|
358
360
|
@patch("amd_debug.s2idle.prompt_test_arguments")
|
|
359
361
|
@patch("amd_debug.s2idle.prompt_report_arguments")
|
|
360
362
|
@patch("amd_debug.s2idle.display_report_file")
|
|
363
|
+
@patch("amd_debug.s2idle.datetime")
|
|
361
364
|
def test_test_success(
|
|
362
365
|
self,
|
|
366
|
+
mock_datetime,
|
|
363
367
|
mock_display_report_file,
|
|
364
368
|
mock_prompt_report_arguments,
|
|
365
369
|
mock_prompt_test_arguments,
|
|
@@ -369,6 +373,11 @@ class TestTestFunction(unittest.TestCase):
|
|
|
369
373
|
mock_installer,
|
|
370
374
|
):
|
|
371
375
|
"""Test the test function when everything succeeds"""
|
|
376
|
+
from datetime import datetime
|
|
377
|
+
|
|
378
|
+
mock_datetime.now.return_value = datetime(2023, 2, 1, 0, 0, 0)
|
|
379
|
+
mock_datetime.side_effect = lambda *args, **kwargs: datetime(*args, **kwargs)
|
|
380
|
+
|
|
372
381
|
mock_installer_instance = mock_installer.return_value
|
|
373
382
|
mock_installer_instance.install_dependencies.return_value = True
|
|
374
383
|
|
|
@@ -414,9 +423,11 @@ class TestTestFunction(unittest.TestCase):
|
|
|
414
423
|
mock_sleep_validator_instance.run.assert_called_once_with(
|
|
415
424
|
duration=10, wait=5, count=3, rand=False, logind=False
|
|
416
425
|
)
|
|
426
|
+
from datetime import datetime
|
|
427
|
+
|
|
417
428
|
mock_sleep_report.assert_called_once_with(
|
|
418
429
|
since="2023-01-01",
|
|
419
|
-
until=
|
|
430
|
+
until=datetime(2023, 2, 1, 0, 0, 0),
|
|
420
431
|
fname="report.html",
|
|
421
432
|
fmt="html",
|
|
422
433
|
tool_debug=True,
|
|
@@ -455,12 +466,18 @@ class TestTestFunction(unittest.TestCase):
|
|
|
455
466
|
|
|
456
467
|
@patch("amd_debug.s2idle.Installer")
|
|
457
468
|
@patch("amd_debug.s2idle.PrerequisiteValidator")
|
|
458
|
-
@patch("amd_debug.
|
|
459
|
-
@patch("amd_debug.
|
|
469
|
+
@patch("amd_debug.s2idle.SleepValidator")
|
|
470
|
+
@patch("amd_debug.s2idle.SleepReport")
|
|
471
|
+
@patch("amd_debug.s2idle.prompt_test_arguments")
|
|
472
|
+
@patch("amd_debug.s2idle.prompt_report_arguments")
|
|
473
|
+
@patch("amd_debug.s2idle.display_report_file")
|
|
460
474
|
def test_test_prerequisite_failure(
|
|
461
475
|
self,
|
|
462
|
-
|
|
463
|
-
|
|
476
|
+
mock_display_report_file,
|
|
477
|
+
mock_prompt_report_arguments,
|
|
478
|
+
mock_prompt_test_arguments,
|
|
479
|
+
mock_sleep_report,
|
|
480
|
+
mock_sleep_validator,
|
|
464
481
|
mock_prerequisite_validator,
|
|
465
482
|
mock_installer,
|
|
466
483
|
):
|
|
@@ -471,6 +488,17 @@ class TestTestFunction(unittest.TestCase):
|
|
|
471
488
|
mock_prerequisite_instance = mock_prerequisite_validator.return_value
|
|
472
489
|
mock_prerequisite_instance.run.return_value = False
|
|
473
490
|
|
|
491
|
+
mock_prompt_test_arguments.return_value = (10, 5, 3)
|
|
492
|
+
mock_prompt_report_arguments.return_value = (
|
|
493
|
+
"2023-01-01",
|
|
494
|
+
"2023-02-01",
|
|
495
|
+
"report.html",
|
|
496
|
+
"html",
|
|
497
|
+
True,
|
|
498
|
+
)
|
|
499
|
+
mock_sleep_validator_instance = mock_sleep_validator.return_value
|
|
500
|
+
mock_sleep_report_instance = mock_sleep_report.return_value
|
|
501
|
+
|
|
474
502
|
result = run_test_cycle(
|
|
475
503
|
duration=None,
|
|
476
504
|
wait=None,
|
|
@@ -492,7 +520,20 @@ class TestTestFunction(unittest.TestCase):
|
|
|
492
520
|
mock_prerequisite_validator.assert_called_once_with(True)
|
|
493
521
|
mock_prerequisite_instance.run.assert_called_once()
|
|
494
522
|
mock_prerequisite_instance.report.assert_called_once()
|
|
495
|
-
|
|
523
|
+
mock_prompt_test_arguments.assert_called_once_with(None, None, None, False)
|
|
524
|
+
mock_prompt_report_arguments.assert_called_once()
|
|
525
|
+
mock_sleep_validator_instance.assert_not_called()
|
|
526
|
+
mock_sleep_report.assert_called_once_with(
|
|
527
|
+
since=None,
|
|
528
|
+
until=None,
|
|
529
|
+
fname="report.html",
|
|
530
|
+
fmt="html",
|
|
531
|
+
tool_debug=True,
|
|
532
|
+
report_debug=True,
|
|
533
|
+
)
|
|
534
|
+
mock_sleep_report_instance.run.assert_called_once()
|
|
535
|
+
mock_display_report_file.assert_called_once_with("report.html", "html")
|
|
536
|
+
self.assertTrue(result)
|
|
496
537
|
|
|
497
538
|
@patch("amd_debug.s2idle.Installer")
|
|
498
539
|
@patch("amd_debug.s2idle.PrerequisiteValidator")
|
|
@@ -533,9 +574,9 @@ class TestTestFunction(unittest.TestCase):
|
|
|
533
574
|
"iasl", "ethtool", "edid-decode"
|
|
534
575
|
)
|
|
535
576
|
mock_installer_instance.install_dependencies.assert_called_once()
|
|
536
|
-
mock_prerequisite_validator.
|
|
537
|
-
mock_prerequisite_instance.run.
|
|
538
|
-
mock_prerequisite_instance.report.
|
|
577
|
+
mock_prerequisite_validator.assert_not_called()
|
|
578
|
+
mock_prerequisite_instance.run.assert_not_called()
|
|
579
|
+
mock_prerequisite_instance.report.assert_not_called()
|
|
539
580
|
mock_prompt_test_arguments.assert_called_once_with(None, None, None, False)
|
|
540
581
|
|
|
541
582
|
|
|
@@ -570,12 +611,18 @@ class TestDisplayReportFile(unittest.TestCase):
|
|
|
570
611
|
self, mock_subprocess_call, mock_env_get, mock_is_root
|
|
571
612
|
):
|
|
572
613
|
"""Test display_report_file when format is html, user is root, and SUDO_USER is set"""
|
|
573
|
-
|
|
614
|
+
with self.assertRaises(SystemExit):
|
|
615
|
+
display_report_file("/tmp/report.html", "html")
|
|
574
616
|
mock_is_root.assert_called_once()
|
|
575
617
|
mock_env_get.assert_any_call("SUDO_USER")
|
|
576
|
-
mock_env_get.assert_any_call("XDG_SESSION_TYPE")
|
|
577
618
|
mock_subprocess_call.assert_called_once_with(
|
|
578
|
-
[
|
|
619
|
+
[
|
|
620
|
+
"systemd-run",
|
|
621
|
+
"--user",
|
|
622
|
+
"--machine=testuser@.host",
|
|
623
|
+
"xdg-open",
|
|
624
|
+
"/tmp/report.html",
|
|
625
|
+
]
|
|
579
626
|
)
|
|
580
627
|
|
|
581
628
|
@patch("amd_debug.s2idle.is_root", return_value=True)
|
test_sleep_report.py
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
This module contains unit tests for the s2idle tool in the amd-debug-tools package.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
+
import math
|
|
8
9
|
import unittest
|
|
9
10
|
from datetime import datetime
|
|
10
11
|
from unittest.mock import patch
|
|
@@ -165,3 +166,31 @@ class TestSleepReport(unittest.TestCase):
|
|
|
165
166
|
self.report.build_hw_sleep_chart()
|
|
166
167
|
self.assertIsNotNone(self.report.hwsleep_svg)
|
|
167
168
|
mock_savefig.assert_called_once()
|
|
169
|
+
|
|
170
|
+
def test_pre_process_dataframe_zero_duration(self):
|
|
171
|
+
"""Test the pre_process_dataframe method when t0 and t1 are the same."""
|
|
172
|
+
# Mock the dataframe with t0 and t1 being the same
|
|
173
|
+
self.report.df = pd.DataFrame(
|
|
174
|
+
{
|
|
175
|
+
"t0": [datetime(2023, 10, 10, 12, 0, 0).strftime("%Y%m%d%H%M%S")],
|
|
176
|
+
"t1": [datetime(2023, 10, 10, 12, 0, 0).strftime("%Y%m%d%H%M%S")],
|
|
177
|
+
"hw": [50],
|
|
178
|
+
"requested": [1],
|
|
179
|
+
"gpio": ["1, 2"],
|
|
180
|
+
"wake_irq": ["1"],
|
|
181
|
+
"b0": [90],
|
|
182
|
+
"b1": [85],
|
|
183
|
+
"full": [100],
|
|
184
|
+
}
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# Call the method
|
|
188
|
+
self.report.pre_process_dataframe()
|
|
189
|
+
|
|
190
|
+
# Verify the dataframe was processed correctly
|
|
191
|
+
self.assertTrue(
|
|
192
|
+
self.report.df["Duration"].isna().iloc[0]
|
|
193
|
+
) # Duration should be NaN
|
|
194
|
+
self.assertTrue(
|
|
195
|
+
math.isnan(self.report.df["Hardware Sleep"].iloc[0])
|
|
196
|
+
) # Hardware Sleep should be NaN
|
test_ttm.py
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
#!/usr/bin/python3
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
This module contains unit tests for the ttm tool in the amd-debug-tools package.
|
|
6
|
+
"""
|
|
7
|
+
import unittest
|
|
8
|
+
import sys
|
|
9
|
+
import logging
|
|
10
|
+
from unittest import mock
|
|
11
|
+
|
|
12
|
+
from amd_debug.ttm import main, parse_args, AmdTtmTool, maybe_reboot
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TestParseArgs(unittest.TestCase):
|
|
16
|
+
"""Test parse_args function"""
|
|
17
|
+
|
|
18
|
+
@classmethod
|
|
19
|
+
def setUpClass(cls):
|
|
20
|
+
logging.basicConfig(filename="/dev/null", level=logging.DEBUG)
|
|
21
|
+
|
|
22
|
+
def setUp(self):
|
|
23
|
+
self.default_sys_argv = sys.argv
|
|
24
|
+
|
|
25
|
+
def tearDown(self):
|
|
26
|
+
sys.argv = self.default_sys_argv
|
|
27
|
+
|
|
28
|
+
@mock.patch.object(sys, "argv", new=["ttm", "--version"])
|
|
29
|
+
def test_parse_args_version(self):
|
|
30
|
+
"""Test version argument"""
|
|
31
|
+
args = parse_args()
|
|
32
|
+
self.assertTrue(args.version)
|
|
33
|
+
self.assertFalse(args.set)
|
|
34
|
+
self.assertFalse(args.clear)
|
|
35
|
+
|
|
36
|
+
@mock.patch.object(sys, "argv", new=["ttm", "--clear"])
|
|
37
|
+
def test_parse_args_clear(self):
|
|
38
|
+
"""Test clear argument"""
|
|
39
|
+
args = parse_args()
|
|
40
|
+
self.assertFalse(args.version)
|
|
41
|
+
self.assertFalse(args.set)
|
|
42
|
+
self.assertTrue(args.clear)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class TestMainFunction(unittest.TestCase):
|
|
46
|
+
"""Test main() function logic"""
|
|
47
|
+
|
|
48
|
+
@mock.patch("amd_debug.ttm.parse_args")
|
|
49
|
+
@mock.patch("amd_debug.ttm.version", return_value="1.2.3")
|
|
50
|
+
@mock.patch("builtins.print")
|
|
51
|
+
def test_main_version(self, mock_print, _mock_version, mock_parse_args):
|
|
52
|
+
"""Test main function with version argument"""
|
|
53
|
+
mock_parse_args.return_value = mock.Mock(
|
|
54
|
+
version=True, set=None, clear=False, tool_debug=False
|
|
55
|
+
)
|
|
56
|
+
ret = main()
|
|
57
|
+
mock_print.assert_called_with("1.2.3")
|
|
58
|
+
self.assertIsNone(ret)
|
|
59
|
+
|
|
60
|
+
@mock.patch("amd_debug.ttm.parse_args")
|
|
61
|
+
@mock.patch("amd_debug.ttm.AmdTtmTool")
|
|
62
|
+
@mock.patch("builtins.print")
|
|
63
|
+
def test_main_set_invalid(self, mock_print, _mock_tool, mock_parse_args):
|
|
64
|
+
"""Test main function with invalid set argument"""
|
|
65
|
+
mock_parse_args.return_value = mock.Mock(
|
|
66
|
+
version=False, set=0, clear=False, tool_debug=False
|
|
67
|
+
)
|
|
68
|
+
ret = main()
|
|
69
|
+
mock_print.assert_called_with("Error: GB value must be greater than 0")
|
|
70
|
+
self.assertEqual(ret, 1)
|
|
71
|
+
|
|
72
|
+
@mock.patch("amd_debug.ttm.parse_args")
|
|
73
|
+
@mock.patch("amd_debug.ttm.AmdTtmTool")
|
|
74
|
+
def test_main_set_valid(self, mock_tool, mock_parse_args):
|
|
75
|
+
"""Test main function with set argument"""
|
|
76
|
+
instance = mock_tool.return_value
|
|
77
|
+
instance.set.return_value = True
|
|
78
|
+
mock_parse_args.return_value = mock.Mock(
|
|
79
|
+
version=False, set=2, clear=False, tool_debug=False
|
|
80
|
+
)
|
|
81
|
+
ret = main()
|
|
82
|
+
instance.set.assert_called_with(2)
|
|
83
|
+
self.assertIsNone(ret)
|
|
84
|
+
|
|
85
|
+
@mock.patch("amd_debug.ttm.parse_args")
|
|
86
|
+
@mock.patch("amd_debug.ttm.AmdTtmTool")
|
|
87
|
+
def test_main_set_failed(self, mock_tool, mock_parse_args):
|
|
88
|
+
instance = mock_tool.return_value
|
|
89
|
+
instance.set.return_value = False
|
|
90
|
+
mock_parse_args.return_value = mock.Mock(
|
|
91
|
+
version=False, set=2, clear=False, tool_debug=False
|
|
92
|
+
)
|
|
93
|
+
ret = main()
|
|
94
|
+
instance.set.assert_called_with(2)
|
|
95
|
+
self.assertEqual(ret, 1)
|
|
96
|
+
|
|
97
|
+
@mock.patch("amd_debug.ttm.parse_args")
|
|
98
|
+
@mock.patch("amd_debug.ttm.AmdTtmTool")
|
|
99
|
+
def test_main_clear_success(self, mock_tool, mock_parse_args):
|
|
100
|
+
"""Test main function with clear argument"""
|
|
101
|
+
instance = mock_tool.return_value
|
|
102
|
+
instance.clear.return_value = True
|
|
103
|
+
mock_parse_args.return_value = mock.Mock(
|
|
104
|
+
version=False, set=None, clear=True, tool_debug=False
|
|
105
|
+
)
|
|
106
|
+
ret = main()
|
|
107
|
+
instance.clear.assert_called_once()
|
|
108
|
+
self.assertIsNone(ret)
|
|
109
|
+
|
|
110
|
+
@mock.patch("amd_debug.ttm.parse_args")
|
|
111
|
+
@mock.patch("amd_debug.ttm.AmdTtmTool")
|
|
112
|
+
def test_main_clear_failed(self, mock_tool, mock_parse_args):
|
|
113
|
+
"""Test main function with clear argument failure"""
|
|
114
|
+
instance = mock_tool.return_value
|
|
115
|
+
instance.clear.return_value = False
|
|
116
|
+
mock_parse_args.return_value = mock.Mock(
|
|
117
|
+
version=False, set=None, clear=True, tool_debug=False
|
|
118
|
+
)
|
|
119
|
+
ret = main()
|
|
120
|
+
instance.clear.assert_called_once()
|
|
121
|
+
self.assertEqual(ret, 1)
|
|
122
|
+
|
|
123
|
+
@mock.patch("amd_debug.ttm.parse_args")
|
|
124
|
+
@mock.patch("amd_debug.ttm.AmdTtmTool")
|
|
125
|
+
def test_main_get_success(self, mock_tool, mock_parse_args):
|
|
126
|
+
"""Test main function with get argument"""
|
|
127
|
+
instance = mock_tool.return_value
|
|
128
|
+
instance.get.return_value = True
|
|
129
|
+
mock_parse_args.return_value = mock.Mock(
|
|
130
|
+
version=False, set=None, clear=False, tool_debug=False
|
|
131
|
+
)
|
|
132
|
+
ret = main()
|
|
133
|
+
instance.get.assert_called_once()
|
|
134
|
+
self.assertIsNone(ret)
|
|
135
|
+
|
|
136
|
+
@mock.patch("amd_debug.ttm.parse_args")
|
|
137
|
+
@mock.patch("amd_debug.ttm.AmdTtmTool")
|
|
138
|
+
def test_main_get_failed(self, mock_tool, mock_parse_args):
|
|
139
|
+
"""Test main function with get argument failure"""
|
|
140
|
+
instance = mock_tool.return_value
|
|
141
|
+
instance.get.return_value = False
|
|
142
|
+
mock_parse_args.return_value = mock.Mock(
|
|
143
|
+
version=False, set=None, clear=False, tool_debug=False
|
|
144
|
+
)
|
|
145
|
+
ret = main()
|
|
146
|
+
instance.get.assert_called_once()
|
|
147
|
+
self.assertEqual(ret, 1)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class TestMaybeReboot(unittest.TestCase):
|
|
151
|
+
"""Test maybe_reboot function"""
|
|
152
|
+
|
|
153
|
+
@mock.patch("builtins.input", return_value="y")
|
|
154
|
+
@mock.patch("amd_debug.ttm.reboot", return_value=True)
|
|
155
|
+
def test_maybe_reboot_yes(self, mock_reboot, _mock_input):
|
|
156
|
+
"""Test reboot confirmation and execution"""
|
|
157
|
+
result = maybe_reboot()
|
|
158
|
+
mock_reboot.assert_called_once()
|
|
159
|
+
self.assertTrue(result)
|
|
160
|
+
|
|
161
|
+
@mock.patch("builtins.input", return_value="n")
|
|
162
|
+
@mock.patch("amd_debug.ttm.reboot", return_value=True)
|
|
163
|
+
def test_maybe_reboot_no(self, mock_reboot, _mock_input):
|
|
164
|
+
"""Test reboot confirmation without execution"""
|
|
165
|
+
result = maybe_reboot()
|
|
166
|
+
mock_reboot.assert_not_called()
|
|
167
|
+
self.assertTrue(result)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class TestAmdTtmTool(unittest.TestCase):
|
|
171
|
+
"""Unit tests for AmdTtmTool class"""
|
|
172
|
+
|
|
173
|
+
def setUp(self):
|
|
174
|
+
self.tool = AmdTtmTool(logging=False)
|
|
175
|
+
|
|
176
|
+
@mock.patch("builtins.open", new_callable=mock.mock_open, read_data="4096")
|
|
177
|
+
@mock.patch("amd_debug.ttm.bytes_to_gb", return_value=4.0)
|
|
178
|
+
@mock.patch("amd_debug.ttm.print_color")
|
|
179
|
+
@mock.patch("amd_debug.ttm.get_system_mem", return_value=16.0)
|
|
180
|
+
def test_get_success(self, _mock_mem, mock_print, _mock_bytes_to_gb, mock_open):
|
|
181
|
+
"""Test get() when TTM_PARAM_PATH exists"""
|
|
182
|
+
result = self.tool.get()
|
|
183
|
+
mock_open.assert_called_once_with(
|
|
184
|
+
"/sys/module/ttm/parameters/pages_limit", "r", encoding="utf-8"
|
|
185
|
+
)
|
|
186
|
+
mock_print.assert_any_call(
|
|
187
|
+
"Current TTM pages limit: 4096 pages (4.00 GB)", "💻"
|
|
188
|
+
)
|
|
189
|
+
mock_print.assert_any_call("Total system memory: 16.00 GB", "💻")
|
|
190
|
+
self.assertTrue(result)
|
|
191
|
+
|
|
192
|
+
@mock.patch("builtins.open", side_effect=FileNotFoundError)
|
|
193
|
+
@mock.patch("amd_debug.ttm.print_color")
|
|
194
|
+
def test_get_file_not_found(self, mock_print, _mock_open):
|
|
195
|
+
"""Test get() when TTM_PARAM_PATH does not exist"""
|
|
196
|
+
result = self.tool.get()
|
|
197
|
+
mock_print.assert_called_with(
|
|
198
|
+
"Error: Could not find /sys/module/ttm/parameters/pages_limit", "❌"
|
|
199
|
+
)
|
|
200
|
+
self.assertFalse(result)
|
|
201
|
+
|
|
202
|
+
@mock.patch("amd_debug.ttm.relaunch_sudo", return_value=True)
|
|
203
|
+
@mock.patch("amd_debug.ttm.get_system_mem", return_value=8.0)
|
|
204
|
+
@mock.patch("amd_debug.ttm.print_color")
|
|
205
|
+
def test_set_gb_greater_than_total(
|
|
206
|
+
self, mock_print, _mock_mem, _mock_relaunch_sudo
|
|
207
|
+
):
|
|
208
|
+
"""Test set() when gb_value > total system memory"""
|
|
209
|
+
result = self.tool.set(16)
|
|
210
|
+
mock_print.assert_any_call(
|
|
211
|
+
"16.00 GB is greater than total system memory (8.00 GB)", "❌"
|
|
212
|
+
)
|
|
213
|
+
self.assertFalse(result)
|
|
214
|
+
|
|
215
|
+
@mock.patch("amd_debug.ttm.relaunch_sudo", return_value=True)
|
|
216
|
+
@mock.patch("amd_debug.ttm.get_system_mem", return_value=10.0)
|
|
217
|
+
@mock.patch("amd_debug.ttm.print_color")
|
|
218
|
+
@mock.patch("builtins.input", return_value="n")
|
|
219
|
+
def test_set_gb_exceeds_max_percentage_cancel(
|
|
220
|
+
self, _mock_input, mock_print, _mock_mem, mock_relaunch_sudo
|
|
221
|
+
):
|
|
222
|
+
"""Test set() when gb_value exceeds max percentage and user cancels"""
|
|
223
|
+
result = self.tool.set(9.5)
|
|
224
|
+
self.assertFalse(result)
|
|
225
|
+
mock_print.assert_any_call("Operation cancelled.", "🚦")
|
|
226
|
+
|
|
227
|
+
@mock.patch("amd_debug.ttm.relaunch_sudo", return_value=True)
|
|
228
|
+
@mock.patch("amd_debug.ttm.get_system_mem", return_value=10.0)
|
|
229
|
+
@mock.patch("amd_debug.ttm.gb_to_pages", return_value=20480)
|
|
230
|
+
@mock.patch("amd_debug.ttm.print_color")
|
|
231
|
+
@mock.patch("builtins.open", new_callable=mock.mock_open)
|
|
232
|
+
@mock.patch("builtins.input", return_value="y")
|
|
233
|
+
@mock.patch("amd_debug.ttm.maybe_reboot", return_value=True)
|
|
234
|
+
def test_set_success(
|
|
235
|
+
self,
|
|
236
|
+
_mock_reboot,
|
|
237
|
+
_mock_input,
|
|
238
|
+
mock_open,
|
|
239
|
+
mock_print,
|
|
240
|
+
_mock_gb_to_pages,
|
|
241
|
+
_mock_mem,
|
|
242
|
+
_relaunch_sudo,
|
|
243
|
+
):
|
|
244
|
+
"""Test set() success path"""
|
|
245
|
+
result = self.tool.set(5)
|
|
246
|
+
mock_open.assert_called_once_with(
|
|
247
|
+
"/etc/modprobe.d/ttm.conf", "w", encoding="utf-8"
|
|
248
|
+
)
|
|
249
|
+
mock_print.assert_any_call(
|
|
250
|
+
"Successfully set TTM pages limit to 20480 pages (5.00 GB)", "🐧"
|
|
251
|
+
)
|
|
252
|
+
self.assertTrue(result)
|
|
253
|
+
|
|
254
|
+
@mock.patch("os.path.exists", return_value=False)
|
|
255
|
+
@mock.patch("amd_debug.ttm.print_color")
|
|
256
|
+
def test_clear_file_not_exists(self, mock_print, _mock_exists):
|
|
257
|
+
"""Test clear() when config file does not exist"""
|
|
258
|
+
result = self.tool.clear()
|
|
259
|
+
mock_print.assert_called_with("/etc/modprobe.d/ttm.conf doesn't exist", "❌")
|
|
260
|
+
self.assertFalse(result)
|
|
261
|
+
|
|
262
|
+
@mock.patch("os.path.exists", return_value=True)
|
|
263
|
+
@mock.patch("amd_debug.ttm.relaunch_sudo", return_value=True)
|
|
264
|
+
@mock.patch("os.remove")
|
|
265
|
+
@mock.patch("amd_debug.ttm.print_color")
|
|
266
|
+
@mock.patch("amd_debug.ttm.maybe_reboot", return_value=True)
|
|
267
|
+
def test_clear_success(
|
|
268
|
+
self, _mock_reboot, mock_print, mock_remove, _mock_relaunch_sudo, _mock_exists
|
|
269
|
+
):
|
|
270
|
+
"""Test clear() success path"""
|
|
271
|
+
result = self.tool.clear()
|
|
272
|
+
mock_remove.assert_called_once_with("/etc/modprobe.d/ttm.conf")
|
|
273
|
+
mock_print.assert_any_call(
|
|
274
|
+
"Configuration /etc/modprobe.d/ttm.conf removed", "🐧"
|
|
275
|
+
)
|
|
276
|
+
self.assertTrue(result)
|