| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- package pacer
- import (
- "context"
- "testing"
- "time"
- )
- func TestPacer_Instant(t *testing.T) {
- p := New(100, 0) // 100/s, no ramp
- ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
- defer cancel()
- ch, stop := p.Tick(ctx)
- defer stop()
- var count int
- for range ch {
- count++
- if count > 25 {
- // Should fire ~20 times in 200ms at 100/s
- break
- }
- }
- if count < 15 {
- t.Errorf("instant pacer: expected ≥15 ticks in 200ms, got %d", count)
- }
- }
- func TestPacer_RampLinear(t *testing.T) {
- // This test uses a mock clock that advances with each call.
- // Total wall clock needed: 100ms (ramp) + 200ms (steady) = 300ms.
- p := New(100, 100*time.Millisecond) // 100/s, 100ms ramp
- clockMs := 0
- p.Clock = func() time.Time {
- clockMs += 10 // each p.Clock call advances 10ms
- return time.Date(2000, 1, 1, 0, 0, 0, clockMs*1_000_000, time.UTC)
- }
- ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
- defer cancel()
- ch, stop := p.Tick(ctx)
- defer stop()
- var count int
- for range ch {
- count++
- if count > 50 {
- break
- }
- }
- // With mock clock: ramp phase (100ms) + steady phase (~200ms of ticks)
- // At 100/s, 1 tick per 10ms. In 300ms mock time, should get ~30 ticks.
- if count < 20 {
- t.Errorf("ramp pacer: expected ≥20 ticks in 300ms mock time, got %d", count)
- }
- }
- func TestPacer_Overshoot(t *testing.T) {
- // rate=0 should return a ticker that essentially never fires.
- p := New(0, 0)
- ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
- defer cancel()
- ch, stop := p.Tick(ctx)
- defer stop()
- select {
- case _, ok := <-ch:
- if ok {
- t.Error("channel should be closed for rate=0")
- }
- case <-time.After(60 * time.Millisecond):
- // expected — no ticks fired
- }
- }
- func TestPacer_ContextCancel(t *testing.T) {
- p := New(10_000, 0) // fast rate
- ctx, cancel := context.WithCancel(context.Background())
- ch, stop := p.Tick(ctx)
- // Cancel immediately
- cancel()
- stop()
- // Channel should close (no tick sent after cancel)
- select {
- case _, ok := <-ch:
- if ok {
- t.Error("channel should be closed after context cancel")
- }
- case <-time.After(50 * time.Millisecond):
- // ok — closed within 50ms
- }
- }
|