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  }