76 lines
1.6 KiB
Go
76 lines
1.6 KiB
Go
package jobs
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
type tickRunner struct {
|
|
mu sync.Mutex
|
|
calls, active, max int
|
|
block chan struct{}
|
|
}
|
|
|
|
func (r *tickRunner) Tick(ctx context.Context, _ string) (TickResult, error) {
|
|
r.mu.Lock()
|
|
r.calls++
|
|
r.active++
|
|
if r.active > r.max {
|
|
r.max = r.active
|
|
}
|
|
r.mu.Unlock()
|
|
select {
|
|
case <-r.block:
|
|
case <-ctx.Done():
|
|
}
|
|
r.mu.Lock()
|
|
r.active--
|
|
r.mu.Unlock()
|
|
return TickResult{}, nil
|
|
}
|
|
func TestWorkerLoopStartStopAndPreventsOverlap(t *testing.T) {
|
|
runner := &tickRunner{block: make(chan struct{})}
|
|
loop := NewWorkerLoop(runner, LoopConfig{Interval: time.Millisecond, WorkerID: "loop"})
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
loop.Start(ctx)
|
|
deadline := time.After(time.Second)
|
|
for {
|
|
runner.mu.Lock()
|
|
calls := runner.calls
|
|
runner.mu.Unlock()
|
|
if calls > 0 {
|
|
break
|
|
}
|
|
select {
|
|
case <-deadline:
|
|
t.Fatal("loop did not tick")
|
|
default:
|
|
time.Sleep(time.Millisecond)
|
|
}
|
|
}
|
|
time.Sleep(10 * time.Millisecond)
|
|
runner.mu.Lock()
|
|
if runner.max != 1 || runner.calls != 1 {
|
|
t.Fatalf("calls=%d max=%d", runner.calls, runner.max)
|
|
}
|
|
runner.mu.Unlock()
|
|
close(runner.block)
|
|
loop.Stop()
|
|
loop.Stop()
|
|
}
|
|
func TestWorkerLoopTickNowSkipsOverlap(t *testing.T) {
|
|
r := &tickRunner{block: make(chan struct{})}
|
|
l := NewWorkerLoop(r, LoopConfig{WorkerID: "w"})
|
|
done := make(chan struct{})
|
|
go func() { _, _ = l.Tick(context.Background()); close(done) }()
|
|
time.Sleep(time.Millisecond)
|
|
if _, ok := l.Tick(context.Background()); ok {
|
|
t.Fatal("overlap was not skipped")
|
|
}
|
|
close(r.block)
|
|
<-done
|
|
}
|