github.com/ethersphere/bee/v2@v2.2.0/pkg/topology/mock/mock.go (about) 1 // Copyright 2020 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 mock 6 7 import ( 8 "context" 9 "maps" 10 "sync" 11 "time" 12 13 "github.com/ethersphere/bee/v2/pkg/p2p" 14 "github.com/ethersphere/bee/v2/pkg/swarm" 15 "github.com/ethersphere/bee/v2/pkg/topology" 16 ) 17 18 type mock struct { 19 peers []swarm.Address 20 depth uint8 21 closestPeer swarm.Address 22 closestPeerErr error 23 peersErr error 24 addPeersErr error 25 isWithinFunc func(c swarm.Address) bool 26 marshalJSONFunc func() ([]byte, error) 27 mtx sync.Mutex 28 health map[string]bool 29 } 30 31 var _ topology.Driver = (*mock)(nil) 32 33 func WithPeers(peers ...swarm.Address) Option { 34 return optionFunc(func(d *mock) { 35 d.peers = peers 36 }) 37 } 38 39 func WithAddPeersErr(err error) Option { 40 return optionFunc(func(d *mock) { 41 d.addPeersErr = err 42 }) 43 } 44 45 func WithNeighborhoodDepth(dd uint8) Option { 46 return optionFunc(func(d *mock) { 47 d.depth = dd 48 }) 49 } 50 51 func WithClosestPeer(addr swarm.Address) Option { 52 return optionFunc(func(d *mock) { 53 d.closestPeer = addr 54 }) 55 } 56 57 func WithClosestPeerErr(err error) Option { 58 return optionFunc(func(d *mock) { 59 d.closestPeerErr = err 60 }) 61 } 62 63 func WithMarshalJSONFunc(f func() ([]byte, error)) Option { 64 return optionFunc(func(d *mock) { 65 d.marshalJSONFunc = f 66 }) 67 } 68 69 func WithIsWithinFunc(f func(swarm.Address) bool) Option { 70 return optionFunc(func(d *mock) { 71 d.isWithinFunc = f 72 }) 73 } 74 75 func NewTopologyDriver(opts ...Option) *mock { 76 d := new(mock) 77 for _, o := range opts { 78 o.apply(d) 79 } 80 81 d.health = map[string]bool{} 82 83 return d 84 } 85 86 func (d *mock) AddPeers(addrs ...swarm.Address) { 87 d.mtx.Lock() 88 defer d.mtx.Unlock() 89 90 d.peers = append(d.peers, addrs...) 91 } 92 93 func (d *mock) Connected(ctx context.Context, peer p2p.Peer, _ bool) error { 94 d.AddPeers(peer.Address) 95 return nil 96 } 97 98 func (d *mock) Disconnected(peer p2p.Peer) { 99 d.mtx.Lock() 100 defer d.mtx.Unlock() 101 102 d.peers = swarm.RemoveAddress(d.peers, peer.Address) 103 } 104 105 func (d *mock) Announce(_ context.Context, _ swarm.Address, _ bool) error { 106 return nil 107 } 108 109 func (d *mock) AnnounceTo(_ context.Context, _, _ swarm.Address, _ bool) error { 110 return nil 111 } 112 113 func (d *mock) UpdatePeerHealth(peer swarm.Address, health bool, pingDur time.Duration) { 114 d.mtx.Lock() 115 defer d.mtx.Unlock() 116 d.health[peer.ByteString()] = health 117 } 118 119 func (d *mock) PeersHealth() map[string]bool { 120 d.mtx.Lock() 121 defer d.mtx.Unlock() 122 return maps.Clone(d.health) 123 } 124 125 func (d *mock) Peers() []swarm.Address { 126 return d.peers 127 } 128 129 func (d *mock) ClosestPeer(addr swarm.Address, wantSelf bool, _ topology.Select, skipPeers ...swarm.Address) (peerAddr swarm.Address, err error) { 130 if len(skipPeers) == 0 { 131 if d.closestPeerErr != nil { 132 return d.closestPeer, d.closestPeerErr 133 } 134 if !d.closestPeer.Equal(swarm.ZeroAddress) { 135 return d.closestPeer, nil 136 } 137 } 138 139 d.mtx.Lock() 140 defer d.mtx.Unlock() 141 142 if len(d.peers) == 0 { 143 return peerAddr, topology.ErrNotFound 144 } 145 146 skipPeer := false 147 for _, p := range d.peers { 148 for _, a := range skipPeers { 149 if a.Equal(p) { 150 skipPeer = true 151 break 152 } 153 } 154 if skipPeer { 155 skipPeer = false 156 continue 157 } 158 159 if peerAddr.IsZero() { 160 peerAddr = p 161 } 162 163 if closer, _ := p.Closer(addr, peerAddr); closer { 164 peerAddr = p 165 } 166 } 167 168 if peerAddr.IsZero() { 169 if wantSelf { 170 return peerAddr, topology.ErrWantSelf 171 } else { 172 return peerAddr, topology.ErrNotFound 173 } 174 } 175 176 return peerAddr, nil 177 } 178 179 func (m *mock) IsReachable() bool { 180 return true 181 } 182 183 func (d *mock) SubscribeTopologyChange() (c <-chan struct{}, unsubscribe func()) { 184 return c, unsubscribe 185 } 186 187 func (m *mock) NeighborhoodDepth() uint8 { 188 return m.depth 189 } 190 191 func (m *mock) SetStorageRadius(uint8) {} 192 193 // EachConnectedPeer implements topology.PeerIterator interface. 194 func (d *mock) EachConnectedPeer(f topology.EachPeerFunc, _ topology.Select) (err error) { 195 d.mtx.Lock() 196 defer d.mtx.Unlock() 197 198 if d.peersErr != nil { 199 return d.peersErr 200 } 201 202 for i, p := range d.peers { 203 _, _, err = f(p, uint8(i)) 204 if err != nil { 205 return 206 } 207 } 208 209 return nil 210 } 211 212 // EachConnectedPeerRev implements topology.PeerIterator interface. 213 func (d *mock) EachConnectedPeerRev(f topology.EachPeerFunc, _ topology.Select) (err error) { 214 d.mtx.Lock() 215 defer d.mtx.Unlock() 216 217 for i := len(d.peers) - 1; i >= 0; i-- { 218 _, _, err = f(d.peers[i], uint8(i)) 219 if err != nil { 220 return 221 } 222 } 223 224 return nil 225 } 226 227 func (d *mock) Snapshot() *topology.KadParams { 228 return new(topology.KadParams) 229 } 230 231 func (d *mock) Halt() {} 232 func (d *mock) Close() error { return nil } 233 234 type Option interface { 235 apply(*mock) 236 } 237 238 type optionFunc func(*mock) 239 240 func (f optionFunc) apply(r *mock) { f(r) }