Spaces:
Sleeping
Sleeping
| """ | |
| Manual verification script for Phase 6 testing. | |
| Tests session management, file operations, and multi-language execution. | |
| """ | |
| import requests | |
| import time | |
| import sys | |
| from pathlib import Path | |
| BASE_URL = "http://localhost:7860" | |
| def print_test(name): | |
| print(f"\n{'='*60}") | |
| print(f"TEST: {name}") | |
| print(f"{'='*60}") | |
| def print_success(msg): | |
| print(f"✅ {msg}") | |
| def print_error(msg): | |
| print(f"❌ {msg}") | |
| def print_info(msg): | |
| print(f"ℹ️ {msg}") | |
| def test_1_session_lifecycle(): | |
| """Test creating, getting, and destroying a session""" | |
| print_test("Session Lifecycle") | |
| # Create session | |
| print_info("Creating session...") | |
| resp = requests.post(f"{BASE_URL}/sessions", json={ | |
| "metadata": {"test": "lifecycle"}, | |
| "timeout_minutes": 30 | |
| }) | |
| if resp.status_code != 201: | |
| print_error(f"Failed to create session: {resp.status_code}") | |
| return None | |
| session = resp.json() | |
| session_id = session["session_id"] | |
| print_success(f"Session created: {session_id}") | |
| # Wait for container to be ready | |
| time.sleep(3) | |
| # Get session details | |
| print_info("Getting session details...") | |
| resp = requests.get(f"{BASE_URL}/sessions/{session_id}") | |
| if resp.status_code == 200: | |
| print_success("Session retrieved successfully") | |
| else: | |
| print_error(f"Failed to get session: {resp.status_code}") | |
| # List sessions | |
| print_info("Listing all sessions...") | |
| resp = requests.get(f"{BASE_URL}/sessions") | |
| if resp.status_code == 200: | |
| sessions = resp.json() | |
| print_success(f"Found {len(sessions)} active session(s)") | |
| else: | |
| print_error(f"Failed to list sessions: {resp.status_code}") | |
| return session_id | |
| def test_2_file_operations(session_id): | |
| """Test file upload, list, download""" | |
| print_test("File Operations") | |
| if not session_id: | |
| print_error("No session available") | |
| return False | |
| # Upload file | |
| print_info("Uploading test file...") | |
| file_content = b"print('Hello from uploaded file!')\nprint(f'2 + 2 = {2+2}')" | |
| resp = requests.post( | |
| f"{BASE_URL}/sessions/{session_id}/files", | |
| files={"file": ("test_script.py", file_content, "text/x-python")} | |
| ) | |
| if resp.status_code != 200: | |
| print_error(f"Failed to upload file: {resp.status_code} - {resp.text}") | |
| return False | |
| upload_result = resp.json() | |
| print_success(f"File uploaded: {upload_result['filename']} ({upload_result['size']} bytes)") | |
| # List files | |
| print_info("Listing files...") | |
| resp = requests.get(f"{BASE_URL}/sessions/{session_id}/files") | |
| if resp.status_code == 200: | |
| files = resp.json() | |
| print_success(f"Found {len(files)} file(s) in workspace") | |
| for f in files: | |
| print(f" - {f['filename']} ({f['size']} bytes)") | |
| else: | |
| print_error(f"Failed to list files: {resp.status_code}") | |
| return False | |
| # Download file | |
| print_info("Downloading file...") | |
| resp = requests.get(f"{BASE_URL}/sessions/{session_id}/files/test_script.py") | |
| if resp.status_code == 200: | |
| if resp.content == file_content: | |
| print_success("File downloaded successfully and content matches") | |
| else: | |
| print_error("Downloaded file content doesn't match") | |
| return False | |
| else: | |
| print_error(f"Failed to download file: {resp.status_code}") | |
| return False | |
| return True | |
| def test_3_session_execution(session_id): | |
| """Test code execution in session""" | |
| print_test("Session-Based Code Execution") | |
| if not session_id: | |
| print_error("No session available") | |
| return False | |
| # Execute Python code | |
| print_info("Executing Python code...") | |
| resp = requests.post( | |
| f"{BASE_URL}/sessions/{session_id}/execute", | |
| json={ | |
| "code": "import sys\nprint(f'Python version: {sys.version}')\nprint('Execution successful!')", | |
| "language": "python", | |
| "working_dir": "/workspace" | |
| } | |
| ) | |
| if resp.status_code != 200: | |
| print_error(f"Failed to execute code: {resp.status_code} - {resp.text}") | |
| return False | |
| result = resp.json() | |
| print_success("Code executed successfully") | |
| print(f" Output: {result['stdout'].strip()}") | |
| print(f" Exit code: {result['exit_code']}") | |
| print(f" Execution time: {result['execution_time']}s") | |
| return True | |
| def test_4_file_execution(session_id): | |
| """Test executing uploaded file""" | |
| print_test("Execute Uploaded File") | |
| if not session_id: | |
| print_error("No session available") | |
| return False | |
| # Execute the previously uploaded file | |
| print_info("Executing uploaded Python file...") | |
| resp = requests.post( | |
| f"{BASE_URL}/sessions/{session_id}/execute-file", | |
| json={ | |
| "filepath": "/workspace/test_script.py", | |
| "language": "python", | |
| "args": [] | |
| } | |
| ) | |
| if resp.status_code != 200: | |
| print_error(f"Failed to execute file: {resp.status_code} - {resp.text}") | |
| return False | |
| result = resp.json() | |
| print_success("File executed successfully") | |
| print(f" Output:\n{result['stdout']}") | |
| print(f" Exit code: {result['exit_code']}") | |
| return True | |
| def test_5_persistent_state(session_id): | |
| """Test that files persist across executions""" | |
| print_test("Persistent State Verification") | |
| if not session_id: | |
| print_error("No session available") | |
| return False | |
| # First execution: create a file | |
| print_info("Creating data file in first execution...") | |
| resp = requests.post( | |
| f"{BASE_URL}/sessions/{session_id}/execute", | |
| json={ | |
| "code": "with open('/workspace/persistent.txt', 'w') as f: f.write('Data persists!')", | |
| "language": "python" | |
| } | |
| ) | |
| if resp.status_code != 200: | |
| print_error(f"Failed first execution: {resp.status_code}") | |
| return False | |
| print_success("File created in first execution") | |
| # Second execution: read the file | |
| print_info("Reading file in second execution...") | |
| resp = requests.post( | |
| f"{BASE_URL}/sessions/{session_id}/execute", | |
| json={ | |
| "code": "with open('/workspace/persistent.txt', 'r') as f: print(f'Read: {f.read()}')", | |
| "language": "python" | |
| } | |
| ) | |
| if resp.status_code != 200: | |
| print_error(f"Failed second execution: {resp.status_code}") | |
| return False | |
| result = resp.json() | |
| if "Data persists!" in result['stdout']: | |
| print_success("File persisted across executions!") | |
| print(f" Output: {result['stdout'].strip()}") | |
| else: | |
| print_error("File did not persist") | |
| return False | |
| return True | |
| def test_6_concurrent_sessions(): | |
| """Test creating multiple concurrent sessions""" | |
| print_test("Concurrent Sessions") | |
| session_ids = [] | |
| # Create 3 sessions | |
| for i in range(3): | |
| print_info(f"Creating session {i+1}/3...") | |
| resp = requests.post(f"{BASE_URL}/sessions", json={ | |
| "metadata": {"test": "concurrent", "index": i} | |
| }) | |
| if resp.status_code == 201: | |
| session_id = resp.json()["session_id"] | |
| session_ids.append(session_id) | |
| print_success(f"Session {i+1} created: {session_id[:8]}...") | |
| else: | |
| print_error(f"Failed to create session {i+1}") | |
| # List all sessions | |
| resp = requests.get(f"{BASE_URL}/sessions") | |
| if resp.status_code == 200: | |
| all_sessions = resp.json() | |
| print_success(f"Total active sessions: {len(all_sessions)}") | |
| # Cleanup | |
| print_info("Cleaning up concurrent sessions...") | |
| for sid in session_ids: | |
| requests.delete(f"{BASE_URL}/sessions/{sid}") | |
| print_success("Concurrent session test completed") | |
| return True | |
| def test_7_cleanup(session_id): | |
| """Test session cleanup""" | |
| print_test("Session Cleanup") | |
| if not session_id: | |
| print_info("No session to cleanup") | |
| return True | |
| print_info(f"Destroying session {session_id[:8]}...") | |
| resp = requests.delete(f"{BASE_URL}/sessions/{session_id}") | |
| if resp.status_code == 200: | |
| print_success("Session destroyed successfully") | |
| # Verify it's gone | |
| resp = requests.get(f"{BASE_URL}/sessions/{session_id}") | |
| if resp.status_code == 404: | |
| print_success("Session verified as destroyed") | |
| return True | |
| else: | |
| print_error("Session still exists after destruction") | |
| return False | |
| else: | |
| print_error(f"Failed to destroy session: {resp.status_code}") | |
| return False | |
| def test_8_stateless_execution(): | |
| """Test backward compatibility - stateless execution""" | |
| print_test("Stateless Execution (Backward Compatibility)") | |
| print_info("Executing code without session...") | |
| resp = requests.post(f"{BASE_URL}/execute", json={ | |
| "code": "print('Stateless execution works!')\nprint(f'Result: {10 * 10}')", | |
| "language": "python" | |
| }) | |
| if resp.status_code == 200: | |
| result = resp.json() | |
| print_success("Stateless execution successful") | |
| print(f" Output: {result['stdout'].strip()}") | |
| print(f" Exit code: {result['exit_code']}") | |
| return True | |
| else: | |
| print_error(f"Stateless execution failed: {resp.status_code}") | |
| return False | |
| def main(): | |
| """Run all verification tests""" | |
| print("\n" + "="*60) | |
| print("ENHANCED SANDBOX - MANUAL VERIFICATION") | |
| print("="*60) | |
| # Check if API is running | |
| try: | |
| resp = requests.get(f"{BASE_URL}/health", timeout=2) | |
| if resp.status_code != 200: | |
| print_error("API server is not healthy") | |
| sys.exit(1) | |
| print_success("API server is running") | |
| except requests.exceptions.RequestException as e: | |
| print_error(f"Cannot connect to API server at {BASE_URL}") | |
| print_info("Please run 'python app.py' first") | |
| sys.exit(1) | |
| results = {} | |
| session_id = None | |
| # Run all tests | |
| try: | |
| session_id = test_1_session_lifecycle() | |
| results['session_lifecycle'] = session_id is not None | |
| results['file_operations'] = test_2_file_operations(session_id) | |
| results['session_execution'] = test_3_session_execution(session_id) | |
| results['file_execution'] = test_4_file_execution(session_id) | |
| results['persistent_state'] = test_5_persistent_state(session_id) | |
| results['concurrent_sessions'] = test_6_concurrent_sessions() | |
| results['stateless_execution'] = test_8_stateless_execution() | |
| results['cleanup'] = test_7_cleanup(session_id) | |
| except Exception as e: | |
| print_error(f"Test failed with exception: {e}") | |
| import traceback | |
| traceback.print_exc() | |
| # Summary | |
| print("\n" + "="*60) | |
| print("VERIFICATION SUMMARY") | |
| print("="*60) | |
| passed = sum(1 for v in results.values() if v) | |
| total = len(results) | |
| for test, result in results.items(): | |
| status = "✅ PASS" if result else "❌ FAIL" | |
| print(f"{status} - {test.replace('_', ' ').title()}") | |
| print(f"\nResults: {passed}/{total} tests passed") | |
| if passed == total: | |
| print_success("All verification tests passed!") | |
| sys.exit(0) | |
| else: | |
| print_error(f"{total - passed} test(s) failed") | |
| sys.exit(1) | |
| if __name__ == "__main__": | |
| main() | |