Files
gvisor/pkg/errors/linuxerr/linuxerr_test.go
T
Zach Koopmans 6ef2684096 [syserror] Update syserror to linuxerr for EACCES, EBADF, and EPERM.
Update all instances of the above errors to the faster linuxerr implementation.
With the temporary linuxerr.Equals(), no logical changes are made.

PiperOrigin-RevId: 382306655
2021-06-30 08:18:59 -07:00

307 lines
7.6 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"
"io"
"io/fs"
"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 = linuxerr.ENOMSG
}
}
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 == linuxerr.EACCES {
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 = linuxerr.EPERM
j := 0
for i := b.N; i > 0; i-- {
switch globalError {
case linuxerr.EACCES:
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())
}
})
}
}
// TestEqualsMethod tests that the Equals method correctly compares syerror,
// unix.Errno and linuxerr.
// TODO (b/34162363): Remove this.
func TestEqualsMethod(t *testing.T) {
for _, tc := range []struct {
name string
linuxErr []*gErrors.Error
err []error
equal bool
}{
{
name: "compare nil",
linuxErr: []*gErrors.Error{nil, linuxerr.NOERROR},
err: []error{nil, linuxerr.NOERROR, unix.Errno(0)},
equal: true,
},
{
name: "linuxerr nil error not",
linuxErr: []*gErrors.Error{nil, linuxerr.NOERROR},
err: []error{unix.Errno(1), linuxerr.EPERM, linuxerr.EACCES},
equal: false,
},
{
name: "linuxerr not nil error nil",
linuxErr: []*gErrors.Error{linuxerr.ENOENT},
err: []error{nil, unix.Errno(0), linuxerr.NOERROR},
equal: false,
},
{
name: "equal errors",
linuxErr: []*gErrors.Error{linuxerr.ESRCH},
err: []error{linuxerr.ESRCH, syserror.ESRCH, unix.Errno(linuxerr.ESRCH.Errno())},
equal: true,
},
{
name: "unequal errors",
linuxErr: []*gErrors.Error{linuxerr.ENOENT},
err: []error{linuxerr.ESRCH, syserror.ESRCH, unix.Errno(linuxerr.ESRCH.Errno())},
equal: false,
},
{
name: "other error",
linuxErr: []*gErrors.Error{nil, linuxerr.NOERROR, linuxerr.E2BIG, linuxerr.EINVAL},
err: []error{fs.ErrInvalid, io.EOF},
equal: false,
},
} {
t.Run(tc.name, func(t *testing.T) {
for _, le := range tc.linuxErr {
for _, e := range tc.err {
if linuxerr.Equals(le, e) != tc.equal {
t.Fatalf("Expected %t from Equals method for linuxerr: %s %T and error: %s %T", tc.equal, le, le, e, e)
}
}
}
})
}
}