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  }