#!/usr/bin/env python3 """ Quick performance test - 50 users, 100 requests each """ import asyncio import aiohttp import time import random import statistics from typing import List, Dict API_URL = "https://echoesoftheashgame.patacuack.net/api" NUM_USERS = 50 REQUESTS_PER_USER = 100 async def test_user(session: aiohttp.ClientSession, user_num: int): """Simulate a single user making requests""" username = f"loadtest_user_{user_num}" password = "TestPassword123!" # Login async with session.post(f"{API_URL}/auth/login", json={"username": username, "password": password}) as resp: if resp.status != 200: return [] data = await resp.json() token = data["access_token"] headers = {"Authorization": f"Bearer {token}"} results = [] # Make requests for _ in range(REQUESTS_PER_USER): start = time.time() action = random.choices( ["location", "inventory", "move"], weights=[20, 30, 50] # 50% move, 30% inventory, 20% location )[0] success = False try: if action == "location": async with session.get(f"{API_URL}/game/location", headers=headers, timeout=aiohttp.ClientTimeout(total=10)) as resp: success = resp.status == 200 elif action == "inventory": async with session.get(f"{API_URL}/game/inventory", headers=headers, timeout=aiohttp.ClientTimeout(total=10)) as resp: success = resp.status == 200 elif action == "move": # Get valid directions first async with session.get(f"{API_URL}/game/location", headers=headers, timeout=aiohttp.ClientTimeout(total=10)) as resp: if resp.status == 200: loc_data = await resp.json() directions = loc_data.get("directions", []) if directions: direction = random.choice(directions) async with session.post(f"{API_URL}/game/move", json={"direction": direction}, headers=headers, timeout=aiohttp.ClientTimeout(total=10)) as move_resp: success = move_resp.status == 200 except: pass elapsed = (time.time() - start) * 1000 # Convert to ms results.append({ "action": action, "success": success, "time_ms": elapsed }) await asyncio.sleep(0.001) # Small delay return results async def main(): print("\n" + "="*60) print("QUICK PERFORMANCE TEST") print(f"{NUM_USERS} users × {REQUESTS_PER_USER} requests = {NUM_USERS * REQUESTS_PER_USER} total") print("="*60 + "\n") async with aiohttp.ClientSession() as session: start_time = time.time() # Run all users concurrently tasks = [test_user(session, i) for i in range(1, NUM_USERS + 1)] all_results = await asyncio.gather(*tasks) elapsed = time.time() - start_time # Flatten results results = [r for user_results in all_results for r in user_results] # Calculate stats total = len(results) successful = sum(1 for r in results if r["success"]) failed = total - successful success_rate = (successful / total * 100) if total > 0 else 0 rps = total / elapsed if elapsed > 0 else 0 success_times = [r["time_ms"] for r in results if r["success"]] print("\n" + "="*60) print("RESULTS") print("="*60) print(f"Total Requests: {total}") print(f"Successful: {successful} ({success_rate:.1f}%)") print(f"Failed: {failed} ({100-success_rate:.1f}%)") print(f"Total Time: {elapsed:.2f}s") print(f"Requests/Second: {rps:.2f}") if success_times: print(f"\nResponse Times (successful):") print(f" Min: {min(success_times):.2f}ms") print(f" Max: {max(success_times):.2f}ms") print(f" Mean: {statistics.mean(success_times):.2f}ms") print(f" Median: {statistics.median(success_times):.2f}ms") print(f" 95th: {statistics.quantiles(success_times, n=20)[18]:.2f}ms") # Breakdown by action print(f"\nBreakdown:") for action in ["move", "inventory", "location"]: action_results = [r for r in results if r["action"] == action] if action_results: action_success = sum(1 for r in action_results if r["success"]) action_rate = (action_success / len(action_results) * 100) action_times = [r["time_ms"] for r in action_results if r["success"]] avg_time = statistics.mean(action_times) if action_times else 0 print(f" {action:12s}: {len(action_results):4d} req, {action_rate:5.1f}% success, {avg_time:6.2f}ms avg") print("="*60 + "\n") if __name__ == "__main__": asyncio.run(main())