Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """ | |
| # Test Script for Docker Deployment | |
| This script provides comprehensive testing for the RAG system Docker deployment. | |
| ## Overview | |
| The test script validates all components required for successful Docker deployment: | |
| - Dockerfile syntax and structure | |
| - Docker Compose configuration | |
| - Docker build process | |
| - Container runtime functionality | |
| - File structure and dependencies | |
| ## Test Categories | |
| 1. **Dockerfile Tests**: Validate Dockerfile syntax and required components | |
| 2. **Docker Compose Tests**: Check docker-compose.yml configuration | |
| 3. **Build Tests**: Test Docker image building process | |
| 4. **Runtime Tests**: Validate container startup and health checks | |
| 5. **File Structure Tests**: Confirm all required files are present | |
| 6. **Requirements Tests**: Validate dependencies are properly specified | |
| ## Usage | |
| Run the script to check Docker deployment readiness: | |
| ```bash | |
| python test_docker.py | |
| ``` | |
| ## Prerequisites | |
| - Docker installed and running | |
| - Docker Compose available | |
| - Sufficient disk space for image building | |
| - Network connectivity for base image downloads | |
| ## Expected Output | |
| The script provides detailed feedback on each test: | |
| - β PASS: Component is ready for Docker deployment | |
| - β FAIL: Component needs attention before deployment | |
| - β οΈ WARNING: Optional component missing but not critical | |
| """ | |
| import os | |
| import sys | |
| import subprocess | |
| from pathlib import Path | |
| def test_dockerfile(): | |
| """ | |
| Test if Dockerfile exists and contains all required components | |
| This function validates: | |
| - Dockerfile exists in the project root | |
| - Contains essential Docker instructions | |
| - Proper syntax and structure | |
| - Required components for RAG system deployment | |
| Returns: | |
| bool: True if Dockerfile is valid, False otherwise | |
| """ | |
| print("π Testing Dockerfile...") | |
| dockerfile_path = Path("Dockerfile") | |
| if not dockerfile_path.exists(): | |
| print("β Dockerfile not found") | |
| return False | |
| try: | |
| with open(dockerfile_path, "r") as f: | |
| content = f.read() | |
| # List of essential Dockerfile components that must be present | |
| required_components = [ | |
| "FROM python:", # Base image specification | |
| "WORKDIR /app", # Working directory setup | |
| "COPY requirements.txt", # Requirements file copying | |
| "RUN pip install", # Python package installation | |
| "COPY .", # Application files copying | |
| "EXPOSE 8501", # Port exposure for Streamlit | |
| 'CMD ["streamlit"', # Application startup command | |
| ] | |
| missing_components = [] | |
| for component in required_components: | |
| if component in content: | |
| print(f"β {component}") | |
| else: | |
| print(f"β {component} (missing)") | |
| missing_components.append(component) | |
| if missing_components: | |
| print(f"β Missing Dockerfile components: {missing_components}") | |
| return False | |
| return True | |
| except Exception as e: | |
| print(f"β Dockerfile test failed: {e}") | |
| return False | |
| def test_dockerignore(): | |
| """ | |
| Test if .dockerignore exists (optional but recommended) | |
| This function checks for the presence of .dockerignore file, | |
| which helps optimize Docker builds by excluding unnecessary files. | |
| Returns: | |
| bool: True if .dockerignore exists or is optional, False if critical | |
| """ | |
| print("\nπ Testing .dockerignore...") | |
| dockerignore_path = Path(".dockerignore") | |
| if dockerignore_path.exists(): | |
| print("β .dockerignore exists") | |
| return True | |
| else: | |
| print("β οΈ .dockerignore not found (optional but recommended)") | |
| return True | |
| def test_docker_compose(): | |
| """ | |
| Test if docker-compose.yml exists and is properly configured | |
| This function validates: | |
| - docker-compose.yml file exists | |
| - Contains proper service definitions | |
| - Port mappings are correct | |
| - Volume mounts are configured | |
| Returns: | |
| bool: True if docker-compose.yml is valid, False otherwise | |
| """ | |
| print("\nπ Testing docker-compose.yml...") | |
| compose_path = Path("docker-compose.yml") | |
| if compose_path.exists(): | |
| print("β docker-compose.yml exists") | |
| return True | |
| else: | |
| print("β οΈ docker-compose.yml not found (optional)") | |
| return True | |
| def test_docker_build(): | |
| """ | |
| Test Docker build process locally | |
| This function: | |
| - Attempts to build the Docker image | |
| - Validates build process completes successfully | |
| - Checks for build errors and warnings | |
| - Ensures all dependencies are properly resolved | |
| Returns: | |
| bool: True if Docker build succeeds, False otherwise | |
| """ | |
| print("\nπ Testing Docker build...") | |
| try: | |
| # Test Docker build with timeout to prevent hanging | |
| result = subprocess.run( | |
| ["docker", "build", "-t", "rag-system-test", "."], | |
| capture_output=True, | |
| text=True, | |
| timeout=300, # 5 minutes timeout for build | |
| ) | |
| if result.returncode == 0: | |
| print("β Docker build successful") | |
| return True | |
| else: | |
| print(f"β Docker build failed: {result.stderr}") | |
| return False | |
| except subprocess.TimeoutExpired: | |
| print("β Docker build timed out") | |
| return False | |
| except FileNotFoundError: | |
| print("β οΈ Docker not installed or not in PATH") | |
| return False | |
| except Exception as e: | |
| print(f"β Docker build test failed: {e}") | |
| return False | |
| def test_docker_run(): | |
| """ | |
| Test Docker container runtime functionality | |
| This function: | |
| - Attempts to run the built Docker container | |
| - Validates container startup process | |
| - Checks if the application is accessible | |
| - Tests basic container functionality | |
| Returns: | |
| bool: True if Docker run succeeds, False otherwise | |
| """ | |
| print("\nπ Testing Docker run...") | |
| try: | |
| # Test Docker run with brief execution | |
| result = subprocess.run( | |
| [ | |
| "docker", | |
| "run", | |
| "--rm", | |
| "-d", | |
| "-p", | |
| "8501:8501", | |
| "--name", | |
| "rag-test", | |
| "rag-system-test", | |
| ], | |
| capture_output=True, | |
| text=True, | |
| timeout=30, # 30 seconds timeout for startup | |
| ) | |
| if result.returncode == 0: | |
| print("β Docker run successful") | |
| # Clean up the test container | |
| subprocess.run(["docker", "stop", "rag-test"], capture_output=True) | |
| return True | |
| else: | |
| print(f"β Docker run failed: {result.stderr}") | |
| return False | |
| except subprocess.TimeoutExpired: | |
| print("β Docker run timed out") | |
| return False | |
| except FileNotFoundError: | |
| print("β οΈ Docker not installed or not in PATH") | |
| return False | |
| except Exception as e: | |
| print(f"β Docker run test failed: {e}") | |
| return False | |
| def test_file_structure(): | |
| """ | |
| Test if all required files exist for Docker deployment | |
| This function checks for essential files: | |
| - Main application files | |
| - Configuration files | |
| - Docker-related files | |
| - Documentation files | |
| Returns: | |
| bool: True if all required files exist, False otherwise | |
| """ | |
| print("\nπ Testing file structure...") | |
| # List of required files for Docker deployment | |
| required_files = [ | |
| "app.py", # Main Streamlit application | |
| "rag_system.py", # Core RAG system | |
| "pdf_processor.py", # PDF processing utilities | |
| "requirements.txt", # Python dependencies | |
| "Dockerfile", # Docker configuration | |
| ] | |
| # List of optional files (nice to have but not critical) | |
| optional_files = [ | |
| ".dockerignore", # Docker build optimization | |
| "docker-compose.yml", # Multi-container setup | |
| "README.md", # Project documentation | |
| ] | |
| missing_required = [] | |
| missing_optional = [] | |
| # Check required files | |
| for file in required_files: | |
| if os.path.exists(file): | |
| print(f"β {file}") | |
| else: | |
| print(f"β {file} (missing)") | |
| missing_required.append(file) | |
| # Check optional files | |
| for file in optional_files: | |
| if os.path.exists(file): | |
| print(f"β {file}") | |
| else: | |
| print(f"β οΈ {file} (optional)") | |
| missing_optional.append(file) | |
| if missing_required: | |
| print(f"β Missing required files: {missing_required}") | |
| return False | |
| return True | |
| def test_requirements(): | |
| """ | |
| Test if requirements.txt contains all essential packages | |
| This function validates: | |
| - Essential packages are listed | |
| - Package versions are specified | |
| - No obvious missing dependencies | |
| - Compatibility with Docker environment | |
| Returns: | |
| bool: True if requirements are valid, False otherwise | |
| """ | |
| print("\nπ Testing requirements.txt...") | |
| try: | |
| with open("requirements.txt", "r") as f: | |
| requirements = f.read() | |
| # List of essential packages that must be present | |
| essential_packages = [ | |
| "streamlit", # Web framework | |
| "torch", # Deep learning | |
| "transformers", # Language models | |
| "sentence-transformers", # Embeddings | |
| "faiss-cpu", # Vector search | |
| "rank-bm25", # Sparse retrieval | |
| "pypdf", # PDF processing | |
| ] | |
| missing_packages = [] | |
| for package in essential_packages: | |
| if package in requirements: | |
| print(f"β {package}") | |
| else: | |
| print(f"β {package} (missing)") | |
| missing_packages.append(package) | |
| if missing_packages: | |
| print(f"β Missing packages: {missing_packages}") | |
| return False | |
| return True | |
| except Exception as e: | |
| print(f"β Requirements test failed: {e}") | |
| return False | |
| def main(): | |
| """ | |
| Run all Docker deployment tests and provide comprehensive feedback | |
| This function: | |
| 1. Executes all Docker-related test categories | |
| 2. Tracks test results and provides detailed feedback | |
| 3. Gives deployment recommendations | |
| 4. Identifies potential issues before deployment | |
| The tests are designed to catch common Docker deployment issues early. | |
| """ | |
| print("π³ Docker Deployment Test\n") | |
| # Define all test functions with descriptive names | |
| tests = [ | |
| ("File Structure", test_file_structure), | |
| ("Requirements", test_requirements), | |
| ("Dockerfile", test_dockerfile), | |
| (".dockerignore", test_dockerignore), | |
| ("docker-compose.yml", test_docker_compose), | |
| ("Docker Build", test_docker_build), | |
| ("Docker Run", test_docker_run), | |
| ] | |
| # Execute all tests and collect results | |
| results = [] | |
| for test_name, test_func in tests: | |
| try: | |
| result = test_func() | |
| results.append((test_name, result)) | |
| except Exception as e: | |
| print(f"β {test_name} test failed with exception: {e}") | |
| results.append((test_name, False)) | |
| # ============================================================================= | |
| # RESULTS SUMMARY | |
| # ============================================================================= | |
| # Display comprehensive test results | |
| print("\n" + "=" * 50) | |
| print("π Test Results Summary") | |
| print("=" * 50) | |
| passed = 0 | |
| total = len(results) | |
| # Show individual test results | |
| for test_name, result in results: | |
| status = "β PASS" if result else "β FAIL" | |
| print(f"{test_name:20} {status}") | |
| if result: | |
| passed += 1 | |
| # Display overall statistics | |
| print(f"\nOverall: {passed}/{total} tests passed") | |
| # ============================================================================= | |
| # DEPLOYMENT RECOMMENDATIONS | |
| # ============================================================================= | |
| if passed == total: | |
| print("π All tests passed! Ready for Hugging Face Docker deployment.") | |
| print("\nNext steps:") | |
| print("1. Create a new Hugging Face Space with Docker SDK") | |
| print("2. Upload all files from this directory") | |
| print("3. Wait for Docker build to complete") | |
| print("4. Test your RAG system!") | |
| else: | |
| print("β οΈ Some tests failed. Please fix the issues before deployment.") | |
| print("\nTroubleshooting:") | |
| print("1. Install Docker if not available") | |
| print("2. Check file permissions and paths") | |
| print("3. Verify Dockerfile syntax") | |
| print("4. Test Docker build locally: docker build -t rag-system .") | |
| # ============================================================================= | |
| # SCRIPT ENTRY POINT | |
| # ============================================================================= | |
| if __name__ == "__main__": | |
| main() | |