Alerting: tests for ticker (#47986)

This commit is contained in:
Yuriy Tseretyan 2022-04-21 14:58:05 -04:00 committed by GitHub
parent 4fbc481d1f
commit 53a6c0210d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,121 +1,119 @@
package alerting package alerting
// import ( import (
// "testing" "context"
// "time" "fmt"
// "math/rand"
// "github.com/benbjohnson/clock" "sync"
// ) "testing"
// "time"
// func inspectTick(tick time.Time, last time.Time, offset time.Duration, t *testing.T) {
// if !tick.Equal(last.Add(time.Duration(1) * time.Second)) { "github.com/benbjohnson/clock"
// t.Fatalf("expected a tick 1 second more than prev, %s. got: %s", last, tick) "github.com/stretchr/testify/require"
// } )
// }
// func TestTicker(t *testing.T) {
// returns the new last tick seen readChanOrFail := func(t *testing.T, ctx context.Context, c chan time.Time) time.Time {
// func assertAdvanceUntil(ticker *Ticker, last, desiredLast time.Time, offset, wait time.Duration, t *testing.T) time.Time { t.Helper()
// for { select {
// select { case tick := <-c:
// case tick := <-ticker.C: return tick
// inspectTick(tick, last, offset, t) case <-ctx.Done():
// last = tick require.Failf(t, fmt.Sprintf("%v", ctx.Err()), "timeout reading the channel")
// case <-time.NewTimer(wait).C: default:
// if last.Before(desiredLast) { require.Failf(t, "channel is empty but it should have a tick", "")
// t.Fatalf("waited %s for ticker to advance to %s, but only went up to %s", wait, desiredLast, last) }
// } return time.Time{}
// if last.After(desiredLast) { }
// t.Fatalf("timer advanced too far. should only have gone up to %s, but it went up to %s", desiredLast, last) t.Run("should not drop ticks", func(t *testing.T) {
// } clk := clock.NewMock()
// return last intervalSec := rand.Int63n(100) + 10
// } interval := time.Duration(intervalSec) * time.Second
// } last := clk.Now()
// } ticker := NewTicker(last, 0, clk, intervalSec)
//
// func assertNoAdvance(ticker *Ticker, desiredLast time.Time, wait time.Duration, t *testing.T) { ticks := rand.Intn(9) + 1
// for { jitter := rand.Int63n(int64(interval) - 1)
// select {
// case tick := <-ticker.C: clk.Add(time.Duration(ticks)*interval + time.Duration(jitter))
// t.Fatalf("timer should have stayed at %s, instead it advanced to %s", desiredLast, tick)
// case <-time.NewTimer(wait).C: w := sync.WaitGroup{}
// return w.Add(1)
// } regTicks := make([]time.Time, 0, ticks)
// } go func() {
// } for timestamp := range ticker.C {
// regTicks = append(regTicks, timestamp)
// func TestTickerRetro1Hour(t *testing.T) { if len(regTicks) == ticks {
// offset := time.Duration(10) * time.Second w.Done()
// last := time.Unix(0, 0) }
// mock := clock.NewMock() }
// mock.Add(time.Duration(1) * time.Hour) }()
// desiredLast := mock.Now().Add(-offset) w.Wait()
// ticker := NewTicker(last, offset, mock)
// require.Len(t, regTicks, ticks)
// last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(10)*time.Millisecond, t)
// assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) t.Run("ticks should monotonically increase", func(t *testing.T) {
// for i := 1; i < len(regTicks); i++ {
// } previous := regTicks[i-1]
// current := regTicks[i]
// func TestAdvanceWithUpdateOffset(t *testing.T) { require.Equal(t, interval, current.Sub(previous))
// offset := time.Duration(10) * time.Second }
// last := time.Unix(0, 0) })
// mock := clock.NewMock() })
// mock.Add(time.Duration(1) * time.Hour)
// desiredLast := mock.Now().Add(-offset) t.Run("should not put anything to channel until it's time", func(t *testing.T) {
// ticker := NewTicker(last, offset, mock) clk := clock.NewMock()
// intervalSec := rand.Int63n(9) + 1
// last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(10)*time.Millisecond, t) interval := time.Duration(intervalSec) * time.Second
// assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) last := clk.Now()
// ticker := NewTicker(last, 0, clk, intervalSec)
// // lowering offset should see a few more ticks expectedTick := clk.Now().Add(interval)
// offset = time.Duration(5) * time.Second for {
// ticker.updateOffset(offset) require.Empty(t, ticker.C)
// desiredLast = mock.Now().Add(-offset) clk.Add(time.Duration(rand.Int31n(500)+100) * time.Millisecond)
// last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(9)*time.Millisecond, t) if clk.Now().After(expectedTick) {
// assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) break
// }
// // advancing clock should see even more ticks }
// mock.Add(time.Duration(1) * time.Hour) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
// desiredLast = mock.Now().Add(-offset) t.Cleanup(func() {
// last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(8)*time.Millisecond, t) cancel()
// assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) })
// actual := readChanOrFail(t, ctx, ticker.C)
// } require.Equal(t, expectedTick, actual)
// })
// func getCase(lastSeconds, offsetSeconds int) (time.Time, time.Duration) {
// last := time.Unix(int64(lastSeconds), 0) t.Run("should put the tick in the channel immediately if it is behind", func(t *testing.T) {
// offset := time.Duration(offsetSeconds) * time.Second clk := clock.NewMock()
// return last, offset intervalSec := rand.Int63n(9) + 1
// } interval := time.Duration(intervalSec) * time.Second
// last := clk.Now()
// func TestTickerNoAdvance(t *testing.T) { ticker := NewTicker(last, 0, clk, intervalSec)
//
// // it's 00:01:00 now. what are some cases where we don't want the ticker to advance? // We can expect the first tick to be at a consistent interval. Take a snapshot of the clock now, before we advance it.
// mock := clock.NewMock() expectedTick := clk.Now().Add(interval)
// mock.Add(time.Duration(60) * time.Second)
// require.Empty(t, ticker.C)
// type Case struct {
// last int clk.Add(interval) // advance the clock by the interval to make the ticker tick the first time.
// offset int clk.Add(interval) // advance the clock by the interval to make the ticker tick the second time.
// }
// ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
// // note that some cases add up to now, others go into the future t.Cleanup(func() {
// cases := []Case{ cancel()
// {50, 10}, })
// {50, 30},
// {59, 1}, // Irregardless of wall time, the first tick should be initial clock + interval.
// {59, 10}, actual1 := readChanOrFail(t, ctx, ticker.C)
// {59, 30}, require.Equal(t, expectedTick, actual1)
// {60, 1},
// {60, 10}, var actual2 time.Time
// {60, 30}, require.Eventually(t, func() bool {
// {90, 1}, actual2 = readChanOrFail(t, ctx, ticker.C)
// {90, 10}, return true
// {90, 30}, }, time.Second, 10*time.Millisecond)
// }
// for _, c := range cases { // Similarly, the second tick should be last tick + interval irregardless of wall time.
// last, offset := getCase(c.last, c.offset) require.Equal(t, expectedTick.Add(interval), actual2)
// ticker := NewTicker(last, offset, mock) })
// assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) }
// }
// }