package task import ( "context" "errors" "sync/atomic" "testing" "time" "go.uber.org/zap" ) type mockTask struct { name string interval time.Duration err error runCount *atomic.Int32 } func (m *mockTask) Name() string { return m.name } func (m *mockTask) Interval() time.Duration { return m.interval } func (m *mockTask) Run(ctx context.Context) error { if m.runCount != nil { m.runCount.Add(1) } return m.err } func TestRunner_StartAndWait(t *testing.T) { runCount := &atomic.Int32{} task := &mockTask{name: "ok", interval: 20 * time.Millisecond, runCount: runCount} runner := NewRunner(zap.NewNop(), task) ctx, cancel := context.WithCancel(context.Background()) defer cancel() runner.Start(ctx) time.Sleep(60 * time.Millisecond) cancel() runner.Wait() if runCount.Load() == 0 { t.Fatalf("expected task to run at least once") } } func TestRunner_RunErrorLogged(t *testing.T) { runCount := &atomic.Int32{} task := &mockTask{name: "err", interval: 10 * time.Millisecond, err: errors.New("boom"), runCount: runCount} runner := NewRunner(zap.NewNop(), task) ctx, cancel := context.WithCancel(context.Background()) defer cancel() runner.Start(ctx) time.Sleep(25 * time.Millisecond) cancel() runner.Wait() if runCount.Load() == 0 { t.Fatalf("expected task to be attempted") } }