# tests/integration/middleware/test_middleware_stack.py """ Integration tests for the complete middleware stack. These tests verify that all middleware components work together correctly through real HTTP requests, ensuring proper execution order and state injection. Note: Test routes use /api/test-*, /admin/test-*, /vendor/test-*, or /shop/test-* prefixes to avoid being caught by the platform's /{slug} catch-all route. """ from unittest.mock import patch import pytest @pytest.mark.integration @pytest.mark.middleware class TestMiddlewareStackIntegration: """Test the full middleware stack with real HTTP requests.""" # ======================================================================== # Admin Context Tests # ======================================================================== def test_admin_path_sets_admin_context(self, client): """Test that /admin/* paths set ADMIN context type.""" from fastapi import Request from main import app @app.get("/admin/test-context") async def test_admin_context(request: Request): return { "context_type": ( request.state.context_type.value if hasattr(request.state, "context_type") else None ), "has_vendor": hasattr(request.state, "vendor") and request.state.vendor is not None, "has_theme": hasattr(request.state, "theme"), } response = client.get("/admin/test-context") assert response.status_code == 200 data = response.json() assert data["context_type"] == "admin" def test_admin_subdomain_sets_admin_context(self, client): """Test that admin.* subdomain with API path sets context correctly.""" from fastapi import Request from main import app @app.get("/api/test-admin-subdomain") async def test_admin_subdomain(request: Request): return { "context_type": ( request.state.context_type.value if hasattr(request.state, "context_type") else None ) } with patch("app.core.config.settings") as mock_settings: mock_settings.platform_domain = "platform.com" response = client.get( "/api/test-admin-subdomain", headers={"host": "admin.platform.com"} ) assert response.status_code == 200 data = response.json() # API path takes precedence assert data["context_type"] == "api" # ======================================================================== # API Context Tests # ======================================================================== def test_api_path_sets_api_context(self, client): """Test that /api/* paths set API context type.""" from fastapi import Request from main import app @app.get("/api/test-context") async def test_api_context(request: Request): return { "context_type": ( request.state.context_type.value if hasattr(request.state, "context_type") else None ) } response = client.get("/api/test-context") assert response.status_code == 200 data = response.json() assert data["context_type"] == "api" # ======================================================================== # Vendor Dashboard Context Tests # ======================================================================== def test_vendor_dashboard_path_sets_vendor_context( self, client, vendor_with_subdomain ): """Test that /vendor/* paths with vendor set VENDOR_DASHBOARD context.""" from fastapi import Request from main import app @app.get("/vendor/test-context") async def test_vendor_context(request: Request): return { "context_type": ( request.state.context_type.value if hasattr(request.state, "context_type") else None ), "vendor_id": ( request.state.vendor_id if hasattr(request.state, "vendor_id") else None ), "vendor_code": ( request.state.vendor.vendor_code if hasattr(request.state, "vendor") and request.state.vendor else None ), } with patch("app.core.config.settings") as mock_settings: mock_settings.platform_domain = "platform.com" response = client.get( "/vendor/test-context", headers={"host": f"{vendor_with_subdomain.subdomain}.platform.com"}, ) assert response.status_code == 200 data = response.json() assert data["context_type"] == "vendor_dashboard" assert data["vendor_id"] == vendor_with_subdomain.id assert data["vendor_code"] == vendor_with_subdomain.vendor_code # ======================================================================== # Shop Context Tests # ======================================================================== def test_shop_path_with_subdomain_sets_shop_context( self, client, vendor_with_subdomain ): """Test that /shop/* paths with vendor subdomain set SHOP context.""" from fastapi import Request from main import app @app.get("/shop/test-context") async def test_shop_context(request: Request): return { "context_type": ( request.state.context_type.value if hasattr(request.state, "context_type") else None ), "vendor_id": ( request.state.vendor_id if hasattr(request.state, "vendor_id") else None ), "has_theme": hasattr(request.state, "theme"), } with patch("app.core.config.settings") as mock_settings: mock_settings.platform_domain = "platform.com" response = client.get( "/shop/test-context", headers={"host": f"{vendor_with_subdomain.subdomain}.platform.com"}, ) assert response.status_code == 200 data = response.json() assert data["context_type"] == "shop" assert data["vendor_id"] == vendor_with_subdomain.id assert data["has_theme"] is True def test_shop_path_with_custom_domain_sets_shop_context( self, client, vendor_with_custom_domain ): """Test that /shop/* paths with custom domain set SHOP context.""" from fastapi import Request from main import app @app.get("/shop/test-custom-domain") async def test_shop_custom_domain(request: Request): return { "context_type": ( request.state.context_type.value if hasattr(request.state, "context_type") else None ), "vendor_id": ( request.state.vendor_id if hasattr(request.state, "vendor_id") else None ), } with patch("app.core.config.settings") as mock_settings: mock_settings.platform_domain = "platform.com" response = client.get( "/shop/test-custom-domain", headers={"host": "customdomain.com"} ) assert response.status_code == 200 data = response.json() assert data["context_type"] == "shop" assert data["vendor_id"] == vendor_with_custom_domain.id # ======================================================================== # Middleware Execution Order Tests # ======================================================================== def test_vendor_context_runs_before_context_detection( self, client, vendor_with_subdomain ): """Test that VendorContextMiddleware runs before ContextDetectionMiddleware.""" from fastapi import Request from main import app @app.get("/api/test-execution-order") async def test_execution_order(request: Request): return { "has_vendor": hasattr(request.state, "vendor") and request.state.vendor is not None, "has_clean_path": hasattr(request.state, "clean_path"), "has_context_type": hasattr(request.state, "context_type"), } with patch("app.core.config.settings") as mock_settings: mock_settings.platform_domain = "platform.com" response = client.get( "/api/test-execution-order", headers={"host": f"{vendor_with_subdomain.subdomain}.platform.com"}, ) assert response.status_code == 200 data = response.json() assert data["has_vendor"] is True assert data["has_clean_path"] is True assert data["has_context_type"] is True def test_theme_context_runs_after_vendor_context(self, client, vendor_with_theme): """Test that ThemeContextMiddleware runs after VendorContextMiddleware.""" from fastapi import Request from main import app @app.get("/api/test-theme-loading") async def test_theme_loading(request: Request): return { "has_vendor": hasattr(request.state, "vendor") and request.state.vendor is not None, "has_theme": hasattr(request.state, "theme"), "theme_primary_color": ( request.state.theme.get("primary_color") if hasattr(request.state, "theme") else None ), } with patch("app.core.config.settings") as mock_settings: mock_settings.platform_domain = "platform.com" response = client.get( "/api/test-theme-loading", headers={"host": f"{vendor_with_theme.subdomain}.platform.com"}, ) assert response.status_code == 200 data = response.json() assert data["has_vendor"] is True assert data["has_theme"] is True assert data["theme_primary_color"] == "#FF5733" # ======================================================================== # Static File Handling Tests # ======================================================================== def test_static_files_skip_vendor_detection(self, client): """Test that static file requests skip vendor detection.""" response = client.get("/static/css/style.css") # We expect 404 (file doesn't exist) but middleware should have run assert response.status_code in [404, 200] # ======================================================================== # Error Handling Tests # ======================================================================== def test_missing_vendor_graceful_handling(self, client): """Test that missing vendor is handled gracefully.""" from fastapi import Request from main import app @app.get("/api/test-missing-vendor") async def test_missing_vendor(request: Request): return { "has_vendor": hasattr(request.state, "vendor") and request.state.vendor is not None, "vendor": ( request.state.vendor if hasattr(request.state, "vendor") else None ), "context_type": ( request.state.context_type.value if hasattr(request.state, "context_type") else None ), } with patch("app.core.config.settings") as mock_settings: mock_settings.platform_domain = "platform.com" response = client.get( "/api/test-missing-vendor", headers={"host": "nonexistent.platform.com"} ) assert response.status_code == 200 data = response.json() assert data["has_vendor"] is False or data["vendor"] is None assert data["context_type"] is not None def test_inactive_vendor_not_loaded(self, client, middleware_inactive_vendor): """Test that inactive vendors are not loaded.""" from fastapi import Request from main import app @app.get("/api/test-inactive-vendor") async def test_inactive_vendor_endpoint(request: Request): return { "has_vendor": hasattr(request.state, "vendor") and request.state.vendor is not None, "vendor": ( request.state.vendor if hasattr(request.state, "vendor") else None ), } with patch("app.core.config.settings") as mock_settings: mock_settings.platform_domain = "platform.com" response = client.get( "/api/test-inactive-vendor", headers={ "host": f"{middleware_inactive_vendor.subdomain}.platform.com" }, ) assert response.status_code == 200 data = response.json() assert data["has_vendor"] is False or data["vendor"] is None