github.com/docker/Engine@v17.12.1-ce-rc2+incompatible/image/fs_test.go (about)

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