203 lines
6.7 KiB
Dart
203 lines
6.7 KiB
Dart
import 'package:podman/podman.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
import 'support/fake_podman_transport.dart';
|
|
|
|
void main() {
|
|
group('PodmanClient system API', () {
|
|
test('parses version output', () async {
|
|
final transport = FakePodmanTransport()
|
|
..enqueue(
|
|
method: HttpMethod.get,
|
|
path: '/v5.0.0/libpod/version',
|
|
responseBody: <String, Object?>{
|
|
'Client': <String, Object?>{'Version': '5.2.2'},
|
|
'Server': <String, Object?>{'Version': '5.2.1'},
|
|
},
|
|
);
|
|
|
|
final client = PodmanClient(transport: transport);
|
|
final version = await client.version();
|
|
|
|
expect(version.clientVersion, '5.2.2');
|
|
expect(version.serverVersion, '5.2.1');
|
|
transport.expectNoPending();
|
|
});
|
|
|
|
test('parses info output', () async {
|
|
final transport = FakePodmanTransport()
|
|
..enqueue(
|
|
method: HttpMethod.get,
|
|
path: '/v5.0.0/libpod/info',
|
|
responseBody: <String, Object?>{
|
|
'host': <String, Object?>{'os': 'linux', 'arch': 'amd64'},
|
|
},
|
|
);
|
|
|
|
final client = PodmanClient(transport: transport);
|
|
final info = await client.info();
|
|
|
|
expect(info.hostOs, 'linux');
|
|
expect(info.hostArch, 'amd64');
|
|
transport.expectNoPending();
|
|
});
|
|
|
|
test('supports system df/check/prune', () async {
|
|
final transport = FakePodmanTransport()
|
|
..enqueue(
|
|
method: HttpMethod.get,
|
|
path: '/v5.0.0/libpod/system/df',
|
|
responseBody: const <String, Object?>{
|
|
'ImagesSize': 12345,
|
|
'Images': <Object?>[
|
|
<String, Object?>{
|
|
'Repository': 'docker.io/library/hello-world',
|
|
'Tag': 'latest',
|
|
'ImageID': 'sha256:image1',
|
|
'Created': '2026-01-01T00:00:00Z',
|
|
'Size': 111,
|
|
'SharedSize': 0,
|
|
'UniqueSize': 111,
|
|
'Containers': 1,
|
|
},
|
|
],
|
|
'Containers': <Object?>[
|
|
<String, Object?>{
|
|
'ContainerID': 'container-1',
|
|
'Image': 'docker.io/library/hello-world:latest',
|
|
'Command': <String>['/hello'],
|
|
'LocalVolumes': 0,
|
|
'Size': 222,
|
|
'RWSize': 12,
|
|
'Created': '2026-01-01T00:01:00Z',
|
|
'Status': 'exited',
|
|
'Names': 'hello',
|
|
},
|
|
],
|
|
'Volumes': <Object?>[
|
|
<String, Object?>{
|
|
'VolumeName': 'gv-storage',
|
|
'Links': 1,
|
|
'Size': 333,
|
|
'ReclaimableSize': 111,
|
|
},
|
|
],
|
|
},
|
|
)
|
|
..enqueue(
|
|
method: HttpMethod.post,
|
|
path: '/v5.0.0/libpod/system/check',
|
|
queryParameters: const <String, List<String>>{
|
|
'quick': <String>['true'],
|
|
'repair': <String>['true'],
|
|
'repair_lossy': <String>['true'],
|
|
'unreferenced_layer_max_age': <String>['12h'],
|
|
},
|
|
responseBody: const <String, Object?>{
|
|
'Errors': true,
|
|
'Layers': <String, Object?>{
|
|
'layer-1': <String>['missing digest'],
|
|
},
|
|
'ROLayers': <String, Object?>{},
|
|
'RemovedLayers': <String>['layer-old'],
|
|
'Images': <String, Object?>{
|
|
'image-1': <String>['dangling data'],
|
|
},
|
|
'ROImages': <String, Object?>{},
|
|
'RemovedImages': <String, Object?>{
|
|
'image-1': <String>['localhost/image:old'],
|
|
},
|
|
'Containers': <String, Object?>{
|
|
'ctr-1': <String>['broken mount'],
|
|
},
|
|
'RemovedContainers': <String, String>{'ctr-1': 'old-container'},
|
|
},
|
|
)
|
|
..enqueue(
|
|
method: HttpMethod.post,
|
|
path: '/v5.0.0/libpod/system/prune',
|
|
queryParameters: const <String, List<String>>{
|
|
'all': <String>['true'],
|
|
'volumes': <String>['true'],
|
|
'external': <String>['true'],
|
|
'build': <String>['true'],
|
|
'filters': <String>['{"label":["managed=true"]}'],
|
|
},
|
|
responseBody: const <String, Object?>{
|
|
'PodPruneReport': <Object?>[
|
|
<String, Object?>{'Id': 'pod-1'},
|
|
],
|
|
'ContainerPruneReports': <Object?>[
|
|
<String, Object?>{'Id': 'ctr-1', 'Size': 1024},
|
|
],
|
|
'ImagePruneReports': <Object?>[
|
|
<String, Object?>{'Id': 'img-1', 'Size': 2048},
|
|
],
|
|
'NetworkPruneReports': <Object?>[
|
|
<String, Object?>{'Name': 'net-1'},
|
|
],
|
|
'VolumePruneReports': <Object?>[
|
|
<String, Object?>{'Id': 'vol-1', 'Size': 4096},
|
|
],
|
|
'ReclaimedSpace': 8192,
|
|
},
|
|
);
|
|
|
|
final client = PodmanClient(transport: transport);
|
|
|
|
final df = await client.systemDf();
|
|
expect(df.imagesSize, 12345);
|
|
expect(df.images, hasLength(1));
|
|
expect(df.containers, hasLength(1));
|
|
expect(df.volumes, hasLength(1));
|
|
expect(df.images.first.imageId, 'sha256:image1');
|
|
expect(df.containers.first.containerId, 'container-1');
|
|
expect(df.volumes.first.volumeName, 'gv-storage');
|
|
|
|
final check = await client.systemCheck(
|
|
options: const SystemCheckOptions(
|
|
quick: true,
|
|
repair: true,
|
|
repairLossy: true,
|
|
unreferencedLayerMaxAge: '12h',
|
|
),
|
|
);
|
|
expect(check.errors, isTrue);
|
|
expect(check.layers['layer-1'], contains('missing digest'));
|
|
expect(check.removedContainers['ctr-1'], 'old-container');
|
|
|
|
final prune = await client.systemPrune(
|
|
options: const SystemPruneOptions(
|
|
all: true,
|
|
volumes: true,
|
|
external: true,
|
|
build: true,
|
|
filters: <String, List<String>>{
|
|
'label': <String>['managed=true'],
|
|
},
|
|
),
|
|
);
|
|
expect(prune.podIds, contains('pod-1'));
|
|
expect(prune.containerIds, contains('ctr-1'));
|
|
expect(prune.imageIds, contains('img-1'));
|
|
expect(prune.networkNames, contains('net-1'));
|
|
expect(prune.volumeIds, contains('vol-1'));
|
|
expect(prune.reclaimedSpace, 8192);
|
|
|
|
transport.expectNoPending();
|
|
});
|
|
|
|
test('throws parse exception on invalid JSON', () async {
|
|
final transport = FakePodmanTransport()
|
|
..enqueue(
|
|
method: HttpMethod.get,
|
|
path: '/v5.0.0/libpod/version',
|
|
responseBody: '{invalid-json',
|
|
);
|
|
|
|
final client = PodmanClient(transport: transport);
|
|
|
|
await expectLater(client.version(), throwsA(isA<PodmanParseException>()));
|
|
});
|
|
});
|
|
}
|