"""Tests for OIDC authentication module.""" import pytest from unittest.mock import patch, MagicMock, AsyncMock from fastapi import HTTPException from src.auth.oidc import OIDCConfig, oidc_config, get_jwks, get_current_user class TestOIDCConfig: """Test OIDCConfig class.""" def test_init_defaults(self): """Config should initialize with disabled state.""" config = OIDCConfig() assert config.enabled is False assert config.issuer == "" assert config.audience == "" assert config.jwks_uri == "" def test_configure_sets_values(self): """configure should set all values.""" config = OIDCConfig() config.configure( enabled=True, issuer="https://auth.example.com", audience="core-api" ) assert config.enabled is True assert config.issuer == "https://auth.example.com" assert config.audience == "core-api" assert config.jwks_uri == "https://auth.example.com/jwks/" def test_configure_strips_trailing_slash(self): """configure should handle trailing slash in issuer.""" config = OIDCConfig() config.configure( enabled=True, issuer="https://auth.example.com/", audience="core-api" ) assert config.jwks_uri == "https://auth.example.com/jwks/" class TestGetJWKS: """Test get_jwks function.""" def test_returns_empty_when_disabled(self): """get_jwks should return empty dict when OIDC disabled.""" # Save original state original_enabled = oidc_config.enabled try: oidc_config.enabled = False # Clear the cache get_jwks.cache_clear() result = get_jwks() assert result == {} finally: # Restore original state oidc_config.enabled = original_enabled get_jwks.cache_clear() @patch("src.auth.oidc.httpx.get") def test_fetches_jwks_when_enabled(self, mock_get): """get_jwks should fetch JWKS when enabled.""" # Save original state original_enabled = oidc_config.enabled original_jwks_uri = oidc_config.jwks_uri try: oidc_config.enabled = True oidc_config.jwks_uri = "https://auth.example.com/jwks/" get_jwks.cache_clear() mock_response = MagicMock() mock_response.json.return_value = {"keys": [{"kid": "test"}]} mock_response.raise_for_status = MagicMock() mock_get.return_value = mock_response result = get_jwks() assert "keys" in result mock_get.assert_called_once() finally: oidc_config.enabled = original_enabled oidc_config.jwks_uri = original_jwks_uri get_jwks.cache_clear() @patch("src.auth.oidc.httpx.get") def test_raises_exception_on_error(self, mock_get): """get_jwks should raise HTTPException on fetch error.""" # Save original state original_enabled = oidc_config.enabled original_jwks_uri = oidc_config.jwks_uri try: oidc_config.enabled = True oidc_config.jwks_uri = "https://auth.example.com/jwks/" get_jwks.cache_clear() mock_get.side_effect = Exception("Connection error") with pytest.raises(HTTPException) as exc_info: get_jwks() assert exc_info.value.status_code == 503 finally: oidc_config.enabled = original_enabled oidc_config.jwks_uri = original_jwks_uri get_jwks.cache_clear() class TestGetCurrentUser: """Test get_current_user function.""" @pytest.mark.asyncio async def test_returns_none_when_disabled(self): """get_current_user should return None when OIDC disabled.""" # Save original state original_enabled = oidc_config.enabled try: oidc_config.enabled = False result = await get_current_user(credentials=None) assert result is None finally: oidc_config.enabled = original_enabled @pytest.mark.asyncio async def test_raises_401_when_enabled_without_token(self): """get_current_user should raise 401 when enabled but no token.""" # Save original state original_enabled = oidc_config.enabled try: oidc_config.enabled = True with pytest.raises(HTTPException) as exc_info: await get_current_user(credentials=None) assert exc_info.value.status_code == 401 finally: oidc_config.enabled = original_enabled class TestOIDCGlobalConfig: """Test global OIDC config.""" def test_global_config_exists(self): """oidc_config should be an OIDCConfig instance.""" assert isinstance(oidc_config, OIDCConfig) def test_global_config_starts_disabled(self): """oidc_config should start disabled by default.""" # This tests the initial state before any configure() is called # The actual state depends on app configuration assert hasattr(oidc_config, 'enabled') assert hasattr(oidc_config, 'issuer') assert hasattr(oidc_config, 'audience') assert hasattr(oidc_config, 'jwks_uri')