fs_test.go 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  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/distribution/digest"
  13. )
  14. func TestFSGetSet(t *testing.T) {
  15. tmpdir, err := ioutil.TempDir("", "images-fs-store")
  16. if err != nil {
  17. t.Fatal(err)
  18. }
  19. defer os.RemoveAll(tmpdir)
  20. fs, err := NewFSStoreBackend(tmpdir)
  21. if err != nil {
  22. t.Fatal(err)
  23. }
  24. testGetSet(t, fs)
  25. }
  26. func TestFSGetInvalidData(t *testing.T) {
  27. tmpdir, err := ioutil.TempDir("", "images-fs-store")
  28. if err != nil {
  29. t.Fatal(err)
  30. }
  31. defer os.RemoveAll(tmpdir)
  32. fs, err := NewFSStoreBackend(tmpdir)
  33. if err != nil {
  34. t.Fatal(err)
  35. }
  36. id, err := fs.Set([]byte("foobar"))
  37. if err != nil {
  38. t.Fatal(err)
  39. }
  40. dgst := digest.Digest(id)
  41. if err := ioutil.WriteFile(filepath.Join(tmpdir, contentDirName, string(dgst.Algorithm()), dgst.Hex()), []byte("foobar2"), 0600); err != nil {
  42. t.Fatal(err)
  43. }
  44. _, err = fs.Get(id)
  45. if err == nil {
  46. t.Fatal("Expected get to fail after data modification.")
  47. }
  48. }
  49. func TestFSInvalidSet(t *testing.T) {
  50. tmpdir, err := ioutil.TempDir("", "images-fs-store")
  51. if err != nil {
  52. t.Fatal(err)
  53. }
  54. defer os.RemoveAll(tmpdir)
  55. fs, err := NewFSStoreBackend(tmpdir)
  56. if err != nil {
  57. t.Fatal(err)
  58. }
  59. id := digest.FromBytes([]byte("foobar"))
  60. err = os.Mkdir(filepath.Join(tmpdir, contentDirName, string(id.Algorithm()), id.Hex()), 0700)
  61. if err != nil {
  62. t.Fatal(err)
  63. }
  64. _, err = fs.Set([]byte("foobar"))
  65. if err == nil {
  66. t.Fatal("Expecting error from invalid filesystem data.")
  67. }
  68. }
  69. func TestFSInvalidRoot(t *testing.T) {
  70. tmpdir, err := ioutil.TempDir("", "images-fs-store")
  71. if err != nil {
  72. t.Fatal(err)
  73. }
  74. defer os.RemoveAll(tmpdir)
  75. tcases := []struct {
  76. root, invalidFile string
  77. }{
  78. {"root", "root"},
  79. {"root", "root/content"},
  80. {"root", "root/metadata"},
  81. }
  82. for _, tc := range tcases {
  83. root := filepath.Join(tmpdir, tc.root)
  84. filePath := filepath.Join(tmpdir, tc.invalidFile)
  85. err := os.MkdirAll(filepath.Dir(filePath), 0700)
  86. if err != nil {
  87. t.Fatal(err)
  88. }
  89. f, err := os.Create(filePath)
  90. if err != nil {
  91. t.Fatal(err)
  92. }
  93. f.Close()
  94. _, err = NewFSStoreBackend(root)
  95. if err == nil {
  96. t.Fatalf("Expected error from root %q and invlid file %q", tc.root, tc.invalidFile)
  97. }
  98. os.RemoveAll(root)
  99. }
  100. }
  101. func testMetadataGetSet(t *testing.T, store StoreBackend) {
  102. id, err := store.Set([]byte("foo"))
  103. if err != nil {
  104. t.Fatal(err)
  105. }
  106. id2, err := store.Set([]byte("bar"))
  107. if err != nil {
  108. t.Fatal(err)
  109. }
  110. tcases := []struct {
  111. id ID
  112. key string
  113. value []byte
  114. }{
  115. {id, "tkey", []byte("tval1")},
  116. {id, "tkey2", []byte("tval2")},
  117. {id2, "tkey", []byte("tval3")},
  118. }
  119. for _, tc := range tcases {
  120. err = store.SetMetadata(tc.id, tc.key, tc.value)
  121. if err != nil {
  122. t.Fatal(err)
  123. }
  124. actual, err := store.GetMetadata(tc.id, tc.key)
  125. if err != nil {
  126. t.Fatal(err)
  127. }
  128. if bytes.Compare(actual, tc.value) != 0 {
  129. t.Fatalf("Metadata expected %q, got %q", tc.value, actual)
  130. }
  131. }
  132. _, err = store.GetMetadata(id2, "tkey2")
  133. if err == nil {
  134. t.Fatal("Expected error for getting metadata for unknown key")
  135. }
  136. id3 := digest.FromBytes([]byte("baz"))
  137. err = store.SetMetadata(ID(id3), "tkey", []byte("tval"))
  138. if err == nil {
  139. t.Fatal("Expected error for setting metadata for unknown ID.")
  140. }
  141. _, err = store.GetMetadata(ID(id3), "tkey")
  142. if err == nil {
  143. t.Fatal("Expected error for getting metadata for unknown ID.")
  144. }
  145. }
  146. func TestFSMetadataGetSet(t *testing.T) {
  147. tmpdir, err := ioutil.TempDir("", "images-fs-store")
  148. if err != nil {
  149. t.Fatal(err)
  150. }
  151. defer os.RemoveAll(tmpdir)
  152. fs, err := NewFSStoreBackend(tmpdir)
  153. if err != nil {
  154. t.Fatal(err)
  155. }
  156. testMetadataGetSet(t, fs)
  157. }
  158. func TestFSDelete(t *testing.T) {
  159. tmpdir, err := ioutil.TempDir("", "images-fs-store")
  160. if err != nil {
  161. t.Fatal(err)
  162. }
  163. defer os.RemoveAll(tmpdir)
  164. fs, err := NewFSStoreBackend(tmpdir)
  165. if err != nil {
  166. t.Fatal(err)
  167. }
  168. testDelete(t, fs)
  169. }
  170. func TestFSWalker(t *testing.T) {
  171. tmpdir, err := ioutil.TempDir("", "images-fs-store")
  172. if err != nil {
  173. t.Fatal(err)
  174. }
  175. defer os.RemoveAll(tmpdir)
  176. fs, err := NewFSStoreBackend(tmpdir)
  177. if err != nil {
  178. t.Fatal(err)
  179. }
  180. testWalker(t, fs)
  181. }
  182. func TestFSInvalidWalker(t *testing.T) {
  183. tmpdir, err := ioutil.TempDir("", "images-fs-store")
  184. if err != nil {
  185. t.Fatal(err)
  186. }
  187. defer os.RemoveAll(tmpdir)
  188. fs, err := NewFSStoreBackend(tmpdir)
  189. if err != nil {
  190. t.Fatal(err)
  191. }
  192. fooID, err := fs.Set([]byte("foo"))
  193. if err != nil {
  194. t.Fatal(err)
  195. }
  196. if err := ioutil.WriteFile(filepath.Join(tmpdir, contentDirName, "sha256/foobar"), []byte("foobar"), 0600); err != nil {
  197. t.Fatal(err)
  198. }
  199. n := 0
  200. err = fs.Walk(func(id ID) error {
  201. if id != fooID {
  202. t.Fatalf("Invalid walker ID %q, expected %q", id, fooID)
  203. }
  204. n++
  205. return nil
  206. })
  207. if err != nil {
  208. t.Fatalf("Invalid data should not have caused walker error, got %v", err)
  209. }
  210. if n != 1 {
  211. t.Fatalf("Expected 1 walk initialization, got %d", n)
  212. }
  213. }
  214. func testGetSet(t *testing.T, store StoreBackend) {
  215. type tcase struct {
  216. input []byte
  217. expected ID
  218. }
  219. tcases := []tcase{
  220. {[]byte("foobar"), ID("sha256:c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2")},
  221. }
  222. randomInput := make([]byte, 8*1024)
  223. _, err := rand.Read(randomInput)
  224. if err != nil {
  225. t.Fatal(err)
  226. }
  227. // skipping use of digest pkg because its used by the implementation
  228. h := sha256.New()
  229. _, err = h.Write(randomInput)
  230. if err != nil {
  231. t.Fatal(err)
  232. }
  233. tcases = append(tcases, tcase{
  234. input: randomInput,
  235. expected: ID("sha256:" + hex.EncodeToString(h.Sum(nil))),
  236. })
  237. for _, tc := range tcases {
  238. id, err := store.Set([]byte(tc.input))
  239. if err != nil {
  240. t.Fatal(err)
  241. }
  242. if id != tc.expected {
  243. t.Fatalf("Expected ID %q, got %q", tc.expected, id)
  244. }
  245. }
  246. for _, emptyData := range [][]byte{nil, {}} {
  247. _, err := store.Set(emptyData)
  248. if err == nil {
  249. t.Fatal("Expected error for nil input.")
  250. }
  251. }
  252. for _, tc := range tcases {
  253. data, err := store.Get(tc.expected)
  254. if err != nil {
  255. t.Fatal(err)
  256. }
  257. if bytes.Compare(data, tc.input) != 0 {
  258. t.Fatalf("Expected data %q, got %q", tc.input, data)
  259. }
  260. }
  261. for _, key := range []ID{"foobar:abc", "sha256:abc", "sha256:c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2a"} {
  262. _, err := store.Get(key)
  263. if err == nil {
  264. t.Fatalf("Expected error for ID %q.", key)
  265. }
  266. }
  267. }
  268. func testDelete(t *testing.T, store StoreBackend) {
  269. id, err := store.Set([]byte("foo"))
  270. if err != nil {
  271. t.Fatal(err)
  272. }
  273. id2, err := store.Set([]byte("bar"))
  274. if err != nil {
  275. t.Fatal(err)
  276. }
  277. err = store.Delete(id)
  278. if err != nil {
  279. t.Fatal(err)
  280. }
  281. _, err = store.Get(id)
  282. if err == nil {
  283. t.Fatalf("Expected getting deleted item %q to fail", id)
  284. }
  285. _, err = store.Get(id2)
  286. if err != nil {
  287. t.Fatal(err)
  288. }
  289. err = store.Delete(id2)
  290. if err != nil {
  291. t.Fatal(err)
  292. }
  293. _, err = store.Get(id2)
  294. if err == nil {
  295. t.Fatalf("Expected getting deleted item %q to fail", id2)
  296. }
  297. }
  298. func testWalker(t *testing.T, store StoreBackend) {
  299. id, err := store.Set([]byte("foo"))
  300. if err != nil {
  301. t.Fatal(err)
  302. }
  303. id2, err := store.Set([]byte("bar"))
  304. if err != nil {
  305. t.Fatal(err)
  306. }
  307. tcases := make(map[ID]struct{})
  308. tcases[id] = struct{}{}
  309. tcases[id2] = struct{}{}
  310. n := 0
  311. err = store.Walk(func(id ID) error {
  312. delete(tcases, id)
  313. n++
  314. return nil
  315. })
  316. if err != nil {
  317. t.Fatal(err)
  318. }
  319. if n != 2 {
  320. t.Fatalf("Expected 2 walk initializations, got %d", n)
  321. }
  322. if len(tcases) != 0 {
  323. t.Fatalf("Expected empty unwalked set, got %+v", tcases)
  324. }
  325. // stop on error
  326. tcases = make(map[ID]struct{})
  327. tcases[id] = struct{}{}
  328. err = store.Walk(func(id ID) error {
  329. return errors.New("")
  330. })
  331. if err == nil {
  332. t.Fatalf("Exected error from walker.")
  333. }
  334. }