#!/usr/bin/env python3 """ Verification script for unsandbox Python SDK (Synchronous) This script verifies that the SDK is properly configured and working. Run from the sync/ directory: python3 verify_sdk.py """ import sys import os from pathlib import Path # Add src to path sys.path.insert(0, os.path.join(os.path.dirname(__file__), "src")) from un import ( execute_code, execute_async, get_job, wait_for_job, cancel_job, list_jobs, get_languages, detect_language, CredentialsError, _resolve_credentials, _sign_request, _load_languages_cache, _save_languages_cache, ) def test_language_detection(): """Test language detection""" print("Testing language detection...") tests = [ ("hello.py", "python"), ("app.js", "javascript"), ("main.go", "go"), ("script.rs", "rust"), ("main.cpp", "cpp"), ("unknown.xyz", None), ] for filename, expected in tests: result = detect_language(filename) status = "✓" if result == expected else "✗" print(f" {status} detect_language('{filename}') = {result}") if result != expected: return False return True def test_request_signing(): """Test request signing""" print("\nTesting request signing...") sig1 = _sign_request("secret", 1234567890, "POST", "/execute", '{"code":"test"}') sig2 = _sign_request("secret", 1234567890, "POST", "/execute", '{"code":"test"}') # Test deterministic status = "✓" if sig1 == sig2 else "✗" print(f" {status} Signatures are deterministic: {sig1 == sig2}") # Test format status = "✓" if len(sig1) == 64 else "✗" print(f" {status} Signature is 64 hex chars: {len(sig1)} chars") # Test different secrets produce different sigs sig_diff = _sign_request("different", 1234567890, "POST", "/execute", '{"code":"test"}') status = "✓" if sig1 != sig_diff else "✗" print(f" {status} Different secrets produce different signatures: {sig1 != sig_diff}") return len(sig1) == 64 and sig1 == sig2 and sig1 != sig_diff def test_credentials(): """Test credential resolution""" print("\nTesting credential resolution...") # Test 1: Function arguments try: pk, sk = _resolve_credentials("func_pk", "func_sk") status = "✓" if pk == "func_pk" and sk == "func_sk" else "✗" print(f" {status} Function arguments: {pk == 'func_pk' and sk == 'func_sk'}") except Exception as e: print(f" ✗ Function arguments failed: {e}") return False # Test 2: Can resolve credentials (from env or config) try: pk, sk = _resolve_credentials() print(f" ✓ Credentials resolved: {pk[:20]}... / {sk[:20]}...") return True except CredentialsError: print(f" ✗ No credentials found (this is OK for testing)") print(f" Set UNSANDBOX_PUBLIC_KEY and UNSANDBOX_SECRET_KEY environment variables") return True # Not a test failure, just missing credentials def test_caching(): """Test languages cache""" print("\nTesting caching...") import tempfile import json import time from unittest.mock import patch try: with tempfile.TemporaryDirectory() as tmpdir: cache_path = Path(tmpdir) / "languages.json" # Save cache languages = ["python", "javascript", "go"] with patch("un._get_languages_cache_path", return_value=cache_path): _save_languages_cache(languages) print(f" ✓ Cache saved") # Load cache loaded = _load_languages_cache() if loaded == languages: print(f" ✓ Cache loaded correctly: {loaded}") else: print(f" ✗ Cache mismatch: {loaded}") return False # Test expiration old_time = time.time() - 7200 # 2 hours old os.utime(cache_path, (old_time, old_time)) expired = _load_languages_cache() if expired is None: print(f" ✓ Cache correctly expired") else: print(f" ✗ Cache should be expired: {expired}") return False return True except Exception as e: print(f" ✗ Cache test failed: {e}") import traceback traceback.print_exc() return False def test_imports(): """Test all public imports""" print("\nTesting imports...") functions = [ "execute_code", "execute_async", "get_job", "wait_for_job", "cancel_job", "list_jobs", "get_languages", "detect_language", "session_snapshot", "service_snapshot", "list_snapshots", "restore_snapshot", "delete_snapshot", "CredentialsError", ] print(f" ✓ Imported {len(functions)} public functions and classes:") for func in functions: print(f" - {func}") return True def test_package_structure(): """Verify package structure""" print("\nVerifying package structure...") required_files = [ "src/__init__.py", "src/un.py", "setup.py", "README.md", "USAGE.md", "LICENSE", "MANIFEST.in", "pytest.ini", "tests/__init__.py", "tests/test_credentials.py", "tests/test_language_detection.py", "tests/test_signatures.py", "tests/test_caching.py", "tests/test_integration_mock.py", "tests/test_real_world_scenarios.py", ] base_dir = Path(__file__).parent all_exist = True for filename in required_files: filepath = base_dir / filename status = "✓" if filepath.exists() else "✗" print(f" {status} {filename}") if not filepath.exists(): all_exist = False return all_exist def test_example_structure(): """Verify examples exist""" print("\nVerifying examples...") example_files = [ "examples/hello_world.py", "examples/fibonacci.py", "examples/hello_world_client.py", "examples/fibonacci_client.py", "examples/json_processing.py", "examples/http_request.py", "examples/file_operations.py", ] base_dir = Path(__file__).parent all_exist = True for filename in example_files: filepath = base_dir / filename status = "✓" if filepath.exists() else "✗" print(f" {status} {filename}") if not filepath.exists(): all_exist = False return all_exist def main(): """Run all verification tests""" print("=" * 60) print("Unsandbox Python SDK (Sync) - Verification") print("=" * 60) tests = [ ("Package Structure", test_package_structure), ("Imports", test_imports), ("Language Detection", test_language_detection), ("Request Signing", test_request_signing), ("Credentials", test_credentials), ("Caching", test_caching), ("Examples", test_example_structure), ] results = [] for test_name, test_func in tests: try: result = test_func() results.append((test_name, result)) except Exception as e: print(f"\n✗ {test_name} failed with exception: {e}") import traceback traceback.print_exc() results.append((test_name, False)) print("\n" + "=" * 60) print("Summary") print("=" * 60) passed = sum(1 for _, result in results if result) total = len(results) for test_name, result in results: status = "✓" if result else "✗" print(f"{status} {test_name}") print(f"\nPassed: {passed}/{total}") if passed == total: print("\n✓ All verification tests passed!") return 0 else: print(f"\n✗ {total - passed} test(s) failed") return 1 if __name__ == "__main__": sys.exit(main())