github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/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 syserror_test 16 17 import ( 18 "errors" 19 "io" 20 "io/fs" 21 "syscall" 22 "testing" 23 24 "golang.org/x/sys/unix" 25 "github.com/SagerNet/gvisor/pkg/abi/linux/errno" 26 gErrors "github.com/SagerNet/gvisor/pkg/errors" 27 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 28 "github.com/SagerNet/gvisor/pkg/syserror" 29 ) 30 31 var globalError error 32 33 func BenchmarkAssignUnix(b *testing.B) { 34 for i := b.N; i > 0; i-- { 35 globalError = unix.EINVAL 36 } 37 } 38 39 func BenchmarkAssignLinuxerr(b *testing.B) { 40 for i := b.N; i > 0; i-- { 41 globalError = linuxerr.EINVAL 42 } 43 } 44 45 func BenchmarkAssignSyserror(b *testing.B) { 46 for i := b.N; i > 0; i-- { 47 globalError = linuxerr.ENOMSG 48 } 49 } 50 51 func BenchmarkCompareUnix(b *testing.B) { 52 globalError = unix.EAGAIN 53 j := 0 54 for i := b.N; i > 0; i-- { 55 if globalError == unix.EINVAL { 56 j++ 57 } 58 } 59 } 60 61 func BenchmarkCompareLinuxerr(b *testing.B) { 62 globalError = linuxerr.E2BIG 63 j := 0 64 for i := b.N; i > 0; i-- { 65 if globalError == linuxerr.EINVAL { 66 j++ 67 } 68 } 69 } 70 71 func BenchmarkCompareSyserror(b *testing.B) { 72 globalError = linuxerr.EAGAIN 73 j := 0 74 for i := b.N; i > 0; i-- { 75 if globalError == linuxerr.EACCES { 76 j++ 77 } 78 } 79 } 80 81 func BenchmarkSwitchUnix(b *testing.B) { 82 globalError = unix.EPERM 83 j := 0 84 for i := b.N; i > 0; i-- { 85 switch globalError { 86 case unix.EINVAL: 87 j++ 88 case unix.EINTR: 89 j += 2 90 case unix.EAGAIN: 91 j += 3 92 } 93 } 94 } 95 96 func BenchmarkSwitchLinuxerr(b *testing.B) { 97 globalError = linuxerr.EPERM 98 j := 0 99 for i := b.N; i > 0; i-- { 100 switch globalError { 101 case linuxerr.EINVAL: 102 j++ 103 case linuxerr.EINTR: 104 j += 2 105 case linuxerr.EAGAIN: 106 j += 3 107 } 108 } 109 } 110 111 func BenchmarkSwitchSyserror(b *testing.B) { 112 globalError = linuxerr.EPERM 113 j := 0 114 for i := b.N; i > 0; i-- { 115 switch globalError { 116 case linuxerr.EACCES: 117 j++ 118 case syserror.EINTR: 119 j += 2 120 case linuxerr.EAGAIN: 121 j += 3 122 } 123 } 124 } 125 126 func BenchmarkReturnUnix(b *testing.B) { 127 var localError error 128 f := func() error { 129 return unix.EINVAL 130 } 131 for i := b.N; i > 0; i-- { 132 localError = f() 133 } 134 if localError != nil { 135 return 136 } 137 } 138 139 func BenchmarkReturnLinuxerr(b *testing.B) { 140 var localError error 141 f := func() error { 142 return linuxerr.EINVAL 143 } 144 for i := b.N; i > 0; i-- { 145 localError = f() 146 } 147 if localError != nil { 148 return 149 } 150 } 151 152 func BenchmarkConvertUnixLinuxerr(b *testing.B) { 153 var localError error 154 for i := b.N; i > 0; i-- { 155 localError = linuxerr.ErrorFromErrno(errno.Errno(unix.EINVAL)) 156 } 157 if localError != nil { 158 return 159 } 160 } 161 162 func BenchmarkConvertUnixLinuxerrZero(b *testing.B) { 163 var localError error 164 for i := b.N; i > 0; i-- { 165 localError = linuxerr.ErrorFromErrno(errno.Errno(0)) 166 } 167 if localError != nil { 168 return 169 } 170 } 171 172 type translationTestTable struct { 173 fn string 174 errIn error 175 syscallErrorIn unix.Errno 176 expectedBool bool 177 expectedTranslation unix.Errno 178 } 179 180 func TestErrorTranslation(t *testing.T) { 181 myError := errors.New("My test error") 182 myError2 := errors.New("Another test error") 183 testTable := []translationTestTable{ 184 {"TranslateError", myError, 0, false, 0}, 185 {"TranslateError", myError2, 0, false, 0}, 186 {"AddErrorTranslation", myError, unix.EAGAIN, true, 0}, 187 {"AddErrorTranslation", myError, unix.EAGAIN, false, 0}, 188 {"AddErrorTranslation", myError, unix.EPERM, false, 0}, 189 {"TranslateError", myError, 0, true, unix.EAGAIN}, 190 {"TranslateError", myError2, 0, false, 0}, 191 {"AddErrorTranslation", myError2, unix.EPERM, true, 0}, 192 {"AddErrorTranslation", myError2, unix.EPERM, false, 0}, 193 {"AddErrorTranslation", myError2, unix.EAGAIN, false, 0}, 194 {"TranslateError", myError, 0, true, unix.EAGAIN}, 195 {"TranslateError", myError2, 0, true, unix.EPERM}, 196 } 197 for _, tt := range testTable { 198 switch tt.fn { 199 case "TranslateError": 200 err, ok := syserror.TranslateError(tt.errIn) 201 if ok != tt.expectedBool { 202 t.Fatalf("%v(%v) => %v expected %v", tt.fn, tt.errIn, ok, tt.expectedBool) 203 } else if err != tt.expectedTranslation { 204 t.Fatalf("%v(%v) (error) => %v expected %v", tt.fn, tt.errIn, err, tt.expectedTranslation) 205 } 206 case "AddErrorTranslation": 207 ok := syserror.AddErrorTranslation(tt.errIn, tt.syscallErrorIn) 208 if ok != tt.expectedBool { 209 t.Fatalf("%v(%v) => %v expected %v", tt.fn, tt.errIn, ok, tt.expectedBool) 210 } 211 default: 212 t.Fatalf("Unknown function %v", tt.fn) 213 } 214 } 215 } 216 217 func TestSyscallErrnoToErrors(t *testing.T) { 218 for _, tc := range []struct { 219 errno syscall.Errno 220 err *gErrors.Error 221 }{ 222 {errno: syscall.EACCES, err: linuxerr.EACCES}, 223 {errno: syscall.EAGAIN, err: linuxerr.EAGAIN}, 224 {errno: syscall.EBADF, err: linuxerr.EBADF}, 225 {errno: syscall.EBUSY, err: linuxerr.EBUSY}, 226 {errno: syscall.EDOM, err: linuxerr.EDOM}, 227 {errno: syscall.EEXIST, err: linuxerr.EEXIST}, 228 {errno: syscall.EFAULT, err: linuxerr.EFAULT}, 229 {errno: syscall.EFBIG, err: linuxerr.EFBIG}, 230 {errno: syscall.EINTR, err: linuxerr.EINTR}, 231 {errno: syscall.EINVAL, err: linuxerr.EINVAL}, 232 {errno: syscall.EIO, err: linuxerr.EIO}, 233 {errno: syscall.ENOTDIR, err: linuxerr.ENOTDIR}, 234 {errno: syscall.ENOTTY, err: linuxerr.ENOTTY}, 235 {errno: syscall.EPERM, err: linuxerr.EPERM}, 236 {errno: syscall.EPIPE, err: linuxerr.EPIPE}, 237 {errno: syscall.ESPIPE, err: linuxerr.ESPIPE}, 238 {errno: syscall.EWOULDBLOCK, err: linuxerr.EAGAIN}, 239 } { 240 t.Run(tc.errno.Error(), func(t *testing.T) { 241 e := linuxerr.ErrorFromErrno(errno.Errno(tc.errno)) 242 if e != tc.err { 243 t.Fatalf("Mismatch errors: want: %+v (%d) got: %+v %d", tc.err, tc.err.Errno(), e, e.Errno()) 244 } 245 }) 246 } 247 } 248 249 // TestEqualsMethod tests that the Equals method correctly compares syerror, 250 // unix.Errno and linuxerr. 251 // TODO (b/34162363): Remove this. 252 func TestEqualsMethod(t *testing.T) { 253 for _, tc := range []struct { 254 name string 255 linuxErr []*gErrors.Error 256 err []error 257 equal bool 258 }{ 259 { 260 name: "compare nil", 261 linuxErr: []*gErrors.Error{nil, linuxerr.NOERROR}, 262 err: []error{nil, linuxerr.NOERROR, unix.Errno(0)}, 263 equal: true, 264 }, 265 { 266 name: "linuxerr nil error not", 267 linuxErr: []*gErrors.Error{nil, linuxerr.NOERROR}, 268 err: []error{unix.Errno(1), linuxerr.EPERM, linuxerr.EACCES}, 269 equal: false, 270 }, 271 { 272 name: "linuxerr not nil error nil", 273 linuxErr: []*gErrors.Error{linuxerr.ENOENT}, 274 err: []error{nil, unix.Errno(0), linuxerr.NOERROR}, 275 equal: false, 276 }, 277 { 278 name: "equal errors", 279 linuxErr: []*gErrors.Error{linuxerr.ESRCH}, 280 err: []error{linuxerr.ESRCH, syserror.ESRCH, unix.Errno(linuxerr.ESRCH.Errno())}, 281 equal: true, 282 }, 283 { 284 name: "unequal errors", 285 linuxErr: []*gErrors.Error{linuxerr.ENOENT}, 286 err: []error{linuxerr.ESRCH, syserror.ESRCH, unix.Errno(linuxerr.ESRCH.Errno())}, 287 equal: false, 288 }, 289 { 290 name: "other error", 291 linuxErr: []*gErrors.Error{nil, linuxerr.NOERROR, linuxerr.E2BIG, linuxerr.EINVAL}, 292 err: []error{fs.ErrInvalid, io.EOF}, 293 equal: false, 294 }, 295 } { 296 t.Run(tc.name, func(t *testing.T) { 297 for _, le := range tc.linuxErr { 298 for _, e := range tc.err { 299 if linuxerr.Equals(le, e) != tc.equal { 300 t.Fatalf("Expected %t from Equals method for linuxerr: %s %T and error: %s %T", tc.equal, le, le, e, e) 301 } 302 } 303 } 304 }) 305 } 306 }