93 lines
3.4 KiB
Python
93 lines
3.4 KiB
Python
import requests
|
|
import time
|
|
import json
|
|
import sys
|
|
|
|
BASE_URL = "http://localhost:8000"
|
|
|
|
def log_test(name, status, details=""):
|
|
icon = "✅" if status == "PASS" else "❌"
|
|
print(f"{icon} [{name}] - {details}")
|
|
|
|
def run_api_suite():
|
|
print(f"\n🚀 Starting API Testing Suite (Postman-style logic)\n" + "-"*50)
|
|
|
|
# 1. AUTHENTICATION TEST
|
|
try:
|
|
login_res = requests.post(f"{BASE_URL}/users/login", json={
|
|
"username": "Admin",
|
|
"password": "admin"
|
|
})
|
|
if login_res.status_code == 200:
|
|
token = login_res.json()["access_token"]
|
|
log_test("Auth: Admin Login", "PASS", f"Status: {login_res.status_code}")
|
|
else:
|
|
log_test("Auth: Admin Login", "FAIL", f"Status: {login_res.status_code}")
|
|
return
|
|
except Exception as e:
|
|
log_test("Auth: Admin Login", "FAIL", str(e))
|
|
return
|
|
|
|
headers = {"Authorization": f"Bearer {token}"}
|
|
|
|
# 2. STATUS CODES & CRUD
|
|
try:
|
|
item_res = requests.get(f"{BASE_URL}/items/", headers=headers)
|
|
if item_res.status_code == 200:
|
|
log_test("Items: List All", "PASS", f"Returned {len(item_res.json())} items")
|
|
else:
|
|
log_test("Items: List All", "FAIL", f"Status: {item_res.status_code}")
|
|
except Exception as e:
|
|
log_test("Items: List All", "FAIL", str(e))
|
|
|
|
# 3. RATE LIMITING TEST (Security Policy)
|
|
print("\n⏳ Testing Rate Limiting (Anti Brute-Force)...")
|
|
limit_hit = False
|
|
for i in range(12): # More than the 5/min limit
|
|
res = requests.post(f"{BASE_URL}/users/login", json={"username": "fake", "password": "fake"})
|
|
if res.status_code == 429:
|
|
limit_hit = True
|
|
log_test("Security: Rate Limiter", "PASS", f"Blocked at attempt {i+1} (429 Too Many Requests)")
|
|
break
|
|
if not limit_hit:
|
|
log_test("Security: Rate Limiter", "FAIL", "Limiter did not trigger after 12 quick requests")
|
|
|
|
# 4. RBAC PROTECTION
|
|
# Create a test item to delete
|
|
test_item = requests.post(f"{BASE_URL}/items/", headers=headers, json={
|
|
"barcode": "API-TEST-999",
|
|
"name": "API Test Item",
|
|
"category": "Testing",
|
|
"quantity": 10,
|
|
"min_quantity": 1
|
|
})
|
|
|
|
if test_item.status_code == 201:
|
|
item_id = test_item.json()["id"]
|
|
log_test("Items: Create test resource", "PASS", f"ID: {item_id}")
|
|
|
|
# Now try to delete it (as Admin - should pass)
|
|
del_res = requests.delete(f"{BASE_URL}/items/{item_id}", headers=headers)
|
|
if del_res.status_code == 200:
|
|
log_test("RBAC: Admin Delete", "PASS", "Resource purged successfully")
|
|
else:
|
|
log_test("RBAC: Admin Delete", "FAIL", f"Status: {del_res.status_code}")
|
|
else:
|
|
# Check if it already exists from previous failed run
|
|
if test_item.status_code == 400:
|
|
log_test("Items: Create test resource", "PASS", "Resource already exists")
|
|
else:
|
|
log_test("Items: Create test resource", "FAIL", f"Status: {test_item.status_code}")
|
|
|
|
# 5. ERROR STATES
|
|
unauth_res = requests.get(f"{BASE_URL}/items/stats")
|
|
if unauth_res.status_code == 401:
|
|
log_test("Security: Unauth Block", "PASS", "Blocked 401 Unauthorized")
|
|
else:
|
|
log_test("Security: Unauth Block", "FAIL", f"Server allowed access! Status: {unauth_res.status_code}")
|
|
|
|
print("\n" + "-"*50 + "\n🏁 API Test Suite Finished.")
|
|
|
|
if __name__ == "__main__":
|
|
run_api_suite()
|