Option C Tools
Loading...
Searching...
No Matches
test_integration.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# tests/tests_health/test_integration.py
4
5"""
6Integration tests for the health dashboard.
7
8Purpose
9-------
10Verify end-to-end health report generation with complete projects.
11
12Responsibilities
13----------------
14- Test terminal output format.
15- Test JSON output format and schema.
16- Test verbose output mode.
17- Test health report with various project states.
18
19Diagnostics
20-----------
21Domain: TESTS.HEALTH
22Levels:
23 L2 — test lifecycle
24 L3 — full report generation
25 L4 — output validation and schema verification
26
27Contracts
28---------
29- JSON output is valid JSON with correct schema.
30- Terminal output includes all sections.
31- Verbose mode shows per-file breakdown.
32"""
33
34import json
35import pytest
36from pathlib import Path
37
38from oct.health.oct_health import run_health, check_compat_health, check_fixable_health
39from oct.linter.oct_lint import LinterContext
40from tests.tests_health.conftest import make_compliant_file, make_func_pattern_violation_file
41
42
43def test_health_terminal_output(temp_project_root: Path, capsys):
44 """Test that terminal output includes all sections."""
45 (temp_project_root / "good.py").write_text(make_compliant_file("good.py"), encoding="utf-8")
46
47 run_health(temp_project_root)
48
49 captured = capsys.readouterr()
50 output = captured.out
51
52 assert "OCT HEALTH REPORT" in output
53 assert "Lint Compliance:" in output
54 assert "Fixable Violations:" in output
55 assert "Documentation:" in output
56 assert "Tests:" in output
57 assert "oc_diagnostics:" in output
58
59
60def test_health_json_output(temp_project_root: Path, capsys):
61 """Test that JSON output is valid and has correct schema."""
62 (temp_project_root / "good.py").write_text(make_compliant_file("good.py"), encoding="utf-8")
63
64 run_health(temp_project_root, json_mode=True)
65
66 captured = capsys.readouterr()
67 data = json.loads(captured.out)
68
69 assert "project" in data
70 assert "oct_version" in data
71 assert "timestamp" in data
72 assert "lint" in data
73 assert "fixable" in data
74 assert "docs" in data
75 assert "tests" in data
76 assert "compat" in data
77
78
79def test_health_json_lint_schema(temp_project_root: Path, capsys):
80 """Test that JSON lint section has correct schema."""
81 (temp_project_root / "good.py").write_text(make_compliant_file("good.py"), encoding="utf-8")
82
83 run_health(temp_project_root, json_mode=True)
84
85 captured = capsys.readouterr()
86 data = json.loads(captured.out)
87
88 lint = data["lint"]
89 assert "total_files" in lint
90 assert "fully_compliant" in lint
91 assert "compliance_pct" in lint
92 assert "checks" in lint
93
94
95def test_health_json_fixable_schema(temp_project_root: Path, capsys):
96 """Test that JSON fixable section has correct schema."""
97 (temp_project_root / "good.py").write_text(make_compliant_file("good.py"), encoding="utf-8")
98
99 run_health(temp_project_root, json_mode=True)
100
101 captured = capsys.readouterr()
102 data = json.loads(captured.out)
103
104 fixable = data["fixable"]
105 assert "total" in fixable
106 assert "header" in fixable
107 assert "docstring" in fixable
108 assert "dbg_import" in fixable
109 assert "func_pattern" in fixable
110
111
112def test_health_verbose_output(temp_project_root: Path, capsys):
113 """Test that verbose mode shows per-file breakdown."""
114 (temp_project_root / "good.py").write_text(make_compliant_file("good.py"), encoding="utf-8")
115
116 run_health(temp_project_root, verbose=True)
117
118 captured = capsys.readouterr()
119 output = captured.out
120
121 assert "OCT HEALTH REPORT" in output
122
123
124def test_health_empty_project(temp_project_root: Path, capsys):
125 """Test health report on empty project."""
126 run_health(temp_project_root, json_mode=True)
127
128 captured = capsys.readouterr()
129 data = json.loads(captured.out)
130
131 assert data["lint"]["total_files"] == 0
132 assert data["lint"]["compliance_pct"] == 0.0
133 assert data["fixable"]["total"] == 0
134
135
136def test_health_test_status_no_tests_dir(temp_project_root: Path, capsys):
137 """Test that missing tests/ directory is handled."""
138 import shutil
139 shutil.rmtree(temp_project_root / "tests")
140
141 run_health(temp_project_root, json_mode=True)
142
143 captured = capsys.readouterr()
144 data = json.loads(captured.out)
145
146 assert data["tests"]["status"] == "not_run"
147
148
150 """Test that compat check returns valid structure."""
151 result = check_compat_health()
152
153 assert "installed" in result
154 assert "version" in result
155 assert "compatible" in result
156 assert "message" in result
157 assert isinstance(result["installed"], bool)
158
159
160def test_health_diagnostics_dir_fallback(temp_project_root: Path, capsys):
161 """Test fallback to diagnostics/ directory."""
162 import shutil
163 shutil.rmtree(temp_project_root / "oc_diagnostics")
164 (temp_project_root / "diagnostics").mkdir()
165
166 run_health(temp_project_root, json_mode=True)
167
168 captured = capsys.readouterr()
169 data = json.loads(captured.out)
170
171 # Should still produce a valid report
172 assert "lint" in data
173 assert "docs" in data
174
175
176# ============================================================
177# OI-413: configurable test timeout
178# ============================================================
179
180def test_health_test_timeout_explicit_overrides_default(temp_project_root: Path, monkeypatch):
181 """Explicit test_timeout parameter is threaded through to check_test_health (OI-413)."""
182 from oct.health import oct_health
183
184 captured = {}
185
186 def fake_check(project_root, timeout=300, **_kwargs):
187 captured["timeout"] = timeout
188 return {
189 "status": "pass",
190 "exit_code": 0,
191 "summary": "0 passed",
192 "details": [],
193 "coverage_pct": None,
194 "coverage_threshold": None,
195 "coverage_blocking": False,
196 }
197
198 monkeypatch.setattr(oct_health, "check_test_health", fake_check)
199 run_health(temp_project_root, json_mode=True, test_timeout=37)
200 assert captured.get("timeout") == 37
201
202
203def test_health_test_timeout_from_octrc(temp_project_root: Path, monkeypatch):
204 """health.test_timeout in .octrc.json is honored when no explicit value (OI-413)."""
205 from oct.health import oct_health
206
207 (temp_project_root / ".octrc.json").write_text(
208 json.dumps({"health": {"test_timeout": 55}}), encoding="utf-8"
209 )
210 captured = {}
211
212 def fake_check(project_root, timeout=300, **_kwargs):
213 captured["timeout"] = timeout
214 return {
215 "status": "pass", "exit_code": 0,
216 "summary": "0 passed", "details": [],
217 "coverage_pct": None, "coverage_threshold": None,
218 "coverage_blocking": False,
219 }
220
221 monkeypatch.setattr(oct_health, "check_test_health", fake_check)
222 run_health(temp_project_root, json_mode=True)
223 assert captured.get("timeout") == 55
224
225
226def test_health_explicit_timeout_overrides_octrc(temp_project_root: Path, monkeypatch):
227 """Explicit test_timeout wins over .octrc.json health.test_timeout (OI-413)."""
228 from oct.health import oct_health
229
230 (temp_project_root / ".octrc.json").write_text(
231 json.dumps({"health": {"test_timeout": 55}}), encoding="utf-8"
232 )
233 captured = {}
234
235 def fake_check(project_root, timeout=300, **_kwargs):
236 captured["timeout"] = timeout
237 return {
238 "status": "pass", "exit_code": 0,
239 "summary": "0 passed", "details": [],
240 "coverage_pct": None, "coverage_threshold": None,
241 "coverage_blocking": False,
242 }
243
244 monkeypatch.setattr(oct_health, "check_test_health", fake_check)
245 run_health(temp_project_root, json_mode=True, test_timeout=99)
246 assert captured.get("timeout") == 99
247
248
249# ============================================================
250# Fixable violations verbose output
251# ============================================================
252
253def test_fixable_verbose_lists_violating_files(temp_project_root: Path, linter_ctx: LinterContext):
254 """Verbose fixable check must list files with func_pattern violations."""
255 (temp_project_root / "bad.py").write_text(
256 make_func_pattern_violation_file("bad.py"), encoding="utf-8",
257 )
258
259 result = check_fixable_health(
260 temp_project_root, linter_ctx, verbose=True,
261 )
262
263 assert result["func_pattern"] == 1
264 assert "files" in result
265 paths = [f["path"] for f in result["files"]]
266 assert any("bad.py" in p for p in paths)
267 # Verify the fix type is recorded
268 fixes = result["files"][0]["fixes"]
269 assert "func_pattern" in fixes
270
271
272def test_fixable_non_verbose_omits_files_key(temp_project_root: Path, linter_ctx: LinterContext):
273 """Non-verbose fixable check must not include a 'files' key (backward compat)."""
274 (temp_project_root / "bad.py").write_text(
275 make_func_pattern_violation_file("bad.py"), encoding="utf-8",
276 )
277
278 result = check_fixable_health(
279 temp_project_root, linter_ctx, verbose=False,
280 )
281
282 assert result["func_pattern"] == 1
283 assert "files" not in result
284
285
286def test_fixable_verbose_no_violations_empty_files(temp_project_root: Path, linter_ctx: LinterContext):
287 """Verbose fixable check with a compliant file must return empty files list."""
288 (temp_project_root / "good.py").write_text(
289 make_compliant_file("good.py"), encoding="utf-8",
290 )
291
292 result = check_fixable_health(
293 temp_project_root, linter_ctx, verbose=True,
294 )
295
296 assert result["total"] == 0
297 assert result["files"] == []
test_fixable_verbose_lists_violating_files(Path temp_project_root, LinterContext linter_ctx)
test_health_empty_project(Path temp_project_root, capsys)
test_health_test_status_no_tests_dir(Path temp_project_root, capsys)
test_fixable_non_verbose_omits_files_key(Path temp_project_root, LinterContext linter_ctx)
test_fixable_verbose_no_violations_empty_files(Path temp_project_root, LinterContext linter_ctx)
test_health_diagnostics_dir_fallback(Path temp_project_root, capsys)
test_health_json_output(Path temp_project_root, capsys)
test_health_test_timeout_explicit_overrides_default(Path temp_project_root, monkeypatch)
test_health_test_timeout_from_octrc(Path temp_project_root, monkeypatch)
test_health_json_lint_schema(Path temp_project_root, capsys)
test_health_json_fixable_schema(Path temp_project_root, capsys)
test_health_verbose_output(Path temp_project_root, capsys)
test_health_explicit_timeout_overrides_octrc(Path temp_project_root, monkeypatch)
test_health_terminal_output(Path temp_project_root, capsys)