import pytest from cryptography.fernet import Fernet from httpx import ASGITransport, AsyncClient from app.config import settings @pytest.fixture async def client(monkeypatch, tmp_path): monkeypatch.setattr(settings, "database_url", f"sqlite+aiosqlite:///{tmp_path}/test.db") monkeypatch.setattr(settings, "jwt_secret", "test-jwt-secret") monkeypatch.setattr(settings, "xprv_encryption_key", Fernet.generate_key().decode()) monkeypatch.setattr(settings, "master_key_path", str(tmp_path / "master.xprv.enc")) import app.wallet.hd as hd hd._account_key = None hd.generate_master_key() from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine from app.db import base as db_base import app.db.models # noqa: F401 db_base.engine = create_async_engine(settings.database_url) db_base.AsyncSessionLocal = async_sessionmaker(db_base.engine, expire_on_commit=False) from app.db import session as db_session db_session.AsyncSessionLocal = db_base.AsyncSessionLocal async with db_base.engine.begin() as conn: await conn.run_sync(db_base.Base.metadata.create_all) from fastapi import FastAPI from app.api.routes.rounds import router as rounds_router from app.auth.routes import router as auth_router from app.electrum.listener import ElectrumListener app = FastAPI() app.include_router(auth_router) app.include_router(rounds_router) app.state.electrum_listener = ElectrumListener(lambda: None, db_base.AsyncSessionLocal) transport = ASGITransport(app=app) async with AsyncClient(transport=transport, base_url="http://test") as ac: yield ac, db_base.AsyncSessionLocal await db_base.engine.dispose() async def _register(ac, username): resp = await ac.post("/auth/register", json={"username": username, "password": "hunter2hunter"}) assert resp.status_code == 201 data = resp.json() return data["access_token"], data["user_id"] if "user_id" in data else None async def test_user_played_true_only_for_participants(client): ac, session_factory = client from app.db.models import Round, RoundConfig, RoundParticipant, User player_token, _ = await _register(ac, "player") spectator_token, _ = await _register(ac, "spectator") async with session_factory() as session: from sqlalchemy import select session.add(RoundConfig(fee_address="pool-fee-address")) player = (await session.scalars(select(User).where(User.username == "player"))).one() round_ = Round(status="paying_out", winner_user_id=player.id, winner_amount_sats=123) session.add(round_) await session.flush() session.add( RoundParticipant( round_id=round_.id, user_id=player.id, bet_amount_sats=1_000_000_000, bet_txid="a" * 64, ) ) await session.commit() resp = await ac.get("/rounds/current", headers={"Authorization": f"Bearer {player_token}"}) assert resp.status_code == 200 assert resp.json()["user_played"] is True resp = await ac.get("/rounds/current", headers={"Authorization": f"Bearer {spectator_token}"}) assert resp.status_code == 200 assert resp.json()["user_played"] is False resp = await ac.get("/rounds/current") # no auth at all — logged-out chain-only view assert resp.status_code == 200 assert resp.json()["user_played"] is False