from __future__ import annotations from datetime import datetime, timezone from typing import Any from uuid import uuid4 import pytest from fastapi.testclient import TestClient from backend.app.api import stations as stations_api from backend.app.main import app from backend.app.models import StationCreate, StationModel, StationUpdate AUTH_CREDENTIALS = {"username": "demo", "password": "railgame123"} client = TestClient(app) def _authenticate() -> str: response = client.post("/api/auth/login", json=AUTH_CREDENTIALS) assert response.status_code == 200 return response.json()["accessToken"] def _station_payload(**overrides: Any) -> dict[str, Any]: payload = { "name": "Central", "latitude": 52.52, "longitude": 13.405, "osmId": "123", "code": "BER", "elevationM": 34.5, "isActive": True, } payload.update(overrides) return payload def _station_model(**overrides: Any) -> StationModel: now = datetime.now(timezone.utc) base = StationModel( id=str(uuid4()), name="Central", latitude=52.52, longitude=13.405, code="BER", osm_id="123", elevation_m=34.5, is_active=True, created_at=now, updated_at=now, ) return base.model_copy(update=overrides) def test_list_stations_requires_authentication() -> None: response = client.get("/api/stations") assert response.status_code == 401 def test_list_stations_returns_payload(monkeypatch: pytest.MonkeyPatch) -> None: token = _authenticate() def fake_list_stations(db, include_inactive: bool) -> list[StationModel]: assert include_inactive is True return [_station_model()] monkeypatch.setattr(stations_api, "list_stations", fake_list_stations) response = client.get( "/api/stations", params={"include_inactive": "true"}, headers={"Authorization": f"Bearer {token}"}, ) assert response.status_code == 200 payload = response.json() assert len(payload) == 1 assert payload[0]["name"] == "Central" def test_create_station_delegates_to_service(monkeypatch: pytest.MonkeyPatch) -> None: token = _authenticate() seen: dict[str, StationCreate] = {} def fake_create_station(db, payload: StationCreate) -> StationModel: seen["payload"] = payload return _station_model() monkeypatch.setattr(stations_api, "create_station", fake_create_station) response = client.post( "/api/stations", json=_station_payload(), headers={"Authorization": f"Bearer {token}"}, ) assert response.status_code == 201 assert response.json()["name"] == "Central" assert seen["payload"].name == "Central" def test_update_station_not_found_returns_404(monkeypatch: pytest.MonkeyPatch) -> None: token = _authenticate() def fake_update_station( db, station_id: str, payload: StationUpdate ) -> StationModel: raise LookupError("Station not found") monkeypatch.setattr(stations_api, "update_station", fake_update_station) response = client.put( "/api/stations/123e4567-e89b-12d3-a456-426614174000", json={"name": "New Name"}, headers={"Authorization": f"Bearer {token}"}, ) assert response.status_code == 404 assert response.json()["detail"] == "Station not found" def test_archive_station_returns_updated_model(monkeypatch: pytest.MonkeyPatch) -> None: token = _authenticate() def fake_archive_station(db, station_id: str) -> StationModel: return _station_model(is_active=False) monkeypatch.setattr(stations_api, "archive_station", fake_archive_station) response = client.post( "/api/stations/123e4567-e89b-12d3-a456-426614174000/archive", headers={"Authorization": f"Bearer {token}"}, ) assert response.status_code == 200 assert response.json()["isActive"] is False