Browse code

Forbid syscalls in tests, add 2 new unit tests

Guillaume J. Charmes authored on 2013/11/22 09:32:16
Showing 3 changed files
... ...
@@ -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) {