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