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