83 lines
2.6 KiB
Python
83 lines
2.6 KiB
Python
"""Docker smoke test: build + run + healthcheck.
|
||
|
||
If Docker is not available, the test is skipped with a clear reason.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import shutil
|
||
import subprocess
|
||
import time
|
||
|
||
import pytest
|
||
|
||
|
||
def _docker_available() -> bool:
|
||
"""Check if Docker daemon is reachable."""
|
||
if shutil.which("docker") is None:
|
||
return False
|
||
try:
|
||
subprocess.run(
|
||
["docker", "info"], capture_output=True, timeout=5, check=True
|
||
)
|
||
return True
|
||
except (subprocess.SubprocessError, FileNotFoundError):
|
||
return False
|
||
|
||
|
||
@pytest.mark.skipif(
|
||
not _docker_available(),
|
||
reason="Docker daemon not available or docker CLI not found",
|
||
)
|
||
def test_docker_build_and_healthcheck() -> None:
|
||
"""Build the CRM image, run it briefly, and curl the health endpoint."""
|
||
project_dir = "/a0/.a0/crm-system"
|
||
|
||
# 1. Build
|
||
build_result = subprocess.run(
|
||
["docker", "build", "-t", "crm-system:test", project_dir],
|
||
capture_output=True, text=True, timeout=300,
|
||
)
|
||
assert build_result.returncode == 0, f"docker build failed:\n{build_result.stderr}"
|
||
|
||
# 2. Run container on exposed port 8765 → internal 8000
|
||
container_name = "crm-smoke-test"
|
||
run_result = subprocess.run(
|
||
[
|
||
"docker", "run", "--rm", "--detach",
|
||
"--name", container_name,
|
||
"-p", "8765:8000",
|
||
"crm-system:test",
|
||
],
|
||
capture_output=True, text=True, timeout=30,
|
||
)
|
||
assert run_result.returncode == 0, f"docker run failed:\n{run_result.stderr}"
|
||
container_id = run_result.stdout.strip()
|
||
|
||
# 3. Wait a moment, then curl /health
|
||
try:
|
||
time.sleep(5) # give uvicorn + alembic time
|
||
curl_result = subprocess.run(
|
||
["curl", "-s", "-o", "/dev/null", "-w", "%{http_code}", "http://localhost:8765/health"],
|
||
capture_output=True, text=True, timeout=10,
|
||
)
|
||
status = curl_result.stdout.strip()
|
||
assert status == "200", f"Health check returned HTTP {status}"
|
||
finally:
|
||
# 4. Stop container
|
||
subprocess.run(
|
||
["docker", "stop", container_id],
|
||
capture_output=True, timeout=15,
|
||
)
|
||
|
||
|
||
def test_docker_not_available_is_reported() -> None:
|
||
"""Document Docker availability in a non-skipped test so pytest reports it."""
|
||
if not _docker_available():
|
||
pytest.skip("Docker is not installed or the daemon is unreachable. "
|
||
"Docker smoke test was skipped. "
|
||
"Install Docker CE 24+ to run container-level tests.")
|
||
else:
|
||
# Docker is available – nothing to assert here.
|
||
pass
|