@@ -5,14 +5,17 @@ import { multiaddr } from '@multiformats/multiaddr'
55import { expect } from 'aegir/chai'
66import { stubInterface } from 'sinon-ts'
77import { K } from '../src/constants.ts'
8+ import { MessageType } from '../src/message/dht.ts'
89import { PeerRouting } from '../src/peer-routing/index.ts'
9- import { convertBuffer } from '../src/utils.ts'
10+ import { peerResponseEvent , queryErrorEvent } from '../src/query/events.ts'
11+ import { convertBuffer , convertPeerId } from '../src/utils.ts'
1012import { createPeerIdsWithPrivateKey } from './utils/create-peer-id.ts'
1113import { sortClosestPeers } from './utils/sort-closest-peers.ts'
1214import type { PeerAndKey } from './utils/create-peer-id.ts'
13- import type { Validators } from '../src/index.ts'
15+ import type { QueryEvent , Validators } from '../src/index.ts'
1416import type { Network } from '../src/network.ts'
1517import type { QueryManager } from '../src/query/manager.ts'
18+ import type { QueryFunc } from '../src/query/types.ts'
1619import type { RoutingTable } from '../src/routing-table/index.ts'
1720import type { Peer , ComponentLogger , PeerId , PeerStore } from '@libp2p/interface'
1821import type { ConnectionManager } from '@libp2p/interface-internal'
@@ -135,6 +138,50 @@ describe('peer-routing', () => {
135138 expect ( closer [ 1 ] . id ) . to . equal ( serverPeer . id )
136139 } )
137140 } )
141+
142+ describe ( 'getClosestPeers' , ( ) => {
143+ it ( 'only adds peers to the closest set if they responded to the query' , async ( ) => {
144+ const key = Uint8Array . from ( [ 0 , 1 , 2 , 3 , 4 ] )
145+ const [ livePeer , deadPeer ] = await getSortedPeers ( key , 2 )
146+ const path = { index : 0 , queued : 0 , running : 0 , total : 1 }
147+
148+ // the QueryManager is stubbed, so drive the query function ourselves for
149+ // both peers and re-yield whatever the network produces for each
150+ const run = async function * ( _key : Uint8Array , query : QueryFunc ) : AsyncGenerator < QueryEvent > {
151+ for ( const { peerId } of [ livePeer , deadPeer ] ) {
152+ yield * query ( {
153+ key,
154+ peer : { id : peerId , multiaddrs : [ ] } ,
155+ peerKadId : await convertPeerId ( peerId ) ,
156+ path,
157+ numPaths : 1
158+ } )
159+ }
160+ }
161+ init . queryManager . run . callsFake ( run )
162+
163+ // the live peer answers; the dead peer only errors, never sending a
164+ // PEER_RESPONSE
165+ const sendRequest = async function * ( to : PeerId ) : AsyncGenerator < QueryEvent > {
166+ if ( to . equals ( livePeer . peerId ) ) {
167+ yield peerResponseEvent ( { from : to , messageType : MessageType . FIND_NODE , path } )
168+ } else {
169+ yield queryErrorEvent ( { from : to , error : new Error ( 'could not dial peer' ) , path } )
170+ }
171+ }
172+ init . network . sendRequest . callsFake ( sendRequest )
173+
174+ const finalPeerIds : PeerId [ ] = [ ]
175+ for await ( const event of peerRouting . getClosestPeers ( key ) ) {
176+ if ( event . name === 'FINAL_PEER' ) {
177+ finalPeerIds . push ( event . peer . id )
178+ }
179+ }
180+
181+ expect ( finalPeerIds ) . to . have . lengthOf ( 1 )
182+ expect ( finalPeerIds [ 0 ] . equals ( livePeer . peerId ) ) . to . be . true ( )
183+ } )
184+ } )
138185} )
139186
140187async function getSortedPeers ( key : Uint8Array , count = 3 ) : Promise < PeerAndKey [ ] > {
0 commit comments