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.
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.assertEqual(args.action, "version")
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.assertTrue(result)
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.assertTrue(result)
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="version")
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.assertTrue(result)
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(action=None)
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="2023-02-01",
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.prerequisites.SleepDatabase")
459
- @patch("amd_debug.validator.SleepDatabase")
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
- _mock_sleep_db,
463
- _mock_sleep_db_prerequisite,
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
- self.assertFalse(result)
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.assert_called_once_with(True)
537
- mock_prerequisite_instance.run.assert_called_once()
538
- mock_prerequisite_instance.report.assert_called_once()
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
- display_report_file("report.html", "html")
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
- ["sudo", "-E", "-u", "testuser", "xdg-open", "report.html"]
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)