github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/ipmi/dev_test.go (about)

     1  // Copyright 2022 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ipmi
     6  
     7  import (
     8  	"fmt"
     9  	"io/ioutil"
    10  	"os"
    11  	"strings"
    12  	"syscall"
    13  	"testing"
    14  	"time"
    15  
    16  	"golang.org/x/sys/unix"
    17  )
    18  
    19  type testsyscalls struct {
    20  	forceErrno              unix.Errno
    21  	forceConnReadErr        error
    22  	forcesetReadDeadlineErr error
    23  	forceConnErr            error
    24  }
    25  
    26  func (t *testsyscalls) syscall(trap, a1, a2, a3 uintptr) (uintptr, uintptr, unix.Errno) {
    27  	if t.forceErrno != 0 {
    28  		return 0, 0, t.forceErrno
    29  	}
    30  
    31  	if trap != unix.SYS_IOCTL {
    32  		return 0, 0, unix.EINVAL
    33  	}
    34  
    35  	if a1 < 1 {
    36  		return 0, 0, unix.EINVAL
    37  	}
    38  
    39  	if a3 < 1 {
    40  		return 0, 0, unix.EINVAL
    41  	}
    42  
    43  	switch a2 {
    44  	case _IPMICTL_RECEIVE_MSG_TRUNC, _IPMICTL_SEND_COMMAND:
    45  		return 0, 0, 0
    46  	default:
    47  		return 0, 0, unix.EINVAL
    48  	}
    49  }
    50  
    51  func (t *testsyscalls) fileSyscallConn(f *os.File) (syscall.RawConn, error) {
    52  	if t.forceConnErr != nil {
    53  		return nil, t.forceConnErr
    54  	}
    55  	return f.SyscallConn()
    56  }
    57  
    58  // This function only need to return nil. The real deal only works on special file descriptors.
    59  func (t *testsyscalls) fileSetReadDeadline(f *os.File, time time.Duration) error {
    60  	if t.forcesetReadDeadlineErr != nil {
    61  		return t.forcesetReadDeadlineErr
    62  	}
    63  	return nil
    64  }
    65  
    66  func (t *testsyscalls) connRead(f func(fd uintptr) bool, conn syscall.RawConn) error {
    67  	if t.forceConnReadErr != nil {
    68  		return t.forceConnReadErr
    69  	}
    70  	return conn.Read(f)
    71  }
    72  
    73  func TestDev(t *testing.T) {
    74  	df, err := ioutil.TempFile("", "ipmi_dummy_file-")
    75  	if err != nil {
    76  		t.Error(err)
    77  	}
    78  
    79  	sc := &testsyscalls{}
    80  
    81  	d := dev{
    82  		f:        df,
    83  		syscalls: sc,
    84  	}
    85  	defer os.RemoveAll(df.Name())
    86  
    87  	for _, tt := range []struct {
    88  		name        string
    89  		req         *request
    90  		resp        *response
    91  		forceErrno  unix.Errno
    92  		wantSendErr error
    93  		wantRecvErr error
    94  		connReadErr error
    95  		deadlineErr error
    96  	}{
    97  		{
    98  			name: "NoError",
    99  			req:  &request{},
   100  			resp: &response{},
   101  		},
   102  		{
   103  			name:        "ForceSysCallError",
   104  			forceErrno:  unix.Errno(1),
   105  			wantSendErr: fmt.Errorf("syscall failed with: operation not permitted"),
   106  			wantRecvErr: fmt.Errorf("failed to read rawconn"),
   107  			req:         &request{},
   108  			resp:        &response{},
   109  		},
   110  		{
   111  			name:        "ForceConnError",
   112  			req:         &request{},
   113  			resp:        &response{},
   114  			wantRecvErr: fmt.Errorf("failed to get file rawconn"),
   115  			connReadErr: fmt.Errorf("Force connRead error"),
   116  		},
   117  		{
   118  			name:        "ForceSetReadDeadlineError",
   119  			req:         &request{},
   120  			resp:        &response{},
   121  			wantRecvErr: fmt.Errorf("failed to set read deadline"),
   122  			deadlineErr: fmt.Errorf("force set read deadline"),
   123  		},
   124  		{
   125  			name: "FailMessageID",
   126  			req: &request{
   127  				msgid: 1,
   128  			},
   129  			resp: &response{
   130  				msgid: 2,
   131  			},
   132  			wantRecvErr: fmt.Errorf("failed to read rawconn: waiting for unsupported file type"),
   133  		},
   134  		{
   135  			name: "ForceLongRecvMsgDataLen",
   136  			req:  &request{},
   137  			resp: &response{
   138  				msg: Msg{
   139  					DataLen: _IPMI_BUF_SIZE + 1,
   140  				},
   141  			},
   142  			wantRecvErr: fmt.Errorf("data length received too large"),
   143  		},
   144  	} {
   145  		sc.forceErrno = tt.forceErrno
   146  		sc.forceConnReadErr = tt.connReadErr
   147  		sc.forceConnErr = tt.connReadErr
   148  		sc.forcesetReadDeadlineErr = tt.deadlineErr
   149  
   150  		t.Run("SendRequest"+tt.name, func(t *testing.T) {
   151  			if err := d.SendRequest(tt.req); err != nil {
   152  				if !strings.Contains(err.Error(), tt.wantSendErr.Error()) {
   153  					t.Errorf("d.SendRequest(tt.req) = %q, not %q", err, tt.wantSendErr)
   154  				}
   155  			}
   156  		})
   157  
   158  		t.Run(tt.name, func(t *testing.T) {
   159  			buf := make([]byte, 1)
   160  			if _, err := d.ReceiveResponse(0, tt.resp, buf); err != nil {
   161  				if !strings.Contains(err.Error(), tt.wantRecvErr.Error()) {
   162  					t.Errorf("d.ReceiveResponse(0, tt.resp, buf) = _, %q, not _, %q", err, tt.wantRecvErr)
   163  				}
   164  			}
   165  		})
   166  
   167  	}
   168  }
   169  
   170  func TestNewDev(t *testing.T) {
   171  	df, err := ioutil.TempFile("", "ipmi_dummy_file-")
   172  	if err != nil {
   173  		t.Errorf(`ioutil.TempFile("", "ipmi_dummy_file-") = df, %q, not df, nil`, err)
   174  	}
   175  	defer os.RemoveAll(df.Name())
   176  	_ = newDev(df)
   177  }