package watchdog_test import ( "context" "errors" "reflect" "testing" "time" "code.uint32.ru/tiny/watchdog" ) type mockChecker struct { name string err error called bool } func (m *mockChecker) Func(ctx context.Context) error { m.called = true time.Sleep(time.Millisecond * 10) if err := ctx.Err(); err != nil { return err } return 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, err error) *mockChecker { return &mockChecker{name: name, 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", nil) m2 := newMockChecker("mock2", 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", nil) m2 := newMockChecker("mock2", 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", nil) m2 := newMockChecker("mock2", 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 range out { count++ } if count != 0 { 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", nil) w.AddChecks(m1.Check()) out, _ := w.Start(0) time.Sleep(time.Second) w.Stop() res := <-out if !errors.Is(res.Error, context.DeadlineExceeded) { t.Logf("got err: %v", res.Error) t.Fatal("incorrect status for timed out op") } }