Beispiel #1
0
class SystemIntegrationTest(base.IntegrationTest):
    """system call integration test"""
    def setUp(self):
        super().setUp()
        self.client = PodmanClient(base_url=self.socket_uri)
        self.addCleanup(self.client.close)

    def test_info(self):
        """integration: system info call"""
        output = self.client.info()
        self.assertTrue('host' in output)

    def test_version(self):
        """integration: system version call"""
        output = self.client.version()
        self.assertTrue('Platform' in output)
        self.assertTrue('Version' in output)
        self.assertTrue('ApiVersion' in output)

    def test_show_disk_usage(self):
        """integration: system disk usage call"""
        output = self.client.df()
        self.assertTrue('Images' in output)
        self.assertTrue('Containers' in output)
        self.assertTrue('Volumes' in output)
Beispiel #2
0
    def test_unix_ping(self):
        with PodmanClient(base_url=f"unix://{self.socket_file}") as client:
            self.assertTrue(client.ping())

        with PodmanClient(
                base_url=f"http+unix://{self.socket_file}") as client:
            self.assertTrue(client.ping())
Beispiel #3
0
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()
Beispiel #4
0
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)
Beispiel #5
0
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 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
Beispiel #8
0
    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
Beispiel #9
0
    def _podman_connect(self, podman_uri: str):
        logging.debug("Connecting to Podman API")
        try:
            client = PodmanClient(base_url=podman_uri, timeout=60)
            client.info()  # info() will try to connect to the API
        except APIError as e:
            raise PoolManagerError(f"Could not connect to Podman API: {e}")

        self._podman_client = client
Beispiel #10
0
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()
Beispiel #11
0
    def test_ssh_ping(self):
        with PodmanClient(
                base_url=
                f"http+ssh://{getpass.getuser()}@localhost:22{self.socket_file}"
        ) as client:
            self.assertTrue(client.ping())

        with PodmanClient(
                base_url=
                f"ssh://{getpass.getuser()}@localhost:22{self.socket_file}"
        ) as client:
            self.assertTrue(client.ping())
Beispiel #12
0
    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
Beispiel #13
0
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")
Beispiel #14
0
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)
Beispiel #15
0
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)
Beispiel #16
0
    def setUp(self):
        super().setUp()
        self.client = PodmanClient(base_url=self.socket_uri)
        self.addCleanup(self.client.close)

        with suppress(NotFound):
            self.client.networks.get("integration_test").remove(force=True)
Beispiel #17
0
    def setUp(self):
        super().setUp()

        self.client = PodmanClient(base_url=self.socket_uri)
        self.addCleanup(self.client.close)

        self.alpine_image = self.client.images.pull("quay.io/libpod/alpine",
                                                    tag="latest")
Beispiel #18
0
    def test_tcp_ping(self):
        podman = utils.PodmanLauncher(
            "tcp:localhost:8889",
            podman_path=base.IntegrationTest.podman,
            log_level=self.log_level,
        )
        try:
            podman.start(check_socket=False)
            time.sleep(0.5)

            with PodmanClient(base_url=f"tcp:localhost:8889") as client:
                self.assertTrue(client.ping())

            with PodmanClient(base_url=f"http://localhost:8889") as client:
                self.assertTrue(client.ping())
        finally:
            podman.stop()
Beispiel #19
0
    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
Beispiel #20
0
    def setUp(self):
        super().setUp()

        self.client = PodmanClient(base_url=self.socket_uri)
        self.addCleanup(self.client.close)

        self.alpine_image = self.client.images.pull("quay.io/libpod/alpine", tag="latest")

        # TODO should this use podman binary instead?
        for container in self.client.containers.list():
            container.remove(force=True)
    def test_contextmanager(self, mock):
        body = {
            "host": {
                "arch": "amd65",
                "os": "linux",
            }
        }
        mock.get(tests.BASE_URL + "/libpod/info", json=body)

        with PodmanClient(base_url="http+unix://localhost:9999") as client:
            actual = client.info()
        self.assertDictEqual(actual, body)
Beispiel #22
0
    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)
Beispiel #23
0
    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)
Beispiel #24
0
    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)
Beispiel #25
0
    def setUp(self) -> None:
        super().setUp()

        self.client = PodmanClient(base_url="http+unix://localhost:9999")
Beispiel #26
0
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)
    def setUp(self) -> None:
        super().setUp()

        self.client = PodmanClient(base_url=tests.BASE_SOCK)
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"])
Beispiel #29
0
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")
Beispiel #30
0
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")