Files
core-api/tests/test_oidc.py
T
jpmschweitzerandClaude Opus 4.5 a22e168666 Improve test coverage to 65%
Add comprehensive test suites for:
- NPM client (27 tests)
- Ollama client (16 tests)
- AI client and controller (34 tests)
- Static controller (8 tests)
- Tools controller DNS lookup (9 tests)
- OIDC authentication (10 tests)
- Housekeeping endpoints (28 tests)
- Infrastructure endpoints (15 tests)
- Health endpoints (12 tests)
- Portainer client (12 tests)
- Home Assistant client (24 tests)

Total: 285 tests passing with 65% code coverage.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 16:32:39 +01:00

168 lines
5.3 KiB
Python

"""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')