Skip to content

Commit

Permalink
Migrate testing from pytest-dockerc to using python-on-whales
Browse files Browse the repository at this point in the history
The pytest-dockerc plug is unmaintained and there is now a dependency
issues with PyYAML because of the release of Cython v3 (which is itself
a build dependency for PyYAML). After some research this seemed like
the most similar package in terms of functionality to the package we
are replacing. Although it is not a pytest plugin it still provides
similar access and uses the Docker composition defined in the
repository.
  • Loading branch information
mcdonnnj committed Jul 20, 2023
1 parent 8c26a61 commit 065bfe6
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 14 deletions.
2 changes: 1 addition & 1 deletion requirements-test.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
--requirement requirements.txt
pre-commit
pytest
pytest-dockerc
python-on-whales
19 changes: 15 additions & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,26 @@
"""
# Third-Party Libraries
import pytest
from python_on_whales import docker

MAIN_SERVICE_NAME = "example"
VERSION_SERVICE_NAME = f"{MAIN_SERVICE_NAME}-version"


@pytest.fixture(scope="session")
def dockerc():
"""Start up the Docker composition."""
docker.compose.up(detach=True)
yield docker
docker.compose.down()


@pytest.fixture(scope="session")
def main_container(dockerc):
"""Return the main container from the Docker composition."""
# find the container by name even if it is stopped already
return dockerc.containers(service_names=[MAIN_SERVICE_NAME], stopped=True)[0]
# Find the container by name even if it is stopped already.
# Note: There should only be a single container returned
yield dockerc.compose.ps(services=[MAIN_SERVICE_NAME], all=True)[0]


@pytest.fixture(scope="session")
Expand All @@ -22,8 +32,9 @@ def version_container(dockerc):
The version container should just output the version of its underlying contents.
"""
# find the container by name even if it is stopped already
return dockerc.containers(service_names=[VERSION_SERVICE_NAME], stopped=True)[0]
# Find the container by name even if it is stopped already.
# Note: There should only be a single container returned
yield dockerc.compose.ps(services=[VERSION_SERVICE_NAME], all=True)[0]


def pytest_addoption(parser):
Expand Down
58 changes: 49 additions & 9 deletions tests/container_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ def test_container_count(dockerc):
"""Verify the test composition and container."""
# stopped parameter allows non-running containers in results
assert (
len(dockerc.containers(stopped=True)) == 2
len(dockerc.compose.ps(all=True)) == 2
), "Wrong number of containers were started."


def test_wait_for_ready(main_container):
"""Wait for container to be ready."""
TIMEOUT = 10
for i in range(TIMEOUT):
if READY_MESSAGE in main_container.logs().decode("utf-8"):
if READY_MESSAGE in main_container.logs():
break
time.sleep(1)
else:
Expand All @@ -42,16 +42,46 @@ def test_wait_for_ready(main_container):

def test_wait_for_exits(main_container, version_container):
"""Wait for containers to exit."""
assert main_container.wait() == 0, "Container service (main) did not exit cleanly"
TIMEOUT = 30
ELAPSED = 0
for i in range(TIMEOUT):
if main_container.state.status == "exited":
break
time.sleep(1)
ELAPSED += 1
else:
raise Exception(
f"Container service (main) did not exit within {TIMEOUT} seconds."
)
for i in range(TIMEOUT - ELAPSED):
if version_container.state.status == "exited":
break
time.sleep(1)
else:
raise Exception(
f"Container service (version) did not exit within {TIMEOUT} seconds."
)
assert (
main_container.state.exit_code == 0
), "Container service (main) did not exit cleanly"
assert (
version_container.wait() == 0
version_container.state.exit_code == 0
), "Container service (version) did not exit cleanly"


def test_output(main_container):
"""Verify the container had the correct output."""
main_container.wait() # make sure container exited if running test isolated
log_output = main_container.logs().decode("utf-8")
# make sure container exited if running test isolated
TIMEOUT = 30
for i in range(TIMEOUT):
if main_container.state.status == "exited":
break
time.sleep(1)
else:
raise Exception(
f"Container service (main) did not exit within {TIMEOUT} seconds."
)
log_output = main_container.logs()
assert SECRET_QUOTE in log_output, "Secret not found in log output."


Expand All @@ -71,8 +101,17 @@ def test_release_version():

def test_log_version(version_container):
"""Verify the container outputs the correct version to the logs."""
version_container.wait() # make sure container exited if running test isolated
log_output = version_container.logs().decode("utf-8").strip()
# make sure container exited if running test isolated
TIMEOUT = 30
for i in range(TIMEOUT):
if version_container.state.status == "exited":
break
time.sleep(1)
else:
raise Exception(
f"Container service (version) did not exit within {TIMEOUT} seconds."
)
log_output = version_container.logs().strip()
pkg_vars = {}
with open(VERSION_FILE) as f:
exec(f.read(), pkg_vars) # nosec
Expand All @@ -89,5 +128,6 @@ def test_container_version_label_matches(version_container):
exec(f.read(), pkg_vars) # nosec
project_version = pkg_vars["__version__"]
assert (
version_container.labels["org.opencontainers.image.version"] == project_version
version_container.config.labels["org.opencontainers.image.version"]
== project_version
), "Dockerfile version label does not match project version"

0 comments on commit 065bfe6

Please sign in to comment.