#!/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())