import pytest import uuid def unique_email(prefix: str = "counter") -> str: """Generate a unique email for tests sharing the same database.""" return f"{prefix}-{uuid.uuid4().hex[:8]}@example.com" async def create_user_and_get_headers(client, email: str = None) -> dict: """Create a user and return auth headers for authenticated requests.""" if email is None: email = unique_email() response = await client.post( "/api/auth/register", json={"email": email, "password": "testpass123"}, ) token = response.json()["access_token"] return {"Authorization": f"Bearer {token}"} # Protected endpoint tests - without auth @pytest.mark.asyncio async def test_get_counter_requires_auth(client): response = await client.get("/api/counter") assert response.status_code in [401, 403] @pytest.mark.asyncio async def test_increment_counter_requires_auth(client): response = await client.post("/api/counter/increment") assert response.status_code in [401, 403] @pytest.mark.asyncio async def test_get_counter_invalid_token(client): response = await client.get( "/api/counter", headers={"Authorization": "Bearer invalidtoken"}, ) assert response.status_code == 401 @pytest.mark.asyncio async def test_increment_counter_invalid_token(client): response = await client.post( "/api/counter/increment", headers={"Authorization": "Bearer invalidtoken"}, ) assert response.status_code == 401 # Authenticated counter tests @pytest.mark.asyncio async def test_get_counter_authenticated(client): auth_headers = await create_user_and_get_headers(client) response = await client.get("/api/counter", headers=auth_headers) assert response.status_code == 200 assert "value" in response.json() @pytest.mark.asyncio async def test_increment_counter(client): auth_headers = await create_user_and_get_headers(client) # Get current value before = await client.get("/api/counter", headers=auth_headers) before_value = before.json()["value"] # Increment response = await client.post("/api/counter/increment", headers=auth_headers) assert response.status_code == 200 assert response.json()["value"] == before_value + 1 @pytest.mark.asyncio async def test_increment_counter_multiple(client): auth_headers = await create_user_and_get_headers(client) # Get starting value before = await client.get("/api/counter", headers=auth_headers) start = before.json()["value"] # Increment 3 times await client.post("/api/counter/increment", headers=auth_headers) await client.post("/api/counter/increment", headers=auth_headers) response = await client.post("/api/counter/increment", headers=auth_headers) assert response.json()["value"] == start + 3 @pytest.mark.asyncio async def test_get_counter_after_increment(client): auth_headers = await create_user_and_get_headers(client) before = await client.get("/api/counter", headers=auth_headers) start = before.json()["value"] await client.post("/api/counter/increment", headers=auth_headers) await client.post("/api/counter/increment", headers=auth_headers) response = await client.get("/api/counter", headers=auth_headers) assert response.json()["value"] == start + 2 # Counter is shared between users @pytest.mark.asyncio async def test_counter_shared_between_users(client): headers1 = await create_user_and_get_headers(client, unique_email("share1")) # Get starting value before = await client.get("/api/counter", headers=headers1) start = before.json()["value"] await client.post("/api/counter/increment", headers=headers1) await client.post("/api/counter/increment", headers=headers1) # Second user sees the increments headers2 = await create_user_and_get_headers(client, unique_email("share2")) response = await client.get("/api/counter", headers=headers2) assert response.json()["value"] == start + 2 # Second user increments await client.post("/api/counter/increment", headers=headers2) # First user sees the increment response = await client.get("/api/counter", headers=headers1) assert response.json()["value"] == start + 3