load_test.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. import asyncio
  2. import httpx
  3. import websockets
  4. import json
  5. import time
  6. import random
  7. BASE_URL = "http://localhost:8000"
  8. WS_URL = "ws://localhost:8000"
  9. async def simulate_user(user_id):
  10. """Simulates a single user behavior"""
  11. email = f"testuser_{user_id}@example.com"
  12. password = "password123"
  13. async with httpx.AsyncClient() as client:
  14. # 0. Try to register first (in case users don't exist)
  15. try:
  16. await client.post(f"{BASE_URL}/auth/register", json={
  17. "email": email,
  18. "password": password,
  19. "first_name": "Test",
  20. "last_name": "User",
  21. "phone": "123456"
  22. })
  23. except: pass
  24. # 1. Try to login
  25. print(f"[User {user_id}] Attempting login...")
  26. for i in range(5):
  27. try:
  28. resp = await client.post(f"{BASE_URL}/auth/login", json={
  29. "email": email,
  30. "password": password
  31. })
  32. if resp.status_code == 200:
  33. token = resp.json().get("access_token")
  34. print(f"[User {user_id}] Login successful on attempt {i+1}")
  35. break
  36. elif resp.status_code == 403:
  37. print(f"[User {user_id}] Login failed: Captcha required or rate limited")
  38. # If captcha is required, this user stops login attempts in this simple script
  39. return
  40. except Exception as e:
  41. print(f"[User {user_id}] Login error: {e}")
  42. return
  43. else:
  44. print(f"[User {user_id}] Failed to login after 5 attempts")
  45. return
  46. # 2. Connect to global websocket
  47. ws_uri = f"{WS_URL}/auth/ws/global?token={token}"
  48. try:
  49. async with websockets.connect(ws_uri) as ws:
  50. print(f"[User {user_id}] WebSocket connected")
  51. # 3. Simulate order creation (to test 1-min rate limit)
  52. # We try twice rapidly
  53. for i in range(2):
  54. order_data = {
  55. "first_name": "Test",
  56. "last_name": "User",
  57. "phone": "123456",
  58. "email": email,
  59. "shipping_address": "Test Load Street",
  60. "material_id": 1,
  61. "quantity": 1
  62. }
  63. # Need to use form-data with file
  64. files = {'file': ('model.stl', b'binary content stl', 'application/octet-stream')}
  65. resp = await client.post(f"{BASE_URL}/orders", data=order_data, files=files)
  66. if resp.status_code == 200:
  67. print(f"[User {user_id}] Order {i+1} created successfully")
  68. elif resp.status_code == 429:
  69. print(f"[User {user_id}] Order {i+1} REJECTED (Rate Limit Working!)")
  70. else:
  71. print(f"[User {user_id}] Order {i+1} failed: {resp.status_code}")
  72. # 4. Stay connected for a bit to receive potential updates
  73. # and send pings
  74. for _ in range(5):
  75. await ws.send("ping")
  76. try:
  77. # Wait for a message with timeout
  78. msg = await asyncio.wait_for(ws.recv(), timeout=2.0)
  79. print(f"[User {user_id}] WS Received: {msg[:50]}...")
  80. except asyncio.TimeoutError:
  81. pass
  82. await asyncio.sleep(1)
  83. except Exception as e:
  84. print(f"[User {user_id}] WS/Order error: {e}")
  85. async def main():
  86. print("--- Starting Load Test ---")
  87. start_time = time.time()
  88. # Run 10 concurrent users
  89. tasks = [simulate_user(i) for i in range(10)]
  90. await asyncio.gather(*tasks)
  91. end_time = time.time()
  92. print(f"--- Load Test Finished in {end_time - start_time:.2f}s ---")
  93. if __name__ == "__main__":
  94. asyncio.run(main())