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