//go:build !remote package libimage import ( "context" "os" "path/filepath" "testing" "github.com/containers/common/pkg/config" "github.com/containers/image/v5/pkg/compression" "github.com/containers/image/v5/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestPush(t *testing.T) { runtime := testNewRuntime(t) ctx := context.Background() // Prefetch alpine. pullOptions := &PullOptions{} pullOptions.Writer = os.Stdout _, err := runtime.Pull(ctx, "quay.io/libpod/alpine:latest", config.PullPolicyAlways, pullOptions) require.NoError(t, err) pushOptions := &PushOptions{} pushOptions.Writer = os.Stdout workdir := t.TempDir() for _, test := range []struct { source string destination string expectError bool }{ {"alpine", "dir:" + workdir + "/dir", false}, {"alpine", "oci:" + workdir + "/oci", false}, {"alpine", "oci-archive:" + workdir + "/oci-archive", false}, {"alpine", "docker-archive:" + workdir + "/docker-archive", false}, {"alpine", "containers-storage:localhost/another:alpine", false}, } { _, err := runtime.Push(ctx, test.source, test.destination, pushOptions) if test.expectError { require.Error(t, err, "%v", test) continue } require.NoError(t, err, "%v", test) pulledImages, err := runtime.Pull(ctx, test.destination, config.PullPolicyAlways, pullOptions) require.NoError(t, err, "%v", test) require.Len(t, pulledImages, 1, "%v", test) } // Now there should only be two images: alpine in Docker format and // alpine in OCI format. listOptions := ListImagesOptions{SetListData: true} listedImages, err := runtime.ListImages(ctx, &listOptions) require.NoError(t, err, "error listing images") require.Len(t, listedImages, 2, "there should only be two images (alpine in Docke/OCI)") for _, image := range listedImages { require.NotNil(t, image.ListData.IsDangling, "IsDangling should be set") } // And now remove all of them. rmReports, rmErrors := runtime.RemoveImages(ctx, nil, nil) require.Len(t, rmErrors, 0) require.Len(t, rmReports, 2) for i, image := range listedImages { require.Equal(t, image.ID(), rmReports[i].ID) require.True(t, rmReports[i].Removed) } } func TestPushOtherPlatform(t *testing.T) { runtime := testNewRuntime(t) ctx := context.Background() // Prefetch alpine. pullOptions := &PullOptions{} pullOptions.Writer = os.Stdout pullOptions.Architecture = "arm64" pulledImages, err := runtime.Pull(ctx, "quay.io/libpod/alpine:latest", config.PullPolicyAlways, pullOptions) require.NoError(t, err) require.Len(t, pulledImages, 1) data, err := pulledImages[0].Inspect(ctx, nil) require.NoError(t, err) require.Equal(t, "arm64", data.Architecture) pushOptions := &PushOptions{} pushOptions.Writer = os.Stdout tmp, err := os.CreateTemp(t.TempDir(), "") require.NoError(t, err) tmp.Close() _, err = runtime.Push(ctx, "quay.io/libpod/alpine:latest", "docker-archive:"+tmp.Name(), pushOptions) require.NoError(t, err) } func TestPushWithForceCompression(t *testing.T) { runtime := testNewRuntime(t) ctx := context.Background() // Prefetch alpine. pullOptions := &PullOptions{} pullOptions.Writer = os.Stdout pullOptions.Architecture = "arm64" pulledImages, err := runtime.Pull(ctx, "quay.io/libpod/alpine:latest", config.PullPolicyAlways, pullOptions) require.NoError(t, err) require.Len(t, pulledImages, 1) data, err := pulledImages[0].Inspect(ctx, nil) require.NoError(t, err) require.Equal(t, "arm64", data.Architecture) // Push newly pulled alpine to directory with uncompressed blobs pushOptions := &PushOptions{} pushOptions.SystemContext = &types.SystemContext{} pushOptions.SystemContext.DirForceDecompress = true pushOptions.Writer = os.Stdout dirDest := t.TempDir() _, err = runtime.Push(ctx, "quay.io/libpod/alpine:latest", "dir:"+dirDest, pushOptions) require.NoError(t, err) // Pull uncompressed alpine from `dir:dirDest` as source. pullOptions = &PullOptions{} pullOptions.Writer = os.Stdout pullOptions.Architecture = "arm64" pulledImages, err = runtime.Pull(ctx, "dir:"+dirDest, config.PullPolicyAlways, pullOptions) require.NoError(t, err) require.Len(t, pulledImages, 1) // create `oci` image from uncompressed alpine. pushOptions = &PushOptions{} pushOptions.OciAcceptUncompressedLayers = true pushOptions.Writer = os.Stdout ociDest := t.TempDir() _, err = runtime.Push(ctx, "quay.io/libpod/alpine:latest", "oci:"+ociDest, pushOptions) require.NoError(t, err) // blobs from first push entries, err := os.ReadDir(filepath.Join(ociDest, "blobs", "sha256")) require.NoError(t, err) blobsFirstPush := []string{} for _, e := range entries { blobsFirstPush = append(blobsFirstPush, e.Name()) } // Note: Compression is changed from `uncompressed` to `Gzip` but blobs // should still be same since `ForceCompressionFormat` is `false`. pushOptions = &PushOptions{} pushOptions.Writer = os.Stdout pushOptions.CompressionFormat = &compression.Gzip pushOptions.ForceCompressionFormat = false _, err = runtime.Push(ctx, "quay.io/libpod/alpine:latest", "oci:"+ociDest, pushOptions) require.NoError(t, err) // blobs from second push entries, err = os.ReadDir(filepath.Join(ociDest, "blobs", "sha256")) require.NoError(t, err) blobsSecondPush := []string{} for _, e := range entries { blobsSecondPush = append(blobsSecondPush, e.Name()) } // All blobs of first push should be equivalent to blobs of // second push since same compression was used assert.Equal(t, blobsSecondPush, blobsFirstPush) // Note: Compression is changed from `uncompressed` to `Gzip` but blobs // should still be same since `ForceCompressionFormat` is `false`. pushOptions = &PushOptions{} pushOptions.Writer = os.Stdout pushOptions.CompressionFormat = &compression.Gzip pushOptions.ForceCompressionFormat = true _, err = runtime.Push(ctx, "quay.io/libpod/alpine:latest", "oci:"+ociDest, pushOptions) require.NoError(t, err) // collect blobs from third push entries, err = os.ReadDir(filepath.Join(ociDest, "blobs", "sha256")) require.NoError(t, err) blobsThirdPush := []string{} for _, e := range entries { blobsThirdPush = append(blobsThirdPush, e.Name()) } // All blobs of third push should not be equivalent to blobs of // first push since new compression was used and `ForceCompressionFormat` // was `true`. assert.NotEqual(t, blobsThirdPush, blobsFirstPush) }