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