amd-debug-tools 0.2.5__tar.gz → 0.2.6__tar.gz
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_tools-0.2.5 → amd_debug_tools-0.2.6}/PKG-INFO +6 -3
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/README.md +5 -2
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/pyproject.toml +1 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug/__init__.py +9 -1
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug/bios.py +5 -3
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug/common.py +39 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug/installer.py +2 -2
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug/prerequisites.py +24 -2
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug/pstate.py +5 -3
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug/s2idle.py +5 -3
- amd_debug_tools-0.2.6/src/amd_debug/test_ttm.py +291 -0
- amd_debug_tools-0.2.6/src/amd_debug/ttm.py +161 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug/validator.py +20 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug_tools.egg-info/PKG-INFO +6 -3
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug_tools.egg-info/SOURCES.txt +2 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug_tools.egg-info/entry_points.txt +1 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/test_bios.py +26 -8
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/test_common.py +91 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/test_kernel.py +2 -1
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/test_launcher.py +7 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/test_prerequisites.py +77 -1
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/test_s2idle.py +6 -4
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/test_validator.py +63 -1
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/LICENSE +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/setup.cfg +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug/acpi.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug/bash/amd-s2idle +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug/battery.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug/database.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug/display.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug/failures.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug/kernel.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug/s2idle-hook +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug/sleep_report.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug/templates/html +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug/templates/md +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug/templates/stdout +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug/templates/txt +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug/wake.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug_tools.egg-info/dependency_links.txt +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug_tools.egg-info/requires.txt +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/amd_debug_tools.egg-info/top_level.txt +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/launcher.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/test_acpi.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/test_batteries.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/test_database.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/test_display.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/test_failures.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/test_installer.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/test_pstate.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/test_sleep_report.py +0 -0
- {amd_debug_tools-0.2.5 → amd_debug_tools-0.2.6}/src/test_wake.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: amd-debug-tools
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.6
|
|
4
4
|
Summary: debug tools for AMD systems
|
|
5
5
|
Author-email: Mario Limonciello <superm1@kernel.org>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -131,7 +131,7 @@ The following optional arguments are supported for this command:
|
|
|
131
131
|
If the tool is launched with an environment that can call `xdg-open`, the report
|
|
132
132
|
will be opened in a browser.
|
|
133
133
|
|
|
134
|
-
### `amd-s2idle version`
|
|
134
|
+
### `amd-s2idle --version`
|
|
135
135
|
This will print the version of the tool and exit.
|
|
136
136
|
|
|
137
137
|
### Debug output
|
|
@@ -164,7 +164,7 @@ The following optional arguments are supported for this command:
|
|
|
164
164
|
--input INPUT Optional input file to parse
|
|
165
165
|
--tool-debug Enable tool debug logging
|
|
166
166
|
|
|
167
|
-
### `amd-bios version`
|
|
167
|
+
### `amd-bios --version`
|
|
168
168
|
This will print the version of the tool and exit.
|
|
169
169
|
|
|
170
170
|
## amd-pstate
|
|
@@ -172,6 +172,9 @@ This will print the version of the tool and exit.
|
|
|
172
172
|
It will capture some state from the system as well as from the machine specific registers that
|
|
173
173
|
amd-pstate uses.
|
|
174
174
|
|
|
175
|
+
## amd-ttm
|
|
176
|
+
`amd-ttm` is a tool used for managing the TTM memory settings on AMD systems.
|
|
177
|
+
|
|
175
178
|
## Compatibility scripts
|
|
176
179
|
|
|
177
180
|
Compatibility scripts are provided for the previous names the tools went by:
|
|
@@ -107,7 +107,7 @@ The following optional arguments are supported for this command:
|
|
|
107
107
|
If the tool is launched with an environment that can call `xdg-open`, the report
|
|
108
108
|
will be opened in a browser.
|
|
109
109
|
|
|
110
|
-
### `amd-s2idle version`
|
|
110
|
+
### `amd-s2idle --version`
|
|
111
111
|
This will print the version of the tool and exit.
|
|
112
112
|
|
|
113
113
|
### Debug output
|
|
@@ -140,7 +140,7 @@ The following optional arguments are supported for this command:
|
|
|
140
140
|
--input INPUT Optional input file to parse
|
|
141
141
|
--tool-debug Enable tool debug logging
|
|
142
142
|
|
|
143
|
-
### `amd-bios version`
|
|
143
|
+
### `amd-bios --version`
|
|
144
144
|
This will print the version of the tool and exit.
|
|
145
145
|
|
|
146
146
|
## amd-pstate
|
|
@@ -148,6 +148,9 @@ This will print the version of the tool and exit.
|
|
|
148
148
|
It will capture some state from the system as well as from the machine specific registers that
|
|
149
149
|
amd-pstate uses.
|
|
150
150
|
|
|
151
|
+
## amd-ttm
|
|
152
|
+
`amd-ttm` is a tool used for managing the TTM memory settings on AMD systems.
|
|
153
|
+
|
|
151
154
|
## Compatibility scripts
|
|
152
155
|
|
|
153
156
|
Compatibility scripts are provided for the previous names the tools went by:
|
|
@@ -23,8 +23,15 @@ def amd_pstate():
|
|
|
23
23
|
return pstate.main()
|
|
24
24
|
|
|
25
25
|
|
|
26
|
+
def amd_ttm():
|
|
27
|
+
"""Launch the amd-ttm tool."""
|
|
28
|
+
from . import ttm # pylint: disable=import-outside-toplevel
|
|
29
|
+
|
|
30
|
+
return ttm.main()
|
|
31
|
+
|
|
32
|
+
|
|
26
33
|
def install_dep_superset():
|
|
27
|
-
"""Install all
|
|
34
|
+
"""Install all superset dependencies."""
|
|
28
35
|
from . import installer # pylint: disable=import-outside-toplevel
|
|
29
36
|
|
|
30
37
|
return installer.install_dep_superset()
|
|
@@ -36,6 +43,7 @@ def launch_tool(tool_name):
|
|
|
36
43
|
"amd_s2idle.py": amd_s2idle,
|
|
37
44
|
"amd_bios.py": amd_bios,
|
|
38
45
|
"amd_pstate.py": amd_pstate,
|
|
46
|
+
"amd_ttm.py": amd_ttm,
|
|
39
47
|
"install_deps.py": install_dep_superset,
|
|
40
48
|
}
|
|
41
49
|
if tool_name in tools:
|
|
@@ -105,7 +105,9 @@ def parse_args():
|
|
|
105
105
|
action="store_true",
|
|
106
106
|
help="Enable tool debug logging",
|
|
107
107
|
)
|
|
108
|
-
|
|
108
|
+
parser.add_argument(
|
|
109
|
+
"--version", action="store_true", help="Show version information"
|
|
110
|
+
)
|
|
109
111
|
|
|
110
112
|
if len(sys.argv) == 1:
|
|
111
113
|
parser.print_help(sys.stderr)
|
|
@@ -122,7 +124,7 @@ def parse_args():
|
|
|
122
124
|
return args
|
|
123
125
|
|
|
124
126
|
|
|
125
|
-
def main() -> None|int:
|
|
127
|
+
def main() -> None | int:
|
|
126
128
|
"""Main function"""
|
|
127
129
|
args = parse_args()
|
|
128
130
|
ret = False
|
|
@@ -132,7 +134,7 @@ def main() -> None|int:
|
|
|
132
134
|
elif args.command == "parse":
|
|
133
135
|
app = AmdBios(args.input, args.tool_debug)
|
|
134
136
|
ret = app.run()
|
|
135
|
-
elif args.
|
|
137
|
+
elif args.version:
|
|
136
138
|
print(version())
|
|
137
139
|
show_log_info()
|
|
138
140
|
if ret is False:
|
|
@@ -226,6 +226,45 @@ def get_pretty_distro() -> str:
|
|
|
226
226
|
return distro
|
|
227
227
|
|
|
228
228
|
|
|
229
|
+
def bytes_to_gb(bytes_value):
|
|
230
|
+
"""Convert bytes to GB"""
|
|
231
|
+
return bytes_value * 4096 / (1024 * 1024 * 1024)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def gb_to_pages(gb_value):
|
|
235
|
+
"""Convert GB into bytes"""
|
|
236
|
+
return int(gb_value * (1024 * 1024 * 1024) / 4096)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def reboot():
|
|
240
|
+
"""Reboot the system"""
|
|
241
|
+
try:
|
|
242
|
+
import dbus # pylint: disable=import-outside-toplevel
|
|
243
|
+
|
|
244
|
+
bus = dbus.SystemBus()
|
|
245
|
+
obj = bus.get_object("org.freedesktop.login1", "/org/freedesktop/login1")
|
|
246
|
+
intf = dbus.Interface(obj, "org.freedesktop.login1.Manager")
|
|
247
|
+
intf.Reboot(True)
|
|
248
|
+
return True
|
|
249
|
+
except ImportError:
|
|
250
|
+
fatal_error("Missing dbus")
|
|
251
|
+
except dbus.exceptions.DBusException as e:
|
|
252
|
+
fatal_error({e})
|
|
253
|
+
return True
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def get_system_mem():
|
|
257
|
+
"""Get the total system memory in GB using /proc/meminfo"""
|
|
258
|
+
with open(os.path.join("/", "proc", "meminfo"), "r", encoding="utf-8") as f:
|
|
259
|
+
for line in f:
|
|
260
|
+
if line.startswith("MemTotal:"):
|
|
261
|
+
# MemTotal line format: "MemTotal: 16384516 kB"
|
|
262
|
+
# Extract the number and convert from kB to GB
|
|
263
|
+
mem_kb = int(line.split()[1])
|
|
264
|
+
return mem_kb / (1024 * 1024)
|
|
265
|
+
raise ValueError("Could not find MemTotal in /proc/meminfo")
|
|
266
|
+
|
|
267
|
+
|
|
229
268
|
def is_root() -> bool:
|
|
230
269
|
"""Check if the user is root"""
|
|
231
270
|
return os.geteuid() == 0
|
|
@@ -446,8 +446,8 @@ def parse_args():
|
|
|
446
446
|
return parser.parse_args()
|
|
447
447
|
|
|
448
448
|
|
|
449
|
-
def install_dep_superset() -> None|int:
|
|
450
|
-
"""Install all python
|
|
449
|
+
def install_dep_superset() -> None | int:
|
|
450
|
+
"""Install all python superset dependencies"""
|
|
451
451
|
args = parse_args()
|
|
452
452
|
tool = Installer(tool_debug=args.tool_debug)
|
|
453
453
|
tool.set_requirements(
|
|
@@ -128,6 +128,28 @@ class PrerequisiteValidator(AmdTool):
|
|
|
128
128
|
if not self.db.get_last_prereq_ts():
|
|
129
129
|
self.run()
|
|
130
130
|
|
|
131
|
+
def capture_nvidia(self):
|
|
132
|
+
"""Capture the NVIDIA GPU state"""
|
|
133
|
+
p = os.path.join("/", "proc", "driver", "nvidia", "version")
|
|
134
|
+
if not os.path.exists(p):
|
|
135
|
+
return True
|
|
136
|
+
try:
|
|
137
|
+
self.db.record_debug_file(p)
|
|
138
|
+
except PermissionError:
|
|
139
|
+
self.db.record_prereq("NVIDIA GPU version not readable", "👀")
|
|
140
|
+
return True
|
|
141
|
+
p = os.path.join("/", "proc", "driver", "nvidia", "gpus")
|
|
142
|
+
if not os.path.exists(p):
|
|
143
|
+
return True
|
|
144
|
+
for root, _dirs, files in os.walk(p, topdown=False):
|
|
145
|
+
for f in files:
|
|
146
|
+
try:
|
|
147
|
+
self.db.record_debug(f"NVIDIA {f}")
|
|
148
|
+
self.db.record_debug_file(os.path.join(root, f))
|
|
149
|
+
except PermissionError:
|
|
150
|
+
self.db.record_prereq("NVIDIA GPU {f} not readable", "👀")
|
|
151
|
+
return True
|
|
152
|
+
|
|
131
153
|
def capture_edid(self):
|
|
132
154
|
"""Capture and decode the EDID data"""
|
|
133
155
|
edids = self.display.get_edid()
|
|
@@ -1227,9 +1249,8 @@ class PrerequisiteValidator(AmdTool):
|
|
|
1227
1249
|
# ignore kernel warnings
|
|
1228
1250
|
taint &= ~BIT(9)
|
|
1229
1251
|
if taint != 0:
|
|
1230
|
-
self.db.record_prereq(f"Kernel is tainted: {taint}", "
|
|
1252
|
+
self.db.record_prereq(f"Kernel is tainted: {taint}", "🚦")
|
|
1231
1253
|
self.failures += [TaintedKernel()]
|
|
1232
|
-
return False
|
|
1233
1254
|
return True
|
|
1234
1255
|
|
|
1235
1256
|
def run(self):
|
|
@@ -1244,6 +1265,7 @@ class PrerequisiteValidator(AmdTool):
|
|
|
1244
1265
|
self.capture_logind,
|
|
1245
1266
|
self.capture_pci_acpi,
|
|
1246
1267
|
self.capture_edid,
|
|
1268
|
+
self.capture_nvidia,
|
|
1247
1269
|
]
|
|
1248
1270
|
checks = []
|
|
1249
1271
|
|
|
@@ -293,18 +293,20 @@ def parse_args():
|
|
|
293
293
|
action="store_true",
|
|
294
294
|
help="Enable tool debug logging",
|
|
295
295
|
)
|
|
296
|
-
|
|
296
|
+
parser.add_argument(
|
|
297
|
+
"--version", action="store_true", help="Show version information"
|
|
298
|
+
)
|
|
297
299
|
if len(sys.argv) == 1:
|
|
298
300
|
parser.print_help(sys.stderr)
|
|
299
301
|
sys.exit(1)
|
|
300
302
|
return parser.parse_args()
|
|
301
303
|
|
|
302
304
|
|
|
303
|
-
def main() -> None|int:
|
|
305
|
+
def main() -> None | int:
|
|
304
306
|
"""Main function"""
|
|
305
307
|
args = parse_args()
|
|
306
308
|
ret = False
|
|
307
|
-
if args.
|
|
309
|
+
if args.version:
|
|
308
310
|
print(version())
|
|
309
311
|
return
|
|
310
312
|
elif args.command == "triage":
|
|
@@ -385,7 +385,9 @@ def parse_args():
|
|
|
385
385
|
help="Enable tool debug logging",
|
|
386
386
|
)
|
|
387
387
|
|
|
388
|
-
|
|
388
|
+
parser.add_argument(
|
|
389
|
+
"--version", action="store_true", help="Show version information"
|
|
390
|
+
)
|
|
389
391
|
|
|
390
392
|
if len(sys.argv) == 1:
|
|
391
393
|
parser.print_help(sys.stderr)
|
|
@@ -394,7 +396,7 @@ def parse_args():
|
|
|
394
396
|
return parser.parse_args()
|
|
395
397
|
|
|
396
398
|
|
|
397
|
-
def main() -> None|int:
|
|
399
|
+
def main() -> None | int:
|
|
398
400
|
"""Main function"""
|
|
399
401
|
args = parse_args()
|
|
400
402
|
ret = False
|
|
@@ -427,7 +429,7 @@ def main() -> None|int:
|
|
|
427
429
|
args.logind,
|
|
428
430
|
args.bios_debug,
|
|
429
431
|
)
|
|
430
|
-
elif args.
|
|
432
|
+
elif args.version:
|
|
431
433
|
print(version())
|
|
432
434
|
return
|
|
433
435
|
else:
|
|
@@ -0,0 +1,291 @@
|
|
|
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.is_root", return_value=False)
|
|
203
|
+
@mock.patch("amd_debug.ttm.print_color")
|
|
204
|
+
def test_set_not_root(self, mock_print, _mock_is_root):
|
|
205
|
+
"""Test set() when not root"""
|
|
206
|
+
result = self.tool.set(2)
|
|
207
|
+
mock_print.assert_called_with("Root privileges required", "❌")
|
|
208
|
+
self.assertFalse(result)
|
|
209
|
+
|
|
210
|
+
@mock.patch("amd_debug.ttm.is_root", return_value=True)
|
|
211
|
+
@mock.patch("amd_debug.ttm.get_system_mem", return_value=8.0)
|
|
212
|
+
@mock.patch("amd_debug.ttm.print_color")
|
|
213
|
+
def test_set_gb_greater_than_total(self, mock_print, _mock_mem, _mock_is_root):
|
|
214
|
+
"""Test set() when gb_value > total system memory"""
|
|
215
|
+
result = self.tool.set(16)
|
|
216
|
+
mock_print.assert_any_call(
|
|
217
|
+
"16.00 GB is greater than total system memory (8.00 GB)", "❌"
|
|
218
|
+
)
|
|
219
|
+
self.assertFalse(result)
|
|
220
|
+
|
|
221
|
+
@mock.patch("amd_debug.ttm.is_root", return_value=True)
|
|
222
|
+
@mock.patch("amd_debug.ttm.get_system_mem", return_value=10.0)
|
|
223
|
+
@mock.patch("amd_debug.ttm.print_color")
|
|
224
|
+
@mock.patch("builtins.input", return_value="n")
|
|
225
|
+
def test_set_gb_exceeds_max_percentage_cancel(
|
|
226
|
+
self, _mock_input, mock_print, _mock_mem, mock_is_root
|
|
227
|
+
):
|
|
228
|
+
"""Test set() when gb_value exceeds max percentage and user cancels"""
|
|
229
|
+
result = self.tool.set(9.5)
|
|
230
|
+
self.assertFalse(result)
|
|
231
|
+
mock_print.assert_any_call("Operation cancelled.", "🚦")
|
|
232
|
+
|
|
233
|
+
@mock.patch("amd_debug.ttm.is_root", return_value=True)
|
|
234
|
+
@mock.patch("amd_debug.ttm.get_system_mem", return_value=10.0)
|
|
235
|
+
@mock.patch("amd_debug.ttm.gb_to_pages", return_value=20480)
|
|
236
|
+
@mock.patch("amd_debug.ttm.print_color")
|
|
237
|
+
@mock.patch("builtins.open", new_callable=mock.mock_open)
|
|
238
|
+
@mock.patch("builtins.input", return_value="y")
|
|
239
|
+
@mock.patch("amd_debug.ttm.maybe_reboot", return_value=True)
|
|
240
|
+
def test_set_success(
|
|
241
|
+
self,
|
|
242
|
+
_mock_reboot,
|
|
243
|
+
_mock_input,
|
|
244
|
+
mock_open,
|
|
245
|
+
mock_print,
|
|
246
|
+
_mock_gb_to_pages,
|
|
247
|
+
mock_mem,
|
|
248
|
+
mock_is_root,
|
|
249
|
+
):
|
|
250
|
+
"""Test set() success path"""
|
|
251
|
+
result = self.tool.set(5)
|
|
252
|
+
mock_open.assert_called_once_with(
|
|
253
|
+
"/etc/modprobe.d/ttm.conf", "w", encoding="utf-8"
|
|
254
|
+
)
|
|
255
|
+
mock_print.assert_any_call(
|
|
256
|
+
"Successfully set TTM pages limit to 20480 pages (5.00 GB)", "🐧"
|
|
257
|
+
)
|
|
258
|
+
self.assertTrue(result)
|
|
259
|
+
|
|
260
|
+
@mock.patch("os.path.exists", return_value=False)
|
|
261
|
+
@mock.patch("amd_debug.ttm.print_color")
|
|
262
|
+
def test_clear_file_not_exists(self, mock_print, _mock_exists):
|
|
263
|
+
"""Test clear() when config file does not exist"""
|
|
264
|
+
result = self.tool.clear()
|
|
265
|
+
mock_print.assert_called_with("/etc/modprobe.d/ttm.conf doesn't exist", "❌")
|
|
266
|
+
self.assertFalse(result)
|
|
267
|
+
|
|
268
|
+
@mock.patch("os.path.exists", return_value=True)
|
|
269
|
+
@mock.patch("amd_debug.ttm.is_root", return_value=False)
|
|
270
|
+
@mock.patch("amd_debug.ttm.print_color")
|
|
271
|
+
def test_clear_not_root(self, mock_print, _mock_is_root, _mock_exists):
|
|
272
|
+
"""Test clear() when not root"""
|
|
273
|
+
result = self.tool.clear()
|
|
274
|
+
mock_print.assert_called_with("Root privileges required", "❌")
|
|
275
|
+
self.assertFalse(result)
|
|
276
|
+
|
|
277
|
+
@mock.patch("os.path.exists", return_value=True)
|
|
278
|
+
@mock.patch("amd_debug.ttm.is_root", return_value=True)
|
|
279
|
+
@mock.patch("os.remove")
|
|
280
|
+
@mock.patch("amd_debug.ttm.print_color")
|
|
281
|
+
@mock.patch("amd_debug.ttm.maybe_reboot", return_value=True)
|
|
282
|
+
def test_clear_success(
|
|
283
|
+
self, _mock_reboot, mock_print, mock_remove, _mock_is_root, mock_exists
|
|
284
|
+
):
|
|
285
|
+
"""Test clear() success path"""
|
|
286
|
+
result = self.tool.clear()
|
|
287
|
+
mock_remove.assert_called_once_with("/etc/modprobe.d/ttm.conf")
|
|
288
|
+
mock_print.assert_any_call(
|
|
289
|
+
"Configuration /etc/modprobe.d/ttm.conf removed", "🐧"
|
|
290
|
+
)
|
|
291
|
+
self.assertTrue(result)
|