207 lines
6.3 KiB
Python
207 lines
6.3 KiB
Python
"""Router dependency injection tests.
|
|
|
|
These tests verify that routers can consume service abstractions via FastAPI
|
|
dependencies and that those dependencies can be overridden cleanly for unit
|
|
testing without touching concrete implementations.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
import aiosqlite
|
|
from httpx import ASGITransport, AsyncClient
|
|
|
|
from app.config import Settings
|
|
from app.db import init_db
|
|
|
|
# Note: Service dependency injection at router level is not yet implemented.
|
|
# These tests are placeholders for future refactoring.
|
|
# from app.dependencies import get_auth_service, get_jail_service
|
|
from app.main import create_app
|
|
from app.models.auth import Session
|
|
from app.models.jail import JailListResponse
|
|
from app.utils.constants import SESSION_COOKIE_NAME
|
|
from app.utils.setup_state import set_setup_complete_cache
|
|
|
|
|
|
class FakeAuthService:
|
|
async def login(
|
|
self,
|
|
_db: aiosqlite.Connection,
|
|
password: str,
|
|
session_duration_minutes: int,
|
|
session_repo: object | None = None,
|
|
) -> Session:
|
|
return Session(
|
|
id=1,
|
|
token="fake-token",
|
|
created_at="2025-01-01T00:00:00Z",
|
|
expires_at="2099-01-01T00:00:00Z",
|
|
)
|
|
|
|
async def validate_session(
|
|
self,
|
|
_db: aiosqlite.Connection,
|
|
token: str,
|
|
session_secret: str | None = None,
|
|
session_repo: object | None = None,
|
|
) -> Session:
|
|
return Session(
|
|
id=1,
|
|
token=token,
|
|
created_at="2025-01-01T00:00:00Z",
|
|
expires_at="2099-01-01T00:00:00Z",
|
|
)
|
|
|
|
async def logout(
|
|
self,
|
|
_db: aiosqlite.Connection,
|
|
token: str,
|
|
session_secret: str | None = None,
|
|
session_repo: object | None = None,
|
|
) -> str | None:
|
|
return token
|
|
|
|
|
|
class FakeJailService:
|
|
async def list_jails(self, _socket_path: str) -> JailListResponse:
|
|
return JailListResponse(items=[], total=0)
|
|
|
|
async def get_jail(self, _socket_path: str, _name: str) -> JailListResponse:
|
|
raise NotImplementedError
|
|
|
|
async def reload_all(self, _socket_path: str) -> None:
|
|
raise NotImplementedError
|
|
|
|
async def start_jail(self, _socket_path: str, _name: str) -> None:
|
|
raise NotImplementedError
|
|
|
|
async def stop_jail(self, _socket_path: str, _name: str) -> None:
|
|
raise NotImplementedError
|
|
|
|
async def set_idle(self, socket_path: str, name: str, *, on: bool) -> None:
|
|
raise NotImplementedError
|
|
|
|
async def reload_jail(self, socket_path: str, name: str) -> None:
|
|
raise NotImplementedError
|
|
|
|
async def get_ignore_list(self, socket_path: str, name: str) -> list[str]:
|
|
raise NotImplementedError
|
|
|
|
async def add_ignore_ip(self, socket_path: str, name: str, ip: str) -> None:
|
|
raise NotImplementedError
|
|
|
|
async def del_ignore_ip(self, socket_path: str, name: str, ip: str) -> None:
|
|
raise NotImplementedError
|
|
|
|
async def set_ignore_self(self, socket_path: str, name: str, *, on: bool) -> None:
|
|
raise NotImplementedError
|
|
|
|
async def get_jail_banned_ips(
|
|
self,
|
|
socket_path: str,
|
|
jail_name: str,
|
|
page: int,
|
|
page_size: int,
|
|
search: str | None = None,
|
|
*,
|
|
geo_batch_lookup: object,
|
|
http_session: object,
|
|
app_db: aiosqlite.Connection,
|
|
) -> JailListResponse:
|
|
raise NotImplementedError
|
|
|
|
|
|
async def _build_app(settings: Settings):
|
|
app = create_app(settings=settings)
|
|
set_setup_complete_cache(app, True)
|
|
db = await aiosqlite.connect(settings.database_path)
|
|
db.row_factory = aiosqlite.Row
|
|
await init_db(db)
|
|
return app, db
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
@pytest.mark.skip(reason="Service dependency injection at router level is not yet implemented.")
|
|
async def test_auth_login_uses_injected_auth_service(tmp_path: Path) -> None:
|
|
config_dir = tmp_path / "fail2ban"
|
|
config_dir.mkdir(parents=True)
|
|
settings = Settings(
|
|
database_path=str(tmp_path / "test_bangui.db"),
|
|
fail2ban_socket="/tmp/fake_fail2ban.sock",
|
|
fail2ban_config_dir=str(config_dir),
|
|
session_secret="test-secret-key-do-not-use-in-production",
|
|
session_duration_minutes=60,
|
|
timezone="UTC",
|
|
log_level="debug",
|
|
)
|
|
|
|
app, db = await _build_app(settings)
|
|
|
|
def _fake_auth_service() -> FakeAuthService:
|
|
return FakeAuthService()
|
|
|
|
# Service dependency injection not yet implemented
|
|
# app.dependency_overrides[get_auth_service] = _fake_auth_service
|
|
|
|
transport = ASGITransport(app=app)
|
|
async with AsyncClient(
|
|
transport=transport,
|
|
base_url="http://test",
|
|
) as client:
|
|
response = await client.post(
|
|
"/api/v1/auth/login",
|
|
json={"password": "ignored"},
|
|
)
|
|
|
|
await db.close()
|
|
|
|
assert response.status_code == 200
|
|
assert response.json()["token"].startswith("fake-token")
|
|
assert response.cookies.get(SESSION_COOKIE_NAME) is not None
|
|
|
|
|
|
@pytest.mark.skip(reason="Service dependency injection at router level is not yet implemented.")
|
|
async def test_jail_list_uses_injected_jail_service_and_auth(tmp_path: Path) -> None:
|
|
config_dir = tmp_path / "fail2ban"
|
|
config_dir.mkdir(parents=True)
|
|
settings = Settings(
|
|
database_path=str(tmp_path / "test_bangui.db"),
|
|
fail2ban_socket="/tmp/fake_fail2ban.sock",
|
|
fail2ban_config_dir=str(config_dir),
|
|
session_secret="test-secret-key-do-not-use-in-production",
|
|
session_duration_minutes=60,
|
|
timezone="UTC",
|
|
log_level="debug",
|
|
)
|
|
|
|
app, db = await _build_app(settings)
|
|
|
|
def _fake_auth_service() -> FakeAuthService:
|
|
return FakeAuthService()
|
|
|
|
def _fake_jail_service() -> FakeJailService:
|
|
return FakeJailService()
|
|
|
|
# Service dependency injection not yet implemented
|
|
# app.dependency_overrides[get_auth_service] = _fake_auth_service
|
|
# app.dependency_overrides[get_jail_service] = _fake_jail_service
|
|
|
|
transport = ASGITransport(app=app)
|
|
async with AsyncClient(
|
|
transport=transport,
|
|
base_url="http://test",
|
|
) as client:
|
|
response = await client.get(
|
|
"/api/v1/jails",
|
|
headers={"Cookie": f"{SESSION_COOKIE_NAME}=fake-token"},
|
|
)
|
|
|
|
await db.close()
|
|
|
|
assert response.status_code == 200
|
|
assert response.json() == {"jails": [], "total": 0}
|