| ... | ... |
@@ -21,7 +21,7 @@ type Driver struct {
|
| 21 | 21 |
home string |
| 22 | 22 |
} |
| 23 | 23 |
|
| 24 |
-func Init(home string) (graphdriver.Driver, error) {
|
|
| 24 |
+var Init = func(home string) (graphdriver.Driver, error) {
|
|
| 25 | 25 |
deviceSet, err := NewDeviceSet(home, true) |
| 26 | 26 |
if err != nil {
|
| 27 | 27 |
return nil, err |
| ... | ... |
@@ -56,7 +56,7 @@ func (d *Driver) Cleanup() error {
|
| 56 | 56 |
return d.DeviceSet.Shutdown() |
| 57 | 57 |
} |
| 58 | 58 |
|
| 59 |
-func (d *Driver) Create(id string, parent string) error {
|
|
| 59 |
+func (d *Driver) Create(id, parent string) error {
|
|
| 60 | 60 |
if err := d.DeviceSet.AddDevice(id, parent); err != nil {
|
| 61 | 61 |
return err |
| 62 | 62 |
} |
| ... | ... |
@@ -2,10 +2,12 @@ package devmapper |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"fmt" |
| 5 |
+ "github.com/dotcloud/docker/graphdriver" |
|
| 5 | 6 |
"io/ioutil" |
| 6 | 7 |
"path" |
| 7 | 8 |
"runtime" |
| 8 | 9 |
"strings" |
| 10 |
+ "syscall" |
|
| 9 | 11 |
"testing" |
| 10 | 12 |
) |
| 11 | 13 |
|
| ... | ... |
@@ -82,6 +84,39 @@ func denyAllDevmapper() {
|
| 82 | 82 |
} |
| 83 | 83 |
} |
| 84 | 84 |
|
| 85 |
+func denyAllSyscall() {
|
|
| 86 |
+ sysMount = func(source, target, fstype string, flags uintptr, data string) (err error) {
|
|
| 87 |
+ panic("sysMount: this method should not be called here")
|
|
| 88 |
+ } |
|
| 89 |
+ sysUnmount = func(target string, flags int) (err error) {
|
|
| 90 |
+ panic("sysUnmount: this method should not be called here")
|
|
| 91 |
+ } |
|
| 92 |
+ sysCloseOnExec = func(fd int) {
|
|
| 93 |
+ panic("sysCloseOnExec: this method should not be called here")
|
|
| 94 |
+ } |
|
| 95 |
+ sysSyscall = func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
|
|
| 96 |
+ panic("sysSyscall: this method should not be called here")
|
|
| 97 |
+ } |
|
| 98 |
+ // Not a syscall, but forbidding it here anyway |
|
| 99 |
+ Mounted = func(mnt string) (bool, error) {
|
|
| 100 |
+ panic("devmapper.Mounted: this method should not be called here")
|
|
| 101 |
+ } |
|
| 102 |
+ // osOpenFile = os.OpenFile |
|
| 103 |
+ // osNewFile = os.NewFile |
|
| 104 |
+ // osCreate = os.Create |
|
| 105 |
+ // osStat = os.Stat |
|
| 106 |
+ // osIsNotExist = os.IsNotExist |
|
| 107 |
+ // osIsExist = os.IsExist |
|
| 108 |
+ // osMkdirAll = os.MkdirAll |
|
| 109 |
+ // osRemoveAll = os.RemoveAll |
|
| 110 |
+ // osRename = os.Rename |
|
| 111 |
+ // osReadlink = os.Readlink |
|
| 112 |
+ |
|
| 113 |
+ // execRun = func(name string, args ...string) error {
|
|
| 114 |
+ // return exec.Command(name, args...).Run() |
|
| 115 |
+ // } |
|
| 116 |
+} |
|
| 117 |
+ |
|
| 85 | 118 |
func mkTestDirectory(t *testing.T) string {
|
| 86 | 119 |
dir, err := ioutil.TempDir("", "docker-test-devmapper-")
|
| 87 | 120 |
if err != nil {
|
| ... | ... |
@@ -119,12 +154,15 @@ func (r Set) Assert(t *testing.T, names ...string) {
|
| 119 | 119 |
} |
| 120 | 120 |
|
| 121 | 121 |
func TestInit(t *testing.T) {
|
| 122 |
- home := mkTestDirectory(t) |
|
| 122 |
+ var ( |
|
| 123 |
+ calls = make(Set) |
|
| 124 |
+ devicesAttached = make(Set) |
|
| 125 |
+ taskMessages = make(Set) |
|
| 126 |
+ taskTypes = make(Set) |
|
| 127 |
+ home = mkTestDirectory(t) |
|
| 128 |
+ ) |
|
| 123 | 129 |
defer osRemoveAll(home) |
| 124 |
- calls := make(Set) |
|
| 125 |
- devicesAttached := make(Set) |
|
| 126 |
- taskMessages := make(Set) |
|
| 127 |
- taskTypes := make(Set) |
|
| 130 |
+ |
|
| 128 | 131 |
func() {
|
| 129 | 132 |
denyAllDevmapper() |
| 130 | 133 |
DmSetDevDir = func(dir string) int {
|
| ... | ... |
@@ -295,8 +333,12 @@ func TestInit(t *testing.T) {
|
| 295 | 295 |
} |
| 296 | 296 |
}() |
| 297 | 297 |
}() |
| 298 |
+ // Put all tests in a funciton to make sure the garbage collection will |
|
| 299 |
+ // occur. |
|
| 298 | 300 |
|
| 301 |
+ // Call GC to cleanup runtime.Finalizers |
|
| 299 | 302 |
runtime.GC() |
| 303 |
+ |
|
| 300 | 304 |
calls.Assert(t, |
| 301 | 305 |
"DmSetDevDir", |
| 302 | 306 |
"DmLogWithErrnoInit", |
| ... | ... |
@@ -320,38 +362,288 @@ func TestInit(t *testing.T) {
|
| 320 | 320 |
taskMessages.Assert(t, "create_thin 0", "set_transaction_id 0 1") |
| 321 | 321 |
} |
| 322 | 322 |
|
| 323 |
+func fakeInit() func(home string) (graphdriver.Driver, error) {
|
|
| 324 |
+ oldInit := Init |
|
| 325 |
+ Init = func(home string) (graphdriver.Driver, error) {
|
|
| 326 |
+ return &Driver{
|
|
| 327 |
+ home: home, |
|
| 328 |
+ }, nil |
|
| 329 |
+ } |
|
| 330 |
+ return oldInit |
|
| 331 |
+} |
|
| 332 |
+ |
|
| 333 |
+func restoreInit(init func(home string) (graphdriver.Driver, error)) {
|
|
| 334 |
+ Init = init |
|
| 335 |
+} |
|
| 336 |
+ |
|
| 337 |
+func mockAllDevmapper(calls Set) {
|
|
| 338 |
+ DmSetDevDir = func(dir string) int {
|
|
| 339 |
+ calls["DmSetDevDir"] = true |
|
| 340 |
+ return 0 |
|
| 341 |
+ } |
|
| 342 |
+ LogWithErrnoInit = func() {
|
|
| 343 |
+ calls["DmLogWithErrnoInit"] = true |
|
| 344 |
+ } |
|
| 345 |
+ DmTaskCreate = func(taskType int) *CDmTask {
|
|
| 346 |
+ calls["DmTaskCreate"] = true |
|
| 347 |
+ return &CDmTask{}
|
|
| 348 |
+ } |
|
| 349 |
+ DmTaskSetName = func(task *CDmTask, name string) int {
|
|
| 350 |
+ calls["DmTaskSetName"] = true |
|
| 351 |
+ return 1 |
|
| 352 |
+ } |
|
| 353 |
+ DmTaskRun = func(task *CDmTask) int {
|
|
| 354 |
+ calls["DmTaskRun"] = true |
|
| 355 |
+ return 1 |
|
| 356 |
+ } |
|
| 357 |
+ DmTaskGetInfo = func(task *CDmTask, info *Info) int {
|
|
| 358 |
+ calls["DmTaskGetInfo"] = true |
|
| 359 |
+ return 1 |
|
| 360 |
+ } |
|
| 361 |
+ DmTaskSetSector = func(task *CDmTask, sector uint64) int {
|
|
| 362 |
+ calls["DmTaskSetSector"] = true |
|
| 363 |
+ return 1 |
|
| 364 |
+ } |
|
| 365 |
+ DmTaskSetMessage = func(task *CDmTask, message string) int {
|
|
| 366 |
+ calls["DmTaskSetMessage"] = true |
|
| 367 |
+ return 1 |
|
| 368 |
+ } |
|
| 369 |
+ DmAttachLoopDevice = func(filename string, fd *int) string {
|
|
| 370 |
+ calls["DmAttachLoopDevice"] = true |
|
| 371 |
+ return "/dev/loop42" |
|
| 372 |
+ } |
|
| 373 |
+ DmTaskDestroy = func(task *CDmTask) {
|
|
| 374 |
+ calls["DmTaskDestroy"] = true |
|
| 375 |
+ } |
|
| 376 |
+ DmGetBlockSize = func(fd uintptr) (int64, sysErrno) {
|
|
| 377 |
+ calls["DmGetBlockSize"] = true |
|
| 378 |
+ return int64(4242 * 512), 0 |
|
| 379 |
+ } |
|
| 380 |
+ DmTaskAddTarget = func(task *CDmTask, start, size uint64, ttype, params string) int {
|
|
| 381 |
+ calls["DmTaskSetTarget"] = true |
|
| 382 |
+ return 1 |
|
| 383 |
+ } |
|
| 384 |
+ DmTaskSetCookie = func(task *CDmTask, cookie *uint, flags uint16) int {
|
|
| 385 |
+ calls["DmTaskSetCookie"] = true |
|
| 386 |
+ return 1 |
|
| 387 |
+ } |
|
| 388 |
+ DmUdevWait = func(cookie uint) int {
|
|
| 389 |
+ calls["DmUdevWait"] = true |
|
| 390 |
+ return 1 |
|
| 391 |
+ } |
|
| 392 |
+ DmTaskSetAddNode = func(task *CDmTask, addNode AddNodeType) int {
|
|
| 393 |
+ calls["DmTaskSetAddNode"] = true |
|
| 394 |
+ return 1 |
|
| 395 |
+ } |
|
| 396 |
+ execRun = func(name string, args ...string) error {
|
|
| 397 |
+ calls["execRun"] = true |
|
| 398 |
+ return nil |
|
| 399 |
+ } |
|
| 400 |
+} |
|
| 401 |
+ |
|
| 323 | 402 |
func TestDriverName(t *testing.T) {
|
| 324 |
- t.Skip("FIXME: not a unit test")
|
|
| 325 |
- d := newDriver(t) |
|
| 326 |
- defer cleanup(d) |
|
| 403 |
+ denyAllDevmapper() |
|
| 404 |
+ defer denyAllDevmapper() |
|
| 327 | 405 |
|
| 406 |
+ oldInit := fakeInit() |
|
| 407 |
+ defer restoreInit(oldInit) |
|
| 408 |
+ |
|
| 409 |
+ d := newDriver(t) |
|
| 328 | 410 |
if d.String() != "devicemapper" {
|
| 329 | 411 |
t.Fatalf("Expected driver name to be devicemapper got %s", d.String())
|
| 330 | 412 |
} |
| 331 | 413 |
} |
| 332 | 414 |
|
| 333 | 415 |
func TestDriverCreate(t *testing.T) {
|
| 334 |
- t.Skip("FIXME: not a unit test")
|
|
| 335 |
- d := newDriver(t) |
|
| 336 |
- defer cleanup(d) |
|
| 416 |
+ denyAllDevmapper() |
|
| 417 |
+ denyAllSyscall() |
|
| 418 |
+ defer denyAllSyscall() |
|
| 419 |
+ defer denyAllDevmapper() |
|
| 337 | 420 |
|
| 338 |
- if err := d.Create("1", ""); err != nil {
|
|
| 339 |
- t.Fatal(err) |
|
| 421 |
+ calls := make(Set) |
|
| 422 |
+ mockAllDevmapper(calls) |
|
| 423 |
+ |
|
| 424 |
+ sysMount = func(source, target, fstype string, flags uintptr, data string) (err error) {
|
|
| 425 |
+ calls["sysMount"] = true |
|
| 426 |
+ // FIXME: compare the exact source and target strings (inodes + devname) |
|
| 427 |
+ if expectedSource := "/dev/mapper/docker-"; !strings.HasPrefix(source, expectedSource) {
|
|
| 428 |
+ t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedSource, source)
|
|
| 429 |
+ } |
|
| 430 |
+ if expectedTarget := "/tmp/docker-test-devmapper-"; !strings.HasPrefix(target, expectedTarget) {
|
|
| 431 |
+ t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedTarget, target)
|
|
| 432 |
+ } |
|
| 433 |
+ if expectedFstype := "ext4"; fstype != expectedFstype {
|
|
| 434 |
+ t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedFstype, fstype)
|
|
| 435 |
+ } |
|
| 436 |
+ if expectedFlags := uintptr(3236757504); flags != expectedFlags {
|
|
| 437 |
+ t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedFlags, flags)
|
|
| 438 |
+ } |
|
| 439 |
+ return nil |
|
| 440 |
+ } |
|
| 441 |
+ |
|
| 442 |
+ Mounted = func(mnt string) (bool, error) {
|
|
| 443 |
+ calls["Mounted"] = true |
|
| 444 |
+ if !strings.HasPrefix(mnt, "/tmp/docker-test-devmapper-") || !strings.HasSuffix(mnt, "/mnt/1") {
|
|
| 445 |
+ t.Fatalf("Wrong mounted call\nExpected: Mounted(%v)\nReceived: Mounted(%v)\n", "/tmp/docker-test-devmapper-.../mnt/1", mnt)
|
|
| 446 |
+ } |
|
| 447 |
+ return false, nil |
|
| 340 | 448 |
} |
| 449 |
+ |
|
| 450 |
+ func() {
|
|
| 451 |
+ d := newDriver(t) |
|
| 452 |
+ |
|
| 453 |
+ calls.Assert(t, |
|
| 454 |
+ "DmSetDevDir", |
|
| 455 |
+ "DmLogWithErrnoInit", |
|
| 456 |
+ "DmTaskSetName", |
|
| 457 |
+ "DmTaskRun", |
|
| 458 |
+ "DmTaskGetInfo", |
|
| 459 |
+ "DmAttachLoopDevice", |
|
| 460 |
+ "execRun", |
|
| 461 |
+ "DmTaskCreate", |
|
| 462 |
+ "DmGetBlockSize", |
|
| 463 |
+ "DmTaskSetTarget", |
|
| 464 |
+ "DmTaskSetCookie", |
|
| 465 |
+ "DmUdevWait", |
|
| 466 |
+ "DmTaskSetSector", |
|
| 467 |
+ "DmTaskSetMessage", |
|
| 468 |
+ "DmTaskSetAddNode", |
|
| 469 |
+ ) |
|
| 470 |
+ |
|
| 471 |
+ if err := d.Create("1", ""); err != nil {
|
|
| 472 |
+ t.Fatal(err) |
|
| 473 |
+ } |
|
| 474 |
+ calls.Assert(t, |
|
| 475 |
+ "DmTaskCreate", |
|
| 476 |
+ "DmTaskGetInfo", |
|
| 477 |
+ "sysMount", |
|
| 478 |
+ "Mounted", |
|
| 479 |
+ "DmTaskRun", |
|
| 480 |
+ "DmTaskSetTarget", |
|
| 481 |
+ "DmTaskSetSector", |
|
| 482 |
+ "DmTaskSetCookie", |
|
| 483 |
+ "DmUdevWait", |
|
| 484 |
+ "DmTaskSetName", |
|
| 485 |
+ "DmTaskSetMessage", |
|
| 486 |
+ "DmTaskSetAddNode", |
|
| 487 |
+ ) |
|
| 488 |
+ |
|
| 489 |
+ }() |
|
| 490 |
+ |
|
| 491 |
+ runtime.GC() |
|
| 492 |
+ |
|
| 493 |
+ calls.Assert(t, |
|
| 494 |
+ "DmTaskDestroy", |
|
| 495 |
+ ) |
|
| 341 | 496 |
} |
| 342 | 497 |
|
| 343 | 498 |
func TestDriverRemove(t *testing.T) {
|
| 344 |
- t.Skip("FIXME: not a unit test")
|
|
| 345 |
- d := newDriver(t) |
|
| 346 |
- defer cleanup(d) |
|
| 499 |
+ denyAllDevmapper() |
|
| 500 |
+ denyAllSyscall() |
|
| 501 |
+ defer denyAllSyscall() |
|
| 502 |
+ defer denyAllDevmapper() |
|
| 347 | 503 |
|
| 348 |
- if err := d.Create("1", ""); err != nil {
|
|
| 349 |
- t.Fatal(err) |
|
| 350 |
- } |
|
| 504 |
+ calls := make(Set) |
|
| 505 |
+ mockAllDevmapper(calls) |
|
| 351 | 506 |
|
| 352 |
- if err := d.Remove("1"); err != nil {
|
|
| 353 |
- t.Fatal(err) |
|
| 507 |
+ sysMount = func(source, target, fstype string, flags uintptr, data string) (err error) {
|
|
| 508 |
+ calls["sysMount"] = true |
|
| 509 |
+ // FIXME: compare the exact source and target strings (inodes + devname) |
|
| 510 |
+ if expectedSource := "/dev/mapper/docker-"; !strings.HasPrefix(source, expectedSource) {
|
|
| 511 |
+ t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedSource, source)
|
|
| 512 |
+ } |
|
| 513 |
+ if expectedTarget := "/tmp/docker-test-devmapper-"; !strings.HasPrefix(target, expectedTarget) {
|
|
| 514 |
+ t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedTarget, target)
|
|
| 515 |
+ } |
|
| 516 |
+ if expectedFstype := "ext4"; fstype != expectedFstype {
|
|
| 517 |
+ t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedFstype, fstype)
|
|
| 518 |
+ } |
|
| 519 |
+ if expectedFlags := uintptr(3236757504); flags != expectedFlags {
|
|
| 520 |
+ t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedFlags, flags)
|
|
| 521 |
+ } |
|
| 522 |
+ return nil |
|
| 523 |
+ } |
|
| 524 |
+ sysUnmount = func(target string, flags int) (err error) {
|
|
| 525 |
+ calls["sysUnmount"] = true |
|
| 526 |
+ // FIXME: compare the exact source and target strings (inodes + devname) |
|
| 527 |
+ if expectedTarget := "/tmp/docker-test-devmapper-"; !strings.HasPrefix(target, expectedTarget) {
|
|
| 528 |
+ t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedTarget, target)
|
|
| 529 |
+ } |
|
| 530 |
+ if expectedFlags := 0; flags != expectedFlags {
|
|
| 531 |
+ t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedFlags, flags)
|
|
| 532 |
+ } |
|
| 533 |
+ return nil |
|
| 354 | 534 |
} |
| 535 |
+ Mounted = func(mnt string) (bool, error) {
|
|
| 536 |
+ calls["Mounted"] = true |
|
| 537 |
+ return false, nil |
|
| 538 |
+ } |
|
| 539 |
+ |
|
| 540 |
+ func() {
|
|
| 541 |
+ d := newDriver(t) |
|
| 542 |
+ |
|
| 543 |
+ calls.Assert(t, |
|
| 544 |
+ "DmSetDevDir", |
|
| 545 |
+ "DmLogWithErrnoInit", |
|
| 546 |
+ "DmTaskSetName", |
|
| 547 |
+ "DmTaskRun", |
|
| 548 |
+ "DmTaskGetInfo", |
|
| 549 |
+ "DmAttachLoopDevice", |
|
| 550 |
+ "execRun", |
|
| 551 |
+ "DmTaskCreate", |
|
| 552 |
+ "DmGetBlockSize", |
|
| 553 |
+ "DmTaskSetTarget", |
|
| 554 |
+ "DmTaskSetCookie", |
|
| 555 |
+ "DmUdevWait", |
|
| 556 |
+ "DmTaskSetSector", |
|
| 557 |
+ "DmTaskSetMessage", |
|
| 558 |
+ "DmTaskSetAddNode", |
|
| 559 |
+ ) |
|
| 560 |
+ |
|
| 561 |
+ if err := d.Create("1", ""); err != nil {
|
|
| 562 |
+ t.Fatal(err) |
|
| 563 |
+ } |
|
| 564 |
+ |
|
| 565 |
+ calls.Assert(t, |
|
| 566 |
+ "DmTaskCreate", |
|
| 567 |
+ "DmTaskGetInfo", |
|
| 568 |
+ "sysMount", |
|
| 569 |
+ "Mounted", |
|
| 570 |
+ "DmTaskRun", |
|
| 571 |
+ "DmTaskSetTarget", |
|
| 572 |
+ "DmTaskSetSector", |
|
| 573 |
+ "DmTaskSetCookie", |
|
| 574 |
+ "DmUdevWait", |
|
| 575 |
+ "DmTaskSetName", |
|
| 576 |
+ "DmTaskSetMessage", |
|
| 577 |
+ "DmTaskSetAddNode", |
|
| 578 |
+ ) |
|
| 579 |
+ |
|
| 580 |
+ Mounted = func(mnt string) (bool, error) {
|
|
| 581 |
+ calls["Mounted"] = true |
|
| 582 |
+ return true, nil |
|
| 583 |
+ } |
|
| 584 |
+ |
|
| 585 |
+ if err := d.Remove("1"); err != nil {
|
|
| 586 |
+ t.Fatal(err) |
|
| 587 |
+ } |
|
| 588 |
+ |
|
| 589 |
+ calls.Assert(t, |
|
| 590 |
+ "DmTaskRun", |
|
| 591 |
+ "DmTaskSetSector", |
|
| 592 |
+ "DmTaskSetName", |
|
| 593 |
+ "DmTaskSetMessage", |
|
| 594 |
+ "DmTaskCreate", |
|
| 595 |
+ "DmTaskGetInfo", |
|
| 596 |
+ "Mounted", |
|
| 597 |
+ "sysUnmount", |
|
| 598 |
+ ) |
|
| 599 |
+ }() |
|
| 600 |
+ runtime.GC() |
|
| 601 |
+ |
|
| 602 |
+ calls.Assert(t, |
|
| 603 |
+ "DmTaskDestroy", |
|
| 604 |
+ ) |
|
| 355 | 605 |
} |
| 356 | 606 |
|
| 357 | 607 |
func TestCleanup(t *testing.T) {
|
| ... | ... |
@@ -7,7 +7,7 @@ import ( |
| 7 | 7 |
// FIXME: this is copy-pasted from the aufs driver. |
| 8 | 8 |
// It should be moved into the core. |
| 9 | 9 |
|
| 10 |
-func Mounted(mountpoint string) (bool, error) {
|
|
| 10 |
+var Mounted = func(mountpoint string) (bool, error) {
|
|
| 11 | 11 |
mntpoint, err := osStat(mountpoint) |
| 12 | 12 |
if err != nil {
|
| 13 | 13 |
if osIsNotExist(err) {
|