mirror of
https://github.com/aljazceru/enclava.git
synced 2025-12-17 15:34:36 +01:00
fixing rag
This commit is contained in:
309
backend/tests/clients/nginx_test_client.py
Normal file
309
backend/tests/clients/nginx_test_client.py
Normal file
@@ -0,0 +1,309 @@
|
||||
"""
|
||||
Nginx reverse proxy test client for routing verification.
|
||||
"""
|
||||
|
||||
import aiohttp
|
||||
import asyncio
|
||||
from typing import Dict, List, Optional, Any, Union
|
||||
import json
|
||||
import time
|
||||
|
||||
|
||||
class NginxTestClient:
|
||||
"""Test client for nginx reverse proxy routing"""
|
||||
|
||||
def __init__(self, base_url: str = "http://localhost:3001"):
|
||||
self.base_url = base_url.rstrip('/')
|
||||
self.session_timeout = aiohttp.ClientTimeout(total=30)
|
||||
|
||||
async def test_route(self,
|
||||
path: str,
|
||||
method: str = "GET",
|
||||
headers: Optional[Dict[str, str]] = None,
|
||||
data: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
||||
"""Test a specific route through nginx"""
|
||||
url = f"{self.base_url}{path}"
|
||||
|
||||
async with aiohttp.ClientSession(timeout=self.session_timeout) as session:
|
||||
start_time = time.time()
|
||||
|
||||
try:
|
||||
async with session.request(
|
||||
method=method,
|
||||
url=url,
|
||||
headers=headers,
|
||||
json=data if data else None
|
||||
) as response:
|
||||
end_time = time.time()
|
||||
|
||||
# Read response
|
||||
try:
|
||||
response_data = await response.json()
|
||||
except:
|
||||
response_data = await response.text()
|
||||
|
||||
return {
|
||||
"url": url,
|
||||
"method": method,
|
||||
"status_code": response.status,
|
||||
"headers": dict(response.headers),
|
||||
"response_time": end_time - start_time,
|
||||
"response_data": response_data,
|
||||
"success": 200 <= response.status < 400
|
||||
}
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
return {
|
||||
"url": url,
|
||||
"method": method,
|
||||
"error": "timeout",
|
||||
"response_time": time.time() - start_time,
|
||||
"success": False
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
"url": url,
|
||||
"method": method,
|
||||
"error": str(e),
|
||||
"response_time": time.time() - start_time,
|
||||
"success": False
|
||||
}
|
||||
|
||||
async def test_public_api_routes(self) -> Dict[str, Any]:
|
||||
"""Test public API routing (/api/v1/)"""
|
||||
routes_to_test = [
|
||||
{"path": "/api/v1/models", "method": "GET", "expected_auth": True},
|
||||
{"path": "/api/v1/chat/completions", "method": "POST", "expected_auth": True},
|
||||
{"path": "/api/v1/embeddings", "method": "POST", "expected_auth": True},
|
||||
{"path": "/api/v1/health", "method": "GET", "expected_auth": False},
|
||||
]
|
||||
|
||||
results = {}
|
||||
|
||||
for route in routes_to_test:
|
||||
# Test without authentication
|
||||
result_unauth = await self.test_route(route["path"], route["method"])
|
||||
|
||||
# Test with authentication
|
||||
headers = {"Authorization": "Bearer test-api-key"}
|
||||
result_auth = await self.test_route(route["path"], route["method"], headers)
|
||||
|
||||
results[route["path"]] = {
|
||||
"unauthenticated": result_unauth,
|
||||
"authenticated": result_auth,
|
||||
"expects_auth": route["expected_auth"],
|
||||
"auth_working": (
|
||||
result_unauth["status_code"] == 401 and
|
||||
result_auth["status_code"] != 401
|
||||
) if route["expected_auth"] else True
|
||||
}
|
||||
|
||||
return results
|
||||
|
||||
async def test_internal_api_routes(self) -> Dict[str, Any]:
|
||||
"""Test internal API routing (/api-internal/v1/)"""
|
||||
routes_to_test = [
|
||||
{"path": "/api-internal/v1/auth/me", "method": "GET"},
|
||||
{"path": "/api-internal/v1/auth/register", "method": "POST"},
|
||||
{"path": "/api-internal/v1/chatbot/list", "method": "GET"},
|
||||
{"path": "/api-internal/v1/rag/collections", "method": "GET"},
|
||||
]
|
||||
|
||||
results = {}
|
||||
|
||||
for route in routes_to_test:
|
||||
# Test without authentication
|
||||
result_unauth = await self.test_route(route["path"], route["method"])
|
||||
|
||||
# Test with JWT token
|
||||
headers = {"Authorization": "Bearer test-jwt-token"}
|
||||
result_auth = await self.test_route(route["path"], route["method"], headers)
|
||||
|
||||
results[route["path"]] = {
|
||||
"unauthenticated": result_unauth,
|
||||
"authenticated": result_auth,
|
||||
"requires_auth": result_unauth["status_code"] == 401,
|
||||
"auth_working": result_unauth["status_code"] == 401 and result_auth["status_code"] != 401
|
||||
}
|
||||
|
||||
return results
|
||||
|
||||
async def test_frontend_routes(self) -> Dict[str, Any]:
|
||||
"""Test frontend routing"""
|
||||
routes_to_test = [
|
||||
"/",
|
||||
"/dashboard",
|
||||
"/chatbots",
|
||||
"/rag",
|
||||
"/settings",
|
||||
"/login"
|
||||
]
|
||||
|
||||
results = {}
|
||||
|
||||
for path in routes_to_test:
|
||||
result = await self.test_route(path)
|
||||
results[path] = {
|
||||
"status_code": result["status_code"],
|
||||
"response_time": result["response_time"],
|
||||
"serves_html": "text/html" in result["headers"].get("content-type", ""),
|
||||
"success": result["success"]
|
||||
}
|
||||
|
||||
return results
|
||||
|
||||
async def test_cors_headers(self) -> Dict[str, Any]:
|
||||
"""Test CORS headers configuration"""
|
||||
cors_tests = {}
|
||||
|
||||
# Test preflight request
|
||||
cors_headers = {
|
||||
"Origin": "http://localhost:3000",
|
||||
"Access-Control-Request-Method": "POST",
|
||||
"Access-Control-Request-Headers": "Authorization, Content-Type"
|
||||
}
|
||||
|
||||
preflight_result = await self.test_route("/api/v1/models", "OPTIONS", cors_headers)
|
||||
cors_tests["preflight"] = {
|
||||
"status_code": preflight_result["status_code"],
|
||||
"cors_headers": {
|
||||
k: v for k, v in preflight_result["headers"].items()
|
||||
if k.lower().startswith("access-control")
|
||||
}
|
||||
}
|
||||
|
||||
# Test actual CORS request
|
||||
request_headers = {"Origin": "http://localhost:3000"}
|
||||
cors_result = await self.test_route("/api/v1/models", "GET", request_headers)
|
||||
cors_tests["request"] = {
|
||||
"status_code": cors_result["status_code"],
|
||||
"cors_headers": {
|
||||
k: v for k, v in cors_result["headers"].items()
|
||||
if k.lower().startswith("access-control")
|
||||
}
|
||||
}
|
||||
|
||||
return cors_tests
|
||||
|
||||
async def test_websocket_support(self) -> Dict[str, Any]:
|
||||
"""Test WebSocket upgrade support for Next.js HMR"""
|
||||
ws_headers = {
|
||||
"Upgrade": "websocket",
|
||||
"Connection": "upgrade",
|
||||
"Sec-WebSocket-Key": "dGhlIHNhbXBsZSBub25jZQ==",
|
||||
"Sec-WebSocket-Version": "13"
|
||||
}
|
||||
|
||||
result = await self.test_route("/", "GET", ws_headers)
|
||||
|
||||
return {
|
||||
"status_code": result["status_code"],
|
||||
"upgrade_attempted": result["status_code"] in [101, 426], # 101 = Switching Protocols, 426 = Upgrade Required
|
||||
"connection_header": result["headers"].get("connection", "").lower(),
|
||||
"upgrade_header": result["headers"].get("upgrade", "").lower()
|
||||
}
|
||||
|
||||
async def test_health_endpoints(self) -> Dict[str, Any]:
|
||||
"""Test health check endpoints"""
|
||||
health_endpoints = [
|
||||
"/health",
|
||||
"/api/v1/health",
|
||||
"/test-status"
|
||||
]
|
||||
|
||||
results = {}
|
||||
|
||||
for endpoint in health_endpoints:
|
||||
result = await self.test_route(endpoint)
|
||||
results[endpoint] = {
|
||||
"status_code": result["status_code"],
|
||||
"response_time": result["response_time"],
|
||||
"response_data": result["response_data"],
|
||||
"healthy": result["status_code"] == 200
|
||||
}
|
||||
|
||||
return results
|
||||
|
||||
async def test_static_file_handling(self) -> Dict[str, Any]:
|
||||
"""Test static file serving and caching"""
|
||||
static_files = [
|
||||
"/_next/static/test.js",
|
||||
"/favicon.ico",
|
||||
"/static/test.css"
|
||||
]
|
||||
|
||||
results = {}
|
||||
|
||||
for file_path in static_files:
|
||||
result = await self.test_route(file_path)
|
||||
results[file_path] = {
|
||||
"status_code": result["status_code"],
|
||||
"cache_control": result["headers"].get("cache-control"),
|
||||
"expires": result["headers"].get("expires"),
|
||||
"content_type": result["headers"].get("content-type"),
|
||||
"cached": "cache-control" in result["headers"] or "expires" in result["headers"]
|
||||
}
|
||||
|
||||
return results
|
||||
|
||||
async def test_error_handling(self) -> Dict[str, Any]:
|
||||
"""Test nginx error handling"""
|
||||
error_tests = [
|
||||
{"path": "/nonexistent-page", "expected_status": 404},
|
||||
{"path": "/api/v1/nonexistent-endpoint", "expected_status": 404},
|
||||
{"path": "/api-internal/v1/nonexistent-endpoint", "expected_status": 404}
|
||||
]
|
||||
|
||||
results = {}
|
||||
|
||||
for test in error_tests:
|
||||
result = await self.test_route(test["path"])
|
||||
results[test["path"]] = {
|
||||
"actual_status": result["status_code"],
|
||||
"expected_status": test["expected_status"],
|
||||
"correct_error": result["status_code"] == test["expected_status"],
|
||||
"response_data": result["response_data"]
|
||||
}
|
||||
|
||||
return results
|
||||
|
||||
async def test_load_balancing(self, num_requests: int = 50) -> Dict[str, Any]:
|
||||
"""Test load balancing behavior with multiple requests"""
|
||||
async def make_request(request_id: int) -> Dict[str, Any]:
|
||||
result = await self.test_route("/health")
|
||||
return {
|
||||
"request_id": request_id,
|
||||
"status_code": result["status_code"],
|
||||
"response_time": result["response_time"],
|
||||
"success": result["success"]
|
||||
}
|
||||
|
||||
tasks = [make_request(i) for i in range(num_requests)]
|
||||
results = await asyncio.gather(*tasks)
|
||||
|
||||
success_count = sum(1 for r in results if r["success"])
|
||||
avg_response_time = sum(r["response_time"] for r in results) / len(results)
|
||||
|
||||
return {
|
||||
"total_requests": num_requests,
|
||||
"successful_requests": success_count,
|
||||
"failure_rate": (num_requests - success_count) / num_requests,
|
||||
"average_response_time": avg_response_time,
|
||||
"min_response_time": min(r["response_time"] for r in results),
|
||||
"max_response_time": max(r["response_time"] for r in results),
|
||||
"results": results
|
||||
}
|
||||
|
||||
async def run_comprehensive_test(self) -> Dict[str, Any]:
|
||||
"""Run all nginx tests"""
|
||||
return {
|
||||
"public_api_routes": await self.test_public_api_routes(),
|
||||
"internal_api_routes": await self.test_internal_api_routes(),
|
||||
"frontend_routes": await self.test_frontend_routes(),
|
||||
"cors_headers": await self.test_cors_headers(),
|
||||
"websocket_support": await self.test_websocket_support(),
|
||||
"health_endpoints": await self.test_health_endpoints(),
|
||||
"static_files": await self.test_static_file_handling(),
|
||||
"error_handling": await self.test_error_handling(),
|
||||
"load_test": await self.test_load_balancing(20) # Smaller load test
|
||||
}
|
||||
Reference in New Issue
Block a user