package watchdog_test import ( "context" "errors" "reflect" "testing" "time" "code.uint32.ru/tiny/watchdog" ) type mockChecker struct { name string status watchdog.Status err error called bool } func (m *mockChecker) Func(ctx context.Context) (watchdog.Status, error) { m.called = true time.Sleep(time.Millisecond * 10) if err := ctx.Err(); err != nil { return watchdog.StatusUnknown, err } return m.status, m.err } func (m *mockChecker) HasBeenCalled() bool { return m.called } func (m *mockChecker) Check() watchdog.Check { return watchdog.Check{ Name: m.name, Interval: time.Minute, Check: m.Func, } } func newMockChecker(name string, s watchdog.Status, err error) *mockChecker { return &mockChecker{name: name, status: s, err: err} } func TestCreateWith_new(t *testing.T) { w := new(watchdog.Watchdog) if len(w.ListChecks()) != 0 { t.Errorf("expected len = 0") } } func TestNew(t *testing.T) { w := watchdog.New() if len(w.ListChecks()) != 0 { t.Errorf("expected len = 0") } m1 := newMockChecker("mock", watchdog.StatusOK, nil) m2 := newMockChecker("mock2", watchdog.StatusOK, nil) w = watchdog.New() w.AddChecks(m1.Check(), m2.Check()) if len(w.ListChecks()) != 2 { t.Errorf("expected len = 2") } w.RemoveChecks("mock") if len(w.ListChecks()) != 1 { t.Errorf("expected len = 1") } w.RemoveChecks("mock2") if len(w.ListChecks()) != 0 { t.Errorf("expected len = 0") } w = watchdog.New(m1.Check(), m2.Check()) if len(w.ListChecks()) != 2 { t.Errorf("") } } func TestRunImmediately(t *testing.T) { w := new(watchdog.Watchdog) out, err := w.RunImmediately(t.Context(), 1) if err == nil { t.Error("empty instance must return error on RunImmediately") } if len(out) != 0 { t.Errorf("expected zero len slice for empty instance, got %d", len(out)) } m1 := newMockChecker("mock", watchdog.StatusOK, nil) m2 := newMockChecker("mock2", watchdog.StatusOK, nil) w = watchdog.New(m1.Check(), m2.Check()) out, _ = w.RunImmediately(t.Context(), 0) if len(out) != 2 { t.Error("expected result of len 2") } for _, m := range []*mockChecker{m1, m2} { if !m.HasBeenCalled() { t.Errorf("mock %s has not been called", m.name) } } } func TestStartStop(t *testing.T) { w := new(watchdog.Watchdog) if _, err := w.Start(0); err == nil { t.Error("Start doen't error on empty checks slice") } m1 := newMockChecker("mock", watchdog.StatusOK, nil) m2 := newMockChecker("mock2", watchdog.StatusOK, nil) w.AddChecks(m1.Check(), m2.Check()) out, err := w.Start(0) if err != nil { t.Error("Start returns error", err) } out2, err := w.Start(0) if err != nil { t.Error("second call to Start returns error") } if !reflect.DeepEqual(out, out2) { t.Error("returned channels are not equal") } time.Sleep(time.Second) if err := w.Stop(); err != nil { t.Error("Stop returned error", err) } count := 0 for res := range out { if res.Status != watchdog.StatusOK || res.Error != nil { t.Errorf("incorrect status for check %s", res.Name) } count++ } if count != 2 { t.Error("incorrect result count received from chan") } for _, m := range []*mockChecker{m1, m2} { if !m.HasBeenCalled() { t.Errorf("mock %s has not been called", m.name) } } if err := w.Stop(); err == nil { t.Error("call to stop on stopped instance does not return err") } } func TestSetTimeout(t *testing.T) { w := new(watchdog.Watchdog) w.SetTimeout(time.Millisecond) m1 := newMockChecker("mock", watchdog.StatusOK, nil) w.AddChecks(m1.Check()) out, _ := w.Start(0) time.Sleep(time.Second) w.Stop() res := <-out if !(res.Status == watchdog.StatusUnknown) || !errors.Is(res.Error, context.DeadlineExceeded) { t.Logf("got status: %s, err: %v", res.Status, res.Error) t.Fatal("incorrect status for timed out op") } }