mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-04-25 10:32:14 +00:00
test: add tests for DialRequest
This commit is contained in:
parent
3b06283ad8
commit
c7dcfe5e48
@ -14,7 +14,7 @@ class DialRequest {
|
||||
*
|
||||
* @param {object} options
|
||||
* @param {Multiaddr[]} options.addrs
|
||||
* @param {TransportManager} options.transportManager
|
||||
* @param {function(Multiaddr):Promise<Connection>} options.dialAction
|
||||
* @param {Dialer} options.dialer
|
||||
*/
|
||||
constructor ({
|
||||
@ -31,7 +31,6 @@ class DialRequest {
|
||||
* @async
|
||||
* @param {object} options
|
||||
* @param {AbortSignal} options.signal An AbortController signal
|
||||
* @param {number} options.timeout The max dial time for each request
|
||||
* @returns {Connection}
|
||||
*/
|
||||
async run (options) {
|
||||
|
180
test/dialing/dial-request.spec.js
Normal file
180
test/dialing/dial-request.spec.js
Normal file
@ -0,0 +1,180 @@
|
||||
'use strict'
|
||||
/* eslint-env mocha */
|
||||
|
||||
const chai = require('chai')
|
||||
chai.use(require('dirty-chai'))
|
||||
chai.use(require('chai-as-promised'))
|
||||
const { expect } = chai
|
||||
const sinon = require('sinon')
|
||||
|
||||
const { AbortError } = require('libp2p-interfaces/src/transport/errors')
|
||||
const AbortController = require('abort-controller')
|
||||
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')
|
||||
|
||||
describe('Dial Request', () => {
|
||||
it('should end when a single multiaddr dials succeeds', async () => {
|
||||
const mockConnection = await createMockConnection()
|
||||
const actions = {
|
||||
[1]: () => Promise.reject(),
|
||||
[2]: () => Promise.resolve(mockConnection),
|
||||
[3]: () => Promise.reject()
|
||||
}
|
||||
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 throw an AggregateError if all dials fail', async () => {
|
||||
const actions = {
|
||||
[1]: () => Promise.reject(),
|
||||
[2]: () => Promise.reject(),
|
||||
[3]: () => Promise.reject()
|
||||
}
|
||||
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 (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())
|
||||
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 (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 (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)
|
||||
})
|
||||
})
|
Loading…
x
Reference in New Issue
Block a user