Ejemplo n.º 1
0
func TestSilencerStalled(t *testing.T) {
	type Event struct {
		time time.Time
		n    int
	}
	events := make([]Event, 0)

	var mu sync.Mutex

	// fire 5 events in rapid succession, all within the suppress window. the
	// first call should happen immediately but the next four should be
	// coalesced at the end of the suppress period.
	start := time.Now()
	for i := 0; i < 5; i++ {
		suppress.For(100*time.Millisecond, "anon", func(n int, tag string) {
			mu.Lock()
			defer mu.Unlock()
			events = append(events, Event{time.Now(), n})
			t.Logf("%v", tag)
		})
		time.Sleep(10 * time.Millisecond)
	}
	time.Sleep(start.Add(110 * time.Millisecond).Sub(time.Now()))

	mu.Lock()
	defer mu.Unlock()
	if len(events) != 2 || events[0].n != 1 || events[1].n != 4 {
		t.Errorf("unexpected event stream: %+v", events)
	}
}
Ejemplo n.º 2
0
func test(t *testing.T, ids []string, invocations int, testTime time.Duration, suppressTime time.Duration, expectedPerInvocation int) {
	var attempts, firings, errors int64
	var lasts struct {
		sync.RWMutex
		m map[string]time.Time
	}
	lasts.m = make(map[string]time.Time)

	f := func(count int, tag string) {
		lasts.RLock()
		last := lasts.m[tag]
		lasts.RUnlock()

		now := time.Now()
		if last.IsZero() || math.Abs(float64(now.Sub(last)-suppressTime)) < float64(5*time.Millisecond) {
			atomic.AddInt64(&firings, 1)
		} else {
			t.Logf("Error %q at %v; delta=%v attempts=%d last=%v count=%d",
				tag, time.Now(), now.Sub(last), atomic.LoadInt64(&attempts), last, count)
			atomic.AddInt64(&errors, 1)
		}

		lasts.Lock()
		lasts.m[tag] = now
		lasts.Unlock()
	}

	expected := invocations * len(ids) * expectedPerInvocation

	start := time.Now()
	end := start.Add(testTime)
	for time.Now().Before(end) {
		att := atomic.AddInt64(&attempts, 1)
		if atomic.LoadInt64(&firings) >= int64(expected) {
			break
		}
		tag := ids[att%int64(len(ids))]
		// use separate calls so program counter is different for each
		if invocations > 0 {
			suppress.For(suppressTime, tag, f)
		}
		if invocations > 1 {
			suppress.For(suppressTime, tag, f)
		}
		if invocations > 2 {
			suppress.For(suppressTime, tag, f)
		}
		runtime.Gosched() // yield to other goroutines
	}

	// wait for flusher goroutines to finish
	finished := time.Now()
	time.Sleep(2 * suppressTime)
	finishedAndWaited := time.Now()

	elapsed := finished.Sub(start)
	longElapsed := finishedAndWaited.Sub(start)

	frng := atomic.LoadInt64(&firings)
	e := atomic.LoadInt64(&errors)
	t.Logf("Ran %d iterations in %v (%v with wait), fired correctly %d times (wanted %d) and %d incorrectly",
		attempts, elapsed, longElapsed, frng, expected, e)
	if frng != int64(expected) {
		t.Errorf("Expected %d firings, got %d", expected, frng)
	}
	if e > 0 {
		t.Errorf("Silencer failed to suppress %d times", e)
	}
}