def test_get_uncompressed_image_layer_sizes_multiple_entries_in_manifest_json( self, tmpdir): image_util = imageutil.ImageUtil(util.DockerfileImages([]), self.config) path = Path(tmpdir) / 'tarball.tar' manifest_file_content = ( '[{"Config":"62700350851fb36b2e770ba33639e9d111616d39fc63da8845a5e53e9ad013de.json",' '"RepoTags":[],' '"Layers":["92538e92de2938d7c4e279f871107b835bf0c8cc76a5a1655d66855706da18b0.tar"' ',"eb7bf34352ca9ba2fb0218870ac3c47b76d0b1fb7d50543d3ecfa497eca242b0.tar",' '"6da3b8e0475dcc80515944d0cc3f699429248df6b040f8dd7711e681387185e8.tar",' '"07adb74645fe71dec6917e5caca489018edf7ed94f29ac74398eca89c1b9458b.tar"]}, ' '{"Config": "ec3f0931a6e6b6855d76b2d7b0be30e81860baccd891b2e243280bf1cd8ad711.json"' ', "RepoTags": [], ' '"Layers": ["d31505fd5050f6b96ca3268d1db58fc91ae561ddf14eaabc41d63ea2ef8c1c6e.tar"]}]' ).encode('utf-8') mock_files = { "manifest.json": { "content": manifest_file_content, "size": len(manifest_file_content), }, } mock_tarball(tarball_path=path, files=mock_files) with pytest.raises( ValueError, match= "manifest.json file has multiple entries, expected only one"): image_util.get_uncompressed_image_layer_sizes(path=path)
def test_extract_filesystem_layer_multiple_entries_in_manifest_json( self, tmpdir): image_util = imageutil.ImageUtil(util.DockerfileImages([]), self.config) src_path = Path(tmpdir) / 'tarball.tar' dst_path = Path(tmpdir) / 'dst' expected_layer_filename = 'd31505fd5050f6b96ca3268d1db58fc91ae561ddf14eaabc41d63ea2ef8c1c6d.tar' # noqa manifest_file_content = ( '[{"Config": "ec3f0931a6e6b6855d76b2d7b0be30e81860baccd891b2e243280bf1cd8ad710.json"' ', "RepoTags": [], ' '"Layers": ["d31505fd5050f6b96ca3268d1db58fc91ae561ddf14eaabc41d63ea2ef8c1c6d.tar"]},' '{"Config": "ec3f0931a6e6b6855d76b2d7b0be30e81860baccd891b2e243280bf1cd8ad711.json"' ', "RepoTags": [], ' '"Layers": ["d31505fd5050f6b96ca3268d1db58fc91ae561ddf14eaabc41d63ea2ef8c1c6e.tar"]}]' ).encode("utf-8") mocked_files = { 'manifest.json': { 'content': manifest_file_content, 'size': len(manifest_file_content) }, expected_layer_filename: { 'content': None, 'size': 1 } } mock_tarball(tarball_path=src_path, files=mocked_files) with pytest.raises( ValueError, match= "manifest.json file has multiple entries, expected only one"): image_util.extract_filesystem_layer(src_path, dst_path)
def test_extract_filesystem_layer(self, tmpdir): image_util = imageutil.ImageUtil(util.DockerfileImages([]), self.config) src_path = Path(tmpdir) / 'tarball.tar' dst_path = Path(tmpdir) / 'dst' expected_layer_filename = 'd31505fd5050f6b96ca3268d1db58fc91ae561ddf14eaabc41d63ea2ef8c1c6d.tar' # noqa manifest_file_content = ( '[{"Config": "ec3f0931a6e6b6855d76b2d7b0be30e81860baccd891b2e243280bf1cd8ad710.json"' ', "RepoTags": [], ' '"Layers": ["d31505fd5050f6b96ca3268d1db58fc91ae561ddf14eaabc41d63ea2ef8c1c6d.tar"]}]' ).encode('utf-8') mocked_files = { 'manifest.json': { 'content': manifest_file_content, 'size': len(manifest_file_content) }, expected_layer_filename: { 'content': None, 'size': 1 } } mock_tarball(tarball_path=src_path, files=mocked_files) actual_layer_filename = image_util.extract_filesystem_layer( src_path, dst_path) assert actual_layer_filename == expected_layer_filename assert (dst_path / expected_layer_filename).exists()
def test_download_image_archive_tarball(self): image_util = imageutil.ImageUtil(util.DockerfileImages([]), self.config) image = 'registry.com/fedora:35' path = '/tmp/path' (flexmock(retries).should_receive("run_cmd").with_args( ['skopeo', 'copy', f'docker://{image}', f'docker-archive:{path}']).once()) image_util.download_image_archive_tarball(image=image, path=path)
def test_extract_file_from_image_non_empty_dst_dir(self, tmpdir): image_util = imageutil.ImageUtil(util.DockerfileImages([]), self.config) image = 'registry.com/fedora:35' src_path = '/path/to/file' dst_path = Path(tmpdir) / 'dst_dir' dst_path.mkdir() file = dst_path / 'somefile.txt' file.touch() with pytest.raises(NonEmptyDestinationError, match=f'the destination directory {dst_path} must be empty'): image_util.extract_file_from_image(image=image, src_path=src_path, dst_path=str(dst_path))
def test_get_registry_client(self): """Test the method that makes a RegistryClient (other tests mock this method).""" image_util = imageutil.ImageUtil(util.DockerfileImages([]), self.config) registry_session = flexmock() (flexmock(util.RegistrySession).should_receive( "create_from_config").with_args( self.config, "registry.com").once().and_return(registry_session)) flexmock(util.RegistryClient).should_receive("__init__").with_args( registry_session).once() image_util._get_registry_client("registry.com") # test caching (i.e. test that the create_from_config method is called only once) image_util._get_registry_client("registry.com")
def test_extract_filesystem_layer_more_than_one_layer_fail(self, tmpdir): image_util = imageutil.ImageUtil(util.DockerfileImages([]), self.config) src_path = Path(tmpdir) / 'tarball.tar' dst_path = Path(tmpdir) / 'dst' manifest_file_content = ( '[{"Config":"62700350851fb36b2e770ba33639e9d111616d39fc63da8845a5e53e9ad013de.json",' '"RepoTags":[],' '"Layers":["92538e92de2938d7c4e279f871107b835bf0c8cc76a5a1655d66855706da18b0.tar"' ',"eb7bf34352ca9ba2fb0218870ac3c47b76d0b1fb7d50543d3ecfa497eca242b0.tar",' '"6da3b8e0475dcc80515944d0cc3f699429248df6b040f8dd7711e681387185e8.tar",' '"07adb74645fe71dec6917e5caca489018edf7ed94f29ac74398eca89c1b9458b.tar"]}]' ).encode('utf-8') mocked_files = { "92538e92de2938d7c4e279f871107b835bf0c8cc76a5a1655d66855706da18b0.tar": { "content": None, "size": 1, }, "eb7bf34352ca9ba2fb0218870ac3c47b76d0b1fb7d50543d3ecfa497eca242b0.tar": { "content": None, "size": 2, }, "6da3b8e0475dcc80515944d0cc3f699429248df6b040f8dd7711e681387185e8.tar": { "content": None, "size": 3, }, "07adb74645fe71dec6917e5caca489018edf7ed94f29ac74398eca89c1b9458b.tar": { "content": None, "size": 4, }, "manifest.json": { "content": manifest_file_content, "size": len(manifest_file_content), }, } mock_tarball(tarball_path=src_path, files=mocked_files) with pytest.raises( ValueError, match=f'Tarball at {src_path} has more than 1 layer'): image_util.extract_filesystem_layer(src_path, dst_path)
def test_extract_file_from_image_no_file_extracted(self, tmpdir): image_util = imageutil.ImageUtil(util.DockerfileImages([]), self.config) image = 'registry.com/fedora:35' src_path = '/path/to/file' dst_path = Path(tmpdir) / 'dst_dir' dst_path.mkdir() (flexmock(retries).should_receive("run_cmd").with_args([ 'oc', 'image', 'extract', image, '--path', f'{src_path}:{dst_path}' ]).once()) with pytest.raises( ValueError, match= f"Extraction failed, files at path {src_path} not found in the image", ): image_util.extract_file_from_image(image=image, src_path=src_path, dst_path=dst_path)
def test_extract_file_from_image(self, tmpdir): image_util = imageutil.ImageUtil(util.DockerfileImages([]), self.config) image = 'registry.com/fedora:35' src_path = '/path/to/file' dst_path = Path(tmpdir) / 'dst_dir' dst_path.mkdir() # mock the functionality of oc image extract # just creates a file in dst_path def mock_extract_file(cmd): file = dst_path / 'somefile.txt' file.touch() (flexmock(retries).should_receive("run_cmd").with_args([ 'oc', 'image', 'extract', image, '--path', f'{src_path}:{dst_path}' ]).replace_with(mock_extract_file).once()) image_util.extract_file_from_image(image=image, src_path=src_path, dst_path=dst_path)
def test_extract_file_from_image_failed(self, tmpdir): image_util = imageutil.ImageUtil(util.DockerfileImages([]), self.config) image = 'registry.com/fedora:35' src_path = '/path/to/file' dst_path = Path(tmpdir) / 'dst_dir' dst_path.mkdir() (flexmock(retries).should_receive("run_cmd").with_args([ 'oc', 'image', 'extract', image, '--path', f'{src_path}:{dst_path}' ]).and_raise( subprocess.CalledProcessError(1, ["oc", "..."], output=b'something went wrong'))) with pytest.raises( ExtractionError, match="Image file extraction failed", ): image_util.extract_file_from_image(image=image, src_path=src_path, dst_path=str(dst_path))
def test_get_uncompressed_image_layer_sizes(self, tmpdir): image_util = imageutil.ImageUtil(util.DockerfileImages([]), self.config) path = Path(tmpdir) / 'tarball.tar' manifest_file_content = ( '[{"Config":"62700350851fb36b2e770ba33639e9d111616d39fc63da8845a5e53e9ad013de.json",' '"RepoTags":[],' '"Layers":["92538e92de2938d7c4e279f871107b835bf0c8cc76a5a1655d66855706da18b0.tar"' ',"eb7bf34352ca9ba2fb0218870ac3c47b76d0b1fb7d50543d3ecfa497eca242b0.tar",' '"6da3b8e0475dcc80515944d0cc3f699429248df6b040f8dd7711e681387185e8.tar",' '"07adb74645fe71dec6917e5caca489018edf7ed94f29ac74398eca89c1b9458b.tar"]}]' ).encode('utf-8') config_file_content = ( '{"rootfs": {"type": "layers", "diff_ids": ' '["sha256:92538e92de2938d7c4e279f871107b835bf0c8cc76a5a1655d66855706da18b0", ' '"sha256:eb7bf34352ca9ba2fb0218870ac3c47b76d0b1fb7d50543d3ecfa497eca242b0", ' '"sha256:6da3b8e0475dcc80515944d0cc3f699429248df6b040f8dd7711e681387185e8", ' '"sha256:07adb74645fe71dec6917e5caca489018edf7ed94f29ac74398eca89c1b9458b"]}}' ).encode("utf-8") mock_files = { "92538e92de2938d7c4e279f871107b835bf0c8cc76a5a1655d66855706da18b0.tar": { "content": None, "size": 1, }, "eb7bf34352ca9ba2fb0218870ac3c47b76d0b1fb7d50543d3ecfa497eca242b0.tar": { "content": None, "size": 2, }, "6da3b8e0475dcc80515944d0cc3f699429248df6b040f8dd7711e681387185e8.tar": { "content": None, "size": 3, }, "07adb74645fe71dec6917e5caca489018edf7ed94f29ac74398eca89c1b9458b.tar": { "content": None, "size": 4, }, "manifest.json": { "content": manifest_file_content, "size": len(manifest_file_content), }, "62700350851fb36b2e770ba33639e9d111616d39fc63da8845a5e53e9ad013de.json": { "content": config_file_content, "size": len(config_file_content), }, } mock_tarball(tarball_path=path, files=mock_files) actual_data = image_util.get_uncompressed_image_layer_sizes(path=path) expected_data = [ { "diff_id": "sha256:92538e92de2938d7c4e279f871107b835bf0c8cc76a5a1655d66855706da18b0", # noqa "size": 1, }, { "diff_id": "sha256:eb7bf34352ca9ba2fb0218870ac3c47b76d0b1fb7d50543d3ecfa497eca242b0", # noqa "size": 2, }, { "diff_id": "sha256:6da3b8e0475dcc80515944d0cc3f699429248df6b040f8dd7711e681387185e8", # noqa "size": 3, }, { "diff_id": "sha256:07adb74645fe71dec6917e5caca489018edf7ed94f29ac74398eca89c1b9458b", # noqa "size": 4, }, ] assert actual_data == expected_data
def df_images(): """DockerfileImages instance for testing.""" return util.DockerfileImages(["registry.com/fedora:35"])
def test_base_image_inspect_not_inspectable(self, base_image): """Test that inspecting a non-inspectable base image returns an empty dict.""" image_util = imageutil.ImageUtil(util.DockerfileImages([base_image]), self.config) assert image_util.base_image_inspect() == {}