js-libp2p/test/circuit/v2/hop.spec.js

285 lines
9.5 KiB
JavaScript
Raw Normal View History

2022-02-21 16:28:04 +01:00
'use strict'
/* eslint-env mocha */
const mockConnection = require('../../utils/mockConnection')
const { expect } = require('aegir/utils/chai')
const peerUtils = require('../../utils/creators/peer')
const { handleHopProtocol } = require('../../../src/circuit/v2/hop')
const StreamHandler = require('../../../src/circuit/v2/stream-handler')
const multicodec = require('../../../src/circuit/multicodec')
const { Status, HopMessage } = require('../../../src/circuit/v2/protocol')
const { Multiaddr } = require('multiaddr')
const sinon = require('sinon')
describe('Circuit v2 - hop protocol', function () {
it('error on unknow message type', async function () {
const conn = await mockConnection()
const { stream } = await conn.newStream([multicodec.protocolIDv2Hop])
const streamHandler = new StreamHandler({ stream })
await handleHopProtocol({
connection: conn,
streamHandler,
request: {
type: 'not_existing'
}
})
const msg = HopMessage.decode(await streamHandler.read())
expect(msg.type).to.be.equal(HopMessage.Type.STATUS)
expect(msg.status).to.be.equal(Status.MALFORMED_MESSAGE)
})
describe('reserve', function () {
let srcPeer, relayPeer, conn, streamHandler, reservationStore
beforeEach(async () => {
[srcPeer, relayPeer] = await peerUtils.createPeerId({ number: 2 })
conn = await mockConnection({ localPeer: srcPeer, remotePeer: relayPeer })
const { stream } = await conn.newStream([multicodec.protocolIDv2Hop])
streamHandler = new StreamHandler({ stream })
reservationStore = {
reserve: sinon.stub(),
removeReservation: sinon.stub()
}
})
this.afterEach(async function () {
streamHandler.close()
await conn.close()
})
it('should reserve slot', async function () {
const expire = 123
reservationStore.reserve.resolves({ status: Status.OK, expire })
await handleHopProtocol({
request: {
type: HopMessage.Type.RESERVE
},
connection: conn,
streamHandler,
relayPeer,
relayAddrs: [new Multiaddr('/ip4/127.0.0.1/udp/1234')],
reservationStore
})
expect(reservationStore.reserve.calledOnceWith(conn.remotePeer, conn.remoteAddr)).to.be.true()
const response = HopMessage.decode(await streamHandler.read())
expect(response.type).to.be.equal(HopMessage.Type.STATUS)
expect(response.limit).to.be.null()
expect(response.status).to.be.equal(Status.OK)
2022-03-23 14:41:13 +01:00
expect(response.reservation.expire).to.be.equal(expire)
2022-02-21 16:28:04 +01:00
expect(response.reservation.voucher).to.not.be.null()
expect(response.reservation.addrs.length).to.be.greaterThan(0)
})
it('should fail to reserve slot - acl denied', async function () {
await handleHopProtocol({
request: {
type: HopMessage.Type.RESERVE
},
connection: conn,
streamHandler,
relayPeer,
relayAddrs: [new Multiaddr('/ip4/127.0.0.1/udp/1234')],
reservationStore,
acl: { allowReserve: function () { return false } }
})
expect(reservationStore.reserve.notCalled).to.be.true()
const response = HopMessage.decode(await streamHandler.read())
expect(response.type).to.be.equal(HopMessage.Type.STATUS)
expect(response.limit).to.be.null()
expect(response.status).to.be.equal(Status.PERMISSION_DENIED)
})
it('should fail to reserve slot - resource exceeded', async function () {
reservationStore.reserve.resolves({ status: Status.RESOURCE_LIMIT_EXCEEDED })
await handleHopProtocol({
request: {
type: HopMessage.Type.RESERVE
},
connection: conn,
streamHandler,
relayPeer,
relayAddrs: [new Multiaddr('/ip4/127.0.0.1/udp/1234')],
reservationStore
})
expect(reservationStore.reserve.calledOnce).to.be.true()
const response = HopMessage.decode(await streamHandler.read())
expect(response.type).to.be.equal(HopMessage.Type.STATUS)
expect(response.limit).to.be.null()
expect(response.status).to.be.equal(Status.RESOURCE_LIMIT_EXCEEDED)
})
it('should fail to reserve slot - failed to write response', async function () {
reservationStore.reserve.resolves({ status: Status.OK, expire: 123 })
reservationStore.removeReservation.resolves()
const backup = streamHandler.write
streamHandler.write = function () { throw new Error('connection reset') }
await handleHopProtocol({
request: {
type: HopMessage.Type.RESERVE
},
connection: conn,
streamHandler,
relayPeer,
relayAddrs: [new Multiaddr('/ip4/127.0.0.1/udp/1234')],
reservationStore
})
expect(reservationStore.reserve.calledOnce).to.be.true()
expect(reservationStore.removeReservation.calledOnce).to.be.true()
streamHandler.write = backup
})
})
describe('connect', function () {
let srcPeer, relayPeer, dstPeer, conn, streamHandler, reservationStore, circuit
beforeEach(async () => {
[srcPeer, relayPeer, dstPeer] = await peerUtils.createPeerId({ number: 3 })
conn = await mockConnection({ localPeer: srcPeer, remotePeer: relayPeer })
const { stream } = await conn.newStream([multicodec.protocolIDv2Hop])
streamHandler = new StreamHandler({ stream })
reservationStore = {
reserve: sinon.stub(),
removeReservation: sinon.stub(),
hasReservation: sinon.stub()
}
circuit = {
_connectionManager: {
get: sinon.stub()
}
}
})
this.afterEach(async function () {
streamHandler.close()
await conn.close()
})
it('should succeed to connect', async function () {
reservationStore.hasReservation.resolves(Status.OK)
const dstConn = await mockConnection({ localPeer: dstPeer, remotePeer: relayPeer })
circuit._connectionManager.get.returns(dstConn)
await handleHopProtocol({
connection: conn,
streamHandler,
request: {
type: HopMessage.Type.CONNECT,
peer: {
id: dstPeer.id,
addrs: []
}
},
reservationStore,
circuit
})
const response = HopMessage.decode(await streamHandler.read())
expect(response.type).to.be.equal(HopMessage.Type.STATUS)
expect(response.status).to.be.equal(Status.OK)
})
it('should succeed to connect', async function () {
reservationStore.hasReservation.resolves(Status.OK)
const dstConn = await mockConnection({ localPeer: dstPeer, remotePeer: relayPeer })
circuit._connectionManager.get.returns(dstConn)
await handleHopProtocol({
connection: conn,
streamHandler,
request: {
type: HopMessage.Type.CONNECT,
peer: {
id: dstPeer.id,
addrs: []
}
},
reservationStore,
circuit
})
const response = HopMessage.decode(await streamHandler.read())
expect(response.type).to.be.equal(HopMessage.Type.STATUS)
expect(response.status).to.be.equal(Status.OK)
})
it('should fail to connect - invalid request', async function () {
await handleHopProtocol({
connection: conn,
streamHandler,
request: {
type: HopMessage.Type.CONNECT,
peer: {
}
},
reservationStore,
circuit
})
const response = HopMessage.decode(await streamHandler.read())
expect(response.type).to.be.equal(HopMessage.Type.STATUS)
expect(response.status).to.be.equal(Status.MALFORMED_MESSAGE)
})
it('should failed to connect - acl denied', async function () {
const acl = {
allowConnect: function () { return Status.PERMISSION_DENIED }
}
await handleHopProtocol({
connection: conn,
streamHandler,
request: {
type: HopMessage.Type.CONNECT,
peer: {
id: dstPeer.id,
addrs: []
}
},
reservationStore,
circuit,
acl
})
const response = HopMessage.decode(await streamHandler.read())
expect(response.type).to.be.equal(HopMessage.Type.STATUS)
expect(response.status).to.be.equal(Status.PERMISSION_DENIED)
})
it('should fail to connect - no reservation', async function () {
reservationStore.hasReservation.resolves(Status.NO_RESERVATION)
await handleHopProtocol({
connection: conn,
streamHandler,
request: {
type: HopMessage.Type.CONNECT,
peer: {
id: dstPeer.id,
addrs: []
}
},
reservationStore,
circuit
})
const response = HopMessage.decode(await streamHandler.read())
expect(response.type).to.be.equal(HopMessage.Type.STATUS)
expect(response.status).to.be.equal(Status.NO_RESERVATION)
})
it('should fail to connect - no connection', async function () {
reservationStore.hasReservation.resolves(Status.OK)
await handleHopProtocol({
connection: conn,
streamHandler,
request: {
type: HopMessage.Type.CONNECT,
peer: {
id: dstPeer.id,
addrs: []
}
},
reservationStore,
circuit
})
const response = HopMessage.decode(await streamHandler.read())
expect(response.type).to.be.equal(HopMessage.Type.STATUS)
expect(response.status).to.be.equal(Status.NO_RESERVATION)
expect(circuit._connectionManager.get.calledOnce).to.be.true()
})
})
})