github.com/ethereum-optimism/optimism@v1.7.2/op-node/p2p/monitor/peer_monitor_test.go (about) 1 package monitor 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "testing" 8 "time" 9 10 "github.com/ethereum-optimism/optimism/op-node/p2p/monitor/mocks" 11 clock2 "github.com/ethereum-optimism/optimism/op-service/clock" 12 "github.com/ethereum-optimism/optimism/op-service/testlog" 13 "github.com/ethereum/go-ethereum/log" 14 "github.com/libp2p/go-libp2p/core/peer" 15 "github.com/stretchr/testify/require" 16 ) 17 18 const testBanDuration = 2 * time.Hour 19 20 func peerMonitorSetup(t *testing.T) (*PeerMonitor, *clock2.DeterministicClock, *mocks.PeerManager) { 21 l := testlog.Logger(t, log.LevelInfo) 22 clock := clock2.NewDeterministicClock(time.UnixMilli(10000)) 23 manager := mocks.NewPeerManager(t) 24 monitor := NewPeerMonitor(context.Background(), l, clock, manager, -100, testBanDuration) 25 return monitor, clock, manager 26 } 27 28 func TestPeriodicallyCheckNextPeer(t *testing.T) { 29 monitor, clock, _ := peerMonitorSetup(t) 30 // Each time a step is performed, it calls Done on the wait group so we can wait for it to be performed 31 stepCh := make(chan struct{}, 10) 32 monitor.bgTasks.Add(1) 33 var actionErr error 34 go monitor.background(func() error { 35 stepCh <- struct{}{} 36 return actionErr 37 }) 38 defer monitor.Stop() 39 // Wait for the step ticker to be started 40 clock.WaitForNewPendingTaskWithTimeout(30 * time.Second) 41 42 // Should perform another step after each interval 43 for i := 0; i < 5; i++ { 44 clock.AdvanceTime(checkInterval) 45 waitForChan(t, stepCh, fmt.Sprintf("Did not perform step %v", i)) 46 require.Len(t, stepCh, 0) 47 } 48 49 // Should continue executing periodically even after an error 50 actionErr = errors.New("boom") 51 for i := 0; i < 5; i++ { 52 clock.AdvanceTime(checkInterval) 53 waitForChan(t, stepCh, fmt.Sprintf("Did not perform step %v", i)) 54 require.Len(t, stepCh, 0) 55 } 56 } 57 58 func TestCheckNextPeer(t *testing.T) { 59 peerIDs := []peer.ID{ 60 peer.ID("a"), 61 peer.ID("b"), 62 peer.ID("c"), 63 } 64 65 t.Run("No peers", func(t *testing.T) { 66 monitor, _, manager := peerMonitorSetup(t) 67 manager.EXPECT().Peers().Return(nil).Once() 68 require.NoError(t, monitor.checkNextPeer()) 69 }) 70 71 t.Run("Check each peer then refresh list", func(t *testing.T) { 72 monitor, _, manager := peerMonitorSetup(t) 73 manager.EXPECT().Peers().Return(peerIDs).Once() 74 for _, id := range peerIDs { 75 manager.EXPECT().GetPeerScore(id).Return(1, nil).Once() 76 77 require.NoError(t, monitor.checkNextPeer()) 78 } 79 80 updatedPeers := []peer.ID{ 81 peer.ID("x"), 82 peer.ID("y"), 83 peer.ID("z"), 84 peer.ID("a"), 85 } 86 manager.EXPECT().Peers().Return(updatedPeers).Once() 87 for _, id := range updatedPeers { 88 manager.EXPECT().GetPeerScore(id).Return(1, nil).Once() 89 90 require.NoError(t, monitor.checkNextPeer()) 91 } 92 }) 93 94 t.Run("Close and ban peer when below min score", func(t *testing.T) { 95 monitor, clock, manager := peerMonitorSetup(t) 96 id := peerIDs[0] 97 manager.EXPECT().Peers().Return(peerIDs).Once() 98 manager.EXPECT().GetPeerScore(id).Return(-101, nil).Once() 99 manager.EXPECT().IsStatic(id).Return(false).Once() 100 manager.EXPECT().BanPeer(id, clock.Now().Add(testBanDuration)).Return(nil).Once() 101 102 require.NoError(t, monitor.checkNextPeer()) 103 }) 104 105 t.Run("Do not close protected peer when below min score", func(t *testing.T) { 106 monitor, _, manager := peerMonitorSetup(t) 107 id := peerIDs[0] 108 manager.EXPECT().Peers().Return(peerIDs).Once() 109 manager.EXPECT().GetPeerScore(id).Return(-101, nil).Once() 110 manager.EXPECT().IsStatic(id).Return(true) 111 112 require.NoError(t, monitor.checkNextPeer()) 113 }) 114 } 115 116 func waitForChan(t *testing.T, ch chan struct{}, msg string) { 117 ctx, cancelFn := context.WithTimeout(context.Background(), 30*time.Second) 118 defer cancelFn() 119 select { 120 case <-ctx.Done(): 121 t.Fatal(msg) 122 case <-ch: 123 // Ok 124 } 125 }