pytest_container
Testing Container Images with Python and Pytest
Dan Čermák
Dan Čermák
Software Developer @SUSE | |
i3 SIG, Package maintainer | |
Developer Tools, Testing and Documentation, Home Automation | |
https://dancermak.name | |
dcermak | |
@Defolos@mastodon.social |
When shell scripts are:
x86_64
, aarch64
, s390x
, ppcle64
import pytest
from pytest_container import Container, ContainerData
TW = Container(
url="registry.opensuse.org/opensuse/tumbleweed:latest"
)
@pytest.mark.parametrize("container", [TW], indirect=True)
def test_etc_os_release_present(container: ContainerData):
assert container.connection.file(
"/etc/os-release"
).exists
pytest
fixturesdef test_ehlo(smtp_connection):
response, msg = smtp_connection.ehlo()
assert response == 250
@pytest.mark.parametrize("x", [0, 1])
@pytest.mark.parametrize("y", [2, 3])
def test_foo(x: int, y: int):
# do something with x & y here
@pytest.mark.parametrize("smtp_connection", [25], indirect=True)
def test_ehlo(smtp_connection):
pass
WEB_SERVER = DerivedContainer(
base="registry.opensuse.org/opensuse/leap:latest",
containerfile="""RUN zypper -n in python3 \
&& echo "Hello Green World!" > index.html
ENTRYPOINT ["/usr/bin/python3", "-m", "http.server"]
"""
)
@pytest.mark.parametrize(
"container", [WEB_SERVER], indirect=True
)
def test_python_installed(container: ContainerData):
assert container.connection.package(
"python3"
).is_installed
TW = Container(
url="registry.opensuse.org/opensuse/tumbleweed:latest"
)
NGINX = DerivedContainer(
base=TW,
containerfile="RUN zypper -n in nginx",
)
NGINX_DEBUG = DerivedContainer(
base=NGINX,
containerfile="RUN zypper -n in gdb nginx-debuginfo"
)
CONTAINER_IMAGES=[NGINX_DEBUG]
def test_nginx(auto_container): ...
WEB_SERVER = DerivedContainer(
# snip
forwarded_ports=[PortForwarding(container_port=8000)],
)
@pytest.mark.parametrize(
"container", [WEB_SERVER], indirect=True
)
def test_port_forward(container: ContainerData, host):
cmd = (
"curl --fail localhost:"
+ str(container.forwarded_ports[0].host_port)
)
host.run_expect([0], cmd)
HEALTHCHECK
WEB_SERVER = DerivedContainer(
# snip
containerfile="""
ENTRYPOINT ["/usr/bin/python3", "-m", "http.server"]
HEALTHCHECK CMD curl --fail http://0.0.0.0:8000""",
)
@pytest.mark.parametrize("container", [WEB_SERVER], indirect=True)
def test_server_up(container, container_runtime):
assert (
container_runtime.get_container_health(
container.container_id
) == ContainerHealth.HEALTHY
)
MEDIAWIKI_FPM_POD = Pod(
containers=[MEDIAWIKI_FPM_CONTAINER, NGINX_FPM_PROXY],
forwarded_ports=[PortForwarding(container_port=80)],
)
@pytest.mark.parametrize(
"pod", [MEDIAWIKI_FPM_POD], indirect=True
)
def test_port_forward(pod: PodData, host):
cmd = (
"curl --fail localhost:"
+ str(pod.forwarded_ports[0].host_port)
)
host.run_expect([0], cmd)
use the container_per_test
fixture:
@pytest.mark.parametrize(
"container_per_test", [TW], indirect=True
)
def test_rm_rf(container_per_test):
container_per_test.connection.run_expect([0], "rm -rf /")
@pytest.mark.parametrize(
"container_per_test", [TW], indirect=True
)
def test_uninstall_zypper(container_per_test):
container_per_test.connection.run_expect(
[0], "rpm -e --nodeps zypper"
)
@pytest.mark.parametrize(
"container", [MY_IMAGE], indirect=True
)
def test_inspect(container: ContainerData):
inspect = container.inspect
assert inspect.config.user == "me"
assert inspect.config.cmd == ["/bin/sh"]
assert (
"HOME" in inspect.config.env
and inspect.config.env["HOME"] == "/src/"
)
Bind mounts
ROOTDIR_BIND_MOUNTED = DerivedContainer(
base="registry.opensuse.org/opensuse/tumbleweed",
volume_mounts=[
BindMount("/src/", host_path=get_rootdir())
],
)
@pytest.mark.parametrize(
"container", [ROOTDIR_BIND_MOUNTED], indirect=True
)
def test_bind_mount_cwd(container: ContainerData):
vol = container.container.volume_mounts[0]
assert container.connection.file("/src/").exists
Container volumes
WITH_VAR_LOG_VOLUME = DerivedContainer(
base="registry.opensuse.org/opensuse/tumbleweed",
volume_mounts=[ContainerVolume("/var/log/")],
)
use the auto_container
/ auto_container_per_test
fixtures:
CONTAINER_IMAGES = [TW, LEAP, SLE]
def test_etc_os_release(auto_container): ...
def test_zypper_rm_works(auto_container_per_test): ...
export CONTAINER_RUNTIME=docker
pytest -vv
pip install pytest-xdist
# or
poetry add --group dev pytest-xdist
pytest -vv -- -n auto
Answers!
Suggestions?