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  }