What a mess
This commit is contained in:
133
tests/quick_perf_test.py
Normal file
133
tests/quick_perf_test.py
Normal 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())
|
||||
Reference in New Issue
Block a user