1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package tarball
16
17 import (
18 "bytes"
19 "compress/gzip"
20 "io"
21 "os"
22 "testing"
23
24 "github.com/containerd/stargz-snapshotter/estargz"
25 "github.com/google/go-containerregistry/internal/compare"
26 "github.com/google/go-containerregistry/pkg/compression"
27 v1 "github.com/google/go-containerregistry/pkg/v1"
28 "github.com/google/go-containerregistry/pkg/v1/types"
29 "github.com/google/go-containerregistry/pkg/v1/validate"
30 )
31
32 func TestLayerFromFile(t *testing.T) {
33 setupFixtures(t)
34 defer teardownFixtures(t)
35
36 tarLayer, err := LayerFromFile("testdata/content.tar")
37 if err != nil {
38 t.Fatalf("Unable to create layer from tar file: %v", err)
39 }
40
41 tarGzLayer, err := LayerFromFile("gzip_content.tgz")
42 if err != nil {
43 t.Fatalf("Unable to create layer from compressed tar file: %v", err)
44 }
45
46 tarZstdLayer, err := LayerFromFile("zstd_content.tar.zst")
47 if err != nil {
48 t.Fatalf("Unable to create layer from compressed tar file: %v", err)
49 }
50
51 if err := compare.Layers(tarLayer, tarGzLayer); err != nil {
52 t.Errorf("compare.Layers: %v", err)
53 }
54
55 if err := compare.Layers(tarLayer, tarZstdLayer); err != nil {
56 t.Errorf("compare.Layers: %v", err)
57 }
58
59 if err := validate.Layer(tarLayer); err != nil {
60 t.Errorf("validate.Layer(tarLayer): %v", err)
61 }
62
63 if err := validate.Layer(tarGzLayer); err != nil {
64 t.Errorf("validate.Layer(tarGzLayer): %v", err)
65 }
66
67 if err := validate.Layer(tarZstdLayer); err != nil {
68 t.Errorf("validate.Layer(tarZstdLayer): %v", err)
69 }
70
71 getTestDigest := func(testName string, opts ...LayerOption) v1.Hash {
72 layer, err := LayerFromFile("testdata/content.tar", opts...)
73 if err != nil {
74 t.Fatalf("Unable to create layer with '%s' compression from tar file: %v", testName, err)
75 }
76
77 digest, err := layer.Digest()
78 if err != nil {
79 t.Fatalf("Unable to generate digest with '%s' compression: %v", testName, err)
80 }
81
82 return digest
83 }
84
85 defaultDigest := getTestDigest("Gzip Default", WithCompressionLevel(gzip.DefaultCompression))
86 speedDigest := getTestDigest("Gzip BestSpeed", WithCompressionLevel(gzip.BestSpeed))
87 zstdDigest := getTestDigest("Zstd Default", WithCompression(compression.ZStd))
88 zstdDigest1 := getTestDigest("Zstd BestSpeed", WithCompression(compression.ZStd), WithCompressionLevel(1))
89
90 if defaultDigest.String() == speedDigest.String() {
91 t.Errorf("expected digests to differ: %s", defaultDigest.String())
92 }
93
94 if defaultDigest.String() == zstdDigest.String() {
95 t.Errorf("expected digests to differ: %s", defaultDigest.String())
96 }
97
98 if defaultDigest.String() == zstdDigest1.String() {
99 t.Errorf("expected digests to differ: %s", defaultDigest.String())
100 }
101 }
102
103 func TestLayerFromFileEstargz(t *testing.T) {
104 setupFixtures(t)
105 defer teardownFixtures(t)
106
107 tarLayer, err := LayerFromFile("testdata/content.tar", WithEstargz)
108 if err != nil {
109 t.Fatalf("Unable to create layer from tar file: %v", err)
110 }
111
112 if err := validate.Layer(tarLayer); err != nil {
113 t.Errorf("validate.Layer(tarLayer): %v", err)
114 }
115
116 tarLayerDefaultCompression, err := LayerFromFile("testdata/content.tar", WithEstargz, WithCompressionLevel(gzip.DefaultCompression))
117 if err != nil {
118 t.Fatalf("Unable to create layer with 'Default' compression from tar file: %v", err)
119 }
120 descriptorDefaultCompression, err := tarLayerDefaultCompression.(*layer).Descriptor()
121 if err != nil {
122 t.Fatalf("Descriptor() = %v", err)
123 } else if len(descriptorDefaultCompression.Annotations) != 1 {
124 t.Errorf("Annotations = %#v, wanted 1 annotation", descriptorDefaultCompression.Annotations)
125 }
126
127 defaultDigest, err := tarLayerDefaultCompression.Digest()
128 if err != nil {
129 t.Fatal("Unable to generate digest with 'Default' compression", err)
130 }
131
132 tarLayerSpeedCompression, err := LayerFromFile("testdata/content.tar", WithEstargz, WithCompressionLevel(gzip.BestSpeed))
133 if err != nil {
134 t.Fatalf("Unable to create layer with 'BestSpeed' compression from tar file: %v", err)
135 }
136 descriptorSpeedCompression, err := tarLayerSpeedCompression.(*layer).Descriptor()
137 if err != nil {
138 t.Fatalf("Descriptor() = %v", err)
139 } else if len(descriptorSpeedCompression.Annotations) != 1 {
140 t.Errorf("Annotations = %#v, wanted 1 annotation", descriptorSpeedCompression.Annotations)
141 }
142
143 speedDigest, err := tarLayerSpeedCompression.Digest()
144 if err != nil {
145 t.Fatal("Unable to generate digest with 'BestSpeed' compression", err)
146 }
147
148 if defaultDigest.String() == speedDigest.String() {
149 t.Errorf("expected digests to differ: %s", defaultDigest.String())
150 }
151
152 if descriptorDefaultCompression.Annotations[estargz.TOCJSONDigestAnnotation] == descriptorSpeedCompression.Annotations[estargz.TOCJSONDigestAnnotation] {
153 t.Errorf("wanted different toc digests got default: %s, speed: %s",
154 descriptorDefaultCompression.Annotations[estargz.TOCJSONDigestAnnotation],
155 descriptorSpeedCompression.Annotations[estargz.TOCJSONDigestAnnotation])
156 }
157
158 tarLayerPrioritizedFiles, err := LayerFromFile("testdata/content.tar",
159 WithEstargz,
160
161 WithCompressionLevel(gzip.DefaultCompression),
162
163 WithEstargzOptions(estargz.WithPrioritizedFiles([]string{
164 "./bat",
165 })))
166 if err != nil {
167 t.Fatalf("Unable to create layer with prioritized files from tar file: %v", err)
168 }
169 descriptorPrioritizedFiles, err := tarLayerPrioritizedFiles.(*layer).Descriptor()
170 if err != nil {
171 t.Fatalf("Descriptor() = %v", err)
172 } else if len(descriptorPrioritizedFiles.Annotations) != 1 {
173 t.Errorf("Annotations = %#v, wanted 1 annotation", descriptorPrioritizedFiles.Annotations)
174 }
175
176 prioritizedDigest, err := tarLayerPrioritizedFiles.Digest()
177 if err != nil {
178 t.Fatal("Unable to generate digest with prioritized files", err)
179 }
180
181 if defaultDigest.String() == prioritizedDigest.String() {
182 t.Errorf("expected digests to differ: %s", defaultDigest.String())
183 }
184
185 if descriptorDefaultCompression.Annotations[estargz.TOCJSONDigestAnnotation] == descriptorPrioritizedFiles.Annotations[estargz.TOCJSONDigestAnnotation] {
186 t.Errorf("wanted different toc digests got default: %s, prioritized: %s",
187 descriptorDefaultCompression.Annotations[estargz.TOCJSONDigestAnnotation],
188 descriptorPrioritizedFiles.Annotations[estargz.TOCJSONDigestAnnotation])
189 }
190 }
191
192 func TestLayerFromOpenerReader(t *testing.T) {
193 setupFixtures(t)
194 defer teardownFixtures(t)
195
196 ucBytes, err := os.ReadFile("testdata/content.tar")
197 if err != nil {
198 t.Fatalf("Unable to read tar file: %v", err)
199 }
200 count := 0
201 ucOpener := func() (io.ReadCloser, error) {
202 count++
203 return io.NopCloser(bytes.NewReader(ucBytes)), nil
204 }
205 tarLayer, err := LayerFromOpener(ucOpener, WithCompressedCaching)
206 if err != nil {
207 t.Fatal("Unable to create layer from tar file:", err)
208 }
209 for i := 0; i < 10; i++ {
210 tarLayer.Compressed()
211 }
212
213
214 cachedCount := count
215 count = 0
216
217 tarLayer, err = LayerFromOpener(ucOpener)
218 if err != nil {
219 t.Fatal("Unable to create layer from tar file:", err)
220 }
221 for i := 0; i < 10; i++ {
222 tarLayer.Compressed()
223 }
224
225
226 if cachedCount != 3 {
227 t.Errorf("cached count = %d, wanted %d", cachedCount, 3)
228 }
229 if cachedCount+10 != count {
230 t.Errorf("count = %d, wanted %d", count, cachedCount+10)
231 }
232
233 gzBytes, err := os.ReadFile("gzip_content.tgz")
234 if err != nil {
235 t.Fatalf("Unable to read tar file: %v", err)
236 }
237 gzOpener := func() (io.ReadCloser, error) {
238 return io.NopCloser(bytes.NewReader(gzBytes)), nil
239 }
240 tarGzLayer, err := LayerFromOpener(gzOpener)
241 if err != nil {
242 t.Fatalf("Unable to create layer from tar file: %v", err)
243 }
244
245 if err := compare.Layers(tarLayer, tarGzLayer); err != nil {
246 t.Errorf("compare.Layers: %v", err)
247 }
248
249 zstdBytes, err := os.ReadFile("zstd_content.tar.zst")
250 if err != nil {
251 t.Fatalf("Unable to read tar file: %v", err)
252 }
253 zstdOpener := func() (io.ReadCloser, error) {
254 return io.NopCloser(bytes.NewReader(zstdBytes)), nil
255 }
256 tarZstdLayer, err := LayerFromOpener(zstdOpener)
257 if err != nil {
258 t.Fatalf("Unable to create layer from tar file: %v", err)
259 }
260
261 if err := compare.Layers(tarLayer, tarZstdLayer); err != nil {
262 t.Errorf("compare.Layers: %v", err)
263 }
264 }
265
266 func TestWithMediaType(t *testing.T) {
267 setupFixtures(t)
268 defer teardownFixtures(t)
269
270 l, err := LayerFromFile("testdata/content.tar")
271 if err != nil {
272 t.Fatalf("Unable to create layer from tar file: %v", err)
273 }
274 got, err := l.MediaType()
275 if err != nil {
276 t.Fatalf("MediaType: %v", err)
277 }
278 if want := types.DockerLayer; got != want {
279 t.Errorf("got %v, want %v", got, want)
280 }
281
282 l, err = LayerFromFile("testdata/content.tar", WithMediaType(types.OCILayer))
283 if err != nil {
284 t.Fatalf("Unable to create layer from tar file: %v", err)
285 }
286 got, err = l.MediaType()
287 if err != nil {
288 t.Fatalf("MediaType: %v", err)
289 }
290 if want := types.OCILayer; got != want {
291 t.Errorf("got %v, want %v", got, want)
292 }
293 }
294
295 func TestLayerFromReader(t *testing.T) {
296 setupFixtures(t)
297 defer teardownFixtures(t)
298
299 ucBytes, err := os.ReadFile("testdata/content.tar")
300 if err != nil {
301 t.Fatalf("Unable to read tar file: %v", err)
302 }
303 tarLayer, err := LayerFromReader(bytes.NewReader(ucBytes))
304 if err != nil {
305 t.Fatalf("Unable to create layer from tar file: %v", err)
306 }
307
308 gzBytes, err := os.ReadFile("gzip_content.tgz")
309 if err != nil {
310 t.Fatalf("Unable to read tar file: %v", err)
311 }
312 tarGzLayer, err := LayerFromReader(bytes.NewReader(gzBytes))
313 if err != nil {
314 t.Fatalf("Unable to create layer from tar file: %v", err)
315 }
316
317 if err := compare.Layers(tarLayer, tarGzLayer); err != nil {
318 t.Errorf("compare.Layers: %v", err)
319 }
320
321 zstdBytes, err := os.ReadFile("zstd_content.tar.zst")
322 if err != nil {
323 t.Fatalf("Unable to read tar file: %v", err)
324 }
325 tarZstdLayer, err := LayerFromReader(bytes.NewReader(zstdBytes))
326 if err != nil {
327 t.Fatalf("Unable to create layer from tar file: %v", err)
328 }
329
330 if err := compare.Layers(tarLayer, tarZstdLayer); err != nil {
331 t.Errorf("compare.Layers: %v", err)
332 }
333 }
334
335
336
337
338
339
340
341 func setupFixtures(t *testing.T) {
342 t.Helper()
343
344 setupCompressedTar(t, "gzip_content.tgz")
345 setupCompressedTar(t, "zstd_content.tar.zst")
346 }
347
348 func setupCompressedTar(t *testing.T, fileName string) {
349 t.Helper()
350 in, err := os.Open("testdata/content.tar")
351 if err != nil {
352 t.Errorf("Error setting up fixtures: %v", err)
353 }
354
355 defer in.Close()
356
357 out, err := os.Create(fileName)
358 if err != nil {
359 t.Errorf("Error setting up fixtures: %v", err)
360 }
361
362 defer out.Close()
363
364 gw, _ := gzip.NewWriterLevel(out, gzip.BestSpeed)
365 defer gw.Close()
366
367 _, err = io.Copy(gw, in)
368 if err != nil {
369 t.Errorf("Error setting up fixtures: %v", err)
370 }
371 }
372
373 func teardownFixtures(t *testing.T) {
374 t.Helper()
375 if err := os.Remove("gzip_content.tgz"); err != nil {
376 t.Errorf("Error tearing down fixtures: %v", err)
377 }
378 if err := os.Remove("zstd_content.tar.zst"); err != nil {
379 t.Errorf("Error tearing down fixtures: %v", err)
380 }
381 }
382
View as plain text