"""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}