github.com/toplink-cn/moby@v0.0.0-20240305205811-460b4aebdf81/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  	"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.Encoded()), []byte("foobar2"), 0o600)
    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.Encoded()), 0o700)
    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), 0o700)
    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  func TestFSMetadataGetSet(t *testing.T) {
    84  	store, cleanup := defaultFSStoreBackend(t)
    85  	defer cleanup()
    86  
    87  	id, err := store.Set([]byte("foo"))
    88  	assert.Check(t, err)
    89  
    90  	id2, err := store.Set([]byte("bar"))
    91  	assert.Check(t, err)
    92  
    93  	tcases := []struct {
    94  		id    digest.Digest
    95  		key   string
    96  		value []byte
    97  	}{
    98  		{id, "tkey", []byte("tval1")},
    99  		{id, "tkey2", []byte("tval2")},
   100  		{id2, "tkey", []byte("tval3")},
   101  	}
   102  
   103  	for _, tc := range tcases {
   104  		err = store.SetMetadata(tc.id, tc.key, tc.value)
   105  		assert.Check(t, err)
   106  
   107  		actual, err := store.GetMetadata(tc.id, tc.key)
   108  		assert.Check(t, err)
   109  
   110  		assert.Check(t, is.DeepEqual(tc.value, actual))
   111  	}
   112  
   113  	_, err = store.GetMetadata(id2, "tkey2")
   114  	assert.Check(t, is.ErrorContains(err, "failed to read metadata"))
   115  
   116  	id3 := digest.FromBytes([]byte("baz"))
   117  	err = store.SetMetadata(id3, "tkey", []byte("tval"))
   118  	assert.Check(t, is.ErrorContains(err, "failed to get digest"))
   119  
   120  	_, err = store.GetMetadata(id3, "tkey")
   121  	assert.Check(t, is.ErrorContains(err, "failed to get digest"))
   122  }
   123  
   124  func TestFSInvalidWalker(t *testing.T) {
   125  	store, cleanup := defaultFSStoreBackend(t)
   126  	defer cleanup()
   127  
   128  	fooID, err := store.Set([]byte("foo"))
   129  	assert.Check(t, err)
   130  
   131  	err = os.WriteFile(filepath.Join(store.(*fs).root, contentDirName, "sha256/foobar"), []byte("foobar"), 0o600)
   132  	assert.Check(t, err)
   133  
   134  	n := 0
   135  	err = store.Walk(func(id digest.Digest) error {
   136  		assert.Check(t, is.Equal(fooID, id))
   137  		n++
   138  		return nil
   139  	})
   140  	assert.Check(t, err)
   141  	assert.Check(t, is.Equal(1, n))
   142  }
   143  
   144  func TestFSGetSet(t *testing.T) {
   145  	store, cleanup := defaultFSStoreBackend(t)
   146  	defer cleanup()
   147  
   148  	type tcase struct {
   149  		input    []byte
   150  		expected digest.Digest
   151  	}
   152  	tcases := []tcase{
   153  		{[]byte("foobar"), digest.Digest("sha256:c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2")},
   154  	}
   155  
   156  	randomInput := make([]byte, 8*1024)
   157  	_, err := rand.Read(randomInput)
   158  	assert.Check(t, err)
   159  
   160  	// skipping use of digest pkg because it is used by the implementation
   161  	h := sha256.New()
   162  	_, err = h.Write(randomInput)
   163  	assert.Check(t, err)
   164  
   165  	tcases = append(tcases, tcase{
   166  		input:    randomInput,
   167  		expected: digest.Digest("sha256:" + hex.EncodeToString(h.Sum(nil))),
   168  	})
   169  
   170  	for _, tc := range tcases {
   171  		id, err := store.Set(tc.input)
   172  		assert.Check(t, err)
   173  		assert.Check(t, is.Equal(tc.expected, id))
   174  	}
   175  
   176  	for _, tc := range tcases {
   177  		data, err := store.Get(tc.expected)
   178  		assert.Check(t, err)
   179  		assert.Check(t, is.DeepEqual(tc.input, data))
   180  	}
   181  }
   182  
   183  func TestFSGetUnsetKey(t *testing.T) {
   184  	store, cleanup := defaultFSStoreBackend(t)
   185  	defer cleanup()
   186  
   187  	for _, key := range []digest.Digest{"foobar:abc", "sha256:abc", "sha256:c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2a"} {
   188  		_, err := store.Get(key)
   189  		assert.Check(t, is.ErrorContains(err, "failed to get digest"))
   190  	}
   191  }
   192  
   193  func TestFSGetEmptyData(t *testing.T) {
   194  	store, cleanup := defaultFSStoreBackend(t)
   195  	defer cleanup()
   196  
   197  	for _, emptyData := range [][]byte{nil, {}} {
   198  		_, err := store.Set(emptyData)
   199  		assert.Check(t, is.ErrorContains(err, "invalid empty data"))
   200  	}
   201  }
   202  
   203  func TestFSDelete(t *testing.T) {
   204  	store, cleanup := defaultFSStoreBackend(t)
   205  	defer cleanup()
   206  
   207  	id, err := store.Set([]byte("foo"))
   208  	assert.Check(t, err)
   209  
   210  	id2, err := store.Set([]byte("bar"))
   211  	assert.Check(t, err)
   212  
   213  	err = store.Delete(id)
   214  	assert.Check(t, err)
   215  
   216  	_, err = store.Get(id)
   217  	assert.Check(t, is.ErrorContains(err, "failed to get digest"))
   218  
   219  	_, err = store.Get(id2)
   220  	assert.Check(t, err)
   221  
   222  	err = store.Delete(id2)
   223  	assert.Check(t, err)
   224  
   225  	_, err = store.Get(id2)
   226  	assert.Check(t, is.ErrorContains(err, "failed to get digest"))
   227  }
   228  
   229  func TestFSWalker(t *testing.T) {
   230  	store, cleanup := defaultFSStoreBackend(t)
   231  	defer cleanup()
   232  
   233  	id, err := store.Set([]byte("foo"))
   234  	assert.Check(t, err)
   235  
   236  	id2, err := store.Set([]byte("bar"))
   237  	assert.Check(t, err)
   238  
   239  	tcases := make(map[digest.Digest]struct{})
   240  	tcases[id] = struct{}{}
   241  	tcases[id2] = struct{}{}
   242  	n := 0
   243  	err = store.Walk(func(id digest.Digest) error {
   244  		delete(tcases, id)
   245  		n++
   246  		return nil
   247  	})
   248  	assert.Check(t, err)
   249  	assert.Check(t, is.Equal(2, n))
   250  	assert.Check(t, is.Len(tcases, 0))
   251  }
   252  
   253  func TestFSWalkerStopOnError(t *testing.T) {
   254  	store, cleanup := defaultFSStoreBackend(t)
   255  	defer cleanup()
   256  
   257  	id, err := store.Set([]byte("foo"))
   258  	assert.Check(t, err)
   259  
   260  	tcases := make(map[digest.Digest]struct{})
   261  	tcases[id] = struct{}{}
   262  	err = store.Walk(func(id digest.Digest) error {
   263  		return errors.New("what")
   264  	})
   265  	assert.Check(t, is.ErrorContains(err, "what"))
   266  }