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