github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/watchdog/watchdog_test.go (about) 1 // Copyright 2021 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 watchdog 6 7 import ( 8 "errors" 9 "fmt" 10 "os" 11 "strings" 12 "testing" 13 "time" 14 "unsafe" 15 16 "golang.org/x/sys/unix" 17 ) 18 19 type mockDog struct { 20 forceErrNo unix.Errno 21 forceErr error 22 23 option Option 24 currentStatus uint32 25 bootStatus uint32 26 timeout uint32 27 preTimeout uint32 28 timeLeft uint32 29 info unix.WatchdogInfo 30 } 31 32 func (f *mockDog) unixSyscall(trap, a1, a2 uintptr, a3 unsafe.Pointer) (uintptr, uintptr, unix.Errno) { 33 if f.forceErrNo != 0 { 34 return 0, 0, f.forceErrNo 35 } 36 if trap != unix.SYS_IOCTL { 37 return 0, 0, unix.EINVAL 38 } 39 switch a2 { 40 case wdiocGetSupport: 41 *(*unix.WatchdogInfo)(a3) = f.info 42 case wdiocSetOptions: 43 f.option = *(*Option)(a3) 44 case wdiocSetTimeout: 45 f.timeout = *(*uint32)(a3) 46 case wdiocSetPreTimeout: 47 f.preTimeout = *(*uint32)(a3) 48 default: 49 return 0, 0, unix.EINVAL 50 } 51 return 0, 0, 0 52 } 53 54 func (f *mockDog) unixIoctlGetUint32(fd int, req uint) (uint32, error) { 55 if f.forceErr != nil { 56 return 0, f.forceErr 57 } 58 if fd < 0 { 59 return 0, fmt.Errorf("invalid file descriptor") 60 } 61 switch req { 62 case wdiocGetStatus: 63 return f.currentStatus, nil 64 case wdiocGetBootStatus: 65 return f.bootStatus, nil 66 case wdiocGetTimeout: 67 return f.timeout, nil 68 case wdiocGetPreTimeout: 69 return f.preTimeout, nil 70 case wdiocGetTimeLeft: 71 return f.timeLeft, nil 72 default: 73 return 0, fmt.Errorf("no valid value passed to unixIoctlGetUnit32 for req") 74 } 75 } 76 77 func TestWatchdogSyscallFunctions(t *testing.T) { 78 tmpFile, err := os.CreateTemp("", "") 79 if err != nil { 80 t.Errorf("Could not create temp file: %v", err) 81 } 82 defer os.Remove(tmpFile.Name()) 83 84 wd, err := Open(tmpFile.Name()) 85 if err != nil { 86 t.Errorf("Could not open watchdog : %v", err) 87 } 88 defer wd.Close() 89 90 m := mockDog{} 91 92 wd.syscalls = &m 93 94 for _, tt := range []struct { 95 name string 96 forceErrno unix.Errno 97 wantErr error 98 option Option 99 timeout time.Duration 100 }{ 101 { 102 name: "NoError", 103 option: OptionDisableCard, 104 timeout: 0, 105 }, 106 { 107 name: "FroceSyscallError", 108 forceErrno: unix.EINVAL, 109 wantErr: unix.EINVAL, 110 }, 111 } { 112 m.forceErrNo = tt.forceErrno 113 t.Run("Support"+tt.name, func(t *testing.T) { 114 _, err := wd.Support() 115 if !errors.Is(err, tt.wantErr) { 116 t.Errorf("Test %q failed. Want: %q Got: %q", tt.name, tt.wantErr, err) 117 } 118 }) 119 120 t.Run("SetOption"+tt.name, func(t *testing.T) { 121 if err := wd.SetOptions(tt.option); !errors.Is(err, tt.wantErr) { 122 t.Errorf("Test %q failed. Got: %q Want %q", tt.name, err, tt.wantErr) 123 } 124 }) 125 126 t.Run("SetTimeout"+tt.name, func(t *testing.T) { 127 if err := wd.SetTimeout(tt.timeout); !errors.Is(err, tt.wantErr) { 128 t.Errorf("Test %q failed. Got: %q Want %q", tt.name, err, tt.wantErr) 129 } 130 }) 131 132 t.Run("SetPreTimeout"+tt.name, func(t *testing.T) { 133 if err := wd.SetPreTimeout(tt.timeout); !errors.Is(err, tt.wantErr) { 134 t.Errorf("Test %q failed. Got: %q Want %q", tt.name, err, tt.wantErr) 135 } 136 }) 137 } 138 } 139 140 func TestWatchdogIoctlGetUint32Functions(t *testing.T) { 141 tmpFile, err := os.CreateTemp("", "") 142 if err != nil { 143 t.Errorf("Could not create temp file: %v", err) 144 } 145 defer os.Remove(tmpFile.Name()) 146 147 wd, err := Open(tmpFile.Name()) 148 if err != nil { 149 t.Errorf("Could not open watchdog : %v", err) 150 } 151 defer wd.Close() 152 153 m := mockDog{} 154 155 wd.syscalls = &m 156 157 for _, tt := range []struct { 158 name string 159 forceErrno unix.Errno 160 forceErr error 161 wantErr error 162 option Option 163 timeout time.Duration 164 pretimeout time.Duration 165 timeleft time.Duration 166 status Status 167 }{ 168 { 169 name: "NoError", 170 forceErr: nil, 171 wantErr: nil, 172 option: OptionDisableCard, 173 pretimeout: 0, 174 timeleft: 0, 175 timeout: 0, 176 status: 0, 177 }, 178 { 179 name: "FroceSyscallError", 180 forceErr: errors.New("Duh"), 181 wantErr: nil, 182 option: OptionDisableCard, 183 pretimeout: 0, 184 timeleft: 0, 185 timeout: 0, 186 status: 0, 187 }, 188 } { 189 190 m.forceErr = tt.forceErr 191 tt.wantErr = tt.forceErr 192 t.Run("Status"+tt.name, func(t *testing.T) { 193 s, err := wd.Status() 194 if !errors.Is(err, tt.wantErr) { 195 t.Errorf("Test %q failed. Got: %q Want %q", tt.name, err, tt.wantErr) 196 } 197 if err != nil { 198 return 199 } 200 201 if s != tt.status { 202 t.Errorf("Test %q failed. Got: %d Want %d", tt.name, s, tt.status) 203 } 204 }) 205 206 t.Run("BootStatus"+tt.name, func(t *testing.T) { 207 s, err := wd.BootStatus() 208 if !errors.Is(err, tt.wantErr) { 209 t.Errorf("Test %q failed. Got: %q Want %q", tt.name, err, tt.wantErr) 210 } 211 if err != nil { 212 return 213 } 214 if s != tt.status { 215 t.Errorf("Test %q failed. Got: %q Want %q", tt.name, s, tt.status) 216 } 217 }) 218 219 t.Run("GetTimeout"+tt.name, func(t *testing.T) { 220 s, err := wd.Timeout() 221 if !errors.Is(err, tt.wantErr) { 222 t.Errorf("Test %q failed. Got: %q Want %q", tt.name, err, tt.wantErr) 223 } 224 if err != nil { 225 return 226 } 227 if s != tt.timeout { 228 t.Errorf("Test %q failed. Got: %q Want %q", tt.name, s, tt.timeout) 229 } 230 }) 231 232 t.Run("GetPreTimeout"+tt.name, func(t *testing.T) { 233 s, err := wd.PreTimeout() 234 if !errors.Is(err, tt.wantErr) { 235 t.Errorf("Test %q failed. Got: %q Want %q", tt.name, err, tt.wantErr) 236 } 237 if err != nil { 238 return 239 } 240 if s != tt.timeout { 241 t.Errorf("Test %q failed. Got: %q Want %q", tt.name, s, tt.pretimeout) 242 } 243 }) 244 245 t.Run("GetTimeLeft"+tt.name, func(t *testing.T) { 246 s, err := wd.TimeLeft() 247 if !errors.Is(err, tt.wantErr) { 248 t.Errorf("Test %q failed. Got: %q Want %q", tt.name, err, tt.wantErr) 249 } 250 if err != nil { 251 return 252 } 253 if s != tt.timeout { 254 t.Errorf("Test %q failed. Got: %q Want %q", tt.name, s, tt.timeleft) 255 } 256 }) 257 } 258 } 259 260 func TestSetTimeoutError(t *testing.T) { 261 tmpFile, err := os.CreateTemp("", "") 262 if err != nil { 263 t.Errorf("Could not create temp file: %v", err) 264 } 265 defer os.Remove(tmpFile.Name()) 266 267 wd, err := Open(tmpFile.Name()) 268 if err != nil { 269 t.Errorf("Could not open watchdog : %v", err) 270 } 271 defer wd.Close() 272 273 m := mockDog{} 274 275 wd.syscalls = &m 276 wantErr := errors.New("Watchdog timeout set to 0s, wanted 5ns") 277 278 if err := wd.SetTimeout(5); err != nil { 279 if !strings.Contains(err.Error(), wantErr.Error()) { 280 t.Errorf("SetTimeout failed. Want: %q Got: %q", wantErr, err) 281 } 282 return 283 } 284 t.Error("TestSetTimeout succeeded but shouldnt") 285 286 } 287 288 func TestSetPreTimeoutError(t *testing.T) { 289 tmpFile, err := os.CreateTemp("", "") 290 if err != nil { 291 t.Errorf("Could not create temp file: %v", err) 292 } 293 defer os.Remove(tmpFile.Name()) 294 295 wd, err := Open(tmpFile.Name()) 296 if err != nil { 297 t.Errorf("Could not open watchdog : %v", err) 298 } 299 defer wd.Close() 300 301 m := mockDog{} 302 303 wd.syscalls = &m 304 wantErr := errors.New("Watchdog pretimeout set to 0s, wanted 5ns") 305 306 if err := wd.SetPreTimeout(5); err != nil { 307 if !strings.Contains(err.Error(), wantErr.Error()) { 308 t.Errorf("SetTimeout failed. Want: %q Got: %q", wantErr, err) 309 } 310 return 311 } 312 t.Error("TestSetTimeout succeeded but shouldnt") 313 314 }