405 lines
11 KiB
Python
405 lines
11 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Test all form POST endpoints for Internal Server Errors.
|
|
"""
|
|
|
|
import json
|
|
import sys
|
|
|
|
import httpx
|
|
|
|
BASE_URL = "http://localhost:8000"
|
|
|
|
# All form POST endpoints from admin_web.py
|
|
FORM_POST_ENDPOINTS = [
|
|
# (endpoint, method, form_data, description)
|
|
(
|
|
"/admin/login",
|
|
"POST",
|
|
{"username": "admin", "password": "admin123"},
|
|
"Admin login",
|
|
),
|
|
(
|
|
"/admin/password",
|
|
"POST",
|
|
{
|
|
"old_password": "admin123",
|
|
"new_password": "admin123",
|
|
"re_new_password": "admin123",
|
|
},
|
|
"Change password",
|
|
),
|
|
(
|
|
"/admin/websites",
|
|
"POST",
|
|
{
|
|
"site_name": "Test Site",
|
|
"site_url": "https://test.example.com",
|
|
},
|
|
"Create website",
|
|
),
|
|
(
|
|
"/admin/websites/1/edit",
|
|
"POST",
|
|
{
|
|
"site_name": "Updated Test Site",
|
|
"site_url": "https://updated.example.com",
|
|
},
|
|
"Edit website",
|
|
),
|
|
("/admin/websites/1/delete", "POST", {}, "Delete website"),
|
|
(
|
|
"/admin/tryout-import/preview",
|
|
"POST",
|
|
{
|
|
"website_id": "1",
|
|
},
|
|
"Tryout import preview (no file)",
|
|
),
|
|
(
|
|
"/admin/tryout-import",
|
|
"POST",
|
|
{
|
|
"website_id": "1",
|
|
"preview_token": "invalid-token",
|
|
},
|
|
"Tryout import submit",
|
|
),
|
|
(
|
|
"/admin/snapshot-questions/promote-bulk",
|
|
"POST",
|
|
{
|
|
"snapshot_id": "1",
|
|
"snapshot_question_ids": [],
|
|
},
|
|
"Promote snapshot questions bulk",
|
|
),
|
|
(
|
|
"/admin/basis-items/1/generate",
|
|
"POST",
|
|
{
|
|
"target_level": "mudah",
|
|
"ai_model": "",
|
|
"generation_count": "1",
|
|
"operator_notes": "",
|
|
},
|
|
"Generate variants for basis item",
|
|
),
|
|
(
|
|
"/admin/basis-items/1/review-bulk",
|
|
"POST",
|
|
{
|
|
"item_ids": ["1"],
|
|
"action": "approved",
|
|
},
|
|
"Review bulk variants",
|
|
),
|
|
(
|
|
"/admin/questions/1/generate",
|
|
"POST",
|
|
{
|
|
"target_level": "mudah",
|
|
"ai_model": "meta-llama/llama-4-maverick:free",
|
|
"generation_count": "1",
|
|
"operator_notes": "",
|
|
"include_note_for_admin": True,
|
|
"include_note_in_prompt": False,
|
|
},
|
|
"Generate question variants",
|
|
),
|
|
(
|
|
"/admin/questions/1/generate/review-bulk",
|
|
"POST",
|
|
{
|
|
"item_ids": ["1"],
|
|
"action": "approved",
|
|
"tab": "review",
|
|
},
|
|
"Review question variants bulk",
|
|
),
|
|
]
|
|
|
|
# API POST endpoints
|
|
API_POST_ENDPOINTS = [
|
|
(
|
|
"/api/v1/session/",
|
|
{
|
|
"session_id": "test-session-123",
|
|
"tryout_id": "test",
|
|
"wp_user_id": "123",
|
|
"website_id": 1,
|
|
"scoring_mode": "ctt",
|
|
},
|
|
"Create session",
|
|
),
|
|
(
|
|
"/api/v1/session/test-session-123/complete",
|
|
{
|
|
"end_time": "2024-01-01T00:00:00Z",
|
|
"user_answers": [],
|
|
},
|
|
"Complete session",
|
|
),
|
|
(
|
|
"/api/v1/session/test-session-123/submit_answer",
|
|
{
|
|
"item_id": 1,
|
|
"response": "A",
|
|
"time_spent": 10,
|
|
},
|
|
"Submit answer",
|
|
),
|
|
(
|
|
"/api/v1/wordpress/verify_session",
|
|
{
|
|
"website_id": 1,
|
|
"wp_user_id": "123",
|
|
"token": "test",
|
|
},
|
|
"Verify WordPress session",
|
|
),
|
|
(
|
|
"/api/v1/reports/schedule",
|
|
{
|
|
"tryout_id": "test",
|
|
"report_type": "student_performance",
|
|
},
|
|
"Schedule report",
|
|
),
|
|
(
|
|
"/api/v1/admin/cat/test",
|
|
{
|
|
"tryout_id": "test",
|
|
"website_id": 1,
|
|
},
|
|
"Test CAT algorithm",
|
|
),
|
|
("/api/v1/admin/1/calibrate", {}, "Calibrate tryout"),
|
|
("/api/v1/admin/1/toggle-ai-generation", {}, "Toggle AI generation"),
|
|
("/api/v1/admin/1/reset-normalization", {}, "Reset normalization"),
|
|
]
|
|
|
|
|
|
def get_admin_session():
|
|
"""Login and get session cookies for admin access."""
|
|
with httpx.Client(base_url=BASE_URL, follow_redirects=True, timeout=30.0) as client:
|
|
# Try to login
|
|
response = client.post(
|
|
"/admin/login",
|
|
data={
|
|
"username": "admin",
|
|
"password": "admin123",
|
|
},
|
|
)
|
|
print(f"Login response: {response.status_code}")
|
|
|
|
# Check if we have admin access
|
|
response = client.get("/admin")
|
|
print(f"Admin page response: {response.status_code}")
|
|
|
|
# Return cookies
|
|
return client.cookies
|
|
|
|
|
|
def test_endpoint(
|
|
client: httpx.Client, endpoint: str, method: str, data: dict, cookies: dict = None
|
|
) -> dict:
|
|
"""Test a single endpoint."""
|
|
headers = {"X-Website-ID": "1"}
|
|
|
|
try:
|
|
if method == "POST":
|
|
# Check if this looks like form data or JSON
|
|
if isinstance(data, dict) and all(
|
|
isinstance(v, str) or v is None for v in data.values()
|
|
):
|
|
# Form data
|
|
response = client.post(
|
|
endpoint,
|
|
data=data,
|
|
headers=headers,
|
|
cookies=cookies,
|
|
timeout=30.0,
|
|
follow_redirects=True,
|
|
)
|
|
else:
|
|
# JSON data
|
|
response = client.post(
|
|
endpoint,
|
|
json=data,
|
|
headers=headers,
|
|
cookies=cookies,
|
|
timeout=30.0,
|
|
follow_redirects=True,
|
|
)
|
|
else:
|
|
response = client.request(
|
|
method,
|
|
endpoint,
|
|
headers=headers,
|
|
cookies=cookies,
|
|
timeout=30.0,
|
|
follow_redirects=True,
|
|
)
|
|
|
|
# Check for internal server error
|
|
has_ise = (
|
|
response.status_code == 500
|
|
or "Internal Server Error" in response.text
|
|
or "500 Internal Server Error" in response.text
|
|
)
|
|
|
|
# Check for traceback
|
|
has_traceback = "Traceback" in response.text
|
|
|
|
return {
|
|
"endpoint": endpoint,
|
|
"method": method,
|
|
"status_code": response.status_code,
|
|
"has_ise": has_ise,
|
|
"has_traceback": has_traceback,
|
|
"response_preview": response.text[:500] if response.text else "",
|
|
"redirect_location": response.headers.get("location", ""),
|
|
}
|
|
except httpx.TimeoutException:
|
|
return {
|
|
"endpoint": endpoint,
|
|
"method": method,
|
|
"status_code": None,
|
|
"has_ise": False,
|
|
"has_traceback": False,
|
|
"response_preview": "",
|
|
"error": "Timeout",
|
|
}
|
|
except Exception as e:
|
|
return {
|
|
"endpoint": endpoint,
|
|
"method": method,
|
|
"status_code": None,
|
|
"has_ise": False,
|
|
"has_traceback": False,
|
|
"response_preview": "",
|
|
"error": str(e),
|
|
}
|
|
|
|
|
|
def main():
|
|
print("=" * 80)
|
|
print("Testing all Form POST endpoints for Internal Server Errors")
|
|
print("=" * 80)
|
|
print()
|
|
|
|
# Get admin session
|
|
print("Getting admin session...")
|
|
cookies = get_admin_session()
|
|
print()
|
|
|
|
results = []
|
|
has_errors = False
|
|
|
|
with httpx.Client(base_url=BASE_URL, follow_redirects=True, timeout=30.0) as client:
|
|
# Test admin form POST endpoints
|
|
print("-" * 80)
|
|
print("ADMIN FORM POST ENDPOINTS")
|
|
print("-" * 80)
|
|
|
|
for endpoint, method, data, description in FORM_POST_ENDPOINTS:
|
|
print(f"\nTesting: {description}")
|
|
print(f" Endpoint: {endpoint}")
|
|
|
|
result = test_endpoint(client, endpoint, method, data, cookies)
|
|
results.append((description, result))
|
|
|
|
status = result["status_code"]
|
|
error_details = ""
|
|
|
|
if result.get("error"):
|
|
error_details = f" [ERROR: {result['error']}]"
|
|
has_errors = True
|
|
elif result.get("has_traceback"):
|
|
error_details = f" [TRACEBACK!]"
|
|
has_errors = True
|
|
print(f" Response: {result['response_preview'][:1000]}")
|
|
elif result.get("has_ise"):
|
|
error_details = f" [INTERNAL SERVER ERROR!]"
|
|
has_errors = True
|
|
print(f" Response: {result['response_preview'][:1000]}")
|
|
|
|
status_str = str(status) if status else "N/A"
|
|
print(f" Status: {status_str}{error_details}")
|
|
|
|
if result.get("redirect_location"):
|
|
print(f" Redirect: {result['redirect_location']}")
|
|
|
|
# Test API POST endpoints
|
|
print()
|
|
print("-" * 80)
|
|
print("API POST ENDPOINTS")
|
|
print("-" * 80)
|
|
|
|
for endpoint, data, description in API_POST_ENDPOINTS:
|
|
print(f"\nTesting: {description}")
|
|
print(f" Endpoint: {endpoint}")
|
|
|
|
result = test_endpoint(client, endpoint, "POST", data, cookies)
|
|
results.append((description, result))
|
|
|
|
status = result["status_code"]
|
|
error_details = ""
|
|
|
|
if result.get("error"):
|
|
error_details = f" [ERROR: {result['error']}]"
|
|
has_errors = True
|
|
elif result.get("has_traceback"):
|
|
error_details = f" [TRACEBACK!]"
|
|
has_errors = True
|
|
print(f" Response: {result['response_preview'][:1000]}")
|
|
elif result.get("has_ise"):
|
|
error_details = f" [INTERNAL SERVER ERROR!]"
|
|
has_errors = True
|
|
print(f" Response: {result['response_preview'][:1000]}")
|
|
|
|
status_str = str(status) if status else "N/A"
|
|
print(f" Status: {status_str}{error_details}")
|
|
|
|
# Summary
|
|
print()
|
|
print("=" * 80)
|
|
print("SUMMARY")
|
|
print("=" * 80)
|
|
|
|
total = len(results)
|
|
ise_errors = sum(1 for _, r in results if r.get("has_ise"))
|
|
tracebacks = sum(1 for _, r in results if r.get("has_traceback"))
|
|
timeouts = sum(1 for _, r in results if r.get("error") == "Timeout")
|
|
exceptions = sum(
|
|
1 for _, r in results if r.get("error") and r.get("error") != "Timeout"
|
|
)
|
|
|
|
print(f"Total endpoints tested: {total}")
|
|
print(f"Internal Server Errors: {ise_errors}")
|
|
print(f"Tracebacks: {tracebacks}")
|
|
print(f"Timeouts: {timeouts}")
|
|
print(f"Exceptions: {exceptions}")
|
|
print()
|
|
|
|
if ise_errors > 0 or tracebacks > 0:
|
|
print("Endpoints with issues:")
|
|
for desc, r in results:
|
|
if r.get("has_ise") or r.get("has_traceback"):
|
|
print(f" - {desc}: {r['endpoint']} -> {r['status_code']}")
|
|
if r.get("has_traceback"):
|
|
print(f" Traceback detected in response")
|
|
|
|
print()
|
|
if has_errors:
|
|
print("❌ Some endpoints have issues. Please review the output above.")
|
|
return 1
|
|
else:
|
|
print("✅ All endpoints passed! No Internal Server Errors detected.")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|