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