pacer_test.go 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. package pacer
  2. import (
  3. "context"
  4. "testing"
  5. "time"
  6. )
  7. func TestPacer_Instant(t *testing.T) {
  8. p := New(100, 0) // 100/s, no ramp
  9. ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
  10. defer cancel()
  11. ch, stop := p.Tick(ctx)
  12. defer stop()
  13. var count int
  14. for range ch {
  15. count++
  16. if count > 25 {
  17. // Should fire ~20 times in 200ms at 100/s
  18. break
  19. }
  20. }
  21. if count < 15 {
  22. t.Errorf("instant pacer: expected ≥15 ticks in 200ms, got %d", count)
  23. }
  24. }
  25. func TestPacer_RampLinear(t *testing.T) {
  26. // This test uses a mock clock that advances with each call.
  27. // Total wall clock needed: 100ms (ramp) + 200ms (steady) = 300ms.
  28. p := New(100, 100*time.Millisecond) // 100/s, 100ms ramp
  29. clockMs := 0
  30. p.Clock = func() time.Time {
  31. clockMs += 10 // each p.Clock call advances 10ms
  32. return time.Date(2000, 1, 1, 0, 0, 0, clockMs*1_000_000, time.UTC)
  33. }
  34. ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
  35. defer cancel()
  36. ch, stop := p.Tick(ctx)
  37. defer stop()
  38. var count int
  39. for range ch {
  40. count++
  41. if count > 50 {
  42. break
  43. }
  44. }
  45. // With mock clock: ramp phase (100ms) + steady phase (~200ms of ticks)
  46. // At 100/s, 1 tick per 10ms. In 300ms mock time, should get ~30 ticks.
  47. if count < 20 {
  48. t.Errorf("ramp pacer: expected ≥20 ticks in 300ms mock time, got %d", count)
  49. }
  50. }
  51. func TestPacer_Overshoot(t *testing.T) {
  52. // rate=0 should return a ticker that essentially never fires.
  53. p := New(0, 0)
  54. ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
  55. defer cancel()
  56. ch, stop := p.Tick(ctx)
  57. defer stop()
  58. select {
  59. case _, ok := <-ch:
  60. if ok {
  61. t.Error("channel should be closed for rate=0")
  62. }
  63. case <-time.After(60 * time.Millisecond):
  64. // expected — no ticks fired
  65. }
  66. }
  67. func TestPacer_ContextCancel(t *testing.T) {
  68. p := New(10_000, 0) // fast rate
  69. ctx, cancel := context.WithCancel(context.Background())
  70. ch, stop := p.Tick(ctx)
  71. // Cancel immediately
  72. cancel()
  73. stop()
  74. // Channel should close (no tick sent after cancel)
  75. select {
  76. case _, ok := <-ch:
  77. if ok {
  78. t.Error("channel should be closed after context cancel")
  79. }
  80. case <-time.After(50 * time.Millisecond):
  81. // ok — closed within 50ms
  82. }
  83. }