github.com/nikkelma/oras-project_oras-go@v1.1.1-0.20220201001104-a75f6a419090/pkg/registry/remote/auth/cache_test.go (about) 1 /* 2 Copyright The ORAS Authors. 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 */ 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 // no entry in the cache 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 // set an cache entry 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 // verify cache 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 // set cache entry again 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 // verify cache 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 // test other registry 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 // no entry in the cache 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 // set an cache entry 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 // verify cache 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 // set cache entry again 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 // verify cache 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 // test other key 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 // set an cache entry 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 // verify cache 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 // verify cache of the previous key as keys should not interference each 168 // other 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 // test other registry 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 // set an cache entry 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 // verify cache 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 // verify cache of the previous registry as registries should not 206 // interference each other 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 // test other scheme 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 // set an cache entry 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 // verify cache 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 // cache of the previous scheme should be invalidated due to scheme change. 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 // first round of fetch 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 // repeated fetch 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 // first round of fetch 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 // repeated fetch 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 // first round of fetch 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 // repeated fetch 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 }