262 lines
8.2 KiB
Python
Executable File
262 lines
8.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
||
"""
|
||
Async Docker Operations Test Script
|
||
|
||
Tests the async Docker client implementation to ensure non-blocking operations
|
||
and improved concurrency in FastAPI async contexts.
|
||
"""
|
||
|
||
import os
|
||
import sys
|
||
import asyncio
|
||
import time
|
||
import logging
|
||
from pathlib import Path
|
||
|
||
# Add session-manager to path for imports
|
||
sys.path.insert(0, str(Path(__file__).parent))
|
||
|
||
from async_docker_client import (
|
||
AsyncDockerClient,
|
||
get_async_docker_client,
|
||
async_docker_ping,
|
||
async_create_container,
|
||
async_start_container,
|
||
async_stop_container,
|
||
async_remove_container,
|
||
async_list_containers,
|
||
async_get_container,
|
||
)
|
||
|
||
# Set up logging
|
||
logging.basicConfig(level=logging.INFO)
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
async def test_async_docker_client():
|
||
"""Test the async Docker client functionality."""
|
||
print("🧪 Testing Async Docker Client")
|
||
print("=" * 50)
|
||
|
||
# Test 1: Basic client initialization and ping
|
||
print("1️⃣ Testing client initialization and ping...")
|
||
try:
|
||
async with get_async_docker_client() as client:
|
||
ping_result = await client.ping()
|
||
if ping_result:
|
||
print("✅ Async Docker client ping successful")
|
||
else:
|
||
print("❌ Async Docker client ping failed")
|
||
return False
|
||
except Exception as e:
|
||
print(f"❌ Async client initialization failed: {e}")
|
||
return False
|
||
|
||
# Test 2: Container listing
|
||
print("\n2️⃣ Testing container listing...")
|
||
try:
|
||
containers = await async_list_containers(all=True)
|
||
print(f"✅ Successfully listed {len(containers)} containers")
|
||
except Exception as e:
|
||
print(f"❌ Container listing failed: {e}")
|
||
return False
|
||
|
||
# Test 3: System info retrieval
|
||
print("\n3️⃣ Testing system info retrieval...")
|
||
try:
|
||
async with get_async_docker_client() as client:
|
||
system_info = await client.get_system_info()
|
||
if system_info:
|
||
server_version = system_info.get("ServerVersion", "Unknown")
|
||
print(
|
||
f"✅ Docker system info retrieved: ServerVersion={server_version}"
|
||
)
|
||
else:
|
||
print("⚠️ System info retrieval returned None")
|
||
except Exception as e:
|
||
print(f"❌ System info retrieval failed: {e}")
|
||
return False
|
||
|
||
return True
|
||
|
||
|
||
async def test_concurrent_operations():
|
||
"""Test concurrent async Docker operations."""
|
||
print("\n⚡ Testing Concurrent Operations")
|
||
print("=" * 50)
|
||
|
||
async def concurrent_task(task_id: int):
|
||
"""Simulate concurrent Docker operation."""
|
||
try:
|
||
# Small delay to simulate processing
|
||
await asyncio.sleep(0.1)
|
||
|
||
# Perform a container listing operation
|
||
containers = await async_list_containers(all=False)
|
||
return f"Task {task_id}: Listed {len(containers)} containers"
|
||
except Exception as e:
|
||
return f"Task {task_id}: Failed - {e}"
|
||
|
||
# Test concurrent execution
|
||
print("1️⃣ Testing concurrent container listings...")
|
||
start_time = time.time()
|
||
|
||
# Launch multiple concurrent operations
|
||
tasks = [concurrent_task(i) for i in range(10)]
|
||
results = await asyncio.gather(*tasks, return_exceptions=True)
|
||
|
||
end_time = time.time()
|
||
duration = end_time - start_time
|
||
|
||
# Analyze results
|
||
successful = sum(
|
||
1 for r in results if not isinstance(r, Exception) and "Failed" not in str(r)
|
||
)
|
||
failed = len(results) - successful
|
||
|
||
print(f"✅ Concurrent operations completed in {duration:.2f}s")
|
||
print(f" Successful: {successful}/10")
|
||
print(f" Failed: {failed}/10")
|
||
|
||
if successful >= 8: # Allow some tolerance
|
||
print("✅ Concurrent operations test passed")
|
||
return True
|
||
else:
|
||
print("❌ Concurrent operations test failed")
|
||
return False
|
||
|
||
|
||
async def test_container_lifecycle():
|
||
"""Test full container lifecycle with async operations."""
|
||
print("\n🐳 Testing Container Lifecycle")
|
||
print("=" * 50)
|
||
|
||
container_name = f"test-async-container-{int(time.time())}"
|
||
|
||
try:
|
||
# Test container creation
|
||
print("1️⃣ Creating test container...")
|
||
container = await async_create_container(
|
||
image="alpine:latest",
|
||
name=container_name,
|
||
environment={"TEST": "async"},
|
||
command=["sleep", "30"],
|
||
)
|
||
print(f"✅ Container created: {container.id}")
|
||
|
||
# Test container start
|
||
print("\n2️⃣ Starting container...")
|
||
await async_start_container(container)
|
||
print("✅ Container started")
|
||
|
||
# Small delay to let container start
|
||
await asyncio.sleep(2)
|
||
|
||
# Test container retrieval
|
||
print("\n3️⃣ Retrieving container info...")
|
||
retrieved = await async_get_container(container_name)
|
||
if retrieved and retrieved.id == container.id:
|
||
print("✅ Container retrieval successful")
|
||
else:
|
||
print("❌ Container retrieval failed")
|
||
return False
|
||
|
||
# Test container stop
|
||
print("\n4️⃣ Stopping container...")
|
||
await async_stop_container(container, timeout=5)
|
||
print("✅ Container stopped")
|
||
|
||
# Test container removal
|
||
print("\n5️⃣ Removing container...")
|
||
await async_remove_container(container)
|
||
print("✅ Container removed")
|
||
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"❌ Container lifecycle test failed: {e}")
|
||
# Cleanup on failure
|
||
try:
|
||
container = await async_get_container(container_name)
|
||
if container:
|
||
await async_stop_container(container, timeout=5)
|
||
await async_remove_container(container)
|
||
print("🧹 Cleaned up failed test container")
|
||
except Exception:
|
||
pass
|
||
return False
|
||
|
||
|
||
async def test_performance_comparison():
|
||
"""Compare performance between sync and async operations."""
|
||
print("\n📊 Performance Comparison")
|
||
print("=" * 50)
|
||
|
||
# Test async performance
|
||
print("1️⃣ Testing async operation performance...")
|
||
async_start = time.time()
|
||
|
||
# Perform multiple async operations
|
||
tasks = []
|
||
for i in range(5):
|
||
tasks.append(async_list_containers(all=False))
|
||
tasks.append(async_docker_ping())
|
||
|
||
results = await asyncio.gather(*tasks, return_exceptions=True)
|
||
async_duration = time.time() - async_start
|
||
|
||
successful_async = sum(1 for r in results if not isinstance(r, Exception))
|
||
|
||
print(
|
||
f"✅ Async operations: {successful_async}/{len(tasks)} successful in {async_duration:.3f}s"
|
||
)
|
||
|
||
# Note: We can't easily test sync operations in the same process due to blocking
|
||
print("ℹ️ Note: Sync operations would block and cannot be tested concurrently")
|
||
|
||
return successful_async == len(tasks)
|
||
|
||
|
||
async def run_all_async_tests():
|
||
"""Run all async Docker operation tests."""
|
||
print("🚀 Async Docker Operations Test Suite")
|
||
print("=" * 60)
|
||
|
||
tests = [
|
||
("Async Docker Client", test_async_docker_client),
|
||
("Concurrent Operations", test_concurrent_operations),
|
||
("Container Lifecycle", test_container_lifecycle),
|
||
("Performance Comparison", test_performance_comparison),
|
||
]
|
||
|
||
results = []
|
||
for test_name, test_func in tests:
|
||
print(f"\n{'=' * 20} {test_name} {'=' * 20}")
|
||
try:
|
||
result = await test_func()
|
||
results.append(result)
|
||
status = "✅ PASSED" if result else "❌ FAILED"
|
||
print(f"\n{status}: {test_name}")
|
||
except Exception as e:
|
||
print(f"\n❌ ERROR in {test_name}: {e}")
|
||
results.append(False)
|
||
|
||
# Summary
|
||
print(f"\n{'=' * 60}")
|
||
passed = sum(results)
|
||
total = len(results)
|
||
print(f"📊 Test Results: {passed}/{total} tests passed")
|
||
|
||
if passed == total:
|
||
print("🎉 All async Docker operation tests completed successfully!")
|
||
print("⚡ Async operations are working correctly for improved concurrency.")
|
||
else:
|
||
print("⚠️ Some tests failed. Check the output above for details.")
|
||
print("💡 Ensure Docker daemon is running and accessible.")
|
||
|
||
return passed == total
|
||
|
||
|
||
if __name__ == "__main__":
|
||
asyncio.run(run_all_async_tests())
|