mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-11 00:47:01 +01:00
_detect_gpu matched every _VENDOR_KW key against the whole lspci line. Every display line contains "VGA compATIble controller", so the "ati" key fired unconditionally and "intel" was never reached: Intel iGPUs were reported as AMD, switching on the GPU-accelerated terminal and the AMD-only Electron flags. Match against hw.gpu_model — the description after the last colon, which the line above already extracts — instead of the whole line. The strict=True xfail guarding this is removed and becomes a normal passing regression test, and the two parametrised cases that characterised the bug (Intel -> AMD, unknown vendor -> AMD) are corrected to Intel and Unknown. Added this machine's real second display device, "[AMD/ATI] Raphael", which must still resolve to AMD. Verified by real run: --dry-run still reports the RTX 3090 as NVIDIA with 24576 MB VRAM and still proposes 18 changes, matching the pre-fix baseline. Full gate: 1984 passed, 100% coverage. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011w2Pj4Ek3ZNMQVYcFHgXDY
234 lines
7.3 KiB
Python
234 lines
7.3 KiB
Python
"""Tests for GPU and root-disk detection, and the aggregate probe.
|
|
|
|
Both probes shell out, so ``subprocess.run`` is patched at the boundary; the
|
|
sysfs reads in ``_detect_disk`` are redirected by patching the module-level
|
|
``Path`` name. Nothing here touches the machine's real hardware.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import subprocess
|
|
from typing import TYPE_CHECKING
|
|
|
|
import pytest
|
|
|
|
from python_pkg.vscode_optimizer import _hardware as opt
|
|
from python_pkg.vscode_optimizer._types import _Hw
|
|
from python_pkg.vscode_optimizer.tests.conftest import fake_run as _fake_run
|
|
|
|
if TYPE_CHECKING:
|
|
from collections.abc import Callable
|
|
from pathlib import Path
|
|
|
|
|
|
# --------------------------------------------------------------------------- #
|
|
# _detect_gpu
|
|
# --------------------------------------------------------------------------- #
|
|
_NVIDIA_LINE = (
|
|
"01:00.0 VGA compatible controller: NVIDIA Corporation GA102 [GeForce RTX 3090]"
|
|
)
|
|
|
|
|
|
def test_detect_gpu_reads_nvidia_vram(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
"""An NVIDIA card triggers a second probe for its VRAM."""
|
|
monkeypatch.setattr(
|
|
subprocess,
|
|
"run",
|
|
_fake_run({"lspci": _NVIDIA_LINE, "nvidia-smi": "24576\n"}),
|
|
)
|
|
hw = _Hw()
|
|
|
|
opt._detect_gpu(hw)
|
|
|
|
assert hw.gpu_vendor == "NVIDIA"
|
|
assert hw.gpu_model == "NVIDIA Corporation GA102 [GeForce RTX 3090]"
|
|
assert hw.gpu_vram_mb == 24576
|
|
|
|
|
|
def test_detect_gpu_tolerates_nvidia_smi_being_absent(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
"""Without nvidia-smi the vendor is still known; VRAM stays unset."""
|
|
monkeypatch.setattr(subprocess, "run", _fake_run({"lspci": _NVIDIA_LINE}))
|
|
hw = _Hw()
|
|
|
|
opt._detect_gpu(hw)
|
|
|
|
assert hw.gpu_vendor == "NVIDIA"
|
|
assert hw.gpu_vram_mb == 0
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("line", "vendor"),
|
|
[
|
|
("03:00.0 VGA compatible controller: AMD Radeon RX 7900", "AMD"),
|
|
("03:00.0 VGA compatible controller: ATI Technologies Inc", "AMD"),
|
|
("00:02.0 VGA compatible controller: Intel UHD Graphics 630", "Intel"),
|
|
("04:00.0 VGA compatible controller: Some Unlisted Vendor", "Unknown"),
|
|
("04:00.0 3D controller: Some Unlisted Vendor", "Unknown"),
|
|
# This machine's second display device: the description carries both
|
|
# "AMD" and "ATI", and either key gives the same answer.
|
|
(
|
|
"0d:00.0 VGA compatible controller: "
|
|
"Advanced Micro Devices, Inc. [AMD/ATI] Raphael",
|
|
"AMD",
|
|
),
|
|
],
|
|
)
|
|
def test_detect_gpu_maps_each_vendor_keyword(
|
|
monkeypatch: pytest.MonkeyPatch, line: str, vendor: str
|
|
) -> None:
|
|
"""Vendor keywords map to display names; 3D controllers count as GPUs."""
|
|
monkeypatch.setattr(subprocess, "run", _fake_run({"lspci": line}))
|
|
hw = _Hw()
|
|
|
|
opt._detect_gpu(hw)
|
|
|
|
assert hw.gpu_vendor == vendor
|
|
|
|
|
|
def test_detect_gpu_recognises_an_intel_igpu(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
"""An Intel iGPU is detected as Intel, not as AMD.
|
|
|
|
Regression guard: matching the whole lspci line let "ati" — a substring of
|
|
"VGA compATIble controller" — claim every display device before "intel"
|
|
was tried, so Intel iGPUs enabled the AMD-only Electron flags.
|
|
"""
|
|
line = "00:02.0 VGA compatible controller: Intel UHD Graphics 630"
|
|
monkeypatch.setattr(subprocess, "run", _fake_run({"lspci": line}))
|
|
hw = _Hw()
|
|
|
|
opt._detect_gpu(hw)
|
|
|
|
assert hw.gpu_vendor == "Intel"
|
|
|
|
|
|
def test_detect_gpu_leaves_defaults_when_lspci_lists_no_display_device(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
"""A listing with no VGA/3D line exhausts the loop without a match."""
|
|
monkeypatch.setattr(
|
|
subprocess, "run", _fake_run({"lspci": "00:1f.3 Audio device: Intel\n"})
|
|
)
|
|
hw = _Hw()
|
|
|
|
opt._detect_gpu(hw)
|
|
|
|
assert hw.gpu_vendor == "Unknown"
|
|
assert hw.gpu_model == "Unknown"
|
|
|
|
|
|
def test_detect_gpu_skips_non_display_devices(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
"""Only VGA/3D lines are considered; the first match wins."""
|
|
listing = "00:1f.3 Audio device: Intel\n" + _NVIDIA_LINE + "\n05:00.0 VGA: AMD\n"
|
|
monkeypatch.setattr(
|
|
subprocess, "run", _fake_run({"lspci": listing, "nvidia-smi": "24576"})
|
|
)
|
|
hw = _Hw()
|
|
|
|
opt._detect_gpu(hw)
|
|
|
|
assert hw.gpu_vendor == "NVIDIA"
|
|
|
|
|
|
# --------------------------------------------------------------------------- #
|
|
# _detect_disk
|
|
# --------------------------------------------------------------------------- #
|
|
def _disk_paths(
|
|
monkeypatch: pytest.MonkeyPatch, tmp_path: Path, base: str, rotational: str | None
|
|
) -> None:
|
|
"""Redirect /sys/block lookups into tmp_path, keeping /dev names real."""
|
|
if rotational is not None:
|
|
queue = tmp_path / "sys" / "block" / base / "queue"
|
|
queue.mkdir(parents=True)
|
|
(queue / "rotational").write_text(rotational)
|
|
real_path = opt.Path
|
|
monkeypatch.setattr(
|
|
opt,
|
|
"Path",
|
|
lambda p: (
|
|
tmp_path / str(p).lstrip("/")
|
|
if str(p).startswith("/sys/")
|
|
else real_path(p)
|
|
),
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("device", "base", "rotational", "expected"),
|
|
[
|
|
("/dev/nvme0n1p2", "nvme0n1", "0", "nvme"),
|
|
("/dev/sda1", "sda", "0", "ssd"),
|
|
("/dev/sdb2", "sdb", "1", "hdd"),
|
|
],
|
|
)
|
|
def test_detect_disk_classifies_the_root_device(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
tmp_path: Path,
|
|
device: str,
|
|
base: str,
|
|
rotational: str,
|
|
expected: str,
|
|
) -> None:
|
|
"""Partition suffixes are stripped, then rotational/nvme decide the type."""
|
|
monkeypatch.setattr(subprocess, "run", _fake_run({"findmnt": device}))
|
|
_disk_paths(monkeypatch, tmp_path, base, rotational)
|
|
hw = _Hw()
|
|
|
|
opt._detect_disk(hw)
|
|
|
|
assert hw.disk_type == expected
|
|
|
|
|
|
def test_detect_disk_gives_up_when_findmnt_says_nothing(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
"""No root device means the type stays unknown."""
|
|
monkeypatch.setattr(subprocess, "run", _fake_run({}))
|
|
hw = _Hw()
|
|
|
|
opt._detect_disk(hw)
|
|
|
|
assert hw.disk_type == "unknown"
|
|
|
|
|
|
def test_detect_disk_gives_up_without_a_rotational_flag(
|
|
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
|
|
) -> None:
|
|
"""A device with no sysfs queue entry (e.g. dm-crypt) stays unknown."""
|
|
monkeypatch.setattr(subprocess, "run", _fake_run({"findmnt": "/dev/mapper/root"}))
|
|
_disk_paths(monkeypatch, tmp_path, "mapper/root", None)
|
|
hw = _Hw()
|
|
|
|
opt._detect_disk(hw)
|
|
|
|
assert hw.disk_type == "unknown"
|
|
|
|
|
|
# --------------------------------------------------------------------------- #
|
|
# _detect_hardware
|
|
# --------------------------------------------------------------------------- #
|
|
def test_detect_hardware_runs_every_probe(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
"""The aggregate calls all four detectors against one _Hw."""
|
|
called: list[str] = []
|
|
|
|
def _recorder(name: str) -> Callable[[_Hw], None]:
|
|
"""Build a probe double that records the name it stands in for."""
|
|
|
|
def _probe(_hw: _Hw) -> None:
|
|
called.append(name)
|
|
|
|
return _probe
|
|
|
|
for probe_name in ("_detect_cpu", "_detect_ram", "_detect_gpu", "_detect_disk"):
|
|
monkeypatch.setattr(opt, probe_name, _recorder(probe_name))
|
|
|
|
result = opt._detect_hardware()
|
|
|
|
assert isinstance(result, _Hw)
|
|
assert called == ["_detect_cpu", "_detect_ram", "_detect_gpu", "_detect_disk"]
|