Refactor ACME/Certbot E2E test fixture to use staged service startup for improved reliability
This commit is contained in:
parent
1493beb227
commit
9d1e947675
1 changed files with 75 additions and 19 deletions
|
|
@ -865,37 +865,93 @@ def wait_for_pebble() -> bool:
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def docker_compose_acme() -> Generator[None, None, None]:
|
def docker_compose_acme() -> Generator[None, None, None]:
|
||||||
"""Fixture for docker-compose-acme-e2e.yml - ACME/Certbot E2E test"""
|
"""
|
||||||
|
Fixture for docker-compose-acme-e2e.yml - ACME/Certbot E2E test
|
||||||
|
|
||||||
|
Uses staged startup to ensure services start in the correct order:
|
||||||
|
1. Pebble ACME server first
|
||||||
|
2. HAProxy (after Pebble is ready)
|
||||||
|
3. Backend
|
||||||
|
"""
|
||||||
volume_name = "docker_certbot-certs"
|
volume_name = "docker_certbot-certs"
|
||||||
|
compose_file = str(DOCKER_DIR / "docker-compose-acme-e2e.yml")
|
||||||
|
|
||||||
# Download Pebble CA certificate (only once per test session)
|
# Download Pebble CA certificate (only once per test session)
|
||||||
create_pebble_ca_file()
|
create_pebble_ca_file()
|
||||||
|
|
||||||
# Clean up volume from previous test runs (ensures fresh start)
|
# Clean up volume from previous test runs (ensures fresh start)
|
||||||
subprocess.run(
|
|
||||||
["docker", "volume", "rm", volume_name],
|
|
||||||
stdout=subprocess.DEVNULL,
|
|
||||||
stderr=subprocess.DEVNULL # Ignore error if volume doesn't exist
|
|
||||||
)
|
|
||||||
|
|
||||||
# Use custom health check for Pebble with generous timeout for CI
|
|
||||||
fixture = DockerComposeFixture(
|
|
||||||
str(DOCKER_DIR / "docker-compose-acme-e2e.yml"),
|
|
||||||
startup_wait=0,
|
|
||||||
health_check=wait_for_pebble,
|
|
||||||
health_check_timeout=90 # Extended timeout for slow CI environments
|
|
||||||
)
|
|
||||||
fixture.up()
|
|
||||||
yield
|
|
||||||
fixture.down()
|
|
||||||
|
|
||||||
# Clean up volume after test
|
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
["docker", "volume", "rm", volume_name],
|
["docker", "volume", "rm", volume_name],
|
||||||
stdout=subprocess.DEVNULL,
|
stdout=subprocess.DEVNULL,
|
||||||
stderr=subprocess.DEVNULL
|
stderr=subprocess.DEVNULL
|
||||||
)
|
)
|
||||||
|
|
||||||
|
print()
|
||||||
|
print(" → Starting ACME test environment in stages...")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Stage 1: Start Pebble ACME server first
|
||||||
|
print(" → Stage 1: Starting Pebble ACME server...")
|
||||||
|
result = subprocess.run(
|
||||||
|
["docker", "compose", "-f", compose_file, "up", "-d", "pebble"],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
check=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# Wait for Pebble to be ready
|
||||||
|
print(" → Waiting for Pebble to be ready (timeout: 90s)...")
|
||||||
|
start_time = time.time()
|
||||||
|
while time.time() - start_time < 90:
|
||||||
|
if wait_for_pebble():
|
||||||
|
break
|
||||||
|
time.sleep(1)
|
||||||
|
else:
|
||||||
|
raise TimeoutError("Pebble did not become ready within 90 seconds")
|
||||||
|
|
||||||
|
# Stage 2: Start HAProxy
|
||||||
|
print(" → Stage 2: Starting HAProxy...")
|
||||||
|
result = subprocess.run(
|
||||||
|
["docker", "compose", "-f", compose_file, "up", "-d", "haproxy"],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
check=True
|
||||||
|
)
|
||||||
|
print(" → Waiting for HAProxy to initialize...")
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
# Stage 3: Start Backend
|
||||||
|
print(" → Stage 3: Starting backend...")
|
||||||
|
result = subprocess.run(
|
||||||
|
["docker", "compose", "-f", compose_file, "up", "-d", "backend"],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
check=True
|
||||||
|
)
|
||||||
|
print(" → Waiting for backend to initialize...")
|
||||||
|
time.sleep(3)
|
||||||
|
|
||||||
|
print(" ✓ All services started and ready")
|
||||||
|
|
||||||
|
yield
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# Cleanup
|
||||||
|
print(" → Stopping ACME test environment...")
|
||||||
|
subprocess.run(
|
||||||
|
["docker", "compose", "-f", compose_file, "down", "--remove-orphans", "-t", "0"],
|
||||||
|
capture_output=True,
|
||||||
|
text=True
|
||||||
|
)
|
||||||
|
print(" ✓ Services stopped and cleaned up")
|
||||||
|
|
||||||
|
# Clean up volume
|
||||||
|
subprocess.run(
|
||||||
|
["docker", "volume", "rm", volume_name],
|
||||||
|
stdout=subprocess.DEVNULL,
|
||||||
|
stderr=subprocess.DEVNULL
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.acme
|
@pytest.mark.acme
|
||||||
class TestACME:
|
class TestACME:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue