github.com/kinvolk/docker@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  }