gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/errors/linuxerr/linuxerr_test.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package linuxerr_test 16 17 import ( 18 "errors" 19 "fmt" 20 "io" 21 "io/fs" 22 "syscall" 23 "testing" 24 25 "golang.org/x/sys/unix" 26 gErrors "gvisor.dev/gvisor/pkg/errors" 27 "gvisor.dev/gvisor/pkg/errors/linuxerr" 28 ) 29 30 var globalError error 31 32 func BenchmarkAssignUnix(b *testing.B) { 33 for i := b.N; i > 0; i-- { 34 globalError = unix.EINVAL 35 } 36 } 37 38 func BenchmarkAssignLinuxerr(b *testing.B) { 39 for i := b.N; i > 0; i-- { 40 globalError = linuxerr.EINVAL 41 } 42 } 43 44 func BenchmarkCompareUnix(b *testing.B) { 45 globalError = unix.EAGAIN 46 j := 0 47 for i := b.N; i > 0; i-- { 48 if globalError == unix.EINVAL { 49 j++ 50 } 51 } 52 } 53 54 func BenchmarkCompareLinuxerr(b *testing.B) { 55 globalError = linuxerr.E2BIG 56 j := 0 57 for i := b.N; i > 0; i-- { 58 if globalError == linuxerr.EINVAL { 59 j++ 60 } 61 } 62 } 63 64 func BenchmarkSwitchUnix(b *testing.B) { 65 globalError = unix.EPERM 66 j := 0 67 for i := b.N; i > 0; i-- { 68 switch globalError { 69 case unix.EINVAL: 70 j++ 71 case unix.EINTR: 72 j += 2 73 case unix.EAGAIN: 74 j += 3 75 } 76 } 77 } 78 79 func BenchmarkSwitchLinuxerr(b *testing.B) { 80 globalError = linuxerr.EPERM 81 j := 0 82 for i := b.N; i > 0; i-- { 83 switch globalError { 84 case linuxerr.EINVAL: 85 j++ 86 case linuxerr.EINTR: 87 j += 2 88 case linuxerr.EAGAIN: 89 j += 3 90 } 91 } 92 } 93 94 func BenchmarkReturnUnix(b *testing.B) { 95 var localError error 96 f := func() error { 97 return unix.EINVAL 98 } 99 for i := b.N; i > 0; i-- { 100 localError = f() 101 } 102 if localError != nil { 103 return 104 } 105 } 106 107 func BenchmarkReturnLinuxerr(b *testing.B) { 108 var localError error 109 f := func() error { 110 return linuxerr.EINVAL 111 } 112 for i := b.N; i > 0; i-- { 113 localError = f() 114 } 115 if localError != nil { 116 return 117 } 118 } 119 120 func BenchmarkConvertUnixLinuxerr(b *testing.B) { 121 var localError error 122 for i := b.N; i > 0; i-- { 123 localError = linuxerr.ErrorFromUnix(unix.EINVAL) 124 } 125 if localError != nil { 126 return 127 } 128 } 129 130 func BenchmarkConvertUnixLinuxerrZero(b *testing.B) { 131 var localError error 132 for i := b.N; i > 0; i-- { 133 localError = linuxerr.ErrorFromUnix(unix.Errno(0)) 134 } 135 if localError != nil { 136 return 137 } 138 } 139 140 type translationTestTable struct { 141 errIn error 142 expectedBool bool 143 expectedTranslation *gErrors.Error 144 } 145 146 func TestErrorTranslation(t *testing.T) { 147 testTable := []translationTestTable{ 148 { 149 errIn: linuxerr.ENOENT, 150 }, 151 { 152 errIn: unix.ENOENT, 153 }, 154 { 155 errIn: linuxerr.ErrInterrupted, 156 expectedBool: true, 157 expectedTranslation: linuxerr.EINTR, 158 }, 159 { 160 errIn: linuxerr.ERESTART_RESTARTBLOCK, 161 }, 162 { 163 errIn: errors.New("some new error"), 164 }, 165 } 166 for _, tt := range testTable { 167 t.Run(fmt.Sprintf("err: %v %T", tt.errIn, tt.errIn), func(t *testing.T) { 168 err, ok := linuxerr.TranslateError(tt.errIn) 169 if (!tt.expectedBool && err != nil) || (tt.expectedBool != ok) { 170 t.Fatalf("%v => %v %v expected %v err: nil", tt.errIn, err, ok, tt.expectedBool) 171 } else if err != tt.expectedTranslation { 172 t.Fatalf("%v => %v expected %v", tt.errIn, err, tt.expectedTranslation) 173 } 174 }) 175 } 176 } 177 178 func TestSyscallErrnoToErrors(t *testing.T) { 179 for _, tc := range []struct { 180 errno syscall.Errno 181 err error 182 }{ 183 {errno: syscall.EACCES, err: linuxerr.EACCES}, 184 {errno: syscall.EAGAIN, err: linuxerr.EAGAIN}, 185 {errno: syscall.EBADF, err: linuxerr.EBADF}, 186 {errno: syscall.EBUSY, err: linuxerr.EBUSY}, 187 {errno: syscall.EDOM, err: linuxerr.EDOM}, 188 {errno: syscall.EEXIST, err: linuxerr.EEXIST}, 189 {errno: syscall.EFAULT, err: linuxerr.EFAULT}, 190 {errno: syscall.EFBIG, err: linuxerr.EFBIG}, 191 {errno: syscall.EINTR, err: linuxerr.EINTR}, 192 {errno: syscall.EINVAL, err: linuxerr.EINVAL}, 193 {errno: syscall.EIO, err: linuxerr.EIO}, 194 {errno: syscall.ENOTDIR, err: linuxerr.ENOTDIR}, 195 {errno: syscall.ENOTTY, err: linuxerr.ENOTTY}, 196 {errno: syscall.EPERM, err: linuxerr.EPERM}, 197 {errno: syscall.EPIPE, err: linuxerr.EPIPE}, 198 {errno: syscall.ESPIPE, err: linuxerr.ESPIPE}, 199 {errno: syscall.EWOULDBLOCK, err: linuxerr.EAGAIN}, 200 } { 201 t.Run(tc.errno.Error(), func(t *testing.T) { 202 e := linuxerr.ErrorFromUnix(unix.Errno(tc.errno)) 203 if e != tc.err { 204 t.Fatalf("Mismatch errors: want: %+v %T got: %+v %T", tc.err, tc.err, e, e) 205 } 206 }) 207 } 208 } 209 210 // TestEqualsMethod tests that the Equals method correctly compares syerror, 211 // unix.Errno and linuxerr. 212 // TODO (b/34162363): Remove this. 213 func TestEqualsMethod(t *testing.T) { 214 noError := linuxerr.ErrorFromUnix(unix.Errno(0)) 215 for _, tc := range []struct { 216 name string 217 linuxErr []*gErrors.Error 218 err []error 219 equal bool 220 }{ 221 { 222 name: "compare nil", 223 linuxErr: []*gErrors.Error{nil}, 224 err: []error{nil, noError, unix.Errno(0)}, 225 equal: true, 226 }, 227 { 228 name: "linuxerr nil error not", 229 linuxErr: []*gErrors.Error{nil}, 230 err: []error{unix.Errno(1), linuxerr.EPERM, linuxerr.EACCES}, 231 equal: false, 232 }, 233 { 234 name: "linuxerr not nil error nil", 235 linuxErr: []*gErrors.Error{linuxerr.ENOENT}, 236 err: []error{nil, unix.Errno(0)}, 237 equal: false, 238 }, 239 { 240 name: "equal errors", 241 linuxErr: []*gErrors.Error{linuxerr.ESRCH}, 242 err: []error{linuxerr.ESRCH, linuxerr.ESRCH, unix.Errno(linuxerr.ESRCH.Errno())}, 243 equal: true, 244 }, 245 { 246 name: "unequal errors", 247 linuxErr: []*gErrors.Error{linuxerr.ENOENT}, 248 err: []error{linuxerr.ESRCH, linuxerr.ESRCH, unix.Errno(linuxerr.ESRCH.Errno())}, 249 equal: false, 250 }, 251 { 252 name: "other error", 253 linuxErr: []*gErrors.Error{nil, linuxerr.E2BIG, linuxerr.EINVAL}, 254 err: []error{fs.ErrInvalid, io.EOF}, 255 equal: false, 256 }, 257 } { 258 t.Run(tc.name, func(t *testing.T) { 259 for _, le := range tc.linuxErr { 260 for _, e := range tc.err { 261 if linuxerr.Equals(le, e) != tc.equal { 262 t.Fatalf("Expected %t from Equals method for linuxerr: %s %T and error: %s %T", tc.equal, le, le, e, e) 263 } 264 } 265 } 266 }) 267 } 268 }