github.com/walkingsparrow/docker@v1.4.2-0.20151218153551-b708a2249bfa/image/fs_test.go (about)

     1  package image
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/rand"
     6  	"crypto/sha256"
     7  	"encoding/hex"
     8  	"errors"
     9  	"io/ioutil"
    10  	"os"
    11  	"path/filepath"
    12  	"testing"
    13  
    14  	"github.com/docker/distribution/digest"
    15  )
    16  
    17  func TestFSGetSet(t *testing.T) {
    18  	tmpdir, err := ioutil.TempDir("", "images-fs-store")
    19  	if err != nil {
    20  		t.Fatal(err)
    21  	}
    22  	defer os.RemoveAll(tmpdir)
    23  	fs, err := NewFSStoreBackend(tmpdir)
    24  	if err != nil {
    25  		t.Fatal(err)
    26  	}
    27  
    28  	testGetSet(t, fs)
    29  }
    30  
    31  func TestFSGetInvalidData(t *testing.T) {
    32  	tmpdir, err := ioutil.TempDir("", "images-fs-store")
    33  	if err != nil {
    34  		t.Fatal(err)
    35  	}
    36  	defer os.RemoveAll(tmpdir)
    37  	fs, err := NewFSStoreBackend(tmpdir)
    38  	if err != nil {
    39  		t.Fatal(err)
    40  	}
    41  
    42  	id, err := fs.Set([]byte("foobar"))
    43  	if err != nil {
    44  		t.Fatal(err)
    45  	}
    46  
    47  	dgst := digest.Digest(id)
    48  
    49  	if err := ioutil.WriteFile(filepath.Join(tmpdir, contentDirName, string(dgst.Algorithm()), dgst.Hex()), []byte("foobar2"), 0600); err != nil {
    50  		t.Fatal(err)
    51  	}
    52  
    53  	_, err = fs.Get(id)
    54  	if err == nil {
    55  		t.Fatal("Expected get to fail after data modification.")
    56  	}
    57  }
    58  
    59  func TestFSInvalidSet(t *testing.T) {
    60  	tmpdir, err := ioutil.TempDir("", "images-fs-store")
    61  	if err != nil {
    62  		t.Fatal(err)
    63  	}
    64  	defer os.RemoveAll(tmpdir)
    65  	fs, err := NewFSStoreBackend(tmpdir)
    66  	if err != nil {
    67  		t.Fatal(err)
    68  	}
    69  
    70  	id, err := digest.FromBytes([]byte("foobar"))
    71  	if err != nil {
    72  		t.Fatal(err)
    73  	}
    74  	err = os.Mkdir(filepath.Join(tmpdir, contentDirName, string(id.Algorithm()), id.Hex()), 0700)
    75  	if err != nil {
    76  		t.Fatal(err)
    77  	}
    78  
    79  	_, err = fs.Set([]byte("foobar"))
    80  	if err == nil {
    81  		t.Fatal("Expecting error from invalid filesystem data.")
    82  	}
    83  }
    84  
    85  func TestFSInvalidRoot(t *testing.T) {
    86  	tmpdir, err := ioutil.TempDir("", "images-fs-store")
    87  	if err != nil {
    88  		t.Fatal(err)
    89  	}
    90  	defer os.RemoveAll(tmpdir)
    91  
    92  	tcases := []struct {
    93  		root, invalidFile string
    94  	}{
    95  		{"root", "root"},
    96  		{"root", "root/content"},
    97  		{"root", "root/metadata"},
    98  	}
    99  
   100  	for _, tc := range tcases {
   101  		root := filepath.Join(tmpdir, tc.root)
   102  		filePath := filepath.Join(tmpdir, tc.invalidFile)
   103  		err := os.MkdirAll(filepath.Dir(filePath), 0700)
   104  		if err != nil {
   105  			t.Fatal(err)
   106  		}
   107  		f, err := os.Create(filePath)
   108  		if err != nil {
   109  			t.Fatal(err)
   110  		}
   111  		f.Close()
   112  
   113  		_, err = NewFSStoreBackend(root)
   114  		if err == nil {
   115  			t.Fatalf("Expected error from root %q and invlid file %q", tc.root, tc.invalidFile)
   116  		}
   117  
   118  		os.RemoveAll(root)
   119  	}
   120  
   121  }
   122  
   123  func testMetadataGetSet(t *testing.T, store StoreBackend) {
   124  	id, err := store.Set([]byte("foo"))
   125  	if err != nil {
   126  		t.Fatal(err)
   127  	}
   128  	id2, err := store.Set([]byte("bar"))
   129  	if err != nil {
   130  		t.Fatal(err)
   131  	}
   132  
   133  	tcases := []struct {
   134  		id    ID
   135  		key   string
   136  		value []byte
   137  	}{
   138  		{id, "tkey", []byte("tval1")},
   139  		{id, "tkey2", []byte("tval2")},
   140  		{id2, "tkey", []byte("tval3")},
   141  	}
   142  
   143  	for _, tc := range tcases {
   144  		err = store.SetMetadata(tc.id, tc.key, tc.value)
   145  		if err != nil {
   146  			t.Fatal(err)
   147  		}
   148  
   149  		actual, err := store.GetMetadata(tc.id, tc.key)
   150  		if err != nil {
   151  			t.Fatal(err)
   152  		}
   153  		if bytes.Compare(actual, tc.value) != 0 {
   154  			t.Fatalf("Metadata expected %q, got %q", tc.value, actual)
   155  		}
   156  	}
   157  
   158  	_, err = store.GetMetadata(id2, "tkey2")
   159  	if err == nil {
   160  		t.Fatal("Expected error for getting metadata for unknown key")
   161  	}
   162  
   163  	id3, err := digest.FromBytes([]byte("baz"))
   164  	if err != nil {
   165  		t.Fatal(err)
   166  	}
   167  
   168  	err = store.SetMetadata(ID(id3), "tkey", []byte("tval"))
   169  	if err == nil {
   170  		t.Fatal("Expected error for setting metadata for unknown ID.")
   171  	}
   172  
   173  	_, err = store.GetMetadata(ID(id3), "tkey")
   174  	if err == nil {
   175  		t.Fatal("Expected error for getting metadata for unknown ID.")
   176  	}
   177  }
   178  
   179  func TestFSMetadataGetSet(t *testing.T) {
   180  	tmpdir, err := ioutil.TempDir("", "images-fs-store")
   181  	if err != nil {
   182  		t.Fatal(err)
   183  	}
   184  	defer os.RemoveAll(tmpdir)
   185  	fs, err := NewFSStoreBackend(tmpdir)
   186  	if err != nil {
   187  		t.Fatal(err)
   188  	}
   189  
   190  	testMetadataGetSet(t, fs)
   191  }
   192  
   193  func TestFSDelete(t *testing.T) {
   194  	tmpdir, err := ioutil.TempDir("", "images-fs-store")
   195  	if err != nil {
   196  		t.Fatal(err)
   197  	}
   198  	defer os.RemoveAll(tmpdir)
   199  	fs, err := NewFSStoreBackend(tmpdir)
   200  	if err != nil {
   201  		t.Fatal(err)
   202  	}
   203  
   204  	testDelete(t, fs)
   205  }
   206  
   207  func TestFSWalker(t *testing.T) {
   208  	tmpdir, err := ioutil.TempDir("", "images-fs-store")
   209  	if err != nil {
   210  		t.Fatal(err)
   211  	}
   212  	defer os.RemoveAll(tmpdir)
   213  	fs, err := NewFSStoreBackend(tmpdir)
   214  	if err != nil {
   215  		t.Fatal(err)
   216  	}
   217  
   218  	testWalker(t, fs)
   219  }
   220  
   221  func TestFSInvalidWalker(t *testing.T) {
   222  	tmpdir, err := ioutil.TempDir("", "images-fs-store")
   223  	if err != nil {
   224  		t.Fatal(err)
   225  	}
   226  	defer os.RemoveAll(tmpdir)
   227  	fs, err := NewFSStoreBackend(tmpdir)
   228  	if err != nil {
   229  		t.Fatal(err)
   230  	}
   231  
   232  	fooID, err := fs.Set([]byte("foo"))
   233  	if err != nil {
   234  		t.Fatal(err)
   235  	}
   236  
   237  	if err := ioutil.WriteFile(filepath.Join(tmpdir, contentDirName, "sha256/foobar"), []byte("foobar"), 0600); err != nil {
   238  		t.Fatal(err)
   239  	}
   240  
   241  	n := 0
   242  	err = fs.Walk(func(id ID) error {
   243  		if id != fooID {
   244  			t.Fatalf("Invalid walker ID %q, expected %q", id, fooID)
   245  		}
   246  		n++
   247  		return nil
   248  	})
   249  	if err != nil {
   250  		t.Fatalf("Invalid data should not have caused walker error, got %v", err)
   251  	}
   252  	if n != 1 {
   253  		t.Fatalf("Expected 1 walk initialization, got %d", n)
   254  	}
   255  }
   256  
   257  func testGetSet(t *testing.T, store StoreBackend) {
   258  	type tcase struct {
   259  		input    []byte
   260  		expected ID
   261  	}
   262  	tcases := []tcase{
   263  		{[]byte("foobar"), ID("sha256:c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2")},
   264  	}
   265  
   266  	randomInput := make([]byte, 8*1024)
   267  	_, err := rand.Read(randomInput)
   268  	if err != nil {
   269  		t.Fatal(err)
   270  	}
   271  	// skipping use of digest pkg because its used by the implementation
   272  	h := sha256.New()
   273  	_, err = h.Write(randomInput)
   274  	if err != nil {
   275  		t.Fatal(err)
   276  	}
   277  	tcases = append(tcases, tcase{
   278  		input:    randomInput,
   279  		expected: ID("sha256:" + hex.EncodeToString(h.Sum(nil))),
   280  	})
   281  
   282  	for _, tc := range tcases {
   283  		id, err := store.Set([]byte(tc.input))
   284  		if err != nil {
   285  			t.Fatal(err)
   286  		}
   287  		if id != tc.expected {
   288  			t.Fatalf("Expected ID %q, got %q", tc.expected, id)
   289  		}
   290  	}
   291  
   292  	for _, emptyData := range [][]byte{nil, {}} {
   293  		_, err := store.Set(emptyData)
   294  		if err == nil {
   295  			t.Fatal("Expected error for nil input.")
   296  		}
   297  	}
   298  
   299  	for _, tc := range tcases {
   300  		data, err := store.Get(tc.expected)
   301  		if err != nil {
   302  			t.Fatal(err)
   303  		}
   304  		if bytes.Compare(data, tc.input) != 0 {
   305  			t.Fatalf("Expected data %q, got %q", tc.input, data)
   306  		}
   307  	}
   308  
   309  	for _, key := range []ID{"foobar:abc", "sha256:abc", "sha256:c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2a"} {
   310  		_, err := store.Get(key)
   311  		if err == nil {
   312  			t.Fatalf("Expected error for ID %q.", key)
   313  		}
   314  	}
   315  
   316  }
   317  
   318  func testDelete(t *testing.T, store StoreBackend) {
   319  	id, err := store.Set([]byte("foo"))
   320  	if err != nil {
   321  		t.Fatal(err)
   322  	}
   323  	id2, err := store.Set([]byte("bar"))
   324  	if err != nil {
   325  		t.Fatal(err)
   326  	}
   327  
   328  	err = store.Delete(id)
   329  	if err != nil {
   330  		t.Fatal(err)
   331  	}
   332  
   333  	_, err = store.Get(id)
   334  	if err == nil {
   335  		t.Fatalf("Expected getting deleted item %q to fail", id)
   336  	}
   337  	_, err = store.Get(id2)
   338  	if err != nil {
   339  		t.Fatal(err)
   340  	}
   341  
   342  	err = store.Delete(id2)
   343  	if err != nil {
   344  		t.Fatal(err)
   345  	}
   346  	_, err = store.Get(id2)
   347  	if err == nil {
   348  		t.Fatalf("Expected getting deleted item %q to fail", id2)
   349  	}
   350  }
   351  
   352  func testWalker(t *testing.T, store StoreBackend) {
   353  	id, err := store.Set([]byte("foo"))
   354  	if err != nil {
   355  		t.Fatal(err)
   356  	}
   357  	id2, err := store.Set([]byte("bar"))
   358  	if err != nil {
   359  		t.Fatal(err)
   360  	}
   361  
   362  	tcases := make(map[ID]struct{})
   363  	tcases[id] = struct{}{}
   364  	tcases[id2] = struct{}{}
   365  	n := 0
   366  	err = store.Walk(func(id ID) error {
   367  		delete(tcases, id)
   368  		n++
   369  		return nil
   370  	})
   371  	if err != nil {
   372  		t.Fatal(err)
   373  	}
   374  
   375  	if n != 2 {
   376  		t.Fatalf("Expected 2 walk initializations, got %d", n)
   377  	}
   378  	if len(tcases) != 0 {
   379  		t.Fatalf("Expected empty unwalked set, got %+v", tcases)
   380  	}
   381  
   382  	// stop on error
   383  	tcases = make(map[ID]struct{})
   384  	tcases[id] = struct{}{}
   385  	err = store.Walk(func(id ID) error {
   386  		return errors.New("")
   387  	})
   388  	if err == nil {
   389  		t.Fatalf("Exected error from walker.")
   390  	}
   391  }