Add forecasting service
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
# ================================================================
|
||||
# Performance Tests: tests/performance/test_forecasting_performance.py
|
||||
# ================================================================
|
||||
"""
|
||||
Performance tests for forecasting service
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import httpx
|
||||
import asyncio
|
||||
import time
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
import statistics
|
||||
|
||||
class TestForecastingPerformance:
|
||||
"""Performance tests for forecasting operations"""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_single_forecast_performance(self):
|
||||
"""Test single forecast generation performance"""
|
||||
|
||||
base_url = "http://localhost:8000"
|
||||
|
||||
forecast_request = {
|
||||
"tenant_id": "perf-test-tenant",
|
||||
"product_name": "Pan Integral",
|
||||
"location": "madrid_centro",
|
||||
"forecast_date": "2024-01-17",
|
||||
"business_type": "individual",
|
||||
"confidence_level": 0.8
|
||||
}
|
||||
|
||||
times = []
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
for _ in range(10):
|
||||
start_time = time.time()
|
||||
|
||||
response = await client.post(
|
||||
f"{base_url}/api/v1/forecasting/single",
|
||||
json=forecast_request
|
||||
)
|
||||
|
||||
end_time = time.time()
|
||||
times.append(end_time - start_time)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
# Performance assertions
|
||||
avg_time = statistics.mean(times)
|
||||
p95_time = statistics.quantiles(times, n=20)[18] # 95th percentile
|
||||
|
||||
assert avg_time < 2.0, f"Average response time {avg_time}s exceeds 2s"
|
||||
assert p95_time < 5.0, f"95th percentile {p95_time}s exceeds 5s"
|
||||
|
||||
print(f"Average response time: {avg_time:.2f}s")
|
||||
print(f"95th percentile: {p95_time:.2f}s")
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_concurrent_forecasts(self):
|
||||
"""Test concurrent forecast generation"""
|
||||
|
||||
base_url = "http://localhost:8000"
|
||||
|
||||
async def make_forecast_request(product_id):
|
||||
forecast_request = {
|
||||
"tenant_id": "perf-test-tenant",
|
||||
"product_name": f"Product_{product_id}",
|
||||
"location": "madrid_centro",
|
||||
"forecast_date": "2024-01-17",
|
||||
"business_type": "individual"
|
||||
}
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
start_time = time.time()
|
||||
response = await client.post(
|
||||
f"{base_url}/api/v1/forecasting/single",
|
||||
json=forecast_request
|
||||
)
|
||||
end_time = time.time()
|
||||
|
||||
return {
|
||||
"status_code": response.status_code,
|
||||
"response_time": end_time - start_time,
|
||||
"product_id": product_id
|
||||
}
|
||||
|
||||
# Run 20 concurrent requests
|
||||
tasks = [make_forecast_request(i) for i in range(20)]
|
||||
results = await asyncio.gather(*tasks, return_exceptions=True)
|
||||
|
||||
# Analyze results
|
||||
successful = [r for r in results if isinstance(r, dict) and r["status_code"] == 200]
|
||||
failed = [r for r in results if not isinstance(r, dict) or r["status_code"] != 200]
|
||||
|
||||
success_rate = len(successful) / len(results)
|
||||
|
||||
assert success_rate >= 0.95, f"Success rate {success_rate} below 95%"
|
||||
|
||||
if successful:
|
||||
avg_concurrent_time = statistics.mean([r["response_time"] for r in successful])
|
||||
assert avg_concurrent_time < 10.0, f"Average concurrent time {avg_concurrent_time}s exceeds 10s"
|
||||
|
||||
print(f"Concurrent success rate: {success_rate:.2%}")
|
||||
print(f"Average concurrent response time: {avg_concurrent_time:.2f}s")
|
||||
|
||||
Reference in New Issue
Block a user