github.com/ethersphere/bee/v2@v2.2.0/pkg/p2p/libp2p/internal/reacher/reacher_test.go (about) 1 // Copyright 2021 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package reacher_test 6 7 import ( 8 "context" 9 "errors" 10 "testing" 11 "time" 12 13 "github.com/ethersphere/bee/v2/pkg/p2p" 14 "github.com/ethersphere/bee/v2/pkg/p2p/libp2p/internal/reacher" 15 "github.com/ethersphere/bee/v2/pkg/swarm" 16 "github.com/ethersphere/bee/v2/pkg/util/testutil" 17 ma "github.com/multiformats/go-multiaddr" 18 "go.uber.org/atomic" 19 ) 20 21 var defaultOptions = reacher.Options{ 22 PingTimeout: time.Second * 5, 23 Workers: 8, 24 RetryAfterDuration: time.Second, 25 } 26 27 func TestPingSuccess(t *testing.T) { 28 t.Parallel() 29 30 for _, tc := range []struct { 31 name string 32 pingFunc func(context.Context, ma.Multiaddr) (time.Duration, error) 33 reachableFunc func(chan struct{}) func(addr swarm.Address, got p2p.ReachabilityStatus) 34 }{ 35 { 36 name: "ping success", 37 pingFunc: func(context.Context, ma.Multiaddr) (time.Duration, error) { 38 return 0, nil 39 }, 40 reachableFunc: func(done chan struct{}) func(addr swarm.Address, got p2p.ReachabilityStatus) { 41 return func(addr swarm.Address, got p2p.ReachabilityStatus) { 42 if got != p2p.ReachabilityStatusPublic { 43 t.Fatalf("got %v, want %v", got, p2p.ReachabilityStatusPublic) 44 } 45 done <- struct{}{} 46 } 47 }, 48 }, 49 { 50 name: "ping failure", 51 pingFunc: func(context.Context, ma.Multiaddr) (time.Duration, error) { 52 return 0, errors.New("test error") 53 }, 54 reachableFunc: func(done chan struct{}) func(addr swarm.Address, got p2p.ReachabilityStatus) { 55 return func(addr swarm.Address, got p2p.ReachabilityStatus) { 56 if got != p2p.ReachabilityStatusPrivate { 57 t.Fatalf("got %v, want %v", got, p2p.ReachabilityStatusPrivate) 58 } 59 done <- struct{}{} 60 } 61 }, 62 }, 63 } { 64 tc := tc 65 t.Run(tc.name, func(t *testing.T) { 66 t.Parallel() 67 68 done := make(chan struct{}) 69 mock := newMock(tc.pingFunc, tc.reachableFunc(done)) 70 71 r := reacher.New(mock, mock, &defaultOptions) 72 testutil.CleanupCloser(t, r) 73 74 overlay := swarm.RandAddress(t) 75 76 r.Connected(overlay, nil) 77 78 select { 79 case <-time.After(time.Second * 5): 80 t.Fatalf("test timed out") 81 case <-done: 82 } 83 }) 84 } 85 } 86 87 func TestDisconnected(t *testing.T) { 88 t.Parallel() 89 90 var ( 91 disconnectedOverlay = swarm.RandAddress(t) 92 disconnectedMa, _ = ma.NewMultiaddr("/ip4/127.0.0.1/tcp/7071/p2p/16Uiu2HAmTBuJT9LvNmBiQiNoTsxE5mtNy6YG3paw79m94CRa9sRb") 93 ) 94 95 /* 96 Because the Disconnected is called after Connected, it may be that one of the workers 97 have picked up the peer already. So to test that the Disconnected really works, 98 if the ping function pings the peer we are trying to disconnect, we return an error 99 which triggers another attempt in the future, which by the, the peer should already be removed. 100 */ 101 var errs atomic.Int64 102 pingFunc := func(_ context.Context, a ma.Multiaddr) (time.Duration, error) { 103 if a != nil && a.Equal(disconnectedMa) { 104 errs.Inc() 105 if errs.Load() > 1 { 106 t.Fatalf("overlay should be disconnected already") 107 } 108 return 0, errors.New("test error") 109 } 110 return 0, nil 111 } 112 113 reachableFunc := func(addr swarm.Address, b p2p.ReachabilityStatus) {} 114 115 mock := newMock(pingFunc, reachableFunc) 116 117 r := reacher.New(mock, mock, &defaultOptions) 118 testutil.CleanupCloser(t, r) 119 120 r.Connected(swarm.RandAddress(t), nil) 121 r.Connected(disconnectedOverlay, disconnectedMa) 122 r.Disconnected(disconnectedOverlay) 123 } 124 125 type mock struct { 126 pingFunc func(context.Context, ma.Multiaddr) (time.Duration, error) 127 reachableFunc func(swarm.Address, p2p.ReachabilityStatus) 128 } 129 130 func newMock(ping func(context.Context, ma.Multiaddr) (time.Duration, error), reach func(swarm.Address, p2p.ReachabilityStatus)) *mock { 131 return &mock{ 132 pingFunc: ping, 133 reachableFunc: reach, 134 } 135 } 136 137 func (m *mock) Ping(ctx context.Context, addr ma.Multiaddr) (time.Duration, error) { 138 return m.pingFunc(ctx, addr) 139 } 140 141 func (m *mock) Reachable(addr swarm.Address, status p2p.ReachabilityStatus) { 142 m.reachableFunc(addr, status) 143 }