"""Unit tests for API dependencies.""" import pytest import base64 import json from unittest.mock import patch from fastapi import HTTPException class TestValidateBearerToken: """Test cases for bearer token validation dependency.""" def setup_method(self): """Set up test fixtures.""" # Create a valid JWT token for testing header = {"alg": "HS256", "typ": "JWT"} payload = {"sub": "1234567890", "name": "John Doe", "iat": 1516239022} header_b64 = base64.urlsafe_b64encode( json.dumps(header).encode() ).decode().rstrip('=') payload_b64 = base64.urlsafe_b64encode( json.dumps(payload).encode() ).decode().rstrip('=') self.valid_token = f"{header_b64}.{payload_b64}.test_signature" self.valid_auth_header = f"Bearer {self.valid_token}" @pytest.mark.asyncio async def test_validate_bearer_token_success(self): """Test successful bearer token validation.""" # Import here to avoid module loading issues during collection from interfaces.api.dependencies import validate_bearer_token result = await validate_bearer_token(self.valid_auth_header) assert result == self.valid_token @pytest.mark.asyncio async def test_validate_bearer_token_missing_header(self): """Test validation fails when Authorization header is missing.""" from interfaces.api.dependencies import validate_bearer_token with pytest.raises(HTTPException) as exc_info: await validate_bearer_token(None) assert exc_info.value.status_code == 401 assert "Missing Authorization header" in exc_info.value.detail assert exc_info.value.headers["WWW-Authenticate"] == "Bearer" @pytest.mark.asyncio async def test_validate_bearer_token_invalid_format(self): """Test validation fails for invalid Authorization header format.""" from interfaces.api.dependencies import validate_bearer_token with pytest.raises(HTTPException) as exc_info: await validate_bearer_token("Basic dXNlcjpwYXNz") # Basic auth instead of Bearer assert exc_info.value.status_code == 401 assert "Invalid Authorization header format" in exc_info.value.detail assert exc_info.value.headers["WWW-Authenticate"] == "Bearer" @pytest.mark.asyncio async def test_validate_bearer_token_missing_bearer_prefix(self): """Test validation fails when Bearer prefix is missing.""" from interfaces.api.dependencies import validate_bearer_token with pytest.raises(HTTPException) as exc_info: await validate_bearer_token(self.valid_token) # Token without "Bearer " prefix assert exc_info.value.status_code == 401 assert "Invalid Authorization header format" in exc_info.value.detail @pytest.mark.asyncio async def test_validate_bearer_token_empty_token(self): """Test validation fails for empty token after Bearer prefix.""" from interfaces.api.dependencies import validate_bearer_token with pytest.raises(HTTPException) as exc_info: await validate_bearer_token("Bearer ") # Bearer with no token assert exc_info.value.status_code == 401 assert "Empty bearer token" in exc_info.value.detail @pytest.mark.asyncio async def test_validate_bearer_token_invalid_jwt_structure(self): """Test validation fails for invalid JWT token structure.""" from interfaces.api.dependencies import validate_bearer_token with pytest.raises(HTTPException) as exc_info: await validate_bearer_token("Bearer invalid.token") # Invalid JWT structure assert exc_info.value.status_code == 401 assert "Invalid JWT token structure" in exc_info.value.detail @pytest.mark.asyncio async def test_validate_bearer_token_malformed_jwt(self): """Test validation fails for malformed JWT.""" from interfaces.api.dependencies import validate_bearer_token with pytest.raises(HTTPException) as exc_info: await validate_bearer_token("Bearer not_a_jwt_at_all") assert exc_info.value.status_code == 401 assert "Invalid JWT token structure" in exc_info.value.detail @pytest.mark.asyncio async def test_validate_bearer_token_case_sensitive(self): """Test that Bearer prefix is case sensitive.""" with pytest.raises(HTTPException) as exc_info: await validate_bearer_token(f"bearer {self.valid_token}") # lowercase 'bearer' assert exc_info.value.status_code == 401 assert "Invalid Authorization header format" in exc_info.value.detail @pytest.mark.asyncio async def test_validate_bearer_token_extra_spaces(self): """Test handling of extra spaces in Authorization header.""" # Should work with proper spacing result = await validate_bearer_token(f"Bearer {self.valid_token}") assert result == self.valid_token # Should fail with extra spaces with pytest.raises(HTTPException) as exc_info: await validate_bearer_token(f"Bearer {self.valid_token}") # Extra space assert exc_info.value.status_code == 401