mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-06-28 00:11:34 +00:00
feat: address and proto books (#590)
* feat: address and proto books * chore: apply suggestions from code review Co-Authored-By: Jacob Heun <jacobheun@gmail.com> * chore: minor fixes and initial tests added * chore: integrate new peer-store with code using adapters for other modules * chore: do not use peerstore.put on get-peer-info * chore: apply suggestions from code review Co-Authored-By: Jacob Heun <jacobheun@gmail.com> * chore: add new peer store tests * chore: apply suggestions from code review Co-Authored-By: Jacob Heun <jacobheun@gmail.com> Co-authored-by: Jacob Heun <jacobheun@gmail.com>
This commit is contained in:
@ -44,7 +44,8 @@ describe('DHT subsystem operates correctly', () => {
|
||||
remoteLibp2p.start()
|
||||
])
|
||||
|
||||
remAddr = libp2p.peerStore.multiaddrsForPeer(remotePeerInfo)[0]
|
||||
libp2p.peerStore.addressBook.set(remotePeerInfo.id, [remoteListenAddr])
|
||||
remAddr = libp2p.peerStore.addressBook.getMultiaddrsForPeer(remotePeerInfo.id)[0]
|
||||
})
|
||||
|
||||
afterEach(() => Promise.all([
|
||||
@ -68,7 +69,6 @@ describe('DHT subsystem operates correctly', () => {
|
||||
const value = Buffer.from('world')
|
||||
|
||||
await libp2p.dialProtocol(remAddr, subsystemMulticodecs)
|
||||
|
||||
await Promise.all([
|
||||
pWaitFor(() => libp2p._dht.routingTable.size === 1),
|
||||
pWaitFor(() => remoteLibp2p._dht.routingTable.size === 1)
|
||||
@ -99,7 +99,8 @@ describe('DHT subsystem operates correctly', () => {
|
||||
await libp2p.start()
|
||||
await remoteLibp2p.start()
|
||||
|
||||
remAddr = libp2p.peerStore.multiaddrsForPeer(remotePeerInfo)[0]
|
||||
libp2p.peerStore.addressBook.set(remotePeerInfo.id, [remoteListenAddr])
|
||||
remAddr = libp2p.peerStore.addressBook.getMultiaddrsForPeer(remotePeerInfo.id)[0]
|
||||
})
|
||||
|
||||
afterEach(() => Promise.all([
|
||||
|
@ -100,7 +100,10 @@ describe('Dialing (direct, TCP)', () => {
|
||||
const dialer = new Dialer({
|
||||
transportManager: localTM,
|
||||
peerStore: {
|
||||
multiaddrsForPeer: () => [remoteAddr]
|
||||
addressBook: {
|
||||
add: () => {},
|
||||
getMultiaddrsForPeer: () => [remoteAddr]
|
||||
}
|
||||
}
|
||||
})
|
||||
const peerId = await PeerId.createFromJSON(Peers[0])
|
||||
@ -121,7 +124,7 @@ describe('Dialing (direct, TCP)', () => {
|
||||
const peerId = await PeerId.createFromJSON(Peers[0])
|
||||
const peerInfo = new PeerInfo(peerId)
|
||||
peerInfo.multiaddrs.add(remoteAddr)
|
||||
peerStore.put(peerInfo)
|
||||
peerStore.addressBook.set(peerInfo.id, peerInfo.multiaddrs.toArray())
|
||||
|
||||
const connection = await dialer.connectToPeer(peerInfo)
|
||||
expect(connection).to.exist()
|
||||
@ -132,7 +135,10 @@ describe('Dialing (direct, TCP)', () => {
|
||||
const dialer = new Dialer({
|
||||
transportManager: localTM,
|
||||
peerStore: {
|
||||
multiaddrsForPeer: () => [unsupportedAddr]
|
||||
addressBook: {
|
||||
add: () => {},
|
||||
getMultiaddrsForPeer: () => [unsupportedAddr]
|
||||
}
|
||||
}
|
||||
})
|
||||
const peerId = await PeerId.createFromJSON(Peers[0])
|
||||
@ -173,7 +179,10 @@ describe('Dialing (direct, TCP)', () => {
|
||||
transportManager: localTM,
|
||||
concurrency: 2,
|
||||
peerStore: {
|
||||
multiaddrsForPeer: () => addrs
|
||||
addressBook: {
|
||||
add: () => {},
|
||||
getMultiaddrsForPeer: () => addrs
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -87,7 +87,10 @@ describe('Dialing (direct, WebSockets)', () => {
|
||||
const dialer = new Dialer({
|
||||
transportManager: localTM,
|
||||
peerStore: {
|
||||
multiaddrsForPeer: () => [remoteAddr]
|
||||
addressBook: {
|
||||
add: () => {},
|
||||
getMultiaddrsForPeer: () => [remoteAddr]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -100,7 +103,10 @@ describe('Dialing (direct, WebSockets)', () => {
|
||||
const dialer = new Dialer({
|
||||
transportManager: localTM,
|
||||
peerStore: {
|
||||
multiaddrsForPeer: () => [remoteAddr]
|
||||
addressBook: {
|
||||
add: () => {},
|
||||
getMultiaddrsForPeer: () => [remoteAddr]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -121,7 +127,10 @@ describe('Dialing (direct, WebSockets)', () => {
|
||||
const dialer = new Dialer({
|
||||
transportManager: localTM,
|
||||
peerStore: {
|
||||
multiaddrsForPeer: () => [remoteAddr]
|
||||
addressBook: {
|
||||
add: () => {},
|
||||
getMultiaddrsForPeer: () => [remoteAddr]
|
||||
}
|
||||
}
|
||||
})
|
||||
const peerId = await PeerId.createFromJSON(Peers[0])
|
||||
@ -135,7 +144,10 @@ describe('Dialing (direct, WebSockets)', () => {
|
||||
const dialer = new Dialer({
|
||||
transportManager: localTM,
|
||||
peerStore: {
|
||||
multiaddrsForPeer: () => [unsupportedAddr]
|
||||
addressBook: {
|
||||
set: () => {},
|
||||
getMultiaddrsForPeer: () => [unsupportedAddr]
|
||||
}
|
||||
}
|
||||
})
|
||||
const peerId = await PeerId.createFromJSON(Peers[0])
|
||||
@ -150,7 +162,10 @@ describe('Dialing (direct, WebSockets)', () => {
|
||||
transportManager: localTM,
|
||||
timeout: 50,
|
||||
peerStore: {
|
||||
multiaddrsForPeer: () => [remoteAddr]
|
||||
addressBook: {
|
||||
add: () => {},
|
||||
getMultiaddrsForPeer: () => [remoteAddr]
|
||||
}
|
||||
}
|
||||
})
|
||||
sinon.stub(localTM, 'dial').callsFake(async (addr, options) => {
|
||||
@ -172,7 +187,10 @@ describe('Dialing (direct, WebSockets)', () => {
|
||||
transportManager: localTM,
|
||||
concurrency: 2,
|
||||
peerStore: {
|
||||
multiaddrsForPeer: () => [remoteAddr, remoteAddr, remoteAddr]
|
||||
addressBook: {
|
||||
set: () => {},
|
||||
getMultiaddrsForPeer: () => [remoteAddr, remoteAddr, remoteAddr]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -208,7 +226,10 @@ describe('Dialing (direct, WebSockets)', () => {
|
||||
transportManager: localTM,
|
||||
concurrency: 2,
|
||||
peerStore: {
|
||||
multiaddrsForPeer: () => [remoteAddr, remoteAddr, remoteAddr]
|
||||
addressBook: {
|
||||
set: () => {},
|
||||
getMultiaddrsForPeer: () => [remoteAddr, remoteAddr, remoteAddr]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -316,7 +337,7 @@ describe('Dialing (direct, WebSockets)', () => {
|
||||
})
|
||||
|
||||
sinon.spy(libp2p.dialer, 'connectToPeer')
|
||||
sinon.spy(libp2p.peerStore, 'put')
|
||||
sinon.spy(libp2p.peerStore.addressBook, 'add')
|
||||
|
||||
const connection = await libp2p.dial(remoteAddr)
|
||||
expect(connection).to.exist()
|
||||
@ -325,7 +346,7 @@ describe('Dialing (direct, WebSockets)', () => {
|
||||
expect(protocol).to.equal('/echo/1.0.0')
|
||||
await connection.close()
|
||||
expect(libp2p.dialer.connectToPeer.callCount).to.equal(1)
|
||||
expect(libp2p.peerStore.put.callCount).to.be.at.least(1)
|
||||
expect(libp2p.peerStore.addressBook.add.callCount).to.be.at.least(1)
|
||||
})
|
||||
|
||||
it('should run identify automatically after connecting', async () => {
|
||||
@ -339,19 +360,22 @@ describe('Dialing (direct, WebSockets)', () => {
|
||||
})
|
||||
|
||||
sinon.spy(libp2p.identifyService, 'identify')
|
||||
sinon.spy(libp2p.peerStore, 'replace')
|
||||
sinon.spy(libp2p.upgrader, 'onConnection')
|
||||
|
||||
const connection = await libp2p.dial(remoteAddr)
|
||||
expect(connection).to.exist()
|
||||
|
||||
sinon.spy(libp2p.peerStore.addressBook, 'set')
|
||||
sinon.spy(libp2p.peerStore.protoBook, 'set')
|
||||
|
||||
// Wait for onConnection to be called
|
||||
await pWaitFor(() => libp2p.upgrader.onConnection.callCount === 1)
|
||||
|
||||
expect(libp2p.identifyService.identify.callCount).to.equal(1)
|
||||
await libp2p.identifyService.identify.firstCall.returnValue
|
||||
|
||||
expect(libp2p.peerStore.replace.callCount).to.equal(1)
|
||||
expect(libp2p.peerStore.addressBook.set.callCount).to.equal(1)
|
||||
expect(libp2p.peerStore.protoBook.set.callCount).to.equal(1)
|
||||
})
|
||||
|
||||
it('should be able to use hangup to close connections', async () => {
|
||||
|
@ -12,6 +12,8 @@ const multiaddr = require('multiaddr')
|
||||
const { collect } = require('streaming-iterables')
|
||||
const pipe = require('it-pipe')
|
||||
const AggregateError = require('aggregate-error')
|
||||
const PeerId = require('peer-id')
|
||||
|
||||
const { createPeerInfo } = require('../utils/creators/peer')
|
||||
const baseOptions = require('../utils/base-options')
|
||||
const Libp2p = require('../../src')
|
||||
@ -52,8 +54,9 @@ describe('Dialing (via relay, TCP)', () => {
|
||||
return Promise.all([srcLibp2p, relayLibp2p, dstLibp2p].map(async libp2p => {
|
||||
await libp2p.stop()
|
||||
// Clear the peer stores
|
||||
for (const peerId of libp2p.peerStore.peers.keys()) {
|
||||
libp2p.peerStore.remove(peerId)
|
||||
for (const peerIdStr of libp2p.peerStore.peers.keys()) {
|
||||
const peerId = PeerId.createFromCID(peerIdStr)
|
||||
libp2p.peerStore.delete(peerId)
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
@ -48,7 +48,12 @@ describe('Identify', () => {
|
||||
protocols,
|
||||
registrar: {
|
||||
peerStore: {
|
||||
replace: () => {}
|
||||
addressBook: {
|
||||
set: () => { }
|
||||
},
|
||||
protoBook: {
|
||||
set: () => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -64,7 +69,8 @@ describe('Identify', () => {
|
||||
const [local, remote] = duplexPair()
|
||||
sinon.stub(localConnectionMock, 'newStream').returns({ stream: local, protocol: multicodecs.IDENTIFY })
|
||||
|
||||
sinon.spy(localIdentify.registrar.peerStore, 'replace')
|
||||
sinon.spy(localIdentify.registrar.peerStore.addressBook, 'set')
|
||||
sinon.spy(localIdentify.registrar.peerStore.protoBook, 'set')
|
||||
|
||||
// Run identify
|
||||
await Promise.all([
|
||||
@ -76,9 +82,10 @@ describe('Identify', () => {
|
||||
})
|
||||
])
|
||||
|
||||
expect(localIdentify.registrar.peerStore.replace.callCount).to.equal(1)
|
||||
expect(localIdentify.registrar.peerStore.addressBook.set.callCount).to.equal(1)
|
||||
expect(localIdentify.registrar.peerStore.protoBook.set.callCount).to.equal(1)
|
||||
// Validate the remote peer gets updated in the peer store
|
||||
const call = localIdentify.registrar.peerStore.replace.firstCall
|
||||
const call = localIdentify.registrar.peerStore.addressBook.set.firstCall
|
||||
expect(call.args[0].id.bytes).to.equal(remotePeer.id.bytes)
|
||||
})
|
||||
|
||||
@ -88,7 +95,12 @@ describe('Identify', () => {
|
||||
protocols,
|
||||
registrar: {
|
||||
peerStore: {
|
||||
replace: () => {}
|
||||
addressBook: {
|
||||
set: () => { }
|
||||
},
|
||||
protoBook: {
|
||||
set: () => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -134,7 +146,12 @@ describe('Identify', () => {
|
||||
peerInfo: remotePeer,
|
||||
registrar: {
|
||||
peerStore: {
|
||||
replace: () => {}
|
||||
addressBook: {
|
||||
set: () => {}
|
||||
},
|
||||
protoBook: {
|
||||
set: () => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -152,9 +169,8 @@ describe('Identify', () => {
|
||||
const [local, remote] = duplexPair()
|
||||
sinon.stub(localConnectionMock, 'newStream').returns({ stream: local, protocol: multicodecs.IDENTIFY_PUSH })
|
||||
|
||||
sinon.spy(IdentifyService, 'updatePeerAddresses')
|
||||
sinon.spy(IdentifyService, 'updatePeerProtocols')
|
||||
sinon.spy(remoteIdentify.registrar.peerStore, 'replace')
|
||||
sinon.spy(remoteIdentify.registrar.peerStore.addressBook, 'set')
|
||||
sinon.spy(remoteIdentify.registrar.peerStore.protoBook, 'set')
|
||||
|
||||
// Run identify
|
||||
await Promise.all([
|
||||
@ -166,14 +182,14 @@ describe('Identify', () => {
|
||||
})
|
||||
])
|
||||
|
||||
expect(IdentifyService.updatePeerAddresses.callCount).to.equal(1)
|
||||
expect(IdentifyService.updatePeerProtocols.callCount).to.equal(1)
|
||||
|
||||
expect(remoteIdentify.registrar.peerStore.replace.callCount).to.equal(1)
|
||||
const [peerInfo] = remoteIdentify.registrar.peerStore.replace.firstCall.args
|
||||
expect(peerInfo.id.bytes).to.eql(localPeer.id.bytes)
|
||||
expect(peerInfo.multiaddrs.toArray()).to.eql([listeningAddr])
|
||||
expect(peerInfo.protocols).to.eql(localProtocols)
|
||||
expect(remoteIdentify.registrar.peerStore.addressBook.set.callCount).to.equal(1)
|
||||
expect(remoteIdentify.registrar.peerStore.protoBook.set.callCount).to.equal(1)
|
||||
const [peerId, multiaddrs] = remoteIdentify.registrar.peerStore.addressBook.set.firstCall.args
|
||||
expect(peerId.bytes).to.eql(localPeer.id.bytes)
|
||||
expect(multiaddrs).to.eql([listeningAddr])
|
||||
const [peerId2, protocols] = remoteIdentify.registrar.peerStore.protoBook.set.firstCall.args
|
||||
expect(peerId2.bytes).to.eql(localPeer.id.bytes)
|
||||
expect(protocols).to.eql(Array.from(localProtocols))
|
||||
})
|
||||
})
|
||||
|
||||
@ -204,13 +220,15 @@ describe('Identify', () => {
|
||||
})
|
||||
|
||||
sinon.spy(libp2p.identifyService, 'identify')
|
||||
const peerStoreSpy = sinon.spy(libp2p.peerStore, 'replace')
|
||||
const peerStoreSpySet = sinon.spy(libp2p.peerStore.addressBook, 'set')
|
||||
const peerStoreSpyAdd = sinon.spy(libp2p.peerStore.addressBook, 'add')
|
||||
|
||||
const connection = await libp2p.dialer.connectToPeer(remoteAddr)
|
||||
expect(connection).to.exist()
|
||||
|
||||
// Wait for peer store to be updated
|
||||
await pWaitFor(() => peerStoreSpy.callCount === 1)
|
||||
// Dialer._createDialTarget (add), Identify (replace)
|
||||
await pWaitFor(() => peerStoreSpySet.callCount === 1 && peerStoreSpyAdd.callCount === 1)
|
||||
expect(libp2p.identifyService.identify.callCount).to.equal(1)
|
||||
|
||||
// The connection should have no open streams
|
||||
@ -226,7 +244,6 @@ describe('Identify', () => {
|
||||
|
||||
sinon.spy(libp2p.identifyService, 'identify')
|
||||
sinon.spy(libp2p.identifyService, 'push')
|
||||
sinon.spy(libp2p.peerStore, 'update')
|
||||
|
||||
const connection = await libp2p.dialer.connectToPeer(remoteAddr)
|
||||
expect(connection).to.exist()
|
||||
|
@ -35,7 +35,9 @@ describe('peer discovery', () => {
|
||||
...baseOptions,
|
||||
peerInfo
|
||||
})
|
||||
libp2p.peerStore.add(remotePeerInfo)
|
||||
libp2p.peerStore.addressBook.set(remotePeerInfo.id, remotePeerInfo.multiaddrs.toArray())
|
||||
libp2p.peerStore.protoBook.set(remotePeerInfo.id, Array.from(remotePeerInfo.protocols))
|
||||
|
||||
const deferred = defer()
|
||||
sinon.stub(libp2p.dialer, 'connectToPeer').callsFake((remotePeerInfo) => {
|
||||
expect(remotePeerInfo).to.equal(remotePeerInfo)
|
||||
@ -46,7 +48,9 @@ describe('peer discovery', () => {
|
||||
|
||||
libp2p.start()
|
||||
await deferred.promise
|
||||
expect(spy.getCall(0).args).to.eql([remotePeerInfo])
|
||||
|
||||
expect(spy.calledOnce).to.eql(true)
|
||||
expect(spy.getCall(0).args[0].id.toString()).to.eql(remotePeerInfo.id.toString())
|
||||
})
|
||||
|
||||
it('should stop discovery on libp2p start/stop', async () => {
|
||||
|
365
test/peer-store/address-book.spec.js
Normal file
365
test/peer-store/address-book.spec.js
Normal file
@ -0,0 +1,365 @@
|
||||
'use strict'
|
||||
/* eslint-env mocha */
|
||||
|
||||
const chai = require('chai')
|
||||
chai.use(require('dirty-chai'))
|
||||
const { expect } = chai
|
||||
|
||||
const { EventEmitter } = require('events')
|
||||
const pDefer = require('p-defer')
|
||||
const multiaddr = require('multiaddr')
|
||||
|
||||
const AddressBook = require('../../src/peer-store/address-book')
|
||||
|
||||
const peerUtils = require('../utils/creators/peer')
|
||||
const {
|
||||
ERR_INVALID_PARAMETERS
|
||||
} = require('../../src/errors')
|
||||
|
||||
const addr1 = multiaddr('/ip4/127.0.0.1/tcp/8000')
|
||||
const addr2 = multiaddr('/ip4/127.0.0.1/tcp/8001')
|
||||
const addr3 = multiaddr('/ip4/127.0.0.1/tcp/8002')
|
||||
|
||||
const arraysAreEqual = (a, b) => a.length === b.length && a.sort().every((item, index) => b[index] === item)
|
||||
|
||||
describe('addressBook', () => {
|
||||
let peerId
|
||||
|
||||
before(async () => {
|
||||
[peerId] = await peerUtils.createPeerId()
|
||||
})
|
||||
|
||||
describe('addressBook.set', () => {
|
||||
let ee, ab
|
||||
|
||||
beforeEach(() => {
|
||||
ee = new EventEmitter()
|
||||
ab = new AddressBook(ee)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
ee.removeAllListeners()
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
expect(() => {
|
||||
ab.set('invalid peerId')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if no addresses provided', () => {
|
||||
expect(() => {
|
||||
ab.set(peerId)
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid multiaddrs are provided', () => {
|
||||
expect(() => {
|
||||
ab.set(peerId, 'invalid multiaddr')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('replaces the stored content by default and emit change event', () => {
|
||||
const defer = pDefer()
|
||||
const supportedMultiaddrs = [addr1, addr2]
|
||||
|
||||
ee.once('change:multiaddrs', ({ peerId, multiaddrs }) => {
|
||||
expect(peerId).to.exist()
|
||||
expect(multiaddrs).to.eql(supportedMultiaddrs)
|
||||
defer.resolve()
|
||||
})
|
||||
|
||||
ab.set(peerId, supportedMultiaddrs)
|
||||
const multiaddrInfos = ab.get(peerId)
|
||||
const multiaddrs = multiaddrInfos.map((mi) => mi.multiaddr)
|
||||
expect(multiaddrs).to.have.deep.members(supportedMultiaddrs)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('emits on set if not storing the exact same content', async () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedMultiaddrsA = [addr1, addr2]
|
||||
const supportedMultiaddrsB = [addr2]
|
||||
|
||||
let changeCounter = 0
|
||||
ee.on('change:multiaddrs', () => {
|
||||
changeCounter++
|
||||
if (changeCounter > 1) {
|
||||
defer.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
// set 1
|
||||
ab.set(peerId, supportedMultiaddrsA)
|
||||
|
||||
// set 2 (same content)
|
||||
ab.set(peerId, supportedMultiaddrsB)
|
||||
const multiaddrInfos = ab.get(peerId)
|
||||
const multiaddrs = multiaddrInfos.map((mi) => mi.multiaddr)
|
||||
expect(multiaddrs).to.have.deep.members(supportedMultiaddrsB)
|
||||
|
||||
await defer.promise
|
||||
})
|
||||
|
||||
it('does not emit on set if it is storing the exact same content', async () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedMultiaddrs = [addr1, addr2]
|
||||
|
||||
let changeCounter = 0
|
||||
ee.on('change:multiaddrs', () => {
|
||||
changeCounter++
|
||||
if (changeCounter > 1) {
|
||||
defer.reject()
|
||||
}
|
||||
})
|
||||
|
||||
// set 1
|
||||
ab.set(peerId, supportedMultiaddrs)
|
||||
|
||||
// set 2 (same content)
|
||||
ab.set(peerId, supportedMultiaddrs)
|
||||
|
||||
// Wait 50ms for incorrect second event
|
||||
setTimeout(() => {
|
||||
defer.resolve()
|
||||
}, 50)
|
||||
|
||||
await defer.promise
|
||||
})
|
||||
})
|
||||
|
||||
describe('addressBook.add', () => {
|
||||
let ee, ab
|
||||
|
||||
beforeEach(() => {
|
||||
ee = new EventEmitter()
|
||||
ab = new AddressBook(ee)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
ee.removeAllListeners()
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
expect(() => {
|
||||
ab.add('invalid peerId')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if no addresses provided', () => {
|
||||
expect(() => {
|
||||
ab.add(peerId)
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid multiaddrs are provided', () => {
|
||||
expect(() => {
|
||||
ab.add(peerId, 'invalid multiaddr')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('adds the new content and emits change event', () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedMultiaddrsA = [addr1, addr2]
|
||||
const supportedMultiaddrsB = [addr3]
|
||||
const finalMultiaddrs = supportedMultiaddrsA.concat(supportedMultiaddrsB)
|
||||
|
||||
let changeTrigger = 2
|
||||
ee.on('change:multiaddrs', ({ multiaddrs }) => {
|
||||
changeTrigger--
|
||||
if (changeTrigger === 0 && arraysAreEqual(multiaddrs, finalMultiaddrs)) {
|
||||
defer.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
// Replace
|
||||
ab.set(peerId, supportedMultiaddrsA)
|
||||
let multiaddrInfos = ab.get(peerId)
|
||||
let multiaddrs = multiaddrInfos.map((mi) => mi.multiaddr)
|
||||
expect(multiaddrs).to.have.deep.members(supportedMultiaddrsA)
|
||||
|
||||
// Add
|
||||
ab.add(peerId, supportedMultiaddrsB)
|
||||
multiaddrInfos = ab.get(peerId)
|
||||
multiaddrs = multiaddrInfos.map((mi) => mi.multiaddr)
|
||||
expect(multiaddrs).to.have.deep.members(finalMultiaddrs)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('emits on add if the content to add not exists', async () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedMultiaddrsA = [addr1]
|
||||
const supportedMultiaddrsB = [addr2]
|
||||
const finalMultiaddrs = supportedMultiaddrsA.concat(supportedMultiaddrsB)
|
||||
|
||||
let changeCounter = 0
|
||||
ee.on('change:multiaddrs', () => {
|
||||
changeCounter++
|
||||
if (changeCounter > 1) {
|
||||
defer.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
// set 1
|
||||
ab.set(peerId, supportedMultiaddrsA)
|
||||
|
||||
// set 2 (content already existing)
|
||||
ab.add(peerId, supportedMultiaddrsB)
|
||||
const multiaddrInfos = ab.get(peerId)
|
||||
const multiaddrs = multiaddrInfos.map((mi) => mi.multiaddr)
|
||||
expect(multiaddrs).to.have.deep.members(finalMultiaddrs)
|
||||
|
||||
await defer.promise
|
||||
})
|
||||
|
||||
it('does not emit on add if the content to add already exists', async () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedMultiaddrsA = [addr1, addr2]
|
||||
const supportedMultiaddrsB = [addr2]
|
||||
|
||||
let changeCounter = 0
|
||||
ee.on('change:multiaddrs', () => {
|
||||
changeCounter++
|
||||
if (changeCounter > 1) {
|
||||
defer.reject()
|
||||
}
|
||||
})
|
||||
|
||||
// set 1
|
||||
ab.set(peerId, supportedMultiaddrsA)
|
||||
|
||||
// set 2 (content already existing)
|
||||
ab.add(peerId, supportedMultiaddrsB)
|
||||
|
||||
// Wait 50ms for incorrect second event
|
||||
setTimeout(() => {
|
||||
defer.resolve()
|
||||
}, 50)
|
||||
|
||||
await defer.promise
|
||||
})
|
||||
})
|
||||
|
||||
describe('addressBook.get', () => {
|
||||
let ee, ab
|
||||
|
||||
beforeEach(() => {
|
||||
ee = new EventEmitter()
|
||||
ab = new AddressBook(ee)
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
expect(() => {
|
||||
ab.get('invalid peerId')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('returns undefined if no multiaddrs are known for the provided peer', () => {
|
||||
const multiaddrInfos = ab.get(peerId)
|
||||
|
||||
expect(multiaddrInfos).to.not.exist()
|
||||
})
|
||||
|
||||
it('returns the multiaddrs stored', () => {
|
||||
const supportedMultiaddrs = [addr1, addr2]
|
||||
|
||||
ab.set(peerId, supportedMultiaddrs)
|
||||
|
||||
const multiaddrInfos = ab.get(peerId)
|
||||
const multiaddrs = multiaddrInfos.map((mi) => mi.multiaddr)
|
||||
expect(multiaddrs).to.have.deep.members(supportedMultiaddrs)
|
||||
})
|
||||
})
|
||||
|
||||
describe('addressBook.getMultiaddrsForPeer', () => {
|
||||
let ee, ab
|
||||
|
||||
beforeEach(() => {
|
||||
ee = new EventEmitter()
|
||||
ab = new AddressBook(ee)
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
expect(() => {
|
||||
ab.getMultiaddrsForPeer('invalid peerId')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('returns undefined if no multiaddrs are known for the provided peer', () => {
|
||||
const multiaddrInfos = ab.getMultiaddrsForPeer(peerId)
|
||||
|
||||
expect(multiaddrInfos).to.not.exist()
|
||||
})
|
||||
|
||||
it('returns the multiaddrs stored', () => {
|
||||
const supportedMultiaddrs = [addr1, addr2]
|
||||
|
||||
ab.set(peerId, supportedMultiaddrs)
|
||||
|
||||
const multiaddrs = ab.getMultiaddrsForPeer(peerId)
|
||||
multiaddrs.forEach((m) => {
|
||||
expect(m.getPeerId()).to.equal(peerId.toB58String())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('addressBook.delete', () => {
|
||||
let ee, ab
|
||||
|
||||
beforeEach(() => {
|
||||
ee = new EventEmitter()
|
||||
ab = new AddressBook(ee)
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
expect(() => {
|
||||
ab.delete('invalid peerId')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('returns false if no records exist for the peer and no event is emitted', () => {
|
||||
const defer = pDefer()
|
||||
|
||||
ee.on('change:multiaddrs', () => {
|
||||
defer.reject()
|
||||
})
|
||||
|
||||
const deleted = ab.delete(peerId)
|
||||
|
||||
expect(deleted).to.equal(false)
|
||||
|
||||
// Wait 50ms for incorrect invalid event
|
||||
setTimeout(() => {
|
||||
defer.resolve()
|
||||
}, 50)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('returns true if the record exists and an event is emitted', () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedMultiaddrs = [addr1, addr2]
|
||||
ab.set(peerId, supportedMultiaddrs)
|
||||
|
||||
// Listen after set
|
||||
ee.on('change:multiaddrs', ({ multiaddrs }) => {
|
||||
expect(multiaddrs.length).to.eql(0)
|
||||
defer.resolve()
|
||||
})
|
||||
|
||||
const deleted = ab.delete(peerId)
|
||||
|
||||
expect(deleted).to.equal(true)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
})
|
||||
})
|
@ -4,185 +4,147 @@
|
||||
const chai = require('chai')
|
||||
chai.use(require('dirty-chai'))
|
||||
const { expect } = chai
|
||||
const sinon = require('sinon')
|
||||
|
||||
const pDefer = require('p-defer')
|
||||
|
||||
const PeerStore = require('../../src/peer-store')
|
||||
const multiaddr = require('multiaddr')
|
||||
|
||||
const peerUtils = require('../utils/creators/peer')
|
||||
|
||||
const addr = multiaddr('/ip4/127.0.0.1/tcp/8000')
|
||||
const addr1 = multiaddr('/ip4/127.0.0.1/tcp/8000')
|
||||
const addr2 = multiaddr('/ip4/127.0.0.1/tcp/8001')
|
||||
const addr3 = multiaddr('/ip4/127.0.0.1/tcp/8002')
|
||||
const addr4 = multiaddr('/ip4/127.0.0.1/tcp/8003')
|
||||
|
||||
const proto1 = '/protocol1'
|
||||
const proto2 = '/protocol2'
|
||||
const proto3 = '/protocol3'
|
||||
|
||||
describe('peer-store', () => {
|
||||
let peerStore
|
||||
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore()
|
||||
let peerIds
|
||||
before(async () => {
|
||||
peerIds = await peerUtils.createPeerId({
|
||||
number: 4
|
||||
})
|
||||
})
|
||||
|
||||
it('should add a new peer and emit it when it does not exist', async () => {
|
||||
const defer = pDefer()
|
||||
describe('empty books', () => {
|
||||
let peerStore
|
||||
|
||||
sinon.spy(peerStore, 'put')
|
||||
sinon.spy(peerStore, 'add')
|
||||
sinon.spy(peerStore, 'update')
|
||||
|
||||
const [peerInfo] = await peerUtils.createPeerInfo()
|
||||
|
||||
peerStore.on('peer', (peer) => {
|
||||
expect(peer).to.exist()
|
||||
defer.resolve()
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore()
|
||||
})
|
||||
peerStore.put(peerInfo)
|
||||
|
||||
// Wait for peerStore to emit the peer
|
||||
await defer.promise
|
||||
it('has an empty map of peers', () => {
|
||||
const peers = peerStore.peers
|
||||
expect(peers.size).to.equal(0)
|
||||
})
|
||||
|
||||
expect(peerStore.put.callCount).to.equal(1)
|
||||
expect(peerStore.add.callCount).to.equal(1)
|
||||
expect(peerStore.update.callCount).to.equal(0)
|
||||
it('returns false on trying to delete a non existant peerId', () => {
|
||||
const deleted = peerStore.delete(peerIds[0])
|
||||
expect(deleted).to.equal(false)
|
||||
})
|
||||
|
||||
it('returns undefined on trying to find a non existant peerId', () => {
|
||||
const peerInfo = peerStore.find(peerIds[0])
|
||||
expect(peerInfo).to.not.exist()
|
||||
})
|
||||
})
|
||||
|
||||
it('should update peer when it is already in the store', async () => {
|
||||
const [peerInfo] = await peerUtils.createPeerInfo()
|
||||
describe('previously populated books', () => {
|
||||
let peerStore
|
||||
|
||||
// Put the peer in the store
|
||||
peerStore.put(peerInfo)
|
||||
beforeEach(() => {
|
||||
peerStore = new PeerStore()
|
||||
|
||||
sinon.spy(peerStore, 'add')
|
||||
sinon.spy(peerStore, 'update')
|
||||
// Add peer0 with { addr1, addr2 } and { proto1 }
|
||||
peerStore.addressBook.set(peerIds[0], [addr1, addr2])
|
||||
peerStore.protoBook.set(peerIds[0], [proto1])
|
||||
|
||||
// When updating, peer event must not be emitted
|
||||
peerStore.on('peer', () => {
|
||||
throw new Error('should not emit twice')
|
||||
})
|
||||
// If no multiaddrs change, the event should not be emitted
|
||||
peerStore.on('change:multiaddrs', () => {
|
||||
throw new Error('should not emit change:multiaddrs')
|
||||
})
|
||||
// If no protocols change, the event should not be emitted
|
||||
peerStore.on('change:protocols', () => {
|
||||
throw new Error('should not emit change:protocols')
|
||||
// Add peer1 with { addr3 } and { proto2, proto3 }
|
||||
peerStore.addressBook.set(peerIds[1], [addr3])
|
||||
peerStore.protoBook.set(peerIds[1], [proto2, proto3])
|
||||
|
||||
// Add peer2 with { addr4 }
|
||||
peerStore.addressBook.set(peerIds[2], [addr4])
|
||||
|
||||
// Add peer3 with { addr4 } and { proto2 }
|
||||
peerStore.addressBook.set(peerIds[3], [addr4])
|
||||
peerStore.protoBook.set(peerIds[3], [proto2])
|
||||
})
|
||||
|
||||
peerStore.put(peerInfo)
|
||||
it('has peers', () => {
|
||||
const peers = peerStore.peers
|
||||
|
||||
expect(peerStore.add.callCount).to.equal(0)
|
||||
expect(peerStore.update.callCount).to.equal(1)
|
||||
})
|
||||
expect(peers.size).to.equal(4)
|
||||
expect(Array.from(peers.keys())).to.have.members([
|
||||
peerIds[0].toB58String(),
|
||||
peerIds[1].toB58String(),
|
||||
peerIds[2].toB58String(),
|
||||
peerIds[3].toB58String()
|
||||
])
|
||||
})
|
||||
|
||||
it('should emit the "change:multiaddrs" event when a peer has new multiaddrs', async () => {
|
||||
const defer = pDefer()
|
||||
const [createdPeerInfo] = await peerUtils.createPeerInfo()
|
||||
it('returns true on deleting a stored peer', () => {
|
||||
const deleted = peerStore.delete(peerIds[0])
|
||||
expect(deleted).to.equal(true)
|
||||
|
||||
// Put the peer in the store
|
||||
peerStore.put(createdPeerInfo)
|
||||
const peers = peerStore.peers
|
||||
expect(peers.size).to.equal(3)
|
||||
expect(Array.from(peers.keys())).to.not.have.members([peerIds[0].toB58String()])
|
||||
})
|
||||
|
||||
// When updating, "change:multiaddrs" event must not be emitted
|
||||
peerStore.on('change:multiaddrs', ({ peerInfo, multiaddrs }) => {
|
||||
it('returns true on deleting a stored peer which is only on one book', () => {
|
||||
const deleted = peerStore.delete(peerIds[2])
|
||||
expect(deleted).to.equal(true)
|
||||
|
||||
const peers = peerStore.peers
|
||||
expect(peers.size).to.equal(3)
|
||||
})
|
||||
|
||||
it('finds the stored information of a peer in all its books', () => {
|
||||
const peerInfo = peerStore.find(peerIds[0])
|
||||
expect(peerInfo).to.exist()
|
||||
expect(peerInfo.id).to.eql(createdPeerInfo.id)
|
||||
expect(peerInfo.protocols).to.eql(createdPeerInfo.protocols)
|
||||
expect(multiaddrs).to.exist()
|
||||
expect(multiaddrs).to.eql(createdPeerInfo.multiaddrs.toArray())
|
||||
defer.resolve()
|
||||
})
|
||||
// If no protocols change, the event should not be emitted
|
||||
peerStore.on('change:protocols', () => {
|
||||
throw new Error('should not emit change:protocols')
|
||||
expect(peerInfo.protocols).to.have.members([proto1])
|
||||
|
||||
const peerMultiaddrs = peerInfo.multiaddrInfos.map((mi) => mi.multiaddr)
|
||||
expect(peerMultiaddrs).to.have.members([addr1, addr2])
|
||||
})
|
||||
|
||||
createdPeerInfo.multiaddrs.add(addr)
|
||||
peerStore.put(createdPeerInfo)
|
||||
|
||||
// Wait for peerStore to emit the event
|
||||
await defer.promise
|
||||
})
|
||||
|
||||
it('should emit the "change:protocols" event when a peer has new protocols', async () => {
|
||||
const defer = pDefer()
|
||||
const [createdPeerInfo] = await peerUtils.createPeerInfo()
|
||||
|
||||
// Put the peer in the store
|
||||
peerStore.put(createdPeerInfo)
|
||||
|
||||
// If no multiaddrs change, the event should not be emitted
|
||||
peerStore.on('change:multiaddrs', () => {
|
||||
throw new Error('should not emit change:multiaddrs')
|
||||
})
|
||||
// When updating, "change:protocols" event must be emitted
|
||||
peerStore.on('change:protocols', ({ peerInfo, protocols }) => {
|
||||
it('finds the stored information of a peer that is not present in all its books', () => {
|
||||
const peerInfo = peerStore.find(peerIds[2])
|
||||
expect(peerInfo).to.exist()
|
||||
expect(peerInfo.id).to.eql(createdPeerInfo.id)
|
||||
expect(peerInfo.multiaddrs).to.eql(createdPeerInfo.multiaddrs)
|
||||
expect(protocols).to.exist()
|
||||
expect(protocols).to.eql(Array.from(createdPeerInfo.protocols))
|
||||
defer.resolve()
|
||||
expect(peerInfo.protocols.length).to.eql(0)
|
||||
|
||||
const peerMultiaddrs = peerInfo.multiaddrInfos.map((mi) => mi.multiaddr)
|
||||
expect(peerMultiaddrs).to.have.members([addr4])
|
||||
})
|
||||
|
||||
createdPeerInfo.protocols.add('/new-protocol/1.0.0')
|
||||
peerStore.put(createdPeerInfo)
|
||||
it('can find all the peers supporting a protocol', () => {
|
||||
const peerSupporting2 = []
|
||||
|
||||
// Wait for peerStore to emit the event
|
||||
await defer.promise
|
||||
})
|
||||
for (const [, peerInfo] of peerStore.peers.entries()) {
|
||||
if (peerInfo.protocols.has(proto2)) {
|
||||
peerSupporting2.push(peerInfo)
|
||||
}
|
||||
}
|
||||
|
||||
it('should be able to retrieve a peer from store through its b58str id', async () => {
|
||||
const [peerInfo] = await peerUtils.createPeerInfo()
|
||||
const id = peerInfo.id
|
||||
expect(peerSupporting2.length).to.eql(2)
|
||||
expect(peerSupporting2[0].id.toB58String()).to.eql(peerIds[1].toB58String())
|
||||
expect(peerSupporting2[1].id.toB58String()).to.eql(peerIds[3].toB58String())
|
||||
})
|
||||
|
||||
let retrievedPeer = peerStore.get(id)
|
||||
expect(retrievedPeer).to.not.exist()
|
||||
it('can find all the peers listening on a given address', () => {
|
||||
const peerListenint4 = []
|
||||
|
||||
// Put the peer in the store
|
||||
peerStore.put(peerInfo)
|
||||
for (const [, peerInfo] of peerStore.peers.entries()) {
|
||||
if (peerInfo.multiaddrs.has(addr4)) {
|
||||
peerListenint4.push(peerInfo)
|
||||
}
|
||||
}
|
||||
|
||||
retrievedPeer = peerStore.get(id)
|
||||
expect(retrievedPeer).to.exist()
|
||||
expect(retrievedPeer.id).to.equal(peerInfo.id)
|
||||
expect(retrievedPeer.multiaddrs).to.eql(peerInfo.multiaddrs)
|
||||
expect(retrievedPeer.protocols).to.eql(peerInfo.protocols)
|
||||
})
|
||||
|
||||
it('should be able to remove a peer from store through its b58str id', async () => {
|
||||
const [peerInfo] = await peerUtils.createPeerInfo()
|
||||
const id = peerInfo.id
|
||||
|
||||
let removed = peerStore.remove(id)
|
||||
expect(removed).to.eql(false)
|
||||
|
||||
// Put the peer in the store
|
||||
peerStore.put(peerInfo)
|
||||
expect(peerStore.peers.size).to.equal(1)
|
||||
|
||||
removed = peerStore.remove(id)
|
||||
expect(removed).to.eql(true)
|
||||
expect(peerStore.peers.size).to.equal(0)
|
||||
})
|
||||
|
||||
it('should be able to get the multiaddrs for a peer', async () => {
|
||||
const [peerInfo, relayInfo] = await peerUtils.createPeerInfo({ number: 2 })
|
||||
const id = peerInfo.id
|
||||
const ma1 = multiaddr('/ip4/127.0.0.1/tcp/4001')
|
||||
const ma2 = multiaddr('/ip4/127.0.0.1/tcp/4002/ws')
|
||||
const ma3 = multiaddr(`/ip4/127.0.0.1/tcp/4003/ws/p2p/${relayInfo.id.toB58String()}/p2p-circuit`)
|
||||
|
||||
peerInfo.multiaddrs.add(ma1)
|
||||
peerInfo.multiaddrs.add(ma2)
|
||||
peerInfo.multiaddrs.add(ma3)
|
||||
|
||||
const multiaddrs = peerStore.multiaddrsForPeer(peerInfo)
|
||||
const expectedAddrs = [
|
||||
ma1.encapsulate(`/p2p/${id.toB58String()}`),
|
||||
ma2.encapsulate(`/p2p/${id.toB58String()}`),
|
||||
ma3.encapsulate(`/p2p/${id.toB58String()}`)
|
||||
]
|
||||
|
||||
expect(multiaddrs).to.eql(expectedAddrs)
|
||||
expect(peerListenint4.length).to.eql(2)
|
||||
expect(peerListenint4[0].id.toB58String()).to.eql(peerIds[2].toB58String())
|
||||
expect(peerListenint4[1].id.toB58String()).to.eql(peerIds[3].toB58String())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('peer-store on discovery', () => {
|
||||
// TODO: implement with discovery
|
||||
})
|
||||
|
310
test/peer-store/proto-book.spec.js
Normal file
310
test/peer-store/proto-book.spec.js
Normal file
@ -0,0 +1,310 @@
|
||||
'use strict'
|
||||
/* eslint-env mocha */
|
||||
|
||||
const chai = require('chai')
|
||||
chai.use(require('dirty-chai'))
|
||||
const { expect } = chai
|
||||
|
||||
const { EventEmitter } = require('events')
|
||||
const pDefer = require('p-defer')
|
||||
|
||||
const ProtoBook = require('../../src/peer-store/proto-book')
|
||||
|
||||
const peerUtils = require('../utils/creators/peer')
|
||||
const {
|
||||
ERR_INVALID_PARAMETERS
|
||||
} = require('../../src/errors')
|
||||
|
||||
const arraysAreEqual = (a, b) => a.length === b.length && a.sort().every((item, index) => b[index] === item)
|
||||
|
||||
describe('protoBook', () => {
|
||||
let peerId
|
||||
|
||||
before(async () => {
|
||||
[peerId] = await peerUtils.createPeerId()
|
||||
})
|
||||
|
||||
describe('protoBook.set', () => {
|
||||
let ee, pb
|
||||
|
||||
beforeEach(() => {
|
||||
ee = new EventEmitter()
|
||||
pb = new ProtoBook(ee)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
ee.removeAllListeners()
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
expect(() => {
|
||||
pb.set('invalid peerId')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if no protocols provided', () => {
|
||||
expect(() => {
|
||||
pb.set(peerId)
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('replaces the stored content by default and emit change event', () => {
|
||||
const defer = pDefer()
|
||||
const supportedProtocols = ['protocol1', 'protocol2']
|
||||
|
||||
ee.once('change:protocols', ({ peerId, protocols }) => {
|
||||
expect(peerId).to.exist()
|
||||
expect(protocols).to.have.deep.members(supportedProtocols)
|
||||
defer.resolve()
|
||||
})
|
||||
|
||||
pb.set(peerId, supportedProtocols)
|
||||
const protocols = pb.get(peerId)
|
||||
expect(protocols).to.have.deep.members(supportedProtocols)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('emits on set if not storing the exact same content', () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedProtocolsA = ['protocol1', 'protocol2']
|
||||
const supportedProtocolsB = ['protocol2']
|
||||
|
||||
let changeCounter = 0
|
||||
ee.on('change:protocols', () => {
|
||||
changeCounter++
|
||||
if (changeCounter > 1) {
|
||||
defer.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
// set 1
|
||||
pb.set(peerId, supportedProtocolsA)
|
||||
|
||||
// set 2 (same content)
|
||||
pb.set(peerId, supportedProtocolsB)
|
||||
const protocols = pb.get(peerId)
|
||||
expect(protocols).to.have.deep.members(supportedProtocolsB)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('does not emit on set if it is storing the exact same content', () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedProtocols = ['protocol1', 'protocol2']
|
||||
|
||||
let changeCounter = 0
|
||||
ee.on('change:protocols', () => {
|
||||
changeCounter++
|
||||
if (changeCounter > 1) {
|
||||
defer.reject()
|
||||
}
|
||||
})
|
||||
|
||||
// set 1
|
||||
pb.set(peerId, supportedProtocols)
|
||||
|
||||
// set 2 (same content)
|
||||
pb.set(peerId, supportedProtocols)
|
||||
|
||||
// Wait 50ms for incorrect second event
|
||||
setTimeout(() => {
|
||||
defer.resolve()
|
||||
}, 50)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
})
|
||||
|
||||
describe('protoBook.add', () => {
|
||||
let ee, pb
|
||||
|
||||
beforeEach(() => {
|
||||
ee = new EventEmitter()
|
||||
pb = new ProtoBook(ee)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
ee.removeAllListeners()
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
expect(() => {
|
||||
pb.add('invalid peerId')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if no protocols provided', () => {
|
||||
expect(() => {
|
||||
pb.add(peerId)
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('adds the new content and emits change event', () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedProtocolsA = ['protocol1', 'protocol2']
|
||||
const supportedProtocolsB = ['protocol3']
|
||||
const finalProtocols = supportedProtocolsA.concat(supportedProtocolsB)
|
||||
|
||||
let changeTrigger = 2
|
||||
ee.on('change:protocols', ({ protocols }) => {
|
||||
changeTrigger--
|
||||
if (changeTrigger === 0 && arraysAreEqual(protocols, finalProtocols)) {
|
||||
defer.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
// Replace
|
||||
pb.set(peerId, supportedProtocolsA)
|
||||
let protocols = pb.get(peerId)
|
||||
expect(protocols).to.have.deep.members(supportedProtocolsA)
|
||||
|
||||
// Add
|
||||
pb.add(peerId, supportedProtocolsB)
|
||||
protocols = pb.get(peerId)
|
||||
expect(protocols).to.have.deep.members(finalProtocols)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('emits on add if the content to add not exists', () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedProtocolsA = ['protocol1']
|
||||
const supportedProtocolsB = ['protocol2']
|
||||
const finalProtocols = supportedProtocolsA.concat(supportedProtocolsB)
|
||||
|
||||
let changeCounter = 0
|
||||
ee.on('change:protocols', () => {
|
||||
changeCounter++
|
||||
if (changeCounter > 1) {
|
||||
defer.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
// set 1
|
||||
pb.set(peerId, supportedProtocolsA)
|
||||
|
||||
// set 2 (content already existing)
|
||||
pb.add(peerId, supportedProtocolsB)
|
||||
const protocols = pb.get(peerId)
|
||||
expect(protocols).to.have.deep.members(finalProtocols)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('does not emit on add if the content to add already exists', () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedProtocolsA = ['protocol1', 'protocol2']
|
||||
const supportedProtocolsB = ['protocol2']
|
||||
|
||||
let changeCounter = 0
|
||||
ee.on('change:protocols', () => {
|
||||
changeCounter++
|
||||
if (changeCounter > 1) {
|
||||
defer.reject()
|
||||
}
|
||||
})
|
||||
|
||||
// set 1
|
||||
pb.set(peerId, supportedProtocolsA)
|
||||
|
||||
// set 2 (content already existing)
|
||||
pb.add(peerId, supportedProtocolsB)
|
||||
|
||||
// Wait 50ms for incorrect second event
|
||||
setTimeout(() => {
|
||||
defer.resolve()
|
||||
}, 50)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
})
|
||||
|
||||
describe('protoBook.get', () => {
|
||||
let ee, pb
|
||||
|
||||
beforeEach(() => {
|
||||
ee = new EventEmitter()
|
||||
pb = new ProtoBook(ee)
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
expect(() => {
|
||||
pb.get('invalid peerId')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('returns undefined if no protocols are known for the provided peer', () => {
|
||||
const protocols = pb.get(peerId)
|
||||
|
||||
expect(protocols).to.not.exist()
|
||||
})
|
||||
|
||||
it('returns the protocols stored', () => {
|
||||
const supportedProtocols = ['protocol1', 'protocol2']
|
||||
|
||||
pb.set(peerId, supportedProtocols)
|
||||
|
||||
const protocols = pb.get(peerId)
|
||||
expect(protocols).to.have.deep.members(supportedProtocols)
|
||||
})
|
||||
})
|
||||
|
||||
describe('protoBook.delete', () => {
|
||||
let ee, pb
|
||||
|
||||
beforeEach(() => {
|
||||
ee = new EventEmitter()
|
||||
pb = new ProtoBook(ee)
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
expect(() => {
|
||||
pb.delete('invalid peerId')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('returns false if no records exist for the peer and no event is emitted', () => {
|
||||
const defer = pDefer()
|
||||
|
||||
ee.on('change:protocols', () => {
|
||||
defer.reject()
|
||||
})
|
||||
|
||||
const deleted = pb.delete(peerId)
|
||||
|
||||
expect(deleted).to.equal(false)
|
||||
|
||||
// Wait 50ms for incorrect invalid event
|
||||
setTimeout(() => {
|
||||
defer.resolve()
|
||||
}, 50)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('returns true if the record exists and an event is emitted', () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedProtocols = ['protocol1', 'protocol2']
|
||||
pb.set(peerId, supportedProtocols)
|
||||
|
||||
// Listen after set
|
||||
ee.on('change:protocols', ({ protocols }) => {
|
||||
expect(protocols.length).to.eql(0)
|
||||
defer.resolve()
|
||||
})
|
||||
|
||||
const deleted = pb.delete(peerId)
|
||||
|
||||
expect(deleted).to.equal(true)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
})
|
||||
})
|
@ -89,7 +89,9 @@ describe('registrar', () => {
|
||||
remotePeerInfo.protocols.add(multicodec)
|
||||
|
||||
// Add connected peer to peerStore and registrar
|
||||
peerStore.put(remotePeerInfo)
|
||||
peerStore.addressBook.set(remotePeerInfo.id, remotePeerInfo.multiaddrs.toArray())
|
||||
peerStore.protoBook.set(remotePeerInfo.id, Array.from(remotePeerInfo.protocols))
|
||||
|
||||
registrar.onConnect(remotePeerInfo, conn)
|
||||
expect(registrar.connections.size).to.eql(1)
|
||||
|
||||
@ -156,18 +158,23 @@ describe('registrar', () => {
|
||||
const peerInfo = await PeerInfo.create(conn.remotePeer)
|
||||
|
||||
// Add connected peer to peerStore and registrar
|
||||
peerStore.put(peerInfo)
|
||||
peerStore.addressBook.set(peerInfo.id, peerInfo.multiaddrs.toArray())
|
||||
peerStore.protoBook.set(peerInfo.id, Array.from(peerInfo.protocols))
|
||||
|
||||
registrar.onConnect(peerInfo, conn)
|
||||
|
||||
// Add protocol to peer and update it
|
||||
peerInfo.protocols.add(multicodec)
|
||||
peerStore.put(peerInfo)
|
||||
peerStore.addressBook.add(peerInfo.id, peerInfo.multiaddrs.toArray())
|
||||
peerStore.protoBook.add(peerInfo.id, Array.from(peerInfo.protocols))
|
||||
|
||||
await onConnectDefer.promise
|
||||
|
||||
// Remove protocol to peer and update it
|
||||
peerInfo.protocols.delete(multicodec)
|
||||
peerStore.replace(peerInfo)
|
||||
|
||||
peerStore.addressBook.set(peerInfo.id, peerInfo.multiaddrs.toArray())
|
||||
peerStore.protoBook.set(peerInfo.id, Array.from(peerInfo.protocols))
|
||||
|
||||
await onDisconnectDefer.promise
|
||||
})
|
||||
@ -197,7 +204,8 @@ describe('registrar', () => {
|
||||
const id = peerInfo.id.toB58String()
|
||||
|
||||
// Add connection to registrar
|
||||
peerStore.put(peerInfo)
|
||||
peerStore.addressBook.set(peerInfo.id, peerInfo.multiaddrs.toArray())
|
||||
peerStore.protoBook.set(peerInfo.id, Array.from(peerInfo.protocols))
|
||||
registrar.onConnect(peerInfo, conn1)
|
||||
registrar.onConnect(peerInfo, conn2)
|
||||
|
||||
|
Reference in New Issue
Block a user