Skip to content

Commit

Permalink
Refactor docker-py compatibility tests
Browse files Browse the repository at this point in the history
* Add which python client is being used to run tests, see "python
  client" below.
* Remove redundate code from test classes
* Update/Add comments to modules and classes

======================================================= test session starts ========================================================
platform linux -- Python 3.10.0, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
python client -- DockerClient
rootdir: /home/jhonce/Projects/go/src/github.com/containers/podman
plugins: requests-mock-1.8.0
collected 33 items

test/python/docker/compat/test_containers.py ...s..............  [ 54%]
test/python/docker/compat/test_images.py ............  [ 90%]
test/python/docker/compat/test_system.py ...  [100%]

Note: Follow-up PRs will verify the test results and expand the tests.

Signed-off-by: Jhon Honce <[email protected]>
  • Loading branch information
jwhonce committed Mar 1, 2022
1 parent c39dffe commit 7729afe
Show file tree
Hide file tree
Showing 9 changed files with 275 additions and 299 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ validate.completions:
.PHONY: run-docker-py-tests
run-docker-py-tests:
touch test/__init__.py
env CONTAINERS_CONF=$(CURDIR)/test/apiv2/containers.conf pytest test/python/docker/
env CONTAINERS_CONF=$(CURDIR)/test/apiv2/containers.conf pytest --disable-warnings test/python/docker/
-rm test/__init__.py

.PHONY: localunit
Expand Down
15 changes: 15 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[tool.black]
line-length = 100
target-version = ['py36']
include = '\.pyi?$'
exclude = '''
/(
\.git
| \.tox
| \.venv
| build
| dist
| docs
| hack
)/
'''
30 changes: 16 additions & 14 deletions test/python/docker/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import configparser
"""
Helpers for integration tests using DockerClient
"""
import json
import os
import pathlib
Expand All @@ -11,7 +13,7 @@
from .compat import constant


class Podman(object):
class PodmanAPI:
"""
Instances hold the configuration and setup for running podman commands
"""
Expand Down Expand Up @@ -53,17 +55,13 @@ def __init__(self):
"""

with open(os.environ["CONTAINERS_REGISTRIES_CONF"], "w") as w:
w.write(conf)
with open(os.environ["CONTAINERS_REGISTRIES_CONF"], "w") as file:
file.write(conf)

os.environ["CNI_CONFIG_PATH"] = os.path.join(
self.anchor_directory, "cni", "net.d"
)
os.environ["CNI_CONFIG_PATH"] = os.path.join(self.anchor_directory, "cni", "net.d")
os.makedirs(os.environ["CNI_CONFIG_PATH"], exist_ok=True)
self.cmd.append("--network-config-dir=" + os.environ["CNI_CONFIG_PATH"])
cni_cfg = os.path.join(
os.environ["CNI_CONFIG_PATH"], "87-podman-bridge.conflist"
)
cni_cfg = os.path.join(os.environ["CNI_CONFIG_PATH"], "87-podman-bridge.conflist")
# json decoded and encoded to ensure legal json
buf = json.loads(
"""
Expand Down Expand Up @@ -93,8 +91,8 @@ def __init__(self):
}
"""
)
with open(cni_cfg, "w") as w:
json.dump(buf, w)
with open(cni_cfg, "w") as file:
json.dump(buf, file)

def open(self, command, *args, **kwargs):
"""Podman initialized instance to run a given command
Expand All @@ -111,6 +109,7 @@ def open(self, command, *args, **kwargs):

shell = kwargs.get("shell", False)

# pylint: disable=consider-using-with
return subprocess.Popen(
cmd,
shell=shell,
Expand Down Expand Up @@ -144,9 +143,11 @@ def run(self, command, *args, **kwargs):
)

def tear_down(self):
"""Delete test environment."""
shutil.rmtree(self.anchor_directory, ignore_errors=True)

def restore_image_from_cache(self, client: DockerClient):
"""Populate images from cache."""
path = os.path.join(self.image_cache, constant.ALPINE_TARBALL)
if not os.path.exists(path):
img = client.images.pull(constant.ALPINE)
Expand All @@ -157,5 +158,6 @@ def restore_image_from_cache(self, client: DockerClient):
self.run("load", "-i", path, check=True)

def flush_image_cache(self):
for f in pathlib.Path(self.image_cache).glob("*.tar"):
f.unlink(f)
"""Delete image cache."""
for file in pathlib.Path(self.image_cache).glob("*.tar"):
file.unlink(missing_ok=True)
77 changes: 73 additions & 4 deletions test/python/docker/compat/common.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,92 @@
"""
Fixtures and Helpers for unittests.
"""
import subprocess
import sys
import time
import unittest

# pylint: disable=no-name-in-module,import-error,wrong-import-order
from docker import DockerClient

from test.python.docker import PodmanAPI
from test.python.docker.compat import constant


def run_top_container(client: DockerClient):
c = client.containers.create(
constant.ALPINE, command="top", detach=True, tty=True, name="top"
"""Run top command in a alpine container."""
ctnr = client.containers.create(
constant.ALPINE,
command="top",
detach=True,
tty=True,
name="top",
)
c.start()
return c.id
ctnr.start()
return ctnr.id


def remove_all_containers(client: DockerClient):
"""Delete all containers from the Podman service."""
for ctnr in client.containers.list(all=True):
ctnr.remove(force=True)


def remove_all_images(client: DockerClient):
"""Delete all images from the Podman service."""
for img in client.images.list():
# FIXME should DELETE /images accept the sha256: prefix?
id_ = img.id.removeprefix("sha256:")
client.images.remove(id_, force=True)


class DockerTestCase(unittest.TestCase):
"""Specialized TestCase class for testing against Podman service."""

podman: PodmanAPI = None # initialized podman configuration for tests
service: subprocess.Popen = None # podman service instance

top_container_id: str = None
docker: DockerClient = None

@classmethod
def setUpClass(cls) -> None:
super().setUpClass()

cls.podman = PodmanAPI()
super().addClassCleanup(cls.podman.tear_down)

cls.service = cls.podman.open("system", "service", "tcp:127.0.0.1:8080", "--time=0")
# give the service some time to be ready...
time.sleep(2)

return_code = cls.service.poll()
if return_code is not None:
raise subprocess.CalledProcessError(return_code, "podman system service")

@classmethod
def tearDownClass(cls) -> None:
cls.service.terminate()
stdout, stderr = cls.service.communicate(timeout=0.5)
if stdout:
sys.stdout.write("\ndocker-py -- Service Stdout:\n" + stdout.decode("utf-8"))
if stderr:
sys.stderr.write("\ndocker-py -- Service Stderr:\n" + stderr.decode("utf-8"))

return super().tearDownClass()

def setUp(self) -> None:
super().setUp()

self.docker = DockerClient(base_url="tcp://127.0.0.1:8080", timeout=15)
self.addCleanup(self.docker.close)

self.podman.restore_image_from_cache(self.docker)
self.top_container_id = run_top_container(self.docker)
self.assertIsNotNone(self.top_container_id, "Failed to create 'top' container")

def tearDown(self) -> None:
remove_all_containers(self.docker)
remove_all_images(self.docker)

super().tearDown()
4 changes: 3 additions & 1 deletion test/python/docker/compat/constant.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""
Constants to use in writing unittests.
"""
ALPINE = "quay.io/libpod/alpine:latest"
ALPINE_SHORTNAME = "alpine"
ALPINE_TARBALL = "alpine.tar"
BB = "quay.io/libpod/busybox:latest"
NGINX = "quay.io/libpod/alpine_nginx:latest"
infra = "k8s.gcr.io/pause:3.2"
Loading

0 comments on commit 7729afe

Please sign in to comment.