04e8d72bce
Inventory shows configured RAM speed + the rated speed when lower
('4800 MT/s (rated 5600)'); System Health flags it with the fix (enable
XMP/EXPO in BIOS). With the profile off dmidecode only reports the JEDEC base,
so the rated speed comes from dmidecode's max OR the part number, matched against
known DDR5 speed grades to avoid false positives. inventory.module_speed() shared
by both; needs dmidecode (root/launch elevation). +tests (incl. the user's
CMK..5600 kit → (4800, 5600)). Completes the underperforming-hardware trio with
PCIe gen + refresh rate.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
77 lines
3.0 KiB
Python
77 lines
3.0 KiB
Python
"""Tests for the M5 system inventory (render + dict round-trip; collect on real system)."""
|
|
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
from rigdoctor.core import inventory
|
|
from rigdoctor.core.inventory import Section
|
|
|
|
|
|
class InventoryTests(unittest.TestCase):
|
|
def test_collect_returns_sections(self):
|
|
sections = inventory.collect()
|
|
self.assertTrue(sections)
|
|
titles = {s.title for s in sections}
|
|
self.assertIn("System", titles)
|
|
self.assertIn("CPU", titles)
|
|
|
|
def test_dict_round_trip(self):
|
|
sections = [Section("System", [("Kernel", "7.0.0"), ("Distro", "Ubuntu")])]
|
|
restored = inventory.from_dict(inventory.to_dict(sections))
|
|
self.assertEqual(restored[0].title, "System")
|
|
self.assertEqual(restored[0].items, [("Kernel", "7.0.0"), ("Distro", "Ubuntu")])
|
|
|
|
def test_render_markdown(self):
|
|
md = inventory.render_markdown([Section("CPU", [("Model", "Test CPU")])])
|
|
self.assertIn("## CPU", md)
|
|
self.assertIn("- **Model:** Test CPU", md)
|
|
|
|
|
|
class PcieLinkTests(unittest.TestCase):
|
|
def test_gen_mapping(self):
|
|
self.assertEqual(inventory._gen("16.0 GT/s PCIe"), 4)
|
|
self.assertEqual(inventory._gen("8.0 GT/s PCIe"), 3)
|
|
self.assertIsNone(inventory._gen(""))
|
|
|
|
def _fake_dev(self, cur_s, cur_w, max_s, max_w) -> Path:
|
|
d = Path(tempfile.mkdtemp())
|
|
(d / "current_link_speed").write_text(cur_s)
|
|
(d / "current_link_width").write_text(cur_w)
|
|
(d / "max_link_speed").write_text(max_s)
|
|
(d / "max_link_width").write_text(max_w)
|
|
return d
|
|
|
|
def test_link_at_full_speed(self):
|
|
dev = self._fake_dev("16.0 GT/s PCIe", "4", "16.0 GT/s PCIe", "4")
|
|
self.assertEqual(inventory._link_desc(dev), "PCIe Gen4 x4")
|
|
|
|
def test_link_downtrained_flags_capability(self):
|
|
dev = self._fake_dev("8.0 GT/s PCIe", "4", "16.0 GT/s PCIe", "4")
|
|
self.assertEqual(inventory._link_desc(dev), "PCIe Gen3 x4 (capable of Gen4 x4)")
|
|
|
|
def test_non_nvme_has_no_link(self):
|
|
self.assertEqual(inventory._nvme_link("sda"), "")
|
|
|
|
|
|
class MemorySpeedTests(unittest.TestCase):
|
|
def test_rated_speed_from_part_number(self):
|
|
self.assertEqual(inventory._rated_from_part("CMK32GX5M2B5600Z36"), 5600)
|
|
self.assertEqual(inventory._rated_from_part("F5-6000J3038F16G"), 6000)
|
|
self.assertIsNone(inventory._rated_from_part("NoSpeedHere"))
|
|
|
|
def test_detects_unapplied_expo(self):
|
|
# XMP/EXPO off: dmidecode only sees JEDEC 4800; the 5600 is in the part number.
|
|
m = {"Configured Memory Speed": "4800 MT/s", "Speed": "4800 MT/s",
|
|
"Part Number": "CMK32GX5M2B5600Z36"}
|
|
self.assertEqual(inventory.module_speed(m), (4800, 5600))
|
|
|
|
def test_at_rated_speed(self):
|
|
m = {"Configured Memory Speed": "5600 MT/s", "Speed": "5600 MT/s",
|
|
"Part Number": "CMK32GX5M2B5600Z36"}
|
|
self.assertEqual(inventory.module_speed(m), (5600, 5600))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|