1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package stream
16
17 import (
18 "archive/tar"
19 "bytes"
20 "crypto/rand"
21 "errors"
22 "fmt"
23 "io"
24 "strings"
25 "testing"
26
27 v1 "github.com/google/go-containerregistry/pkg/v1"
28 "github.com/google/go-containerregistry/pkg/v1/tarball"
29 "github.com/google/go-containerregistry/pkg/v1/types"
30 )
31
32 func TestStreamVsBuffer(t *testing.T) {
33 var n, wantSize int64 = 10000, 49
34 newBlob := func() io.ReadCloser { return io.NopCloser(bytes.NewReader(bytes.Repeat([]byte{'a'}, int(n)))) }
35 wantDigest := "sha256:3d7c465be28d9e1ed810c42aeb0e747b44441424f566722ba635dc93c947f30e"
36 wantDiffID := "sha256:27dd1f61b867b6a0f6e9d8a41c43231de52107e53ae424de8f847b821db4b711"
37
38
39 l := NewLayer(newBlob())
40 if c, err := l.Compressed(); err != nil {
41 t.Errorf("Compressed: %v", err)
42 } else {
43 if _, err := io.Copy(io.Discard, c); err != nil {
44 t.Errorf("error reading Compressed: %v", err)
45 }
46 if err := c.Close(); err != nil {
47 t.Errorf("Close: %v", err)
48 }
49 }
50 if d, err := l.Digest(); err != nil {
51 t.Errorf("Digest: %v", err)
52 } else if d.String() != wantDigest {
53 t.Errorf("stream Digest got %q, want %q", d.String(), wantDigest)
54 }
55 if d, err := l.DiffID(); err != nil {
56 t.Errorf("DiffID: %v", err)
57 } else if d.String() != wantDiffID {
58 t.Errorf("stream DiffID got %q, want %q", d.String(), wantDiffID)
59 }
60 if s, err := l.Size(); err != nil {
61 t.Errorf("Size: %v", err)
62 } else if s != wantSize {
63 t.Errorf("stream Size got %d, want %d", s, wantSize)
64 }
65
66
67
68 tl, err := tarball.LayerFromOpener(func() (io.ReadCloser, error) { return newBlob(), nil })
69 if err != nil {
70 t.Fatalf("LayerFromOpener: %v", err)
71 }
72 if d, err := tl.Digest(); err != nil {
73 t.Errorf("Digest: %v", err)
74 } else if d.String() != wantDigest {
75 t.Errorf("tarball Digest got %q, want %q", d.String(), wantDigest)
76 }
77 if d, err := tl.DiffID(); err != nil {
78 t.Errorf("DiffID: %v", err)
79 } else if d.String() != wantDiffID {
80 t.Errorf("tarball DiffID got %q, want %q", d.String(), wantDiffID)
81 }
82 if s, err := tl.Size(); err != nil {
83 t.Errorf("Size: %v", err)
84 } else if s != wantSize {
85 t.Errorf("stream Size got %d, want %d", s, wantSize)
86 }
87
88
89 l2 := NewLayer(newBlob(), WithCompressionLevel(2))
90 l2WantDigest := "sha256:c9afe7b0da6783232e463e12328cb306142548384accf3995806229c9a6a707f"
91 if c, err := l2.Compressed(); err != nil {
92 t.Errorf("Compressed: %v", err)
93 } else {
94 if _, err := io.Copy(io.Discard, c); err != nil {
95 t.Errorf("error reading Compressed: %v", err)
96 }
97 if err := c.Close(); err != nil {
98 t.Errorf("Close: %v", err)
99 }
100 }
101 if d, err := l2.Digest(); err != nil {
102 t.Errorf("Digest: %v", err)
103 } else if d.String() != l2WantDigest {
104 t.Errorf("stream Digest got %q, want %q", d.String(), l2WantDigest)
105 }
106 }
107
108 func TestLargeStream(t *testing.T) {
109 var n, wantSize int64 = 10000000, 10000788
110 sl := NewLayer(io.NopCloser(io.LimitReader(rand.Reader, n)))
111 rc, err := sl.Compressed()
112 if err != nil {
113 t.Fatalf("Uncompressed: %v", err)
114 }
115 if _, err := io.Copy(io.Discard, rc); err != nil {
116 t.Fatalf("Reading layer: %v", err)
117 }
118 if err := rc.Close(); err != nil {
119 t.Fatalf("Close: %v", err)
120 }
121
122 if dig, err := sl.Digest(); err != nil {
123 t.Errorf("Digest: %v", err)
124 } else if dig.String() == (v1.Hash{}).String() {
125 t.Errorf("Digest got %q, want anything else", (v1.Hash{}).String())
126 }
127 if diffID, err := sl.DiffID(); err != nil {
128 t.Errorf("DiffID: %v", err)
129 } else if diffID.String() == (v1.Hash{}).String() {
130 t.Errorf("DiffID got %q, want anything else", (v1.Hash{}).String())
131 }
132 if size, err := sl.Size(); err != nil {
133 t.Errorf("Size: %v", err)
134 } else if size != wantSize {
135 t.Errorf("Size got %d, want %d", size, wantSize)
136 }
137 }
138
139 func TestStreamableLayerFromTarball(t *testing.T) {
140 pr, pw := io.Pipe()
141 tw := tar.NewWriter(pw)
142 go func() {
143
144 pw.CloseWithError(func() error {
145 for i := 0; i < 1000; i++ {
146 name := fmt.Sprintf("file-%d.txt", i)
147 body := fmt.Sprintf("i am file number %d", i)
148 if err := tw.WriteHeader(&tar.Header{
149 Name: name,
150 Mode: 0600,
151 Size: int64(len(body)),
152 Typeflag: tar.TypeReg,
153 }); err != nil {
154 return err
155 }
156 if _, err := tw.Write([]byte(body)); err != nil {
157 return err
158 }
159 }
160 return tw.Close()
161 }())
162 }()
163
164 l := NewLayer(pr)
165 rc, err := l.Compressed()
166 if err != nil {
167 t.Fatalf("Compressed: %v", err)
168 }
169 if _, err := io.Copy(io.Discard, rc); err != nil {
170 t.Fatalf("Copy: %v", err)
171 }
172 if err := rc.Close(); err != nil {
173 t.Fatalf("Close: %v", err)
174 }
175
176 wantDigest := "sha256:ed80efd7e7e884fb59db568f234332283b341b96155e872d638de42d55a34198"
177 if got, err := l.Digest(); err != nil {
178 t.Errorf("Digest: %v", err)
179 } else if got.String() != wantDigest {
180 t.Errorf("Digest: got %q, want %q", got.String(), wantDigest)
181 }
182 }
183
184
185
186 func TestNotComputed(t *testing.T) {
187 l := NewLayer(io.NopCloser(bytes.NewBufferString("hi")))
188
189
190
191 if _, err := l.Size(); !errors.Is(err, ErrNotComputed) {
192 t.Errorf("Size: got %v, want %v", err, ErrNotComputed)
193 }
194 if _, err := l.Digest(); err == nil {
195 t.Errorf("Digest: got %v, want %v", err, ErrNotComputed)
196 }
197 if _, err := l.DiffID(); err == nil {
198 t.Errorf("DiffID: got %v, want %v", err, ErrNotComputed)
199 }
200 }
201
202
203
204 func TestConsumed(t *testing.T) {
205 l := NewLayer(io.NopCloser(strings.NewReader("hello")))
206 rc, err := l.Compressed()
207 if err != nil {
208 t.Errorf("Compressed: %v", err)
209 }
210 if _, err := io.Copy(io.Discard, rc); err != nil {
211 t.Errorf("Error reading contents: %v", err)
212 }
213 if err := rc.Close(); err != nil {
214 t.Errorf("Close: %v", err)
215 }
216
217 if _, err := l.Compressed(); !errors.Is(err, ErrConsumed) {
218 t.Errorf("Compressed() after consuming; got %v, want %v", err, ErrConsumed)
219 }
220 }
221
222 func TestCloseTextStreamBeforeConsume(t *testing.T) {
223
224 l := NewLayer(io.NopCloser(strings.NewReader("hello")))
225 rc, err := l.Compressed()
226 if err != nil {
227 t.Fatalf("Compressed: %v", err)
228 }
229
230
231 if err := rc.Close(); err != nil {
232 t.Fatalf("Close: %v", err)
233 }
234 }
235
236 func TestCloseTarStreamBeforeConsume(t *testing.T) {
237
238 pr, pw := io.Pipe()
239 tw := tar.NewWriter(pw)
240 go func() {
241 pw.CloseWithError(func() error {
242 body := "test file"
243 if err := tw.WriteHeader(&tar.Header{
244 Name: "test.txt",
245 Mode: 0600,
246 Size: int64(len(body)),
247 Typeflag: tar.TypeReg,
248 }); err != nil {
249 return err
250 }
251 if _, err := tw.Write([]byte(body)); err != nil {
252 return err
253 }
254 return tw.Close()
255 }())
256 }()
257
258
259 l := NewLayer(pr)
260 rc, err := l.Compressed()
261 if err != nil {
262 t.Fatalf("Compressed: %v", err)
263 }
264
265
266 if err := rc.Close(); err != nil {
267 t.Fatalf("Close: %v", err)
268 }
269 }
270
271 func TestMediaType(t *testing.T) {
272 l := NewLayer(io.NopCloser(strings.NewReader("hello")))
273 mediaType, err := l.MediaType()
274
275 if err != nil {
276 t.Fatalf("MediaType(): %v", err)
277 }
278
279 if got, want := mediaType, types.DockerLayer; got != want {
280 t.Errorf("MediaType(): want %q, got %q", want, got)
281 }
282 }
283
284 func TestMediaTypeOption(t *testing.T) {
285 l := NewLayer(io.NopCloser(strings.NewReader("hello")), WithMediaType(types.OCILayer))
286 mediaType, err := l.MediaType()
287
288 if err != nil {
289 t.Fatalf("MediaType(): %v", err)
290 }
291
292 if got, want := mediaType, types.OCILayer; got != want {
293 t.Errorf("MediaType(): want %q, got %q", want, got)
294 }
295 }
296
View as plain text