Improve test coverage to 65%

Add comprehensive test suites for:
- NPM client (27 tests)
- Ollama client (16 tests)
- AI client and controller (34 tests)
- Static controller (8 tests)
- Tools controller DNS lookup (9 tests)
- OIDC authentication (10 tests)
- Housekeeping endpoints (28 tests)
- Infrastructure endpoints (15 tests)
- Health endpoints (12 tests)
- Portainer client (12 tests)
- Home Assistant client (24 tests)

Total: 285 tests passing with 65% code coverage.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-17 16:32:39 +01:00
co-authored by Claude Opus 4.5
parent 33f31b09a3
commit a22e168666
13 changed files with 4269 additions and 0 deletions
+115
View File
@@ -0,0 +1,115 @@
"""Tests for static controller."""
import pytest
from fastapi.testclient import TestClient
from unittest.mock import patch, MagicMock
from pathlib import Path
import tempfile
import os
from src.main import app
@pytest.fixture
def client():
"""Create a test client."""
return TestClient(app)
class TestListWidgets:
"""Test /static/widgets endpoint."""
def test_list_widgets_returns_200(self, client):
"""List widgets should return 200."""
response = client.get("/static/widgets")
assert response.status_code == 200
def test_list_widgets_returns_widgets_list(self, client):
"""List widgets should return widgets array."""
response = client.get("/static/widgets")
data = response.json()
assert "widgets" in data
assert "count" in data
assert isinstance(data["widgets"], list)
@patch("src.controllers.static_controller.StaticController")
def test_list_widgets_handles_missing_directory(self, mock_controller_class, client):
"""List widgets should handle missing widgets directory."""
# Create a mock controller with non-existent static dir
with tempfile.TemporaryDirectory() as tmpdir:
mock_static_dir = Path(tmpdir) / "nonexistent"
with patch.object(
client.app.state if hasattr(client.app, 'state') else client.app,
'static_dir',
mock_static_dir,
create=True
):
# The actual endpoint handles this case gracefully
response = client.get("/static/widgets")
# Should still return 200 with empty list or message
assert response.status_code == 200
class TestGetWidget:
"""Test /static/widgets/{filename} endpoint."""
def test_get_widget_returns_404_for_nonexistent(self, client):
"""Get widget should return 404 for non-existent file."""
response = client.get("/static/widgets/nonexistent-widget.html")
assert response.status_code == 404
def test_get_widget_returns_html_content_type(self, client):
"""Get widget should return HTML content type for existing file."""
# First check if any widgets exist
list_response = client.get("/static/widgets")
widgets = list_response.json().get("widgets", [])
if widgets:
# Test with first available widget
widget_name = widgets[0]["name"]
response = client.get(f"/static/widgets/{widget_name}")
assert response.status_code == 200
assert "text/html" in response.headers.get("content-type", "")
def test_get_widget_prevents_path_traversal(self, client):
"""Get widget should prevent path traversal attacks."""
# Attempt path traversal
response = client.get("/static/widgets/../../../etc/passwd")
# Should either return 404 or 403, not the actual file
assert response.status_code in [400, 403, 404]
def test_get_widget_includes_cache_headers(self, client):
"""Get widget should include no-cache headers."""
list_response = client.get("/static/widgets")
widgets = list_response.json().get("widgets", [])
if widgets:
widget_name = widgets[0]["name"]
response = client.get(f"/static/widgets/{widget_name}")
if response.status_code == 200:
assert "no-cache" in response.headers.get("cache-control", "")
class TestStaticControllerInit:
"""Test StaticController initialization."""
def test_controller_has_static_dir(self):
"""Controller should have static directory configured."""
from src.controllers.static_controller import static_controller
assert static_controller.static_dir is not None
assert isinstance(static_controller.static_dir, Path)
def test_controller_has_correct_prefix(self):
"""Controller should have /static prefix."""
from src.controllers.static_controller import static_controller
assert static_controller.prefix == "/static"
def test_controller_has_correct_tags(self):
"""Controller should have Static tag."""
from src.controllers.static_controller import static_controller
assert "Static" in static_controller.tags