package watchdog_test import ( "context" "reflect" "testing" "time" "code.uint32.ru/tiny/watchdog" ) type mockChecker struct { name string status watchdog.Status err error called bool } func (m *mockChecker) Func(_ context.Context) (watchdog.Status, error) { m.called = true 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 TestStart(t *testing.T) { w := new(watchdog.Watchdog) if _, err := w.Start(t.Context(), 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(t.Context(), 0) if err != nil { t.Error("Start returns error", err) } out2, err := w.Start(t.Context(), 0) if err != nil { t.Error("second call to Start returns error") } if !reflect.DeepEqual(out, out2) { t.Error("returned channels are not equal") } count := 0 go func() { time.Sleep(time.Second) if err := w.Stop(); err != nil { t.Error("Stop returned error", err) } }() 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 TestWatchdogObeysContext(t *testing.T) { w := new(watchdog.Watchdog) m1 := newMockChecker("mock", watchdog.StatusOK, nil) m2 := newMockChecker("mock2", watchdog.StatusOK, nil) w.AddChecks(m1.Check(), m2.Check()) ctx, stop := context.WithCancel(t.Context()) if _, err := w.Start(ctx, 2); err != nil { t.Error(err) } stop() // wait for goroutines to finish time.Sleep(time.Second) if err := w.Stop(); err == nil { t.Error("no error calling Stop for stopped instance") } }