Files
orion/tests/integration/middleware/test_middleware_stack.py

299 lines
13 KiB
Python

# 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.
"""
import pytest
from unittest.mock import patch
from middleware.context import RequestContext
@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."""
# Create a simple endpoint to inspect request state
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"
# Admin context typically doesn't require vendor, but might have one
# The key assertion is that context_type is correctly set to admin
def test_admin_subdomain_sets_admin_context(self, client):
"""Test that admin.* subdomain sets ADMIN context type."""
from fastapi import Request
from main import app
@app.get("/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
}
# Simulate request with admin subdomain
with patch('app.core.config.settings') as mock_settings:
mock_settings.platform_domain = "platform.com"
response = client.get(
"/test-admin-subdomain",
headers={"host": "admin.platform.com"}
)
assert response.status_code == 200
data = response.json()
assert data["context_type"] == "admin"
# ========================================================================
# 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.code if hasattr(request.state, 'vendor') else None
}
# Request with vendor subdomain
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.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("/test-execution-order")
async def test_execution_order(request: Request):
# If vendor context runs first, clean_path should be available
# before context detection uses it
return {
"has_vendor": hasattr(request.state, 'vendor'),
"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(
"/test-execution-order",
headers={"host": f"{vendor_with_subdomain.subdomain}.platform.com"}
)
assert response.status_code == 200
data = response.json()
# All middleware should have run and set their state
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("/test-theme-loading")
async def test_theme_loading(request: Request):
return {
"has_vendor": hasattr(request.state, 'vendor'),
"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(
"/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."""
# Static file requests should not trigger vendor detection
response = client.get("/static/css/style.css")
# We expect 404 (file doesn't exist) but middleware should have run
# The important thing is it doesn't crash trying to detect vendor
assert response.status_code in [404, 200] # Depending on if file exists
# ========================================================================
# 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("/test-missing-vendor")
async def test_missing_vendor(request: Request):
return {
"has_vendor": hasattr(request.state, 'vendor'),
"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(
"/test-missing-vendor",
headers={"host": "nonexistent.platform.com"}
)
assert response.status_code == 200
data = response.json()
# Should handle missing vendor gracefully
assert data["has_vendor"] is False or data["vendor"] is None
# Should still set a context type (fallback)
assert data["context_type"] is not None
def test_inactive_vendor_not_loaded(self, client, inactive_vendor):
"""Test that inactive vendors are not loaded."""
from fastapi import Request
from main import app
@app.get("/test-inactive-vendor")
async def test_inactive_vendor_endpoint(request: Request):
return {
"has_vendor": hasattr(request.state, 'vendor'),
"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(
"/test-inactive-vendor",
headers={"host": f"{inactive_vendor.subdomain}.platform.com"}
)
assert response.status_code == 200
data = response.json()
# Inactive vendor should not be loaded
assert data["has_vendor"] is False or data["vendor"] is None