5682878f22
The seed use case end to end, orchestrating M3 + M4 (ARCHITECTURE §7.1). - core/diagnostic.py: start(game) runs a focused, game-tagged capture into a dedicated diagnostic log (window-scoped report, separate from the always-on crash log); finish() stops it and combines the capture summary (M3) with the health findings (M4). Game recorded as a log event so it survives crash+reboot. - CLI: rigdoctor diagnose start --game/--appid | status | finish. - recorder/record run gained an optional --game tag; reccontrol passes it through. - Tests for game recovery + the finish() combination. GUI/tray "Run Diagnostic" button and auto start/stop (D12 wrapper) come next. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
62 lines
2.5 KiB
Python
62 lines
2.5 KiB
Python
"""Tests for the guided diagnostic orchestration (M3+M4 glue)."""
|
||
|
||
import tempfile
|
||
import time
|
||
import unittest
|
||
from pathlib import Path
|
||
from unittest import mock
|
||
|
||
from rigdoctor.core import diagnostic
|
||
from rigdoctor.core.crashlog import CrashLogWriter, summarize
|
||
from rigdoctor.core.health import Finding
|
||
from rigdoctor.core.sample import Reading, Sample
|
||
|
||
|
||
def _write_log(path: str, game: str) -> None:
|
||
w = CrashLogWriter(path)
|
||
w.write_event("session-start", "interval=1s")
|
||
w.write_event("game", game)
|
||
for temp in (60.0, 72.0, 81.0):
|
||
w.write_sample(Sample(ts=time.time(), readings=[Reading("gpu", "temp", temp, "°C", "")]))
|
||
w.write_event("gpu-lost", "nvidia-smi query timed out")
|
||
w.close()
|
||
|
||
|
||
class GameRecoveryTests(unittest.TestCase):
|
||
def test_game_recovered_from_log_event(self):
|
||
with tempfile.TemporaryDirectory() as d:
|
||
log = str(Path(d) / "capture.jsonl")
|
||
_write_log(log, "Path of Exile 2")
|
||
summary = summarize(log)
|
||
self.assertEqual(diagnostic._game_from_summary(summary), "Path of Exile 2")
|
||
|
||
def test_no_game_event_returns_none(self):
|
||
with tempfile.TemporaryDirectory() as d:
|
||
log = str(Path(d) / "capture.jsonl")
|
||
w = CrashLogWriter(log)
|
||
w.write_event("session-start")
|
||
w.close()
|
||
self.assertIsNone(diagnostic._game_from_summary(summarize(log)))
|
||
|
||
|
||
class FinishTests(unittest.TestCase):
|
||
def test_finish_combines_summary_and_findings(self):
|
||
with tempfile.TemporaryDirectory() as d:
|
||
log = Path(d) / "capture.jsonl"
|
||
_write_log(str(log), "Satisfactory")
|
||
fake = [Finding("warning", "GPU", "NVIDIA Xid 79 ×1", "fell off the bus")]
|
||
with mock.patch("rigdoctor.core.health.run_health_checks", return_value=fake), \
|
||
mock.patch.object(diagnostic.reccontrol, "stop_background", return_value=False), \
|
||
mock.patch.object(diagnostic.reccontrol, "running_pid", return_value=None):
|
||
result = diagnostic.finish(log_path=log)
|
||
self.assertEqual(result.game, "Satisfactory")
|
||
self.assertEqual(result.summary.samples, 3)
|
||
self.assertEqual(result.findings, fake)
|
||
# peak GPU temp captured in the window, GPU-lost event recorded
|
||
self.assertEqual(result.summary.maxima["gpu.temp"][0], 81.0)
|
||
self.assertTrue(any(kind == "gpu-lost" for _ts, kind, _d in result.summary.events))
|
||
|
||
|
||
if __name__ == "__main__":
|
||
unittest.main()
|