github.com/liuzhiyi/docker@v1.5.0/registry/registry_test.go (about) 1 package registry 2 3 import ( 4 "fmt" 5 "net/http" 6 "net/url" 7 "strings" 8 "testing" 9 10 "github.com/docker/docker/utils" 11 ) 12 13 var ( 14 token = []string{"fake-token"} 15 ) 16 17 const ( 18 imageID = "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d" 19 REPO = "foo42/bar" 20 ) 21 22 func spawnTestRegistrySession(t *testing.T) *Session { 23 authConfig := &AuthConfig{} 24 endpoint, err := NewEndpoint(makeIndex("/v1/")) 25 if err != nil { 26 t.Fatal(err) 27 } 28 r, err := NewSession(authConfig, utils.NewHTTPRequestFactory(), endpoint, true) 29 if err != nil { 30 t.Fatal(err) 31 } 32 return r 33 } 34 35 func TestPublicSession(t *testing.T) { 36 authConfig := &AuthConfig{} 37 38 getSessionDecorators := func(index *IndexInfo) int { 39 endpoint, err := NewEndpoint(index) 40 if err != nil { 41 t.Fatal(err) 42 } 43 r, err := NewSession(authConfig, utils.NewHTTPRequestFactory(), endpoint, true) 44 if err != nil { 45 t.Fatal(err) 46 } 47 return len(r.reqFactory.GetDecorators()) 48 } 49 50 decorators := getSessionDecorators(makeIndex("/v1/")) 51 assertEqual(t, decorators, 0, "Expected no decorator on http session") 52 53 decorators = getSessionDecorators(makeHttpsIndex("/v1/")) 54 assertNotEqual(t, decorators, 0, "Expected decorator on https session") 55 56 decorators = getSessionDecorators(makePublicIndex()) 57 assertEqual(t, decorators, 0, "Expected no decorator on public session") 58 } 59 60 func TestPingRegistryEndpoint(t *testing.T) { 61 testPing := func(index *IndexInfo, expectedStandalone bool, assertMessage string) { 62 ep, err := NewEndpoint(index) 63 if err != nil { 64 t.Fatal(err) 65 } 66 regInfo, err := ep.Ping() 67 if err != nil { 68 t.Fatal(err) 69 } 70 71 assertEqual(t, regInfo.Standalone, expectedStandalone, assertMessage) 72 } 73 74 testPing(makeIndex("/v1/"), true, "Expected standalone to be true (default)") 75 testPing(makeHttpsIndex("/v1/"), true, "Expected standalone to be true (default)") 76 testPing(makePublicIndex(), false, "Expected standalone to be false for public index") 77 } 78 79 func TestEndpoint(t *testing.T) { 80 // Simple wrapper to fail test if err != nil 81 expandEndpoint := func(index *IndexInfo) *Endpoint { 82 endpoint, err := NewEndpoint(index) 83 if err != nil { 84 t.Fatal(err) 85 } 86 return endpoint 87 } 88 89 assertInsecureIndex := func(index *IndexInfo) { 90 index.Secure = true 91 _, err := NewEndpoint(index) 92 assertNotEqual(t, err, nil, index.Name+": Expected error for insecure index") 93 assertEqual(t, strings.Contains(err.Error(), "insecure-registry"), true, index.Name+": Expected insecure-registry error for insecure index") 94 index.Secure = false 95 } 96 97 assertSecureIndex := func(index *IndexInfo) { 98 index.Secure = true 99 _, err := NewEndpoint(index) 100 assertNotEqual(t, err, nil, index.Name+": Expected cert error for secure index") 101 assertEqual(t, strings.Contains(err.Error(), "certificate signed by unknown authority"), true, index.Name+": Expected cert error for secure index") 102 index.Secure = false 103 } 104 105 index := &IndexInfo{} 106 index.Name = makeURL("/v1/") 107 endpoint := expandEndpoint(index) 108 assertEqual(t, endpoint.String(), index.Name, "Expected endpoint to be "+index.Name) 109 if endpoint.Version != APIVersion1 { 110 t.Fatal("Expected endpoint to be v1") 111 } 112 assertInsecureIndex(index) 113 114 index.Name = makeURL("") 115 endpoint = expandEndpoint(index) 116 assertEqual(t, endpoint.String(), index.Name+"/v1/", index.Name+": Expected endpoint to be "+index.Name+"/v1/") 117 if endpoint.Version != APIVersion1 { 118 t.Fatal("Expected endpoint to be v1") 119 } 120 assertInsecureIndex(index) 121 122 httpURL := makeURL("") 123 index.Name = strings.SplitN(httpURL, "://", 2)[1] 124 endpoint = expandEndpoint(index) 125 assertEqual(t, endpoint.String(), httpURL+"/v1/", index.Name+": Expected endpoint to be "+httpURL+"/v1/") 126 if endpoint.Version != APIVersion1 { 127 t.Fatal("Expected endpoint to be v1") 128 } 129 assertInsecureIndex(index) 130 131 index.Name = makeHttpsURL("/v1/") 132 endpoint = expandEndpoint(index) 133 assertEqual(t, endpoint.String(), index.Name, "Expected endpoint to be "+index.Name) 134 if endpoint.Version != APIVersion1 { 135 t.Fatal("Expected endpoint to be v1") 136 } 137 assertSecureIndex(index) 138 139 index.Name = makeHttpsURL("") 140 endpoint = expandEndpoint(index) 141 assertEqual(t, endpoint.String(), index.Name+"/v1/", index.Name+": Expected endpoint to be "+index.Name+"/v1/") 142 if endpoint.Version != APIVersion1 { 143 t.Fatal("Expected endpoint to be v1") 144 } 145 assertSecureIndex(index) 146 147 httpsURL := makeHttpsURL("") 148 index.Name = strings.SplitN(httpsURL, "://", 2)[1] 149 endpoint = expandEndpoint(index) 150 assertEqual(t, endpoint.String(), httpsURL+"/v1/", index.Name+": Expected endpoint to be "+httpsURL+"/v1/") 151 if endpoint.Version != APIVersion1 { 152 t.Fatal("Expected endpoint to be v1") 153 } 154 assertSecureIndex(index) 155 156 badEndpoints := []string{ 157 "http://127.0.0.1/v1/", 158 "https://127.0.0.1/v1/", 159 "http://127.0.0.1", 160 "https://127.0.0.1", 161 "127.0.0.1", 162 } 163 for _, address := range badEndpoints { 164 index.Name = address 165 _, err := NewEndpoint(index) 166 checkNotEqual(t, err, nil, "Expected error while expanding bad endpoint") 167 } 168 } 169 170 func TestGetRemoteHistory(t *testing.T) { 171 r := spawnTestRegistrySession(t) 172 hist, err := r.GetRemoteHistory(imageID, makeURL("/v1/"), token) 173 if err != nil { 174 t.Fatal(err) 175 } 176 assertEqual(t, len(hist), 2, "Expected 2 images in history") 177 assertEqual(t, hist[0], imageID, "Expected "+imageID+"as first ancestry") 178 assertEqual(t, hist[1], "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20", 179 "Unexpected second ancestry") 180 } 181 182 func TestLookupRemoteImage(t *testing.T) { 183 r := spawnTestRegistrySession(t) 184 err := r.LookupRemoteImage(imageID, makeURL("/v1/"), token) 185 assertEqual(t, err, nil, "Expected error of remote lookup to nil") 186 if err := r.LookupRemoteImage("abcdef", makeURL("/v1/"), token); err == nil { 187 t.Fatal("Expected error of remote lookup to not nil") 188 } 189 } 190 191 func TestGetRemoteImageJSON(t *testing.T) { 192 r := spawnTestRegistrySession(t) 193 json, size, err := r.GetRemoteImageJSON(imageID, makeURL("/v1/"), token) 194 if err != nil { 195 t.Fatal(err) 196 } 197 assertEqual(t, size, 154, "Expected size 154") 198 if len(json) <= 0 { 199 t.Fatal("Expected non-empty json") 200 } 201 202 _, _, err = r.GetRemoteImageJSON("abcdef", makeURL("/v1/"), token) 203 if err == nil { 204 t.Fatal("Expected image not found error") 205 } 206 } 207 208 func TestGetRemoteImageLayer(t *testing.T) { 209 r := spawnTestRegistrySession(t) 210 data, err := r.GetRemoteImageLayer(imageID, makeURL("/v1/"), token, 0) 211 if err != nil { 212 t.Fatal(err) 213 } 214 if data == nil { 215 t.Fatal("Expected non-nil data result") 216 } 217 218 _, err = r.GetRemoteImageLayer("abcdef", makeURL("/v1/"), token, 0) 219 if err == nil { 220 t.Fatal("Expected image not found error") 221 } 222 } 223 224 func TestGetRemoteTags(t *testing.T) { 225 r := spawnTestRegistrySession(t) 226 tags, err := r.GetRemoteTags([]string{makeURL("/v1/")}, REPO, token) 227 if err != nil { 228 t.Fatal(err) 229 } 230 assertEqual(t, len(tags), 1, "Expected one tag") 231 assertEqual(t, tags["latest"], imageID, "Expected tag latest to map to "+imageID) 232 233 _, err = r.GetRemoteTags([]string{makeURL("/v1/")}, "foo42/baz", token) 234 if err == nil { 235 t.Fatal("Expected error when fetching tags for bogus repo") 236 } 237 } 238 239 func TestGetRepositoryData(t *testing.T) { 240 r := spawnTestRegistrySession(t) 241 parsedURL, err := url.Parse(makeURL("/v1/")) 242 if err != nil { 243 t.Fatal(err) 244 } 245 host := "http://" + parsedURL.Host + "/v1/" 246 data, err := r.GetRepositoryData("foo42/bar") 247 if err != nil { 248 t.Fatal(err) 249 } 250 assertEqual(t, len(data.ImgList), 2, "Expected 2 images in ImgList") 251 assertEqual(t, len(data.Endpoints), 2, 252 fmt.Sprintf("Expected 2 endpoints in Endpoints, found %d instead", len(data.Endpoints))) 253 assertEqual(t, data.Endpoints[0], host, 254 fmt.Sprintf("Expected first endpoint to be %s but found %s instead", host, data.Endpoints[0])) 255 assertEqual(t, data.Endpoints[1], "http://test.example.com/v1/", 256 fmt.Sprintf("Expected first endpoint to be http://test.example.com/v1/ but found %s instead", data.Endpoints[1])) 257 258 } 259 260 func TestPushImageJSONRegistry(t *testing.T) { 261 r := spawnTestRegistrySession(t) 262 imgData := &ImgData{ 263 ID: "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20", 264 Checksum: "sha256:1ac330d56e05eef6d438586545ceff7550d3bdcb6b19961f12c5ba714ee1bb37", 265 } 266 267 err := r.PushImageJSONRegistry(imgData, []byte{0x42, 0xdf, 0x0}, makeURL("/v1/"), token) 268 if err != nil { 269 t.Fatal(err) 270 } 271 } 272 273 func TestPushImageLayerRegistry(t *testing.T) { 274 r := spawnTestRegistrySession(t) 275 layer := strings.NewReader("") 276 _, _, err := r.PushImageLayerRegistry(imageID, layer, makeURL("/v1/"), token, []byte{}) 277 if err != nil { 278 t.Fatal(err) 279 } 280 } 281 282 func TestValidateRepositoryName(t *testing.T) { 283 validRepoNames := []string{ 284 "docker/docker", 285 "library/debian", 286 "debian", 287 "docker.io/docker/docker", 288 "docker.io/library/debian", 289 "docker.io/debian", 290 "index.docker.io/docker/docker", 291 "index.docker.io/library/debian", 292 "index.docker.io/debian", 293 "127.0.0.1:5000/docker/docker", 294 "127.0.0.1:5000/library/debian", 295 "127.0.0.1:5000/debian", 296 "thisisthesongthatneverendsitgoesonandonandonthisisthesongthatnev", 297 } 298 invalidRepoNames := []string{ 299 "https://github.com/docker/docker", 300 "docker/Docker", 301 "docker///docker", 302 "docker.io/docker/Docker", 303 "docker.io/docker///docker", 304 "1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a", 305 "docker.io/1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a", 306 } 307 308 for _, name := range invalidRepoNames { 309 err := ValidateRepositoryName(name) 310 assertNotEqual(t, err, nil, "Expected invalid repo name: "+name) 311 } 312 313 for _, name := range validRepoNames { 314 err := ValidateRepositoryName(name) 315 assertEqual(t, err, nil, "Expected valid repo name: "+name) 316 } 317 318 err := ValidateRepositoryName(invalidRepoNames[0]) 319 assertEqual(t, err, ErrInvalidRepositoryName, "Expected ErrInvalidRepositoryName: "+invalidRepoNames[0]) 320 } 321 322 func TestParseRepositoryInfo(t *testing.T) { 323 expectedRepoInfos := map[string]RepositoryInfo{ 324 "fooo/bar": { 325 Index: &IndexInfo{ 326 Name: IndexServerName(), 327 Official: true, 328 }, 329 RemoteName: "fooo/bar", 330 LocalName: "fooo/bar", 331 CanonicalName: "fooo/bar", 332 Official: false, 333 }, 334 "library/ubuntu": { 335 Index: &IndexInfo{ 336 Name: IndexServerName(), 337 Official: true, 338 }, 339 RemoteName: "library/ubuntu", 340 LocalName: "ubuntu", 341 CanonicalName: "ubuntu", 342 Official: true, 343 }, 344 "nonlibrary/ubuntu": { 345 Index: &IndexInfo{ 346 Name: IndexServerName(), 347 Official: true, 348 }, 349 RemoteName: "nonlibrary/ubuntu", 350 LocalName: "nonlibrary/ubuntu", 351 CanonicalName: "nonlibrary/ubuntu", 352 Official: false, 353 }, 354 "ubuntu": { 355 Index: &IndexInfo{ 356 Name: IndexServerName(), 357 Official: true, 358 }, 359 RemoteName: "library/ubuntu", 360 LocalName: "ubuntu", 361 CanonicalName: "ubuntu", 362 Official: true, 363 }, 364 "other/library": { 365 Index: &IndexInfo{ 366 Name: IndexServerName(), 367 Official: true, 368 }, 369 RemoteName: "other/library", 370 LocalName: "other/library", 371 CanonicalName: "other/library", 372 Official: false, 373 }, 374 "127.0.0.1:8000/private/moonbase": { 375 Index: &IndexInfo{ 376 Name: "127.0.0.1:8000", 377 Official: false, 378 }, 379 RemoteName: "private/moonbase", 380 LocalName: "127.0.0.1:8000/private/moonbase", 381 CanonicalName: "127.0.0.1:8000/private/moonbase", 382 Official: false, 383 }, 384 "127.0.0.1:8000/privatebase": { 385 Index: &IndexInfo{ 386 Name: "127.0.0.1:8000", 387 Official: false, 388 }, 389 RemoteName: "privatebase", 390 LocalName: "127.0.0.1:8000/privatebase", 391 CanonicalName: "127.0.0.1:8000/privatebase", 392 Official: false, 393 }, 394 "localhost:8000/private/moonbase": { 395 Index: &IndexInfo{ 396 Name: "localhost:8000", 397 Official: false, 398 }, 399 RemoteName: "private/moonbase", 400 LocalName: "localhost:8000/private/moonbase", 401 CanonicalName: "localhost:8000/private/moonbase", 402 Official: false, 403 }, 404 "localhost:8000/privatebase": { 405 Index: &IndexInfo{ 406 Name: "localhost:8000", 407 Official: false, 408 }, 409 RemoteName: "privatebase", 410 LocalName: "localhost:8000/privatebase", 411 CanonicalName: "localhost:8000/privatebase", 412 Official: false, 413 }, 414 "example.com/private/moonbase": { 415 Index: &IndexInfo{ 416 Name: "example.com", 417 Official: false, 418 }, 419 RemoteName: "private/moonbase", 420 LocalName: "example.com/private/moonbase", 421 CanonicalName: "example.com/private/moonbase", 422 Official: false, 423 }, 424 "example.com/privatebase": { 425 Index: &IndexInfo{ 426 Name: "example.com", 427 Official: false, 428 }, 429 RemoteName: "privatebase", 430 LocalName: "example.com/privatebase", 431 CanonicalName: "example.com/privatebase", 432 Official: false, 433 }, 434 "example.com:8000/private/moonbase": { 435 Index: &IndexInfo{ 436 Name: "example.com:8000", 437 Official: false, 438 }, 439 RemoteName: "private/moonbase", 440 LocalName: "example.com:8000/private/moonbase", 441 CanonicalName: "example.com:8000/private/moonbase", 442 Official: false, 443 }, 444 "example.com:8000/privatebase": { 445 Index: &IndexInfo{ 446 Name: "example.com:8000", 447 Official: false, 448 }, 449 RemoteName: "privatebase", 450 LocalName: "example.com:8000/privatebase", 451 CanonicalName: "example.com:8000/privatebase", 452 Official: false, 453 }, 454 "localhost/private/moonbase": { 455 Index: &IndexInfo{ 456 Name: "localhost", 457 Official: false, 458 }, 459 RemoteName: "private/moonbase", 460 LocalName: "localhost/private/moonbase", 461 CanonicalName: "localhost/private/moonbase", 462 Official: false, 463 }, 464 "localhost/privatebase": { 465 Index: &IndexInfo{ 466 Name: "localhost", 467 Official: false, 468 }, 469 RemoteName: "privatebase", 470 LocalName: "localhost/privatebase", 471 CanonicalName: "localhost/privatebase", 472 Official: false, 473 }, 474 IndexServerName() + "/public/moonbase": { 475 Index: &IndexInfo{ 476 Name: IndexServerName(), 477 Official: true, 478 }, 479 RemoteName: "public/moonbase", 480 LocalName: "public/moonbase", 481 CanonicalName: "public/moonbase", 482 Official: false, 483 }, 484 "index." + IndexServerName() + "/public/moonbase": { 485 Index: &IndexInfo{ 486 Name: IndexServerName(), 487 Official: true, 488 }, 489 RemoteName: "public/moonbase", 490 LocalName: "public/moonbase", 491 CanonicalName: "public/moonbase", 492 Official: false, 493 }, 494 IndexServerName() + "/public/moonbase": { 495 Index: &IndexInfo{ 496 Name: IndexServerName(), 497 Official: true, 498 }, 499 RemoteName: "public/moonbase", 500 LocalName: "public/moonbase", 501 CanonicalName: "public/moonbase", 502 Official: false, 503 }, 504 "ubuntu-12.04-base": { 505 Index: &IndexInfo{ 506 Name: IndexServerName(), 507 Official: true, 508 }, 509 RemoteName: "library/ubuntu-12.04-base", 510 LocalName: "ubuntu-12.04-base", 511 CanonicalName: "ubuntu-12.04-base", 512 Official: true, 513 }, 514 IndexServerName() + "/ubuntu-12.04-base": { 515 Index: &IndexInfo{ 516 Name: IndexServerName(), 517 Official: true, 518 }, 519 RemoteName: "library/ubuntu-12.04-base", 520 LocalName: "ubuntu-12.04-base", 521 CanonicalName: "ubuntu-12.04-base", 522 Official: true, 523 }, 524 IndexServerName() + "/ubuntu-12.04-base": { 525 Index: &IndexInfo{ 526 Name: IndexServerName(), 527 Official: true, 528 }, 529 RemoteName: "library/ubuntu-12.04-base", 530 LocalName: "ubuntu-12.04-base", 531 CanonicalName: "ubuntu-12.04-base", 532 Official: true, 533 }, 534 "index." + IndexServerName() + "/ubuntu-12.04-base": { 535 Index: &IndexInfo{ 536 Name: IndexServerName(), 537 Official: true, 538 }, 539 RemoteName: "library/ubuntu-12.04-base", 540 LocalName: "ubuntu-12.04-base", 541 CanonicalName: "ubuntu-12.04-base", 542 Official: true, 543 }, 544 } 545 546 for reposName, expectedRepoInfo := range expectedRepoInfos { 547 repoInfo, err := ParseRepositoryInfo(reposName) 548 if err != nil { 549 t.Error(err) 550 } else { 551 checkEqual(t, repoInfo.Index.Name, expectedRepoInfo.Index.Name, reposName) 552 checkEqual(t, repoInfo.RemoteName, expectedRepoInfo.RemoteName, reposName) 553 checkEqual(t, repoInfo.LocalName, expectedRepoInfo.LocalName, reposName) 554 checkEqual(t, repoInfo.CanonicalName, expectedRepoInfo.CanonicalName, reposName) 555 checkEqual(t, repoInfo.Index.Official, expectedRepoInfo.Index.Official, reposName) 556 checkEqual(t, repoInfo.Official, expectedRepoInfo.Official, reposName) 557 } 558 } 559 } 560 561 func TestNewIndexInfo(t *testing.T) { 562 testIndexInfo := func(config *ServiceConfig, expectedIndexInfos map[string]*IndexInfo) { 563 for indexName, expectedIndexInfo := range expectedIndexInfos { 564 index, err := config.NewIndexInfo(indexName) 565 if err != nil { 566 t.Fatal(err) 567 } else { 568 checkEqual(t, index.Name, expectedIndexInfo.Name, indexName+" name") 569 checkEqual(t, index.Official, expectedIndexInfo.Official, indexName+" is official") 570 checkEqual(t, index.Secure, expectedIndexInfo.Secure, indexName+" is secure") 571 checkEqual(t, len(index.Mirrors), len(expectedIndexInfo.Mirrors), indexName+" mirrors") 572 } 573 } 574 } 575 576 config := NewServiceConfig(nil) 577 noMirrors := make([]string, 0) 578 expectedIndexInfos := map[string]*IndexInfo{ 579 IndexServerName(): { 580 Name: IndexServerName(), 581 Official: true, 582 Secure: true, 583 Mirrors: noMirrors, 584 }, 585 "index." + IndexServerName(): { 586 Name: IndexServerName(), 587 Official: true, 588 Secure: true, 589 Mirrors: noMirrors, 590 }, 591 "example.com": { 592 Name: "example.com", 593 Official: false, 594 Secure: true, 595 Mirrors: noMirrors, 596 }, 597 "127.0.0.1:5000": { 598 Name: "127.0.0.1:5000", 599 Official: false, 600 Secure: false, 601 Mirrors: noMirrors, 602 }, 603 } 604 testIndexInfo(config, expectedIndexInfos) 605 606 publicMirrors := []string{"http://mirror1.local", "http://mirror2.local"} 607 config = makeServiceConfig(publicMirrors, []string{"example.com"}) 608 609 expectedIndexInfos = map[string]*IndexInfo{ 610 IndexServerName(): { 611 Name: IndexServerName(), 612 Official: true, 613 Secure: true, 614 Mirrors: publicMirrors, 615 }, 616 "index." + IndexServerName(): { 617 Name: IndexServerName(), 618 Official: true, 619 Secure: true, 620 Mirrors: publicMirrors, 621 }, 622 "example.com": { 623 Name: "example.com", 624 Official: false, 625 Secure: false, 626 Mirrors: noMirrors, 627 }, 628 "example.com:5000": { 629 Name: "example.com:5000", 630 Official: false, 631 Secure: true, 632 Mirrors: noMirrors, 633 }, 634 "127.0.0.1": { 635 Name: "127.0.0.1", 636 Official: false, 637 Secure: false, 638 Mirrors: noMirrors, 639 }, 640 "127.0.0.1:5000": { 641 Name: "127.0.0.1:5000", 642 Official: false, 643 Secure: false, 644 Mirrors: noMirrors, 645 }, 646 "other.com": { 647 Name: "other.com", 648 Official: false, 649 Secure: true, 650 Mirrors: noMirrors, 651 }, 652 } 653 testIndexInfo(config, expectedIndexInfos) 654 655 config = makeServiceConfig(nil, []string{"42.42.0.0/16"}) 656 expectedIndexInfos = map[string]*IndexInfo{ 657 "example.com": { 658 Name: "example.com", 659 Official: false, 660 Secure: false, 661 Mirrors: noMirrors, 662 }, 663 "example.com:5000": { 664 Name: "example.com:5000", 665 Official: false, 666 Secure: false, 667 Mirrors: noMirrors, 668 }, 669 "127.0.0.1": { 670 Name: "127.0.0.1", 671 Official: false, 672 Secure: false, 673 Mirrors: noMirrors, 674 }, 675 "127.0.0.1:5000": { 676 Name: "127.0.0.1:5000", 677 Official: false, 678 Secure: false, 679 Mirrors: noMirrors, 680 }, 681 "other.com": { 682 Name: "other.com", 683 Official: false, 684 Secure: true, 685 Mirrors: noMirrors, 686 }, 687 } 688 testIndexInfo(config, expectedIndexInfos) 689 } 690 691 func TestPushRegistryTag(t *testing.T) { 692 r := spawnTestRegistrySession(t) 693 err := r.PushRegistryTag("foo42/bar", imageID, "stable", makeURL("/v1/"), token) 694 if err != nil { 695 t.Fatal(err) 696 } 697 } 698 699 func TestPushImageJSONIndex(t *testing.T) { 700 r := spawnTestRegistrySession(t) 701 imgData := []*ImgData{ 702 { 703 ID: "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20", 704 Checksum: "sha256:1ac330d56e05eef6d438586545ceff7550d3bdcb6b19961f12c5ba714ee1bb37", 705 }, 706 { 707 ID: "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d", 708 Checksum: "sha256:bea7bf2e4bacd479344b737328db47b18880d09096e6674165533aa994f5e9f2", 709 }, 710 } 711 repoData, err := r.PushImageJSONIndex("foo42/bar", imgData, false, nil) 712 if err != nil { 713 t.Fatal(err) 714 } 715 if repoData == nil { 716 t.Fatal("Expected RepositoryData object") 717 } 718 repoData, err = r.PushImageJSONIndex("foo42/bar", imgData, true, []string{r.indexEndpoint.String()}) 719 if err != nil { 720 t.Fatal(err) 721 } 722 if repoData == nil { 723 t.Fatal("Expected RepositoryData object") 724 } 725 } 726 727 func TestSearchRepositories(t *testing.T) { 728 r := spawnTestRegistrySession(t) 729 results, err := r.SearchRepositories("fakequery") 730 if err != nil { 731 t.Fatal(err) 732 } 733 if results == nil { 734 t.Fatal("Expected non-nil SearchResults object") 735 } 736 assertEqual(t, results.NumResults, 1, "Expected 1 search results") 737 assertEqual(t, results.Query, "fakequery", "Expected 'fakequery' as query") 738 assertEqual(t, results.Results[0].StarCount, 42, "Expected 'fakeimage' a ot hae 42 stars") 739 } 740 741 func TestValidRemoteName(t *testing.T) { 742 validRepositoryNames := []string{ 743 // Sanity check. 744 "docker/docker", 745 746 // Allow 64-character non-hexadecimal names (hexadecimal names are forbidden). 747 "thisisthesongthatneverendsitgoesonandonandonthisisthesongthatnev", 748 749 // Allow embedded hyphens. 750 "docker-rules/docker", 751 752 // Allow underscores everywhere (as opposed to hyphens). 753 "____/____", 754 } 755 for _, repositoryName := range validRepositoryNames { 756 if err := validateRemoteName(repositoryName); err != nil { 757 t.Errorf("Repository name should be valid: %v. Error: %v", repositoryName, err) 758 } 759 } 760 761 invalidRepositoryNames := []string{ 762 // Disallow capital letters. 763 "docker/Docker", 764 765 // Only allow one slash. 766 "docker///docker", 767 768 // Disallow 64-character hexadecimal. 769 "1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a", 770 771 // Disallow leading and trailing hyphens in namespace. 772 "-docker/docker", 773 "docker-/docker", 774 "-docker-/docker", 775 776 // Disallow consecutive hyphens. 777 "dock--er/docker", 778 779 // Namespace too short. 780 "doc/docker", 781 782 // No repository. 783 "docker/", 784 } 785 for _, repositoryName := range invalidRepositoryNames { 786 if err := validateRemoteName(repositoryName); err == nil { 787 t.Errorf("Repository name should be invalid: %v", repositoryName) 788 } 789 } 790 } 791 792 func TestTrustedLocation(t *testing.T) { 793 for _, url := range []string{"http://example.com", "https://example.com:7777", "http://docker.io", "http://test.docker.com", "https://fakedocker.com"} { 794 req, _ := http.NewRequest("GET", url, nil) 795 if trustedLocation(req) == true { 796 t.Fatalf("'%s' shouldn't be detected as a trusted location", url) 797 } 798 } 799 800 for _, url := range []string{"https://docker.io", "https://test.docker.com:80"} { 801 req, _ := http.NewRequest("GET", url, nil) 802 if trustedLocation(req) == false { 803 t.Fatalf("'%s' should be detected as a trusted location", url) 804 } 805 } 806 } 807 808 func TestAddRequiredHeadersToRedirectedRequests(t *testing.T) { 809 for _, urls := range [][]string{ 810 {"http://docker.io", "https://docker.com"}, 811 {"https://foo.docker.io:7777", "http://bar.docker.com"}, 812 {"https://foo.docker.io", "https://example.com"}, 813 } { 814 reqFrom, _ := http.NewRequest("GET", urls[0], nil) 815 reqFrom.Header.Add("Content-Type", "application/json") 816 reqFrom.Header.Add("Authorization", "super_secret") 817 reqTo, _ := http.NewRequest("GET", urls[1], nil) 818 819 AddRequiredHeadersToRedirectedRequests(reqTo, []*http.Request{reqFrom}) 820 821 if len(reqTo.Header) != 1 { 822 t.Fatalf("Expected 1 headers, got %d", len(reqTo.Header)) 823 } 824 825 if reqTo.Header.Get("Content-Type") != "application/json" { 826 t.Fatal("'Content-Type' should be 'application/json'") 827 } 828 829 if reqTo.Header.Get("Authorization") != "" { 830 t.Fatal("'Authorization' should be empty") 831 } 832 } 833 834 for _, urls := range [][]string{ 835 {"https://docker.io", "https://docker.com"}, 836 {"https://foo.docker.io:7777", "https://bar.docker.com"}, 837 } { 838 reqFrom, _ := http.NewRequest("GET", urls[0], nil) 839 reqFrom.Header.Add("Content-Type", "application/json") 840 reqFrom.Header.Add("Authorization", "super_secret") 841 reqTo, _ := http.NewRequest("GET", urls[1], nil) 842 843 AddRequiredHeadersToRedirectedRequests(reqTo, []*http.Request{reqFrom}) 844 845 if len(reqTo.Header) != 2 { 846 t.Fatalf("Expected 2 headers, got %d", len(reqTo.Header)) 847 } 848 849 if reqTo.Header.Get("Content-Type") != "application/json" { 850 t.Fatal("'Content-Type' should be 'application/json'") 851 } 852 853 if reqTo.Header.Get("Authorization") != "super_secret" { 854 t.Fatal("'Authorization' should be 'super_secret'") 855 } 856 } 857 } 858 859 func TestIsSecureIndex(t *testing.T) { 860 tests := []struct { 861 addr string 862 insecureRegistries []string 863 expected bool 864 }{ 865 {IndexServerName(), nil, true}, 866 {"example.com", []string{}, true}, 867 {"example.com", []string{"example.com"}, false}, 868 {"localhost", []string{"localhost:5000"}, false}, 869 {"localhost:5000", []string{"localhost:5000"}, false}, 870 {"localhost", []string{"example.com"}, false}, 871 {"127.0.0.1:5000", []string{"127.0.0.1:5000"}, false}, 872 {"localhost", nil, false}, 873 {"localhost:5000", nil, false}, 874 {"127.0.0.1", nil, false}, 875 {"localhost", []string{"example.com"}, false}, 876 {"127.0.0.1", []string{"example.com"}, false}, 877 {"example.com", nil, true}, 878 {"example.com", []string{"example.com"}, false}, 879 {"127.0.0.1", []string{"example.com"}, false}, 880 {"127.0.0.1:5000", []string{"example.com"}, false}, 881 {"example.com:5000", []string{"42.42.0.0/16"}, false}, 882 {"example.com", []string{"42.42.0.0/16"}, false}, 883 {"example.com:5000", []string{"42.42.42.42/8"}, false}, 884 {"127.0.0.1:5000", []string{"127.0.0.0/8"}, false}, 885 {"42.42.42.42:5000", []string{"42.1.1.1/8"}, false}, 886 {"invalid.domain.com", []string{"42.42.0.0/16"}, true}, 887 {"invalid.domain.com", []string{"invalid.domain.com"}, false}, 888 {"invalid.domain.com:5000", []string{"invalid.domain.com"}, true}, 889 {"invalid.domain.com:5000", []string{"invalid.domain.com:5000"}, false}, 890 } 891 for _, tt := range tests { 892 config := makeServiceConfig(nil, tt.insecureRegistries) 893 if sec := config.isSecureIndex(tt.addr); sec != tt.expected { 894 t.Errorf("isSecureIndex failed for %q %v, expected %v got %v", tt.addr, tt.insecureRegistries, tt.expected, sec) 895 } 896 } 897 }