js-libp2p/test/switch/identify.node.js

174 lines
5.2 KiB
JavaScript

/* eslint-env mocha */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
chai.use(require('chai-checkmark'))
const expect = chai.expect
const parallel = require('async/parallel')
const TCP = require('libp2p-tcp')
const multiplex = require('libp2p-mplex')
const pull = require('pull-stream')
const secio = require('libp2p-secio')
const PeerInfo = require('peer-info')
const PeerBook = require('peer-book')
const identify = require('../../src/identify')
const lp = require('pull-length-prefixed')
const sinon = require('sinon')
const utils = require('./utils')
const createInfos = utils.createInfos
const Switch = require('../../src/switch')
describe('Identify', () => {
let switchA
let switchB
let switchC
before((done) => createInfos(3, (err, infos) => {
expect(err).to.not.exist()
const peerA = infos[0]
const peerB = infos[1]
const peerC = infos[2]
peerA.multiaddrs.add('/ip4/127.0.0.1/tcp/9001')
peerB.multiaddrs.add('/ip4/127.0.0.1/tcp/9002')
peerC.multiaddrs.add('/ip4/127.0.0.1/tcp/9003')
switchA = new Switch(peerA, new PeerBook())
switchB = new Switch(peerB, new PeerBook())
switchC = new Switch(peerC, new PeerBook())
switchA.transport.add('tcp', new TCP())
switchB.transport.add('tcp', new TCP())
switchC.transport.add('tcp', new TCP())
switchA.connection.crypto(secio.tag, secio.encrypt)
switchB.connection.crypto(secio.tag, secio.encrypt)
switchC.connection.crypto(secio.tag, secio.encrypt)
switchA.connection.addStreamMuxer(multiplex)
switchB.connection.addStreamMuxer(multiplex)
switchC.connection.addStreamMuxer(multiplex)
switchA.connection.reuse()
switchB.connection.reuse()
switchC.connection.reuse()
parallel([
(cb) => switchA.transport.listen('tcp', {}, null, cb),
(cb) => switchB.transport.listen('tcp', {}, null, cb),
(cb) => switchC.transport.listen('tcp', {}, null, cb)
], done)
}))
after((done) => {
parallel([
(cb) => switchA.stop(cb),
(cb) => switchB.stop(cb),
(cb) => switchC.stop(cb)
], done)
})
afterEach(function (done) {
sinon.restore()
// Hangup everything
parallel([
(cb) => switchA.hangUp(switchB._peerInfo, cb),
(cb) => switchA.hangUp(switchC._peerInfo, cb),
(cb) => switchB.hangUp(switchA._peerInfo, cb),
(cb) => switchB.hangUp(switchC._peerInfo, cb),
(cb) => switchC.hangUp(switchA._peerInfo, cb),
(cb) => switchC.hangUp(switchB._peerInfo, cb)
], done)
})
it('should identify a good peer', (done) => {
switchA.handle('/id-test/1.0.0', (protocol, conn) => pull(conn, conn))
switchB.dial(switchA._peerInfo, '/id-test/1.0.0', (err, conn) => {
expect(err).to.not.exist()
const data = Buffer.from('data that can be had')
pull(
pull.values([data]),
conn,
pull.collect((err, values) => {
expect(err).to.not.exist()
expect(values).to.deep.equal([data])
done()
})
)
})
})
it('should get protocols for one another', (done) => {
// We need to reset the PeerInfo objects we use,
// since we share memory we can receive a false positive if not
const peerA = new PeerInfo(switchA._peerInfo.id)
switchA._peerInfo.multiaddrs.toArray().forEach((m) => {
peerA.multiaddrs.add(m)
})
switchB._peerBook.remove(switchA._peerInfo.id.toB58String())
switchA._peerBook.remove(switchB._peerInfo.id.toB58String())
switchA.handle('/id-test/1.0.0', (protocol, conn) => pull(conn, conn))
switchB.dial(peerA, '/id-test/1.0.0', (err) => {
expect(err).to.not.exist()
// Give identify a moment to run
setTimeout(() => {
const peerB = switchA._peerBook.get(switchB._peerInfo.id.toB58String())
const peerA = switchB._peerBook.get(switchA._peerInfo.id.toB58String())
expect(Array.from(peerB.protocols)).to.eql([
multiplex.multicodec,
identify.multicodec
])
expect(Array.from(peerA.protocols)).to.eql([
multiplex.multicodec,
identify.multicodec,
'/id-test/1.0.0'
])
done()
}, 500)
})
})
it('should close connection when identify fails', (done) => {
const stub = sinon.stub(identify, 'listener').callsFake((conn) => {
conn.getObservedAddrs((err, observedAddrs) => {
if (err) { return }
observedAddrs = observedAddrs[0]
// pretend to be another peer
const publicKey = switchC._peerInfo.id.pubKey.bytes
const msgSend = identify.message.encode({
protocolVersion: 'ipfs/0.1.0',
agentVersion: 'na',
publicKey: publicKey,
listenAddrs: switchC._peerInfo.multiaddrs.toArray().map((ma) => ma.buffer),
observedAddr: observedAddrs ? observedAddrs.buffer : Buffer.from('')
})
pull(
pull.values([msgSend]),
lp.encode(),
conn
)
})
})
expect(2).checks(done)
switchA.handle('/id-test/1.0.0', (protocol, conn) => pull(conn, conn))
switchB.dialFSM(switchA._peerInfo, '/id-test/1.0.0', (err, connFSM) => {
expect(err).to.not.exist().mark()
connFSM.once('close', () => {
expect(stub.called).to.eql(true).mark()
})
})
})
})