github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/image/fs_test.go (about)

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