返回 last30days-skill
test_health.py
根目录 / tests / test_health.py
1 """Tests for scripts/lib/health.py and pipeline degradation preservation."""
2
3 import subprocess
4 from unittest import mock
5
6 from lib import health, pipeline
7
8
9 class TestProbeCommand:
10 def test_missing_when_not_on_path(self):
11 result = health.probe_command(["definitely-not-a-real-binary-xyz"])
12 assert result.state == health.MISSING
13 assert not result.usable
14
15 def test_ok_on_exit_zero(self):
16 result = health.probe_command(["true"])
17 assert result.state == health.OK
18 assert result.ok
19
20 def test_error_on_nonzero_exit(self):
21 result = health.probe_command(["false"])
22 assert result.state == health.ERROR
23 assert not result.ok
24
25 def test_timeout(self):
26 result = health.probe_command(["sleep", "5"], timeout=0.1)
27 assert result.state == health.TIMEOUT
28
29 def test_broken_when_exec_raises(self):
30 # On PATH (which returns a path) but exec raises -> broken, not missing.
31 with mock.patch.object(health.shutil, "which", return_value="/usr/bin/x"), \
32 mock.patch.object(health.subprocess, "run", side_effect=OSError("exec format error")):
33 result = health.probe_command(["x"])
34 assert result.state == health.BROKEN
35
36 def test_broken_on_exit_127(self):
37 fake = subprocess.CompletedProcess(args=["x"], returncode=127, stdout="", stderr="not found")
38 with mock.patch.object(health.shutil, "which", return_value="/usr/bin/x"), \
39 mock.patch.object(health.subprocess, "run", return_value=fake):
40 result = health.probe_command(["x"])
41 assert result.state == health.BROKEN
42
43
44 class _FakeCandidate:
45 def __init__(self, sources):
46 self.sources = sources
47
48
49 def _candidates(n=6):
50 return [_FakeCandidate(["reddit"]) for _ in range(n)]
51
52
53 class TestDegradationWarnings:
54 """Partial failures survive as a distinct 'degraded' warning."""
55
56 def test_degraded_surfaced_distinctly_from_failed(self):
57 warnings = pipeline._warnings(
58 items_by_source={"reddit": [object()], "github": [object()]},
59 candidates=_candidates(),
60 errors_by_source={"x": "hard failure"},
61 degraded_by_source={"reddit": "429 on one subquery"},
62 )
63 joined = " | ".join(warnings)
64 assert "Some sources failed: x" in joined
65 assert "degraded" in joined.lower()
66 assert "reddit" in joined
67
68 def test_no_degraded_warning_when_none(self):
69 warnings = pipeline._warnings(
70 items_by_source={"reddit": [object()]},
71 candidates=_candidates(),
72 errors_by_source={},
73 degraded_by_source={},
74 )
75 assert not any("degraded" in w.lower() for w in warnings)
76
76 lines PYTHON