mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
e1dc1c78e7
Add Equals method to compare syserror and unix.Errno errors to linuxerr errors. This will facilitate removal of syserror definitions in a followup, and finding needed conversions from unix.Errno to linuxerr. PiperOrigin-RevId: 380909667
307 lines
7.6 KiB
Go
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 = 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())
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// 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, syserror.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)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|