aboutsummaryrefslogtreecommitdiffhomepage
path: root/container/errors_test.go
blob: 3d3274301f670a27333aac6b52b39801cbc977a8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package container

import (
	"errors"
	"os"
	"reflect"
	"syscall"
	"testing"
)

func TestMountError(t *testing.T) {
	testCases := []struct {
		name  string
		err   error
		errno syscall.Errno
		want  string
	}{
		{"bind", &MountError{
			Source: "/host/nix/store",
			Target: "/sysroot/nix/store",
			Fstype: FstypeNULL,
			Flags:  syscall.MS_SILENT | syscall.MS_BIND | syscall.MS_REC,
			Data:   zeroString,
			Errno:  syscall.ENOSYS,
		}, syscall.ENOSYS,
			"bind /host/nix/store on /sysroot/nix/store: function not implemented"},

		{"remount", &MountError{
			Source: SourceNone,
			Target: "/sysroot/nix/store",
			Fstype: FstypeNULL,
			Flags:  syscall.MS_SILENT | syscall.MS_BIND | syscall.MS_REMOUNT,
			Data:   zeroString,
			Errno:  syscall.EPERM,
		}, syscall.EPERM,
			"remount /sysroot/nix/store: operation not permitted"},

		{"overlay", &MountError{
			Source: SourceOverlay,
			Target: sysrootPath,
			Fstype: FstypeOverlay,
			Data:   `lowerdir=/host/var/lib/planterette/base/debian\:f92c9052`,
			Errno:  syscall.EINVAL,
		}, syscall.EINVAL,
			"mount overlay on /sysroot: invalid argument"},

		{"fallback", &MountError{
			Source: SourceNone,
			Target: sysrootPath,
			Fstype: FstypeNULL,
			Errno:  syscall.ENOTRECOVERABLE,
		}, syscall.ENOTRECOVERABLE,
			"mount /sysroot: state not recoverable"},
	}
	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			t.Run("is", func(t *testing.T) {
				if !errors.Is(tc.err, tc.errno) {
					t.Errorf("Is: %#v is not %v", tc.err, tc.errno)
				}
			})
			t.Run("error", func(t *testing.T) {
				if got := tc.err.Error(); got != tc.want {
					t.Errorf("Error: %q, want %q", got, tc.want)
				}
			})
		})
	}

	t.Run("zero", func(t *testing.T) {
		if errors.Is(new(MountError), syscall.Errno(0)) {
			t.Errorf("Is: zero MountError unexpected true")
		}
	})
}

func TestErrnoFallback(t *testing.T) {
	testCases := []struct {
		name      string
		err       error
		wantErrno syscall.Errno
		wantPath  *os.PathError
	}{
		{"mount", &MountError{
			Errno: syscall.ENOTRECOVERABLE,
		}, syscall.ENOTRECOVERABLE, nil},

		{"path errno", &os.PathError{
			Err: syscall.ETIMEDOUT,
		}, syscall.ETIMEDOUT, nil},

		{"fallback", errUnique, 0, &os.PathError{
			Op:   "fallback",
			Path: "/proc/nonexistent",
			Err:  errUnique,
		}},
	}
	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			errno, err := errnoFallback(tc.name, Nonexistent, tc.err)
			if errno != tc.wantErrno {
				t.Errorf("errnoFallback: errno = %v, want %v", errno, tc.wantErrno)
			}
			if !reflect.DeepEqual(err, tc.wantPath) {
				t.Errorf("errnoFallback: pathError = %#v, want %#v", err, tc.wantPath)
			}
		})
	}
}