mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-06-27 16:01:32 +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:
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
|
||||
})
|
||||
})
|
||||
})
|
Reference in New Issue
Block a user