class VolumeTestCase(unittest.TestCase): def setUp(self) -> None: super().setUp() self.client = PodmanClient(base_url="http+unix://localhost:9999") def tearDown(self) -> None: super().tearDown() self.client.close() def test_id(self): actual = Volume(attrs={"Name": "dbase"}) self.assertEqual(actual.id, "dbase") @requests_mock.Mocker() def test_remove(self, mock): adapter = mock.delete( "http+unix://localhost:9999/v3.0.0/libpod/volumes/dbase?force=True", status_code=204) mock.get("http+unix://localhost:9999/v3.0.0/libpod/volumes/dbase", json=FIRST_VOLUME) volume = self.client.volumes.get("dbase") volume.remove(force=True) self.assertTrue(adapter.called_once)
class PodmanConnect: """Connect to the podman unix socket.""" def __init__(self, socket="/var/run/podman/podman.sock"): """Initialize the Directord pod connection class. Sets up the pod api object. :param socket: Socket path to connect to. :type socket: String """ self.pod = PodmanClient(base_url="unix://{socket}".format( socket=socket)) self.api = self.pod.api def __exit__(self, *args, **kwargs): """Close the connection and exit.""" self.close() def __enter__(self): """Return self for use within a context manager.""" return self def close(self): """Close the connection.""" self.pod.close()
class ManifestTestCase(unittest.TestCase): def setUp(self) -> None: super().setUp() self.client = PodmanClient(base_url="http+unix://localhost:9999") def tearDown(self) -> None: super().tearDown() self.client.close() def test_podmanclient(self): manager = self.client.manifests self.assertIsInstance(manager, ManifestsManager) def test_list(self): with self.assertRaises(NotImplementedError): self.client.manifests.list() def test_name(self): with self.assertRaises(ValueError): manifest = Manifest(attrs={"names": ""}) _ = manifest.name with self.assertRaises(ValueError): manifest = Manifest() _ = manifest.name
class VolumeTestCase(unittest.TestCase): def setUp(self) -> None: super().setUp() self.client = PodmanClient(base_url=tests.BASE_SOCK) def tearDown(self) -> None: super().tearDown() self.client.close() def test_id(self): actual = Volume(attrs={"Name": "dbase"}) self.assertEqual(actual.id, "dbase") @requests_mock.Mocker() def test_remove(self, mock): adapter = mock.delete(tests.BASE_URL + "/libpod/volumes/dbase?force=True", status_code=204) vol_manager = VolumesManager(self.client.api) volume = vol_manager.prepare_model(attrs=FIRST_VOLUME) volume.remove(force=True) self.assertTrue(adapter.called_once)
class TestPodmanClient(unittest.TestCase): """Test the PodmanClient() object.""" def setUp(self) -> None: super().setUp() self.client = PodmanClient(base_url='unix://*****:*****@mock.patch('requests.Session.close') def test_close(self, mock_close): self.client.close() mock_close.assert_called_once_with() @requests_mock.Mocker() def test_contextmanager(self, mock): body = { "host": { "arch": "amd65", "os": "linux", } } mock.get("http+unix://localhost:9999/v3.0.0/libpod/system/info", json=body) with PodmanClient(base_url="http+unix://localhost:9999") as client: actual = client.info() self.assertDictEqual(actual, body)
class TestPodmanClient(unittest.TestCase): """Test the PodmanClient() object.""" def setUp(self) -> None: super().setUp() self.client = PodmanClient(base_url='unix://*****:*****@mock.patch('requests.Session.close') def test_close(self, mock_close): self.client.close() mock_close.assert_called_once_with()
class EventsManagerTestCase(unittest.TestCase): def setUp(self) -> None: super().setUp() self.client = PodmanClient(base_url=tests.BASE_SOCK) def tearDown(self) -> None: super().tearDown() self.client.close() @requests_mock.Mocker() def test_list(self, mock): stream = [{ "Type": "pod", "Action": "create", "Actor": { "ID": "", "Attributes": { "image": "", "name": "", "containerExitCode": 0, }, }, "Scope": "local", "Time": 1615845480, "TimeNano": 1615845480, }] buffer = io.StringIO() for item in stream: buffer.write(json.JSONEncoder().encode(item)) buffer.write("\n") adapter = mock.get(tests.LIBPOD_URL + "/events", text=buffer.getvalue()) manager = EventsManager(client=self.client.api) actual = manager.list(decode=True) self.assertIsInstance(actual, GeneratorType) for item in actual: self.assertIsInstance(item, dict) self.assertEqual(item["Type"], "pod") actual = manager.list(decode=False) self.assertIsInstance(actual, GeneratorType) for item in actual: self.assertIsInstance(item, bytes) event = json.loads(item) self.assertEqual(event["Type"], "pod")
class SecretsTestCase(unittest.TestCase): def setUp(self) -> None: super().setUp() self.client = PodmanClient(base_url=tests.BASE_SOCK) def tearDown(self) -> None: super().tearDown() self.client.close() def test_podmanclient(self): manager = self.client.secrets self.assertIsInstance(manager, SecretsManager)
class PodsManagerTestCase(unittest.TestCase): def setUp(self) -> None: super().setUp() self.client = PodmanClient(base_url="http+unix://localhost:9999") def tearDown(self) -> None: super().tearDown() self.client.close() def test_podmanclient(self): manager = self.client.pods self.assertIsInstance(manager, PodsManager)
class VolumesManagerTestCase(unittest.TestCase): """Test VolumesManager area of concern. Note: Mock responses need to be coded for libpod returns. The python bindings are responsible for mapping to compatible output. """ def setUp(self) -> None: super().setUp() self.client = PodmanClient(base_url=tests.BASE_SOCK) def tearDown(self) -> None: super().tearDown() self.client.close() def test_podmanclient(self): manager = self.client.volumes self.assertIsInstance(manager, VolumesManager) @requests_mock.Mocker() def test_create(self, mock): adapter = mock.post( tests.LIBPOD_URL + "/volumes/create", json=FIRST_VOLUME, status_code=requests.codes.created, ) actual = self.client.volumes.create( "dbase", labels={ "BackupRequired": True, }, ) self.assertIsInstance(actual, Volume) self.assertTrue(adapter.called_once) self.assertDictEqual( adapter.last_request.json(), { "Name": "dbase", "Labels": { "BackupRequired": True, }, }, ) self.assertEqual(actual.id, "dbase") self.assertDictEqual( actual.attrs["Labels"], { "BackupRequired": True, }, ) @requests_mock.Mocker() def test_get(self, mock): mock.get( tests.LIBPOD_URL + "/volumes/dbase/json", json=FIRST_VOLUME, ) actual = self.client.volumes.get("dbase") self.assertIsInstance(actual, Volume) self.assertDictEqual(actual.attrs, FIRST_VOLUME) self.assertEqual(actual.id, actual.name) @requests_mock.Mocker() def test_get_404(self, mock): adapter = mock.get( tests.LIBPOD_URL + "/volumes/dbase/json", text="Not Found", status_code=404, ) with self.assertRaises(NotFound): self.client.volumes.get("dbase") self.assertTrue(adapter.called_once) @requests_mock.Mocker() def test_list(self, mock): mock.get(tests.LIBPOD_URL + "/volumes/json", json=[FIRST_VOLUME, SECOND_VOLUME]) actual = self.client.volumes.list(filters={"driver": "local"}) self.assertEqual(len(actual), 2) self.assertIsInstance(actual[0], Volume) self.assertEqual(actual[0].name, "dbase") self.assertIsInstance(actual[1], Volume) self.assertEqual(actual[1].id, "source") @requests_mock.Mocker() def test_list_404(self, mock): mock.get(tests.LIBPOD_URL + "/volumes/json", text="Not Found", status_code=404) actual = self.client.volumes.list() self.assertIsInstance(actual, list) self.assertEqual(len(actual), 0) @requests_mock.Mocker() def test_prune(self, mock): mock.post( tests.LIBPOD_URL + "/volumes/prune", json=[ { "Id": "dbase", "Size": 1024 }, { "Id": "source", "Size": 1024 }, ], ) actual = self.client.volumes.prune() self.assertDictEqual(actual, { "VolumesDeleted": ["dbase", "source"], "SpaceReclaimed": 2048 })
class TestClientImagesManager(unittest.TestCase): """Test ImagesManager area of concern. Note: Mock responses need to be coded for libpod returns. The python bindings are responsible for mapping to compatible output. """ def setUp(self) -> None: super().setUp() self.client = PodmanClient(base_url=tests.BASE_SOCK) def tearDown(self) -> None: super().tearDown() self.client.close() def test_podmanclient(self): manager = self.client.images self.assertIsInstance(manager, ImagesManager) @requests_mock.Mocker() def test_list_empty(self, mock): """Unit test Images list().""" mock.get( tests.BASE_URL + "/libpod/images/json", text="[]", ) images = self.client.images.list() self.assertEqual(len(images), 0) @requests_mock.Mocker() def test_list_1(self, mock): """Unit test Images list().""" mock.get( tests.BASE_URL + "/libpod/images/json", json=[FIRST_IMAGE], ) images = self.client.images.list() self.assertEqual(len(images), 1) self.assertIsInstance(images[0], Image) self.assertEqual(str(images[0]), "<Image: 'fedora:latest', 'fedora:33'>") self.assertEqual( images[0].id, "sha256:326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab" ) self.assertIsInstance(images[0].labels, dict) self.assertEqual(len(images[0].labels), 1) self.assertEqual(images[0].short_id, "sha256:326dd9d7ad") self.assertIsInstance(images[0].tags, list) self.assertEqual(len(images[0].tags), 2) @requests_mock.Mocker() def test_list_2(self, mock): """Unit test Images list().""" mock.get( tests.BASE_URL + "/libpod/images/json", json=[FIRST_IMAGE, SECOND_IMAGE], ) images = self.client.images.list() self.assertEqual(len(images), 2) self.assertIsInstance(images[0], Image) self.assertIsInstance(images[1], Image) self.assertEqual(images[1].short_id, "c4b16966ec") self.assertIsInstance(images[1].labels, dict) self.assertEqual(len(images[1].labels), 0) self.assertIsInstance(images[1].tags, list) self.assertEqual(len(images[1].tags), 0) @requests_mock.Mocker() def test_list_filters(self, mock): """Unit test filters param for Images list().""" mock.get( tests.BASE_URL + "/libpod/images/json" "?filters=%7B%22dangling%22%3A+%5B%22True%22%5D%7D", json=[FIRST_IMAGE], ) images = self.client.images.list(filters={"dangling": True}) self.assertEqual( images[0].id, "sha256:326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab" ) @requests_mock.Mocker() def test_list_all(self, mock): """Unit test filters param for Images list().""" mock.get( tests.BASE_URL + "/libpod/images/json?all=true", json=[FIRST_IMAGE], ) images = self.client.images.list(all=True) self.assertEqual( images[0].id, "sha256:326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab" ) @requests_mock.Mocker() def test_prune(self, mock): """Unit test Images prune().""" mock.post( tests.BASE_URL + "/libpod/images/prune", json=[{ "Id": "326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab", "Err": None, "Size": 1024, }], ) results = self.client.images.prune() self.assertIn("ImagesDeleted", results) self.assertIn("SpaceReclaimed", results) self.assertEqual( results["ImagesDeleted"][0]["Deleted"], "326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab", ) self.assertEqual(results["SpaceReclaimed"], 1024) @requests_mock.Mocker() def test_prune_filters(self, mock): """Unit test filters param for Images prune().""" mock.post( tests.BASE_URL + "/libpod/images/prune" "?filters=%7B%22dangling%22%3A+%5B%22True%22%5D%7D", json=[ { "Id": "326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab", "Size": 1024, }, { "Id": "c4b16966ecd94ffa910eab4e630e24f259bf34a87e924cd4b1434f267b0e354e", "Size": 1024, }, ], ) report = self.client.images.prune(filters={"dangling": True}) self.assertIn("ImagesDeleted", report) self.assertIn("SpaceReclaimed", report) self.assertEqual(report["SpaceReclaimed"], 2048) deleted = [ r["Deleted"] for r in report["ImagesDeleted"] if "Deleted" in r ] self.assertEqual(len(deleted), 2) self.assertIn( "326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab", deleted) self.assertGreater(len("".join(deleted)), 0) untagged = [ r["Untagged"] for r in report["ImagesDeleted"] if "Untagged" in r ] self.assertEqual(len(untagged), 2) self.assertEqual(len("".join(untagged)), 0) @requests_mock.Mocker() def test_prune_failure(self, mock): """Unit test to report error carried in response body.""" mock.post( tests.BASE_URL + "/libpod/images/prune", json=[{ "Err": "Test prune failure in response body.", }], ) with self.assertRaises(APIError) as e: self.client.images.prune() self.assertEqual(e.exception.explanation, "Test prune failure in response body.") @requests_mock.Mocker() def test_get(self, mock): mock.get( tests.BASE_URL + "/libpod/images/fedora%3Alatest/json", json=FIRST_IMAGE, ) image = self.client.images.get("fedora:latest") self.assertIsInstance(image, Image) self.assertDictEqual(FIRST_IMAGE["Labels"], image.attrs["Labels"]) @requests_mock.Mocker() def test_get_oserror(self, mock): mock.get( tests.BASE_URL + "/libpod/images/bad_image/json", exc=OSError, ) with self.assertRaises(APIError) as e: _ = self.client.images.get("bad_image") self.assertEqual( str(e.exception), tests.BASE_URL + "/libpod/images/bad_image/json (GET operation failed)", ) @requests_mock.Mocker() def test_get_404(self, mock): mock.get( tests.BASE_URL + "/libpod/images/bad_image/json", status_code=404, json={ "cause": "Image not found", "message": "Image not found", "response": 404, }, ) with self.assertRaises(ImageNotFound): _ = self.client.images.get("bad_image") @requests_mock.Mocker() def test_get_500(self, mock): mock.get( tests.BASE_URL + "/libpod/images/bad_image/json", status_code=500, json={ "cause": "Server error", "message": "Server error", "response": 500, }, ) with self.assertRaises(APIError): _ = self.client.images.get("bad_image") @requests_mock.Mocker() def test_remove(self, mock): mock.delete( tests.BASE_URL + "/libpod/images/fedora:latest", json={ "Untagged": [ "326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab" ], "Deleted": [ "326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab", "c4b16966ecd94ffa910eab4e630e24f259bf34a87e924cd4b1434f267b0e354e", ], "Errors": [], "ExitCode": 0, }, ) report = self.client.images.remove("fedora:latest") self.assertEqual(len(report), 4) deleted = [r["Deleted"] for r in report if "Deleted" in r] self.assertEqual(len(deleted), 2) untagged = [r["Untagged"] for r in report if "Untagged" in r] self.assertEqual(len(untagged), 1) errors = [r["Errors"] for r in report if "Errors" in r] self.assertEqual(len(errors), 0) codes = [r["ExitCode"] for r in report if "ExitCode" in r] self.assertEqual(len(codes), 1) self.assertEqual(codes[0], 0) @requests_mock.Mocker() def test_load(self, mock): mock.post( tests.BASE_URL + "/libpod/images/load", json={"Names": ["quay.io/fedora:latest"]}, ) mock.get( tests.BASE_URL + "/libpod/images/quay.io%2Ffedora%3Alatest/json", json=FIRST_IMAGE, ) gntr = self.client.images.load(b'This is a weird tarball...') self.assertIsInstance(gntr, types.GeneratorType) report = list(gntr) self.assertEqual(len(report), 1) self.assertEqual( report[0].id, "sha256:326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab" ) @requests_mock.Mocker() def test_search(self, mock): mock.get( tests.BASE_URL + "/libpod/images/search?term=fedora&noTrunc=true", json=[ { "description": "mock term=fedora search", "is_official": False, "is_automated": False, "name": "quay.io/libpod/fedora", "star_count": 0, }, ], ) report = self.client.images.search("fedora") self.assertEqual(len(report), 1) self.assertEqual(report[0]["name"], "quay.io/libpod/fedora") @requests_mock.Mocker() def test_search_oserror(self, mock): mock.get( tests.BASE_URL + "/libpod/images/search?term=fedora&noTrunc=true", exc=OSError, ) with self.assertRaises(OSError): self.client.images.search("fedora") @requests_mock.Mocker() def test_search_500(self, mock): mock.get( tests.BASE_URL + "/libpod/images/search?term=fedora&noTrunc=true", status_code=500, json={ "cause": "Server error", "message": "Server error", "response": 500, }, ) with self.assertRaises(OSError): self.client.images.search("fedora") @requests_mock.Mocker() def test_search_limit(self, mock): mock.get( tests.BASE_URL + "/libpod/images/search?term=fedora&noTrunc=true&limit=5", json=[ { "description": "mock term=fedora search", "is_official": False, "is_automated": False, "name": "quay.io/libpod/fedora", "star_count": 0, }, ], ) report = self.client.images.search("fedora", limit=5) self.assertEqual(len(report), 1) self.assertEqual(report[0]["name"], "quay.io/libpod/fedora") @requests_mock.Mocker() def test_search_filters(self, mock): mock.get( tests.BASE_URL + "/libpod/images/search" "?filters=%7B%22stars%22%3A+%5B%225%22%5D%7D&noTrunc=True&term=fedora", json=[ { "description": "mock term=fedora search", "is_official": False, "is_automated": False, "name": "quay.io/libpod/fedora", "star_count": 0, }, ], ) report = self.client.images.search("fedora", filters={"stars": 5}) self.assertEqual(len(report), 1) self.assertEqual(report[0]["name"], "quay.io/libpod/fedora") @requests_mock.Mocker() def test_push(self, mock): mock.post(tests.BASE_URL + "/libpod/images/quay.io%2Ffedora/push") report = self.client.images.push("quay.io/fedora", "latest") expected = r"""{"status": "Pushing repository quay.io/fedora (1 tags)"} {"status": "Pushing", "progressDetail": {}, "id": "quay.io/fedora"} """ self.assertEqual(report, expected) @requests_mock.Mocker() def test_pull(self, mock): image_id = "sha256:326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab" mock.post( tests.BASE_URL + "/libpod/images/pull" "?reference=quay.io%2Ffedora%3Alatest", json={ "error": "", "id": image_id, "images": [image_id], "stream": "", }, ) mock.get( tests.BASE_URL + "/libpod/images" "/sha256%3A326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab/json", json=FIRST_IMAGE, ) image = self.client.images.pull("quay.io/fedora", "latest") self.assertEqual(image.id, image_id) @requests_mock.Mocker() def test_pull_enhanced(self, mock): image_id = "sha256:326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab" mock.post( tests.BASE_URL + "/libpod/images/pull" "?reference=quay.io%2Ffedora%3Alatest", json={ "error": "", "id": image_id, "images": [image_id], "stream": "", }, ) mock.get( tests.BASE_URL + "/libpod/images" "/sha256%3A326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab/json", json=FIRST_IMAGE, ) image = self.client.images.pull("quay.io/fedora:latest") self.assertEqual(image.id, image_id) @requests_mock.Mocker() def test_pull_platform(self, mock): image_id = "sha256:326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab" adapter = mock.post( tests.BASE_URL + "/libpod/images/pull?reference=quay.io%2Ffedora%3Alatest&OS=linux", json={ "error": "", "id": image_id, "images": [image_id], "stream": "", }, ) mock.get( tests.BASE_URL + "/libpod/images" "/sha256%3A326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab/json", json=FIRST_IMAGE, ) image = self.client.images.pull("quay.io/fedora:latest", platform="linux") self.assertEqual(image.id, image_id) self.assertTrue(adapter.called_once) @requests_mock.Mocker() def test_pull_2x(self, mock): image_id = "sha256:326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab" mock.post( tests.BASE_URL + "/libpod/images/pull" "?reference=quay.io%2Ffedora&allTags=True", json={ "error": "", "id": image_id, "images": [ image_id, "c4b16966ecd94ffa910eab4e630e24f259bf34a87e924cd4b1434f267b0e354e", ], "stream": "", }, ) mock.get( tests.BASE_URL + "/libpod/images" "/sha256%3A326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab/json", json=FIRST_IMAGE, ) mock.get( tests.BASE_URL + "/libpod/images" "/c4b16966ecd94ffa910eab4e630e24f259bf34a87e924cd4b1434f267b0e354e/json", json=SECOND_IMAGE, ) images = self.client.images.pull("quay.io/fedora", "latest", all_tags=True) self.assertIsInstance(images, Iterable) self.assertIsInstance(images[0], Image) self.assertIsInstance(images[1], Image) self.assertEqual(images[0].id, image_id) self.assertEqual( images[1].id, "c4b16966ecd94ffa910eab4e630e24f259bf34a87e924cd4b1434f267b0e354e")
class TestClientImages(unittest.TestCase): def setUp(self) -> None: super().setUp() self.client = PodmanClient(base_url="http+unix://localhost:9999") def tearDown(self) -> None: super().tearDown() self.client.close() def test_podmanclient(self): manager = self.client.images self.assertIsInstance(manager, ImagesManager) @requests_mock.Mocker() def test_history(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/images" "/326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab/history", json=[{ "Id": "326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab", "Comment": "", "Created": 1614208404, "CreatedBy": "2021-02-24T23:13:24+00:00", "Tags": ["latest"], "Size": 1024, }], ) mock.get( "http+unix://localhost:9999/v3.0.0/libpod/images" "/326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab/json", json=FIRST_IMAGE, ) image = self.client.images.get( "326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab") history = image.history() self.assertEqual(history[0]["Id"], image.id) @requests_mock.Mocker() def test_reload(self, mock): update = FIRST_IMAGE.copy() update["Containers"] = 0 mock.get( "http+unix://localhost:9999/v3.0.0/libpod/images" "/326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab/json", [ { "json": FIRST_IMAGE }, { "json": update }, ], ) image = self.client.images.get( "326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab") self.assertEqual(image.attrs["Containers"], 2) image.reload() self.assertEqual(image.attrs["Containers"], 0) @requests_mock.Mocker() def test_save(self, mock): tarball = b'Yet another weird tarball...' body = io.BytesIO(tarball) mock.get( "http+unix://localhost:9999/v3.0.0/libpod/images" "/326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab/json", json=FIRST_IMAGE, ) mock.get( "http+unix://localhost:9999/v3.0.0/libpod/images/" "326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab/get", body=body, ) image = self.client.images.get( "326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab") with io.BytesIO() as fd: for chunk in image.save(): fd.write(chunk) self.assertEqual(fd.getbuffer(), tarball)
class PodsManagerTestCase(unittest.TestCase): def setUp(self) -> None: super().setUp() self.client = PodmanClient(base_url=tests.BASE_SOCK) def tearDown(self) -> None: super().tearDown() self.client.close() def test_podmanclient(self): manager = self.client.pods self.assertIsInstance(manager, PodsManager) @requests_mock.Mocker() def test_create(self, mock): adapter = mock.post( tests.BASE_URL + "/libpod/pods/create", json={ "Id": "c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8" }, status_code=201, ) mock.get( tests.BASE_URL + "/libpod/pods" "/c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8/json", json=FIRST_POD, ) actual = self.client.pods.create(name="database") self.assertIsInstance(actual, Pod) self.assertTrue(adapter.called_once) self.assertDictEqual(adapter.last_request.json(), {"name": "database"}) @requests_mock.Mocker() def test_get(self, mock): mock.get( tests.BASE_URL + "/libpod/pods" "/c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8/json", json=FIRST_POD, ) actual = self.client.pods.get( "c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8") self.assertEqual( actual.id, "c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8") @requests_mock.Mocker() def test_get404(self, mock): mock.get( tests.BASE_URL + "/libpod/pods" "/c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8/json", status_code=404, json={ "cause": "no such pod", "message": "no pod with name or ID " "c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8" " found: no such pod", "response": 404, }, ) with self.assertRaises(NotFound): self.client.pods.get( "c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8" ) @requests_mock.Mocker() def test_list(self, mock): mock.get(tests.BASE_URL + "/libpod/pods/json", json=[FIRST_POD, SECOND_POD]) actual = self.client.pods.list() self.assertEqual( actual[0].id, "c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8") self.assertEqual( actual[1].id, "c847d00ed0474835a2e246f00e90346fe98d388f98064f4494953c5fb921b8bc") @requests_mock.Mocker() def test_prune(self, mock): adapter = mock.post( tests.BASE_URL + "/libpod/pods/prune", json=[ { "Err": None, "Id": "c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8", }, { "Err": None, "Id": "c847d00ed0474835a2e246f00e90346fe98d388f98064f4494953c5fb921b8bc", }, ], ) actual = self.client.pods.prune() self.assertTrue(adapter.called_once) self.assertListEqual( actual["PodsDeleted"], [ "c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8", "c847d00ed0474835a2e246f00e90346fe98d388f98064f4494953c5fb921b8bc", ], ) self.assertEqual(actual["SpaceReclaimed"], 0) @requests_mock.Mocker() def test_stats(self, mock): body = { "Processes": [ [ 'jhonce', '2417', '2274', '0', 'Mar01', '?', '00:00:01', '/usr/bin/ssh-agent /bin/sh -c exec -l /bin/bash -c "/usr/bin/gnome-session"', ], [ 'jhonce', '5544', '3522', '0', 'Mar01', 'pts/1', '00:00:02', '-bash' ], [ 'jhonce', '6140', '3522', '0', 'Mar01', 'pts/2', '00:00:00', '-bash' ], ], "Titles": ["UID", "PID", "PPID", "C", "STIME", "TTY", "TIME CMD"], } mock.get( tests.BASE_URL + "/libpod/pods/stats" "?namesOrIDs=c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8", json=body, ) actual = self.client.pods.stats( name= "c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8") self.assertDictEqual(actual, body) def test_stats_400(self): with self.assertRaises(ValueError): self.client.pods.stats(all=True, name="container")
class SystemTestCase(unittest.TestCase): def setUp(self) -> None: super().setUp() self.client = PodmanClient(base_url=tests.BASE_SOCK) def tearDown(self) -> None: super().tearDown() self.client.close() @requests_mock.Mocker() def test_df(self, mock): body = { "Containers": [ {"ContainerID": "f1fb3564c202"}, {"ContainerID": "779afab684c7"}, ], "Images": [ {"ImageID": "118cc2c68ef5"}, {"ImageID": "a6b4a8255f9e"}, ], "Volumes": [ {"VolumeName": "27df59163be8"}, {"VolumeName": "77a83a10f86e"}, ], } mock.get( tests.BASE_URL + "/libpod/system/df", json=body, ) actual = self.client.df() self.assertDictEqual(actual, body) @requests_mock.Mocker() def test_info(self, mock): body = { "host": { "arch": "amd65", "os": "linux", } } mock.get(tests.BASE_URL + "/libpod/info", json=body) actual = self.client.info() self.assertDictEqual(actual, body) @requests_mock.Mocker() def test_ping(self, mock): mock.head(tests.BASE_URL + "/libpod/_ping") self.assertTrue(self.client.ping()) @requests_mock.Mocker() def test_version(self, mock): body = { "APIVersion": "3.0.0", "MinAPIVersion": "3.0.0", "Arch": "amd64", "Os": "linux", } mock.get(tests.BASE_URL + "/libpod/version", json=body) self.assertDictEqual(self.client.version(), body)
class NetworkTestCase(unittest.TestCase): def setUp(self) -> None: super().setUp() self.client = PodmanClient(base_url="http+unix://localhost:9999") def tearDown(self) -> None: super().tearDown() self.client.close() def test_id(self): expected = {"Id": "1cf06390-709d-4ffa-a054-c3083abe367c"} actual = Network(attrs=expected) self.assertEqual(actual.id, expected["Id"]) actual = Network(attrs={"name": "database"}) self.assertEqual( actual.id, "3549b0028b75d981cdda2e573e9cb49dedc200185876df299f912b79f69dabd8") def test_name(self): actual = Network(attrs={"Name": "database"}) self.assertEqual(actual.name, "database") actual = Network({"name": "database"}) self.assertEqual(actual.name, "database") @requests_mock.Mocker() def test_remove(self, mock): adapter = mock.delete( "http+unix://localhost:9999/v1.40/networks/podman", json={ "Name": "podman", "Err": None }, ) mock.get("http+unix://localhost:9999/v1.40/networks/podman", json=FIRST_NETWORK) net = self.client.networks.get("podman") net.remove(force=True) self.assertEqual(adapter.call_count, 1) @requests_mock.Mocker() def test_connect(self, mock): adapter = mock.post( "http+unix://localhost:9999/v1.40/networks/podman/connect", ) mock.get("http+unix://localhost:9999/v1.40/networks/podman", json=FIRST_NETWORK) net = self.client.networks.get("podman") net.connect( "podman_ctnr", aliases=["production"], ipv4_address="172.16.0.1", ) self.assertEqual(adapter.call_count, 1) self.assertDictEqual( adapter.last_request.json(), { 'Container': 'podman_ctnr', "EndpointConfig": { 'Aliases': ['production'], 'IPAMConfig': { 'IPv4Address': '172.16.0.1' }, 'IPAddress': '172.16.0.1', 'NetworkID': '2f259bab93aaaaa2542ba43ef33eb990d0999ee1b9924b557b7be53c0b7a1bb9', }, }, ) @requests_mock.Mocker() def test_disconnect(self, mock): adapter = mock.post( "http+unix://localhost:9999/v1.40/networks/podman/disconnect", ) mock.get("http+unix://localhost:9999/v1.40/networks/podman", json=FIRST_NETWORK) net = self.client.networks.get("podman") net.disconnect("podman_ctnr", force=True) self.assertEqual(adapter.call_count, 1) self.assertDictEqual( adapter.last_request.json(), { 'Container': 'podman_ctnr', "Force": True, }, )
class ContainersManagerTestCase(unittest.TestCase): """Test ContainersManager area of concern. Note: Mock responses need to be coded for libpod returns. The python bindings are responsible for mapping to compatible output. """ def setUp(self) -> None: super().setUp() self.client = PodmanClient(base_url="http+unix://localhost:9999") def tearDown(self) -> None: super().tearDown() self.client.close() def test_podmanclient(self): manager = self.client.containers self.assertIsInstance(manager, ContainersManager) @requests_mock.Mocker() def test_get(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers" "/87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) actual = self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") self.assertEqual( actual.id, "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") @requests_mock.Mocker() def test_get_404(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers" "/87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json={ "cause": "Container not found.", "message": "Container not found.", "response": 404, }, status_code=404, ) with self.assertRaises(NotFound): self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd" ) @requests_mock.Mocker() def test_list_empty(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/json", text="[]", ) actual = self.client.containers.list() self.assertListEqual(actual, []) @requests_mock.Mocker() def test_list(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/json", json=[FIRST_CONTAINER, SECOND_CONTAINER], ) actual = self.client.containers.list() self.assertIsInstance(actual, list) self.assertEqual( actual[0].id, "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") self.assertEqual( actual[1].id, "6dc84cc0a46747da94e4c1571efcc01a756b4017261440b4b8985d37203c3c03") @requests_mock.Mocker() def test_list_filtered(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/json" "?all=True" "&filters=%7B%22status%22%3A+%5B%22running%22%5D%2C+" "%22before%22%3A+%5B%226dc84cc0a46747da94e4c1571efcc01a756b4017261440b4b8985d37203c3c03%22%5D%2C+" "%22since%22%3A+%5B%2287e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd%22%5D%7D", json=[FIRST_CONTAINER, SECOND_CONTAINER], ) actual = self.client.containers.list( all=True, filters={"status": "running"}, since= "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd", before= "6dc84cc0a46747da94e4c1571efcc01a756b4017261440b4b8985d37203c3c03", ) self.assertIsInstance(actual, list) self.assertEqual( actual[0].id, "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") self.assertEqual( actual[1].id, "6dc84cc0a46747da94e4c1571efcc01a756b4017261440b4b8985d37203c3c03") @requests_mock.Mocker() def test_list_no_filters(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/json", json=[FIRST_CONTAINER, SECOND_CONTAINER], ) actual = self.client.containers.list() self.assertIsInstance(actual, list) self.assertEqual( actual[0].id, "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") self.assertEqual( actual[1].id, "6dc84cc0a46747da94e4c1571efcc01a756b4017261440b4b8985d37203c3c03") @requests_mock.Mocker() def test_prune(self, mock): mock.post( "http+unix://localhost:9999/v3.0.0/libpod/containers/prune", json=[ { "id": "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd", "space": 1024, }, { "id": "6dc84cc0a46747da94e4c1571efcc01a756b4017261440b4b8985d37203c3c03", "space": 1024, }, ], ) actual = self.client.containers.prune() self.assertDictEqual( actual, { "ContainersDeleted": [ "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd", "6dc84cc0a46747da94e4c1571efcc01a756b4017261440b4b8985d37203c3c03", ], "SpaceReclaimed": 2048, }, )
class NetworksManagerTestCase(unittest.TestCase): """Test NetworksManager area of concern. Note: Mock responses need to be coded for libpod returns. The python bindings are responsible for mapping to compatible output. """ def setUp(self) -> None: super().setUp() self.client = PodmanClient(base_url=tests.BASE_SOCK) def tearDown(self) -> None: super().tearDown() self.client.close() def test_podmanclient(self): manager = self.client.networks self.assertIsInstance(manager, NetworksManager) @requests_mock.Mocker() def test_get(self, mock): mock.get( tests.COMPATIBLE_URL + "/networks/podman", json=FIRST_NETWORK, ) actual = self.client.networks.get("podman") self.assertIsInstance(actual, Network) self.assertEqual( actual.id, "2f259bab93aaaaa2542ba43ef33eb990d0999ee1b9924b557b7be53c0b7a1bb9" ) @requests_mock.Mocker() def test_get_libpod(self, mock): mock.get( tests.LIBPOD_URL + "/networks/podman/json", json=FIRST_NETWORK_LIBPOD, ) actual = self.client.networks.get("podman", compatible=False) self.assertIsInstance(actual, Network) self.assertEqual(actual.attrs["name"], "podman") @requests_mock.Mocker() def test_list(self, mock): mock.get( tests.COMPATIBLE_URL + "/networks", json=[FIRST_NETWORK, SECOND_NETWORK], ) actual = self.client.networks.list() self.assertEqual(len(actual), 2) self.assertIsInstance(actual[0], Network) self.assertEqual( actual[0].id, "2f259bab93aaaaa2542ba43ef33eb990d0999ee1b9924b557b7be53c0b7a1bb9" ) self.assertEqual(actual[0].attrs["Name"], "podman") self.assertIsInstance(actual[1], Network) self.assertEqual( actual[1].id, "3549b0028b75d981cdda2e573e9cb49dedc200185876df299f912b79f69dabd8" ) self.assertEqual(actual[1].name, "database") @requests_mock.Mocker() def test_list_libpod(self, mock): mock.get( tests.LIBPOD_URL + "/networks/json", json=FIRST_NETWORK_LIBPOD + SECOND_NETWORK_LIBPOD, ) actual = self.client.networks.list(compatible=False) self.assertEqual(len(actual), 2) self.assertIsInstance(actual[0], Network) self.assertEqual( actual[0].id, "2f259bab93aaaaa2542ba43ef33eb990d0999ee1b9924b557b7be53c0b7a1bb9" ) self.assertEqual(actual[0].attrs["name"], "podman") self.assertIsInstance(actual[1], Network) self.assertEqual( actual[1].id, "3549b0028b75d981cdda2e573e9cb49dedc200185876df299f912b79f69dabd8" ) self.assertEqual(actual[1].name, "database") @requests_mock.Mocker() def test_create(self, mock): adapter = mock.post( tests.LIBPOD_URL + "/networks/create?name=podman", json={ "Filename": "/home/developer/.config/cni/net.d/podman.conflist", }, ) mock.get( tests.COMPATIBLE_URL + "/networks/podman", json=FIRST_NETWORK, ) pool = IPAMPool(subnet="172.16.0.0/12", iprange="172.16.0.0/16", gateway="172.31.255.254") ipam = IPAMConfig(pool_configs=[pool]) network = self.client.networks.create( "podman", disabled_dns=True, enable_ipv6=False, ipam=ipam ) self.assertIsInstance(network, Network) self.assertEqual(adapter.call_count, 1) self.assertDictEqual( adapter.last_request.json(), { 'DisabledDNS': True, 'Gateway': '172.31.255.254', 'IPv6': False, 'Range': {'IP': '172.16.0.0', 'Mask': "//8AAA=="}, 'Subnet': {'IP': '172.16.0.0', 'Mask': "//AAAA=="}, }, ) self.assertEqual(network.name, "podman") @requests_mock.Mocker() def test_create_defaults(self, mock): adapter = mock.post( tests.LIBPOD_URL + "/networks/create?name=podman", json={ "Filename": "/home/developer/.config/cni/net.d/podman.conflist", }, ) mock.get( tests.COMPATIBLE_URL + "/networks/podman", json=FIRST_NETWORK, ) network = self.client.networks.create("podman") self.assertEqual(adapter.call_count, 1) self.assertEqual(network.name, "podman") self.assertEqual(len(adapter.last_request.json()), 0) @requests_mock.Mocker() def test_prune(self, mock): mock.post( tests.COMPATIBLE_URL + "/networks/prune", json={"NetworksDeleted": ["podman", "database"]}, ) actual = self.client.networks.prune() self.assertListEqual(actual["NetworksDeleted"], ["podman", "database"]) @requests_mock.Mocker() def test_prune_libpod(self, mock): mock.post( tests.LIBPOD_URL + "/networks/prune", json=[ {"Name": "podman", "Error": None}, {"Name": "database", "Error": None}, ], ) actual = self.client.networks.prune(compatible=False) self.assertListEqual(actual["NetworksDeleted"], ["podman", "database"])
class ContainersManagerTestCase(unittest.TestCase): """Test ContainersManager area of concern. Note: Mock responses need to be coded for libpod returns. The python bindings are responsible for mapping to compatible output. """ def setUp(self) -> None: super().setUp() self.client = PodmanClient(base_url=tests.BASE_SOCK) def tearDown(self) -> None: super().tearDown() self.client.close() def test_podmanclient(self): manager = self.client.containers self.assertIsInstance(manager, ContainersManager) @requests_mock.Mocker() def test_get(self, mock): mock.get( tests.BASE_URL + "/libpod/containers" "/87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) actual = self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") self.assertEqual( actual.id, "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") @requests_mock.Mocker() def test_get_404(self, mock): mock.get( tests.BASE_URL + "/libpod/containers" "/87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json={ "cause": "Container not found.", "message": "Container not found.", "response": 404, }, status_code=404, ) with self.assertRaises(NotFound): self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd" ) @requests_mock.Mocker() def test_list_empty(self, mock): mock.get( tests.BASE_URL + "/libpod/containers/json", text="[]", ) actual = self.client.containers.list() self.assertListEqual(actual, []) @requests_mock.Mocker() def test_list(self, mock): mock.get( tests.BASE_URL + "/libpod/containers/json", json=[FIRST_CONTAINER, SECOND_CONTAINER], ) actual = self.client.containers.list() self.assertIsInstance(actual, list) self.assertEqual( actual[0].id, "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") self.assertEqual( actual[1].id, "6dc84cc0a46747da94e4c1571efcc01a756b4017261440b4b8985d37203c3c03") @requests_mock.Mocker() def test_list_filtered(self, mock): mock.get( tests.BASE_URL + "/libpod/containers/json?" "all=True" "&filters=%7B" "%22before%22%3A" "+%5B%226dc84cc0a46747da94e4c1571efcc01a756b4017261440b4b8985d37203c3c03%22%5D%2C" "+%22since%22%3A" "+%5B%2287e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd%22%5D%2C" "+%22status%22%3A+%5B%22running%22%5D%7D", json=[FIRST_CONTAINER, SECOND_CONTAINER], ) actual = self.client.containers.list( all=True, filters={"status": "running"}, since= "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd", before= "6dc84cc0a46747da94e4c1571efcc01a756b4017261440b4b8985d37203c3c03", ) self.assertIsInstance(actual, list) self.assertEqual( actual[0].id, "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") self.assertEqual( actual[1].id, "6dc84cc0a46747da94e4c1571efcc01a756b4017261440b4b8985d37203c3c03") @requests_mock.Mocker() def test_list_no_filters(self, mock): mock.get( tests.BASE_URL + "/libpod/containers/json", json=[FIRST_CONTAINER, SECOND_CONTAINER], ) actual = self.client.containers.list() self.assertIsInstance(actual, list) self.assertEqual( actual[0].id, "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") self.assertEqual( actual[1].id, "6dc84cc0a46747da94e4c1571efcc01a756b4017261440b4b8985d37203c3c03") @requests_mock.Mocker() def test_prune(self, mock): mock.post( tests.BASE_URL + "/libpod/containers/prune", json=[ { "Id": "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd", "Size": 1024, }, { "Id": "6dc84cc0a46747da94e4c1571efcc01a756b4017261440b4b8985d37203c3c03", "Size": 1024, }, ], ) actual = self.client.containers.prune() self.assertDictEqual( actual, { "ContainersDeleted": [ "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd", "6dc84cc0a46747da94e4c1571efcc01a756b4017261440b4b8985d37203c3c03", ], "SpaceReclaimed": 2048, }, ) @requests_mock.Mocker() def test_create(self, mock): mock.post( tests.BASE_URL + "/libpod/containers/create", status_code=201, json={ "Id": "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd", "Warnings": [], }, ) mock.get( tests.BASE_URL + "/libpod/containers" "/87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) actual = self.client.containers.create("fedora", "/usr/bin/ls", cpu_count=9999) self.assertIsInstance(actual, Container) @requests_mock.Mocker() def test_create_404(self, mock): mock.post( tests.BASE_URL + "/libpod/containers/create", status_code=404, json={ "cause": "Image not found", "message": "Image not found", "response": 404, }, ) with self.assertRaises(ImageNotFound): self.client.containers.create("fedora", "/usr/bin/ls", cpu_count=9999) def test_create_unsupported_key(self): with self.assertRaises(TypeError) as e: self.client.containers.create("fedora", "/usr/bin/ls", blkio_weight=100.0) def test_create_unknown_key(self): with self.assertRaises(TypeError) as e: self.client.containers.create("fedora", "/usr/bin/ls", unknown_key=100.0) @requests_mock.Mocker() def test_run_detached(self, mock): mock.post( tests.BASE_URL + "/libpod/containers/create", status_code=201, json={ "Id": "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd", "Warnings": [], }, ) mock.post( tests.BASE_URL + "/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/start", status_code=204, ) mock.get( tests.BASE_URL + "/libpod/containers" "/87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) with patch.multiple(Container, logs=DEFAULT, wait=DEFAULT, autospec=True) as mock_container: mock_container["logs"].return_value = list() mock_container["wait"].return_value = {"StatusCode": 0} actual = self.client.containers.run("fedora", "/usr/bin/ls", detach=True) self.assertIsInstance(actual, Container) @requests_mock.Mocker() def test_run(self, mock): mock.post( tests.BASE_URL + "/libpod/containers/create", status_code=201, json={ "Id": "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd", "Warnings": [], }, ) mock.post( tests.BASE_URL + "/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/start", status_code=204, ) mock.get( tests.BASE_URL + "/libpod/containers" "/87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) mock_logs = ( b"This is a unittest - line 1", b"This is a unittest - line 2", ) with patch.multiple(Container, logs=DEFAULT, wait=DEFAULT, autospec=True) as mock_container: mock_container["wait"].return_value = {"StatusCode": 0} with self.subTest("Results not streamed"): mock_container["logs"].return_value = iter(mock_logs) actual = self.client.containers.run("fedora", "/usr/bin/ls") self.assertIsInstance(actual, bytes) self.assertEqual( actual, b'This is a unittest - line 1This is a unittest - line 2') # iter() cannot be reset so subtests used to create new instance with self.subTest("Stream results"): mock_container["logs"].return_value = iter(mock_logs) actual = self.client.containers.run("fedora", "/usr/bin/ls", stream=True) self.assertNotIsInstance(actual, bytes) self.assertIsInstance(actual, Iterator) self.assertEqual(next(actual), b"This is a unittest - line 1") self.assertEqual(next(actual), b"This is a unittest - line 2")
class PodmanClientTestCase(unittest.TestCase): """Test the PodmanClient() object.""" opener = mock.mock_open(read_data=""" [containers] log_size_max = -1 pids_limit = 2048 userns_size = 65536 [engine] num_locks = 2048 active_service = "testing" stop_timeout = 10 [engine.service_destinations] [engine.service_destinations.production] uri = "ssh://root@localhost:22/run/podman/podman.sock" identity = "/home/root/.ssh/id_rsa" [engine.service_destinations.testing] uri = "ssh://qe@localhost:2222/run/podman/podman.sock" identity = "/home/qe/.ssh/id_rsa" [network] """) def setUp(self) -> None: super().setUp() self.client = PodmanClient(base_url=tests.BASE_SOCK) def mocked_open(self, *args, **kwargs): return PodmanClientTestCase.opener(self, *args, **kwargs) self.mocked_open = mocked_open @mock.patch('requests.Session.close') def test_close(self, mock_close): self.client.close() mock_close.assert_called_once_with() @requests_mock.Mocker() def test_contextmanager(self, mock): body = { "host": { "arch": "amd65", "os": "linux", } } adapter = mock.get(tests.LIBPOD_URL + "/info", json=body) with PodmanClient(base_url=tests.BASE_SOCK) as client: actual = client.info() self.assertDictEqual(actual, body) self.assertIn("User-Agent", mock.last_request.headers) self.assertIn("PodmanPy/", mock.last_request.headers["User-Agent"], mock.last_request.headers) def test_swarm(self): with PodmanClient(base_url=tests.BASE_SOCK) as client: with self.assertRaises(NotImplementedError): # concrete property _ = client.swarm with self.assertRaises(NotImplementedError): # aliased property _ = client.nodes def test_connect(self): with mock.patch.multiple(Path, open=self.mocked_open, exists=MagicMock(return_value=True)): with PodmanClient(connection="testing") as client: self.assertEqual( client.api.base_url.geturl(), "http+ssh://qe@localhost:2222/run/podman/podman.sock", ) # Build path to support tests running as root or a user expected = Path(xdg.BaseDirectory.xdg_config_home ) / "containers" / "containers.conf" PodmanClientTestCase.opener.assert_called_with(expected, encoding="utf-8") def test_connect_404(self): with mock.patch.multiple(Path, open=self.mocked_open, exists=MagicMock(return_value=True)): with self.assertRaises(KeyError): _ = PodmanClient(connection="not defined") def test_connect_default(self): with mock.patch.multiple(Path, open=self.mocked_open, exists=MagicMock(return_value=True)): with PodmanClient() as client: expected = "http+unix://" + urllib.parse.quote_plus( str( Path(xdg.BaseDirectory.get_runtime_dir(strict=False)) / "podman" / "podman.sock")) self.assertEqual(client.api.base_url.geturl(), expected) # Build path to support tests running as root or a user expected = Path(xdg.BaseDirectory.xdg_config_home ) / "containers" / "containers.conf" PodmanClientTestCase.opener.assert_called_with(expected, encoding="utf-8")
class ImageTestCase(unittest.TestCase): def setUp(self) -> None: super().setUp() self.client = PodmanClient(base_url=tests.BASE_SOCK) def tearDown(self) -> None: super().tearDown() self.client.close() @requests_mock.Mocker() def test_history(self, mock): adapter = mock.get( tests.LIBPOD_URL + "/images/326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab/history", json=[{ "Id": "326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab", "Comment": "", "Created": 1614208404, "CreatedBy": "2021-02-24T23:13:24+00:00", "Tags": ["latest"], "Size": 1024, }], ) image = Image(attrs=FIRST_IMAGE, client=self.client.api) history = image.history() self.assertEqual(history[0]["Id"], image.id) self.assertTrue(adapter.called_once) @requests_mock.Mocker() def test_reload(self, mock): update = FIRST_IMAGE.copy() update["Containers"] = 0 adapter = mock.get( tests.LIBPOD_URL + "/images/326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab/json", [ { "json": FIRST_IMAGE }, { "json": update }, ], ) image = self.client.images.get( "326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab") self.assertEqual(image.attrs["Containers"], 2) image.reload() self.assertEqual(image.attrs["Containers"], 0) self.assertTrue(adapter.call_count, 2) @requests_mock.Mocker() def test_save(self, mock): tarball = b'Yet another weird tarball...' body = io.BytesIO(tarball) adapter = mock.get( tests.LIBPOD_URL + "/images/326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab/get", body=body, ) image = Image(attrs=FIRST_IMAGE, client=self.client.api) with io.BytesIO() as fd: for chunk in image.save(): fd.write(chunk) self.assertEqual(fd.getbuffer(), tarball) self.assertTrue(adapter.called_once)
class RegistryDataTestCase(unittest.TestCase): """Test RegistryData. Note: Mock responses need to be coded for libpod returns. The python bindings are responsible for mapping to compatible output. """ def setUp(self) -> None: super().setUp() self.client = PodmanClient(base_url="http+unix://localhost:9999") def tearDown(self) -> None: super().tearDown() self.client.close() @requests_mock.Mocker() def test_init(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/images/" "326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab/json", json=FIRST_IMAGE, ) actual = RegistryData( "326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab", client=self.client.api, collection=ImagesManager(client=self.client.api), ) self.assertEqual( actual.id, "326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab" ) def test_platform(self): rd = RegistryData( "326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab", attrs=FIRST_IMAGE, collection=ImagesManager(client=self.client.api), ) self.assertTrue(rd.has_platform("linux/amd64/fedora")) def test_platform_dict(self): rd = RegistryData( "326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab", attrs=FIRST_IMAGE, collection=ImagesManager(client=self.client.api), ) self.assertTrue(rd.has_platform({"os": "linux", "architecture": "amd64"})) def test_platform_404(self): rd = RegistryData( "326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab", attrs=FIRST_IMAGE, collection=ImagesManager(client=self.client.api), ) self.assertFalse(rd.has_platform({"os": "COS", "architecture": "X-MP"})) def test_platform_409(self): rd = RegistryData( "326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab", attrs=FIRST_IMAGE, collection=ImagesManager(client=self.client.api), ) with self.assertRaises(InvalidArgument): rd.has_platform(list()) def test_platform_500(self): rd = RegistryData( "326dd9d7add24646a325e8eaa82125294027db2332e49c5828d96312c5d773ab", attrs=FIRST_IMAGE, collection=ImagesManager(client=self.client.api), ) with self.assertRaises(InvalidArgument): rd.has_platform("This/is/not/a/legal/image/name")
class PodTestCase(unittest.TestCase): def setUp(self) -> None: super().setUp() self.client = PodmanClient(base_url=tests.BASE_SOCK) def tearDown(self) -> None: super().tearDown() self.client.close() def test_id(self): expected = {"Id": "c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8"} actual = Pod(attrs=expected) self.assertEqual(actual.id, expected["Id"]) expected = {"Name": "redis-ngnix"} actual = Pod(attrs=expected) self.assertEqual(actual.name, expected["Name"]) @requests_mock.Mocker() def test_kill(self, mock): adapter = mock.post( tests.BASE_URL + "/libpod/pods" "/c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8/kill", json={ "Errs": [], "Id": "c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8", }, ) pod = Pod(attrs=FIRST_POD, client=self.client.api) pod.kill() self.assertTrue(adapter.called_once) @requests_mock.Mocker() def test_kill_404(self, mock): adapter = mock.post( tests.BASE_URL + "/libpod/pods" "/c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8/kill", status_code=404, json={ "cause": "no such pod", "message": "no pod with name or ID xyz found: no such pod", "response": 404, }, ) pod = Pod(attrs=FIRST_POD, client=self.client.api) with self.assertRaises(NotFound): pod.kill() self.assertTrue(adapter.called_once) @requests_mock.Mocker() def test_pause(self, mock): adapter = mock.post( tests.BASE_URL + "/libpod/pods" "/c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8/pause", json={ "Errs": [], "Id": "c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8", }, ) pod = Pod(attrs=FIRST_POD, client=self.client.api) pod.pause() self.assertTrue(adapter.called_once) @requests_mock.Mocker() def test_pause_404(self, mock): adapter = mock.post( tests.BASE_URL + "/libpod/pods" "/c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8/pause", status_code=404, json={ "cause": "no such pod", "message": "no pod with name or ID xyz found: no such pod", "response": 404, }, ) pod = Pod(attrs=FIRST_POD, client=self.client.api) with self.assertRaises(NotFound): pod.pause() self.assertTrue(adapter.called_once) @requests_mock.Mocker() def test_remove(self, mock): adapter = mock.delete( tests.BASE_URL + "/libpod/pods/" "c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8?force=True", json={ "Errs": [], "Id": "c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8", }, ) pod_manager = PodsManager(client=self.client.api) pod = pod_manager.prepare_model(attrs=FIRST_POD) pod.remove(force=True) self.assertTrue(adapter.called_once) @requests_mock.Mocker() def test_restart(self, mock): adapter = mock.post( tests.BASE_URL + "/libpod/pods" "/c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8/restart", json={ "Errs": [], "Id": "c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8", }, ) pod = Pod(attrs=FIRST_POD, client=self.client.api) pod.restart() self.assertTrue(adapter.called_once) @requests_mock.Mocker() def test_start(self, mock): adapter = mock.post( tests.BASE_URL + "/libpod/pods" "/c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8/start", json={ "Errs": [], "Id": "c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8", }, ) pod = Pod(attrs=FIRST_POD, client=self.client.api) pod.start() self.assertTrue(adapter.called_once) @requests_mock.Mocker() def test_stop(self, mock): adapter = mock.post( tests.BASE_URL + "/libpod/pods" "/c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8/stop?t=70.0", json={ "Errs": [], "Id": "c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8", }, ) pod = Pod(attrs=FIRST_POD, client=self.client.api) pod.stop(timeout=70.0) self.assertTrue(adapter.called_once) @requests_mock.Mocker() def test_top(self, mock): body = { "Processes": [ [ 'jhonce', '2417', '2274', '0', 'Mar01', '?', '00:00:01', '/usr/bin/ssh-agent /bin/sh -c exec -l /bin/bash -c "/usr/bin/gnome-session"', ], ['jhonce', '5544', '3522', '0', 'Mar01', 'pts/1', '00:00:02', '-bash'], ['jhonce', '6140', '3522', '0', 'Mar01', 'pts/2', '00:00:00', '-bash'], ], "Titles": ["UID", "PID", "PPID", "C", "STIME", "TTY", "TIME CMD"], } adapter = mock.get( tests.BASE_URL + "/libpod/pods" "/c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8/top" "?ps_args=aux&stream=False", json=body, ) pod = Pod(attrs=FIRST_POD, client=self.client.api) actual = pod.top(ps_args="aux") self.assertDictEqual(actual, body) self.assertTrue(adapter.called_once) @requests_mock.Mocker() def test_unpause(self, mock): adapter = mock.post( tests.BASE_URL + "/libpod/pods" "/c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8/unpause", json={ "Errs": [], "Id": "c8b9f5b17dc1406194010c752fc6dcb330192032e27648db9b14060447ecf3b8", }, ) pod = Pod(attrs=FIRST_POD, client=self.client.api) pod.unpause() self.assertTrue(adapter.called_once)
class ContainersTestCase(unittest.TestCase): def setUp(self) -> None: super().setUp() self.client = PodmanClient(base_url="http+unix://localhost:9999") def tearDown(self) -> None: super().tearDown() self.client.close() @requests_mock.Mocker() def test_remove(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) mock.delete( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd?v=True&force=True", status_code=204, ) container = self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") container.remove(v=True, force=True) @requests_mock.Mocker() def test_rename(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) mock.post( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/rename", status_code=204, ) container = self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") container.rename("good_galileo") self.assertEqual(container.attrs["Name"], "good_galileo") @requests_mock.Mocker() def test_rename_409(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) mock.post( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/rename", status_code=204, ) container = self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") with self.assertRaises(ValueError): container.rename() @requests_mock.Mocker() def test_restart(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) mock.post( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/restart?timeout=10", status_code=204, ) container = self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") container.restart(timeout=10) @requests_mock.Mocker() def test_start_dkeys(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) mock.post( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/start" "?detachKeys=%5Ef%5Eu", status_code=204, ) container = self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") container.start(detach_keys="^f^u") @requests_mock.Mocker() def test_start(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) mock.post( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/start", status_code=204, ) container = self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") container.start() @requests_mock.Mocker() def test_stats(self, mock): stream = [{ "Error": None, "Stats": [{ "ContainerId": "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd", "Name": "evil_ptolemy", "CPU": 1000.0, }], }] buffer = io.StringIO() for entry in stream: buffer.write(json.JSONEncoder().encode(entry)) buffer.write("\n") mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/stats" "?containers=87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd" "&stream=True", text=buffer.getvalue(), ) container = self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") stats = container.stats(decode=True) self.assertIsInstance(stats, Iterable) for entry in stats: self.assertIsInstance(entry, dict) for stat in entry["Stats"]: self.assertEqual( stat["ContainerId"], "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd", ) @requests_mock.Mocker() def test_stop(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) mock.post( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/stop" "?all=True&timeout=10.0", status_code=204, ) container = self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") container.stop(all=True, timeout=10.0) @requests_mock.Mocker() def test_stop_304(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) mock.post( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/stop", json={ "cause": "container already stopped", "message": "container already stopped", "response": 304, }, status_code=304, ) with self.assertRaises(APIError): container = self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd" ) container.stop() @requests_mock.Mocker() def test_unpause(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) mock.post( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/unpause", status_code=204, ) container = self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") container.unpause() @requests_mock.Mocker() def test_pause(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) mock.post( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/pause", status_code=204, ) container = self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") container.pause() @requests_mock.Mocker() def test_wait(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) mock.post( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/wait", status_code=204, ) container = self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") container.wait() @requests_mock.Mocker() def test_diff(self, mock): payload = [ { "Path": "modified", "Kind": 0 }, { "Path": "added", "Kind": 1 }, { "Path": "deleted", "Kind": 2 }, ] mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/changes", json=payload, ) container = self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") actual = container.diff() self.assertListEqual(actual, payload) @requests_mock.Mocker() def test_diff_404(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/changes", json={ "cause": "Container not found.", "message": "Container not found.", "response": 404, }, status_code=404, ) container = self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") with self.assertRaises(NotFound): container.diff() @requests_mock.Mocker() def test_export(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) tarball = b'Yet another weird tarball...' body = io.BytesIO(tarball) mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/export", body=body, ) container = self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") with io.BytesIO() as fd: for chunk in container.export(): fd.write(chunk) self.assertEqual(fd.getbuffer(), tarball) @requests_mock.Mocker() def test_get_archive(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) tarball = b'Yet another weird tarball...' body = io.BytesIO(tarball) header_value = { "name": "/etc/motd", "size": len(tarball), "mode": 0o444, "mtime": "20210309T12:49:0205:00", } encoded_value = base64.urlsafe_b64encode( json.dumps(header_value).encode("utf8")) mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/archive" "?path=/etc/motd", body=body, headers={ "x-docker-container-path-stat": encoded_value.decode("utf8") }, ) container = self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") actual = container.get_archive("/etc/motd") self.assertEqual(len(actual), 2) self.assertEqual(actual[1]["name"], "/etc/motd") with io.BytesIO() as fd: for chunk in actual[0]: fd.write(chunk) self.assertEqual(fd.getbuffer(), tarball) @requests_mock.Mocker() def test_commit(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) mock.post( "http+unix://localhost:9999/v3.0.0/libpod/commit" "?author=redhat&changes=ADD+%2Fetc%2Fmod&comment=This+is+a+unittest" "&container=87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd&format=docker" "&pause=True&repo=quay.local&tag=unittest", status_code=201, json={ "ID": "d2459aad75354ddc9b5b23f863786e279637125af6ba4d4a83f881866b3c903f" }, ) mock.get( "http+unix://localhost:9999/v3.0.0/libpod/images/" "d2459aad75354ddc9b5b23f863786e279637125af6ba4d4a83f881866b3c903f/json", json={ "Id": "d2459aad75354ddc9b5b23f863786e279637125af6ba4d4a83f881866b3c903f" }, ) container = self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") image = container.commit( repository="quay.local", tag="unittest", author="redhat", changes=["ADD /etc/mod"], comment="This is a unittest", format="docker", message="This is a unittest", pause=True, ) self.assertEqual( image.id, "d2459aad75354ddc9b5b23f863786e279637125af6ba4d4a83f881866b3c903f") @requests_mock.Mocker() def test_put_archive(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) mock.put( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/archive" "?path=%2Fetc%2Fmotd", status_code=200, ) container = self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") tarball = b'Yet another weird tarball...' body = io.BytesIO(tarball) actual = container.put_archive(path="/etc/motd", data=body.getvalue()) self.assertTrue(actual) @requests_mock.Mocker() def test_put_archive_404(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) mock.put( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/archive" "?path=deadbeef", status_code=404, ) container = self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") tarball = b'Yet another weird tarball...' body = io.BytesIO(tarball) actual = container.put_archive(path="deadbeef", data=body.getvalue()) self.assertFalse(actual) @requests_mock.Mocker() def test_top(self, mock): mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/json", json=FIRST_CONTAINER, ) body = { "Processes": [ [ 'jhonce', '2417', '2274', '0', 'Mar01', '?', '00:00:01', '/usr/bin/ssh-agent /bin/sh -c exec -l /bin/bash -c "/usr/bin/gnome-session"', ], [ 'jhonce', '5544', '3522', '0', 'Mar01', 'pts/1', '00:00:02', '-bash' ], [ 'jhonce', '6140', '3522', '0', 'Mar01', 'pts/2', '00:00:00', '-bash' ], ], "Titles": ["UID", "PID", "PPID", "C", "STIME", "TTY", "TIME CMD"], } mock.get( "http+unix://localhost:9999/v3.0.0/libpod/containers/" "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd/top", json=body, ) container = self.client.containers.get( "87e1325c82424e49a00abdd4de08009eb76c7de8d228426a9b8af9318ced5ecd") actual = container.top() self.assertDictEqual(actual, body)
class TestBuildCase(unittest.TestCase): """Test ImagesManager build(). Note: Mock responses need to be coded for libpod returns. The python bindings are responsible for mapping to compatible output. """ def setUp(self) -> None: super().setUp() self.client = PodmanClient(base_url="http+unix://localhost:9999") def tearDown(self) -> None: super().tearDown() self.client.close() @patch.object(api, "create_tar") @patch.object(api, "prepare_containerfile") def test_build(self, mock_prepare_containerfile, mock_create_tar): mock_prepare_containerfile.return_value = "Containerfile" mock_create_tar.return_value = b"This is a mocked tarball." stream = [ { "stream": " ---\u003e a9eb17255234" }, { "stream": "Step 1 : VOLUME /data" }, { "stream": " ---\u003e Running in abdc1e6896c6" }, { "stream": " ---\u003e 713bca62012e" }, { "stream": "Removing intermediate container abdc1e6896c6" }, { "stream": "Step 2 : CMD [\"/bin/sh\"]" }, { "stream": " ---\u003e Running in dba30f2a1a7e" }, { "stream": " ---\u003e 032b8b2855fc" }, { "stream": "Removing intermediate container dba30f2a1a7e" }, { "stream": "032b8b2855fc\n" }, ] buffer = io.StringIO() for entry in stream: buffer.write(json.JSONEncoder().encode(entry)) buffer.write("\n") with requests_mock.Mocker() as mock: mock.post( "http+unix://localhost:9999/v3.0.0/libpod/build" "?t=latest" "&buildargs=%7B%22BUILD_DATE%22%3A+%22January+1%2C+1970%22%7D" "&cpuperiod=10" "&extrahosts=%7B%22database%22%3A+%22127.0.0.1%22%7D" "&labels=%7B%22Unittest%22%3A+%22true%22%7D", text=buffer.getvalue(), ) mock.get( "http+unix://localhost:9999/v3.0.0/libpod/images/032b8b2855fc/json", json={ "Id": "032b8b2855fc", "ParentId": "", "RepoTags": ["fedora:latest", "fedora:33", "<none>:<none>"], "RepoDigests": [ "fedora@sha256:9598a10fa72b402db876ccd4b3d240a4061c7d1e442745f1896ba37e1bf38664" ], "Created": 1614033320, "Size": 23855104, "VirtualSize": 23855104, "SharedSize": 0, "Labels": {}, "Containers": 2, }, ) image, logs = self.client.images.build( path="/tmp/context_dir", tag="latest", buildargs={ "BUILD_DATE": "January 1, 1970", }, container_limits={ "cpuperiod": 10, }, extra_hosts={"database": "127.0.0.1"}, labels={"Unittest": "true"}, ) self.assertIsInstance(image, Image) self.assertEqual(image.id, "032b8b2855fc") self.assertIsInstance(logs, Iterable) @patch.object(api, "create_tar") @patch.object(api, "prepare_containerfile") def test_build_logged_error(self, mock_prepare_containerfile, mock_create_tar): mock_prepare_containerfile.return_value = "Containerfile" mock_create_tar.return_value = b"This is a mocked tarball." stream = [ { "error": "We do not need any stinking badges." }, ] buffer = io.StringIO() for entry in stream: buffer.write(json.JSONEncoder().encode(entry)) buffer.write("\n") with requests_mock.Mocker() as mock: mock.post( "http+unix://localhost:9999/v3.0.0/libpod/build", text=buffer.getvalue(), ) with self.assertRaises(BuildError) as e: self.client.images.build(path="/tmp/context_dir") self.assertEqual(e.exception.msg, "We do not need any stinking badges.") @requests_mock.Mocker() def test_build_no_context(self, mock): mock.post("http+unix://localhost:9999/v3.0.0/libpod/images/build") with self.assertRaises(TypeError): self.client.images.build() @requests_mock.Mocker() def test_build_encoding(self, mock): mock.post("http+unix://localhost:9999/v3.0.0/libpod/images/build") with self.assertRaises(DockerException): self.client.images.build(path="/root", gzip=True, encoding="utf-8")