Files
rail-game/backend/tests/test_tracks_api.py
zwitschi 68048ff574
Some checks failed
Backend CI / lint-and-test (push) Failing after 2m27s
Frontend CI / lint-and-build (push) Successful in 57s
feat: Add combined track functionality with repository and service layers
- Introduced CombinedTrackModel, CombinedTrackCreate, and CombinedTrackRepository for managing combined tracks.
- Implemented logic to create combined tracks based on existing tracks between two stations.
- Added methods to check for existing combined tracks and retrieve constituent track IDs.
- Enhanced TrackModel and TrackRepository to support OSM ID and track updates.
- Created migration scripts for adding combined tracks table and OSM ID to tracks.
- Updated services and API endpoints to handle combined track operations.
- Added tests for combined track creation, repository methods, and API interactions.
2025-11-10 14:12:28 +01:00

159 lines
4.5 KiB
Python

from __future__ import annotations
from datetime import datetime, timezone
from typing import Any
import pytest
from fastapi.testclient import TestClient
from backend.app.api import tracks as tracks_api
from backend.app.main import app
from backend.app.models import CombinedTrackModel, TrackModel
client = TestClient(app)
def _track_model(track_id: str = "track-1") -> TrackModel:
now = datetime.now(timezone.utc)
return TrackModel(
id=track_id,
start_station_id="station-a",
end_station_id="station-b",
length_meters=None,
max_speed_kph=None,
status="planned",
coordinates=[(52.5, 13.4), (52.6, 13.5)],
is_bidirectional=True,
created_at=now,
updated_at=now,
)
def _combined_model(track_id: str = "combined-1") -> CombinedTrackModel:
now = datetime.now(timezone.utc)
return CombinedTrackModel(
id=track_id,
start_station_id="station-a",
end_station_id="station-b",
length_meters=1000,
max_speed_kph=120,
status="operational",
coordinates=[(52.5, 13.4), (52.6, 13.5)],
constituent_track_ids=["track-1", "track-2"],
is_bidirectional=True,
created_at=now,
updated_at=now,
)
def _authenticate() -> str:
response = client.post(
"/api/auth/login",
json={"username": "demo", "password": "railgame123"},
)
assert response.status_code == 200
return response.json()["accessToken"]
def test_list_tracks(monkeypatch: pytest.MonkeyPatch) -> None:
token = _authenticate()
monkeypatch.setattr(tracks_api, "list_tracks", lambda db: [_track_model()])
response = client.get(
"/api/tracks",
headers={"Authorization": f"Bearer {token}"},
)
assert response.status_code == 200
payload = response.json()
assert isinstance(payload, list)
assert payload[0]["id"] == "track-1"
def test_get_track_returns_404(monkeypatch: pytest.MonkeyPatch) -> None:
token = _authenticate()
monkeypatch.setattr(tracks_api, "get_track", lambda db, track_id: None)
response = client.get(
"/api/tracks/not-found",
headers={"Authorization": f"Bearer {token}"},
)
assert response.status_code == 404
def test_create_track_calls_service(monkeypatch: pytest.MonkeyPatch) -> None:
token = _authenticate()
captured: dict[str, Any] = {}
payload = {
"startStationId": "station-a",
"endStationId": "station-b",
"coordinates": [[52.5, 13.4], [52.6, 13.5]],
}
def fake_create(db: Any, data: Any) -> TrackModel:
assert data.start_station_id == "station-a"
captured["payload"] = data
return _track_model("track-new")
monkeypatch.setattr(tracks_api, "create_track", fake_create)
response = client.post(
"/api/tracks",
json=payload,
headers={"Authorization": f"Bearer {token}"},
)
assert response.status_code == 201
body = response.json()
assert body["id"] == "track-new"
assert captured["payload"].end_station_id == "station-b"
def test_delete_track_returns_404(monkeypatch: pytest.MonkeyPatch) -> None:
token = _authenticate()
monkeypatch.setattr(
tracks_api, "delete_track", lambda db, tid, regenerate=False: False
)
response = client.delete(
"/api/tracks/missing",
headers={"Authorization": f"Bearer {token}"},
)
assert response.status_code == 404
def test_delete_track_success(monkeypatch: pytest.MonkeyPatch) -> None:
token = _authenticate()
seen: dict[str, Any] = {}
def fake_delete(db: Any, track_id: str, regenerate: bool = False) -> bool:
seen["track_id"] = track_id
seen["regenerate"] = regenerate
return True
monkeypatch.setattr(tracks_api, "delete_track", fake_delete)
response = client.delete(
"/api/tracks/track-99",
params={"regenerate": "true"},
headers={"Authorization": f"Bearer {token}"},
)
assert response.status_code == 204
assert seen["track_id"] == "track-99"
assert seen["regenerate"] is True
def test_list_combined_tracks(monkeypatch: pytest.MonkeyPatch) -> None:
token = _authenticate()
monkeypatch.setattr(
tracks_api, "list_combined_tracks", lambda db: [_combined_model()]
)
response = client.get(
"/api/tracks/combined",
headers={"Authorization": f"Bearer {token}"},
)
assert response.status_code == 200
payload = response.json()
assert len(payload) == 1
assert payload[0]["id"] == "combined-1"