class TestContainerManager(TestCase):
    """
    Verifies functionality of ContainerManager by calling Docker APIs
    """
    IMAGE = "busybox"  # small sized Linux container

    @classmethod
    def setUpClass(cls):
        # Make sure we start with a clean slate
        docker_client = docker.from_env()
        TestContainerManager._remove_image(docker_client)

    def setUp(self):
        self.manager = ContainerManager()
        self.docker_client = docker.from_env()

    def tearDown(self):
        self._remove_image(self.docker_client)

    def test_pull_image(self):
        # Image should not exist
        self.assertFalse(self.manager.has_image(self.IMAGE))

        # Pull the image
        self.manager.pull_image(self.IMAGE)

        # Image should be available now
        self.assertTrue(self.manager.has_image(self.IMAGE))

    @classmethod
    def _remove_image(cls, docker_client):
        try:
            docker_client.images.remove(cls.IMAGE)
        except docker.errors.ImageNotFound:
            pass
class TestContainerManager_pull_image(TestCase):
    def setUp(self):
        self.image_name = "image name"

        self.mock_docker_client = Mock()
        self.mock_docker_client.api = Mock()
        self.mock_docker_client.api.pull = Mock()

        self.manager = ContainerManager(docker_client=self.mock_docker_client)

    def test_must_pull_and_print_progress_dots(self):

        stream = io.StringIO()
        pull_result = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
        self.mock_docker_client.api.pull.return_value = pull_result
        expected_stream_output = "\nFetching {} Docker container image...{}\n".format(
            self.image_name, "." * len(pull_result)  # Progress bar will print one dot per response from pull API
        )

        self.manager.pull_image(self.image_name, stream=stream)

        self.mock_docker_client.api.pull.assert_called_with(self.image_name, stream=True, decode=True)
        self.assertEqual(stream.getvalue(), expected_stream_output)

    def test_must_raise_if_image_not_found(self):
        msg = "some error"
        self.mock_docker_client.api.pull.side_effect = APIError(msg)

        with self.assertRaises(DockerImagePullFailedException) as context:
            self.manager.pull_image("imagename")

        ex = context.exception
        self.assertEqual(str(ex), msg)
Example #3
0
class TestContainerManager_pull_image(TestCase):

    def setUp(self):
        self.image_name = "image name"

        self.mock_docker_client = Mock()
        self.mock_docker_client.api = Mock()
        self.mock_docker_client.api.pull = Mock()

        self.manager = ContainerManager(docker_client=self.mock_docker_client)

    def test_must_pull_and_print_progress_dots(self):

        stream = io.StringIO()
        pull_result = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
        self.mock_docker_client.api.pull.return_value = pull_result
        expected_stream_output = "\nFetching {} Docker container image...{}\n".format(
            self.image_name,
            '.' * len(pull_result)  # Progress bar will print one dot per response from pull API
        )

        self.manager.pull_image(self.image_name, stream=stream)

        self.mock_docker_client.api.pull.assert_called_with(self.image_name,
                                                            stream=True,
                                                            decode=True)
        self.assertEquals(stream.getvalue(), expected_stream_output)

    def test_must_raise_if_image_not_found(self):
        msg = "some error"
        self.mock_docker_client.api.pull.side_effect = APIError(msg)

        with self.assertRaises(DockerImagePullFailedException) as context:
            self.manager.pull_image("imagename")

        ex = context.exception
        self.assertEquals(str(ex), msg)
    def setUpClass(cls):

        manager = ContainerManager()
        if not manager.has_image(cls.IMAGE_NAME):
            manager.pull_image(cls.IMAGE_NAME)
    def setUpClass(cls):

        manager = ContainerManager()
        if not manager.has_image(cls.IMAGE_NAME):
            manager.pull_image(cls.IMAGE_NAME)
Example #6
0
class TestContainerManager_pull_image(TestCase):
    def setUp(self):
        self.image_name = "image name"

        self.mock_docker_client = Mock()
        self.mock_docker_client.api = Mock()
        self.mock_docker_client.api.pull = Mock()

        self.manager = ContainerManager(docker_client=self.mock_docker_client)

    def test_must_pull_and_print_progress_dots(self):

        stream = io.StringIO()
        pull_result = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
        self.mock_docker_client.api.pull.return_value = pull_result
        expected_stream_output = "\nFetching {} Docker container image...{}\n".format(
            self.image_name,
            "." *
            len(pull_result
                )  # Progress bar will print one dot per response from pull API
        )

        self.manager.pull_image(self.image_name, stream=stream)

        self.mock_docker_client.api.pull.assert_called_with(self.image_name,
                                                            stream=True,
                                                            decode=True)
        self.assertEqual(stream.getvalue(), expected_stream_output)

    def test_must_raise_if_image_not_found(self):
        msg = "some error"
        self.mock_docker_client.api.pull.side_effect = APIError(msg)

        with self.assertRaises(DockerImagePullFailedException) as context:
            self.manager.pull_image("imagename")

        ex = context.exception
        self.assertEqual(str(ex), msg)

    @patch("samcli.local.docker.manager.threading")
    def test_multiple_image_pulls_must_use_locks(self, mock_threading):
        self.mock_docker_client.api.pull.return_value = [1, 2, 3]

        # mock general lock
        mock_lock = MagicMock()
        self.manager._lock = mock_lock

        # mock locks per image
        mock_image1_lock = MagicMock()
        mock_image2_lock = MagicMock()
        mock_threading.Lock.side_effect = [mock_image1_lock, mock_image2_lock]

        # pull 2 different images for multiple times
        self.manager.pull_image("image1")
        self.manager.pull_image("image1")
        self.manager.pull_image("image2")

        # assert that image1 lock have been used twice and image2 lock only used once
        mock_image1_lock.assert_has_calls(
            2 *
            [call.__enter__(), call.__exit__(ANY, ANY, ANY)],
            any_order=True)
        mock_image2_lock.assert_has_calls(
            [call.__enter__(), call.__exit__(ANY, ANY, ANY)])

        # assert that general lock have been used three times for all the image pulls
        mock_lock.assert_has_calls(
            3 *
            [call.__enter__(), call.__exit__(ANY, ANY, ANY)],
            any_order=True)