1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package remote
16
17 import (
18 "fmt"
19 "net/http"
20 "net/http/httptest"
21 "net/url"
22 "strings"
23 "sync"
24 "testing"
25
26 "github.com/google/go-cmp/cmp"
27 "github.com/google/go-containerregistry/pkg/name"
28 "github.com/google/go-containerregistry/pkg/registry"
29 v1 "github.com/google/go-containerregistry/pkg/v1"
30 "github.com/google/go-containerregistry/pkg/v1/empty"
31 "github.com/google/go-containerregistry/pkg/v1/mutate"
32 "github.com/google/go-containerregistry/pkg/v1/random"
33 "github.com/google/go-containerregistry/pkg/v1/types"
34 )
35
36 func TestWriteLayer_Progress(t *testing.T) {
37 l, err := random.Layer(1000, types.OCIUncompressedLayer)
38 if err != nil {
39 t.Fatal(err)
40 }
41 c := make(chan v1.Update, 200)
42
43
44 s := httptest.NewServer(registry.New())
45 defer s.Close()
46 u, err := url.Parse(s.URL)
47 if err != nil {
48 t.Fatal(err)
49 }
50 dst := fmt.Sprintf("%s/test/progress/upload", u.Host)
51 ref, err := name.ParseReference(dst)
52 if err != nil {
53 t.Fatal(err)
54 }
55
56 if err := WriteLayer(ref.Context(), l, WithProgress(c)); err != nil {
57 t.Fatalf("WriteLayer: %v", err)
58 }
59 if err := checkUpdates(c); err != nil {
60 t.Fatal(err)
61 }
62 }
63
64
65
66
67 func TestWriteLayer_Progress_Exists(t *testing.T) {
68 l, err := random.Layer(1000, types.OCILayer)
69 if err != nil {
70 t.Fatal(err)
71 }
72 c := make(chan v1.Update, 200)
73
74
75 s := httptest.NewServer(registry.New())
76 defer s.Close()
77 u, err := url.Parse(s.URL)
78 if err != nil {
79 t.Fatal(err)
80 }
81 dst := fmt.Sprintf("%s/test/progress/upload", u.Host)
82 ref, err := name.ParseReference(dst)
83 if err != nil {
84 t.Fatal(err)
85 }
86
87
88 if err := WriteLayer(ref.Context(), l); err != nil {
89 t.Fatalf("WriteLayer: %v", err)
90 }
91 if err := WriteLayer(ref.Context(), l, WithProgress(c)); err != nil {
92 t.Fatalf("WriteLayer: %v", err)
93 }
94 if err := checkUpdates(c); err != nil {
95 t.Fatal(err)
96 }
97 }
98
99 func TestWrite_Progress(t *testing.T) {
100 img, err := random.Image(1000, 5)
101 if err != nil {
102 t.Fatal(err)
103 }
104 c := make(chan v1.Update, 200)
105
106
107 s := httptest.NewServer(registry.New())
108 defer s.Close()
109 u, err := url.Parse(s.URL)
110 if err != nil {
111 t.Fatal(err)
112 }
113 dst := fmt.Sprintf("%s/test/progress/upload", u.Host)
114 ref, err := name.ParseReference(dst)
115 if err != nil {
116 t.Fatal(err)
117 }
118
119 if err := Write(ref, img, WithProgress(c)); err != nil {
120 t.Fatalf("Write: %v", err)
121 }
122
123 if err := checkUpdates(c); err != nil {
124 t.Fatal(err)
125 }
126 }
127
128
129 func TestWrite_Progress_DedupeLayers(t *testing.T) {
130 img := empty.Image
131 for i := 0; i < 10; i++ {
132 l, err := random.Layer(1000, types.OCILayer)
133 if err != nil {
134 t.Fatal(err)
135 }
136
137 img, err = mutate.AppendLayers(img, l)
138 if err != nil {
139 t.Fatal(err)
140 }
141 }
142
143 c := make(chan v1.Update, 200)
144
145
146 s := httptest.NewServer(registry.New())
147 defer s.Close()
148 u, err := url.Parse(s.URL)
149 if err != nil {
150 t.Fatal(err)
151 }
152 dst := fmt.Sprintf("%s/test/progress/upload", u.Host)
153 ref, err := name.ParseReference(dst)
154 if err != nil {
155 t.Fatal(err)
156 }
157
158 if err := Write(ref, img, WithProgress(c)); err != nil {
159 t.Fatalf("Write: %v", err)
160 }
161
162 if err := checkUpdates(c); err != nil {
163 t.Fatal(err)
164 }
165 }
166
167 func TestWriteIndex_Progress(t *testing.T) {
168 idx, err := random.Index(1000, 3, 3)
169 if err != nil {
170 t.Fatal(err)
171 }
172 c := make(chan v1.Update, 200)
173
174
175 s := httptest.NewServer(registry.New())
176 defer s.Close()
177 u, err := url.Parse(s.URL)
178 if err != nil {
179 t.Fatal(err)
180 }
181 dst := fmt.Sprintf("%s/test/progress/upload", u.Host)
182 ref, err := name.ParseReference(dst)
183 if err != nil {
184 t.Fatal(err)
185 }
186
187 if err := WriteIndex(ref, idx, WithProgress(c)); err != nil {
188 t.Fatalf("WriteIndex: %v", err)
189 }
190
191 if err := checkUpdates(c); err != nil {
192 t.Fatal(err)
193 }
194 }
195
196 func TestMultiWrite_Progress(t *testing.T) {
197 idx, err := random.Index(1000, 3, 3)
198 if err != nil {
199 t.Fatal(err)
200 }
201 c := make(chan v1.Update, 1000)
202
203
204 s := httptest.NewServer(registry.New())
205 defer s.Close()
206 u, err := url.Parse(s.URL)
207 if err != nil {
208 t.Fatal(err)
209 }
210 ref, err := name.ParseReference(fmt.Sprintf("%s/test/progress/upload", u.Host))
211 if err != nil {
212 t.Fatal(err)
213 }
214 ref2, err := name.ParseReference(fmt.Sprintf("%s/test/progress/upload:again", u.Host))
215 if err != nil {
216 t.Fatal(err)
217 }
218
219 if err := MultiWrite(map[name.Reference]Taggable{
220 ref: idx,
221 ref2: idx,
222 }, WithProgress(c)); err != nil {
223 t.Fatalf("MultiWrite: %v", err)
224 }
225
226 if err := checkUpdates(c); err != nil {
227 t.Fatal(err)
228 }
229 }
230
231 func TestMultiWrite_Progress_Retry(t *testing.T) {
232 idx, err := random.Index(1000, 3, 3)
233 if err != nil {
234 t.Fatal(err)
235 }
236 c := make(chan v1.Update, 1000)
237
238
239 handler := registry.New()
240 numOfInternalServerErrors := 0
241 var mu sync.Mutex
242 registryThatFailsOnFirstUpload := http.HandlerFunc(func(responseWriter http.ResponseWriter, request *http.Request) {
243 mu.Lock()
244 defer mu.Unlock()
245 if strings.Contains(request.URL.Path, "/manifests/") && numOfInternalServerErrors < 1 {
246 numOfInternalServerErrors++
247 responseWriter.WriteHeader(500)
248 return
249 }
250 handler.ServeHTTP(responseWriter, request)
251 })
252
253 s := httptest.NewServer(registryThatFailsOnFirstUpload)
254 defer s.Close()
255 u, err := url.Parse(s.URL)
256 if err != nil {
257 t.Fatal(err)
258 }
259
260 ref, err := name.ParseReference(fmt.Sprintf("%s/test/progress/upload", u.Host))
261 if err != nil {
262 t.Fatal(err)
263 }
264 ref2, err := name.ParseReference(fmt.Sprintf("%s/test/progress/upload:again", u.Host))
265 if err != nil {
266 t.Fatal(err)
267 }
268
269 if err := MultiWrite(map[name.Reference]Taggable{
270 ref: idx,
271 ref2: idx,
272 }, WithProgress(c), WithRetryBackoff(fastBackoff)); err != nil {
273 t.Fatalf("MultiWrite: %v", err)
274 }
275
276 if err := checkUpdates(c); err != nil {
277 t.Fatal(err)
278 }
279 }
280
281 func TestWriteLayer_Progress_Retry(t *testing.T) {
282 l, err := random.Layer(100000, types.OCIUncompressedLayer)
283 if err != nil {
284 t.Fatal(err)
285 }
286 c := make(chan v1.Update, 200)
287
288
289 handler := registry.New()
290
291 numOfInternalServerErrors := 0
292 registryThatFailsOnFirstUpload := http.HandlerFunc(func(responseWriter http.ResponseWriter, request *http.Request) {
293 if request.Method == http.MethodPatch && strings.Contains(request.URL.Path, "upload/blobs/uploads") && numOfInternalServerErrors < 1 {
294 numOfInternalServerErrors++
295 responseWriter.WriteHeader(500)
296 return
297 }
298 handler.ServeHTTP(responseWriter, request)
299 })
300
301 s := httptest.NewServer(registryThatFailsOnFirstUpload)
302 defer s.Close()
303 u, err := url.Parse(s.URL)
304 if err != nil {
305 t.Fatal(err)
306 }
307 dst := fmt.Sprintf("%s/test/progress/upload", u.Host)
308 ref, err := name.ParseReference(dst)
309 if err != nil {
310 t.Fatal(err)
311 }
312
313 if err := WriteLayer(ref.Context(), l, WithProgress(c), WithRetryBackoff(fastBackoff)); err != nil {
314 t.Fatalf("WriteLayer: %v", err)
315 }
316
317 everyUpdate := []v1.Update{}
318 for update := range c {
319 everyUpdate = append(everyUpdate, update)
320 }
321
322 if diff := cmp.Diff(everyUpdate, []v1.Update{
323 {Total: 101921, Complete: 32768},
324 {Total: 101921, Complete: 65536},
325 {Total: 101921, Complete: 98304},
326 {Total: 101921, Complete: 101921},
327
328 {Total: 101921, Complete: 0},
329 {Total: 101921, Complete: 32768},
330 {Total: 101921, Complete: 65536},
331 {Total: 101921, Complete: 98304},
332 {Total: 101921, Complete: 101921},
333 }); diff != "" {
334 t.Errorf("received updates (-want +got) = %s", diff)
335 }
336 }
337
338 func TestWriteLayer_Progress_Error(t *testing.T) {
339 l, err := random.Layer(100000, types.OCIUncompressedLayer)
340 if err != nil {
341 t.Fatal(err)
342 }
343 c := make(chan v1.Update, 200)
344
345
346 handler := registry.New()
347 registryThatAlwaysFails := http.HandlerFunc(func(responseWriter http.ResponseWriter, request *http.Request) {
348 if request.Method == http.MethodPatch && strings.Contains(request.URL.Path, "blobs/uploads") {
349 responseWriter.WriteHeader(403)
350 }
351 handler.ServeHTTP(responseWriter, request)
352 })
353
354 s := httptest.NewServer(registryThatAlwaysFails)
355 defer s.Close()
356 u, err := url.Parse(s.URL)
357 if err != nil {
358 t.Fatal(err)
359 }
360 dst := fmt.Sprintf("%s/test/progress/upload", u.Host)
361 ref, err := name.ParseReference(dst)
362 if err != nil {
363 t.Fatal(err)
364 }
365
366 if err := WriteLayer(ref.Context(), l, WithProgress(c)); err == nil {
367 t.Errorf("WriteLayer: wanted error, got nil")
368 }
369
370 everyUpdate := []v1.Update{}
371 for update := range c {
372 everyUpdate = append(everyUpdate, update)
373 }
374
375 if diff := cmp.Diff(everyUpdate[:len(everyUpdate)-1], []v1.Update{
376 {Total: 101921, Complete: 32768},
377 {Total: 101921, Complete: 65536},
378 {Total: 101921, Complete: 98304},
379 {Total: 101921, Complete: 101921},
380
381 {Total: 101921, Complete: 0},
382 }); diff != "" {
383 t.Errorf("received updates (-want +got) = %s", diff)
384 }
385 if everyUpdate[len(everyUpdate)-1].Error == nil {
386 t.Errorf("Last update had nil error")
387 }
388 }
389
390 func TestWrite_Progress_WithNonDistributableLayer_AndIncludeNonDistributableLayersOption(t *testing.T) {
391 ociLayer, err := random.Layer(1000, types.OCILayer)
392 if err != nil {
393 t.Fatal(err)
394 }
395
396 nonDistributableLayer, err := random.Layer(1000, types.OCIRestrictedLayer)
397 if err != nil {
398 t.Fatal(err)
399 }
400
401 img, err := mutate.AppendLayers(empty.Image, ociLayer, nonDistributableLayer)
402 if err != nil {
403 t.Fatal(err)
404 }
405
406 c := make(chan v1.Update, 200)
407
408
409 s := httptest.NewServer(registry.New())
410 defer s.Close()
411 u, err := url.Parse(s.URL)
412 if err != nil {
413 t.Fatal(err)
414 }
415 dst := fmt.Sprintf("%s/test/progress/upload", u.Host)
416 ref, err := name.ParseReference(dst)
417 if err != nil {
418 t.Fatal(err)
419 }
420
421 if err := Write(ref, img, WithProgress(c), WithNondistributable); err != nil {
422 t.Fatalf("Write: %v", err)
423 }
424
425 if err := checkUpdates(c); err != nil {
426 t.Fatal(err)
427 }
428 }
429
430
431
432 func checkUpdates(updates <-chan v1.Update) error {
433 var high, total int64
434 for u := range updates {
435 if u.Error != nil {
436 return u.Error
437 }
438
439 if u.Total < total {
440 return fmt.Errorf("total changed: was %d, saw %d", total, u.Total)
441 }
442
443 total = u.Total
444
445 if u.Complete < high {
446 return fmt.Errorf("saw progress revert: was high of %d, saw %d", high, u.Complete)
447 }
448 high = u.Complete
449 }
450
451 if high > total {
452 return fmt.Errorf("final progress (%d) exceeded total (%d) by %d", high, total, high-total)
453 } else if high < total {
454 return fmt.Errorf("final progress (%d) did not reach total (%d) by %d", high, total, total-high)
455 }
456
457 return nil
458 }
459
View as plain text