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