mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-20 00:38:38 +02:00
feat(system): log-health scanner + Add/Edit-Printer setup pre-flight
Adds a passive log-health check that complements the active Connection Diagnostic. Scans Bambuddy's recent app log against a curated allowlist catalog of known failure signatures (rejected access code, FTPS :990 timeout, FTPS TLS failure, flapping MQTT, unreachable camera, SQLite "database is locked" contention), dedupes and classifies each finding as layer8/environment/bug, and deep-links to the troubleshooting wiki. Sample log lines are sanitized before they leave the process. Exposed via GET /system/health and surfaced on two surfaces sharing one SystemHealthPanel component: a System Health section on the System page, and inline in the bug reporter when the form opens. The Add-Printer and Edit-Printer dialogs gained a setup-time pre-flight: saving runs the connection diagnostic and, on a failed check, warns with a "save anyway" escape hatch instead of silently saving a printer that will immediately show offline. Log read/parse/sanitize primitives extracted from routes/support.py into a shared services/log_reader.py (behaviour-preserving); affected support tests repointed accordingly. Tests: test_log_health.py (11), test_system_api.py (2 new), SystemHealthPanel + BugReportBubble + AddPrinterPreflight + EditPrinterPreflight (8 frontend). All strings translated across the 9 locales. Backend ruff clean, full unit suite green, frontend build + eslint clean, i18n parity green.
This commit is contained in:
@@ -308,3 +308,48 @@ class TestSystemHelperFunctions:
|
||||
|
||||
result = format_uptime(30) # 30 seconds
|
||||
assert result == "< 1m"
|
||||
|
||||
|
||||
class TestSystemHealthAPI:
|
||||
"""Integration tests for GET /api/v1/system/health (log-health scan)."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.integration
|
||||
async def test_health_clean_log(self, async_client: AsyncClient, tmp_path, monkeypatch):
|
||||
"""A log with no known issues returns an empty, healthy result."""
|
||||
from backend.app.core.config import settings
|
||||
|
||||
(tmp_path / "bambuddy.log").write_text(
|
||||
"2026-05-22 10:00:00,000 INFO [backend.app.main] Application startup complete\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
monkeypatch.setattr(settings, "log_dir", tmp_path)
|
||||
|
||||
response = await async_client.get("/api/v1/system/health")
|
||||
|
||||
assert response.status_code == 200
|
||||
result = response.json()
|
||||
assert result["log_available"] is True
|
||||
assert result["findings"] == []
|
||||
assert result["summary"]["total"] == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.integration
|
||||
async def test_health_detects_known_issue(self, async_client: AsyncClient, tmp_path, monkeypatch):
|
||||
"""A known signature in the log surfaces as a finding."""
|
||||
from backend.app.core.config import settings
|
||||
|
||||
(tmp_path / "bambuddy.log").write_text(
|
||||
"2026-05-22 10:00:00,000 WARNING [backend.app.services.bambu_ftp] "
|
||||
"FTP connection permission error to 10.0.0.9: 530\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
monkeypatch.setattr(settings, "log_dir", tmp_path)
|
||||
|
||||
response = await async_client.get("/api/v1/system/health")
|
||||
|
||||
assert response.status_code == 200
|
||||
result = response.json()
|
||||
ids = [f["signature_id"] for f in result["findings"]]
|
||||
assert "ftp-auth-rejected" in ids
|
||||
assert result["summary"]["layer8"] >= 1
|
||||
|
||||
Reference in New Issue
Block a user