| package system |
| |
| import ( |
| "net/netip" |
| "testing" |
| |
| "github.com/google/go-cmp/cmp/cmpopts" |
| containertypes "github.com/moby/moby/api/types/container" |
| "github.com/moby/moby/client" |
| "github.com/moby/moby/v2/integration/internal/container" |
| "github.com/moby/moby/v2/internal/testutil" |
| "github.com/moby/moby/v2/internal/testutil/daemon" |
| "gotest.tools/v3/assert" |
| is "gotest.tools/v3/assert/cmp" |
| "gotest.tools/v3/skip" |
| ) |
| |
| func TestDiskUsage(t *testing.T) { |
| skip.If(t, testEnv.DaemonInfo.OSType == "windows") // d.Start fails on Windows with `protocol not available` |
| |
| t.Parallel() |
| |
| ctx := testutil.StartSpan(baseContext, t) |
| |
| d := daemon.New(t) |
| defer d.Cleanup(t) |
| d.Start(t, "--iptables=false", "--ip6tables=false") |
| defer d.Stop(t) |
| apiClient := d.NewClientT(t) |
| |
| var stepDU client.DiskUsageResult |
| for _, step := range []struct { |
| doc string |
| next func(t *testing.T, prev client.DiskUsageResult) client.DiskUsageResult |
| }{ |
| { |
| doc: "empty", |
| next: func(t *testing.T, _ client.DiskUsageResult) client.DiskUsageResult { |
| du, err := apiClient.DiskUsage(ctx, client.DiskUsageOptions{ |
| Images: true, |
| Containers: true, |
| BuildCache: true, |
| Volumes: true, |
| Verbose: true, |
| }) |
| assert.NilError(t, err) |
| |
| assert.DeepEqual(t, du, client.DiskUsageResult{ |
| Containers: client.ContainersDiskUsage{}, |
| Images: client.ImagesDiskUsage{ |
| TotalSize: 0, |
| }, |
| BuildCache: client.BuildCacheDiskUsage{}, |
| Volumes: client.VolumesDiskUsage{}, |
| }) |
| return du |
| }, |
| }, |
| { |
| doc: "after LoadBusybox", |
| next: func(t *testing.T, _ client.DiskUsageResult) client.DiskUsageResult { |
| d.LoadBusybox(ctx, t) |
| |
| du, err := apiClient.DiskUsage(ctx, client.DiskUsageOptions{ |
| Images: true, |
| Containers: true, |
| BuildCache: true, |
| Volumes: true, |
| Verbose: true, |
| }) |
| assert.NilError(t, err) |
| |
| assert.Equal(t, du.Images.ActiveCount, int64(0)) |
| assert.Equal(t, du.Images.TotalCount, int64(1)) |
| |
| assert.Equal(t, du.Images.TotalSize, du.Images.Reclaimable) |
| assert.Assert(t, du.Images.TotalSize > 0) |
| assert.Equal(t, len(du.Images.Items), 1) |
| assert.Equal(t, len(du.Images.Items[0].RepoTags), 1) |
| assert.Check(t, is.Equal(du.Images.Items[0].RepoTags[0], "busybox:latest")) |
| |
| // With a single image, the aggregate image size matches the image item size. |
| assert.Equal(t, du.Images.TotalSize, du.Images.Items[0].Size) |
| |
| return du |
| }, |
| }, |
| { |
| doc: "after container.Run", |
| next: func(t *testing.T, prev client.DiskUsageResult) client.DiskUsageResult { |
| cID := container.Run(ctx, t, apiClient) |
| |
| du, err := apiClient.DiskUsage(ctx, client.DiskUsageOptions{ |
| Images: true, |
| Containers: true, |
| BuildCache: true, |
| Volumes: true, |
| Verbose: true, |
| }) |
| assert.NilError(t, err) |
| |
| assert.Equal(t, du.Containers.ActiveCount, int64(1)) |
| assert.Equal(t, du.Containers.TotalCount, int64(1)) |
| assert.Equal(t, len(du.Containers.Items), 1) |
| assert.Equal(t, len(du.Containers.Items[0].Names), 1) |
| assert.Assert(t, len(prev.Images.Items) > 0) |
| assert.Check(t, du.Containers.Items[0].Created >= prev.Images.Items[0].Created) |
| |
| // Additional container layer could add to the size |
| assert.Check(t, du.Images.TotalSize >= prev.Images.TotalSize) |
| |
| assert.Equal(t, du.Images.ActiveCount, int64(1)) |
| assert.Equal(t, du.Images.TotalCount, int64(1)) |
| assert.Equal(t, du.Images.Reclaimable, int64(0)) |
| assert.Equal(t, len(du.Images.Items), 1) |
| assert.Equal(t, du.Images.Items[0].Containers, prev.Images.Items[0].Containers+1) |
| |
| assert.Check(t, is.Equal(du.Containers.Items[0].ID, cID)) |
| assert.Check(t, is.Equal(du.Containers.Items[0].Image, "busybox")) |
| assert.Check(t, is.Equal(du.Containers.Items[0].ImageID, prev.Images.Items[0].ID)) |
| |
| // ImageManifestDescriptor should NOT be populated. |
| assert.Check(t, is.Nil(du.Containers.Items[0].ImageManifestDescriptor)) |
| |
| return du |
| }, |
| }, |
| } { |
| t.Run(step.doc, func(t *testing.T) { |
| ctx := testutil.StartSpan(ctx, t) |
| stepDU = step.next(t, stepDU) |
| |
| for _, tc := range []struct { |
| doc string |
| options client.DiskUsageOptions |
| expected client.DiskUsageResult |
| }{ |
| { |
| doc: "container types", |
| options: client.DiskUsageOptions{ |
| Containers: true, |
| Verbose: true, |
| }, |
| expected: client.DiskUsageResult{ |
| Containers: stepDU.Containers, |
| Images: client.ImagesDiskUsage{}, |
| BuildCache: client.BuildCacheDiskUsage{}, |
| Volumes: client.VolumesDiskUsage{}, |
| }, |
| }, |
| { |
| doc: "image types", |
| options: client.DiskUsageOptions{ |
| Images: true, |
| Verbose: true, |
| }, |
| expected: client.DiskUsageResult{ |
| Containers: client.ContainersDiskUsage{}, |
| Images: stepDU.Images, |
| BuildCache: client.BuildCacheDiskUsage{}, |
| Volumes: client.VolumesDiskUsage{}, |
| }, |
| }, |
| { |
| doc: "volume types", |
| options: client.DiskUsageOptions{ |
| Volumes: true, |
| Verbose: true, |
| }, |
| expected: client.DiskUsageResult{ |
| Containers: client.ContainersDiskUsage{}, |
| Images: client.ImagesDiskUsage{}, |
| BuildCache: client.BuildCacheDiskUsage{}, |
| Volumes: stepDU.Volumes, |
| }, |
| }, |
| { |
| doc: "build-cache types", |
| options: client.DiskUsageOptions{ |
| BuildCache: true, |
| Verbose: true, |
| }, |
| expected: client.DiskUsageResult{ |
| Containers: client.ContainersDiskUsage{}, |
| Images: client.ImagesDiskUsage{}, |
| BuildCache: stepDU.BuildCache, |
| Volumes: client.VolumesDiskUsage{}, |
| }, |
| }, |
| { |
| doc: "container, volume types", |
| options: client.DiskUsageOptions{ |
| Containers: true, |
| Volumes: true, |
| Verbose: true, |
| }, |
| expected: client.DiskUsageResult{ |
| Containers: stepDU.Containers, |
| Images: client.ImagesDiskUsage{}, |
| BuildCache: client.BuildCacheDiskUsage{}, |
| Volumes: stepDU.Volumes, |
| }, |
| }, |
| { |
| doc: "image, build-cache types", |
| options: client.DiskUsageOptions{ |
| Images: true, |
| BuildCache: true, |
| Verbose: true, |
| }, |
| expected: client.DiskUsageResult{ |
| Containers: client.ContainersDiskUsage{}, |
| Images: stepDU.Images, |
| BuildCache: stepDU.BuildCache, |
| Volumes: client.VolumesDiskUsage{}, |
| }, |
| }, |
| { |
| doc: "container, volume, build-cache types", |
| options: client.DiskUsageOptions{ |
| Containers: true, |
| BuildCache: true, |
| Volumes: true, |
| Verbose: true, |
| }, |
| expected: client.DiskUsageResult{ |
| Containers: stepDU.Containers, |
| Images: client.ImagesDiskUsage{}, |
| BuildCache: stepDU.BuildCache, |
| Volumes: stepDU.Volumes, |
| }, |
| }, |
| { |
| doc: "image, volume, build-cache types", |
| options: client.DiskUsageOptions{ |
| Images: true, |
| BuildCache: true, |
| Volumes: true, |
| Verbose: true, |
| }, |
| expected: client.DiskUsageResult{ |
| Containers: client.ContainersDiskUsage{}, |
| Images: stepDU.Images, |
| BuildCache: stepDU.BuildCache, |
| Volumes: stepDU.Volumes, |
| }, |
| }, |
| { |
| doc: "container, image, volume types", |
| options: client.DiskUsageOptions{ |
| Containers: true, |
| Images: true, |
| Volumes: true, |
| Verbose: true, |
| }, |
| expected: client.DiskUsageResult{ |
| Containers: stepDU.Containers, |
| Images: stepDU.Images, |
| BuildCache: client.BuildCacheDiskUsage{}, |
| Volumes: stepDU.Volumes, |
| }, |
| }, |
| { |
| doc: "container, image, volume, build-cache types", |
| options: client.DiskUsageOptions{ |
| Containers: true, |
| Images: true, |
| BuildCache: true, |
| Volumes: true, |
| Verbose: true, |
| }, |
| expected: client.DiskUsageResult{ |
| Containers: stepDU.Containers, |
| Images: stepDU.Images, |
| BuildCache: stepDU.BuildCache, |
| Volumes: stepDU.Volumes, |
| }, |
| }, |
| } { |
| t.Run(tc.doc, func(t *testing.T) { |
| ctx := testutil.StartSpan(ctx, t) |
| // TODO: Run in parallel once https://github.com/moby/moby/pull/42560 is merged. |
| |
| du, err := apiClient.DiskUsage(ctx, tc.options) |
| assert.NilError(t, err) |
| assert.DeepEqual(t, du, tc.expected, |
| cmpopts.EquateComparable(netip.Addr{}, netip.Prefix{}), |
| cmpopts.IgnoreFields(containertypes.Summary{}, "Status"), |
| ) |
| }) |
| } |
| }) |
| } |
| } |