def img_metadata(self, name, tag, deps): img = ImageFSM(os.path.join(fixtures_dir, "foo-bar"), self.builder.client, self.builder.config) img.image.short_name = name # Clean up the images registry before initiating images this way. ImageFSM._instances.pop() ImageFSM._instances.append(name) img.image.tag = tag img.image.metadata["depends"] = deps img.state = ImageFSM.STATE_TO_BUILD return img
def test_image_state(self, exists, client): exists.return_value = True ImageFSM._instances = [] # We set up no registry, thus we can't have a published image. img = ImageFSM(os.path.join(fixtures_dir, "foo-bar"), client, {"seed_image": "test"}) self.assertEqual(img.state, ImageFSM.STATE_BUILT) ImageFSM._instances = [] exists.return_value = False img = ImageFSM(os.path.join(fixtures_dir, "foo-bar"), client, {"seed_image": "test"}) self.assertEqual(img.state, ImageFSM.STATE_TO_BUILD)
def test_build(self, verify, build, exists): # Simple build exists.return_value = False # The first image builds correctly, the second one doesn't build.side_effect = [True, False] # Assume verification is successful verify.return_value = True img0 = ImageFSM(os.path.join(fixtures_dir, "foo-bar"), self.builder.client, self.builder.config) img1 = ImageFSM(os.path.join(fixtures_dir, "foobar-server"), self.builder.client, self.builder.config) self.builder.all_images = set([img0, img1]) result = [r for r in self.builder.build()] # Check we did not pull the base image. self.builder.client.images.pull.assert_not_called() # Check we called verify only once, for the image correctly built self.assertEqual(verify.call_count, 1) # Check the results. self.assertEqual("foo-bar:0.0.1", result[0].label) self.assertEqual("verified", result[0].state) self.builder.client.api.tag.assert_any_call("foo-bar:0.0.1", "foo-bar", "latest") self.assertEqual("foobar-server:0.0.1~alpha1", result[1].label) self.assertEqual("error", result[1].state)
def test_images_in_state(self): img0 = ImageFSM(os.path.join(fixtures_dir, "foo-bar"), self.builder.client, self.builder.config) img1 = ImageFSM(os.path.join(fixtures_dir, "foobar-server"), self.builder.client, self.builder.config) img0.state = ImageFSM.STATE_BUILT img1.state = ImageFSM.STATE_ERROR self.builder.all_images = set([img0, img1]) self.assertEqual([img0], self.builder.images_in_state(ImageFSM.STATE_BUILT))
def test_pull_images(self): img0 = ImageFSM(os.path.join(fixtures_dir, "foo-bar"), self.builder.client, self.builder.config) img1 = ImageFSM(os.path.join(fixtures_dir, "foobar-server"), self.builder.client, self.builder.config) img0.state = ImageFSM.STATE_BUILT img1.state = ImageFSM.STATE_TO_BUILD self.builder.all_images = set([img0, img1]) # img1 is locally built, but not published. No image should be pulled. self.builder.pull_dependencies(img1) self.builder.client.images.assert_not_called() # now if it's published, we should pull it instead img0.state = ImageFSM.STATE_PUBLISHED self.builder.pull_dependencies(img1) self.builder.client.images.pull.assert_called_with(img0.image.image)
def test_build_pull(self, pull, verify, build): self.builder.pull = True verify.return_value = True def pull_result(img): if img.label == "foobar-server:0.0.1~alpha1": img.state = ImageFSM.STATE_ERROR pull.side_effect = pull_result img0 = ImageFSM(os.path.join(fixtures_dir, "foo-bar"), self.builder.client, self.builder.config) img1 = ImageFSM(os.path.join(fixtures_dir, "foobar-server"), self.builder.client, self.builder.config) img0.state = ImageFSM.STATE_TO_BUILD img1.state = ImageFSM.STATE_TO_BUILD build.return_value = True self.builder.all_images = set([img0, img1]) result = [r for r in self.builder.build()] # Check we also pulled the base image self.builder.client.images.pull.assert_called_with("test") pull.assert_has_calls([call(img0), call(img1)]) assert build.call_count == 1
def test_publish(self, verify): self.builder.client.api = MagicMock() self.builder.config["username"] = None self.builder.config["password"] = None self.builder.config["registry"] = "example.org" with patch("docker_pkg.builder.ImageFSM._is_published") as mp: mp.return_value = False img0 = ImageFSM(os.path.join(fixtures_dir, "foo-bar"), self.builder.client, self.builder.config) img1 = ImageFSM( os.path.join(fixtures_dir, "foobar-server"), self.builder.client, self.builder.config, ) # One image was already built, the other was verified. img0.state = "built" img1.state = "verified" self.builder.all_images = set([img0, img1]) # No image gets published if no credentials are set. self.assertEqual([], [r for r in self.builder.publish()]) self.assertEqual(self.builder.client.api.tag.call_count, 0) self.assertEqual(verify.call_count, 0) # Now with credentials set self.builder.config["username"] = "******" self.builder.config["password"] = "******" result = [r for r in self.builder.publish()] self.assertEqual(ImageFSM.STATE_PUBLISHED, result[1].state) self.builder.client.api.push.assert_any_call( "example.org/foobar-server", "0.0.1~alpha1", auth_config={ "username": "******", "password": "******" }, ) # Only one image needed to be verified before publishing. self.assertEqual(verify.call_count, 1)
def setUp(self): ImageFSM._instances = [] dockerfile.TemplateEngine.setup({}, []) with patch("docker.from_env") as client: self.img = ImageFSM(os.path.join(fixtures_dir, "foo-bar"), client, {"seed_image": "test"})
class TestImageFSM(unittest.TestCase): def setUp(self): ImageFSM._instances = [] dockerfile.TemplateEngine.setup({}, []) with patch("docker.from_env") as client: self.img = ImageFSM(os.path.join(fixtures_dir, "foo-bar"), client, {"seed_image": "test"}) def test_init(self): self.assertIsInstance(self.img.image, image.DockerImage) self.assertEqual(self.img.children, set()) # Reinitializing the same image raises an error self.assertRaises( RuntimeError, ImageFSM, os.path.join(fixtures_dir, "foo-bar"), MagicMock(), # here should go a docker client {"seed_image": "test"}, ) @patch("docker.from_env") @patch("docker_pkg.image.DockerImage.exists") def test_image_state(self, exists, client): exists.return_value = True ImageFSM._instances = [] # We set up no registry, thus we can't have a published image. img = ImageFSM(os.path.join(fixtures_dir, "foo-bar"), client, {"seed_image": "test"}) self.assertEqual(img.state, ImageFSM.STATE_BUILT) ImageFSM._instances = [] exists.return_value = False img = ImageFSM(os.path.join(fixtures_dir, "foo-bar"), client, {"seed_image": "test"}) self.assertEqual(img.state, ImageFSM.STATE_TO_BUILD) def test_label(self): self.assertEqual(self.img.label, "foo-bar:0.0.1") self.img.config["namespace"] = "test" self.img.config["registry"] = "example.org" self.assertEqual(self.img.label, "example.org/test/foo-bar:0.0.1") def test_name(self): self.assertEqual(self.img.name, "foo-bar") def test_repr(self): self.assertEqual(repr(self.img), "ImageFSM(foo-bar:0.0.1, built)") @patch("docker_pkg.image.DockerImage.build") def test_build(self, build): # An already built image doesn't get built again self.img.state = ImageFSM.STATE_BUILT self.img.build() self.assertEqual(build.call_count, 0) # Trying to build a published image raises an error self.img.state = ImageFSM.STATE_PUBLISHED self.assertRaises(ValueError, self.img.build) # If the build fails, we end up in an error state self.img.state = ImageFSM.STATE_TO_BUILD build.return_value = False self.img.build() self.assertEqual(self.img.state, ImageFSM.STATE_ERROR) # Happy path: to build => built self.img.state = ImageFSM.STATE_TO_BUILD build.return_value = True self.img.build() self.assertEqual(self.img.state, ImageFSM.STATE_BUILT) @patch("docker_pkg.image.DockerImage.verify") def test_verify(self, verify): self.img.state = ImageFSM.STATE_BUILT self.img.verify() self.assertEqual(self.img.state, ImageFSM.STATE_VERIFIED) self.assertEqual(verify.call_count, 1) @patch("docker_pkg.image.DockerImage.verify") def test_verify_no_action(self, verify): self.img.state = ImageFSM.STATE_VERIFIED self.img.verify() self.assertEqual(verify.call_count, 0) @patch("docker_pkg.image.DockerImage.verify") def test_verify_bad_state(self, verify): self.img.state = ImageFSM.STATE_TO_BUILD self.assertRaises(ValueError, self.img.verify) self.assertEqual(verify.call_count, 0)