fs_test.go 6.4 KB

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