From 22be1b5adfec8daeaf2eee49d4e04df8b016c7f7 Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Mon, 20 Mar 2023 21:06:53 -0700 Subject: [PATCH] Move mockclock to separate file --- p2p/host/autorelay/autorelay_test.go | 147 +++------------------------ p2p/host/autorelay/relay_finder.go | 4 - 2 files changed, 16 insertions(+), 135 deletions(-) diff --git a/p2p/host/autorelay/autorelay_test.go b/p2p/host/autorelay/autorelay_test.go index 65da8a16bf..d51fb16836 100644 --- a/p2p/host/autorelay/autorelay_test.go +++ b/p2p/host/autorelay/autorelay_test.go @@ -3,9 +3,7 @@ package autorelay_test import ( "context" "fmt" - "sort" "strings" - "sync" "sync/atomic" "testing" "time" @@ -14,6 +12,7 @@ import ( "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/test" "github.com/libp2p/go-libp2p/p2p/host/autorelay" circuitv2_proto "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/proto" @@ -184,7 +183,7 @@ func TestWaitForCandidates(t *testing.T) { func TestBackoff(t *testing.T) { const backoff = 20 * time.Second - cl := newMockClock() + cl := test.NewMockClock() r, err := libp2p.New( libp2p.DisableRelay(), libp2p.ForceReachabilityPublic(), @@ -230,10 +229,10 @@ func TestBackoff(t *testing.T) { }, 10*time.Second, 20*time.Millisecond, "reservations load should be 1 was %d", reservations.Load()) // make sure we don't add any relays yet for i := 0; i < 2; i++ { - cl.advanceBy(backoff / 3) + cl.AdvanceBy(backoff / 3) require.Equal(t, 1, int(reservations.Load())) } - cl.advanceBy(backoff) + cl.AdvanceBy(backoff) require.Eventually(t, func() bool { return reservations.Load() == 2 }, 10*time.Second, 100*time.Millisecond, "reservations load should be 2 was %d", reservations.Load()) @@ -296,122 +295,8 @@ func TestConnectOnDisconnect(t *testing.T) { require.NotEqualf(t, oldRelay, relaysInUse[0], "old relay should not be used again") } -type mockClock struct { - mu sync.Mutex - now time.Time - timers []*mockInstantTimer -} - -var _ autorelay.ClockWithInstantTimer = &mockClock{} - -type mockInstantTimer struct { - c *mockClock - mu sync.Mutex - when time.Time - active bool - ch chan time.Time -} - -// Ch implements autorelay.InstantTimer -func (t *mockInstantTimer) Ch() <-chan time.Time { - return t.ch -} - -// Reset implements autorelay.InstantTimer -func (t *mockInstantTimer) Reset(d time.Time) bool { - t.mu.Lock() - defer t.mu.Unlock() - wasActive := t.active - t.active = true - t.when = d - - // Schedule any timers that need to run. This will run this timer if t.when is before c.now - go t.c.advanceBy(0) - - return wasActive -} - -// Stop implements autorelay.InstantTimer -func (t *mockInstantTimer) Stop() bool { - t.mu.Lock() - defer t.mu.Unlock() - wasActive := t.active - t.active = false - return wasActive -} - -var _ autorelay.InstantTimer = &mockInstantTimer{} - -func newMockClock() *mockClock { - return &mockClock{now: time.Unix(0, 0)} -} - -// InstantTimer implements autorelay.ClockWithInstantTimer -func (c *mockClock) InstantTimer(when time.Time) autorelay.InstantTimer { - c.mu.Lock() - defer c.mu.Unlock() - t := &mockInstantTimer{ - c: c, - when: when, - ch: make(chan time.Time, 1), - active: true, - } - c.timers = append(c.timers, t) - return t -} - -// Since implements autorelay.ClockWithInstantTimer -func (c *mockClock) Since(t time.Time) time.Duration { - c.mu.Lock() - defer c.mu.Unlock() - return c.now.Sub(t) -} - -func (c *mockClock) Now() time.Time { - c.mu.Lock() - defer c.mu.Unlock() - return c.now -} - -func (c *mockClock) advanceBy(dur time.Duration) { - c.mu.Lock() - defer c.mu.Unlock() - endTime := c.now.Add(dur) - - // sort timers by when - if len(c.timers) > 1 { - sort.Slice(c.timers, func(i, j int) bool { - return c.timers[i].when.Before(c.timers[j].when) - }) - } - - for _, t := range c.timers { - t.mu.Lock() - if !t.active { - t.mu.Unlock() - continue - } - if !t.when.After(c.now) { - t.active = false - t.mu.Unlock() - // This may block if the channel is full, but that's intended. This way our mock clock never gets too far ahead of consumer. - // This also prevents us from dropping times because we're advancing too fast. - t.ch <- c.now - } else if !t.when.After(endTime) { - c.now = t.when - t.active = false - t.mu.Unlock() - // This may block if the channel is full, but that's intended. See comment above - t.ch <- c.now - } else { - t.mu.Unlock() - } - } - c.now = endTime -} - func TestMaxAge(t *testing.T) { - cl := newMockClock() + cl := test.NewMockClock() const num = 4 peerChan1 := make(chan peer.AddrInfo, num) @@ -456,16 +341,16 @@ func TestMaxAge(t *testing.T) { relays := usedRelays(h) require.Len(t, relays, 1) - cl.advanceBy(time.Minute) + cl.AdvanceBy(time.Minute) require.Eventually(t, func() bool { return len(peerChans) == 0 }, 10*time.Second, 100*time.Millisecond) - cl.advanceBy(10 * time.Minute) + cl.AdvanceBy(10 * time.Minute) for _, r := range relays2 { peerChan2 <- peer.AddrInfo{ID: r.ID(), Addrs: r.Addrs()} } - cl.advanceBy(11 * time.Minute) + cl.AdvanceBy(11 * time.Minute) require.Eventually(t, func() bool { relays = usedRelays(h) @@ -510,7 +395,7 @@ func TestMaxAge(t *testing.T) { } func TestReconnectToStaticRelays(t *testing.T) { - cl := newMockClock() + cl := test.NewMockClock() var staticRelays []peer.AddrInfo const numStaticRelays = 1 relays := make([]host.Host, 0, numStaticRelays) @@ -528,7 +413,7 @@ func TestReconnectToStaticRelays(t *testing.T) { ) defer h.Close() - cl.advanceBy(time.Minute) + cl.AdvanceBy(time.Minute) require.Eventually(t, func() bool { return numRelays(h) == 1 }, 10*time.Second, 100*time.Millisecond) @@ -544,14 +429,14 @@ func TestReconnectToStaticRelays(t *testing.T) { return numRelays(h) == 0 }, 10*time.Second, 100*time.Millisecond) - cl.advanceBy(time.Hour) + cl.AdvanceBy(time.Hour) require.Eventually(t, func() bool { return numRelays(h) == 1 }, 10*time.Second, 100*time.Millisecond) } func TestMinInterval(t *testing.T) { - cl := newMockClock() + cl := test.NewMockClock() h := newPrivateNode(t, func(context.Context, int) <-chan peer.AddrInfo { peerChan := make(chan peer.AddrInfo, 1) @@ -569,16 +454,16 @@ func TestMinInterval(t *testing.T) { ) defer h.Close() - cl.advanceBy(400 * time.Millisecond) + cl.AdvanceBy(400 * time.Millisecond) // The second call to peerSource should happen after 1 second require.Never(t, func() bool { return numRelays(h) > 0 }, 500*time.Millisecond, 100*time.Millisecond) - cl.advanceBy(600 * time.Millisecond) + cl.AdvanceBy(600 * time.Millisecond) require.Eventually(t, func() bool { return numRelays(h) > 0 }, 3*time.Second, 100*time.Millisecond) } func TestNoBusyLoop0MinInterval(t *testing.T) { var calledTimes uint64 - cl := newMockClock() + cl := test.NewMockClock() h := newPrivateNode(t, func(context.Context, int) <-chan peer.AddrInfo { atomic.AddUint64(&calledTimes, 1) @@ -599,7 +484,7 @@ func TestNoBusyLoop0MinInterval(t *testing.T) { defer h.Close() require.Never(t, func() bool { - cl.advanceBy(time.Second) + cl.AdvanceBy(time.Second) val := atomic.LoadUint64(&calledTimes) return val >= 2 }, 500*time.Millisecond, 100*time.Millisecond) diff --git a/p2p/host/autorelay/relay_finder.go b/p2p/host/autorelay/relay_finder.go index c0c4766093..53be76971d 100644 --- a/p2p/host/autorelay/relay_finder.go +++ b/p2p/host/autorelay/relay_finder.go @@ -148,10 +148,6 @@ func (rf *relayFinder) background(ctx context.Context) { if rsvpRefreshInterval > leastFrequentInterval || leastFrequentInterval == 0 { leastFrequentInterval = rsvpRefreshInterval } - if leastFrequentInterval == 0 { - // fallback to avoid busy looping in case the config is set to all 0s - leastFrequentInterval = time.Hour - } scheduledWork := &scheduledWorkTimes{ leastFrequentInterval: leastFrequentInterval,