- FastAPI application with OpenTelemetry instrumentation - Redis caching and Celery task processing - Docker Compose setup with monitoring stack - Grafana dashboards and Prometheus metrics - Jaeger distributed tracing - Comprehensive documentation in docs/ folder - Monitoring configuration and troubleshooting guides
230 lines
8.2 KiB
Python
230 lines
8.2 KiB
Python
"""
|
||
Test script demonstrating Redis caching in Dice Roll and Fibonacci APIs
|
||
"""
|
||
import requests
|
||
import time
|
||
|
||
BASE_URL = "http://localhost:8000"
|
||
|
||
def print_header(title):
|
||
print("\n" + "=" * 70)
|
||
print(f" {title}")
|
||
print("=" * 70)
|
||
|
||
def print_section(title):
|
||
print(f"\n{title}")
|
||
print("-" * 70)
|
||
|
||
def test_dice_with_caching():
|
||
"""Test dice roll API with Redis caching"""
|
||
print_header("DICE ROLL API - Redis Caching Test")
|
||
|
||
session_id = "player_123"
|
||
|
||
# First roll - should generate fresh results and cache them
|
||
print_section("1️⃣ First Roll (Fresh - should cache)")
|
||
response = requests.get(f"{BASE_URL}/api/dice/roll", params={
|
||
"session_id": session_id,
|
||
"use_cache": True
|
||
})
|
||
data1 = response.json()
|
||
print(f" Session ID: {data1['session_id']}")
|
||
print(f" Total Rolls: {data1['total']}")
|
||
print(f" Statistics: {data1['statistics']}")
|
||
print(f" Source: {data1['source']}")
|
||
print(f" Cache Key: {data1['cache_key']}")
|
||
print(f" Status: {response.status_code}")
|
||
|
||
# Second roll - should return cached results (same rolls)
|
||
print_section("2️⃣ Second Roll (Same Session - should hit cache)")
|
||
response = requests.get(f"{BASE_URL}/api/dice/roll", params={
|
||
"session_id": session_id,
|
||
"use_cache": True
|
||
})
|
||
data2 = response.json()
|
||
print(f" Source: {data2['source']}")
|
||
print(f" Total Rolls: {data2['total']}")
|
||
print(f" Statistics: {data2['statistics']}")
|
||
print(f" Same results as first roll: {data1['dice_rolls'] == data2['dice_rolls']}")
|
||
print(f" Status: {response.status_code}")
|
||
|
||
# Third roll - different session, fresh results
|
||
print_section("3️⃣ Third Roll (Different Session - fresh)")
|
||
response = requests.get(f"{BASE_URL}/api/dice/roll", params={
|
||
"session_id": "player_456",
|
||
"use_cache": True
|
||
})
|
||
data3 = response.json()
|
||
print(f" Session ID: {data3['session_id']}")
|
||
print(f" Source: {data3['source']}")
|
||
print(f" Total Rolls: {data3['total']}")
|
||
print(f" Statistics: {data3['statistics']}")
|
||
print(f" Status: {response.status_code}")
|
||
|
||
# Fourth roll - cache disabled
|
||
print_section("4️⃣ Fourth Roll (Cache Disabled)")
|
||
response = requests.get(f"{BASE_URL}/api/dice/roll", params={
|
||
"session_id": session_id,
|
||
"use_cache": False
|
||
})
|
||
data4 = response.json()
|
||
print(f" Source: {data4['source']}")
|
||
print(f" Statistics: {data4['statistics']}")
|
||
print(f" Different from cached: {data1['dice_rolls'] != data4['dice_rolls']}")
|
||
print(f" Status: {response.status_code}")
|
||
|
||
def test_fibonacci_with_caching():
|
||
"""Test Fibonacci API with Redis caching"""
|
||
print_header("FIBONACCI API - Redis Caching Test")
|
||
|
||
# Test with n=10
|
||
n = 10
|
||
|
||
# First request - should compute and cache
|
||
print_section(f"1️⃣ First Request (n={n}) - Fresh Computation")
|
||
start = time.time()
|
||
response = requests.post(f"{BASE_URL}/api/tasks/fibonacci", params={
|
||
"n": n,
|
||
"use_cache": True
|
||
})
|
||
elapsed1 = time.time() - start
|
||
data1 = response.json()
|
||
print(f" n: {data1['n']}")
|
||
print(f" Status: {data1['status']}")
|
||
print(f" Source: {data1['source']}")
|
||
print(f" Response Time: {elapsed1:.3f}s")
|
||
print(f" Cache Key: {data1['cache_key']}")
|
||
|
||
if data1['source'] == 'celery_task':
|
||
print(f" Task ID: {data1['task_id']}")
|
||
print(f" Check result at: {data1['check_result_at']}")
|
||
|
||
# Wait for task completion
|
||
print("\n ⏳ Waiting for task to complete...")
|
||
time.sleep(2)
|
||
|
||
# Get result
|
||
task_response = requests.get(f"{BASE_URL}/api/tasks/{data1['task_id']}")
|
||
task_data = task_response.json()
|
||
print(f" ✅ Task Status: {task_data['status']}")
|
||
if task_data['status'] == 'completed':
|
||
result = task_data['result']
|
||
print(f" Result: Fibonacci({n}) = {result.get('result', result.get('fibonacci'))}")
|
||
print(f" Computation Time: {result.get('computation_time_seconds', 'N/A')}s")
|
||
else:
|
||
print(f" ✅ Result: Fibonacci({n}) = {data1['result']}")
|
||
|
||
# Second request - should hit cache immediately
|
||
print_section(f"2️⃣ Second Request (n={n}) - Should Hit Cache")
|
||
start = time.time()
|
||
response = requests.post(f"{BASE_URL}/api/tasks/fibonacci", params={
|
||
"n": n,
|
||
"use_cache": True
|
||
})
|
||
elapsed2 = time.time() - start
|
||
data2 = response.json()
|
||
print(f" Status: {data2['status']}")
|
||
print(f" Source: {data2['source']}")
|
||
print(f" Response Time: {elapsed2:.3f}s")
|
||
print(f" Result: Fibonacci({n}) = {data2.get('result', 'N/A')}")
|
||
print(f" 🚀 Speedup: {elapsed1/elapsed2:.1f}x faster!")
|
||
|
||
# Third request - cache disabled, force recomputation
|
||
print_section(f"3️⃣ Third Request (n={n}) - Cache Disabled")
|
||
start = time.time()
|
||
response = requests.post(f"{BASE_URL}/api/tasks/fibonacci", params={
|
||
"n": n,
|
||
"use_cache": False
|
||
})
|
||
elapsed3 = time.time() - start
|
||
data3 = response.json()
|
||
print(f" Status: {data3['status']}")
|
||
print(f" Source: {data3['source']}")
|
||
print(f" Response Time: {elapsed3:.3f}s")
|
||
|
||
# Test with larger number
|
||
n_large = 20
|
||
print_section(f"4️⃣ Large Fibonacci (n={n_large}) - First Request")
|
||
start = time.time()
|
||
response = requests.post(f"{BASE_URL}/api/tasks/fibonacci", params={
|
||
"n": n_large,
|
||
"use_cache": True
|
||
})
|
||
elapsed_large1 = time.time() - start
|
||
data_large = response.json()
|
||
print(f" Source: {data_large['source']}")
|
||
print(f" Response Time: {elapsed_large1:.3f}s")
|
||
|
||
if data_large['source'] == 'celery_task':
|
||
print(f" Task ID: {data_large['task_id']}")
|
||
print("\n ⏳ Waiting for computation...")
|
||
time.sleep(3)
|
||
|
||
task_response = requests.get(f"{BASE_URL}/api/tasks/{data_large['task_id']}")
|
||
task_data = task_response.json()
|
||
if task_data['status'] == 'completed':
|
||
result = task_data['result']
|
||
print(f" ✅ Result: Fibonacci({n_large}) = {result.get('result', result.get('fibonacci'))}")
|
||
|
||
# Cached request for large number
|
||
print_section(f"5️⃣ Large Fibonacci (n={n_large}) - Cached Request")
|
||
start = time.time()
|
||
response = requests.post(f"{BASE_URL}/api/tasks/fibonacci", params={
|
||
"n": n_large,
|
||
"use_cache": True
|
||
})
|
||
elapsed_large2 = time.time() - start
|
||
data_large2 = response.json()
|
||
print(f" Source: {data_large2['source']}")
|
||
print(f" Response Time: {elapsed_large2:.3f}s")
|
||
if data_large2['source'] == 'cache':
|
||
print(f" ✅ Result: Fibonacci({n_large}) = {data_large2['result']}")
|
||
print(f" 🚀 Much faster with cache!")
|
||
|
||
def test_cache_stats():
|
||
"""Display Redis cache statistics"""
|
||
print_header("REDIS CACHE STATISTICS")
|
||
|
||
response = requests.get(f"{BASE_URL}/api/cache/stats")
|
||
data = response.json()
|
||
stats = data['stats']
|
||
|
||
print(f"\n Memory Used: {stats['used_memory']}")
|
||
print(f" Total Keys: {stats['total_keys']}")
|
||
print(f" Connected Clients: {stats['connected_clients']}")
|
||
print(f" Cache Hits: {stats['hits']}")
|
||
print(f" Cache Misses: {stats['misses']}")
|
||
print(f" Hit Ratio: {stats['hit_ratio_percent']}%")
|
||
print(f" Uptime: {stats['uptime_seconds']} seconds")
|
||
|
||
def main():
|
||
print("\n" + "🎲" * 35)
|
||
print(" Redis Caching Test Suite for DevServer API")
|
||
print("🎲" * 35)
|
||
|
||
try:
|
||
# Test Dice Roll API
|
||
test_dice_with_caching()
|
||
|
||
# Test Fibonacci API
|
||
test_fibonacci_with_caching()
|
||
|
||
# Display cache statistics
|
||
test_cache_stats()
|
||
|
||
print("\n" + "=" * 70)
|
||
print(" ✅ All tests completed successfully!")
|
||
print("=" * 70)
|
||
print("\n💡 Key Takeaways:")
|
||
print(" • Dice rolls are cached per session (5 min TTL)")
|
||
print(" • Fibonacci results are cached globally (1 hour TTL)")
|
||
print(" • Cache dramatically improves response times")
|
||
print(" • Both APIs support cache bypass with use_cache=false")
|
||
print("\n")
|
||
|
||
except Exception as e:
|
||
print(f"\n❌ Error: {e}")
|
||
|
||
if __name__ == "__main__":
|
||
main()
|