Files
mywhoosh2garmin/tests/conftest.py
Bastian Wagner 420d089760 log
2026-08-15 20:54:35 +02:00

139 lines
4.1 KiB
Python

from pathlib import Path
import pytest
from cryptography.fernet import Fernet
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker
from sqlalchemy.pool import StaticPool
from app.config import Settings
from app.db.models import Activity, Base, HealthState
from app.db.repositories import ActivityRepository, SyncRunRepository, SystemLogRepository, UserRepository
from app.main import create_app
@pytest.fixture
def db_session() -> Session:
engine = create_engine(
"sqlite://",
connect_args={"check_same_thread": False},
poolclass=StaticPool,
)
Base.metadata.create_all(engine)
factory = sessionmaker(bind=engine, expire_on_commit=False)
try:
with factory() as session:
yield session
finally:
engine.dispose()
@pytest.fixture
def user_repository(db_session: Session) -> UserRepository:
return UserRepository(db_session)
@pytest.fixture
def activity_repository(db_session: Session) -> ActivityRepository:
return ActivityRepository(db_session)
@pytest.fixture
def sync_run_repository(db_session: Session) -> SyncRunRepository:
return SyncRunRepository(db_session)
@pytest.fixture
def system_log_repository(db_session: Session) -> SystemLogRepository:
return SystemLogRepository(db_session)
@pytest.fixture
def app(tmp_path: Path):
settings = Settings(
ADMIN_PASSWORD="admin-secret",
SECRET_KEY="0123456789abcdef0123456789abcdef",
CREDENTIAL_ENCRYPTION_KEY=Fernet.generate_key().decode("ascii"),
DATA_DIR=str(tmp_path),
DATABASE_URL=f"sqlite:///{tmp_path / 'app.db'}",
SYNC_INTERVAL_MINUTES=5,
)
application = create_app(settings)
try:
yield application
finally:
application.state.db_engine.dispose()
@pytest.fixture
def client(app) -> TestClient:
return TestClient(app)
def _extract_csrf(html: str) -> str:
marker = 'name="csrf_token" value="'
start = html.index(marker) + len(marker)
end = html.index('"', start)
return html[start:end]
class FakeSyncManager:
def __init__(self) -> None:
self.user_calls: list[int] = []
self.all_calls = 0
self.raise_already_running = False
self.mfa_calls: list[tuple[int, str]] = []
async def sync_user(self, user_id: int, mfa_code: str | None = None):
if self.raise_already_running:
from app.sync.manager import SyncAlreadyRunning
raise SyncAlreadyRunning(f"sync already running for user {user_id}")
self.user_calls.append(user_id)
if mfa_code is not None:
self.mfa_calls.append((user_id, mfa_code))
from app.sync.states import SyncOutcome
return SyncOutcome(user_id=user_id, status="success", discovered=0, imported=0, skipped=0, failed=0)
async def sync_all_enabled(self):
self.all_calls += 1
return []
@pytest.fixture
def fake_sync_manager() -> FakeSyncManager:
return FakeSyncManager()
@pytest.fixture
def authenticated_client(app, client: TestClient, fake_sync_manager: FakeSyncManager) -> TestClient:
page = client.get("/login")
csrf = _extract_csrf(page.text)
response = client.post("/login", data={"password": "admin-secret", "csrf_token": csrf}, follow_redirects=False)
assert response.status_code == 303
app.state.sync_manager = fake_sync_manager
client.csrf_token = csrf
return client
@pytest.fixture
def seeded_activity(db_session: Session, user_repository: UserRepository, activity_repository: ActivityRepository) -> Activity:
user = user_repository.create(
name="Test User",
enabled=True,
health_state=HealthState.HEALTHY,
mywhoosh_email_enc="test@example.com",
mywhoosh_password_enc="password",
garmin_email_enc="test@garmin.com",
garmin_password_enc="garmin_password",
)
activity, _ = activity_repository.get_or_create_discovered(
user_id=user.id,
mywhoosh_activity_id="mw-test-123",
activity_name="Test Activity",
activity_timestamp=None,
)
return activity