summaryrefslogtreecommitdiffstats
path: root/pkg/v1/tarball/layer_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/v1/tarball/layer_test.go')
-rw-r--r--pkg/v1/tarball/layer_test.go381
1 files changed, 381 insertions, 0 deletions
diff --git a/pkg/v1/tarball/layer_test.go b/pkg/v1/tarball/layer_test.go
new file mode 100644
index 0000000..5d93360
--- /dev/null
+++ b/pkg/v1/tarball/layer_test.go
@@ -0,0 +1,381 @@
+// Copyright 2018 Google LLC All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package tarball
+
+import (
+ "bytes"
+ "compress/gzip"
+ "io"
+ "os"
+ "testing"
+
+ "github.com/containerd/stargz-snapshotter/estargz"
+ "github.com/google/go-containerregistry/internal/compare"
+ "github.com/google/go-containerregistry/pkg/compression"
+ v1 "github.com/google/go-containerregistry/pkg/v1"
+ "github.com/google/go-containerregistry/pkg/v1/types"
+ "github.com/google/go-containerregistry/pkg/v1/validate"
+)
+
+func TestLayerFromFile(t *testing.T) {
+ setupFixtures(t)
+ defer teardownFixtures(t)
+
+ tarLayer, err := LayerFromFile("testdata/content.tar")
+ if err != nil {
+ t.Fatalf("Unable to create layer from tar file: %v", err)
+ }
+
+ tarGzLayer, err := LayerFromFile("gzip_content.tgz")
+ if err != nil {
+ t.Fatalf("Unable to create layer from compressed tar file: %v", err)
+ }
+
+ tarZstdLayer, err := LayerFromFile("zstd_content.tar.zst")
+ if err != nil {
+ t.Fatalf("Unable to create layer from compressed tar file: %v", err)
+ }
+
+ if err := compare.Layers(tarLayer, tarGzLayer); err != nil {
+ t.Errorf("compare.Layers: %v", err)
+ }
+
+ if err := compare.Layers(tarLayer, tarZstdLayer); err != nil {
+ t.Errorf("compare.Layers: %v", err)
+ }
+
+ if err := validate.Layer(tarLayer); err != nil {
+ t.Errorf("validate.Layer(tarLayer): %v", err)
+ }
+
+ if err := validate.Layer(tarGzLayer); err != nil {
+ t.Errorf("validate.Layer(tarGzLayer): %v", err)
+ }
+
+ if err := validate.Layer(tarZstdLayer); err != nil {
+ t.Errorf("validate.Layer(tarZstdLayer): %v", err)
+ }
+
+ getTestDigest := func(testName string, opts ...LayerOption) v1.Hash {
+ layer, err := LayerFromFile("testdata/content.tar", opts...)
+ if err != nil {
+ t.Fatalf("Unable to create layer with '%s' compression from tar file: %v", testName, err)
+ }
+
+ digest, err := layer.Digest()
+ if err != nil {
+ t.Fatalf("Unable to generate digest with '%s' compression: %v", testName, err)
+ }
+
+ return digest
+ }
+
+ defaultDigest := getTestDigest("Gzip Default", WithCompressionLevel(gzip.DefaultCompression))
+ speedDigest := getTestDigest("Gzip BestSpeed", WithCompressionLevel(gzip.BestSpeed))
+ zstdDigest := getTestDigest("Zstd Default", WithCompression(compression.ZStd))
+ zstdDigest1 := getTestDigest("Zstd BestSpeed", WithCompression(compression.ZStd), WithCompressionLevel(1))
+
+ if defaultDigest.String() == speedDigest.String() {
+ t.Errorf("expected digests to differ: %s", defaultDigest.String())
+ }
+
+ if defaultDigest.String() == zstdDigest.String() {
+ t.Errorf("expected digests to differ: %s", defaultDigest.String())
+ }
+
+ if defaultDigest.String() == zstdDigest1.String() {
+ t.Errorf("expected digests to differ: %s", defaultDigest.String())
+ }
+}
+
+func TestLayerFromFileEstargz(t *testing.T) {
+ setupFixtures(t)
+ defer teardownFixtures(t)
+
+ tarLayer, err := LayerFromFile("testdata/content.tar", WithEstargz)
+ if err != nil {
+ t.Fatalf("Unable to create layer from tar file: %v", err)
+ }
+
+ if err := validate.Layer(tarLayer); err != nil {
+ t.Errorf("validate.Layer(tarLayer): %v", err)
+ }
+
+ tarLayerDefaultCompression, err := LayerFromFile("testdata/content.tar", WithEstargz, WithCompressionLevel(gzip.DefaultCompression))
+ if err != nil {
+ t.Fatalf("Unable to create layer with 'Default' compression from tar file: %v", err)
+ }
+ descriptorDefaultCompression, err := tarLayerDefaultCompression.(*layer).Descriptor()
+ if err != nil {
+ t.Fatalf("Descriptor() = %v", err)
+ } else if len(descriptorDefaultCompression.Annotations) != 1 {
+ t.Errorf("Annotations = %#v, wanted 1 annotation", descriptorDefaultCompression.Annotations)
+ }
+
+ defaultDigest, err := tarLayerDefaultCompression.Digest()
+ if err != nil {
+ t.Fatal("Unable to generate digest with 'Default' compression", err)
+ }
+
+ tarLayerSpeedCompression, err := LayerFromFile("testdata/content.tar", WithEstargz, WithCompressionLevel(gzip.BestSpeed))
+ if err != nil {
+ t.Fatalf("Unable to create layer with 'BestSpeed' compression from tar file: %v", err)
+ }
+ descriptorSpeedCompression, err := tarLayerSpeedCompression.(*layer).Descriptor()
+ if err != nil {
+ t.Fatalf("Descriptor() = %v", err)
+ } else if len(descriptorSpeedCompression.Annotations) != 1 {
+ t.Errorf("Annotations = %#v, wanted 1 annotation", descriptorSpeedCompression.Annotations)
+ }
+
+ speedDigest, err := tarLayerSpeedCompression.Digest()
+ if err != nil {
+ t.Fatal("Unable to generate digest with 'BestSpeed' compression", err)
+ }
+
+ if defaultDigest.String() == speedDigest.String() {
+ t.Errorf("expected digests to differ: %s", defaultDigest.String())
+ }
+
+ if descriptorDefaultCompression.Annotations[estargz.TOCJSONDigestAnnotation] == descriptorSpeedCompression.Annotations[estargz.TOCJSONDigestAnnotation] {
+ t.Errorf("wanted different toc digests got default: %s, speed: %s",
+ descriptorDefaultCompression.Annotations[estargz.TOCJSONDigestAnnotation],
+ descriptorSpeedCompression.Annotations[estargz.TOCJSONDigestAnnotation])
+ }
+
+ tarLayerPrioritizedFiles, err := LayerFromFile("testdata/content.tar",
+ WithEstargz,
+ // We compare with default, so pass for apples-to-apples comparison.
+ WithCompressionLevel(gzip.DefaultCompression),
+ // By passing a list of priority files, we expect the layer to be different.
+ WithEstargzOptions(estargz.WithPrioritizedFiles([]string{
+ "./bat",
+ })))
+ if err != nil {
+ t.Fatalf("Unable to create layer with prioritized files from tar file: %v", err)
+ }
+ descriptorPrioritizedFiles, err := tarLayerPrioritizedFiles.(*layer).Descriptor()
+ if err != nil {
+ t.Fatalf("Descriptor() = %v", err)
+ } else if len(descriptorPrioritizedFiles.Annotations) != 1 {
+ t.Errorf("Annotations = %#v, wanted 1 annotation", descriptorPrioritizedFiles.Annotations)
+ }
+
+ prioritizedDigest, err := tarLayerPrioritizedFiles.Digest()
+ if err != nil {
+ t.Fatal("Unable to generate digest with prioritized files", err)
+ }
+
+ if defaultDigest.String() == prioritizedDigest.String() {
+ t.Errorf("expected digests to differ: %s", defaultDigest.String())
+ }
+
+ if descriptorDefaultCompression.Annotations[estargz.TOCJSONDigestAnnotation] == descriptorPrioritizedFiles.Annotations[estargz.TOCJSONDigestAnnotation] {
+ t.Errorf("wanted different toc digests got default: %s, prioritized: %s",
+ descriptorDefaultCompression.Annotations[estargz.TOCJSONDigestAnnotation],
+ descriptorPrioritizedFiles.Annotations[estargz.TOCJSONDigestAnnotation])
+ }
+}
+
+func TestLayerFromOpenerReader(t *testing.T) {
+ setupFixtures(t)
+ defer teardownFixtures(t)
+
+ ucBytes, err := os.ReadFile("testdata/content.tar")
+ if err != nil {
+ t.Fatalf("Unable to read tar file: %v", err)
+ }
+ count := 0
+ ucOpener := func() (io.ReadCloser, error) {
+ count++
+ return io.NopCloser(bytes.NewReader(ucBytes)), nil
+ }
+ tarLayer, err := LayerFromOpener(ucOpener, WithCompressedCaching)
+ if err != nil {
+ t.Fatal("Unable to create layer from tar file:", err)
+ }
+ for i := 0; i < 10; i++ {
+ tarLayer.Compressed()
+ }
+
+ // Store the count and reset the counter.
+ cachedCount := count
+ count = 0
+
+ tarLayer, err = LayerFromOpener(ucOpener)
+ if err != nil {
+ t.Fatal("Unable to create layer from tar file:", err)
+ }
+ for i := 0; i < 10; i++ {
+ tarLayer.Compressed()
+ }
+
+ // We expect three calls: gzip sniff, diffid computation, cached compression
+ if cachedCount != 3 {
+ t.Errorf("cached count = %d, wanted %d", cachedCount, 3)
+ }
+ if cachedCount+10 != count {
+ t.Errorf("count = %d, wanted %d", count, cachedCount+10)
+ }
+
+ gzBytes, err := os.ReadFile("gzip_content.tgz")
+ if err != nil {
+ t.Fatalf("Unable to read tar file: %v", err)
+ }
+ gzOpener := func() (io.ReadCloser, error) {
+ return io.NopCloser(bytes.NewReader(gzBytes)), nil
+ }
+ tarGzLayer, err := LayerFromOpener(gzOpener)
+ if err != nil {
+ t.Fatalf("Unable to create layer from tar file: %v", err)
+ }
+
+ if err := compare.Layers(tarLayer, tarGzLayer); err != nil {
+ t.Errorf("compare.Layers: %v", err)
+ }
+
+ zstdBytes, err := os.ReadFile("zstd_content.tar.zst")
+ if err != nil {
+ t.Fatalf("Unable to read tar file: %v", err)
+ }
+ zstdOpener := func() (io.ReadCloser, error) {
+ return io.NopCloser(bytes.NewReader(zstdBytes)), nil
+ }
+ tarZstdLayer, err := LayerFromOpener(zstdOpener)
+ if err != nil {
+ t.Fatalf("Unable to create layer from tar file: %v", err)
+ }
+
+ if err := compare.Layers(tarLayer, tarZstdLayer); err != nil {
+ t.Errorf("compare.Layers: %v", err)
+ }
+}
+
+func TestWithMediaType(t *testing.T) {
+ setupFixtures(t)
+ defer teardownFixtures(t)
+
+ l, err := LayerFromFile("testdata/content.tar")
+ if err != nil {
+ t.Fatalf("Unable to create layer from tar file: %v", err)
+ }
+ got, err := l.MediaType()
+ if err != nil {
+ t.Fatalf("MediaType: %v", err)
+ }
+ if want := types.DockerLayer; got != want {
+ t.Errorf("got %v, want %v", got, want)
+ }
+
+ l, err = LayerFromFile("testdata/content.tar", WithMediaType(types.OCILayer))
+ if err != nil {
+ t.Fatalf("Unable to create layer from tar file: %v", err)
+ }
+ got, err = l.MediaType()
+ if err != nil {
+ t.Fatalf("MediaType: %v", err)
+ }
+ if want := types.OCILayer; got != want {
+ t.Errorf("got %v, want %v", got, want)
+ }
+}
+
+func TestLayerFromReader(t *testing.T) {
+ setupFixtures(t)
+ defer teardownFixtures(t)
+
+ ucBytes, err := os.ReadFile("testdata/content.tar")
+ if err != nil {
+ t.Fatalf("Unable to read tar file: %v", err)
+ }
+ tarLayer, err := LayerFromReader(bytes.NewReader(ucBytes))
+ if err != nil {
+ t.Fatalf("Unable to create layer from tar file: %v", err)
+ }
+
+ gzBytes, err := os.ReadFile("gzip_content.tgz")
+ if err != nil {
+ t.Fatalf("Unable to read tar file: %v", err)
+ }
+ tarGzLayer, err := LayerFromReader(bytes.NewReader(gzBytes))
+ if err != nil {
+ t.Fatalf("Unable to create layer from tar file: %v", err)
+ }
+
+ if err := compare.Layers(tarLayer, tarGzLayer); err != nil {
+ t.Errorf("compare.Layers: %v", err)
+ }
+
+ zstdBytes, err := os.ReadFile("zstd_content.tar.zst")
+ if err != nil {
+ t.Fatalf("Unable to read tar file: %v", err)
+ }
+ tarZstdLayer, err := LayerFromReader(bytes.NewReader(zstdBytes))
+ if err != nil {
+ t.Fatalf("Unable to create layer from tar file: %v", err)
+ }
+
+ if err := compare.Layers(tarLayer, tarZstdLayer); err != nil {
+ t.Errorf("compare.Layers: %v", err)
+ }
+}
+
+// Compression settings matter in order for the digest, size,
+// compressed assertions to pass
+//
+// Since our gzip.GzipReadCloser uses gzip.BestSpeed
+// we need our fixture to use the same - bazel's pkg_tar doesn't
+// seem to let you control compression settings
+func setupFixtures(t *testing.T) {
+ t.Helper()
+
+ setupCompressedTar(t, "gzip_content.tgz")
+ setupCompressedTar(t, "zstd_content.tar.zst")
+}
+
+func setupCompressedTar(t *testing.T, fileName string) {
+ t.Helper()
+ in, err := os.Open("testdata/content.tar")
+ if err != nil {
+ t.Errorf("Error setting up fixtures: %v", err)
+ }
+
+ defer in.Close()
+
+ out, err := os.Create(fileName)
+ if err != nil {
+ t.Errorf("Error setting up fixtures: %v", err)
+ }
+
+ defer out.Close()
+
+ gw, _ := gzip.NewWriterLevel(out, gzip.BestSpeed)
+ defer gw.Close()
+
+ _, err = io.Copy(gw, in)
+ if err != nil {
+ t.Errorf("Error setting up fixtures: %v", err)
+ }
+}
+
+func teardownFixtures(t *testing.T) {
+ t.Helper()
+ if err := os.Remove("gzip_content.tgz"); err != nil {
+ t.Errorf("Error tearing down fixtures: %v", err)
+ }
+ if err := os.Remove("zstd_content.tar.zst"); err != nil {
+ t.Errorf("Error tearing down fixtures: %v", err)
+ }
+}