amd-debug-tools 0.2.4__py3-none-any.whl → 0.2.6__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.

Potentially problematic release.


This version of amd-debug-tools might be problematic. Click here for more details.

test_prerequisites.py CHANGED
@@ -143,6 +143,16 @@ class TestPrerequisiteValidator(unittest.TestCase):
143
143
  result = self.validator.check_port_pm_override()
144
144
  self.assertTrue(result)
145
145
 
146
+ @patch("amd_debug.prerequisites.version.parse")
147
+ def test_check_port_pm_override_smu_version_missing(self, mock_version_parse):
148
+ """Test check_port_pm_override with SMU version undefined"""
149
+ self.validator.cpu_family = 0x19
150
+ self.validator.cpu_model = 0x74
151
+ mock_version_parse.side_effect = lambda v: v if isinstance(v, str) else None
152
+ self.validator.smu_version = ""
153
+ result = self.validator.check_port_pm_override()
154
+ self.assertTrue(result)
155
+
146
156
  @patch("amd_debug.prerequisites.version.parse")
147
157
  def test_check_port_pm_override_smu_version_too_low(self, mock_version_parse):
148
158
  """Test check_port_pm_override with SMU version < 76.18.0"""
@@ -185,15 +195,18 @@ class TestPrerequisiteValidator(unittest.TestCase):
185
195
  new_callable=unittest.mock.mock_open,
186
196
  read_data=b"\x00" * 45,
187
197
  )
188
- def test_check_iommu_no_dma_protection(self, _mock_open):
189
- """Test check_iommu when DMA protection is not enabled"""
198
+ @patch("amd_debug.prerequisites.os.path.exists", return_value=True)
199
+ def test_check_iommu_no_dma_protection_no_msft0201(self, _mock_open, _mock_exists):
200
+ """Test check_iommu when DMA protection is not enabled and no MSFT0201 in IVRS"""
190
201
  self.validator.cpu_family = 0x1A
191
202
  self.validator.cpu_model = 0x20
192
203
  iommu_device = MagicMock(sys_path="/sys/devices/iommu")
204
+ acpi_device = MagicMock(sys_path="/sys/devices/acpi/MSFT0201")
205
+ platform_device = MagicMock(sys_path="/sys/devices/platform/MSFT0201")
193
206
  self.mock_pyudev.list_devices.side_effect = [
194
207
  [iommu_device],
195
- [],
196
- [],
208
+ [acpi_device],
209
+ [platform_device],
197
210
  ]
198
211
  result = self.validator.check_iommu()
199
212
  self.assertFalse(result)
@@ -204,6 +217,27 @@ class TestPrerequisiteValidator(unittest.TestCase):
204
217
  "IOMMU is misconfigured: Pre-boot DMA protection not enabled", "❌"
205
218
  )
206
219
 
220
+ @patch(
221
+ "amd_debug.prerequisites.open",
222
+ new_callable=unittest.mock.mock_open,
223
+ read_data=b"\x00" * 45 + "MSFT0201".encode("utf-8"),
224
+ )
225
+ @patch("amd_debug.prerequisites.os.path.exists", return_value=True)
226
+ def test_check_iommu_no_dma_protection_BUT_msft0201(self, _mock_open, _mock_exists):
227
+ """Test check_iommu when DMA protection is not enabled BUT MSFT0201 is in IVRS"""
228
+ self.validator.cpu_family = 0x1A
229
+ self.validator.cpu_model = 0x20
230
+ iommu_device = MagicMock(sys_path="/sys/devices/iommu")
231
+ acpi_device = MagicMock(sys_path="/sys/devices/acpi/MSFT0201")
232
+ platform_device = MagicMock(sys_path="/sys/devices/platform/MSFT0201")
233
+ self.mock_pyudev.list_devices.side_effect = [
234
+ [iommu_device],
235
+ [acpi_device],
236
+ [platform_device],
237
+ ]
238
+ result = self.validator.check_iommu()
239
+ self.assertTrue(result)
240
+
207
241
  @patch(
208
242
  "amd_debug.prerequisites.open",
209
243
  new_callable=unittest.mock.mock_open,
@@ -292,7 +326,7 @@ class TestPrerequisiteValidator(unittest.TestCase):
292
326
  BIT(9) | 1
293
327
  ) # Kernel warnings ignored, other taint present
294
328
  result = self.validator.check_taint()
295
- self.assertFalse(result)
329
+ self.assertTrue(result)
296
330
  self.assertTrue(
297
331
  any(isinstance(f, TaintedKernel) for f in self.validator.failures)
298
332
  )
@@ -1925,3 +1959,79 @@ class TestPrerequisiteValidator(unittest.TestCase):
1925
1959
  result = self.validator.check_dpia_pg_dmcub()
1926
1960
  self.assertTrue(result)
1927
1961
  self.mock_db.record_prereq.assert_not_called()
1962
+
1963
+ @patch("amd_debug.prerequisites.os.path.exists")
1964
+ def test_capture_nvidia_version_file_missing(self, mock_exists):
1965
+ """Test capture_nvidia when /proc/driver/nvidia/version does not exist"""
1966
+ mock_exists.side_effect = lambda p: False if "version" in p else True
1967
+ result = self.validator.capture_nvidia()
1968
+ self.assertTrue(result)
1969
+ self.mock_db.record_debug_file.assert_not_called()
1970
+ self.mock_db.record_prereq.assert_not_called()
1971
+
1972
+ @patch("amd_debug.prerequisites.os.path.exists")
1973
+ def test_capture_nvidia_gpus_dir_missing(self, mock_exists):
1974
+ """Test capture_nvidia when /proc/driver/nvidia/gpus does not exist"""
1975
+
1976
+ def exists_side_effect(path):
1977
+ if "version" in path:
1978
+ return True
1979
+ if "gpus" in path:
1980
+ return False
1981
+ return True
1982
+
1983
+ mock_exists.side_effect = exists_side_effect
1984
+ result = self.validator.capture_nvidia()
1985
+ self.assertTrue(result)
1986
+ self.mock_db.record_debug_file.assert_called_once_with(
1987
+ "/proc/driver/nvidia/version"
1988
+ )
1989
+ self.mock_db.record_prereq.assert_not_called()
1990
+
1991
+ @patch("amd_debug.prerequisites.os.walk")
1992
+ @patch("amd_debug.prerequisites.os.path.exists")
1993
+ def test_capture_nvidia_success(self, mock_exists, mock_walk):
1994
+ """Test capture_nvidia when NVIDIA GPU files are present and readable"""
1995
+ mock_exists.side_effect = lambda p: True
1996
+ mock_walk.return_value = [
1997
+ ("/proc/driver/nvidia/gpus/0000:01:00.0", [], ["info", "power"])
1998
+ ]
1999
+ result = self.validator.capture_nvidia()
2000
+ self.assertTrue(result)
2001
+ self.mock_db.record_debug_file.assert_any_call("/proc/driver/nvidia/version")
2002
+ self.mock_db.record_debug.assert_any_call("NVIDIA info")
2003
+ self.mock_db.record_debug_file.assert_any_call(
2004
+ "/proc/driver/nvidia/gpus/0000:01:00.0/info"
2005
+ )
2006
+ self.mock_db.record_debug.assert_any_call("NVIDIA power")
2007
+ self.mock_db.record_debug_file.assert_any_call(
2008
+ "/proc/driver/nvidia/gpus/0000:01:00.0/power"
2009
+ )
2010
+
2011
+ @patch("amd_debug.prerequisites.os.walk")
2012
+ @patch("amd_debug.prerequisites.os.path.exists")
2013
+ def test_capture_nvidia_permission_error_on_version(self, mock_exists, mock_walk):
2014
+ """Test capture_nvidia when PermissionError occurs reading version file"""
2015
+ mock_exists.side_effect = lambda p: True if "version" in p else False
2016
+ self.mock_db.record_debug_file.side_effect = PermissionError
2017
+ result = self.validator.capture_nvidia()
2018
+ self.assertTrue(result)
2019
+ self.mock_db.record_prereq.assert_called_with(
2020
+ "NVIDIA GPU version not readable", "👀"
2021
+ )
2022
+
2023
+ @patch("amd_debug.prerequisites.os.walk")
2024
+ @patch("amd_debug.prerequisites.os.path.exists")
2025
+ def test_capture_nvidia_permission_error_on_gpu_file(self, mock_exists, mock_walk):
2026
+ """Test capture_nvidia when PermissionError occurs reading a GPU file"""
2027
+ mock_exists.side_effect = lambda p: True
2028
+ mock_walk.return_value = [
2029
+ ("/proc/driver/nvidia/gpus/0000:01:00.0", [], ["info"])
2030
+ ]
2031
+ self.mock_db.record_debug_file.side_effect = [None, PermissionError]
2032
+ result = self.validator.capture_nvidia()
2033
+ self.assertTrue(result)
2034
+ self.mock_db.record_debug.assert_any_call("NVIDIA info")
2035
+ self.mock_db.record_prereq.assert_called_with(
2036
+ "NVIDIA GPU {f} not readable", "👀"
2037
+ )
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):
@@ -214,7 +214,7 @@ class TestMainFunction(unittest.TestCase):
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()
@@ -226,7 +226,9 @@ class TestMainFunction(unittest.TestCase):
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")
test_validator.py CHANGED
@@ -71,7 +71,8 @@ class TestValidator(unittest.TestCase):
71
71
  logging.basicConfig(filename="/dev/null", level=logging.DEBUG)
72
72
 
73
73
  @patch("amd_debug.validator.SleepDatabase")
74
- def setUp(self, _db_mock):
74
+ @patch("subprocess.run")
75
+ def setUp(self, _db_mock, _mock_run):
75
76
  """Set up a mock context for testing"""
76
77
  self.validator = SleepValidator(tool_debug=True, bios_debug=False)
77
78
 
@@ -830,3 +831,64 @@ class TestValidator(unittest.TestCase):
830
831
  )
831
832
  mock_os_write.assert_called_once_with(3, b"mem")
832
833
  mock_os_close.assert_called_once_with(3)
834
+
835
+ @patch("os.path.exists")
836
+ @patch("os.open")
837
+ @patch("os.write")
838
+ @patch("os.close")
839
+ def test_toggle_nvidia_file_not_exists(
840
+ self, mock_close, mock_write, mock_open, mock_exists
841
+ ):
842
+ """Test toggle_nvidia returns True if NVIDIA suspend file does not exist"""
843
+ mock_exists.return_value = False
844
+ result = self.validator.toggle_nvidia(b"suspend")
845
+ self.assertTrue(result)
846
+ mock_open.assert_not_called()
847
+ mock_write.assert_not_called()
848
+ mock_close.assert_not_called()
849
+
850
+ @patch("os.path.exists")
851
+ @patch("os.open")
852
+ @patch("os.write")
853
+ @patch("os.close")
854
+ def test_toggle_nvidia_success(
855
+ self, mock_close, mock_write, mock_open, mock_exists
856
+ ):
857
+ """Test toggle_nvidia writes value and returns True on success"""
858
+ mock_exists.return_value = True
859
+ mock_open.return_value = 42
860
+ mock_write.return_value = None
861
+ with patch.object(self.validator.db, "record_debug") as mock_record_debug:
862
+ result = self.validator.toggle_nvidia(b"suspend")
863
+ self.assertTrue(result)
864
+ mock_open.assert_called_once_with(
865
+ "/proc/driver/nvidia/suspend", os.O_WRONLY | os.O_SYNC
866
+ )
867
+ mock_write.assert_called_once_with(42, b"suspend")
868
+ mock_close.assert_called_once_with(42)
869
+ mock_record_debug.assert_called_once_with(
870
+ "Wrote b'suspend' to NVIDIA driver"
871
+ )
872
+
873
+ @patch("os.path.exists")
874
+ @patch("os.open")
875
+ @patch("os.write")
876
+ @patch("os.close")
877
+ def test_toggle_nvidia_oserror(
878
+ self, mock_close, mock_write, mock_open, mock_exists
879
+ ):
880
+ """Test toggle_nvidia handles OSError and returns False"""
881
+ mock_exists.return_value = True
882
+ mock_open.return_value = 99
883
+ mock_write.side_effect = OSError("write error")
884
+ with patch.object(
885
+ self.validator.db, "record_cycle_data"
886
+ ) as mock_record_cycle_data:
887
+ result = self.validator.toggle_nvidia(b"resume")
888
+ self.assertFalse(result)
889
+ mock_open.assert_called_once_with(
890
+ "/proc/driver/nvidia/suspend", os.O_WRONLY | os.O_SYNC
891
+ )
892
+ mock_write.assert_called_once_with(99, b"resume")
893
+ mock_close.assert_called_once_with(99)
894
+ mock_record_cycle_data.assert_called_once()