From d1dcb0e330398cfadd4cec9ee1962432c7b1e368 Mon Sep 17 00:00:00 2001 From: Sukun Date: Thu, 15 Jun 2023 14:55:55 +0530 Subject: [PATCH] test: document why InstantTimer is required (#2351) originally explained by @marcopolo here: https://github.com/libp2p/go-libp2p/pull/2260#discussion_r1201284744 --- core/test/mockclock.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/test/mockclock.go b/core/test/mockclock.go index 1ed7250332..4916465586 100644 --- a/core/test/mockclock.go +++ b/core/test/mockclock.go @@ -50,6 +50,14 @@ func NewMockClock() *MockClock { return &MockClock{now: time.Unix(0, 0), advanceBySem: make(chan struct{}, 1)} } +// InstantTimer implements a timer that triggers at a fixed instant in time as opposed to after a +// fixed duration from the moment of creation/reset. +// +// In test environments, when using a Timer which fires after a duration, there is a race between +// the goroutine moving time forward using `clock.Advanceby` and the goroutine resetting the +// timer by doing `timer.Reset(desiredInstant.Sub(time.Now()))`. The value of +// `desiredInstance.sub(time.Now())` is different depending on whether `clock.AdvanceBy` finishes +// before or after the timer reset. func (c *MockClock) InstantTimer(when time.Time) *mockInstantTimer { c.mu.Lock() defer c.mu.Unlock()