import pytest import app.routes.auth as auth_module @pytest.fixture(autouse=True) def _reset_guest_limiter(): # The limiter is module-level state; a previous test's hits would bleed # into the next one's per-IP budget. auth_module.guest_limiter._hits.clear() yield @pytest.mark.asyncio async def test_guest_creates_wanderer_and_cookie_works_on_me(client): response = await client.post("/auth/guest") assert response.status_code == 201 body = response.json() assert body["username"].startswith("wanderer-") assert "password" not in body assert "qm_session" in response.cookies me_resp = await client.get("/auth/me") assert me_resp.status_code == 200 assert me_resp.json()["username"] == body["username"] @pytest.mark.asyncio async def test_guest_cannot_login_with_any_password(client): response = await client.post("/auth/guest") username = response.json()["username"] login_resp = await client.post( "/auth/login", json={"username": username, "password": "anythingatall"} ) assert login_resp.status_code == 401 @pytest.mark.asyncio async def test_guest_rate_limit_fires_per_ip(client): for _ in range(5): response = await client.post("/auth/guest") assert response.status_code == 201 response = await client.post("/auth/guest") assert response.status_code == 429 @pytest.mark.asyncio async def test_guest_username_collision_retries(client, monkeypatch): taken_resp = await client.post("/auth/guest") taken = taken_resp.json()["username"].removeprefix("wanderer-") # First attempt collides with the existing wanderer; the retry must land # on the fresh suffix instead of erroring out. suffixes = iter([taken, "f4ee"]) monkeypatch.setattr( auth_module.secrets, "token_hex", lambda n: next(suffixes) ) response = await client.post("/auth/guest") assert response.status_code == 201 assert response.json()["username"] == "wanderer-f4ee"