import 'package:podman/podman.dart'; import 'package:test/test.dart'; import 'support/fake_podman_transport.dart'; void main() { group('PodmanClient image API', () { test('lists images', () async { final transport = FakePodmanTransport() ..enqueue( method: HttpMethod.get, path: '/v5.0.0/libpod/images/json', queryParameters: const >{ 'all': ['false'], }, responseBody: [ { 'Id': 'sha256:abc', 'Repository': 'hello-world', 'Tag': 'latest', 'Digest': 'sha256:def', 'Size': '123 MB', }, ], ); final client = PodmanClient(transport: transport); final images = await client.listImages(); expect(images, hasLength(1)); expect(images.first.id, 'sha256:abc'); expect(images.first.reference, 'hello-world:latest'); transport.expectNoPending(); }); test('pull returns response body', () async { final transport = FakePodmanTransport() ..enqueue( method: HttpMethod.post, path: '/v5.0.0/libpod/images/pull', queryParameters: const >{ 'reference': ['hello-world:latest'], 'quiet': ['true'], }, responseBody: 'pull complete', ); final client = PodmanClient(transport: transport); final output = await client.pull('hello-world:latest', quiet: true); expect(output, 'pull complete'); transport.expectNoPending(); }); test('image exists false on 404', () async { final transport = FakePodmanTransport() ..enqueue( method: HttpMethod.get, path: '/v5.0.0/libpod/images/missing%3Alatest/exists', statusCode: 404, ); final client = PodmanClient(transport: transport); final exists = await client.imageExists('missing:latest'); expect(exists, isFalse); transport.expectNoPending(); }); test('supports remove, tag, and prune', () async { final transport = FakePodmanTransport() ..enqueue( method: HttpMethod.delete, path: '/v5.0.0/libpod/images/hello-world%3Alatest', queryParameters: const >{ 'force': ['true'], }, statusCode: 200, ) ..enqueue( method: HttpMethod.post, path: '/v5.0.0/libpod/images/hello-world%3Alatest/tag', queryParameters: const >{ 'repo': ['local/hello-world'], 'tag': ['test'], }, statusCode: 201, ) ..enqueue( method: HttpMethod.post, path: '/v5.0.0/libpod/images/prune', queryParameters: const >{ 'all': ['true'], }, statusCode: 200, responseBody: const [], ); final client = PodmanClient(transport: transport); await client.removeImage('hello-world:latest', force: true); await client.tagImage('hello-world:latest', 'local/hello-world:test'); await client.pruneImages(all: true); transport.expectNoPending(); }); test( 'supports inspect, history, tree, push, load/import/export, and batch remove', () async { final archiveBytes = [1, 2, 3, 4]; final exportBytes = [9, 8, 7]; final transport = FakePodmanTransport() ..enqueue( method: HttpMethod.get, path: '/v5.0.0/libpod/images/hello-world%3Alatest/json', responseBody: const { 'Id': 'sha256:abc', 'Digest': 'sha256:def', 'RepoTags': ['hello-world:latest'], 'RepoDigests': ['hello-world@sha256:def'], 'Created': '2026-04-01T00:00:00Z', 'Size': 1234, }, ) ..enqueue( method: HttpMethod.get, path: '/v5.0.0/libpod/images/hello-world%3Alatest/history', responseBody: [ { 'Id': 'sha256:layer1', 'Created': 1712361600, 'CreatedBy': '/bin/sh -c echo hi', 'Tags': ['hello-world:latest'], 'Size': 42, 'Comment': 'base layer', }, ], ) ..enqueue( method: HttpMethod.get, path: '/v5.0.0/libpod/images/hello-world%3Alatest/tree', queryParameters: const >{ 'whatrequires': ['true'], }, responseBody: const { 'Tree': 'hello-world:latest\n└── scratch', }, ) ..enqueue( method: HttpMethod.post, path: '/v5.0.0/libpod/images/hello-world%3Alatest/push', queryParameters: const >{ 'destination': ['quay.io/groupware/hello-world:latest'], 'retry': ['3'], 'retryDelay': ['1s'], 'tlsVerify': ['false'], 'quiet': ['false'], }, responseBody: '{"stream":"copying"}\n' '{"manifestdigest":"sha256:push"}\n', ) ..enqueue( method: HttpMethod.post, path: '/v5.0.0/libpod/images/load', body: archiveBytes, responseBody: const { 'Names': ['hello-world:latest'], }, ) ..enqueue( method: HttpMethod.post, path: '/v5.0.0/libpod/images/load', queryParameters: const >{ 'path': ['/tmp/image.tar'], }, responseBody: const { 'Names': ['hello-world:latest'], }, ) ..enqueue( method: HttpMethod.post, path: '/v5.0.0/libpod/images/import', queryParameters: const >{ 'reference': ['quay.io/groupware/imported:latest'], 'message': ['import image'], 'changes': ['CMD ["/bin/sh"]'], }, body: archiveBytes, responseBody: const {'Id': 'sha256:imported'}, ) ..enqueue( method: HttpMethod.get, path: '/v5.0.0/libpod/images/hello-world%3Alatest/get', queryParameters: const >{ 'compress': ['true'], 'format': ['docker-archive'], }, responseBody: exportBytes, ) ..enqueue( method: HttpMethod.get, path: '/v5.0.0/libpod/images/export', queryParameters: const >{ 'format': ['docker-archive'], 'references': ['hello-world:latest', 'busybox:latest'], }, responseBody: exportBytes, ) ..enqueue( method: HttpMethod.delete, path: '/v5.0.0/libpod/images/remove', queryParameters: const >{ 'images': ['hello-world:latest'], 'ignore': ['true'], }, responseBody: const { 'Deleted': ['sha256:def'], 'Untagged': ['hello-world:latest'], 'ExitCode': 0, 'Errors': [], }, ); final client = PodmanClient(transport: transport); final details = await client.inspectImage('hello-world:latest'); expect(details.id, 'sha256:abc'); final history = await client.imageHistory('hello-world:latest'); expect(history, hasLength(1)); expect(history.first.id, 'sha256:layer1'); final tree = await client.imageTree( 'hello-world:latest', whatRequires: true, ); expect(tree.tree, contains('hello-world:latest')); final pushEvents = await client.pushImage( 'hello-world:latest', options: const ImagePushOptions( destination: 'quay.io/groupware/hello-world:latest', retry: 3, retryDelay: '1s', tlsVerify: false, quiet: false, ), ); expect(pushEvents, hasLength(2)); expect(pushEvents.last.manifestDigest, 'sha256:push'); final loaded = await client.loadImages(archiveBytes); expect(loaded.names, contains('hello-world:latest')); final loadedFromPath = await client.loadImagesFromPath( '/tmp/image.tar', ); expect(loadedFromPath.names, contains('hello-world:latest')); final imported = await client.importImage( options: const ImageImportOptions( reference: 'quay.io/groupware/imported:latest', message: 'import image', changes: ['CMD ["/bin/sh"]'], ), archiveBytes: archiveBytes, ); expect(imported.id, 'sha256:imported'); final exported = await client.exportImage( 'hello-world:latest', options: const ImageExportOptions( compress: true, format: 'docker-archive', ), ); expect(exported, exportBytes); final exportedMulti = await client.exportImages(const [ 'hello-world:latest', 'busybox:latest', ], options: const ImageExportOptions(format: 'docker-archive')); expect(exportedMulti, exportBytes); final removed = await client.removeImages( const ImageRemoveOptions( images: ['hello-world:latest'], ignore: true, ), ); expect(removed.deleted, contains('sha256:def')); transport.expectNoPending(); }, ); }); }