moby/image/fs_test.go

267 lines
6.3 KiB
Go
Raw Normal View History

package image // import "github.com/docker/docker/image"
import (
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"errors"
"os"
"path/filepath"
"testing"
"github.com/opencontainers/go-digest"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
func defaultFSStoreBackend(t *testing.T) (StoreBackend, func()) {
tmpdir, err := os.MkdirTemp("", "images-fs-store")
assert.Check(t, err)
fsBackend, err := NewFSStoreBackend(tmpdir)
assert.Check(t, err)
return fsBackend, func() { os.RemoveAll(tmpdir) }
}
func TestFSGetInvalidData(t *testing.T) {
store, cleanup := defaultFSStoreBackend(t)
defer cleanup()
dgst, err := store.Set([]byte("foobar"))
assert.Check(t, err)
err = os.WriteFile(filepath.Join(store.(*fs).root, contentDirName, string(dgst.Algorithm()), dgst.Encoded()), []byte("foobar2"), 0o600)
assert.Check(t, err)
_, err = store.Get(dgst)
assert.Check(t, is.ErrorContains(err, "failed to verify"))
}
func TestFSInvalidSet(t *testing.T) {
store, cleanup := defaultFSStoreBackend(t)
defer cleanup()
id := digest.FromBytes([]byte("foobar"))
err := os.Mkdir(filepath.Join(store.(*fs).root, contentDirName, string(id.Algorithm()), id.Encoded()), 0o700)
assert.Check(t, err)
_, err = store.Set([]byte("foobar"))
assert.Check(t, is.ErrorContains(err, "failed to write digest data"))
}
func TestFSInvalidRoot(t *testing.T) {
tmpdir, err := os.MkdirTemp("", "images-fs-store")
assert.Check(t, err)
defer os.RemoveAll(tmpdir)
tcases := []struct {
root, invalidFile string
}{
{"root", "root"},
{"root", "root/content"},
{"root", "root/metadata"},
}
for _, tc := range tcases {
root := filepath.Join(tmpdir, tc.root)
filePath := filepath.Join(tmpdir, tc.invalidFile)
err := os.MkdirAll(filepath.Dir(filePath), 0700)
assert.Check(t, err)
f, err := os.Create(filePath)
assert.Check(t, err)
f.Close()
_, err = NewFSStoreBackend(root)
assert.Check(t, is.ErrorContains(err, "failed to create storage backend"))
os.RemoveAll(root)
}
}
func TestFSMetadataGetSet(t *testing.T) {
store, cleanup := defaultFSStoreBackend(t)
defer cleanup()
id, err := store.Set([]byte("foo"))
assert.Check(t, err)
id2, err := store.Set([]byte("bar"))
assert.Check(t, err)
tcases := []struct {
id digest.Digest
key string
value []byte
}{
{id, "tkey", []byte("tval1")},
{id, "tkey2", []byte("tval2")},
{id2, "tkey", []byte("tval3")},
}
for _, tc := range tcases {
err = store.SetMetadata(tc.id, tc.key, tc.value)
assert.Check(t, err)
actual, err := store.GetMetadata(tc.id, tc.key)
assert.Check(t, err)
assert.Check(t, is.DeepEqual(tc.value, actual))
}
_, err = store.GetMetadata(id2, "tkey2")
assert.Check(t, is.ErrorContains(err, "failed to read metadata"))
id3 := digest.FromBytes([]byte("baz"))
err = store.SetMetadata(id3, "tkey", []byte("tval"))
assert.Check(t, is.ErrorContains(err, "failed to get digest"))
_, err = store.GetMetadata(id3, "tkey")
assert.Check(t, is.ErrorContains(err, "failed to get digest"))
}
func TestFSInvalidWalker(t *testing.T) {
store, cleanup := defaultFSStoreBackend(t)
defer cleanup()
fooID, err := store.Set([]byte("foo"))
assert.Check(t, err)
err = os.WriteFile(filepath.Join(store.(*fs).root, contentDirName, "sha256/foobar"), []byte("foobar"), 0600)
assert.Check(t, err)
n := 0
err = store.Walk(func(id digest.Digest) error {
assert.Check(t, is.Equal(fooID, id))
n++
return nil
})
assert.Check(t, err)
assert.Check(t, is.Equal(1, n))
}
func TestFSGetSet(t *testing.T) {
store, cleanup := defaultFSStoreBackend(t)
defer cleanup()
type tcase struct {
input []byte
expected digest.Digest
}
tcases := []tcase{
{[]byte("foobar"), digest.Digest("sha256:c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2")},
}
randomInput := make([]byte, 8*1024)
_, err := rand.Read(randomInput)
assert.Check(t, err)
// skipping use of digest pkg because it is used by the implementation
h := sha256.New()
_, err = h.Write(randomInput)
assert.Check(t, err)
tcases = append(tcases, tcase{
input: randomInput,
expected: digest.Digest("sha256:" + hex.EncodeToString(h.Sum(nil))),
})
for _, tc := range tcases {
id, err := store.Set(tc.input)
assert.Check(t, err)
assert.Check(t, is.Equal(tc.expected, id))
}
for _, tc := range tcases {
data, err := store.Get(tc.expected)
assert.Check(t, err)
assert.Check(t, is.DeepEqual(tc.input, data))
}
}
func TestFSGetUnsetKey(t *testing.T) {
store, cleanup := defaultFSStoreBackend(t)
defer cleanup()
for _, key := range []digest.Digest{"foobar:abc", "sha256:abc", "sha256:c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2a"} {
_, err := store.Get(key)
assert.Check(t, is.ErrorContains(err, "failed to get digest"))
}
}
func TestFSGetEmptyData(t *testing.T) {
store, cleanup := defaultFSStoreBackend(t)
defer cleanup()
for _, emptyData := range [][]byte{nil, {}} {
_, err := store.Set(emptyData)
assert.Check(t, is.ErrorContains(err, "invalid empty data"))
}
}
func TestFSDelete(t *testing.T) {
store, cleanup := defaultFSStoreBackend(t)
defer cleanup()
id, err := store.Set([]byte("foo"))
assert.Check(t, err)
id2, err := store.Set([]byte("bar"))
assert.Check(t, err)
err = store.Delete(id)
assert.Check(t, err)
_, err = store.Get(id)
assert.Check(t, is.ErrorContains(err, "failed to get digest"))
_, err = store.Get(id2)
assert.Check(t, err)
err = store.Delete(id2)
assert.Check(t, err)
_, err = store.Get(id2)
assert.Check(t, is.ErrorContains(err, "failed to get digest"))
}
func TestFSWalker(t *testing.T) {
store, cleanup := defaultFSStoreBackend(t)
defer cleanup()
id, err := store.Set([]byte("foo"))
assert.Check(t, err)
id2, err := store.Set([]byte("bar"))
assert.Check(t, err)
tcases := make(map[digest.Digest]struct{})
tcases[id] = struct{}{}
tcases[id2] = struct{}{}
n := 0
err = store.Walk(func(id digest.Digest) error {
delete(tcases, id)
n++
return nil
})
assert.Check(t, err)
assert.Check(t, is.Equal(2, n))
assert.Check(t, is.Len(tcases, 0))
}
func TestFSWalkerStopOnError(t *testing.T) {
store, cleanup := defaultFSStoreBackend(t)
defer cleanup()
id, err := store.Set([]byte("foo"))
assert.Check(t, err)
tcases := make(map[digest.Digest]struct{})
tcases[id] = struct{}{}
err = store.Walk(func(id digest.Digest) error {
return errors.New("what")
})
assert.Check(t, is.ErrorContains(err, "what"))
}