""" Integration tests for POST /api/register. UUID notes: RegisterRequest.uuid requires a valid UUID v4 pattern (^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$). All UUID constants below satisfy this constraint. BATON-SEC-003: /api/register now returns api_key in the response. """ from __future__ import annotations import os os.environ.setdefault("BOT_TOKEN", "test-bot-token") os.environ.setdefault("CHAT_ID", "-1001234567890") os.environ.setdefault("WEBHOOK_SECRET", "test-webhook-secret") os.environ.setdefault("WEBHOOK_URL", "https://example.com/api/webhook/telegram") os.environ.setdefault("FRONTEND_ORIGIN", "http://localhost:3000") os.environ.setdefault("ADMIN_TOKEN", "test-admin-token") import pytest from tests.conftest import make_app_client # Valid UUID v4 constants for register tests _UUID_REG_1 = "b0000001-0000-4000-8000-000000000001" _UUID_REG_2 = "b0000002-0000-4000-8000-000000000002" _UUID_REG_3 = "b0000003-0000-4000-8000-000000000003" _UUID_REG_4 = "b0000004-0000-4000-8000-000000000004" _UUID_REG_5 = "b0000005-0000-4000-8000-000000000005" _UUID_REG_6 = "b0000006-0000-4000-8000-000000000006" @pytest.mark.asyncio async def test_register_new_user_success(): """POST /api/register returns 200 with user_id > 0 and api_key.""" async with make_app_client() as client: resp = await client.post( "/api/register", json={"uuid": _UUID_REG_1, "name": "Alice"}, ) assert resp.status_code == 200 data = resp.json() assert data["user_id"] > 0 assert data["uuid"] == _UUID_REG_1 assert "api_key" in data assert len(data["api_key"]) == 64 # secrets.token_hex(32) = 64 hex chars @pytest.mark.asyncio async def test_register_idempotent(): """Registering the same uuid twice returns the same user_id.""" async with make_app_client() as client: r1 = await client.post( "/api/register", json={"uuid": _UUID_REG_2, "name": "Bob"}, ) r2 = await client.post( "/api/register", json={"uuid": _UUID_REG_2, "name": "Bob"}, ) assert r1.status_code == 200 assert r2.status_code == 200 assert r1.json()["user_id"] == r2.json()["user_id"] @pytest.mark.asyncio async def test_register_idempotent_returns_api_key_on_every_call(): """Each registration call returns an api_key (key rotation on re-register).""" async with make_app_client() as client: r1 = await client.post( "/api/register", json={"uuid": _UUID_REG_3, "name": "Carol"}, ) r2 = await client.post( "/api/register", json={"uuid": _UUID_REG_3, "name": "Carol"}, ) assert r1.status_code == 200 assert r2.status_code == 200 assert "api_key" in r1.json() assert "api_key" in r2.json() @pytest.mark.asyncio async def test_register_empty_name_returns_422(): """Empty name must fail validation with 422.""" async with make_app_client() as client: resp = await client.post( "/api/register", json={"uuid": _UUID_REG_4, "name": ""}, ) assert resp.status_code == 422 @pytest.mark.asyncio async def test_register_missing_uuid_returns_422(): """Missing uuid field must return 422.""" async with make_app_client() as client: resp = await client.post( "/api/register", json={"name": "Charlie"}, ) assert resp.status_code == 422 @pytest.mark.asyncio async def test_register_missing_name_returns_422(): """Missing name field must return 422.""" async with make_app_client() as client: resp = await client.post( "/api/register", json={"uuid": _UUID_REG_4}, ) assert resp.status_code == 422 @pytest.mark.asyncio async def test_register_invalid_uuid_format_returns_422(): """Non-UUID4 string as uuid must return 422.""" async with make_app_client() as client: resp = await client.post( "/api/register", json={"uuid": "not-a-uuid", "name": "Dave"}, ) assert resp.status_code == 422 @pytest.mark.asyncio async def test_register_user_stored_in_db(): """After register, the user is persisted (second call returns same id).""" async with make_app_client() as client: r1 = await client.post( "/api/register", json={"uuid": _UUID_REG_5, "name": "Dana"}, ) r2 = await client.post( "/api/register", json={"uuid": _UUID_REG_5, "name": "Dana"}, ) assert r1.json()["user_id"] == r2.json()["user_id"] @pytest.mark.asyncio async def test_register_response_contains_uuid(): """Response body includes the submitted uuid.""" async with make_app_client() as client: resp = await client.post( "/api/register", json={"uuid": _UUID_REG_6, "name": "Eve"}, ) assert resp.json()["uuid"] == _UUID_REG_6