github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/image/fs_test.go (about)

     1  package image // import "github.com/docker/docker/image"
     2  
     3  import (
     4  	"crypto/rand"
     5  	"crypto/sha256"
     6  	"encoding/hex"
     7  	"errors"
     8  	"io/ioutil"
     9  	"os"
    10  	"path/filepath"
    11  	"testing"
    12  
    13  	digest "github.com/opencontainers/go-digest"
    14  	"gotest.tools/v3/assert"
    15  	is "gotest.tools/v3/assert/cmp"
    16  )
    17  
    18  func defaultFSStoreBackend(t *testing.T) (StoreBackend, func()) {
    19  	tmpdir, err := ioutil.TempDir("", "images-fs-store")
    20  	assert.Check(t, err)
    21  
    22  	fsBackend, err := NewFSStoreBackend(tmpdir)
    23  	assert.Check(t, err)
    24  
    25  	return fsBackend, func() { os.RemoveAll(tmpdir) }
    26  }
    27  
    28  func TestFSGetInvalidData(t *testing.T) {
    29  	store, cleanup := defaultFSStoreBackend(t)
    30  	defer cleanup()
    31  
    32  	dgst, err := store.Set([]byte("foobar"))
    33  	assert.Check(t, err)
    34  
    35  	err = ioutil.WriteFile(filepath.Join(store.(*fs).root, contentDirName, string(dgst.Algorithm()), dgst.Hex()), []byte("foobar2"), 0600)
    36  	assert.Check(t, err)
    37  
    38  	_, err = store.Get(dgst)
    39  	assert.Check(t, is.ErrorContains(err, "failed to verify"))
    40  }
    41  
    42  func TestFSInvalidSet(t *testing.T) {
    43  	store, cleanup := defaultFSStoreBackend(t)
    44  	defer cleanup()
    45  
    46  	id := digest.FromBytes([]byte("foobar"))
    47  	err := os.Mkdir(filepath.Join(store.(*fs).root, contentDirName, string(id.Algorithm()), id.Hex()), 0700)
    48  	assert.Check(t, err)
    49  
    50  	_, err = store.Set([]byte("foobar"))
    51  	assert.Check(t, is.ErrorContains(err, "failed to write digest data"))
    52  }
    53  
    54  func TestFSInvalidRoot(t *testing.T) {
    55  	tmpdir, err := ioutil.TempDir("", "images-fs-store")
    56  	assert.Check(t, err)
    57  	defer os.RemoveAll(tmpdir)
    58  
    59  	tcases := []struct {
    60  		root, invalidFile string
    61  	}{
    62  		{"root", "root"},
    63  		{"root", "root/content"},
    64  		{"root", "root/metadata"},
    65  	}
    66  
    67  	for _, tc := range tcases {
    68  		root := filepath.Join(tmpdir, tc.root)
    69  		filePath := filepath.Join(tmpdir, tc.invalidFile)
    70  		err := os.MkdirAll(filepath.Dir(filePath), 0700)
    71  		assert.Check(t, err)
    72  
    73  		f, err := os.Create(filePath)
    74  		assert.Check(t, err)
    75  		f.Close()
    76  
    77  		_, err = NewFSStoreBackend(root)
    78  		assert.Check(t, is.ErrorContains(err, "failed to create storage backend"))
    79  
    80  		os.RemoveAll(root)
    81  	}
    82  
    83  }
    84  
    85  func TestFSMetadataGetSet(t *testing.T) {
    86  	store, cleanup := defaultFSStoreBackend(t)
    87  	defer cleanup()
    88  
    89  	id, err := store.Set([]byte("foo"))
    90  	assert.Check(t, err)
    91  
    92  	id2, err := store.Set([]byte("bar"))
    93  	assert.Check(t, err)
    94  
    95  	tcases := []struct {
    96  		id    digest.Digest
    97  		key   string
    98  		value []byte
    99  	}{
   100  		{id, "tkey", []byte("tval1")},
   101  		{id, "tkey2", []byte("tval2")},
   102  		{id2, "tkey", []byte("tval3")},
   103  	}
   104  
   105  	for _, tc := range tcases {
   106  		err = store.SetMetadata(tc.id, tc.key, tc.value)
   107  		assert.Check(t, err)
   108  
   109  		actual, err := store.GetMetadata(tc.id, tc.key)
   110  		assert.Check(t, err)
   111  
   112  		assert.Check(t, is.DeepEqual(tc.value, actual))
   113  	}
   114  
   115  	_, err = store.GetMetadata(id2, "tkey2")
   116  	assert.Check(t, is.ErrorContains(err, "failed to read metadata"))
   117  
   118  	id3 := digest.FromBytes([]byte("baz"))
   119  	err = store.SetMetadata(id3, "tkey", []byte("tval"))
   120  	assert.Check(t, is.ErrorContains(err, "failed to get digest"))
   121  
   122  	_, err = store.GetMetadata(id3, "tkey")
   123  	assert.Check(t, is.ErrorContains(err, "failed to get digest"))
   124  }
   125  
   126  func TestFSInvalidWalker(t *testing.T) {
   127  	store, cleanup := defaultFSStoreBackend(t)
   128  	defer cleanup()
   129  
   130  	fooID, err := store.Set([]byte("foo"))
   131  	assert.Check(t, err)
   132  
   133  	err = ioutil.WriteFile(filepath.Join(store.(*fs).root, contentDirName, "sha256/foobar"), []byte("foobar"), 0600)
   134  	assert.Check(t, err)
   135  
   136  	n := 0
   137  	err = store.Walk(func(id digest.Digest) error {
   138  		assert.Check(t, is.Equal(fooID, id))
   139  		n++
   140  		return nil
   141  	})
   142  	assert.Check(t, err)
   143  	assert.Check(t, is.Equal(1, n))
   144  }
   145  
   146  func TestFSGetSet(t *testing.T) {
   147  	store, cleanup := defaultFSStoreBackend(t)
   148  	defer cleanup()
   149  
   150  	type tcase struct {
   151  		input    []byte
   152  		expected digest.Digest
   153  	}
   154  	tcases := []tcase{
   155  		{[]byte("foobar"), digest.Digest("sha256:c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2")},
   156  	}
   157  
   158  	randomInput := make([]byte, 8*1024)
   159  	_, err := rand.Read(randomInput)
   160  	assert.Check(t, err)
   161  
   162  	// skipping use of digest pkg because it is used by the implementation
   163  	h := sha256.New()
   164  	_, err = h.Write(randomInput)
   165  	assert.Check(t, err)
   166  
   167  	tcases = append(tcases, tcase{
   168  		input:    randomInput,
   169  		expected: digest.Digest("sha256:" + hex.EncodeToString(h.Sum(nil))),
   170  	})
   171  
   172  	for _, tc := range tcases {
   173  		id, err := store.Set(tc.input)
   174  		assert.Check(t, err)
   175  		assert.Check(t, is.Equal(tc.expected, id))
   176  	}
   177  
   178  	for _, tc := range tcases {
   179  		data, err := store.Get(tc.expected)
   180  		assert.Check(t, err)
   181  		assert.Check(t, is.DeepEqual(tc.input, data))
   182  	}
   183  }
   184  
   185  func TestFSGetUnsetKey(t *testing.T) {
   186  	store, cleanup := defaultFSStoreBackend(t)
   187  	defer cleanup()
   188  
   189  	for _, key := range []digest.Digest{"foobar:abc", "sha256:abc", "sha256:c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2a"} {
   190  		_, err := store.Get(key)
   191  		assert.Check(t, is.ErrorContains(err, "failed to get digest"))
   192  	}
   193  }
   194  
   195  func TestFSGetEmptyData(t *testing.T) {
   196  	store, cleanup := defaultFSStoreBackend(t)
   197  	defer cleanup()
   198  
   199  	for _, emptyData := range [][]byte{nil, {}} {
   200  		_, err := store.Set(emptyData)
   201  		assert.Check(t, is.ErrorContains(err, "invalid empty data"))
   202  	}
   203  }
   204  
   205  func TestFSDelete(t *testing.T) {
   206  	store, cleanup := defaultFSStoreBackend(t)
   207  	defer cleanup()
   208  
   209  	id, err := store.Set([]byte("foo"))
   210  	assert.Check(t, err)
   211  
   212  	id2, err := store.Set([]byte("bar"))
   213  	assert.Check(t, err)
   214  
   215  	err = store.Delete(id)
   216  	assert.Check(t, err)
   217  
   218  	_, err = store.Get(id)
   219  	assert.Check(t, is.ErrorContains(err, "failed to get digest"))
   220  
   221  	_, err = store.Get(id2)
   222  	assert.Check(t, err)
   223  
   224  	err = store.Delete(id2)
   225  	assert.Check(t, err)
   226  
   227  	_, err = store.Get(id2)
   228  	assert.Check(t, is.ErrorContains(err, "failed to get digest"))
   229  }
   230  
   231  func TestFSWalker(t *testing.T) {
   232  	store, cleanup := defaultFSStoreBackend(t)
   233  	defer cleanup()
   234  
   235  	id, err := store.Set([]byte("foo"))
   236  	assert.Check(t, err)
   237  
   238  	id2, err := store.Set([]byte("bar"))
   239  	assert.Check(t, err)
   240  
   241  	tcases := make(map[digest.Digest]struct{})
   242  	tcases[id] = struct{}{}
   243  	tcases[id2] = struct{}{}
   244  	n := 0
   245  	err = store.Walk(func(id digest.Digest) error {
   246  		delete(tcases, id)
   247  		n++
   248  		return nil
   249  	})
   250  	assert.Check(t, err)
   251  	assert.Check(t, is.Equal(2, n))
   252  	assert.Check(t, is.Len(tcases, 0))
   253  }
   254  
   255  func TestFSWalkerStopOnError(t *testing.T) {
   256  	store, cleanup := defaultFSStoreBackend(t)
   257  	defer cleanup()
   258  
   259  	id, err := store.Set([]byte("foo"))
   260  	assert.Check(t, err)
   261  
   262  	tcases := make(map[digest.Digest]struct{})
   263  	tcases[id] = struct{}{}
   264  	err = store.Walk(func(id digest.Digest) error {
   265  		return errors.New("what")
   266  	})
   267  	assert.Check(t, is.ErrorContains(err, "what"))
   268  }