github.com/stchris/docker@v1.4.2-0.20150106053530-1510a324dbd5/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(makeURL("/v1/"), insecureRegistries) 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 TestPingRegistryEndpoint(t *testing.T) { 36 ep, err := NewEndpoint(makeURL("/v1/"), insecureRegistries) 37 if err != nil { 38 t.Fatal(err) 39 } 40 regInfo, err := ep.Ping() 41 if err != nil { 42 t.Fatal(err) 43 } 44 assertEqual(t, regInfo.Standalone, true, "Expected standalone to be true (default)") 45 } 46 47 func TestGetRemoteHistory(t *testing.T) { 48 r := spawnTestRegistrySession(t) 49 hist, err := r.GetRemoteHistory(imageID, makeURL("/v1/"), token) 50 if err != nil { 51 t.Fatal(err) 52 } 53 assertEqual(t, len(hist), 2, "Expected 2 images in history") 54 assertEqual(t, hist[0], imageID, "Expected "+imageID+"as first ancestry") 55 assertEqual(t, hist[1], "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20", 56 "Unexpected second ancestry") 57 } 58 59 func TestLookupRemoteImage(t *testing.T) { 60 r := spawnTestRegistrySession(t) 61 err := r.LookupRemoteImage(imageID, makeURL("/v1/"), token) 62 assertEqual(t, err, nil, "Expected error of remote lookup to nil") 63 if err := r.LookupRemoteImage("abcdef", makeURL("/v1/"), token); err == nil { 64 t.Fatal("Expected error of remote lookup to not nil") 65 } 66 } 67 68 func TestGetRemoteImageJSON(t *testing.T) { 69 r := spawnTestRegistrySession(t) 70 json, size, err := r.GetRemoteImageJSON(imageID, makeURL("/v1/"), token) 71 if err != nil { 72 t.Fatal(err) 73 } 74 assertEqual(t, size, 154, "Expected size 154") 75 if len(json) <= 0 { 76 t.Fatal("Expected non-empty json") 77 } 78 79 _, _, err = r.GetRemoteImageJSON("abcdef", makeURL("/v1/"), token) 80 if err == nil { 81 t.Fatal("Expected image not found error") 82 } 83 } 84 85 func TestGetRemoteImageLayer(t *testing.T) { 86 r := spawnTestRegistrySession(t) 87 data, err := r.GetRemoteImageLayer(imageID, makeURL("/v1/"), token, 0) 88 if err != nil { 89 t.Fatal(err) 90 } 91 if data == nil { 92 t.Fatal("Expected non-nil data result") 93 } 94 95 _, err = r.GetRemoteImageLayer("abcdef", makeURL("/v1/"), token, 0) 96 if err == nil { 97 t.Fatal("Expected image not found error") 98 } 99 } 100 101 func TestGetRemoteTags(t *testing.T) { 102 r := spawnTestRegistrySession(t) 103 tags, err := r.GetRemoteTags([]string{makeURL("/v1/")}, REPO, token) 104 if err != nil { 105 t.Fatal(err) 106 } 107 assertEqual(t, len(tags), 1, "Expected one tag") 108 assertEqual(t, tags["latest"], imageID, "Expected tag latest to map to "+imageID) 109 110 _, err = r.GetRemoteTags([]string{makeURL("/v1/")}, "foo42/baz", token) 111 if err == nil { 112 t.Fatal("Expected error when fetching tags for bogus repo") 113 } 114 } 115 116 func TestGetRepositoryData(t *testing.T) { 117 r := spawnTestRegistrySession(t) 118 parsedURL, err := url.Parse(makeURL("/v1/")) 119 if err != nil { 120 t.Fatal(err) 121 } 122 host := "http://" + parsedURL.Host + "/v1/" 123 data, err := r.GetRepositoryData("foo42/bar") 124 if err != nil { 125 t.Fatal(err) 126 } 127 assertEqual(t, len(data.ImgList), 2, "Expected 2 images in ImgList") 128 assertEqual(t, len(data.Endpoints), 2, 129 fmt.Sprintf("Expected 2 endpoints in Endpoints, found %d instead", len(data.Endpoints))) 130 assertEqual(t, data.Endpoints[0], host, 131 fmt.Sprintf("Expected first endpoint to be %s but found %s instead", host, data.Endpoints[0])) 132 assertEqual(t, data.Endpoints[1], "http://test.example.com/v1/", 133 fmt.Sprintf("Expected first endpoint to be http://test.example.com/v1/ but found %s instead", data.Endpoints[1])) 134 135 } 136 137 func TestPushImageJSONRegistry(t *testing.T) { 138 r := spawnTestRegistrySession(t) 139 imgData := &ImgData{ 140 ID: "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20", 141 Checksum: "sha256:1ac330d56e05eef6d438586545ceff7550d3bdcb6b19961f12c5ba714ee1bb37", 142 } 143 144 err := r.PushImageJSONRegistry(imgData, []byte{0x42, 0xdf, 0x0}, makeURL("/v1/"), token) 145 if err != nil { 146 t.Fatal(err) 147 } 148 } 149 150 func TestPushImageLayerRegistry(t *testing.T) { 151 r := spawnTestRegistrySession(t) 152 layer := strings.NewReader("") 153 _, _, err := r.PushImageLayerRegistry(imageID, layer, makeURL("/v1/"), token, []byte{}) 154 if err != nil { 155 t.Fatal(err) 156 } 157 } 158 159 func TestResolveRepositoryName(t *testing.T) { 160 _, _, err := ResolveRepositoryName("https://github.com/docker/docker") 161 assertEqual(t, err, ErrInvalidRepositoryName, "Expected error invalid repo name") 162 ep, repo, err := ResolveRepositoryName("fooo/bar") 163 if err != nil { 164 t.Fatal(err) 165 } 166 assertEqual(t, ep, IndexServerAddress(), "Expected endpoint to be index server address") 167 assertEqual(t, repo, "fooo/bar", "Expected resolved repo to be foo/bar") 168 169 u := makeURL("")[7:] 170 ep, repo, err = ResolveRepositoryName(u + "/private/moonbase") 171 if err != nil { 172 t.Fatal(err) 173 } 174 assertEqual(t, ep, u, "Expected endpoint to be "+u) 175 assertEqual(t, repo, "private/moonbase", "Expected endpoint to be private/moonbase") 176 177 ep, repo, err = ResolveRepositoryName("ubuntu-12.04-base") 178 if err != nil { 179 t.Fatal(err) 180 } 181 assertEqual(t, ep, IndexServerAddress(), "Expected endpoint to be "+IndexServerAddress()) 182 assertEqual(t, repo, "ubuntu-12.04-base", "Expected endpoint to be ubuntu-12.04-base") 183 } 184 185 func TestPushRegistryTag(t *testing.T) { 186 r := spawnTestRegistrySession(t) 187 err := r.PushRegistryTag("foo42/bar", imageID, "stable", makeURL("/v1/"), token) 188 if err != nil { 189 t.Fatal(err) 190 } 191 } 192 193 func TestPushImageJSONIndex(t *testing.T) { 194 r := spawnTestRegistrySession(t) 195 imgData := []*ImgData{ 196 { 197 ID: "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20", 198 Checksum: "sha256:1ac330d56e05eef6d438586545ceff7550d3bdcb6b19961f12c5ba714ee1bb37", 199 }, 200 { 201 ID: "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d", 202 Checksum: "sha256:bea7bf2e4bacd479344b737328db47b18880d09096e6674165533aa994f5e9f2", 203 }, 204 } 205 repoData, err := r.PushImageJSONIndex("foo42/bar", imgData, false, nil) 206 if err != nil { 207 t.Fatal(err) 208 } 209 if repoData == nil { 210 t.Fatal("Expected RepositoryData object") 211 } 212 repoData, err = r.PushImageJSONIndex("foo42/bar", imgData, true, []string{r.indexEndpoint.String()}) 213 if err != nil { 214 t.Fatal(err) 215 } 216 if repoData == nil { 217 t.Fatal("Expected RepositoryData object") 218 } 219 } 220 221 func TestSearchRepositories(t *testing.T) { 222 r := spawnTestRegistrySession(t) 223 results, err := r.SearchRepositories("fakequery") 224 if err != nil { 225 t.Fatal(err) 226 } 227 if results == nil { 228 t.Fatal("Expected non-nil SearchResults object") 229 } 230 assertEqual(t, results.NumResults, 1, "Expected 1 search results") 231 assertEqual(t, results.Query, "fakequery", "Expected 'fakequery' as query") 232 assertEqual(t, results.Results[0].StarCount, 42, "Expected 'fakeimage' a ot hae 42 stars") 233 } 234 235 func TestValidRepositoryName(t *testing.T) { 236 validRepositoryNames := []string{ 237 // Sanity check. 238 "docker/docker", 239 240 // Allow 64-character non-hexadecimal names (hexadecimal names are forbidden). 241 "thisisthesongthatneverendsitgoesonandonandonthisisthesongthatnev", 242 243 // Allow embedded hyphens. 244 "docker-rules/docker", 245 246 // Allow underscores everywhere (as opposed to hyphens). 247 "____/____", 248 } 249 for _, repositoryName := range validRepositoryNames { 250 if err := validateRepositoryName(repositoryName); err != nil { 251 t.Errorf("Repository name should be valid: %v. Error: %v", repositoryName, err) 252 } 253 } 254 255 invalidRepositoryNames := []string{ 256 // Disallow capital letters. 257 "docker/Docker", 258 259 // Only allow one slash. 260 "docker///docker", 261 262 // Disallow 64-character hexadecimal. 263 "1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a", 264 265 // Disallow leading and trailing hyphens in namespace. 266 "-docker/docker", 267 "docker-/docker", 268 "-docker-/docker", 269 270 // Disallow consecutive hyphens. 271 "dock--er/docker", 272 273 // Namespace too short. 274 "doc/docker", 275 276 // No repository. 277 "docker/", 278 } 279 for _, repositoryName := range invalidRepositoryNames { 280 if err := validateRepositoryName(repositoryName); err == nil { 281 t.Errorf("Repository name should be invalid: %v", repositoryName) 282 } 283 } 284 } 285 286 func TestTrustedLocation(t *testing.T) { 287 for _, url := range []string{"http://example.com", "https://example.com:7777", "http://docker.io", "http://test.docker.com", "https://fakedocker.com"} { 288 req, _ := http.NewRequest("GET", url, nil) 289 if trustedLocation(req) == true { 290 t.Fatalf("'%s' shouldn't be detected as a trusted location", url) 291 } 292 } 293 294 for _, url := range []string{"https://docker.io", "https://test.docker.com:80"} { 295 req, _ := http.NewRequest("GET", url, nil) 296 if trustedLocation(req) == false { 297 t.Fatalf("'%s' should be detected as a trusted location", url) 298 } 299 } 300 } 301 302 func TestAddRequiredHeadersToRedirectedRequests(t *testing.T) { 303 for _, urls := range [][]string{ 304 {"http://docker.io", "https://docker.com"}, 305 {"https://foo.docker.io:7777", "http://bar.docker.com"}, 306 {"https://foo.docker.io", "https://example.com"}, 307 } { 308 reqFrom, _ := http.NewRequest("GET", urls[0], nil) 309 reqFrom.Header.Add("Content-Type", "application/json") 310 reqFrom.Header.Add("Authorization", "super_secret") 311 reqTo, _ := http.NewRequest("GET", urls[1], nil) 312 313 AddRequiredHeadersToRedirectedRequests(reqTo, []*http.Request{reqFrom}) 314 315 if len(reqTo.Header) != 1 { 316 t.Fatalf("Expected 1 headers, got %d", len(reqTo.Header)) 317 } 318 319 if reqTo.Header.Get("Content-Type") != "application/json" { 320 t.Fatal("'Content-Type' should be 'application/json'") 321 } 322 323 if reqTo.Header.Get("Authorization") != "" { 324 t.Fatal("'Authorization' should be empty") 325 } 326 } 327 328 for _, urls := range [][]string{ 329 {"https://docker.io", "https://docker.com"}, 330 {"https://foo.docker.io:7777", "https://bar.docker.com"}, 331 } { 332 reqFrom, _ := http.NewRequest("GET", urls[0], nil) 333 reqFrom.Header.Add("Content-Type", "application/json") 334 reqFrom.Header.Add("Authorization", "super_secret") 335 reqTo, _ := http.NewRequest("GET", urls[1], nil) 336 337 AddRequiredHeadersToRedirectedRequests(reqTo, []*http.Request{reqFrom}) 338 339 if len(reqTo.Header) != 2 { 340 t.Fatalf("Expected 2 headers, got %d", len(reqTo.Header)) 341 } 342 343 if reqTo.Header.Get("Content-Type") != "application/json" { 344 t.Fatal("'Content-Type' should be 'application/json'") 345 } 346 347 if reqTo.Header.Get("Authorization") != "super_secret" { 348 t.Fatal("'Authorization' should be 'super_secret'") 349 } 350 } 351 } 352 353 func TestIsSecure(t *testing.T) { 354 tests := []struct { 355 addr string 356 insecureRegistries []string 357 expected bool 358 }{ 359 {IndexServerURL.Host, nil, true}, 360 {"example.com", []string{}, true}, 361 {"example.com", []string{"example.com"}, false}, 362 {"localhost", []string{"localhost:5000"}, false}, 363 {"localhost:5000", []string{"localhost:5000"}, false}, 364 {"localhost", []string{"example.com"}, false}, 365 {"127.0.0.1:5000", []string{"127.0.0.1:5000"}, false}, 366 {"localhost", nil, false}, 367 {"localhost:5000", nil, false}, 368 {"127.0.0.1", nil, false}, 369 {"localhost", []string{"example.com"}, false}, 370 {"127.0.0.1", []string{"example.com"}, false}, 371 {"example.com", nil, true}, 372 {"example.com", []string{"example.com"}, false}, 373 {"127.0.0.1", []string{"example.com"}, false}, 374 {"127.0.0.1:5000", []string{"example.com"}, false}, 375 {"example.com:5000", []string{"42.42.0.0/16"}, false}, 376 {"example.com", []string{"42.42.0.0/16"}, false}, 377 {"example.com:5000", []string{"42.42.42.42/8"}, false}, 378 {"127.0.0.1:5000", []string{"127.0.0.0/8"}, false}, 379 {"42.42.42.42:5000", []string{"42.1.1.1/8"}, false}, 380 {"invalid.domain.com", []string{"42.42.0.0/16"}, true}, 381 {"invalid.domain.com", []string{"invalid.domain.com"}, false}, 382 {"invalid.domain.com:5000", []string{"invalid.domain.com"}, true}, 383 {"invalid.domain.com:5000", []string{"invalid.domain.com:5000"}, false}, 384 } 385 for _, tt := range tests { 386 // TODO: remove this once we remove localhost insecure by default 387 insecureRegistries := append(tt.insecureRegistries, "127.0.0.0/8") 388 if sec, err := isSecure(tt.addr, insecureRegistries); err != nil || sec != tt.expected { 389 t.Fatalf("isSecure failed for %q %v, expected %v got %v. Error: %v", tt.addr, insecureRegistries, tt.expected, sec, err) 390 } 391 } 392 }