import pytest from fastapi.testclient import TestClient from unittest.mock import patch from ea_chatbot.api.main import app from ea_chatbot.history.models import User # We will need to mock HistoryManager and get_db dependencies later # For now, we define the expected behavior of the auth endpoints. @pytest.fixture def client(): return TestClient(app) @pytest.fixture def mock_user(): return User( id="user-123", username="test@example.com", display_name="Test User", password_hash="hashed_password", theme_preference="light" ) def test_register_user_success(client): """Test successful user registration.""" # We mock it where it is used in the router with patch("ea_chatbot.api.routers.auth.history_manager") as mock_hm: mock_hm.get_user.return_value = None mock_hm.create_user.return_value = User(id="1", username="new@example.com", display_name="New", theme_preference="light") response = client.post( "/api/v1/auth/register", json={"email": "new@example.com", "password": "password123", "display_name": "New"} ) assert response.status_code == 201 assert response.json()["email"] == "new@example.com" def test_login_success(client): """Test successful login and JWT return.""" with patch("ea_chatbot.api.routers.auth.history_manager") as mock_hm: mock_hm.authenticate_user.return_value = User(id="1", username="test@example.com") response = client.post( "/api/v1/auth/login", data={"username": "test@example.com", "password": "password123"} ) assert response.status_code == 200 assert "access_token" in response.json() assert response.json()["token_type"] == "bearer" def test_login_invalid_credentials(client): """Test login with wrong password.""" with patch("ea_chatbot.api.routers.auth.history_manager") as mock_hm: mock_hm.authenticate_user.return_value = None response = client.post( "/api/v1/auth/login", data={"username": "test@example.com", "password": "wrongpassword"} ) assert response.status_code == 401 assert "detail" in response.json() def test_protected_route_without_token(client): """Test that protected routes require a token.""" response = client.get("/api/v1/auth/me") assert response.status_code == 401 def test_oidc_login_redirect(client): """Test that OIDC login returns a redirect URL and sets session cookie.""" with patch("ea_chatbot.api.routers.auth.oidc_client") as mock_oidc: mock_oidc.get_auth_data.return_value = { "url": "https://oidc-provider.com/auth", "state": "test_state", "nonce": "test_nonce", "code_verifier": "test_verifier" } response = client.get("/api/v1/auth/oidc/login") assert response.status_code == 200 assert response.json()["url"] == "https://oidc-provider.com/auth" assert "oidc_session" in response.cookies def test_oidc_callback_success(client): """Test successful OIDC callback and JWT issuance.""" with patch("ea_chatbot.api.routers.auth.oidc_client") as mock_oidc, \ patch("ea_chatbot.api.routers.auth.OIDCSession.decrypt") as mock_decrypt, \ patch("ea_chatbot.api.routers.auth.history_manager") as mock_hm: mock_decrypt.return_value = { "state": "test_state", "nonce": "test_nonce", "code_verifier": "test_verifier" } mock_oidc.exchange_code_for_token.return_value = {"id_token": "fake_id_token"} mock_oidc.validate_id_token.return_value = {"email": "sso@example.com", "name": "SSO User"} mock_hm.sync_user_from_oidc.return_value = User(id="sso-123", username="sso@example.com", display_name="SSO User", theme_preference="light") client.cookies.set("oidc_session", "fake_token") response = client.get( "/api/v1/auth/oidc/callback?code=some-code&state=test_state", follow_redirects=False ) assert response.status_code == 302 assert "access_token" in response.cookies def test_get_me_success(client): """Test getting current user with a valid token.""" from ea_chatbot.api.utils import create_access_token token = create_access_token(data={"sub": "123"}) with patch("ea_chatbot.api.dependencies.history_manager") as mock_hm: mock_hm.get_user_by_id.return_value = User(id="123", username="test@example.com", display_name="Test", theme_preference="light") response = client.get( "/api/v1/auth/me", headers={"Authorization": f"Bearer {token}"} ) assert response.status_code == 200 assert response.json()["email"] == "test@example.com" assert response.json()["id"] == "123" def test_get_me_rejects_refresh_token(client): """Test that /auth/me rejects refresh tokens for authentication.""" from ea_chatbot.api.utils import create_refresh_token token = create_refresh_token(data={"sub": "123"}) with patch("ea_chatbot.api.dependencies.history_manager") as mock_hm: # Even if the user exists, the dependency should reject the token type mock_hm.get_user_by_id.return_value = User(id="123", username="test@example.com") response = client.get( "/api/v1/auth/me", headers={"Authorization": f"Bearer {token}"} ) assert response.status_code == 401 assert "Cannot use refresh token" in response.json()["detail"]