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)
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)
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)