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