"""Tests for self-hosted authentication system. This module tests the JWT-based authentication with OAuth2 Password Flow. """ import pytest from fastapi.testclient import TestClient from sqlalchemy import select from sqlmodel.ext.asyncio.session import AsyncSession from app.core.security import create_access_token, get_password_hash, verify_password from app.main import app from app.models import User from app.schemas.user import UserCreate client = TestClient(app) class TestSecurityUtilities: """Test cases for security utilities.""" def test_password_hashing(self): """Test password hashing and verification.""" password = "testpassword123" hashed = get_password_hash(password) # Hash should be different from plain password assert hashed != password # Verification should succeed assert verify_password(password, hashed) is True # Wrong password should fail assert verify_password("wrongpassword", hashed) is False def test_create_access_token(self): """Test JWT token creation.""" data = {"sub": "123e4567-e89b-12d3-a456-426614174000"} token = create_access_token(data) assert token is not None assert isinstance(token, str) # JWT tokens have 3 parts separated by dots assert len(token.split(".")) == 3 class TestAuthEndpoints: """Test cases for authentication endpoints.""" def test_register_success(self): """Test successful user registration.""" response = client.post( "/api/v1/auth/register", json={ "email": "test@wealthwise.app", "password": "testpassword123", }, ) assert response.status_code == 201 data = response.json() assert data["email"] == "test@wealthwise.app" assert "id" in data assert "hashed_password" not in data assert data["is_active"] is True def test_register_duplicate_email(self): """Test registration with duplicate email.""" # First registration client.post( "/api/v1/auth/register", json={ "email": "duplicate@wealthwise.app", "password": "testpassword123", }, ) # Second registration with same email response = client.post( "/api/v1/auth/register", json={ "email": "duplicate@wealthwise.app", "password": "testpassword123", }, ) assert response.status_code == 400 assert "email already registered" in response.json()["detail"].lower() def test_login_success(self): """Test successful login.""" # Register first client.post( "/api/v1/auth/register", json={ "email": "login@wealthwise.app", "password": "testpassword123", }, ) # Login response = client.post( "/api/v1/auth/token", data={ "username": "login@wealthwise.app", "password": "testpassword123", }, ) assert response.status_code == 200 data = response.json() assert "access_token" in data assert data["token_type"] == "bearer" def test_login_invalid_credentials(self): """Test login with invalid credentials.""" response = client.post( "/api/v1/auth/token", data={ "username": "nonexistent@wealthwise.app", "password": "wrongpassword", }, ) assert response.status_code == 401 def test_login_wrong_password(self): """Test login with wrong password.""" # Register first client.post( "/api/v1/auth/register", json={ "email": "wrongpass@wealthwise.app", "password": "testpassword123", }, ) # Login with wrong password response = client.post( "/api/v1/auth/token", data={ "username": "wrongpass@wealthwise.app", "password": "wrongpassword", }, ) assert response.status_code == 401 class TestProtectedEndpoints: """Test cases for protected endpoints.""" def test_me_without_auth(self): """Test accessing /me without authentication.""" response = client.get("/api/v1/users/me") assert response.status_code == 401 def test_me_with_valid_token(self): """Test accessing /me with valid token.""" # Register and login register_response = client.post( "/api/v1/auth/register", json={ "email": "protected@wealthwise.app", "password": "testpassword123", }, ) login_response = client.post( "/api/v1/auth/token", data={ "username": "protected@wealthwise.app", "password": "testpassword123", }, ) token = login_response.json()["access_token"] # Access protected endpoint response = client.get( "/api/v1/users/me", headers={"Authorization": f"Bearer {token}"}, ) assert response.status_code == 200 data = response.json() assert data["email"] == "protected@wealthwise.app" def test_me_with_invalid_token(self): """Test accessing /me with invalid token.""" response = client.get( "/api/v1/users/me", headers={"Authorization": "Bearer invalid-token"}, ) assert response.status_code == 401