diff options
author | Jhon Honce <jhonce@redhat.com> | 2020-06-24 12:40:55 -0700 |
---|---|---|
committer | Jhon Honce <jhonce@redhat.com> | 2020-06-24 12:40:55 -0700 |
commit | d7770df5ef9f6085a5e31e3260f7dc1f0056f162 (patch) | |
tree | e4b6b381ff67448209f3787483e24ae960e3911e | |
parent | 988fd27541dfa852ee9543c2d8a916896ef0c774 (diff) | |
download | podman-d7770df5ef9f6085a5e31e3260f7dc1f0056f162.tar.gz podman-d7770df5ef9f6085a5e31e3260f7dc1f0056f162.tar.bz2 podman-d7770df5ef9f6085a5e31e3260f7dc1f0056f162.zip |
Fix python dockerpy tests
* Refactor packaging so unittest discovery works
* Refactor tests to use python3-docker.rpm that ships with Fedora32
* Flush image cache between tests suites
* Update documentation to reflect changes
Outstanding issue:
* client.get_image() does not fail if image does not exist
Signed-off-by: Jhon Honce <jhonce@redhat.com>
-rw-r--r-- | test/python/dockerpy/README.md | 40 | ||||
-rw-r--r-- | test/python/dockerpy/__init__.py (renamed from test/test_dockerpy/__init__.py) | 0 | ||||
-rw-r--r-- | test/python/dockerpy/tests/__init__.py | 0 | ||||
-rw-r--r-- | test/python/dockerpy/tests/common.py | 105 | ||||
-rw-r--r-- | test/python/dockerpy/tests/constant.py | 13 | ||||
-rw-r--r-- | test/python/dockerpy/tests/test_containers.py (renamed from test/test_dockerpy/test_containers.py) | 43 | ||||
-rw-r--r-- | test/python/dockerpy/tests/test_images.py (renamed from test/test_dockerpy/test_images.py) | 84 | ||||
-rw-r--r-- | test/python/dockerpy/tests/test_info_version.py (renamed from test/test_dockerpy/test_info_version.py) | 12 | ||||
-rw-r--r-- | test/test_dockerpy/README.md | 30 | ||||
-rw-r--r-- | test/test_dockerpy/common.py | 85 | ||||
-rw-r--r-- | test/test_dockerpy/constant.py | 13 |
11 files changed, 232 insertions, 193 deletions
diff --git a/test/python/dockerpy/README.md b/test/python/dockerpy/README.md new file mode 100644 index 000000000..22908afc6 --- /dev/null +++ b/test/python/dockerpy/README.md @@ -0,0 +1,40 @@ +# Dockerpy regression test + +Python test suite to validate Podman endpoints using dockerpy library + +## Running Tests + +To run the tests locally in your sandbox (Fedora 32): + +```shell script +# dnf install python3-docker +``` + +### Run the entire test suite + +```shell +# cd test/python/dockerpy +# PYTHONPATH=/usr/bin/python python -m unittest discover . +``` + +Passing the -v option to your test script will instruct unittest.main() to enable a higher level of verbosity, and produce detailed output: + +```shell +# cd test/python/dockerpy +# PYTHONPATH=/usr/bin/python python -m unittest -v discover . +``` + +### Run a specific test class + +```shell +# cd test/python/dockerpy +# PYTHONPATH=/usr/bin/python python -m unittest -v tests.test_images +``` + +### Run a specific test within the test class + +```shell +# cd test/python/dockerpy +# PYTHONPATH=/usr/bin/python python -m unittest tests.test_images.TestImages.test_import_image + +``` diff --git a/test/test_dockerpy/__init__.py b/test/python/dockerpy/__init__.py index e69de29bb..e69de29bb 100644 --- a/test/test_dockerpy/__init__.py +++ b/test/python/dockerpy/__init__.py diff --git a/test/python/dockerpy/tests/__init__.py b/test/python/dockerpy/tests/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/python/dockerpy/tests/__init__.py diff --git a/test/python/dockerpy/tests/common.py b/test/python/dockerpy/tests/common.py new file mode 100644 index 000000000..f83f4076f --- /dev/null +++ b/test/python/dockerpy/tests/common.py @@ -0,0 +1,105 @@ +import os +import pathlib +import subprocess +import sys +import time + +from docker import APIClient + +from . import constant + +alpineDict = { + "name": "docker.io/library/alpine:latest", + "shortName": "alpine", + "tarballName": "alpine.tar" +} + + +def get_client(): + client = APIClient(base_url="http://localhost:8080", timeout=15) + return client + + +client = get_client() + + +def podman(): + binary = os.getenv("PODMAN_BINARY") + if binary is None: + binary = "../../../bin/podman" + return binary + + +def restore_image_from_cache(TestClass): + alpineImage = os.path.join(constant.ImageCacheDir, + alpineDict["tarballName"]) + if not os.path.exists(alpineImage): + os.makedirs(constant.ImageCacheDir, exist_ok=True) + client.pull(constant.ALPINE) + image = client.get_image(constant.ALPINE) + tarball = open(alpineImage, mode="wb") + for frame in image: + tarball.write(frame) + tarball.close() + else: + subprocess.run( + [podman(), "load", "-i", alpineImage], + shell=False, + stdin=subprocess.DEVNULL, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + check=True, + ) + + +def flush_image_cache(TestCase): + for f in pathlib.Path(constant.ImageCacheDir).glob("*"): + f.unlink(f) + + +def run_top_container(): + c = client.create_container(image=constant.ALPINE, + command='/bin/sleep 5', + name=constant.TOP) + client.start(container=c.get("Id")) + return c.get("Id") + + +def enable_sock(TestClass): + TestClass.podman = subprocess.Popen( + [ + podman(), "system", "service", "tcp:localhost:8080", + "--log-level=debug", "--time=0" + ], + shell=False, + stdin=subprocess.DEVNULL, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + time.sleep(2) + + +def terminate_connection(TestClass): + TestClass.podman.terminate() + stdout, stderr = TestClass.podman.communicate(timeout=0.5) + if stdout: + print("\nService Stdout:\n" + stdout.decode('utf-8')) + if stderr: + print("\nService Stderr:\n" + stderr.decode('utf-8')) + + if TestClass.podman.returncode > 0: + sys.stderr.write("podman exited with error code {}\n".format( + TestClass.podman.returncode)) + sys.exit(2) + + +def remove_all_containers(): + containers = client.containers(quiet=True) + for c in containers: + client.remove_container(container=c.get("Id"), force=True) + + +def remove_all_images(): + allImages = client.images() + for image in allImages: + client.remove_image(image, force=True) diff --git a/test/python/dockerpy/tests/constant.py b/test/python/dockerpy/tests/constant.py new file mode 100644 index 000000000..b44442d02 --- /dev/null +++ b/test/python/dockerpy/tests/constant.py @@ -0,0 +1,13 @@ +BB = "docker.io/library/busybox:latest" +NGINX = "docker.io/library/nginx:latest" +ALPINE = "docker.io/library/alpine:latest" +ALPINE_SHORTNAME = "alpine" +ALPINELISTTAG = "docker.io/library/alpine:3.10.2" +ALPINELISTDIGEST = "docker.io/library/alpine@sha256:72c42ed48c3a2db31b7dafe17d275b634664a708d901ec9fd57b1529280f01fb" +ALPINEAMD64DIGEST = "docker.io/library/alpine@sha256:acd3ca9941a85e8ed16515bfc5328e4e2f8c128caa72959a58a127b7801ee01f" +ALPINEAMD64ID = "961769676411f082461f9ef46626dd7a2d1e2b2a38e6a44364bcbecf51e66dd4" +ALPINEARM64DIGEST = "docker.io/library/alpine@sha256:db7f3dcef3d586f7dd123f107c93d7911515a5991c4b9e51fa2a43e46335a43e" +ALPINEARM64ID = "915beeae46751fc564998c79e73a1026542e945ca4f73dc841d09ccc6c2c0672" +infra = "k8s.gcr.io/pause:3.2" +TOP = "top" +ImageCacheDir = "/tmp/podman/imagecachedir" diff --git a/test/test_dockerpy/test_containers.py b/test/python/dockerpy/tests/test_containers.py index 34fe82c18..6b89688d4 100644 --- a/test/test_dockerpy/test_containers.py +++ b/test/python/dockerpy/tests/test_containers.py @@ -1,18 +1,15 @@ - -import unittest -import docker -import requests import os -from docker import Client -from . import constant -from . import common import time +import unittest + +import requests + +from . import common, constant client = common.get_client() -class TestContainers(unittest.TestCase): - podman = None +class TestContainers(unittest.TestCase): topContainerId = "" def setUp(self): @@ -33,6 +30,7 @@ class TestContainers(unittest.TestCase): @classmethod def tearDownClass(cls): common.terminate_connection(cls) + common.flush_image_cache(cls) return super().tearDownClass() def test_inspect_container(self): @@ -42,16 +40,15 @@ class TestContainers(unittest.TestCase): self.assertEqual(error.exception.response.status_code, 404) # Inspect valid container by name container = client.inspect_container(constant.TOP) - self.assertIn(TestContainers.topContainerId , container["Id"]) + self.assertIn(TestContainers.topContainerId, container["Id"]) # Inspect valid container by Id container = client.inspect_container(TestContainers.topContainerId) - self.assertIn(constant.TOP , container["Name"]) + self.assertIn(constant.TOP, container["Name"]) def test_create_container(self): # Run a container with detach mode container = client.create_container(image="alpine", detach=True) - self.assertEqual(len(container),2) - + self.assertEqual(len(container), 2) def test_start_container(self): # Start bogus container @@ -65,9 +62,9 @@ class TestContainers(unittest.TestCase): # self.assertEqual(error.exception.response.status_code, 304) # Create a new container and validate the count - client.create_container(image=constant.ALPINE,name="container2") - containers = client.containers(quiet=True,all=True) - self.assertEqual(len(containers),2) + client.create_container(image=constant.ALPINE, name="container2") + containers = client.containers(quiet=True, all=True) + self.assertEqual(len(containers), 2) def test_stop_container(self): # Stop bogus container @@ -82,7 +79,10 @@ class TestContainers(unittest.TestCase): # Stop a running container and validate the state client.stop(TestContainers.topContainerId) container = client.inspect_container(constant.TOP) - self.assertIn(container["State"]["Status"],"stopped exited",) + self.assertIn( + container["State"]["Status"], + "stopped exited", + ) def test_restart_container(self): # Restart bogus container @@ -109,12 +109,12 @@ class TestContainers(unittest.TestCase): # Remove container by ID with force client.remove_container(TestContainers.topContainerId, force=True) containers = client.containers() - self.assertEqual(len(containers),0) + self.assertEqual(len(containers), 0) def test_remove_container_without_force(self): # Validate current container count containers = client.containers() - self.assertTrue(len(containers),1) + self.assertTrue(len(containers), 1) # Remove running container should throw error with self.assertRaises(requests.HTTPError) as error: @@ -125,7 +125,7 @@ class TestContainers(unittest.TestCase): client.stop(TestContainers.topContainerId) client.remove_container(TestContainers.topContainerId) containers = client.containers() - self.assertEqual(len(containers),0) + self.assertEqual(len(containers), 0) def test_pause_container(self): # Pause bogus container @@ -151,7 +151,6 @@ class TestContainers(unittest.TestCase): client.pause(TestContainers.topContainerId) self.assertEqual(error.exception.response.status_code, 500) - def test_unpause_container(self): # Unpause bogus container with self.assertRaises(requests.HTTPError) as error: @@ -173,7 +172,7 @@ class TestContainers(unittest.TestCase): # Add container and validate the count client.create_container(image="alpine", detach=True) containers = client.containers(all=True) - self.assertEqual(len(containers),2) + self.assertEqual(len(containers), 2) # Not working for now......checking # # List container with filter by id diff --git a/test/test_dockerpy/test_images.py b/test/python/dockerpy/tests/test_images.py index c88353b79..5eae61c2f 100644 --- a/test/test_dockerpy/test_images.py +++ b/test/python/dockerpy/tests/test_images.py @@ -1,17 +1,18 @@ - +import os +import stat import unittest +from os import remove +from stat import ST_SIZE + import docker import requests -import os -from docker import Client -from . import constant -from . import common + +from . import common, constant client = common.get_client() -class TestImages(unittest.TestCase): - podman = None +class TestImages(unittest.TestCase): def setUp(self): super().setUp() common.restore_image_from_cache(self) @@ -25,13 +26,12 @@ class TestImages(unittest.TestCase): super().setUpClass() common.enable_sock(cls) - @classmethod def tearDownClass(cls): common.terminate_connection(cls) + common.flush_image_cache(cls) return super().tearDownClass() - # Inspect Image def test_inspect_image(self): @@ -43,46 +43,46 @@ class TestImages(unittest.TestCase): # Tag Image - # Validates if invalid image name is given a bad response is encountered. +# Validates if invalid image name is given a bad response is encountered. + def test_tag_invalid_image(self): with self.assertRaises(requests.HTTPError): - client.tag("dummy","demo") - - + client.tag("dummy", "demo") # Validates if the image is tagged successfully. def test_tag_valid_image(self): - client.tag(constant.ALPINE,"demo",constant.ALPINE_SHORTNAME) + client.tag(constant.ALPINE, "demo", constant.ALPINE_SHORTNAME) alpine_image = client.inspect_image(constant.ALPINE) for x in alpine_image["RepoTags"]: - if("demo:alpine" in x): + if ("demo:alpine" in x): self.assertTrue self.assertFalse # Validates if name updates when the image is retagged. @unittest.skip("dosent work now") def test_retag_valid_image(self): - client.tag(constant.ALPINE_SHORTNAME, "demo","rename") + client.tag(constant.ALPINE_SHORTNAME, "demo", "rename") alpine_image = client.inspect_image(constant.ALPINE) self.assertNotIn("demo:test", alpine_image["RepoTags"]) # List Image - # List All Images +# List All Images + def test_list_images(self): allImages = client.images() self.assertEqual(len(allImages), 1) # Add more images client.pull(constant.BB) allImages = client.images() - self.assertEqual(len(allImages) , 2) - + self.assertEqual(len(allImages), 2) - # List images with filter - filters = {'reference':'alpine'} - allImages = client.images(filters = filters) - self.assertEqual(len(allImages) , 1) + # List images with filter + filters = {'reference': 'alpine'} + allImages = client.images(filters=filters) + self.assertEqual(len(allImages), 1) # Search Image + def test_search_image(self): response = client.search("alpine") for i in response: @@ -94,22 +94,25 @@ class TestImages(unittest.TestCase): # Image Exist (No docker-py support yet) # Remove Image + def test_remove_image(self): # Check for error with wrong image name with self.assertRaises(requests.HTTPError): client.remove_image("dummy") allImages = client.images() - self.assertEqual(len(allImages) , 1) + self.assertEqual(len(allImages), 1) alpine_image = client.inspect_image(constant.ALPINE) client.remove_image(alpine_image) allImages = client.images() - self.assertEqual(len(allImages) , 0) + self.assertEqual(len(allImages), 0) # Image History + def test_image_history(self): # Check for error with wrong image name with self.assertRaises(requests.HTTPError): - client.remove_image("dummy") + client.history("dummy") + imageHistory = client.history(constant.ALPINE) alpine_image = client.inspect_image(constant.ALPINE) for h in imageHistory: @@ -119,28 +122,37 @@ class TestImages(unittest.TestCase): # Prune Image (No docker-py support yet) + def test_get_image_dummy(self): + # FIXME: seems to be an error in the library + self.skipTest("Documentation and library do not match") + # Check for error with wrong image name + with self.assertRaises(docker.errors.ImageNotFound): + client.get_image("dummy") + # Export Image def test_export_image(self): client.pull(constant.BB) - file = os.path.join(constant.ImageCacheDir , "busybox.tar") if not os.path.exists(constant.ImageCacheDir): os.makedirs(constant.ImageCacheDir) - # Check for error with wrong image name - with self.assertRaises(requests.HTTPError): - client.get_image("dummy") - response = client.get_image(constant.BB) - image_tar = open(file,mode="wb") - image_tar.write(response.data) - image_tar.close() - os.stat(file) + + image = client.get_image(constant.BB) + + file = os.path.join(constant.ImageCacheDir, "busybox.tar") + tarball = open(file, mode="wb") + for frame in image: + tarball.write(frame) + tarball.close() + sz = os.path.getsize(file) + self.assertGreater(sz, 0) + # Import|Load Image def test_import_image(self): allImages = client.images() self.assertEqual(len(allImages), 1) - file = os.path.join(constant.ImageCacheDir , "busybox.tar") + file = os.path.join(constant.ImageCacheDir, "alpine.tar") client.import_image_from_file(filename=file) allImages = client.images() self.assertEqual(len(allImages), 2) diff --git a/test/test_dockerpy/test_info_version.py b/test/python/dockerpy/tests/test_info_version.py index be1a2aab9..e3ee18ec7 100644 --- a/test/test_dockerpy/test_info_version.py +++ b/test/python/dockerpy/tests/test_info_version.py @@ -1,11 +1,10 @@ import unittest -import docker -from docker import Client -from . import constant -from . import common + +from . import common, constant client = common.get_client() + class TestInfo_Version(unittest.TestCase): podman = None @@ -31,16 +30,15 @@ class TestInfo_Version(unittest.TestCase): common.terminate_connection(cls) return super().tearDownClass() - def test_Info(self): self.assertIsNotNone(client.info()) def test_info_container_details(self): info = client.info() - self.assertEqual(info["Containers"],1) + self.assertEqual(info["Containers"], 1) client.create_container(image=constant.ALPINE) info = client.info() - self.assertEqual(info["Containers"],2) + self.assertEqual(info["Containers"], 2) def test_version(self): self.assertIsNotNone(client.version()) diff --git a/test/test_dockerpy/README.md b/test/test_dockerpy/README.md deleted file mode 100644 index 32e426d58..000000000 --- a/test/test_dockerpy/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# Dockerpy regression test - -Python test suite to validate Podman endpoints using dockerpy library - -Running tests -============= -To run the tests locally in your sandbox: - -#### Run the entire test - -``` -sudo PYTHONPATH=/usr/bin/python python -m dockerpy.images -``` - -Passing the -v option to your test script will instruct unittest.main() to enable a higher level of verbosity, and produce detailed output: - -``` -sudo PYTHONPATH=/usr/bin/python python -m unittest -v dockerpy.images -``` -#### Run a specific test class - -``` -sudo PYTHONPATH=/usr/bin/python python -m unittest -v dockerpy.images.TestImages -``` - -#### Run a specific test within the test class - -``` -sudo PYTHONPATH=/usr/bin/python python -m unittest -v dockerpy.images.TestImages.test_list_images -``` diff --git a/test/test_dockerpy/common.py b/test/test_dockerpy/common.py deleted file mode 100644 index 975b13dc6..000000000 --- a/test/test_dockerpy/common.py +++ /dev/null @@ -1,85 +0,0 @@ -import docker -import subprocess -import os -import sys -import time -from docker import Client -from . import constant - -alpineDict = { - "name": "docker.io/library/alpine:latest", - "shortName": "alpine", - "tarballName": "alpine.tar"} - -def get_client(): - client = docker.Client(base_url="http://localhost:8080",timeout=15) - return client - -client = get_client() - -def podman(): - binary = os.getenv("PODMAN_BINARY") - if binary is None: - binary = "bin/podman" - return binary - -def restore_image_from_cache(TestClass): - alpineImage = os.path.join(constant.ImageCacheDir , alpineDict["tarballName"]) - if not os.path.exists(alpineImage): - os.makedirs(constant.ImageCacheDir) - client.pull(constant.ALPINE) - response = client.get_image(constant.ALPINE) - image_tar = open(alpineImage,mode="wb") - image_tar.write(response.data) - image_tar.close() - else : - TestClass.podman = subprocess.run( - [ - podman(), "load", "-i", alpineImage - ], - shell=False, - stdin=subprocess.DEVNULL, - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - ) - -def run_top_container(): - c = client.create_container(image=constant.ALPINE,command='/bin/sleep 5',name=constant.TOP) - client.start(container=c.get("Id")) - return c.get("Id") - -def enable_sock(TestClass): - TestClass.podman = subprocess.Popen( - [ - podman(), "system", "service", "tcp:localhost:8080", - "--log-level=debug", "--time=0" - ], - shell=False, - stdin=subprocess.DEVNULL, - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - ) - time.sleep(2) - -def terminate_connection(TestClass): - TestClass.podman.terminate() - stdout, stderr = TestClass.podman.communicate(timeout=0.5) - if stdout: - print("\nService Stdout:\n" + stdout.decode('utf-8')) - if stderr: - print("\nService Stderr:\n" + stderr.decode('utf-8')) - - if TestClass.podman.returncode > 0: - sys.stderr.write("podman exited with error code {}\n".format( - TestClass.podman.returncode)) - sys.exit(2) - -def remove_all_containers(): - containers = client.containers(quiet=True) - for c in containers: - client.remove_container(container=c.get("Id"), force=True) - -def remove_all_images(): - allImages = client.images() - for image in allImages: - client.remove_image(image,force=True) diff --git a/test/test_dockerpy/constant.py b/test/test_dockerpy/constant.py deleted file mode 100644 index 8a3f1d984..000000000 --- a/test/test_dockerpy/constant.py +++ /dev/null @@ -1,13 +0,0 @@ -BB = "docker.io/library/busybox:latest" -NGINX = "docker.io/library/nginx:latest" -ALPINE = "docker.io/library/alpine:latest" -ALPINE_SHORTNAME = "alpine" -ALPINELISTTAG = "docker.io/library/alpine:3.10.2" -ALPINELISTDIGEST = "docker.io/library/alpine@sha256:72c42ed48c3a2db31b7dafe17d275b634664a708d901ec9fd57b1529280f01fb" -ALPINEAMD64DIGEST = "docker.io/library/alpine@sha256:acd3ca9941a85e8ed16515bfc5328e4e2f8c128caa72959a58a127b7801ee01f" -ALPINEAMD64ID = "961769676411f082461f9ef46626dd7a2d1e2b2a38e6a44364bcbecf51e66dd4" -ALPINEARM64DIGEST = "docker.io/library/alpine@sha256:db7f3dcef3d586f7dd123f107c93d7911515a5991c4b9e51fa2a43e46335a43e" -ALPINEARM64ID = "915beeae46751fc564998c79e73a1026542e945ca4f73dc841d09ccc6c2c0672" -infra = "k8s.gcr.io/pause:3.2" -TOP = "top" -ImageCacheDir = "/tmp/podman/imagecachedir" |