github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/reference/store_test.go (about) 1 package reference 2 3 import ( 4 "bytes" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "strings" 9 "testing" 10 11 "github.com/docker/distribution/reference" 12 "github.com/opencontainers/go-digest" 13 ) 14 15 var ( 16 saveLoadTestCases = map[string]digest.Digest{ 17 "registry:5000/foobar:HEAD": "sha256:470022b8af682154f57a2163d030eb369549549cba00edc69e1b99b46bb924d6", 18 "registry:5000/foobar:alternate": "sha256:ae300ebc4a4f00693702cfb0a5e0b7bc527b353828dc86ad09fb95c8a681b793", 19 "registry:5000/foobar:latest": "sha256:6153498b9ac00968d71b66cca4eac37e990b5f9eb50c26877eb8799c8847451b", 20 "registry:5000/foobar:master": "sha256:6c9917af4c4e05001b346421959d7ea81b6dc9d25718466a37a6add865dfd7fc", 21 "jess/hollywood:latest": "sha256:ae7a5519a0a55a2d4ef20ddcbd5d0ca0888a1f7ab806acc8e2a27baf46f529fe", 22 "registry@sha256:367eb40fd0330a7e464777121e39d2f5b3e8e23a1e159342e53ab05c9e4d94e6": "sha256:24126a56805beb9711be5f4590cc2eb55ab8d4a85ebd618eed72bb19fc50631c", 23 "busybox:latest": "sha256:91e54dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c", 24 } 25 26 marshalledSaveLoadTestCases = []byte(`{"Repositories":{"busybox":{"busybox:latest":"sha256:91e54dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c"},"jess/hollywood":{"jess/hollywood:latest":"sha256:ae7a5519a0a55a2d4ef20ddcbd5d0ca0888a1f7ab806acc8e2a27baf46f529fe"},"registry":{"registry@sha256:367eb40fd0330a7e464777121e39d2f5b3e8e23a1e159342e53ab05c9e4d94e6":"sha256:24126a56805beb9711be5f4590cc2eb55ab8d4a85ebd618eed72bb19fc50631c"},"registry:5000/foobar":{"registry:5000/foobar:HEAD":"sha256:470022b8af682154f57a2163d030eb369549549cba00edc69e1b99b46bb924d6","registry:5000/foobar:alternate":"sha256:ae300ebc4a4f00693702cfb0a5e0b7bc527b353828dc86ad09fb95c8a681b793","registry:5000/foobar:latest":"sha256:6153498b9ac00968d71b66cca4eac37e990b5f9eb50c26877eb8799c8847451b","registry:5000/foobar:master":"sha256:6c9917af4c4e05001b346421959d7ea81b6dc9d25718466a37a6add865dfd7fc"}}}`) 27 ) 28 29 func TestLoad(t *testing.T) { 30 jsonFile, err := ioutil.TempFile("", "tag-store-test") 31 if err != nil { 32 t.Fatalf("error creating temp file: %v", err) 33 } 34 defer os.RemoveAll(jsonFile.Name()) 35 36 // Write canned json to the temp file 37 _, err = jsonFile.Write(marshalledSaveLoadTestCases) 38 if err != nil { 39 t.Fatalf("error writing to temp file: %v", err) 40 } 41 jsonFile.Close() 42 43 store, err := NewReferenceStore(jsonFile.Name()) 44 if err != nil { 45 t.Fatalf("error creating tag store: %v", err) 46 } 47 48 for refStr, expectedID := range saveLoadTestCases { 49 ref, err := reference.ParseNormalizedNamed(refStr) 50 if err != nil { 51 t.Fatalf("failed to parse reference: %v", err) 52 } 53 id, err := store.Get(ref) 54 if err != nil { 55 t.Fatalf("could not find reference %s: %v", refStr, err) 56 } 57 if id != expectedID { 58 t.Fatalf("expected %s - got %s", expectedID, id) 59 } 60 } 61 } 62 63 func TestSave(t *testing.T) { 64 jsonFile, err := ioutil.TempFile("", "tag-store-test") 65 if err != nil { 66 t.Fatalf("error creating temp file: %v", err) 67 } 68 _, err = jsonFile.Write([]byte(`{}`)) 69 jsonFile.Close() 70 defer os.RemoveAll(jsonFile.Name()) 71 72 store, err := NewReferenceStore(jsonFile.Name()) 73 if err != nil { 74 t.Fatalf("error creating tag store: %v", err) 75 } 76 77 for refStr, id := range saveLoadTestCases { 78 ref, err := reference.ParseNormalizedNamed(refStr) 79 if err != nil { 80 t.Fatalf("failed to parse reference: %v", err) 81 } 82 if canonical, ok := ref.(reference.Canonical); ok { 83 err = store.AddDigest(canonical, id, false) 84 if err != nil { 85 t.Fatalf("could not add digest reference %s: %v", refStr, err) 86 } 87 } else { 88 err = store.AddTag(ref, id, false) 89 if err != nil { 90 t.Fatalf("could not add reference %s: %v", refStr, err) 91 } 92 } 93 } 94 95 jsonBytes, err := ioutil.ReadFile(jsonFile.Name()) 96 if err != nil { 97 t.Fatalf("could not read json file: %v", err) 98 } 99 100 if !bytes.Equal(jsonBytes, marshalledSaveLoadTestCases) { 101 t.Fatalf("save output did not match expectations\nexpected:\n%s\ngot:\n%s", marshalledSaveLoadTestCases, jsonBytes) 102 } 103 } 104 105 func TestAddDeleteGet(t *testing.T) { 106 jsonFile, err := ioutil.TempFile("", "tag-store-test") 107 if err != nil { 108 t.Fatalf("error creating temp file: %v", err) 109 } 110 _, err = jsonFile.Write([]byte(`{}`)) 111 jsonFile.Close() 112 defer os.RemoveAll(jsonFile.Name()) 113 114 store, err := NewReferenceStore(jsonFile.Name()) 115 if err != nil { 116 t.Fatalf("error creating tag store: %v", err) 117 } 118 119 testImageID1 := digest.Digest("sha256:9655aef5fd742a1b4e1b7b163aa9f1c76c186304bf39102283d80927c916ca9c") 120 testImageID2 := digest.Digest("sha256:9655aef5fd742a1b4e1b7b163aa9f1c76c186304bf39102283d80927c916ca9d") 121 testImageID3 := digest.Digest("sha256:9655aef5fd742a1b4e1b7b163aa9f1c76c186304bf39102283d80927c916ca9e") 122 123 // Try adding a reference with no tag or digest 124 nameOnly, err := reference.ParseNormalizedNamed("username/repo") 125 if err != nil { 126 t.Fatalf("could not parse reference: %v", err) 127 } 128 if err = store.AddTag(nameOnly, testImageID1, false); err != nil { 129 t.Fatalf("error adding to store: %v", err) 130 } 131 132 // Add a few references 133 ref1, err := reference.ParseNormalizedNamed("username/repo1:latest") 134 if err != nil { 135 t.Fatalf("could not parse reference: %v", err) 136 } 137 if err = store.AddTag(ref1, testImageID1, false); err != nil { 138 t.Fatalf("error adding to store: %v", err) 139 } 140 141 ref2, err := reference.ParseNormalizedNamed("username/repo1:old") 142 if err != nil { 143 t.Fatalf("could not parse reference: %v", err) 144 } 145 if err = store.AddTag(ref2, testImageID2, false); err != nil { 146 t.Fatalf("error adding to store: %v", err) 147 } 148 149 ref3, err := reference.ParseNormalizedNamed("username/repo1:alias") 150 if err != nil { 151 t.Fatalf("could not parse reference: %v", err) 152 } 153 if err = store.AddTag(ref3, testImageID1, false); err != nil { 154 t.Fatalf("error adding to store: %v", err) 155 } 156 157 ref4, err := reference.ParseNormalizedNamed("username/repo2:latest") 158 if err != nil { 159 t.Fatalf("could not parse reference: %v", err) 160 } 161 if err = store.AddTag(ref4, testImageID2, false); err != nil { 162 t.Fatalf("error adding to store: %v", err) 163 } 164 165 ref5, err := reference.ParseNormalizedNamed("username/repo3@sha256:58153dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c") 166 if err != nil { 167 t.Fatalf("could not parse reference: %v", err) 168 } 169 if err = store.AddDigest(ref5.(reference.Canonical), testImageID2, false); err != nil { 170 t.Fatalf("error adding to store: %v", err) 171 } 172 173 // Attempt to overwrite with force == false 174 if err = store.AddTag(ref4, testImageID3, false); err == nil || !strings.HasPrefix(err.Error(), "Conflict:") { 175 t.Fatalf("did not get expected error on overwrite attempt - got %v", err) 176 } 177 // Repeat to overwrite with force == true 178 if err = store.AddTag(ref4, testImageID3, true); err != nil { 179 t.Fatalf("failed to force tag overwrite: %v", err) 180 } 181 182 // Check references so far 183 id, err := store.Get(nameOnly) 184 if err != nil { 185 t.Fatalf("Get returned error: %v", err) 186 } 187 if id != testImageID1 { 188 t.Fatalf("id mismatch: got %s instead of %s", id.String(), testImageID1.String()) 189 } 190 191 id, err = store.Get(ref1) 192 if err != nil { 193 t.Fatalf("Get returned error: %v", err) 194 } 195 if id != testImageID1 { 196 t.Fatalf("id mismatch: got %s instead of %s", id.String(), testImageID1.String()) 197 } 198 199 id, err = store.Get(ref2) 200 if err != nil { 201 t.Fatalf("Get returned error: %v", err) 202 } 203 if id != testImageID2 { 204 t.Fatalf("id mismatch: got %s instead of %s", id.String(), testImageID2.String()) 205 } 206 207 id, err = store.Get(ref3) 208 if err != nil { 209 t.Fatalf("Get returned error: %v", err) 210 } 211 if id != testImageID1 { 212 t.Fatalf("id mismatch: got %s instead of %s", id.String(), testImageID1.String()) 213 } 214 215 id, err = store.Get(ref4) 216 if err != nil { 217 t.Fatalf("Get returned error: %v", err) 218 } 219 if id != testImageID3 { 220 t.Fatalf("id mismatch: got %s instead of %s", id.String(), testImageID3.String()) 221 } 222 223 id, err = store.Get(ref5) 224 if err != nil { 225 t.Fatalf("Get returned error: %v", err) 226 } 227 if id != testImageID2 { 228 t.Fatalf("id mismatch: got %s instead of %s", id.String(), testImageID3.String()) 229 } 230 231 // Get should return ErrDoesNotExist for a nonexistent repo 232 nonExistRepo, err := reference.ParseNormalizedNamed("username/nonexistrepo:latest") 233 if err != nil { 234 t.Fatalf("could not parse reference: %v", err) 235 } 236 if _, err = store.Get(nonExistRepo); err != ErrDoesNotExist { 237 t.Fatal("Expected ErrDoesNotExist from Get") 238 } 239 240 // Get should return ErrDoesNotExist for a nonexistent tag 241 nonExistTag, err := reference.ParseNormalizedNamed("username/repo1:nonexist") 242 if err != nil { 243 t.Fatalf("could not parse reference: %v", err) 244 } 245 if _, err = store.Get(nonExistTag); err != ErrDoesNotExist { 246 t.Fatal("Expected ErrDoesNotExist from Get") 247 } 248 249 // Check References 250 refs := store.References(testImageID1) 251 if len(refs) != 3 { 252 t.Fatal("unexpected number of references") 253 } 254 // Looking for the references in this order verifies that they are 255 // returned lexically sorted. 256 if refs[0].String() != ref3.String() { 257 t.Fatalf("unexpected reference: %v", refs[0].String()) 258 } 259 if refs[1].String() != ref1.String() { 260 t.Fatalf("unexpected reference: %v", refs[1].String()) 261 } 262 if refs[2].String() != nameOnly.String()+":latest" { 263 t.Fatalf("unexpected reference: %v", refs[2].String()) 264 } 265 266 // Check ReferencesByName 267 repoName, err := reference.ParseNormalizedNamed("username/repo1") 268 if err != nil { 269 t.Fatalf("could not parse reference: %v", err) 270 } 271 associations := store.ReferencesByName(repoName) 272 if len(associations) != 3 { 273 t.Fatal("unexpected number of associations") 274 } 275 // Looking for the associations in this order verifies that they are 276 // returned lexically sorted. 277 if associations[0].Ref.String() != ref3.String() { 278 t.Fatalf("unexpected reference: %v", associations[0].Ref.String()) 279 } 280 if associations[0].ID != testImageID1 { 281 t.Fatalf("unexpected reference: %v", associations[0].Ref.String()) 282 } 283 if associations[1].Ref.String() != ref1.String() { 284 t.Fatalf("unexpected reference: %v", associations[1].Ref.String()) 285 } 286 if associations[1].ID != testImageID1 { 287 t.Fatalf("unexpected reference: %v", associations[1].Ref.String()) 288 } 289 if associations[2].Ref.String() != ref2.String() { 290 t.Fatalf("unexpected reference: %v", associations[2].Ref.String()) 291 } 292 if associations[2].ID != testImageID2 { 293 t.Fatalf("unexpected reference: %v", associations[2].Ref.String()) 294 } 295 296 // Delete should return ErrDoesNotExist for a nonexistent repo 297 if _, err = store.Delete(nonExistRepo); err != ErrDoesNotExist { 298 t.Fatal("Expected ErrDoesNotExist from Delete") 299 } 300 301 // Delete should return ErrDoesNotExist for a nonexistent tag 302 if _, err = store.Delete(nonExistTag); err != ErrDoesNotExist { 303 t.Fatal("Expected ErrDoesNotExist from Delete") 304 } 305 306 // Delete a few references 307 if deleted, err := store.Delete(ref1); err != nil || deleted != true { 308 t.Fatal("Delete failed") 309 } 310 if _, err := store.Get(ref1); err != ErrDoesNotExist { 311 t.Fatal("Expected ErrDoesNotExist from Get") 312 } 313 if deleted, err := store.Delete(ref5); err != nil || deleted != true { 314 t.Fatal("Delete failed") 315 } 316 if _, err := store.Get(ref5); err != ErrDoesNotExist { 317 t.Fatal("Expected ErrDoesNotExist from Get") 318 } 319 if deleted, err := store.Delete(nameOnly); err != nil || deleted != true { 320 t.Fatal("Delete failed") 321 } 322 if _, err := store.Get(nameOnly); err != ErrDoesNotExist { 323 t.Fatal("Expected ErrDoesNotExist from Get") 324 } 325 } 326 327 func TestInvalidTags(t *testing.T) { 328 tmpDir, err := ioutil.TempDir("", "tag-store-test") 329 defer os.RemoveAll(tmpDir) 330 331 store, err := NewReferenceStore(filepath.Join(tmpDir, "repositories.json")) 332 if err != nil { 333 t.Fatalf("error creating tag store: %v", err) 334 } 335 id := digest.Digest("sha256:470022b8af682154f57a2163d030eb369549549cba00edc69e1b99b46bb924d6") 336 337 // sha256 as repo name 338 ref, err := reference.ParseNormalizedNamed("sha256:abc") 339 if err != nil { 340 t.Fatal(err) 341 } 342 err = store.AddTag(ref, id, true) 343 if err == nil { 344 t.Fatalf("expected setting tag %q to fail", ref) 345 } 346 347 // setting digest as a tag 348 ref, err = reference.ParseNormalizedNamed("registry@sha256:367eb40fd0330a7e464777121e39d2f5b3e8e23a1e159342e53ab05c9e4d94e6") 349 if err != nil { 350 t.Fatal(err) 351 } 352 err = store.AddTag(ref, id, true) 353 if err == nil { 354 t.Fatalf("expected setting tag %q to fail", ref) 355 } 356 357 }