github.com/rawahars/moby@v24.0.4+incompatible/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 "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.Encoded()), []byte("foobar2"), 0o600) 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.Encoded()), 0o700) 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 func TestFSMetadataGetSet(t *testing.T) { 84 store, cleanup := defaultFSStoreBackend(t) 85 defer cleanup() 86 87 id, err := store.Set([]byte("foo")) 88 assert.Check(t, err) 89 90 id2, err := store.Set([]byte("bar")) 91 assert.Check(t, err) 92 93 tcases := []struct { 94 id digest.Digest 95 key string 96 value []byte 97 }{ 98 {id, "tkey", []byte("tval1")}, 99 {id, "tkey2", []byte("tval2")}, 100 {id2, "tkey", []byte("tval3")}, 101 } 102 103 for _, tc := range tcases { 104 err = store.SetMetadata(tc.id, tc.key, tc.value) 105 assert.Check(t, err) 106 107 actual, err := store.GetMetadata(tc.id, tc.key) 108 assert.Check(t, err) 109 110 assert.Check(t, is.DeepEqual(tc.value, actual)) 111 } 112 113 _, err = store.GetMetadata(id2, "tkey2") 114 assert.Check(t, is.ErrorContains(err, "failed to read metadata")) 115 116 id3 := digest.FromBytes([]byte("baz")) 117 err = store.SetMetadata(id3, "tkey", []byte("tval")) 118 assert.Check(t, is.ErrorContains(err, "failed to get digest")) 119 120 _, err = store.GetMetadata(id3, "tkey") 121 assert.Check(t, is.ErrorContains(err, "failed to get digest")) 122 } 123 124 func TestFSInvalidWalker(t *testing.T) { 125 store, cleanup := defaultFSStoreBackend(t) 126 defer cleanup() 127 128 fooID, err := store.Set([]byte("foo")) 129 assert.Check(t, err) 130 131 err = os.WriteFile(filepath.Join(store.(*fs).root, contentDirName, "sha256/foobar"), []byte("foobar"), 0600) 132 assert.Check(t, err) 133 134 n := 0 135 err = store.Walk(func(id digest.Digest) error { 136 assert.Check(t, is.Equal(fooID, id)) 137 n++ 138 return nil 139 }) 140 assert.Check(t, err) 141 assert.Check(t, is.Equal(1, n)) 142 } 143 144 func TestFSGetSet(t *testing.T) { 145 store, cleanup := defaultFSStoreBackend(t) 146 defer cleanup() 147 148 type tcase struct { 149 input []byte 150 expected digest.Digest 151 } 152 tcases := []tcase{ 153 {[]byte("foobar"), digest.Digest("sha256:c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2")}, 154 } 155 156 randomInput := make([]byte, 8*1024) 157 _, err := rand.Read(randomInput) 158 assert.Check(t, err) 159 160 // skipping use of digest pkg because it is used by the implementation 161 h := sha256.New() 162 _, err = h.Write(randomInput) 163 assert.Check(t, err) 164 165 tcases = append(tcases, tcase{ 166 input: randomInput, 167 expected: digest.Digest("sha256:" + hex.EncodeToString(h.Sum(nil))), 168 }) 169 170 for _, tc := range tcases { 171 id, err := store.Set(tc.input) 172 assert.Check(t, err) 173 assert.Check(t, is.Equal(tc.expected, id)) 174 } 175 176 for _, tc := range tcases { 177 data, err := store.Get(tc.expected) 178 assert.Check(t, err) 179 assert.Check(t, is.DeepEqual(tc.input, data)) 180 } 181 } 182 183 func TestFSGetUnsetKey(t *testing.T) { 184 store, cleanup := defaultFSStoreBackend(t) 185 defer cleanup() 186 187 for _, key := range []digest.Digest{"foobar:abc", "sha256:abc", "sha256:c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2a"} { 188 _, err := store.Get(key) 189 assert.Check(t, is.ErrorContains(err, "failed to get digest")) 190 } 191 } 192 193 func TestFSGetEmptyData(t *testing.T) { 194 store, cleanup := defaultFSStoreBackend(t) 195 defer cleanup() 196 197 for _, emptyData := range [][]byte{nil, {}} { 198 _, err := store.Set(emptyData) 199 assert.Check(t, is.ErrorContains(err, "invalid empty data")) 200 } 201 } 202 203 func TestFSDelete(t *testing.T) { 204 store, cleanup := defaultFSStoreBackend(t) 205 defer cleanup() 206 207 id, err := store.Set([]byte("foo")) 208 assert.Check(t, err) 209 210 id2, err := store.Set([]byte("bar")) 211 assert.Check(t, err) 212 213 err = store.Delete(id) 214 assert.Check(t, err) 215 216 _, err = store.Get(id) 217 assert.Check(t, is.ErrorContains(err, "failed to get digest")) 218 219 _, err = store.Get(id2) 220 assert.Check(t, err) 221 222 err = store.Delete(id2) 223 assert.Check(t, err) 224 225 _, err = store.Get(id2) 226 assert.Check(t, is.ErrorContains(err, "failed to get digest")) 227 } 228 229 func TestFSWalker(t *testing.T) { 230 store, cleanup := defaultFSStoreBackend(t) 231 defer cleanup() 232 233 id, err := store.Set([]byte("foo")) 234 assert.Check(t, err) 235 236 id2, err := store.Set([]byte("bar")) 237 assert.Check(t, err) 238 239 tcases := make(map[digest.Digest]struct{}) 240 tcases[id] = struct{}{} 241 tcases[id2] = struct{}{} 242 n := 0 243 err = store.Walk(func(id digest.Digest) error { 244 delete(tcases, id) 245 n++ 246 return nil 247 }) 248 assert.Check(t, err) 249 assert.Check(t, is.Equal(2, n)) 250 assert.Check(t, is.Len(tcases, 0)) 251 } 252 253 func TestFSWalkerStopOnError(t *testing.T) { 254 store, cleanup := defaultFSStoreBackend(t) 255 defer cleanup() 256 257 id, err := store.Set([]byte("foo")) 258 assert.Check(t, err) 259 260 tcases := make(map[digest.Digest]struct{}) 261 tcases[id] = struct{}{} 262 err = store.Walk(func(id digest.Digest) error { 263 return errors.New("what") 264 }) 265 assert.Check(t, is.ErrorContains(err, "what")) 266 }