mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-07-05 11:51:37 +00:00
The peer routing module starts a recurring process that searches for peers close to our peer id. This makes the DHT module query the network for peers. Thing is the DHT module is already doing this because periodically searching for peers close to us is in the DHT spec so this ends up making redundant queries. This PR removes the recurring task configured by the peer routing module.
225 lines
6.7 KiB
JavaScript
225 lines
6.7 KiB
JavaScript
'use strict'
|
|
/* eslint-env mocha */
|
|
|
|
const { expect } = require('aegir/utils/chai')
|
|
const sinon = require('sinon')
|
|
|
|
const { AbortError } = require('libp2p-interfaces/src/transport/errors')
|
|
const AggregateError = require('aggregate-error')
|
|
const pDefer = require('p-defer')
|
|
const delay = require('delay')
|
|
|
|
const DialRequest = require('../../src/dialer/dial-request')
|
|
const createMockConnection = require('../utils/mockConnection')
|
|
const error = new Error('dial failes')
|
|
|
|
describe('Dial Request', () => {
|
|
it('should end when a single multiaddr dials succeeds', async () => {
|
|
const mockConnection = await createMockConnection()
|
|
const actions = {
|
|
1: () => Promise.reject(error),
|
|
2: () => Promise.resolve(mockConnection),
|
|
3: () => Promise.reject(error)
|
|
}
|
|
const dialAction = (num) => actions[num]()
|
|
const tokens = ['a', 'b']
|
|
const controller = new AbortController()
|
|
const dialer = {
|
|
getTokens: () => [...tokens],
|
|
releaseToken: () => {}
|
|
}
|
|
|
|
const dialRequest = new DialRequest({
|
|
addrs: Object.keys(actions),
|
|
dialer,
|
|
dialAction
|
|
})
|
|
|
|
sinon.spy(actions, 1)
|
|
sinon.spy(actions, 2)
|
|
sinon.spy(actions, 3)
|
|
sinon.spy(dialer, 'releaseToken')
|
|
const result = await dialRequest.run({ signal: controller.signal })
|
|
expect(result).to.equal(mockConnection)
|
|
expect(actions[1]).to.have.property('callCount', 1)
|
|
expect(actions[2]).to.have.property('callCount', 1)
|
|
expect(actions[3]).to.have.property('callCount', 0)
|
|
expect(dialer.releaseToken).to.have.property('callCount', tokens.length)
|
|
})
|
|
|
|
it('should release tokens when all addr dials have started', async () => {
|
|
const mockConnection = await createMockConnection()
|
|
const firstDials = pDefer()
|
|
const deferred = pDefer()
|
|
const actions = {
|
|
1: () => firstDials.promise,
|
|
2: () => firstDials.promise,
|
|
3: () => deferred.promise
|
|
}
|
|
const dialAction = (num) => actions[num]()
|
|
const tokens = ['a', 'b']
|
|
const controller = new AbortController()
|
|
const dialer = {
|
|
getTokens: () => [...tokens],
|
|
releaseToken: () => {}
|
|
}
|
|
|
|
const dialRequest = new DialRequest({
|
|
addrs: Object.keys(actions),
|
|
dialer,
|
|
dialAction
|
|
})
|
|
|
|
sinon.spy(actions, 1)
|
|
sinon.spy(actions, 2)
|
|
sinon.spy(actions, 3)
|
|
sinon.spy(dialer, 'releaseToken')
|
|
dialRequest.run({ signal: controller.signal })
|
|
// Let the first dials run
|
|
await delay(0)
|
|
|
|
// Finish the first 2 dials
|
|
firstDials.reject(error)
|
|
await delay(0)
|
|
|
|
// Only 1 dial should remain, so 1 token should have been released
|
|
expect(actions[1]).to.have.property('callCount', 1)
|
|
expect(actions[2]).to.have.property('callCount', 1)
|
|
expect(actions[3]).to.have.property('callCount', 1)
|
|
expect(dialer.releaseToken).to.have.property('callCount', 1)
|
|
|
|
// Finish the dial and release the 2nd token
|
|
deferred.resolve(mockConnection)
|
|
await delay(0)
|
|
expect(dialer.releaseToken).to.have.property('callCount', 2)
|
|
})
|
|
|
|
it('should throw an AggregateError if all dials fail', async () => {
|
|
const actions = {
|
|
1: () => Promise.reject(error),
|
|
2: () => Promise.reject(error),
|
|
3: () => Promise.reject(error)
|
|
}
|
|
const dialAction = (num) => actions[num]()
|
|
const addrs = Object.keys(actions)
|
|
const tokens = ['a', 'b']
|
|
const controller = new AbortController()
|
|
const dialer = {
|
|
getTokens: () => [...tokens],
|
|
releaseToken: () => {}
|
|
}
|
|
|
|
const dialRequest = new DialRequest({
|
|
addrs,
|
|
dialer,
|
|
dialAction
|
|
})
|
|
|
|
sinon.spy(actions, 1)
|
|
sinon.spy(actions, 2)
|
|
sinon.spy(actions, 3)
|
|
sinon.spy(dialer, 'getTokens')
|
|
sinon.spy(dialer, 'releaseToken')
|
|
|
|
try {
|
|
await dialRequest.run({ signal: controller.signal })
|
|
expect.fail('Should have thrown')
|
|
} catch (/** @type {any} */ err) {
|
|
expect(err).to.be.an.instanceof(AggregateError)
|
|
}
|
|
|
|
expect(actions[1]).to.have.property('callCount', 1)
|
|
expect(actions[2]).to.have.property('callCount', 1)
|
|
expect(actions[3]).to.have.property('callCount', 1)
|
|
expect(dialer.getTokens.calledWith(addrs.length)).to.equal(true)
|
|
expect(dialer.releaseToken).to.have.property('callCount', tokens.length)
|
|
})
|
|
|
|
it('should handle a large number of addrs', async () => {
|
|
const reject = sinon.stub().callsFake(() => Promise.reject(error))
|
|
const actions = {}
|
|
const addrs = [...new Array(25)].map((_, index) => index + 1)
|
|
addrs.forEach(addr => {
|
|
actions[addr] = reject
|
|
})
|
|
|
|
const dialAction = (addr) => actions[addr]()
|
|
const tokens = ['a', 'b']
|
|
const controller = new AbortController()
|
|
const dialer = {
|
|
getTokens: () => [...tokens],
|
|
releaseToken: () => {}
|
|
}
|
|
|
|
const dialRequest = new DialRequest({
|
|
addrs,
|
|
dialer,
|
|
dialAction
|
|
})
|
|
|
|
sinon.spy(dialer, 'releaseToken')
|
|
try {
|
|
await dialRequest.run({ signal: controller.signal })
|
|
expect.fail('Should have thrown')
|
|
} catch (/** @type {any} */ err) {
|
|
expect(err).to.be.an.instanceof(AggregateError)
|
|
}
|
|
|
|
expect(reject).to.have.property('callCount', addrs.length)
|
|
expect(dialer.releaseToken).to.have.property('callCount', tokens.length)
|
|
})
|
|
|
|
it('should abort all dials when its signal is aborted', async () => {
|
|
const deferToAbort = ({ signal }) => {
|
|
if (signal.aborted) throw new Error('already aborted')
|
|
const deferred = pDefer()
|
|
const onAbort = () => {
|
|
deferred.reject(new AbortError())
|
|
signal.removeEventListener('abort', onAbort)
|
|
}
|
|
signal.addEventListener('abort', onAbort)
|
|
return deferred.promise
|
|
}
|
|
|
|
const actions = {
|
|
1: deferToAbort,
|
|
2: deferToAbort,
|
|
3: deferToAbort
|
|
}
|
|
const dialAction = (num, opts) => actions[num](opts)
|
|
const addrs = Object.keys(actions)
|
|
const tokens = ['a', 'b']
|
|
const controller = new AbortController()
|
|
const dialer = {
|
|
getTokens: () => [...tokens],
|
|
releaseToken: () => {}
|
|
}
|
|
|
|
const dialRequest = new DialRequest({
|
|
addrs,
|
|
dialer,
|
|
dialAction
|
|
})
|
|
|
|
sinon.spy(actions, 1)
|
|
sinon.spy(actions, 2)
|
|
sinon.spy(actions, 3)
|
|
sinon.spy(dialer, 'getTokens')
|
|
sinon.spy(dialer, 'releaseToken')
|
|
|
|
try {
|
|
setTimeout(() => controller.abort(), 100)
|
|
await dialRequest.run({ signal: controller.signal })
|
|
expect.fail('dial should have failed')
|
|
} catch (/** @type {any} */ err) {
|
|
expect(err).to.be.an.instanceof(AggregateError)
|
|
}
|
|
|
|
expect(actions[1]).to.have.property('callCount', 1)
|
|
expect(actions[2]).to.have.property('callCount', 1)
|
|
expect(actions[3]).to.have.property('callCount', 1)
|
|
expect(dialer.getTokens.calledWith(addrs.length)).to.equal(true)
|
|
expect(dialer.releaseToken).to.have.property('callCount', tokens.length)
|
|
})
|
|
})
|