Skip to main content
Glama

Fal.ai MCP Server

by raveenb
test_docker.py11.5 kB
"""Tests for Docker container functionality These tests require Docker to be installed and running. They are skipped in CI environments where Docker-in-Docker is not available. Run these tests locally with: pytest tests/test_docker.py """ import os import subprocess import time import pytest def docker_available(): """Check if Docker is available and usable""" # Skip Docker tests in CI environment (act or GitHub Actions) if os.environ.get("CI") == "true" or os.environ.get("GITHUB_ACTIONS") == "true": return False try: result = subprocess.run( ["docker", "--version"], capture_output=True, text=True, check=False ) if result.returncode != 0: return False # Also check if Docker daemon is running result = subprocess.run( ["docker", "info"], capture_output=True, text=True, check=False ) return result.returncode == 0 except FileNotFoundError: return False @pytest.mark.skipif(not docker_available(), reason="Docker not available") class TestDockerIntegration: """Docker integration tests""" @classmethod def setup_class(cls): """Build the Docker image before tests""" # Build the test image result = subprocess.run( ["docker", "build", "-t", "fal-mcp-test:pytest", "."], capture_output=True, text=True, check=False, ) if result.returncode != 0: pytest.skip(f"Failed to build Docker image: {result.stderr}") @classmethod def teardown_class(cls): """Clean up Docker containers and images""" # Stop and remove any test containers subprocess.run( ["docker", "rm", "-f", "fal-mcp-pytest"], capture_output=True, check=False ) def test_docker_image_builds(self): """Test that Docker image builds successfully""" result = subprocess.run( ["docker", "images", "fal-mcp-test:pytest", "--format", "{{.Repository}}"], capture_output=True, text=True, check=True, ) assert "fal-mcp-test" in result.stdout def test_docker_help_command(self): """Test that Docker container can run Python commands""" # Just test that Python works in the container result = subprocess.run( [ "docker", "run", "--rm", "fal-mcp-test:pytest", "python", "-c", "print('Python works')", ], capture_output=True, text=True, check=True, ) assert "Python works" in result.stdout def test_docker_http_mode(self): """Test Docker container in HTTP mode""" # Clean up any existing container first subprocess.run( ["docker", "rm", "-f", "fal-mcp-pytest"], capture_output=True, check=False ) # Start container in HTTP mode result = subprocess.run( [ "docker", "run", "-d", "--name", "fal-mcp-pytest", "-e", "FAL_KEY=test-key", "-e", "FAL_MCP_TRANSPORT=http", "-p", "8090:8080", "fal-mcp-test:pytest", "python", "-m", "fal_mcp_server.server_http", "--port", "8080", ], capture_output=True, check=True, ) # Wait for container to start time.sleep(5) # Give more time for the server to start try: # Check if container is running result = subprocess.run( [ "docker", "ps", "--filter", "name=fal-mcp-pytest", "--format", "{{.Names}}", ], capture_output=True, text=True, check=True, ) assert "fal-mcp-pytest" in result.stdout # Just check that the server is responding (simpler test) # SSE connections can be tricky in tests logs = subprocess.run( ["docker", "logs", "fal-mcp-pytest"], capture_output=True, text=True, check=False, ) # Check that server started successfully assert ( "Uvicorn running on" in logs.stderr or "Server running" in logs.stderr ) finally: # Stop and remove container subprocess.run( ["docker", "rm", "-f", "fal-mcp-pytest"], capture_output=True, check=False, ) def test_docker_environment_variables(self): """Test that environment variables are properly set""" result = subprocess.run( [ "docker", "run", "--rm", "-e", "FAL_KEY=test-key-123", "-e", "FAL_MCP_TRANSPORT=http", "-e", "FAL_MCP_PORT=9000", "fal-mcp-test:pytest", "sh", "-c", "echo $FAL_KEY $FAL_MCP_TRANSPORT $FAL_MCP_PORT", ], capture_output=True, text=True, check=True, ) assert "test-key-123" in result.stdout assert "http" in result.stdout assert "9000" in result.stdout def test_docker_healthcheck(self): """Test Docker container health check""" # Clean up any existing container first subprocess.run( ["docker", "rm", "-f", "fal-mcp-pytest"], capture_output=True, check=False ) # Start container subprocess.run( [ "docker", "run", "-d", "--name", "fal-mcp-pytest", "-e", "FAL_KEY=test-key", "-p", "8091:8080", "fal-mcp-test:pytest", "python", "-m", "fal_mcp_server.server_http", ], capture_output=True, check=True, ) try: # Wait for container to be healthy max_attempts = 15 # More attempts since health check has start period healthy = False for _ in range(max_attempts): result = subprocess.run( [ "docker", "inspect", "--format", "{{.State.Health.Status}}", "fal-mcp-pytest", ], capture_output=True, text=True, check=False, ) if "healthy" in result.stdout: healthy = True break elif "unhealthy" in result.stdout: # Get logs for debugging logs = subprocess.run( ["docker", "logs", "fal-mcp-pytest"], capture_output=True, text=True, check=False, ) print(f"Container unhealthy. Logs: {logs.stdout}") break time.sleep(2) # Health check should have succeeded or container should be starting assert healthy or "starting" in result.stdout finally: # Clean up subprocess.run( ["docker", "rm", "-f", "fal-mcp-pytest"], capture_output=True, check=False, ) def test_docker_non_root_user(self): """Test that container runs as non-root user""" result = subprocess.run( [ "docker", "run", "--rm", "fal-mcp-test:pytest", "whoami", ], capture_output=True, text=True, check=True, ) assert "mcp" in result.stdout def test_docker_volume_mount(self): """Test that volumes can be mounted""" import tempfile # Create a temporary file in a more portable way with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".txt") as f: test_content = "test configuration" f.write(test_content) temp_path = f.name try: result = subprocess.run( [ "docker", "run", "--rm", "-v", f"{temp_path}:/app/config.txt", "fal-mcp-test:pytest", "cat", "/app/config.txt", ], capture_output=True, text=True, check=True, ) assert test_content in result.stdout finally: # Clean up if os.path.exists(temp_path): os.remove(temp_path) def get_docker_compose_command(): """Get the appropriate docker compose command""" # Try 'docker compose' first (newer Docker versions) result = subprocess.run( ["docker", "compose", "version"], capture_output=True, check=False, ) if result.returncode == 0: return ["docker", "compose"] # Try 'docker-compose' (older Docker versions) result = subprocess.run( ["docker-compose", "--version"], capture_output=True, check=False, ) if result.returncode == 0: return ["docker-compose"] return None @pytest.mark.skipif(not docker_available(), reason="Docker not available") class TestDockerCompose: """Docker Compose integration tests""" def test_docker_compose_config(self): """Test that docker-compose.yml is valid""" compose_cmd = get_docker_compose_command() if compose_cmd is None: pytest.skip("Docker Compose not available") result = subprocess.run( compose_cmd + ["config"], capture_output=True, text=True, check=False, ) # Should parse without errors or show services assert result.returncode == 0 or "services" in result.stdout def test_docker_compose_build(self): """Test that docker-compose can build the image""" compose_cmd = get_docker_compose_command() if compose_cmd is None: pytest.skip("Docker Compose not available") # Just validate the config, don't actually build result = subprocess.run( compose_cmd + ["config", "--quiet"], capture_output=True, text=True, check=False, timeout=30, ) # Config should be valid assert result.returncode == 0 or len(result.stderr) == 0 # File validation tests moved to test_docker_basic.py # These runtime tests require actual Docker daemon access

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/raveenb/fal-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server