1
15 package auth
16
17 import (
18 "context"
19 "errors"
20 "strconv"
21 "sync"
22 "sync/atomic"
23 "testing"
24 "time"
25
26 errdef "oras.land/oras-go/pkg/content"
27 )
28
29 func Test_concurrentCache_GetScheme(t *testing.T) {
30 cache := NewCache()
31
32
33 ctx := context.Background()
34 registry := "localhost:5000"
35 got, err := cache.GetScheme(ctx, registry)
36 if want := errdef.ErrNotFound; err != want {
37 t.Fatalf("concurrentCache.GetScheme() error = %v, wantErr %v", err, want)
38 }
39 if got != SchemeUnknown {
40 t.Errorf("concurrentCache.GetScheme() = %v, want %v", got, SchemeUnknown)
41 }
42
43
44 scheme := SchemeBasic
45 _, err = cache.Set(ctx, registry, scheme, "", func(c context.Context) (string, error) {
46 return "foo", nil
47 })
48 if err != nil {
49 t.Fatalf("failed to set cache: %v", err)
50 }
51
52
53 got, err = cache.GetScheme(ctx, registry)
54 if err != nil {
55 t.Fatalf("concurrentCache.GetScheme() error = %v", err)
56 }
57 if got != scheme {
58 t.Errorf("concurrentCache.GetScheme() = %v, want %v", got, scheme)
59 }
60
61
62 scheme = SchemeBearer
63 _, err = cache.Set(ctx, registry, scheme, "", func(c context.Context) (string, error) {
64 return "bar", nil
65 })
66 if err != nil {
67 t.Fatalf("failed to set cache: %v", err)
68 }
69
70
71 got, err = cache.GetScheme(ctx, registry)
72 if err != nil {
73 t.Fatalf("concurrentCache.GetScheme() error = %v", err)
74 }
75 if got != scheme {
76 t.Errorf("concurrentCache.GetScheme() = %v, want %v", got, scheme)
77 }
78
79
80 registry = "localhost:5001"
81 got, err = cache.GetScheme(ctx, registry)
82 if want := errdef.ErrNotFound; err != want {
83 t.Fatalf("concurrentCache.GetScheme() error = %v, wantErr %v", err, want)
84 }
85 if got != SchemeUnknown {
86 t.Errorf("concurrentCache.GetScheme() = %v, want %v", got, SchemeUnknown)
87 }
88 }
89
90 func Test_concurrentCache_GetToken(t *testing.T) {
91 cache := NewCache()
92
93
94 ctx := context.Background()
95 registry := "localhost:5000"
96 scheme := SchemeBearer
97 key := "1st key"
98 got, err := cache.GetToken(ctx, registry, scheme, key)
99 if want := errdef.ErrNotFound; err != want {
100 t.Fatalf("concurrentCache.GetToken() error = %v, wantErr %v", err, want)
101 }
102 if got != "" {
103 t.Errorf("concurrentCache.GetToken() = %v, want %v", got, "")
104 }
105
106
107 _, err = cache.Set(ctx, registry, scheme, key, func(c context.Context) (string, error) {
108 return "foo", nil
109 })
110 if err != nil {
111 t.Fatalf("failed to set cache: %v", err)
112 }
113
114
115 got, err = cache.GetToken(ctx, registry, scheme, key)
116 if err != nil {
117 t.Fatalf("concurrentCache.GetToken() error = %v", err)
118 }
119 if want := "foo"; got != want {
120 t.Errorf("concurrentCache.GetToken() = %v, want %v", got, want)
121 }
122
123
124 _, err = cache.Set(ctx, registry, scheme, key, func(c context.Context) (string, error) {
125 return "bar", nil
126 })
127 if err != nil {
128 t.Fatalf("failed to set cache: %v", err)
129 }
130
131
132 got, err = cache.GetToken(ctx, registry, scheme, key)
133 if err != nil {
134 t.Fatalf("concurrentCache.GetToken() error = %v", err)
135 }
136 if want := "bar"; got != want {
137 t.Errorf("concurrentCache.GetToken() = %v, want %v", got, want)
138 }
139
140
141 key = "2nd key"
142 got, err = cache.GetToken(ctx, registry, scheme, key)
143 if want := errdef.ErrNotFound; err != want {
144 t.Fatalf("concurrentCache.GetToken() error = %v, wantErr %v", err, want)
145 }
146 if got != "" {
147 t.Errorf("concurrentCache.GetToken() = %v, want %v", got, "")
148 }
149
150
151 _, err = cache.Set(ctx, registry, scheme, key, func(c context.Context) (string, error) {
152 return "hello world", nil
153 })
154 if err != nil {
155 t.Fatalf("failed to set cache: %v", err)
156 }
157
158
159 got, err = cache.GetToken(ctx, registry, scheme, key)
160 if err != nil {
161 t.Fatalf("concurrentCache.GetToken() error = %v", err)
162 }
163 if want := "hello world"; got != want {
164 t.Errorf("concurrentCache.GetToken() = %v, want %v", got, want)
165 }
166
167
168
169 key = "1st key"
170 got, err = cache.GetToken(ctx, registry, scheme, key)
171 if err != nil {
172 t.Fatalf("concurrentCache.GetToken() error = %v", err)
173 }
174 if want := "bar"; got != want {
175 t.Errorf("concurrentCache.GetToken() = %v, want %v", got, want)
176 }
177
178
179 registry = "localhost:5001"
180 got, err = cache.GetToken(ctx, registry, scheme, key)
181 if want := errdef.ErrNotFound; err != want {
182 t.Fatalf("concurrentCache.GetToken() error = %v, wantErr %v", err, want)
183 }
184 if got != "" {
185 t.Errorf("concurrentCache.GetToken() = %v, want %v", got, "")
186 }
187
188
189 _, err = cache.Set(ctx, registry, scheme, key, func(c context.Context) (string, error) {
190 return "foobar", nil
191 })
192 if err != nil {
193 t.Fatalf("failed to set cache: %v", err)
194 }
195
196
197 got, err = cache.GetToken(ctx, registry, scheme, key)
198 if err != nil {
199 t.Fatalf("concurrentCache.GetToken() error = %v", err)
200 }
201 if want := "foobar"; got != want {
202 t.Errorf("concurrentCache.GetToken() = %v, want %v", got, want)
203 }
204
205
206
207 registry = "localhost:5000"
208 got, err = cache.GetToken(ctx, registry, scheme, key)
209 if err != nil {
210 t.Fatalf("concurrentCache.GetToken() error = %v", err)
211 }
212 if want := "bar"; got != want {
213 t.Errorf("concurrentCache.GetToken() = %v, want %v", got, want)
214 }
215
216
217 scheme = SchemeBasic
218 got, err = cache.GetToken(ctx, registry, scheme, key)
219 if want := errdef.ErrNotFound; err != want {
220 t.Fatalf("concurrentCache.GetToken() error = %v, wantErr %v", err, want)
221 }
222 if got != "" {
223 t.Errorf("concurrentCache.GetToken() = %v, want %v", got, "")
224 }
225
226
227 _, err = cache.Set(ctx, registry, scheme, key, func(c context.Context) (string, error) {
228 return "new scheme", nil
229 })
230 if err != nil {
231 t.Fatalf("failed to set cache: %v", err)
232 }
233
234
235 got, err = cache.GetToken(ctx, registry, scheme, key)
236 if err != nil {
237 t.Fatalf("concurrentCache.GetToken() error = %v", err)
238 }
239 if want := "new scheme"; got != want {
240 t.Errorf("concurrentCache.GetToken() = %v, want %v", got, want)
241 }
242
243
244 got, err = cache.GetToken(ctx, registry, SchemeBearer, key)
245 if want := errdef.ErrNotFound; err != want {
246 t.Fatalf("concurrentCache.GetToken() error = %v, wantErr %v", err, want)
247 }
248 if got != "" {
249 t.Errorf("concurrentCache.GetToken() = %v, want %v", got, "")
250 }
251 }
252
253 func Test_concurrentCache_Set(t *testing.T) {
254 registries := []string{
255 "localhost:5000",
256 "localhost:5001",
257 }
258 scheme := SchemeBearer
259 keys := []string{
260 "foo",
261 "bar",
262 }
263 count := len(registries) * len(keys)
264
265 ctx := context.Background()
266 cache := NewCache()
267
268
269 fetch := func(i int) func(context.Context) (string, error) {
270 return func(context.Context) (string, error) {
271 return strconv.Itoa(i), nil
272 }
273 }
274 var wg sync.WaitGroup
275 for i := 0; i < 10; i++ {
276 for j := 0; j < count; j++ {
277 wg.Add(1)
278 go func(i int) {
279 defer wg.Done()
280 registry := registries[i&1]
281 key := keys[(i>>1)&1]
282 got, err := cache.Set(ctx, registry, scheme, key, fetch(i))
283 if err != nil {
284 t.Errorf("concurrentCache.Set() error = %v", err)
285 }
286 if want := strconv.Itoa(i); got != want {
287 t.Errorf("concurrentCache.Set() = %v, want %v", got, want)
288 }
289 }(j)
290 }
291 }
292 wg.Wait()
293
294 for i := 0; i < count; i++ {
295 registry := registries[i&1]
296 key := keys[(i>>1)&1]
297
298 gotScheme, err := cache.GetScheme(ctx, registry)
299 if err != nil {
300 t.Fatalf("concurrentCache.GetScheme() error = %v", err)
301 }
302 if want := scheme; gotScheme != want {
303 t.Errorf("concurrentCache.GetScheme() = %v, want %v", gotScheme, want)
304 }
305
306 gotToken, err := cache.GetToken(ctx, registry, scheme, key)
307 if err != nil {
308 t.Fatalf("concurrentCache.GetToken() error = %v", err)
309 }
310 if want := strconv.Itoa(i); gotToken != want {
311 t.Errorf("concurrentCache.GetToken() = %v, want %v", gotToken, want)
312 }
313 }
314
315
316 fetch = func(i int) func(context.Context) (string, error) {
317 return func(context.Context) (string, error) {
318 return strconv.Itoa(i) + " repeated", nil
319 }
320 }
321 for i := 0; i < 10; i++ {
322 for j := 0; j < count; j++ {
323 wg.Add(1)
324 go func(i int) {
325 defer wg.Done()
326 registry := registries[i&1]
327 key := keys[(i>>1)&1]
328 got, err := cache.Set(ctx, registry, scheme, key, fetch(i))
329 if err != nil {
330 t.Errorf("concurrentCache.Set() error = %v", err)
331 }
332 if want := strconv.Itoa(i) + " repeated"; got != want {
333 t.Errorf("concurrentCache.Set() = %v, want %v", got, want)
334 }
335 }(j)
336 }
337 }
338 wg.Wait()
339
340 for i := 0; i < count; i++ {
341 registry := registries[i&1]
342 key := keys[(i>>1)&1]
343
344 gotScheme, err := cache.GetScheme(ctx, registry)
345 if err != nil {
346 t.Fatalf("concurrentCache.GetScheme() error = %v", err)
347 }
348 if want := scheme; gotScheme != want {
349 t.Errorf("concurrentCache.GetScheme() = %v, want %v", gotScheme, want)
350 }
351
352 gotToken, err := cache.GetToken(ctx, registry, scheme, key)
353 if err != nil {
354 t.Fatalf("concurrentCache.GetToken() error = %v", err)
355 }
356 if want := strconv.Itoa(i) + " repeated"; gotToken != want {
357 t.Errorf("concurrentCache.GetToken() = %v, want %v", gotToken, want)
358 }
359 }
360 }
361
362 func Test_concurrentCache_Set_Fetch_Once(t *testing.T) {
363 registries := []string{
364 "localhost:5000",
365 "localhost:5001",
366 }
367 schemes := []Scheme{
368 SchemeBasic,
369 SchemeBearer,
370 }
371 keys := []string{
372 "foo",
373 "bar",
374 }
375 count := make([]int64, len(registries)*len(schemes)*len(keys))
376 fetch := func(i int) func(context.Context) (string, error) {
377 return func(context.Context) (string, error) {
378 time.Sleep(500 * time.Millisecond)
379 atomic.AddInt64(&count[i], 1)
380 return strconv.Itoa(i), nil
381 }
382 }
383
384 ctx := context.Background()
385 cache := NewCache()
386
387
388 var wg sync.WaitGroup
389 for i := 0; i < 10; i++ {
390 for j := 0; j < len(count); j++ {
391 wg.Add(1)
392 go func(i int) {
393 defer wg.Done()
394 registry := registries[i&1]
395 scheme := schemes[(i>>1)&1]
396 key := keys[(i>>2)&1]
397 got, err := cache.Set(ctx, registry, scheme, key, fetch(i))
398 if err != nil {
399 t.Errorf("concurrentCache.Set() error = %v", err)
400 }
401 if want := strconv.Itoa(i); got != want {
402 t.Errorf("concurrentCache.Set() = %v, want %v", got, want)
403 }
404 }(j)
405 }
406 }
407 wg.Wait()
408
409 for i := 0; i < len(count); i++ {
410 if got := count[i]; got != 1 {
411 t.Errorf("fetch is called more than once: %d", got)
412 }
413 }
414
415
416 for i := 0; i < 10; i++ {
417 for j := 0; j < len(count); j++ {
418 wg.Add(1)
419 go func(i int) {
420 defer wg.Done()
421 registry := registries[i&1]
422 scheme := schemes[(i>>1)&1]
423 key := keys[(i>>2)&1]
424 got, err := cache.Set(ctx, registry, scheme, key, fetch(i))
425 if err != nil {
426 t.Errorf("concurrentCache.Set() error = %v", err)
427 }
428 if want := strconv.Itoa(i); got != want {
429 t.Errorf("concurrentCache.Set() = %v, want %v", got, want)
430 }
431 }(j)
432 }
433 }
434 wg.Wait()
435
436 for i := 0; i < len(count); i++ {
437 if got := count[i]; got != 2 {
438 t.Errorf("fetch is called more than once: %d", got)
439 }
440 }
441 }
442
443 func Test_concurrentCache_Set_Fetch_Failure(t *testing.T) {
444 registries := []string{
445 "localhost:5000",
446 "localhost:5001",
447 }
448 scheme := SchemeBearer
449 keys := []string{
450 "foo",
451 "bar",
452 }
453 count := len(registries) * len(keys)
454
455 ctx := context.Background()
456 cache := NewCache()
457
458
459 fetch := func(i int) func(context.Context) (string, error) {
460 return func(context.Context) (string, error) {
461 return "", errors.New(strconv.Itoa(i))
462 }
463 }
464 var wg sync.WaitGroup
465 for i := 0; i < 10; i++ {
466 for j := 0; j < count; j++ {
467 wg.Add(1)
468 go func(i int) {
469 defer wg.Done()
470 registry := registries[i&1]
471 key := keys[(i>>1)&1]
472 _, err := cache.Set(ctx, registry, scheme, key, fetch(i))
473 if want := strconv.Itoa(i); err == nil || err.Error() != want {
474 t.Errorf("concurrentCache.Set() error = %v, wantErr %v", err, want)
475 }
476 }(j)
477 }
478 }
479 wg.Wait()
480
481 for i := 0; i < count; i++ {
482 registry := registries[i&1]
483 key := keys[(i>>1)&1]
484
485 _, err := cache.GetScheme(ctx, registry)
486 if want := errdef.ErrNotFound; err != want {
487 t.Fatalf("concurrentCache.GetScheme() error = %v, wantErr %v", err, want)
488 }
489
490 _, err = cache.GetToken(ctx, registry, scheme, key)
491 if want := errdef.ErrNotFound; err != want {
492 t.Errorf("concurrentCache.GetToken() error = %v, wantErr %v", err, want)
493 }
494 }
495
496
497 fetch = func(i int) func(context.Context) (string, error) {
498 return func(context.Context) (string, error) {
499 return strconv.Itoa(i), nil
500 }
501 }
502 for i := 0; i < 10; i++ {
503 for j := 0; j < count; j++ {
504 wg.Add(1)
505 go func(i int) {
506 defer wg.Done()
507 registry := registries[i&1]
508 key := keys[(i>>1)&1]
509 got, err := cache.Set(ctx, registry, scheme, key, fetch(i))
510 if err != nil {
511 t.Errorf("concurrentCache.Set() error = %v", err)
512 }
513 if want := strconv.Itoa(i); got != want {
514 t.Errorf("concurrentCache.Set() = %v, want %v", got, want)
515 }
516 }(j)
517 }
518 }
519 wg.Wait()
520
521 for i := 0; i < count; i++ {
522 registry := registries[i&1]
523 key := keys[(i>>1)&1]
524
525 gotScheme, err := cache.GetScheme(ctx, registry)
526 if err != nil {
527 t.Fatalf("concurrentCache.GetScheme() error = %v", err)
528 }
529 if want := scheme; gotScheme != want {
530 t.Errorf("concurrentCache.GetScheme() = %v, want %v", gotScheme, want)
531 }
532
533 gotToken, err := cache.GetToken(ctx, registry, scheme, key)
534 if err != nil {
535 t.Fatalf("concurrentCache.GetToken() error = %v", err)
536 }
537 if want := strconv.Itoa(i); gotToken != want {
538 t.Errorf("concurrentCache.GetToken() = %v, want %v", gotToken, want)
539 }
540 }
541 }
542
View as plain text