""" Complete API Test Suite Tests all endpoints including Redis operations """ import requests import time import json from datetime import datetime BASE_URL = "http://localhost:8000" print("=" * 70) print("DevServer API - Complete Test Suite") print("=" * 70) print(f"Base URL: {BASE_URL}") print(f"Started at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") print("=" * 70) def test_api_info(): """Test API information endpoint""" print("\n1. API Information") print("-" * 70) response = requests.get(f"{BASE_URL}/") data = response.json() print(f" Service: {data['service']}") print(f" Version: {data['version']}") print(f" Endpoints: {len(data['endpoints'])} categories") print(f" Status: {response.status_code}") def test_health(): """Test health check""" print("\n2. Health Check") print("-" * 70) response = requests.get(f"{BASE_URL}/health") data = response.json() print(f" Status: {data['status']}") print(f" Redis: {data['redis']}") print(f" Status: {response.status_code}") def test_dice_roll(): """Test dice rolling""" print("\n3. Dice Roll (FastAPI + Tracing)") print("-" * 70) start = time.time() response = requests.get(f"{BASE_URL}/api/dice/roll") elapsed = time.time() - start data = response.json() print(f" Total rolls: {data['total']}") print(f" Service: {data['service']}") print(f" Duration: {elapsed:.3f}s") print(f" Status: {response.status_code}") def test_redis_single(): """Test single Redis operations""" print("\n4. Redis Single Operations") print("-" * 70) # Set key = f"test_{int(time.time())}" value = f"hello_world_{int(time.time())}" response = requests.post(f"{BASE_URL}/api/cache/set", params={ "key": key, "value": value, "ttl": 300 }) print(f" SET {key} = {value}") print(f" Status: {response.status_code}") # Get response = requests.get(f"{BASE_URL}/api/cache/{key}") data = response.json() print(f" GET {key}") print(f" Value: {data['value']}") print(f" Status: {response.status_code}") # Delete response = requests.delete(f"{BASE_URL}/api/cache/{key}") data = response.json() print(f" DELETE {key}") print(f" Deleted: {data['deleted']}") print(f" Status: {response.status_code}") def test_redis_batch(): """Test batch Redis operations""" print("\n5. Redis Batch Operations") print("-" * 70) # Batch Set items = { f"batch_key_1_{int(time.time())}": "value1", f"batch_key_2_{int(time.time())}": "value2", f"batch_key_3_{int(time.time())}": "value3" } response = requests.post(f"{BASE_URL}/api/cache/batch-set", json=items) data = response.json() print(f" BATCH SET: {len(items)} items") print(f" Successful: {data['successful']}/{data['total']}") print(f" Status: {response.status_code}") # Batch Get keys = ",".join(items.keys()) response = requests.get(f"{BASE_URL}/api/cache/batch-get", params={"keys": keys}) data = response.json() print(f" BATCH GET: {len(items)} keys") print(f" Found: {data['found']}/{data['requested']}") print(f" Status: {response.status_code}") def test_redis_stats(): """Test Redis statistics""" print("\n6. Redis Statistics") print("-" * 70) response = requests.get(f"{BASE_URL}/api/cache/stats") data = response.json() stats = data['stats'] print(f" 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']}s") print(f" Status: {response.status_code}") def test_redis_keys(): """Test listing cache keys""" print("\n7. List Cache Keys") print("-" * 70) response = requests.get(f"{BASE_URL}/api/cache/keys", params={"pattern": "*"}) data = response.json() print(f" Pattern: {data['pattern']}") print(f" Keys Found: {data['count']}") if data['keys'] and len(data['keys']) <= 5: print(f" Keys: {data['keys']}") elif data['keys']: print(f" Sample Keys: {data['keys'][:5]}...") print(f" Status: {response.status_code}") def test_celery_fibonacci(): """Test Celery Fibonacci task""" print("\n8. Celery Task (Fibonacci Calculation)") print("-" * 70) # Create task n = 15 start = time.time() response = requests.post(f"{BASE_URL}/api/tasks/fibonacci", params={"n": n}) data = response.json() task_id = data['task_id'] print(f" Creating Fibonacci({n}) task...") print(f" Task ID: {task_id}") print(f" Status: {response.status_code}") # Wait for completion print(f" Waiting for task completion...") max_attempts = 30 for attempt in range(max_attempts): response = requests.get(f"{BASE_URL}/api/tasks/{task_id}") data = response.json() if data['status'] == 'completed': elapsed = time.time() - start result = data['result'] print(f" Task completed in {elapsed:.2f}s") print(f" Fibonacci({n}) = {result['fibonacci']}") print(f" Calculation time: {result['calculation_time']}") print(f" Service: {result['service']}") break time.sleep(1) else: print(f" Task did not complete within {max_attempts}s") def test_process_workflow(): """Test combined cache + Celery workflow""" print("\n9. Data Processing Workflow (Cache + Celery)") print("-" * 70) data_payload = { "user_id": 12345, "action": "test_workflow", "timestamp": time.time(), "data": "sample processing data" } # First request - should process with Celery print(f" First request (cache miss - will use Celery)...") start1 = time.time() elapsed1 = 0.0 response = requests.post(f"{BASE_URL}/api/process", json=data_payload) data1 = response.json() print(f" Source: {data1['source']}") if data1['source'] == 'celery_task': task_id = data1['task_id'] print(f" Task ID: {task_id}") # Wait for task for _ in range(30): response = requests.get(f"{BASE_URL}/api/tasks/{task_id}") result = response.json() if result['status'] == 'completed': elapsed1 = time.time() - start1 print(f" Task completed in {elapsed1:.2f}s") break time.sleep(1) # Second request - should return from cache print(f" Second request (cache hit - should be instant)...") start2 = time.time() response = requests.post(f"{BASE_URL}/api/process", json=data_payload) data2 = response.json() elapsed2 = time.time() - start2 print(f" Source: {data2['source']}") print(f" Duration: {elapsed2:.3f}s") if data1['source'] == 'celery_task' and data2['source'] == 'cache' and elapsed1 > 0: speedup = elapsed1 / elapsed2 if elapsed2 > 0 else 0 print(f" Cache speedup: {speedup:.1f}x faster!") def run_all_tests(): """Run complete test suite""" start_time = time.time() try: test_api_info() time.sleep(0.5) test_health() time.sleep(0.5) test_dice_roll() time.sleep(0.5) test_redis_single() time.sleep(0.5) test_redis_batch() time.sleep(0.5) test_redis_stats() time.sleep(0.5) test_redis_keys() time.sleep(0.5) test_celery_fibonacci() time.sleep(0.5) test_process_workflow() elapsed = time.time() - start_time print("\n" + "=" * 70) print(f"All tests completed successfully in {elapsed:.2f}s!") print("=" * 70) print("\nNext Steps:") print(" 1. Open Jaeger UI: http://localhost:16686") print(" 2. Select service: 'devserver.api.fastapi' or 'devserver.celery.worker'") print(" 3. Click 'Find Traces' to see distributed tracing") print(" 4. Explore traces to see request flow across services") print(" 5. Check logs in ./logs/ directory") print("=" * 70) except requests.exceptions.ConnectionError: print("\nERROR: Cannot connect to DevServer") print(" Make sure the server is running:") print(" docker-compose up -d") except Exception as e: print(f"\nERROR: {e}") import traceback traceback.print_exc() if __name__ == "__main__": run_all_tests()