Checkpoint React frontend migration
This commit is contained in:
275
backend/test_all_post_endpoints.py
Normal file
275
backend/test_all_post_endpoints.py
Normal file
@@ -0,0 +1,275 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Comprehensive test of all form POST endpoints with proper authentication.
|
||||
"""
|
||||
|
||||
import re
|
||||
import sys
|
||||
|
||||
import httpx
|
||||
|
||||
BASE_URL = "http://localhost:8000"
|
||||
|
||||
|
||||
def login(client: httpx.Client) -> bool:
|
||||
"""Login and maintain session."""
|
||||
response = client.get("/admin/login")
|
||||
if response.status_code != 200:
|
||||
return False
|
||||
|
||||
match = re.search(r'name="csrf_token" value="([^"]+)"', response.text)
|
||||
csrf_token = match.group(1) if match else ""
|
||||
|
||||
if not csrf_token:
|
||||
return False
|
||||
|
||||
response = client.post(
|
||||
"/admin/login",
|
||||
data={
|
||||
"username": "admin",
|
||||
"password": "admin123",
|
||||
"csrf_token": csrf_token,
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
return response.status_code == 200 and "/admin/dashboard" in str(response.url)
|
||||
|
||||
|
||||
def get_csrf_token(client: httpx.Client, page_url: str) -> str:
|
||||
"""Extract CSRF token from a page."""
|
||||
response = client.get(page_url)
|
||||
if response.status_code == 200:
|
||||
match = re.search(r'name="csrf_token" value="([^"]+)"', response.text)
|
||||
if match:
|
||||
return match.group(1)
|
||||
return ""
|
||||
|
||||
|
||||
def test_endpoint(client: httpx.Client, name: str, url: str, data: dict) -> dict:
|
||||
"""Test a single POST endpoint."""
|
||||
csrf_token = get_csrf_token(client, url)
|
||||
|
||||
# Get the base URL (strip query params) for CSRF token extraction
|
||||
base_url = url.split("?")[0] if "?" in url else url
|
||||
|
||||
# If we're on a different page, get CSRF token from there
|
||||
if not csrf_token:
|
||||
# Try to get CSRF from dashboard if it's a subpage
|
||||
csrf_token = get_csrf_token(client, "/admin/dashboard")
|
||||
|
||||
if not csrf_token:
|
||||
return {
|
||||
"name": name,
|
||||
"status_code": None,
|
||||
"has_ise": False,
|
||||
"has_traceback": False,
|
||||
"error": "Could not get CSRF token",
|
||||
"response_preview": "",
|
||||
}
|
||||
|
||||
# Add CSRF token to data
|
||||
test_data = data.copy()
|
||||
test_data["csrf_token"] = csrf_token
|
||||
|
||||
response = client.post(
|
||||
url,
|
||||
data=test_data,
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
has_ise = response.status_code == 500 or "Internal Server Error" in response.text
|
||||
has_traceback = "Traceback" in response.text
|
||||
|
||||
if has_traceback:
|
||||
idx = response.text.find("Traceback")
|
||||
traceback_text = response.text[idx : idx + 2000]
|
||||
print(f"\n ⚠️ TRACEBACK on {name}:")
|
||||
print(f" {traceback_text[:500]}...")
|
||||
|
||||
return {
|
||||
"name": name,
|
||||
"status_code": response.status_code,
|
||||
"has_ise": has_ise,
|
||||
"has_traceback": has_traceback,
|
||||
"error": None,
|
||||
"response_preview": response.text[:500],
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
print("=" * 80)
|
||||
print("Testing All Form POST Endpoints for Internal Server Errors")
|
||||
print("=" * 80)
|
||||
|
||||
results = []
|
||||
|
||||
with httpx.Client(base_url=BASE_URL, timeout=60.0) as client:
|
||||
print("\nStep 1: Logging in...")
|
||||
if not login(client):
|
||||
print("❌ Login failed")
|
||||
return 1
|
||||
print("✅ Login successful")
|
||||
|
||||
# Test 1: Variant approval (with item ID 4)
|
||||
print("\nStep 2: Testing variant approval...")
|
||||
result = test_endpoint(
|
||||
client,
|
||||
"Variant approval (/admin/questions/4/generate/review-bulk)",
|
||||
"/admin/questions/4/generate?tab=review",
|
||||
{"item_ids": "4", "action": "approved", "tab": "review"},
|
||||
)
|
||||
results.append(result)
|
||||
print(
|
||||
f" Status: {result['status_code']} {'✅' if result['status_code'] in [200, 303] else '❌'}"
|
||||
)
|
||||
|
||||
# Test 2: Basis item review
|
||||
print("\nStep 3: Testing basis item review...")
|
||||
result = test_endpoint(
|
||||
client,
|
||||
"Basis item review (/admin/basis-items/4/review-bulk)",
|
||||
"/admin/basis-items/4",
|
||||
{"item_ids": "4", "action": "approved"},
|
||||
)
|
||||
results.append(result)
|
||||
print(
|
||||
f" Status: {result['status_code']} {'✅' if result['status_code'] in [200, 303] else '❌'}"
|
||||
)
|
||||
|
||||
# Test 3: Generate variants for question
|
||||
print("\nStep 4: Testing generate variants...")
|
||||
result = test_endpoint(
|
||||
client,
|
||||
"Generate variants (/admin/questions/4/generate)",
|
||||
"/admin/questions/4/generate?tab=generate",
|
||||
{
|
||||
"target_level": "mudah",
|
||||
"ai_model": "meta-llama/llama-4-maverick:free",
|
||||
"generation_count": "1",
|
||||
"operator_notes": "",
|
||||
"include_note_for_admin": "on",
|
||||
"include_note_in_prompt": "",
|
||||
},
|
||||
)
|
||||
results.append(result)
|
||||
print(
|
||||
f" Status: {result['status_code']} {'✅' if result['status_code'] in [200, 303] else '❌'}"
|
||||
)
|
||||
|
||||
# Test 5: Website creation
|
||||
print("\nStep 5: Testing website creation...")
|
||||
result = test_endpoint(
|
||||
client,
|
||||
"Website creation (/admin/websites)",
|
||||
"/admin/websites",
|
||||
{"site_name": "Test Site API", "site_url": "https://test-api.example.com"},
|
||||
)
|
||||
results.append(result)
|
||||
print(
|
||||
f" Status: {result['status_code']} {'✅' if result['status_code'] in [200, 303] else '❌'}"
|
||||
)
|
||||
|
||||
# Test 6: Website deletion (with test ID)
|
||||
print("\nStep 6: Testing website deletion...")
|
||||
# First create a website
|
||||
result_create = test_endpoint(
|
||||
client,
|
||||
"Create test website",
|
||||
"/admin/websites",
|
||||
{
|
||||
"site_name": "Delete Test Site",
|
||||
"site_url": "https://delete-test.example.com",
|
||||
},
|
||||
)
|
||||
|
||||
# Now delete it (using website ID 2 if exists)
|
||||
result = test_endpoint(
|
||||
client,
|
||||
"Website deletion (/admin/websites/2/delete)",
|
||||
"/admin/websites/2/delete",
|
||||
{},
|
||||
)
|
||||
results.append(result)
|
||||
print(
|
||||
f" Status: {result['status_code']} {'✅' if result['status_code'] in [200, 303] else '❌'}"
|
||||
)
|
||||
|
||||
# Test 7: Tryout import preview (without file - should get validation error not server error)
|
||||
print("\nStep 7: Testing tryout import preview...")
|
||||
result = test_endpoint(
|
||||
client,
|
||||
"Tryout import preview (/admin/tryout-import/preview)",
|
||||
"/admin/tryout-import",
|
||||
{"website_id": "1"},
|
||||
)
|
||||
results.append(result)
|
||||
print(f" Status: {result['status_code']} (validation error expected: 422)")
|
||||
|
||||
# Test 8: Snapshot promote bulk
|
||||
print("\nStep 8: Testing snapshot promote bulk...")
|
||||
result = test_endpoint(
|
||||
client,
|
||||
"Snapshot promote (/admin/snapshot-questions/promote-bulk)",
|
||||
"/admin/snapshot-questions",
|
||||
{"snapshot_id": "1", "snapshot_question_ids": ""},
|
||||
)
|
||||
results.append(result)
|
||||
print(
|
||||
f" Status: {result['status_code']} {'✅' if result['status_code'] in [200, 303] else '❌'}"
|
||||
)
|
||||
|
||||
# Test 9: AI generation basis item
|
||||
print("\nStep 9: Testing AI generation for basis item...")
|
||||
result = test_endpoint(
|
||||
client,
|
||||
"Basis item generate (/admin/basis-items/4/generate)",
|
||||
"/admin/basis-items/4",
|
||||
{
|
||||
"target_level": "mudah",
|
||||
"ai_model": "",
|
||||
"generation_count": "1",
|
||||
"operator_notes": "",
|
||||
},
|
||||
)
|
||||
results.append(result)
|
||||
print(
|
||||
f" Status: {result['status_code']} {'✅' if result['status_code'] in [200, 303] else '❌'}"
|
||||
)
|
||||
|
||||
# Summary
|
||||
print("\n" + "=" * 80)
|
||||
print("RESULTS SUMMARY")
|
||||
print("=" * 80)
|
||||
|
||||
errors = []
|
||||
for result in results:
|
||||
if result.get("has_traceback"):
|
||||
errors.append(f"❌ {result['name']}: TRACEBACK")
|
||||
print(f"❌ {result['name']}: TRACEBACK")
|
||||
elif result.get("has_ise"):
|
||||
errors.append(f"❌ {result['name']}: INTERNAL SERVER ERROR")
|
||||
print(f"❌ {result['name']}: INTERNAL SERVER ERROR")
|
||||
elif result.get("error"):
|
||||
print(f"⚠️ {result['name']}: {result['error']}")
|
||||
elif result["status_code"] in [200, 303]:
|
||||
print(f"✅ {result['name']}: OK ({result['status_code']})")
|
||||
elif result["status_code"] == 422:
|
||||
print(f"✅ {result['name']}: Validation Error (expected)")
|
||||
else:
|
||||
print(f"⚠️ {result['name']}: Status {result['status_code']}")
|
||||
|
||||
print()
|
||||
if errors:
|
||||
print("❌ Some endpoints have INTERNAL SERVER ERRORS:")
|
||||
for error in errors:
|
||||
print(f" {error}")
|
||||
return 1
|
||||
else:
|
||||
print("✅ All form POST endpoints tested successfully!")
|
||||
print(" No Internal Server Errors detected.")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user