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 }