audit: clean Docker architecture, consolidate test fixtures, add containerized test runner (#94)

This commit is contained in:
Alexander Whitestone
2026-02-28 16:11:58 -05:00
committed by GitHub
parent 1e19164379
commit d7d7a5a80a
24 changed files with 700 additions and 494 deletions

View File

@@ -1,175 +1,120 @@
"""End-to-end tests for Docker deployment.
These tests verify that the Dockerized application starts correctly,
responds to requests, and all services are properly orchestrated.
These tests verify that Dockerfiles and compose configs are present,
syntactically valid, and declare the expected services and settings.
"""
import pytest
import subprocess
import time
import requests
import json
import subprocess
import pytest
from pathlib import Path
@pytest.fixture(scope="module")
def docker_compose_file():
"""Return the path to the docker-compose file."""
return Path(__file__).parent.parent.parent / "docker-compose.enhanced.yml"
@pytest.fixture(scope="module")
def docker_services_running(docker_compose_file):
"""Start Docker services for testing."""
if not docker_compose_file.exists():
pytest.skip("docker-compose.enhanced.yml not found")
# Start services
result = subprocess.run(
["docker", "compose", "-f", str(docker_compose_file), "up", "-d"],
capture_output=True,
text=True,
)
if result.returncode != 0:
pytest.skip(f"Failed to start Docker services: {result.stderr}")
# Wait for services to be ready
time.sleep(10)
yield
# Cleanup
subprocess.run(
["docker", "compose", "-f", str(docker_compose_file), "down"],
capture_output=True,
)
PROJECT_ROOT = Path(__file__).parent.parent.parent
@pytest.mark.skipif(
subprocess.run(["which", "docker"], capture_output=True).returncode != 0,
reason="Docker not installed"
reason="Docker not installed",
)
def test_docker_compose_file_exists():
"""Test that docker-compose.enhanced.yml exists."""
compose_file = Path(__file__).parent.parent.parent / "docker-compose.enhanced.yml"
assert compose_file.exists(), "docker-compose.enhanced.yml should exist"
class TestDockerComposeFiles:
"""Validate that all compose files exist and parse cleanly."""
def test_base_compose_exists(self):
assert (PROJECT_ROOT / "docker-compose.yml").exists()
def test_dev_overlay_exists(self):
assert (PROJECT_ROOT / "docker-compose.dev.yml").exists()
def test_prod_compose_exists(self):
assert (PROJECT_ROOT / "docker-compose.prod.yml").exists()
def test_test_compose_exists(self):
assert (PROJECT_ROOT / "docker-compose.test.yml").exists()
def test_microservices_compose_exists(self):
assert (PROJECT_ROOT / "docker-compose.microservices.yml").exists()
def test_base_compose_syntax(self):
result = subprocess.run(
["docker", "compose", "-f", str(PROJECT_ROOT / "docker-compose.yml"), "config"],
capture_output=True,
text=True,
)
assert result.returncode == 0, f"Docker Compose syntax error: {result.stderr}"
def test_microservices_compose_services_defined(self):
result = subprocess.run(
[
"docker", "compose",
"-f", str(PROJECT_ROOT / "docker-compose.microservices.yml"),
"config", "--format", "json",
],
capture_output=True,
text=True,
)
assert result.returncode == 0, f"Config error: {result.stderr}"
config = json.loads(result.stdout)
services = config.get("services", {})
assert "ollama" in services, "ollama service should be defined"
assert "dashboard" in services, "dashboard service should be defined"
assert "timmy" in services, "timmy service should be defined"
def test_microservices_compose_content(self):
content = (PROJECT_ROOT / "docker-compose.microservices.yml").read_text()
assert "ollama" in content
assert "dashboard" in content
assert "timmy" in content
assert "timmy-net" in content
assert "ollama-data" in content
assert "timmy-data" in content
def test_test_compose_has_test_runner(self):
content = (PROJECT_ROOT / "docker-compose.test.yml").read_text()
assert "test:" in content, "Test compose should define a 'test' service"
assert "TIMMY_TEST_MODE" in content
assert "pytest" in content
@pytest.mark.skipif(
subprocess.run(["which", "docker"], capture_output=True).returncode != 0,
reason="Docker not installed"
)
def test_docker_compose_syntax():
"""Test that docker-compose file has valid syntax."""
compose_file = Path(__file__).parent.parent.parent / "docker-compose.enhanced.yml"
result = subprocess.run(
["docker", "compose", "-f", str(compose_file), "config"],
capture_output=True,
text=True,
class TestDockerfiles:
"""Validate the primary Dockerfile and specialised images."""
def test_dockerfile_exists(self):
assert (PROJECT_ROOT / "Dockerfile").exists()
def test_dockerfile_ollama_exists(self):
assert (PROJECT_ROOT / "docker" / "Dockerfile.ollama").exists()
def test_dockerfile_agent_exists(self):
assert (PROJECT_ROOT / "docker" / "Dockerfile.agent").exists()
def test_dockerfile_dashboard_exists(self):
assert (PROJECT_ROOT / "docker" / "Dockerfile.dashboard").exists()
def test_dockerfile_test_exists(self):
assert (PROJECT_ROOT / "docker" / "Dockerfile.test").exists()
def test_dockerfile_health_check(self):
content = (PROJECT_ROOT / "Dockerfile").read_text()
assert "HEALTHCHECK" in content, "Dockerfile should include HEALTHCHECK"
assert "/health" in content
def test_dockerfile_non_root_user(self):
content = (PROJECT_ROOT / "Dockerfile").read_text()
assert "USER timmy" in content
assert "groupadd -r timmy" in content
@pytest.mark.skipif(
subprocess.run(["which", "docker"], capture_output=True).returncode != 0,
reason="Docker not installed",
)
assert result.returncode == 0, f"Docker Compose syntax error: {result.stderr}"
@pytest.mark.skipif(
subprocess.run(["which", "docker"], capture_output=True).returncode != 0,
reason="Docker not installed"
)
def test_dockerfile_exists():
"""Test that Dockerfile exists."""
dockerfile = Path(__file__).parent.parent.parent / "Dockerfile"
assert dockerfile.exists(), "Dockerfile should exist"
@pytest.mark.skipif(
subprocess.run(["which", "docker"], capture_output=True).returncode != 0,
reason="Docker not installed"
)
def test_dockerfile_ollama_exists():
"""Test that Dockerfile.ollama exists."""
dockerfile = Path(__file__).parent.parent.parent / "Dockerfile.ollama"
assert dockerfile.exists(), "Dockerfile.ollama should exist"
@pytest.mark.skipif(
subprocess.run(["which", "docker"], capture_output=True).returncode != 0,
reason="Docker not installed"
)
def test_docker_image_build():
"""Test that the Docker image can be built."""
result = subprocess.run(
["docker", "build", "-t", "timmy-time:test", "."],
cwd=Path(__file__).parent.parent.parent,
capture_output=True,
text=True,
timeout=300,
)
# Don't fail if build fails, just skip
if result.returncode != 0:
pytest.skip(f"Docker build failed: {result.stderr}")
@pytest.mark.skipif(
subprocess.run(["which", "docker"], capture_output=True, shell=True).returncode != 0,
reason="Docker not installed"
)
def test_docker_compose_services_defined():
"""Test that docker-compose defines all required services."""
compose_file = Path(__file__).parent.parent.parent / "docker-compose.enhanced.yml"
result = subprocess.run(
["docker", "compose", "-f", str(compose_file), "config"],
capture_output=True,
text=True,
)
assert result.returncode == 0, "Docker Compose config should be valid"
config = json.loads(result.stdout)
services = config.get("services", {})
# Check for required services
assert "ollama" in services, "ollama service should be defined"
assert "dashboard" in services, "dashboard service should be defined"
assert "timmy" in services, "timmy service should be defined"
def test_docker_compose_enhanced_yml_content():
"""Test that docker-compose.enhanced.yml has correct configuration."""
compose_file = Path(__file__).parent.parent.parent / "docker-compose.enhanced.yml"
with open(compose_file) as f:
content = f.read()
# Check for key configurations
assert "ollama" in content, "Should reference ollama service"
assert "dashboard" in content, "Should reference dashboard service"
assert "timmy" in content, "Should reference timmy agent"
assert "swarm-net" in content, "Should define swarm network"
assert "ollama-data" in content, "Should define ollama-data volume"
assert "timmy-data" in content, "Should define timmy-data volume"
def test_dockerfile_health_check():
"""Test that Dockerfile includes health check."""
dockerfile = Path(__file__).parent.parent.parent / "Dockerfile"
with open(dockerfile) as f:
content = f.read()
assert "HEALTHCHECK" in content, "Dockerfile should include HEALTHCHECK"
assert "/health" in content, "Health check should use /health endpoint"
def test_dockerfile_non_root_user():
"""Test that Dockerfile runs as non-root user."""
dockerfile = Path(__file__).parent.parent.parent / "Dockerfile"
with open(dockerfile) as f:
content = f.read()
assert "USER timmy" in content, "Dockerfile should run as non-root user"
assert "groupadd -r timmy" in content, "Dockerfile should create timmy user"
def test_docker_image_build(self):
result = subprocess.run(
["docker", "build", "-t", "timmy-time:test", "."],
cwd=PROJECT_ROOT,
capture_output=True,
text=True,
timeout=300,
)
if result.returncode != 0:
pytest.skip(f"Docker build failed: {result.stderr}")