What a mess

This commit is contained in:
Joan
2025-11-07 15:27:13 +01:00
parent 0b79b3ae59
commit 33cc9586c2
130 changed files with 29819 additions and 1175 deletions

133
tests/quick_perf_test.py Normal file
View File

@@ -0,0 +1,133 @@
#!/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())