184 lines
3.7 KiB
Go
184 lines
3.7 KiB
Go
|
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")
|
||
|
}
|
||
|
}
|