Files
visor/pkg/errors/linuxerr/linuxerr_test.go
T
Zach KoopmansandgVisor bot 3b0fa805bb [syserror] Refactor linuxerr and error package.
Move Error struct to pkg/errors package for use in multiple places.
Move linuxerr static definitions under pkg/errors/linuxerr.
Add a lookup list for quick lookup of *errors.Error by errno. This is useful
when converting syserror errors and unix.Errno/syscall.Errrno values to
*errors.Error.
Update benchmarks routines to include conversions.

The below benchmarks show *errors.Error usage to be comparable to using
unix.Errno.

BenchmarkAssignUnix
BenchmarkAssignUnix-32                 	787875022	         1.284 ns/op
BenchmarkAssignLinuxerr
BenchmarkAssignLinuxerr-32             	1000000000	         1.209 ns/op
BenchmarkAssignSyserror
BenchmarkAssignSyserror-32             	759269229	         1.429 ns/op
BenchmarkCompareUnix
BenchmarkCompareUnix-32                	1000000000	         1.310 ns/op
BenchmarkCompareLinuxerr
BenchmarkCompareLinuxerr-32            	1000000000	         1.241 ns/op
BenchmarkCompareSyserror
BenchmarkCompareSyserror-32            	147196165	         8.248 ns/op
BenchmarkSwitchUnix
BenchmarkSwitchUnix-32                 	373233556	         3.664 ns/op
BenchmarkSwitchLinuxerr
BenchmarkSwitchLinuxerr-32             	476323929	         3.294 ns/op
BenchmarkSwitchSyserror
BenchmarkSwitchSyserror-32             	39293408	        29.62 ns/op
BenchmarkReturnUnix
BenchmarkReturnUnix-32                 	1000000000	         0.5042 ns/op
BenchmarkReturnLinuxerr
BenchmarkReturnLinuxerr-32             	1000000000	         0.8152 ns/op
BenchmarkConvertUnixLinuxerr
BenchmarkConvertUnixLinuxerr-32        	739948875	         1.547 ns/op
BenchmarkConvertUnixLinuxerrZero
BenchmarkConvertUnixLinuxerrZero-32    	977733974	         1.489 ns/op

PiperOrigin-RevId: 379806801
2021-06-16 14:08:52 -07:00

246 lines
5.9 KiB
Go

// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package syserror_test
import (
"errors"
"syscall"
"testing"
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/abi/linux/errno"
gErrors "gvisor.dev/gvisor/pkg/errors"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/syserror"
)
var globalError error
func BenchmarkAssignUnix(b *testing.B) {
for i := b.N; i > 0; i-- {
globalError = unix.EINVAL
}
}
func BenchmarkAssignLinuxerr(b *testing.B) {
for i := b.N; i > 0; i-- {
globalError = linuxerr.EINVAL
}
}
func BenchmarkAssignSyserror(b *testing.B) {
for i := b.N; i > 0; i-- {
globalError = syserror.EINVAL
}
}
func BenchmarkCompareUnix(b *testing.B) {
globalError = unix.EAGAIN
j := 0
for i := b.N; i > 0; i-- {
if globalError == unix.EINVAL {
j++
}
}
}
func BenchmarkCompareLinuxerr(b *testing.B) {
globalError = linuxerr.E2BIG
j := 0
for i := b.N; i > 0; i-- {
if globalError == linuxerr.EINVAL {
j++
}
}
}
func BenchmarkCompareSyserror(b *testing.B) {
globalError = syserror.EAGAIN
j := 0
for i := b.N; i > 0; i-- {
if globalError == syserror.EINVAL {
j++
}
}
}
func BenchmarkSwitchUnix(b *testing.B) {
globalError = unix.EPERM
j := 0
for i := b.N; i > 0; i-- {
switch globalError {
case unix.EINVAL:
j++
case unix.EINTR:
j += 2
case unix.EAGAIN:
j += 3
}
}
}
func BenchmarkSwitchLinuxerr(b *testing.B) {
globalError = linuxerr.EPERM
j := 0
for i := b.N; i > 0; i-- {
switch globalError {
case linuxerr.EINVAL:
j++
case linuxerr.EINTR:
j += 2
case linuxerr.EAGAIN:
j += 3
}
}
}
func BenchmarkSwitchSyserror(b *testing.B) {
globalError = syserror.EPERM
j := 0
for i := b.N; i > 0; i-- {
switch globalError {
case syserror.EINVAL:
j++
case syserror.EINTR:
j += 2
case syserror.EAGAIN:
j += 3
}
}
}
func BenchmarkReturnUnix(b *testing.B) {
var localError error
f := func() error {
return unix.EINVAL
}
for i := b.N; i > 0; i-- {
localError = f()
}
if localError != nil {
return
}
}
func BenchmarkReturnLinuxerr(b *testing.B) {
var localError error
f := func() error {
return linuxerr.EINVAL
}
for i := b.N; i > 0; i-- {
localError = f()
}
if localError != nil {
return
}
}
func BenchmarkConvertUnixLinuxerr(b *testing.B) {
var localError error
for i := b.N; i > 0; i-- {
localError = linuxerr.ErrorFromErrno(errno.Errno(unix.EINVAL))
}
if localError != nil {
return
}
}
func BenchmarkConvertUnixLinuxerrZero(b *testing.B) {
var localError error
for i := b.N; i > 0; i-- {
localError = linuxerr.ErrorFromErrno(errno.Errno(0))
}
if localError != nil {
return
}
}
type translationTestTable struct {
fn string
errIn error
syscallErrorIn unix.Errno
expectedBool bool
expectedTranslation unix.Errno
}
func TestErrorTranslation(t *testing.T) {
myError := errors.New("My test error")
myError2 := errors.New("Another test error")
testTable := []translationTestTable{
{"TranslateError", myError, 0, false, 0},
{"TranslateError", myError2, 0, false, 0},
{"AddErrorTranslation", myError, unix.EAGAIN, true, 0},
{"AddErrorTranslation", myError, unix.EAGAIN, false, 0},
{"AddErrorTranslation", myError, unix.EPERM, false, 0},
{"TranslateError", myError, 0, true, unix.EAGAIN},
{"TranslateError", myError2, 0, false, 0},
{"AddErrorTranslation", myError2, unix.EPERM, true, 0},
{"AddErrorTranslation", myError2, unix.EPERM, false, 0},
{"AddErrorTranslation", myError2, unix.EAGAIN, false, 0},
{"TranslateError", myError, 0, true, unix.EAGAIN},
{"TranslateError", myError2, 0, true, unix.EPERM},
}
for _, tt := range testTable {
switch tt.fn {
case "TranslateError":
err, ok := syserror.TranslateError(tt.errIn)
if ok != tt.expectedBool {
t.Fatalf("%v(%v) => %v expected %v", tt.fn, tt.errIn, ok, tt.expectedBool)
} else if err != tt.expectedTranslation {
t.Fatalf("%v(%v) (error) => %v expected %v", tt.fn, tt.errIn, err, tt.expectedTranslation)
}
case "AddErrorTranslation":
ok := syserror.AddErrorTranslation(tt.errIn, tt.syscallErrorIn)
if ok != tt.expectedBool {
t.Fatalf("%v(%v) => %v expected %v", tt.fn, tt.errIn, ok, tt.expectedBool)
}
default:
t.Fatalf("Unknown function %v", tt.fn)
}
}
}
func TestSyscallErrnoToErrors(t *testing.T) {
for _, tc := range []struct {
errno syscall.Errno
err *gErrors.Error
}{
{errno: syscall.EACCES, err: linuxerr.EACCES},
{errno: syscall.EAGAIN, err: linuxerr.EAGAIN},
{errno: syscall.EBADF, err: linuxerr.EBADF},
{errno: syscall.EBUSY, err: linuxerr.EBUSY},
{errno: syscall.EDOM, err: linuxerr.EDOM},
{errno: syscall.EEXIST, err: linuxerr.EEXIST},
{errno: syscall.EFAULT, err: linuxerr.EFAULT},
{errno: syscall.EFBIG, err: linuxerr.EFBIG},
{errno: syscall.EINTR, err: linuxerr.EINTR},
{errno: syscall.EINVAL, err: linuxerr.EINVAL},
{errno: syscall.EIO, err: linuxerr.EIO},
{errno: syscall.ENOTDIR, err: linuxerr.ENOTDIR},
{errno: syscall.ENOTTY, err: linuxerr.ENOTTY},
{errno: syscall.EPERM, err: linuxerr.EPERM},
{errno: syscall.EPIPE, err: linuxerr.EPIPE},
{errno: syscall.ESPIPE, err: linuxerr.ESPIPE},
{errno: syscall.EWOULDBLOCK, err: linuxerr.EAGAIN},
} {
t.Run(tc.errno.Error(), func(t *testing.T) {
e := linuxerr.ErrorFromErrno(errno.Errno(tc.errno))
if e != tc.err {
t.Fatalf("Mismatch errors: want: %+v (%d) got: %+v %d", tc.err, tc.err.Errno(), e, e.Errno())
}
})
}
}