1
2
3
4 package scsi
5
6 import (
7 "context"
8 "errors"
9 "fmt"
10 "os"
11 "testing"
12
13 "github.com/Microsoft/hcsshim/internal/protocol/guestresource"
14 "golang.org/x/sys/unix"
15 )
16
17 func clearTestDependencies() {
18 osMkdirAll = nil
19 osRemoveAll = nil
20 unixMount = nil
21 controllerLunToName = nil
22 createVerityTarget = nil
23 encryptDevice = nil
24 cleanupCryptDevice = nil
25 storageUnmountPath = nil
26 }
27
28 func Test_Mount_Mkdir_Fails_Error(t *testing.T) {
29 clearTestDependencies()
30
31 expectedErr := errors.New("mkdir : no such file or directory")
32 osMkdirAll = func(path string, perm os.FileMode) error {
33 return expectedErr
34 }
35
36 controllerLunToName = func(ctx context.Context, controller, lun uint8) (string, error) {
37 return "", nil
38 }
39
40 if err := Mount(
41 context.Background(),
42 0,
43 0,
44 "",
45 false,
46 false,
47 nil,
48 nil,
49 ); !errors.Is(err, expectedErr) {
50 t.Fatalf("expected err: %v, got: %v", expectedErr, err)
51 }
52 }
53
54 func Test_Mount_Mkdir_ExpectedPath(t *testing.T) {
55 clearTestDependencies()
56
57
58
59
60 target := "/fake/path"
61 osMkdirAll = func(path string, perm os.FileMode) error {
62 if path != target {
63 t.Errorf("expected path: %v, got: %v", target, path)
64 return errors.New("unexpected path")
65 }
66 return nil
67 }
68 controllerLunToName = func(ctx context.Context, controller, lun uint8) (string, error) {
69 return "", nil
70 }
71 unixMount = func(source string, target string, fstype string, flags uintptr, data string) error {
72
73 return nil
74 }
75
76 if err := Mount(
77 context.Background(),
78 0,
79 0,
80 target,
81 false,
82 false,
83 nil,
84 nil,
85 ); err != nil {
86 t.Fatalf("expected nil error got: %v", err)
87 }
88 }
89
90 func Test_Mount_Mkdir_ExpectedPerm(t *testing.T) {
91 clearTestDependencies()
92
93
94
95
96 target := "/fake/path"
97 osMkdirAll = func(path string, perm os.FileMode) error {
98 if perm != os.FileMode(0700) {
99 t.Errorf("expected perm: %v, got: %v", os.FileMode(0700), perm)
100 return errors.New("unexpected perm")
101 }
102 return nil
103 }
104 controllerLunToName = func(ctx context.Context, controller, lun uint8) (string, error) {
105 return "", nil
106 }
107 unixMount = func(source string, target string, fstype string, flags uintptr, data string) error {
108
109 return nil
110 }
111
112 if err := Mount(
113 context.Background(),
114 0,
115 0,
116 target,
117 false,
118 false,
119 nil,
120 nil,
121 ); err != nil {
122 t.Fatalf("expected nil error got: %v", err)
123 }
124 }
125
126 func Test_Mount_ControllerLunToName_Valid_Controller(t *testing.T) {
127 clearTestDependencies()
128
129
130
131
132 osMkdirAll = func(path string, perm os.FileMode) error {
133 return nil
134 }
135 expectedController := uint8(2)
136 controllerLunToName = func(ctx context.Context, controller, lun uint8) (string, error) {
137 if expectedController != controller {
138 t.Errorf("expected controller: %v, got: %v", expectedController, controller)
139 return "", errors.New("unexpected controller")
140 }
141 return "", nil
142 }
143 unixMount = func(source string, target string, fstype string, flags uintptr, data string) error {
144
145 return nil
146 }
147
148 if err := Mount(
149 context.Background(),
150 expectedController,
151 0,
152 "/fake/path",
153 false,
154 false,
155 nil,
156 nil,
157 ); err != nil {
158 t.Fatalf("expected nil error got: %v", err)
159 }
160 }
161
162 func Test_Mount_ControllerLunToName_Valid_Lun(t *testing.T) {
163 clearTestDependencies()
164
165
166
167
168 osMkdirAll = func(path string, perm os.FileMode) error {
169 return nil
170 }
171 expectedLun := uint8(2)
172 controllerLunToName = func(ctx context.Context, controller, lun uint8) (string, error) {
173 if expectedLun != lun {
174 t.Errorf("expected lun: %v, got: %v", expectedLun, lun)
175 return "", errors.New("unexpected lun")
176 }
177 return "", nil
178 }
179 unixMount = func(source string, target string, fstype string, flags uintptr, data string) error {
180
181 return nil
182 }
183
184 if err := Mount(
185 context.Background(),
186 0,
187 expectedLun,
188 "/fake/path",
189 false,
190 false,
191 nil,
192 nil,
193 ); err != nil {
194 t.Fatalf("expected nil error got: %v", err)
195 }
196 }
197
198 func Test_Mount_Calls_RemoveAll_OnMountFailure(t *testing.T) {
199 clearTestDependencies()
200
201 osMkdirAll = func(path string, perm os.FileMode) error {
202 return nil
203 }
204 controllerLunToName = func(ctx context.Context, controller, lun uint8) (string, error) {
205 return "", nil
206 }
207 target := "/fake/path"
208 removeAllCalled := false
209 osRemoveAll = func(path string) error {
210 removeAllCalled = true
211 if path != target {
212 t.Errorf("expected path: %v, got: %v", target, path)
213 return errors.New("unexpected path")
214 }
215 return nil
216 }
217 expectedErr := errors.New("unexpected mount failure")
218 unixMount = func(source string, target string, fstype string, flags uintptr, data string) error {
219
220 return expectedErr
221 }
222
223 if err := Mount(
224 context.Background(),
225 0,
226 0,
227 target,
228 false,
229 false,
230 nil,
231 nil,
232 ); !errors.Is(err, expectedErr) {
233 t.Fatalf("expected err: %v, got: %v", expectedErr, err)
234 }
235 if !removeAllCalled {
236 t.Fatal("expected os.RemoveAll to be called on mount failure")
237 }
238 }
239
240 func Test_Mount_Valid_Source(t *testing.T) {
241 clearTestDependencies()
242
243
244
245
246 osMkdirAll = func(path string, perm os.FileMode) error {
247 return nil
248 }
249 expectedSource := "/dev/sdz"
250 controllerLunToName = func(ctx context.Context, controller, lun uint8) (string, error) {
251 return expectedSource, nil
252 }
253 unixMount = func(source string, target string, fstype string, flags uintptr, data string) error {
254 if expectedSource != source {
255 t.Errorf("expected source: %s, got: %s", expectedSource, source)
256 return errors.New("unexpected source")
257 }
258 return nil
259 }
260 err := Mount(context.Background(), 0, 0, "/fake/path", false, false, nil, nil)
261 if err != nil {
262 t.Fatalf("expected nil err, got: %v", err)
263 }
264 }
265
266 func Test_Mount_Valid_Target(t *testing.T) {
267 clearTestDependencies()
268
269
270
271
272 osMkdirAll = func(path string, perm os.FileMode) error {
273 return nil
274 }
275 controllerLunToName = func(ctx context.Context, controller, lun uint8) (string, error) {
276 return "", nil
277 }
278 expectedTarget := "/fake/path"
279 unixMount = func(source string, target string, fstype string, flags uintptr, data string) error {
280 if expectedTarget != target {
281 t.Errorf("expected target: %s, got: %s", expectedTarget, target)
282 return errors.New("unexpected target")
283 }
284 return nil
285 }
286
287 if err := Mount(
288 context.Background(),
289 0,
290 0,
291 expectedTarget,
292 false,
293 false,
294 nil,
295 nil,
296 ); err != nil {
297 t.Fatalf("expected nil err, got: %v", err)
298 }
299 }
300
301 func Test_Mount_Valid_FSType(t *testing.T) {
302 clearTestDependencies()
303
304
305
306
307 osMkdirAll = func(path string, perm os.FileMode) error {
308 return nil
309 }
310 controllerLunToName = func(ctx context.Context, controller, lun uint8) (string, error) {
311 return "", nil
312 }
313 unixMount = func(source string, target string, fstype string, flags uintptr, data string) error {
314 expectedFSType := "ext4"
315 if expectedFSType != fstype {
316 t.Errorf("expected fstype: %s, got: %s", expectedFSType, fstype)
317 return errors.New("unexpected fstype")
318 }
319 return nil
320 }
321
322 if err := Mount(
323 context.Background(),
324 0,
325 0,
326 "/fake/path",
327 false,
328 false,
329 nil,
330 nil,
331 ); err != nil {
332 t.Fatalf("expected nil err, got: %v", err)
333 }
334 }
335
336 func Test_Mount_Valid_Flags(t *testing.T) {
337 clearTestDependencies()
338
339
340
341
342 osMkdirAll = func(path string, perm os.FileMode) error {
343 return nil
344 }
345 controllerLunToName = func(ctx context.Context, controller, lun uint8) (string, error) {
346 return "", nil
347 }
348 unixMount = func(source string, target string, fstype string, flags uintptr, data string) error {
349 expectedFlags := uintptr(0)
350 if expectedFlags != flags {
351 t.Errorf("expected flags: %v, got: %v", expectedFlags, flags)
352 return errors.New("unexpected flags")
353 }
354 return nil
355 }
356
357 if err := Mount(
358 context.Background(),
359 0,
360 0,
361 "/fake/path",
362 false,
363 false,
364 nil,
365 nil,
366 ); err != nil {
367 t.Fatalf("expected nil err, got: %v", err)
368 }
369 }
370
371 func Test_Mount_Readonly_Valid_Flags(t *testing.T) {
372 clearTestDependencies()
373
374
375
376
377 osMkdirAll = func(path string, perm os.FileMode) error {
378 return nil
379 }
380 controllerLunToName = func(ctx context.Context, controller, lun uint8) (string, error) {
381 return "", nil
382 }
383 unixMount = func(source string, target string, fstype string, flags uintptr, data string) error {
384 expectedFlags := uintptr(unix.MS_RDONLY)
385 if expectedFlags != flags {
386 t.Errorf("expected flags: %v, got: %v", expectedFlags, flags)
387 return errors.New("unexpected flags")
388 }
389 return nil
390 }
391
392 if err := Mount(
393 context.Background(),
394 0,
395 0,
396 "/fake/path",
397 true,
398 false,
399 nil,
400 nil,
401 ); err != nil {
402 t.Fatalf("expected nil err, got: %v", err)
403 }
404 }
405
406 func Test_Mount_Valid_Data(t *testing.T) {
407 clearTestDependencies()
408
409
410
411
412 osMkdirAll = func(path string, perm os.FileMode) error {
413 return nil
414 }
415 controllerLunToName = func(ctx context.Context, controller, lun uint8) (string, error) {
416 return "", nil
417 }
418 unixMount = func(source string, target string, fstype string, flags uintptr, data string) error {
419 if data != "" {
420 t.Errorf("expected empty data, got: %s", data)
421 return errors.New("unexpected data")
422 }
423 return nil
424 }
425
426 if err := Mount(
427 context.Background(),
428 0,
429 0,
430 "/fake/path",
431 false,
432 false,
433 nil,
434 nil,
435 ); err != nil {
436 t.Fatalf("expected nil err, got: %v", err)
437 }
438 }
439
440 func Test_Mount_Readonly_Valid_Data(t *testing.T) {
441 clearTestDependencies()
442
443
444
445
446 osMkdirAll = func(path string, perm os.FileMode) error {
447 return nil
448 }
449 controllerLunToName = func(ctx context.Context, controller, lun uint8) (string, error) {
450 return "", nil
451 }
452 unixMount = func(source string, target string, fstype string, flags uintptr, data string) error {
453 expectedData := "noload"
454 if expectedData != data {
455 t.Errorf("expected data: %s, got: %s", expectedData, data)
456 return errors.New("unexpected data")
457 }
458 return nil
459 }
460
461 if err := Mount(
462 context.Background(),
463 0,
464 0,
465 "/fake/path",
466 true,
467 false,
468 nil,
469 nil,
470 ); err != nil {
471 t.Fatalf("expected nil err, got: %v", err)
472 }
473 }
474
475
476
477 func Test_CreateVerityTarget_And_Mount_Called_With_Correct_Parameters(t *testing.T) {
478 clearTestDependencies()
479
480 expectedVerityName := fmt.Sprintf(verityDeviceFmt, 0, 0, "hash")
481 expectedSource := "/dev/sdb"
482 expectedMapperPath := fmt.Sprintf("/dev/mapper/%s", expectedVerityName)
483 expectedTarget := "/foo"
484 createVerityTargetCalled := false
485
486 controllerLunToName = func(_ context.Context, _, _ uint8) (string, error) {
487 return expectedSource, nil
488 }
489
490 osMkdirAll = func(_ string, _ os.FileMode) error {
491 return nil
492 }
493
494 vInfo := &guestresource.DeviceVerityInfo{
495 RootDigest: "hash",
496 }
497 createVerityTarget = func(_ context.Context, source, name string, verityInfo *guestresource.DeviceVerityInfo) (string, error) {
498 createVerityTargetCalled = true
499 if source != expectedSource {
500 t.Errorf("expected source %s, got %s", expectedSource, source)
501 }
502 if name != expectedVerityName {
503 t.Errorf("expected verity target name %s, got %s", expectedVerityName, name)
504 }
505 return expectedMapperPath, nil
506 }
507
508 unixMount = func(source string, target string, fstype string, flags uintptr, data string) error {
509 if source != expectedMapperPath {
510 t.Errorf("expected unixMount source %s, got %s", expectedMapperPath, source)
511 }
512 if target != expectedTarget {
513 t.Errorf("expected unixMount target %s, got %s", expectedTarget, target)
514 }
515 return nil
516 }
517
518 if err := Mount(
519 context.Background(),
520 0,
521 0,
522 expectedTarget,
523 true,
524 false,
525 nil,
526 vInfo,
527 ); err != nil {
528 t.Fatalf("unexpected error during Mount: %s", err)
529 }
530 if !createVerityTargetCalled {
531 t.Fatalf("expected createVerityTargetCalled to be called")
532 }
533 }
534
535 func Test_osMkdirAllFails_And_RemoveDevice_Called(t *testing.T) {
536 clearTestDependencies()
537
538 expectedError := errors.New("osMkdirAll error")
539 expectedVerityName := fmt.Sprintf(verityDeviceFmt, 0, 0, "hash")
540 removeDeviceCalled := false
541
542 controllerLunToName = func(_ context.Context, _, _ uint8) (string, error) {
543 return "/dev/sdb", nil
544 }
545
546 osMkdirAll = func(_ string, _ os.FileMode) error {
547 return expectedError
548 }
549
550 verityInfo := &guestresource.DeviceVerityInfo{
551 RootDigest: "hash",
552 }
553
554 createVerityTarget = func(_ context.Context, _, _ string, _ *guestresource.DeviceVerityInfo) (string, error) {
555 return fmt.Sprintf("/dev/mapper/%s", expectedVerityName), nil
556 }
557
558 removeDevice = func(name string) error {
559 removeDeviceCalled = true
560 if name != expectedVerityName {
561 t.Errorf("expected RemoveDevice name %s, got %s", expectedVerityName, name)
562 }
563 return nil
564 }
565
566 if err := Mount(
567 context.Background(),
568 0,
569 0,
570 "/foo",
571 true,
572 false,
573 nil,
574 verityInfo,
575 ); err != expectedError {
576 t.Fatalf("expected Mount error %s, got %s", expectedError, err)
577 }
578 if !removeDeviceCalled {
579 t.Fatal("expected removeDevice to be called")
580 }
581 }
582
583 func Test_Mount_EncryptDevice_Called(t *testing.T) {
584 clearTestDependencies()
585
586 osMkdirAll = func(string, os.FileMode) error {
587 return nil
588 }
589 controllerLunToName = func(context.Context, uint8, uint8) (string, error) {
590 return "", nil
591 }
592 unixMount = func(string, string, string, uintptr, string) error {
593 return nil
594 }
595 encryptDeviceCalled := false
596 encryptDevice = func(_ context.Context, source string, devName string) (string, error) {
597 expectedCryptTarget := fmt.Sprintf(cryptDeviceFmt, 0, 0)
598 if devName != expectedCryptTarget {
599 t.Fatalf("expected crypt device %q got %q", expectedCryptTarget, devName)
600 }
601 encryptDeviceCalled = true
602 return "", nil
603 }
604 if err := Mount(
605 context.Background(),
606 0,
607 0,
608 "/fake/path",
609 false,
610 true,
611 nil,
612 nil,
613 ); err != nil {
614 t.Fatalf("expected nil error, got: %s", err)
615 }
616 if !encryptDeviceCalled {
617 t.Fatal("expected encryptDevice to be called")
618 }
619 }
620
621 func Test_Mount_RemoveAllCalled_When_EncryptDevice_Fails(t *testing.T) {
622 clearTestDependencies()
623
624 osMkdirAll = func(string, os.FileMode) error {
625 return nil
626 }
627 controllerLunToName = func(context.Context, uint8, uint8) (string, error) {
628 return "", nil
629 }
630 unixMount = func(string, string, string, uintptr, string) error {
631 return nil
632 }
633 encryptDeviceError := errors.New("encrypt device error")
634 encryptDevice = func(context.Context, string, string) (string, error) {
635 return "", encryptDeviceError
636 }
637 removeAllCalled := false
638 osRemoveAll = func(string) error {
639 removeAllCalled = true
640 return nil
641 }
642
643 err := Mount(
644 context.Background(),
645 0,
646 0,
647 "/fake/path",
648 false,
649 true,
650 nil,
651 nil,
652 )
653 if err == nil {
654 t.Fatalf("expected to fail")
655 }
656 if errors.Unwrap(err) != encryptDeviceError {
657 t.Fatalf("expected error %q, got %q", encryptDeviceError, err)
658 }
659 if !removeAllCalled {
660 t.Fatal("osRemoveAll was not called")
661 }
662 }
663
664 func Test_Unmount_CleanupCryptDevice_Called(t *testing.T) {
665 clearTestDependencies()
666
667 storageUnmountPath = func(context.Context, string, bool) error {
668 return nil
669 }
670 cleanupCryptDeviceCalled := false
671 cleanupCryptDevice = func(devName string) error {
672 expectedDevName := fmt.Sprintf(cryptDeviceFmt, 0, 0)
673 if devName != expectedDevName {
674 t.Fatalf("expected crypt target %q, got %q", expectedDevName, devName)
675 }
676 cleanupCryptDeviceCalled = true
677 return nil
678 }
679
680 if err := Unmount(context.Background(), 0, 0, "/fake/path", true, nil); err != nil {
681 t.Fatalf("unexpected error: %s", err)
682 }
683 if !cleanupCryptDeviceCalled {
684 t.Fatal("cleanupCryptDevice not called")
685 }
686 }
687
View as plain text