2025-07-21 18:09:23 +03:00
|
|
|
package watchdog_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2025-07-25 18:42:16 +03:00
|
|
|
"errors"
|
2025-07-21 18:09:23 +03:00
|
|
|
"reflect"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"code.uint32.ru/tiny/watchdog"
|
|
|
|
)
|
|
|
|
|
|
|
|
type mockChecker struct {
|
|
|
|
name string
|
|
|
|
status watchdog.Status
|
|
|
|
err error
|
|
|
|
called bool
|
|
|
|
}
|
|
|
|
|
2025-07-25 18:42:16 +03:00
|
|
|
func (m *mockChecker) Func(ctx context.Context) (watchdog.Status, error) {
|
2025-07-21 18:09:23 +03:00
|
|
|
m.called = true
|
2025-07-25 18:42:16 +03:00
|
|
|
|
|
|
|
time.Sleep(time.Millisecond * 10)
|
|
|
|
if err := ctx.Err(); err != nil {
|
|
|
|
return watchdog.StatusUnknown, err
|
|
|
|
}
|
|
|
|
|
2025-07-21 18:09:23 +03:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2025-07-25 18:42:16 +03:00
|
|
|
func TestStartStop(t *testing.T) {
|
2025-07-21 18:09:23 +03:00
|
|
|
w := new(watchdog.Watchdog)
|
2025-07-25 18:42:16 +03:00
|
|
|
if _, err := w.Start(0); err == nil {
|
2025-07-21 18:09:23 +03:00
|
|
|
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())
|
|
|
|
|
2025-07-25 18:42:16 +03:00
|
|
|
out, err := w.Start(0)
|
2025-07-21 18:09:23 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Error("Start returns error", err)
|
|
|
|
}
|
|
|
|
|
2025-07-25 18:42:16 +03:00
|
|
|
out2, err := w.Start(0)
|
2025-07-21 18:09:23 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Error("second call to Start returns error")
|
|
|
|
}
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(out, out2) {
|
|
|
|
t.Error("returned channels are not equal")
|
|
|
|
}
|
|
|
|
|
2025-07-25 18:42:16 +03:00
|
|
|
time.Sleep(time.Second)
|
|
|
|
if err := w.Stop(); err != nil {
|
|
|
|
t.Error("Stop returned error", err)
|
|
|
|
}
|
|
|
|
|
2025-07-21 18:09:23 +03:00
|
|
|
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")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-07-25 18:42:16 +03:00
|
|
|
func TestSetTimeout(t *testing.T) {
|
2025-07-21 18:09:23 +03:00
|
|
|
w := new(watchdog.Watchdog)
|
2025-07-25 18:42:16 +03:00
|
|
|
w.SetTimeout(time.Millisecond)
|
2025-07-21 18:09:23 +03:00
|
|
|
m1 := newMockChecker("mock", watchdog.StatusOK, nil)
|
2025-07-25 18:42:16 +03:00
|
|
|
w.AddChecks(m1.Check())
|
2025-07-21 18:09:23 +03:00
|
|
|
|
2025-07-25 18:42:16 +03:00
|
|
|
out, _ := w.Start(0)
|
2025-07-21 18:09:23 +03:00
|
|
|
time.Sleep(time.Second)
|
2025-07-25 18:42:16 +03:00
|
|
|
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")
|
2025-07-21 18:09:23 +03:00
|
|
|
}
|
|
|
|
}
|