fixed tests

This commit is contained in:
2026-05-15 20:41:05 +02:00
parent 96ce516ecf
commit 77df5d5d65
50 changed files with 1482 additions and 5089 deletions

View File

@@ -14,7 +14,6 @@ from app.db import init_db
from app.main import create_app
from app.models.history import (
HistoryBanItem,
HistoryListResponse,
IpDetailResponse,
IpTimelineEvent,
)
@@ -48,13 +47,26 @@ def _make_history_item(ip: str = "1.2.3.4", jail: str = "sshd") -> HistoryBanIte
)
def _make_history_list(n: int = 2) -> HistoryListResponse:
"""Build a mock ``HistoryListResponse`` with *n* items."""
from app.utils.pagination import create_pagination_metadata
def _make_history_list(n: int = 2):
"""Build a mock ``DomainHistoryList`` with *n* items."""
from app.models.history_domain import DomainHistoryBanItem, DomainHistoryList
items = [_make_history_item(ip=f"1.2.3.{i}") for i in range(n)]
pagination = create_pagination_metadata(total=n, page=1, page_size=100)
return HistoryListResponse(items=items, pagination=pagination)
items = [
DomainHistoryBanItem(
ip=f"1.2.3.{i}",
jail="sshd",
banned_at="2026-03-01T10:00:00+00:00",
ban_count=3,
failures=5,
matches=["Mar 1 10:00:00 host sshd[123]: Failed password for root"],
country_code="DE",
country_name="Germany",
asn="AS3320",
org="Telekom",
)
for i in range(n)
]
return DomainHistoryList(items=items, total=n, page=1, page_size=100)
def _make_ip_detail(ip: str = "1.2.3.4") -> IpDetailResponse:
@@ -96,13 +108,17 @@ def _make_ip_detail(ip: str = "1.2.3.4") -> IpDetailResponse:
@pytest.fixture
async def history_client(tmp_path: Path) -> AsyncClient: # type: ignore[misc]
"""Provide an authenticated ``AsyncClient`` for history endpoint tests."""
config_dir = tmp_path / "fail2ban"
config_dir.mkdir()
settings = Settings(
database_path=str(tmp_path / "history_test.db"),
fail2ban_socket="/tmp/fake_fail2ban.sock",
fail2ban_config_dir=str(config_dir),
session_secret="test-history-secret-32chars-long!!",
session_duration_minutes=60,
timezone="UTC",
log_level="debug",
session_cookie_secure=False,
)
app = create_app(settings=settings)
@@ -136,9 +152,7 @@ async def history_client(tmp_path: Path) -> AsyncClient: # type: ignore[misc]
class TestHistoryList:
"""GET /api/history — paginated history list."""
async def test_returns_200_when_authenticated(
self, history_client: AsyncClient
) -> None:
async def test_returns_200_when_authenticated(self, history_client: AsyncClient) -> None:
"""Authenticated request returns HTTP 200."""
with patch(
"app.routers.history.history_service.list_history",
@@ -147,9 +161,7 @@ class TestHistoryList:
response = await history_client.get("/api/v1/history")
assert response.status_code == 200
async def test_returns_401_when_unauthenticated(
self, client: AsyncClient
) -> None:
async def test_returns_401_when_unauthenticated(self, client: AsyncClient) -> None:
"""Unauthenticated request returns HTTP 401."""
await client.post("/api/v1/setup", json=_SETUP_PAYLOAD)
response = await client.get("/api/v1/history")
@@ -245,9 +257,7 @@ class TestHistoryList:
_args, kwargs = mock_fn.call_args
assert kwargs.get("source") == "archive"
async def test_archive_route_forces_source_archive(
self, history_client: AsyncClient
) -> None:
async def test_archive_route_forces_source_archive(self, history_client: AsyncClient) -> None:
"""GET /api/history/archive should call list_history with source='archive'."""
mock_fn = AsyncMock(return_value=_make_history_list(n=0))
with patch(
@@ -261,14 +271,16 @@ class TestHistoryList:
async def test_empty_result(self, history_client: AsyncClient) -> None:
"""An empty history returns items=[] and total=0."""
from app.utils.pagination import create_pagination_metadata
from app.models.history_domain import DomainHistoryList
with patch(
"app.routers.history.history_service.list_history",
new=AsyncMock(
return_value=HistoryListResponse(
return_value=DomainHistoryList(
items=[],
pagination=create_pagination_metadata(total=0, page=1, page_size=100),
total=0,
page=1,
page_size=100,
)
),
):
@@ -287,9 +299,7 @@ class TestHistoryList:
class TestIpHistory:
"""GET /api/history/{ip} — per-IP detail."""
async def test_returns_200_when_authenticated(
self, history_client: AsyncClient
) -> None:
async def test_returns_200_when_authenticated(self, history_client: AsyncClient) -> None:
"""Authenticated request returns HTTP 200 for a known IP."""
with patch(
"app.routers.history.history_service.get_ip_detail",
@@ -298,17 +308,13 @@ class TestIpHistory:
response = await history_client.get("/api/v1/history/1.2.3.4")
assert response.status_code == 200
async def test_returns_401_when_unauthenticated(
self, client: AsyncClient
) -> None:
async def test_returns_401_when_unauthenticated(self, client: AsyncClient) -> None:
"""Unauthenticated request returns HTTP 401."""
await client.post("/api/v1/setup", json=_SETUP_PAYLOAD)
response = await client.get("/api/v1/history/1.2.3.4")
assert response.status_code == 401
async def test_returns_404_for_unknown_ip(
self, history_client: AsyncClient
) -> None:
async def test_returns_404_for_unknown_ip(self, history_client: AsyncClient) -> None:
"""Returns 404 when the IP has no records in the database."""
with patch(
"app.routers.history.history_service.get_ip_detail",
@@ -341,9 +347,7 @@ class TestIpHistory:
assert "failures" in event
assert "matches" in event
async def test_aggregation_sums_failures(
self, history_client: AsyncClient
) -> None:
async def test_aggregation_sums_failures(self, history_client: AsyncClient) -> None:
"""total_failures reflects the sum across all timeline events."""
mock_detail = _make_ip_detail("10.0.0.1")
mock_detail = IpDetailResponse(