mirror of
https://github.com/moby/moby.git
synced 2026-01-11 10:41:43 +00:00
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com> Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
142 lines
4.0 KiB
Go
142 lines
4.0 KiB
Go
package image
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"testing"
|
|
|
|
"github.com/containerd/platforms"
|
|
buildtypes "github.com/moby/moby/api/types/build"
|
|
"github.com/moby/moby/client"
|
|
build "github.com/moby/moby/v2/integration/internal/build"
|
|
"github.com/moby/moby/v2/internal/testutil"
|
|
"github.com/moby/moby/v2/internal/testutil/fakecontext"
|
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
"gotest.tools/v3/assert"
|
|
is "gotest.tools/v3/assert/cmp"
|
|
"gotest.tools/v3/skip"
|
|
)
|
|
|
|
func TestAPIImagesHistory(t *testing.T) {
|
|
ctx := setupTest(t)
|
|
client := testEnv.APIClient()
|
|
|
|
dockerfile := "FROM busybox\nENV FOO bar"
|
|
|
|
imgID := build.Do(ctx, t, client, fakecontext.New(t, t.TempDir(), fakecontext.WithDockerfile(dockerfile)))
|
|
|
|
res, err := client.ImageHistory(ctx, imgID)
|
|
assert.NilError(t, err)
|
|
|
|
assert.Assert(t, len(res.Items) != 0)
|
|
|
|
var found bool
|
|
for _, imageLayer := range res.Items {
|
|
if imageLayer.ID == imgID {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
assert.Assert(t, found)
|
|
}
|
|
|
|
// TestAPIImageHistoryCrossPlatform tests the image history functionality
|
|
// when dealing with cross-platform image builds.
|
|
// This is a regression test for https://github.com/moby/moby/issues/50851
|
|
// where `docker history` fails with "snapshot does not exist" error for
|
|
// images built for non-native platforms.
|
|
func TestAPIImageHistoryCrossPlatform(t *testing.T) {
|
|
skip.If(t, testEnv.DaemonInfo.OSType == "windows")
|
|
|
|
ctx := setupTest(t)
|
|
apiClient := testEnv.APIClient()
|
|
|
|
// Determine the non-native platform to use for testing
|
|
nonNativePlatform := ocispec.Platform{OS: testEnv.DaemonInfo.OSType, Architecture: "amd64"}
|
|
if testEnv.DaemonInfo.Architecture == "amd64" {
|
|
nonNativePlatform = ocispec.Platform{OS: testEnv.DaemonInfo.OSType, Architecture: "arm64"}
|
|
}
|
|
|
|
// We need to pull the image for the non-native platform
|
|
// TODO: Make sure we have a multi-platform frozen image we could use
|
|
pullImageForPlatform(t, ctx, apiClient, "alpine", nonNativePlatform)
|
|
|
|
dockerfile := "FROM alpine\nRUN true"
|
|
|
|
buildCtx := fakecontext.New(t, t.TempDir(), fakecontext.WithDockerfile(dockerfile))
|
|
defer buildCtx.Close()
|
|
|
|
// Build the image for a non-native platform
|
|
resp, err := apiClient.ImageBuild(ctx, buildCtx.AsTarReader(t), client.ImageBuildOptions{
|
|
Version: buildtypes.BuilderBuildKit,
|
|
Tags: []string{"cross-platform-test"},
|
|
Platform: platforms.FormatAll(nonNativePlatform),
|
|
})
|
|
assert.NilError(t, err)
|
|
defer resp.Body.Close()
|
|
|
|
imgID := build.GetImageIDFromBody(t, resp.Body)
|
|
t.Cleanup(func() {
|
|
apiClient.ImageRemove(ctx, imgID, client.ImageRemoveOptions{Force: true})
|
|
})
|
|
|
|
testCases := []struct {
|
|
name string
|
|
imageRef string
|
|
options []client.ImageHistoryOption
|
|
}{
|
|
{
|
|
name: "without explicit platform",
|
|
imageRef: imgID,
|
|
options: nil,
|
|
},
|
|
{
|
|
name: "with explicit platform",
|
|
imageRef: imgID,
|
|
options: []client.ImageHistoryOption{client.ImageHistoryWithPlatform(nonNativePlatform)},
|
|
},
|
|
{
|
|
name: "using image reference",
|
|
imageRef: "cross-platform-test",
|
|
options: nil,
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
ctx := testutil.StartSpan(ctx, t)
|
|
|
|
res, err := apiClient.ImageHistory(ctx, tc.imageRef, tc.options...)
|
|
|
|
assert.NilError(t, err)
|
|
found := false
|
|
for _, layer := range res.Items {
|
|
if layer.ID == imgID {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
assert.Assert(t, found, "History should contain the built image ID")
|
|
assert.Assert(t, is.Len(res.Items, 3))
|
|
|
|
for i, layer := range res.Items {
|
|
assert.Assert(t, layer.Size >= 0, "Layer %d should not have negative size", i)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func pullImageForPlatform(t *testing.T, ctx context.Context, apiClient client.APIClient, ref string, platform ocispec.Platform) {
|
|
pullResp, err := apiClient.ImagePull(ctx, ref, client.ImagePullOptions{Platform: platforms.FormatAll(platform)})
|
|
assert.NilError(t, err)
|
|
_, _ = io.Copy(io.Discard, pullResp)
|
|
|
|
_, err = apiClient.ImageInspect(ctx, ref)
|
|
assert.NilError(t, err)
|
|
|
|
t.Cleanup(func() {
|
|
_, _ = apiClient.ImageRemove(ctx, ref, client.ImageRemoveOptions{Force: true})
|
|
})
|
|
}
|