diff --git a/tests/unit/middleware/test_auth.py b/tests/unit/middleware/test_auth.py index 031c4e81..d998b4cb 100644 --- a/tests/unit/middleware/test_auth.py +++ b/tests/unit/middleware/test_auth.py @@ -16,6 +16,7 @@ import pytest from unittest.mock import Mock, MagicMock, patch from datetime import datetime, timedelta, timezone from jose import jwt +from fastapi import HTTPException from middleware.auth import AuthManager from app.exceptions import ( @@ -350,6 +351,26 @@ class TestJWTTokenVerification: with pytest.raises(InvalidTokenException): auth_manager.verify_token(token) + def test_verify_token_additional_expiration_check(self): + """Test the additional expiration check after jwt.decode.""" + auth_manager = AuthManager() + + # Create a token with expiration in the past + past_time = datetime.now(timezone.utc) - timedelta(minutes=1) + payload = { + "sub": "1", + "username": "testuser", + "exp": past_time.timestamp() + } + token = jwt.encode(payload, auth_manager.secret_key, algorithm=auth_manager.algorithm) + + # Mock jwt.decode to bypass its expiration check and test line 205 + with patch('middleware.auth.jwt.decode') as mock_decode: + mock_decode.return_value = payload + + with pytest.raises(TokenExpiredException): + auth_manager.verify_token(token) + @pytest.mark.unit @pytest.mark.auth @@ -661,3 +682,62 @@ class TestEdgeCases: # Result depends on how the filter is implemented # This test documents the expected behavior assert result is None or result is mock_user + + def test_verify_token_unexpected_exception(self): + """Test generic exception handler in verify_token.""" + auth_manager = AuthManager() + + # Create a valid token with a mock user + mock_user = Mock(spec=User) + mock_user.id = 1 + mock_user.username = "test" + mock_user.email = "test@example.com" + mock_user.role = "user" + + token_data = auth_manager.create_access_token(mock_user) + token = token_data["access_token"] + + # Mock jose.jwt.decode to raise an unexpected exception + with patch('middleware.auth.jwt.decode', side_effect=RuntimeError("Unexpected error")): + with pytest.raises(InvalidTokenException) as exc_info: + auth_manager.verify_token(token) + + # The message should be "Authentication failed" from the generic except handler + assert "Authentication failed" in str(exc_info.value.message) + + def test_require_role_decorator_wrapper_functionality(self): + """Test the require_role decorator wrapper execution.""" + auth_manager = AuthManager() + + # Create a test function decorated with require_role + @auth_manager.require_role("admin") + def test_function(current_user, additional_arg=None): + return {"user": current_user.username, "arg": additional_arg} + + # Test successful case - user has required role + admin_user = Mock(spec=User) + admin_user.role = "admin" + admin_user.username = "admin_user" + + result = test_function(admin_user, additional_arg="test_value") + + assert result["user"] == "admin_user" + assert result["arg"] == "test_value" + + def test_require_role_decorator_blocks_wrong_role(self): + """Test that require_role decorator blocks users with wrong role.""" + auth_manager = AuthManager() + + @auth_manager.require_role("admin") + def admin_only_function(current_user): + return {"status": "success"} + + # Test with user that has wrong role + regular_user = Mock(spec=User) + regular_user.role = "user" + + with pytest.raises(HTTPException) as exc_info: + admin_only_function(regular_user) + + assert exc_info.value.status_code == 403 + assert "Required role 'admin' not found" in exc_info.value.detail diff --git a/tests/unit/middleware/test_vendor_context.py b/tests/unit/middleware/test_vendor_context.py index 56ca72ca..3071b092 100644 --- a/tests/unit/middleware/test_vendor_context.py +++ b/tests/unit/middleware/test_vendor_context.py @@ -435,6 +435,10 @@ class TestVendorContextManager: "/image.jpg", "/style.css", "/app.webmanifest", + "/static/", # Path starting with /static/ but no extension + "/media/uploads", # Path starting with /media/ but no extension + "/subfolder/favicon.ico", # favicon.ico in subfolder + "/favicon.ico.bak", # Contains favicon.ico but doesn't end with static extension (hits line 226) ]) def test_is_static_file_request(self, path): """Test static file detection for various paths and extensions.""" @@ -719,3 +723,23 @@ class TestEdgeCases: # Should detect 'shop' as subdomain since it's the first part assert context["detection_method"] == "subdomain" assert context["subdomain"] == "shop" + + def test_get_vendor_logs_warning_when_not_found_subdomain(self): + """Test that warning is logged when vendor is not found by subdomain.""" + mock_db = Mock() + # Mock the complete query chain properly - need to mock filter twice and then first + mock_query = mock_db.query.return_value + mock_filter1 = mock_query.filter.return_value + mock_filter2 = mock_filter1.filter.return_value + mock_filter2.first.return_value = None + + context = {"subdomain": "nonexistent", "detection_method": "subdomain"} + + with patch('middleware.vendor_context.logger') as mock_logger: + vendor = VendorContextManager.get_vendor_from_context(mock_db, context) + + assert vendor is None + # Verify warning was logged + mock_logger.warning.assert_called() + warning_message = str(mock_logger.warning.call_args) + assert "No active vendor found for subdomain" in warning_message and "nonexistent" in warning_message