1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00
moby--moby/image/fs_test.go
Tonis Tiigi 01ba0a935b Add image store
The image store abstracts image handling. It keeps track of the
available images, and makes it possible to delete existing images or
register new ones. The image store holds references to the underlying
layers for each image.

The image/v1 package provides compatibility functions for interoperating
with older (non-content-addressable) image structures.

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2015-11-24 09:40:24 -08:00

391 lines
7.6 KiB
Go

package image
import (
"bytes"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"errors"
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/docker/distribution/digest"
)
func TestFSGetSet(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "images-fs-store")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
fs, err := NewFSStoreBackend(tmpdir)
if err != nil {
t.Fatal(err)
}
testGetSet(t, fs)
}
func TestFSGetInvalidData(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "images-fs-store")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
fs, err := NewFSStoreBackend(tmpdir)
if err != nil {
t.Fatal(err)
}
id, err := fs.Set([]byte("foobar"))
if err != nil {
t.Fatal(err)
}
dgst := digest.Digest(id)
if err := ioutil.WriteFile(filepath.Join(tmpdir, contentDirName, string(dgst.Algorithm()), dgst.Hex()), []byte("foobar2"), 0600); err != nil {
t.Fatal(err)
}
_, err = fs.Get(id)
if err == nil {
t.Fatal("Expected get to fail after data modification.")
}
}
func TestFSInvalidSet(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "images-fs-store")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
fs, err := NewFSStoreBackend(tmpdir)
if err != nil {
t.Fatal(err)
}
id, err := digest.FromBytes([]byte("foobar"))
if err != nil {
t.Fatal(err)
}
err = os.Mkdir(filepath.Join(tmpdir, contentDirName, string(id.Algorithm()), id.Hex()), 0700)
if err != nil {
t.Fatal(err)
}
_, err = fs.Set([]byte("foobar"))
if err == nil {
t.Fatal("Expecting error from invalid filesystem data.")
}
}
func TestFSInvalidRoot(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "images-fs-store")
if err != nil {
t.Fatal(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)
if err != nil {
t.Fatal(err)
}
f, err := os.Create(filePath)
if err != nil {
t.Fatal(err)
}
f.Close()
_, err = NewFSStoreBackend(root)
if err == nil {
t.Fatalf("Expected error from root %q and invlid file %q", tc.root, tc.invalidFile)
}
os.RemoveAll(root)
}
}
func testMetadataGetSet(t *testing.T, store StoreBackend) {
id, err := store.Set([]byte("foo"))
if err != nil {
t.Fatal(err)
}
id2, err := store.Set([]byte("bar"))
if err != nil {
t.Fatal(err)
}
tcases := []struct {
id ID
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)
if err != nil {
t.Fatal(err)
}
actual, err := store.GetMetadata(tc.id, tc.key)
if err != nil {
t.Fatal(err)
}
if bytes.Compare(actual, tc.value) != 0 {
t.Fatalf("Metadata expected %q, got %q", tc.value, actual)
}
}
_, err = store.GetMetadata(id2, "tkey2")
if err == nil {
t.Fatal("Expected error for getting metadata for unknown key")
}
id3, err := digest.FromBytes([]byte("baz"))
if err != nil {
t.Fatal(err)
}
err = store.SetMetadata(ID(id3), "tkey", []byte("tval"))
if err == nil {
t.Fatal("Expected error for setting metadata for unknown ID.")
}
_, err = store.GetMetadata(ID(id3), "tkey")
if err == nil {
t.Fatal("Expected error for getting metadata for unknown ID.")
}
}
func TestFSMetadataGetSet(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "images-fs-store")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
fs, err := NewFSStoreBackend(tmpdir)
if err != nil {
t.Fatal(err)
}
testMetadataGetSet(t, fs)
}
func TestFSDelete(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "images-fs-store")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
fs, err := NewFSStoreBackend(tmpdir)
if err != nil {
t.Fatal(err)
}
testDelete(t, fs)
}
func TestFSWalker(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "images-fs-store")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
fs, err := NewFSStoreBackend(tmpdir)
if err != nil {
t.Fatal(err)
}
testWalker(t, fs)
}
func TestFSInvalidWalker(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "images-fs-store")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
fs, err := NewFSStoreBackend(tmpdir)
if err != nil {
t.Fatal(err)
}
fooID, err := fs.Set([]byte("foo"))
if err != nil {
t.Fatal(err)
}
if err := ioutil.WriteFile(filepath.Join(tmpdir, contentDirName, "sha256/foobar"), []byte("foobar"), 0600); err != nil {
t.Fatal(err)
}
n := 0
err = fs.Walk(func(id ID) error {
if id != fooID {
t.Fatalf("Invalid walker ID %q, expected %q", id, fooID)
}
n++
return nil
})
if err != nil {
t.Fatalf("Invalid data should not have caused walker error, got %v", err)
}
if n != 1 {
t.Fatalf("Expected 1 walk initialization, got %d", n)
}
}
func testGetSet(t *testing.T, store StoreBackend) {
type tcase struct {
input []byte
expected ID
}
tcases := []tcase{
{[]byte("foobar"), ID("sha256:c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2")},
}
randomInput := make([]byte, 8*1024)
_, err := rand.Read(randomInput)
if err != nil {
t.Fatal(err)
}
// skipping use of digest pkg because its used by the imlementation
h := sha256.New()
_, err = h.Write(randomInput)
if err != nil {
t.Fatal(err)
}
tcases = append(tcases, tcase{
input: randomInput,
expected: ID("sha256:" + hex.EncodeToString(h.Sum(nil))),
})
for _, tc := range tcases {
id, err := store.Set([]byte(tc.input))
if err != nil {
t.Fatal(err)
}
if id != tc.expected {
t.Fatalf("Expected ID %q, got %q", tc.expected, id)
}
}
for _, emptyData := range [][]byte{nil, {}} {
_, err := store.Set(emptyData)
if err == nil {
t.Fatal("Expected error for nil input.")
}
}
for _, tc := range tcases {
data, err := store.Get(tc.expected)
if err != nil {
t.Fatal(err)
}
if bytes.Compare(data, tc.input) != 0 {
t.Fatalf("Expected data %q, got %q", tc.input, data)
}
}
for _, key := range []ID{"foobar:abc", "sha256:abc", "sha256:c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2a"} {
_, err := store.Get(key)
if err == nil {
t.Fatalf("Expected error for ID %q.", key)
}
}
}
func testDelete(t *testing.T, store StoreBackend) {
id, err := store.Set([]byte("foo"))
if err != nil {
t.Fatal(err)
}
id2, err := store.Set([]byte("bar"))
if err != nil {
t.Fatal(err)
}
err = store.Delete(id)
if err != nil {
t.Fatal(err)
}
_, err = store.Get(id)
if err == nil {
t.Fatalf("Expected getting deleted item %q to fail", id)
}
_, err = store.Get(id2)
if err != nil {
t.Fatal(err)
}
err = store.Delete(id2)
if err != nil {
t.Fatal(err)
}
_, err = store.Get(id2)
if err == nil {
t.Fatalf("Expected getting deleted item %q to fail", id2)
}
}
func testWalker(t *testing.T, store StoreBackend) {
id, err := store.Set([]byte("foo"))
if err != nil {
t.Fatal(err)
}
id2, err := store.Set([]byte("bar"))
if err != nil {
t.Fatal(err)
}
tcases := make(map[ID]struct{})
tcases[id] = struct{}{}
tcases[id2] = struct{}{}
n := 0
err = store.Walk(func(id ID) error {
delete(tcases, id)
n++
return nil
})
if err != nil {
t.Fatal(err)
}
if n != 2 {
t.Fatalf("Expected 2 walk initializations, got %d", n)
}
if len(tcases) != 0 {
t.Fatalf("Expected empty unwalked set, got %+v", tcases)
}
// stop on error
tcases = make(map[ID]struct{})
tcases[id] = struct{}{}
err = store.Walk(func(id ID) error {
return errors.New("")
})
if err == nil {
t.Fatalf("Exected error from walker.")
}
}