| import asyncio |
|
|
| from sqlalchemy import select |
|
|
| from src.database.db import session_pool |
| from src.model import Profile, User, UserSettings |
|
|
|
|
| def test_register_creates_user_profile_and_settings(client): |
| payload = { |
| "email": "new-user@example.com", |
| "password": "Password123!", |
| "full_name": "New User", |
| "username": "new_user", |
| } |
|
|
| response = client.post("/api/v1/auth/register", json=payload) |
|
|
| assert response.status_code == 200 |
| assert response.json()["email"] == payload["email"] |
|
|
| async def _load_user_state(): |
| async with session_pool() as session: |
| user = ( |
| await session.execute(select(User).where(User.email == payload["email"])) |
| ).scalar_one() |
| profile = ( |
| await session.execute(select(Profile).where(Profile.user_id == user.id)) |
| ).scalar_one_or_none() |
| settings = ( |
| await session.execute( |
| select(UserSettings).where(UserSettings.user_id == user.id) |
| ) |
| ).scalar_one_or_none() |
| return user, profile, settings |
|
|
| user, profile, settings = asyncio.run(_load_user_state()) |
| assert user.username == payload["username"] |
| assert profile is not None |
| assert settings is not None |
|
|
|
|
| def test_register_rejects_duplicate_email(client, create_user): |
| create_user(email="duplicate@example.com", username="original_user") |
|
|
| response = client.post( |
| "/api/v1/auth/register", |
| json={ |
| "email": "duplicate@example.com", |
| "password": "Password123!", |
| "full_name": "Another User", |
| "username": "another_user", |
| }, |
| ) |
|
|
| assert response.status_code == 400 |
| assert response.json()["detail"] == "Email already registered" |
|
|
|
|
| def test_register_rejects_duplicate_username(client, create_user): |
| create_user(email="existing@example.com", username="taken_name") |
|
|
| response = client.post( |
| "/api/v1/auth/register", |
| json={ |
| "email": "new@example.com", |
| "password": "Password123!", |
| "full_name": "Another User", |
| "username": "taken_name", |
| }, |
| ) |
|
|
| assert response.status_code == 400 |
| assert response.json()["detail"] == "Username already taken" |
|
|
|
|
| def test_login_refresh_logout_and_session_listing(client, create_user): |
| user = create_user( |
| email="login@example.com", |
| username="login_user", |
| password="Password123!", |
| ) |
|
|
| login_response = client.post( |
| "/api/v1/auth/login", |
| json={"email": user["email"], "password": user["password"]}, |
| headers={"user-agent": "pytest"}, |
| ) |
|
|
| assert login_response.status_code == 200 |
| login_payload = login_response.json() |
| assert login_payload["token_type"] == "bearer" |
| assert login_payload["user"]["email"] == user["email"] |
|
|
| access_token = login_payload["access_token"] |
| refresh_token = login_payload["refresh_token"] |
|
|
| sessions_response = client.get( |
| "/api/v1/auth/sessions", |
| headers={"Authorization": f"Bearer {access_token}"}, |
| ) |
| assert sessions_response.status_code == 200 |
| sessions = sessions_response.json() |
| assert len(sessions) == 1 |
| assert sessions[0]["is_active"] is True |
|
|
| refresh_response = client.post( |
| "/api/v1/auth/refresh", |
| json={"refresh_token": refresh_token}, |
| ) |
| assert refresh_response.status_code == 200 |
| refreshed_access_token = refresh_response.json()["access_token"] |
| assert refreshed_access_token != access_token |
|
|
| logout_response = client.post( |
| "/api/v1/auth/logout", |
| headers={"Authorization": f"Bearer {refreshed_access_token}"}, |
| ) |
| assert logout_response.status_code == 200 |
| assert logout_response.json()["message"] == "Logged out from 1 sessions" |
|
|
| revoked_response = client.get( |
| "/api/v1/auth/sessions", |
| headers={"Authorization": f"Bearer {refreshed_access_token}"}, |
| ) |
| assert revoked_response.status_code == 401 |
|
|
|
|
| def test_login_rejects_invalid_credentials(client, create_user): |
| user = create_user(email="bad-login@example.com", username="bad_login") |
|
|
| response = client.post( |
| "/api/v1/auth/login", |
| json={"email": user["email"], "password": "wrong-password"}, |
| ) |
|
|
| assert response.status_code == 401 |
| assert response.json()["detail"] == "Invalid credentials" |
|
|
|
|
| def test_delete_account_removes_user(client, create_authenticated_user): |
| auth_user = create_authenticated_user( |
| email="delete-me@example.com", |
| username="delete_me", |
| ) |
|
|
| response = client.delete( |
| "/api/v1/auth/account", |
| headers=auth_user["headers"], |
| ) |
|
|
| assert response.status_code == 200 |
| assert response.json()["message"] == "User account deleted successfully" |
|
|
| async def _load_user(): |
| async with session_pool() as session: |
| return ( |
| await session.execute(select(User).where(User.id == auth_user["id"])) |
| ).scalar_one_or_none() |
|
|
| assert asyncio.run(_load_user()) is None |
|
|