github.com/cdoern/storage@v1.12.13/drivers/aufs/aufs_test.go (about) 1 // +build linux 2 3 package aufs 4 5 import ( 6 "crypto/sha256" 7 "encoding/hex" 8 "fmt" 9 "io/ioutil" 10 "os" 11 "path" 12 "path/filepath" 13 "sync" 14 "testing" 15 16 "github.com/containers/storage/drivers" 17 "github.com/containers/storage/drivers/graphtest" 18 "github.com/containers/storage/pkg/archive" 19 "github.com/containers/storage/pkg/reexec" 20 "github.com/containers/storage/pkg/stringid" 21 "github.com/pkg/errors" 22 "github.com/stretchr/testify/assert" 23 "github.com/stretchr/testify/require" 24 ) 25 26 var ( 27 tmpOuter = path.Join(os.TempDir(), "aufs-tests") 28 tmp = path.Join(tmpOuter, "aufs") 29 ) 30 31 func init() { 32 reexec.Init() 33 } 34 35 func testInit(dir string, t testing.TB) graphdriver.Driver { 36 d, err := Init(dir, graphdriver.Options{}) 37 if err != nil { 38 if errors.Cause(err) == graphdriver.ErrNotSupported { 39 t.Skip(err) 40 } else { 41 t.Fatal(err) 42 } 43 } 44 return d 45 } 46 47 func driverGet(d *Driver, id string, mntLabel string) (string, error) { 48 options := graphdriver.MountOpts{ 49 MountLabel: mntLabel, 50 } 51 return d.Get(id, options) 52 } 53 54 func newDriver(t testing.TB) *Driver { 55 if err := os.MkdirAll(tmp, 0755); err != nil { 56 t.Fatal(err) 57 } 58 59 d := testInit(tmp, t) 60 return d.(*Driver) 61 } 62 63 func TestNewDriver(t *testing.T) { 64 if err := os.MkdirAll(tmp, 0755); err != nil { 65 t.Fatal(err) 66 } 67 68 d := testInit(tmp, t) 69 defer os.RemoveAll(tmp) 70 if d == nil { 71 t.Fatal("Driver should not be nil") 72 } 73 } 74 75 func TestAufsString(t *testing.T) { 76 d := newDriver(t) 77 defer os.RemoveAll(tmp) 78 79 if d.String() != "aufs" { 80 t.Fatalf("Expected aufs got %s", d.String()) 81 } 82 } 83 84 func TestCreateDirStructure(t *testing.T) { 85 newDriver(t) 86 defer os.RemoveAll(tmp) 87 88 paths := []string{ 89 "mnt", 90 "layers", 91 "diff", 92 } 93 94 for _, p := range paths { 95 if _, err := os.Stat(path.Join(tmp, p)); err != nil { 96 t.Fatal(err) 97 } 98 } 99 } 100 101 // We should be able to create two drivers with the same dir structure 102 func TestNewDriverFromExistingDir(t *testing.T) { 103 if err := os.MkdirAll(tmp, 0755); err != nil { 104 t.Fatal(err) 105 } 106 107 testInit(tmp, t) 108 testInit(tmp, t) 109 os.RemoveAll(tmp) 110 } 111 112 func TestCreateNewDir(t *testing.T) { 113 d := newDriver(t) 114 defer os.RemoveAll(tmp) 115 116 if err := d.Create("1", "", nil); err != nil { 117 t.Fatal(err) 118 } 119 } 120 121 func TestCreateNewDirStructure(t *testing.T) { 122 d := newDriver(t) 123 defer os.RemoveAll(tmp) 124 125 if err := d.Create("1", "", nil); err != nil { 126 t.Fatal(err) 127 } 128 129 paths := []string{ 130 "mnt", 131 "diff", 132 "layers", 133 } 134 135 for _, p := range paths { 136 if _, err := os.Stat(path.Join(tmp, p, "1")); err != nil { 137 t.Fatal(err) 138 } 139 } 140 } 141 142 func TestRemoveImage(t *testing.T) { 143 d := newDriver(t) 144 defer os.RemoveAll(tmp) 145 146 if err := d.Create("1", "", nil); err != nil { 147 t.Fatal(err) 148 } 149 150 if err := d.Remove("1"); err != nil { 151 t.Fatal(err) 152 } 153 154 paths := []string{ 155 "mnt", 156 "diff", 157 "layers", 158 } 159 160 for _, p := range paths { 161 if _, err := os.Stat(path.Join(tmp, p, "1")); err == nil { 162 t.Fatalf("Error should not be nil because dirs with id 1 should be deleted: %s", p) 163 } 164 if _, err := os.Stat(path.Join(tmp, p, "1-removing")); err == nil { 165 t.Fatalf("Error should not be nil because dirs with id 1-removing should be deleted: %s", p) 166 } 167 } 168 } 169 170 func TestGetWithoutParent(t *testing.T) { 171 d := newDriver(t) 172 defer os.RemoveAll(tmp) 173 174 if err := d.Create("1", "", nil); err != nil { 175 t.Fatal(err) 176 } 177 178 diffPath, err := d.Get("1", graphdriver.MountOpts{}) 179 if err != nil { 180 t.Fatal(err) 181 } 182 expected := path.Join(tmp, "diff", "1") 183 if diffPath != expected { 184 t.Fatalf("Expected path %s got %s", expected, diffPath) 185 } 186 } 187 188 func TestCleanupWithNoDirs(t *testing.T) { 189 d := newDriver(t) 190 defer os.RemoveAll(tmp) 191 192 err := d.Cleanup() 193 assert.NoError(t, err) 194 } 195 196 func TestCleanupWithDir(t *testing.T) { 197 d := newDriver(t) 198 defer os.RemoveAll(tmp) 199 200 if err := d.Create("1", "", nil); err != nil { 201 t.Fatal(err) 202 } 203 204 if err := d.Cleanup(); err != nil { 205 t.Fatal(err) 206 } 207 } 208 209 func TestMountedFalseResponse(t *testing.T) { 210 d := newDriver(t) 211 defer os.RemoveAll(tmp) 212 213 err := d.Create("1", "", nil) 214 require.NoError(t, err) 215 216 response, err := d.mounted(d.getDiffPath("1")) 217 require.NoError(t, err) 218 assert.False(t, response) 219 } 220 221 func TestMountedTrueResponse(t *testing.T) { 222 d := newDriver(t) 223 defer os.RemoveAll(tmp) 224 defer d.Cleanup() 225 226 err := d.Create("1", "", nil) 227 require.NoError(t, err) 228 err = d.Create("2", "1", nil) 229 require.NoError(t, err) 230 231 _, err = d.Get("2", graphdriver.MountOpts{}) 232 require.NoError(t, err) 233 234 response, err := d.mounted(d.pathCache["2"]) 235 require.NoError(t, err) 236 assert.True(t, response) 237 } 238 239 func TestMountWithParent(t *testing.T) { 240 d := newDriver(t) 241 defer os.RemoveAll(tmp) 242 243 if err := d.Create("1", "", nil); err != nil { 244 t.Fatal(err) 245 } 246 if err := d.Create("2", "1", nil); err != nil { 247 t.Fatal(err) 248 } 249 250 defer func() { 251 if err := d.Cleanup(); err != nil { 252 t.Fatal(err) 253 } 254 }() 255 256 mntPath, err := d.Get("2", graphdriver.MountOpts{}) 257 if err != nil { 258 t.Fatal(err) 259 } 260 if mntPath == "" { 261 t.Fatal("mntPath should not be nil") 262 } 263 264 expected := path.Join(tmp, "mnt", "2") 265 if mntPath != expected { 266 t.Fatalf("Expected %s got %s", expected, mntPath) 267 } 268 } 269 270 func TestRemoveMountedDir(t *testing.T) { 271 d := newDriver(t) 272 defer os.RemoveAll(tmp) 273 274 if err := d.Create("1", "", nil); err != nil { 275 t.Fatal(err) 276 } 277 if err := d.Create("2", "1", nil); err != nil { 278 t.Fatal(err) 279 } 280 281 defer func() { 282 if err := d.Cleanup(); err != nil { 283 t.Fatal(err) 284 } 285 }() 286 287 mntPath, err := d.Get("2", graphdriver.MountOpts{}) 288 if err != nil { 289 t.Fatal(err) 290 } 291 if mntPath == "" { 292 t.Fatal("mntPath should not be empty") 293 } 294 295 mounted, err := d.mounted(d.pathCache["2"]) 296 if err != nil { 297 t.Fatal(err) 298 } 299 300 if !mounted { 301 t.Fatal("Dir id 2 should be mounted") 302 } 303 304 if err := d.Remove("2"); err != nil { 305 t.Fatal(err) 306 } 307 } 308 309 func TestCreateWithInvalidParent(t *testing.T) { 310 d := newDriver(t) 311 defer os.RemoveAll(tmp) 312 313 if err := d.Create("1", "storage", nil); err == nil { 314 t.Fatal("Error should not be nil with parent does not exist") 315 } 316 } 317 318 func TestGetDiff(t *testing.T) { 319 d := newDriver(t) 320 defer os.RemoveAll(tmp) 321 322 if err := d.CreateReadWrite("1", "", nil); err != nil { 323 t.Fatal(err) 324 } 325 326 diffPath, err := driverGet(d, "1", "") 327 if err != nil { 328 t.Fatal(err) 329 } 330 331 // Add a file to the diff path with a fixed size 332 size := int64(1024) 333 334 f, err := os.Create(path.Join(diffPath, "test_file")) 335 if err != nil { 336 t.Fatal(err) 337 } 338 if err := f.Truncate(size); err != nil { 339 t.Fatal(err) 340 } 341 f.Close() 342 343 a, err := d.Diff("1", nil, "", nil, "") 344 if err != nil { 345 t.Fatal(err) 346 } 347 if a == nil { 348 t.Fatal("Archive should not be nil") 349 } 350 } 351 352 func TestChanges(t *testing.T) { 353 d := newDriver(t) 354 defer os.RemoveAll(tmp) 355 356 if err := d.Create("1", "", nil); err != nil { 357 t.Fatal(err) 358 } 359 360 if err := d.CreateReadWrite("2", "1", nil); err != nil { 361 t.Fatal(err) 362 } 363 364 defer func() { 365 if err := d.Cleanup(); err != nil { 366 t.Fatal(err) 367 } 368 }() 369 370 mntPoint, err := driverGet(d, "2", "") 371 if err != nil { 372 t.Fatal(err) 373 } 374 375 // Create a file to save in the mountpoint 376 f, err := os.Create(path.Join(mntPoint, "test.txt")) 377 if err != nil { 378 t.Fatal(err) 379 } 380 381 if _, err := f.WriteString("testline"); err != nil { 382 t.Fatal(err) 383 } 384 if err := f.Close(); err != nil { 385 t.Fatal(err) 386 } 387 388 changes, err := d.Changes("2", nil, "", nil, "") 389 if err != nil { 390 t.Fatal(err) 391 } 392 if len(changes) != 1 { 393 t.Fatalf("Dir 2 should have one change from parent got %d", len(changes)) 394 } 395 change := changes[0] 396 397 expectedPath := "/test.txt" 398 if change.Path != expectedPath { 399 t.Fatalf("Expected path %s got %s", expectedPath, change.Path) 400 } 401 402 if change.Kind != archive.ChangeAdd { 403 t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind) 404 } 405 406 if err := d.CreateReadWrite("3", "2", nil); err != nil { 407 t.Fatal(err) 408 } 409 mntPoint, err = driverGet(d, "3", "") 410 if err != nil { 411 t.Fatal(err) 412 } 413 414 // Create a file to save in the mountpoint 415 f, err = os.Create(path.Join(mntPoint, "test2.txt")) 416 if err != nil { 417 t.Fatal(err) 418 } 419 420 if _, err := f.WriteString("testline"); err != nil { 421 t.Fatal(err) 422 } 423 if err := f.Close(); err != nil { 424 t.Fatal(err) 425 } 426 427 changes, err = d.Changes("3", nil, "2", nil, "") 428 if err != nil { 429 t.Fatal(err) 430 } 431 432 if len(changes) != 1 { 433 t.Fatalf("Dir 2 should have one change from parent got %d", len(changes)) 434 } 435 change = changes[0] 436 437 expectedPath = "/test2.txt" 438 if change.Path != expectedPath { 439 t.Fatalf("Expected path %s got %s", expectedPath, change.Path) 440 } 441 442 if change.Kind != archive.ChangeAdd { 443 t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind) 444 } 445 } 446 447 func TestDiffSize(t *testing.T) { 448 d := newDriver(t) 449 defer os.RemoveAll(tmp) 450 451 if err := d.CreateReadWrite("1", "", nil); err != nil { 452 t.Fatal(err) 453 } 454 455 diffPath, err := driverGet(d, "1", "") 456 if err != nil { 457 t.Fatal(err) 458 } 459 460 // Add a file to the diff path with a fixed size 461 size := int64(1024) 462 463 f, err := os.Create(path.Join(diffPath, "test_file")) 464 if err != nil { 465 t.Fatal(err) 466 } 467 if err := f.Truncate(size); err != nil { 468 t.Fatal(err) 469 } 470 s, err := f.Stat() 471 if err != nil { 472 t.Fatal(err) 473 } 474 size = s.Size() 475 if err := f.Close(); err != nil { 476 t.Fatal(err) 477 } 478 479 diffSize, err := d.DiffSize("1", nil, "", nil, "") 480 if err != nil { 481 t.Fatal(err) 482 } 483 if diffSize != size { 484 t.Fatalf("Expected size to be %d got %d", size, diffSize) 485 } 486 } 487 488 func TestChildDiffSize(t *testing.T) { 489 d := newDriver(t) 490 defer os.RemoveAll(tmp) 491 defer d.Cleanup() 492 493 if err := d.CreateReadWrite("1", "", nil); err != nil { 494 t.Fatal(err) 495 } 496 497 diffPath, err := driverGet(d, "1", "") 498 if err != nil { 499 t.Fatal(err) 500 } 501 502 // Add a file to the diff path with a fixed size 503 size := int64(1024) 504 505 f, err := os.Create(path.Join(diffPath, "test_file")) 506 if err != nil { 507 t.Fatal(err) 508 } 509 if err := f.Truncate(size); err != nil { 510 t.Fatal(err) 511 } 512 s, err := f.Stat() 513 if err != nil { 514 t.Fatal(err) 515 } 516 size = s.Size() 517 if err := f.Close(); err != nil { 518 t.Fatal(err) 519 } 520 521 diffSize, err := d.DiffSize("1", nil, "", nil, "") 522 if err != nil { 523 t.Fatal(err) 524 } 525 if diffSize != size { 526 t.Fatalf("Expected size to be %d got %d", size, diffSize) 527 } 528 529 if err := d.Create("2", "1", nil); err != nil { 530 t.Fatal(err) 531 } 532 533 diffSize, err = d.DiffSize("2", nil, "1", nil, "") 534 if err != nil { 535 t.Fatal(err) 536 } 537 // The diff size for the child should be zero 538 if diffSize != 0 { 539 t.Fatalf("Expected size to be %d got %d", 0, diffSize) 540 } 541 } 542 543 func TestExists(t *testing.T) { 544 d := newDriver(t) 545 defer os.RemoveAll(tmp) 546 defer d.Cleanup() 547 548 if err := d.Create("1", "", nil); err != nil { 549 t.Fatal(err) 550 } 551 552 if d.Exists("none") { 553 t.Fatal("id none should not exist in the driver") 554 } 555 556 if !d.Exists("1") { 557 t.Fatal("id 1 should exist in the driver") 558 } 559 } 560 561 func TestStatus(t *testing.T) { 562 d := newDriver(t) 563 defer os.RemoveAll(tmp) 564 defer d.Cleanup() 565 566 if err := d.Create("1", "", nil); err != nil { 567 t.Fatal(err) 568 } 569 570 status := d.Status() 571 assert.Len(t, status, 4) 572 573 rootDir := status[0] 574 dirs := status[2] 575 if rootDir[0] != "Root Dir" { 576 t.Fatalf("Expected Root Dir got %s", rootDir[0]) 577 } 578 if rootDir[1] != d.rootPath() { 579 t.Fatalf("Expected %s got %s", d.rootPath(), rootDir[1]) 580 } 581 if dirs[0] != "Dirs" { 582 t.Fatalf("Expected Dirs got %s", dirs[0]) 583 } 584 if dirs[1] != "1" { 585 t.Fatalf("Expected 1 got %s", dirs[1]) 586 } 587 } 588 589 func TestApplyDiff(t *testing.T) { 590 d := newDriver(t) 591 defer os.RemoveAll(tmp) 592 defer d.Cleanup() 593 594 if err := d.CreateReadWrite("1", "", nil); err != nil { 595 t.Fatal(err) 596 } 597 598 diffPath, err := driverGet(d, "1", "") 599 if err != nil { 600 t.Fatal(err) 601 } 602 603 // Add a file to the diff path with a fixed size 604 size := int64(1024) 605 606 f, err := os.Create(path.Join(diffPath, "test_file")) 607 if err != nil { 608 t.Fatal(err) 609 } 610 if err := f.Truncate(size); err != nil { 611 t.Fatal(err) 612 } 613 f.Close() 614 615 diff, err := d.Diff("1", nil, "", nil, "") 616 if err != nil { 617 t.Fatal(err) 618 } 619 620 if err := d.Create("2", "", nil); err != nil { 621 t.Fatal(err) 622 } 623 if err := d.Create("3", "2", nil); err != nil { 624 t.Fatal(err) 625 } 626 627 if err := d.applyDiff("3", nil, diff); err != nil { 628 t.Fatal(err) 629 } 630 631 // Ensure that the file is in the mount point for id 3 632 633 mountPoint, err := driverGet(d, "3", "") 634 if err != nil { 635 t.Fatal(err) 636 } 637 if _, err := os.Stat(path.Join(mountPoint, "test_file")); err != nil { 638 t.Fatal(err) 639 } 640 } 641 642 func hash(c string) string { 643 h := sha256.New() 644 fmt.Fprint(h, c) 645 return hex.EncodeToString(h.Sum(nil)) 646 } 647 648 func testMountMoreThan42Layers(t *testing.T, mountPath string) { 649 if err := os.MkdirAll(mountPath, 0755); err != nil { 650 t.Fatal(err) 651 } 652 653 defer os.RemoveAll(mountPath) 654 d := testInit(mountPath, t).(*Driver) 655 defer d.Cleanup() 656 var last string 657 var expected int 658 659 for i := 1; i < 127; i++ { 660 expected++ 661 var ( 662 parent = fmt.Sprintf("%d", i-1) 663 current = fmt.Sprintf("%d", i) 664 ) 665 666 if parent == "0" { 667 parent = "" 668 } else { 669 parent = hash(parent) 670 } 671 current = hash(current) 672 673 err := d.CreateReadWrite(current, parent, nil) 674 require.NoError(t, err, "current layer %d", i) 675 676 point, err := driverGet(d, current, "") 677 require.NoError(t, err, "current layer %d", i) 678 679 f, err := os.Create(path.Join(point, current)) 680 require.NoError(t, err, "current layer %d", i) 681 f.Close() 682 683 if i%10 == 0 { 684 err := os.Remove(path.Join(point, parent)) 685 require.NoError(t, err, "current layer %d", i) 686 expected-- 687 } 688 last = current 689 } 690 691 // Perform the actual mount for the top most image 692 point, err := driverGet(d, last, "") 693 require.NoError(t, err) 694 files, err := ioutil.ReadDir(point) 695 require.NoError(t, err) 696 assert.Len(t, files, expected) 697 } 698 699 func TestMountMoreThan42Layers(t *testing.T) { 700 defer os.RemoveAll(tmpOuter) 701 testMountMoreThan42Layers(t, tmp) 702 } 703 704 func TestMountMoreThan42LayersMatchingPathLength(t *testing.T) { 705 defer os.RemoveAll(tmpOuter) 706 zeroes := "0" 707 for { 708 // This finds a mount path so that when combined into aufs mount options 709 // 4096 byte boundary would be in between the paths or in permission 710 // section. For '/tmp' it will use '/tmp/aufs-tests/00000000/aufs' 711 mountPath := path.Join(tmpOuter, zeroes, "aufs") 712 pathLength := 77 + len(mountPath) 713 714 if mod := 4095 % pathLength; mod == 0 || mod > pathLength-2 { 715 t.Logf("Using path: %s", mountPath) 716 testMountMoreThan42Layers(t, mountPath) 717 return 718 } 719 zeroes += "0" 720 } 721 } 722 723 func BenchmarkConcurrentAccess(b *testing.B) { 724 b.StopTimer() 725 b.ResetTimer() 726 727 d := newDriver(b) 728 defer os.RemoveAll(tmp) 729 defer d.Cleanup() 730 731 numConcurrent := 256 732 // create a bunch of ids 733 var ids []string 734 for i := 0; i < numConcurrent; i++ { 735 ids = append(ids, stringid.GenerateNonCryptoID()) 736 } 737 738 if err := d.Create(ids[0], "", nil); err != nil { 739 b.Fatal(err) 740 } 741 742 if err := d.Create(ids[1], ids[0], nil); err != nil { 743 b.Fatal(err) 744 } 745 746 parent := ids[1] 747 ids = append(ids[2:]) 748 749 chErr := make(chan error, numConcurrent) 750 var outerGroup sync.WaitGroup 751 outerGroup.Add(len(ids)) 752 b.StartTimer() 753 754 // here's the actual bench 755 for _, id := range ids { 756 go func(id string) { 757 defer outerGroup.Done() 758 if err := d.Create(id, parent, nil); err != nil { 759 b.Logf("Create %s failed", id) 760 chErr <- err 761 return 762 } 763 var innerGroup sync.WaitGroup 764 for i := 0; i < b.N; i++ { 765 innerGroup.Add(1) 766 go func() { 767 d.Get(id, graphdriver.MountOpts{}) 768 d.Put(id) 769 innerGroup.Done() 770 }() 771 } 772 innerGroup.Wait() 773 d.Remove(id) 774 }(id) 775 } 776 777 outerGroup.Wait() 778 b.StopTimer() 779 close(chErr) 780 for err := range chErr { 781 if err != nil { 782 b.Log(err) 783 b.Fail() 784 } 785 } 786 } 787 788 func TestInitStaleCleanup(t *testing.T) { 789 if err := os.MkdirAll(tmp, 0755); err != nil { 790 t.Fatal(err) 791 } 792 defer os.RemoveAll(tmp) 793 794 for _, d := range []string{"diff", "mnt"} { 795 if err := os.MkdirAll(filepath.Join(tmp, d, "123-removing"), 0755); err != nil { 796 t.Fatal(err) 797 } 798 } 799 800 testInit(tmp, t) 801 for _, d := range []string{"diff", "mnt"} { 802 if _, err := os.Stat(filepath.Join(tmp, d, "123-removing")); err == nil { 803 t.Fatal("cleanup failed") 804 } 805 } 806 } 807 808 func TestAufsCreateEmpty(t *testing.T) { 809 graphtest.DriverTestCreateEmpty(t, "aufs") 810 } 811 812 func TestAufsCreateBase(t *testing.T) { 813 graphtest.DriverTestCreateBase(t, "aufs") 814 } 815 816 func TestAufsCreateSnap(t *testing.T) { 817 graphtest.DriverTestCreateSnap(t, "aufs") 818 } 819 820 func TestAufsCreateFromTemplate(t *testing.T) { 821 graphtest.DriverTestCreateFromTemplate(t, "aufs") 822 } 823 824 func TestAufsEcho(t *testing.T) { 825 graphtest.DriverTestEcho(t, "aufs") 826 }