ipfs-coord
Version:
A JS library for helping IPFS peers coordinate, find a common interest, and stay connected around that interest.
397 lines (306 loc) • 10.9 kB
JavaScript
/*
Unit tests for the this-node use case.
*/
// npm libraries
const assert = require('chai').assert
const sinon = require('sinon')
// Local libraries
const ThisNodeUseCases = require('../../../lib/use-cases/this-node-use-cases')
const AdapterMock = require('../../mocks/adapter-mock')
const adapters = new AdapterMock()
const mockData = require('../../mocks/peers-mock')
const UseCasesMock = require('../../mocks/use-case-mocks')
describe('#thisNode-Use-Cases', () => {
let uut
let sandbox
beforeEach(() => {
// Restore the sandbox before each test.
sandbox = sinon.createSandbox()
uut = new ThisNodeUseCases({
adapters,
controllers: {}
})
const useCases = new UseCasesMock()
uut.updateUseCases(useCases)
})
afterEach(() => sandbox.restore())
describe('#constructor', () => {
it('should throw an error if adapters is not included', () => {
try {
uut = new ThisNodeUseCases()
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Must inject instance of adapters when instantiating thisNode Use Cases library.'
)
}
})
it('should throw an error if controllers are not included', () => {
try {
uut = new ThisNodeUseCases({ adapters: {} })
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Must inject instance of controllers when instantiating thisNode Use Cases library.'
)
}
})
it('should instantiate the use cases library', () => {
uut = new ThisNodeUseCases({
adapters: {},
controllers: {}
})
assert.property(uut, 'adapters')
})
})
describe('#createSelf', () => {
it('should create a thisNode entity', async () => {
uut = new ThisNodeUseCases({ adapters, controllers: {}, statusLog: {} })
const result = await uut.createSelf({ type: 'node.js' })
// console.log('result: ', result)
assert.property(result, 'ipfsId')
assert.property(result, 'type')
})
})
describe('#addSubnetPeer', () => {
it('should track a new peer', async () => {
// Mock dependencies
sandbox.stub(uut, 'isFreshPeer').returns(true)
const announceObj = {
from: 'peerId',
data: {}
}
await uut.createSelf({ type: 'node.js' })
const result = await uut.addSubnetPeer(announceObj)
// console.log('result: ', result)
assert.equal(result, true)
})
it('should track a new Relay peer', async () => {
// Mock dependencies
sandbox.stub(uut, 'isFreshPeer').returns(true)
sandbox.stub(uut.useCases.relays, 'addRelay').resolves()
const announceObj = {
from: 'peerId',
data: {
isCircuitRelay: true
}
}
await uut.createSelf({ type: 'node.js' })
const result = await uut.addSubnetPeer(announceObj)
// console.log('result: ', result)
assert.equal(result, true)
})
it('should update an existing peer', async () => {
// Mock dependencies
sandbox.stub(uut, 'isFreshPeer').returns(true)
const announceObj = {
from: 'peerId',
data: {
orbitdb: 'orbitdbId'
}
}
await uut.createSelf({ type: 'node.js' })
// Add the new peer
await uut.addSubnetPeer(announceObj)
// Simulate a second announcement object.
const result = await uut.addSubnetPeer(announceObj)
// console.log('result: ', result)
assert.equal(result, true)
// peerData array should only have one peer.
assert.equal(uut.thisNode.peerData.length, 1)
})
// TODO: Create new test case:
// it('should not update an existing peer if broadcast message is older the current one')'
it('should catch and report an error', async () => {
try {
const announceObj = {
from: 'peerId'
}
await uut.addSubnetPeer(announceObj)
assert.isOk(true, 'Not throwing an error is a pass')
} catch (err) {
// console.log(err)
assert.fail('Unexpected code path')
}
})
})
describe('#refreshPeerConnections', () => {
it('should execute with no connected peers', async () => {
await uut.createSelf({ type: 'node.js' })
// Add a peer
await uut.addSubnetPeer(mockData.announceObj)
// Mock dependencies
sandbox.stub(uut.adapters.ipfs, 'getPeers').resolves(mockData.swarmPeers)
// Connect to that peer.
await uut.refreshPeerConnections()
})
it('should skip if peer is already connected', async () => {
await uut.createSelf({ type: 'node.js' })
// Add a peer that is already in the list of connected peers.
uut.thisNode.peerList = ['QmbyYXKbnAmMbMGo8LRBZ58jYs58anqUzY1m4jxDmhDsjd']
// Add a peer
await uut.addSubnetPeer(mockData.announceObj2)
// Mock dependencies
sandbox.stub(uut.adapters.ipfs, 'getPeers').resolves(mockData.swarmPeers)
// Connect to that peer.
const result = await uut.refreshPeerConnections()
assert.equal(result, true)
})
it('should refresh a connection', async () => {
await uut.createSelf({ type: 'node.js' })
// Add a peer that is not in the list of connected peers.
const ipfsId = 'QmbyYXKbnAmMbMGo8LRBZ58jYs58anqUzY1m4jxDmhDsje'
uut.thisNode.peerList = [ipfsId]
uut.thisNode.peerData = [{ from: ipfsId }]
// Add a peer
await uut.addSubnetPeer(mockData.announceObj)
// Force circuit relay to be used.
uut.thisNode.relayData = mockData.mockRelayData
// Mock dependencies
sandbox.stub(uut.adapters.ipfs, 'getPeers').resolves(mockData.swarmPeers)
sandbox.stub(uut.adapters.ipfs, 'connectToPeer').resolves(true)
sandbox.stub(uut, 'isFreshPeer').returns(true)
// Connect to that peer.
const result = await uut.refreshPeerConnections()
assert.equal(result, true)
})
it('should skip if peer is stale', async () => {
await uut.createSelf({ type: 'node.js' })
// Add a peer that is not in the list of connected peers.
const ipfsId = 'QmbyYXKbnAmMbMGo8LRBZ58jYs58anqUzY1m4jxDmhDsje'
uut.thisNode.peerList = [ipfsId]
uut.thisNode.peerData = [{ from: ipfsId }]
// Add a peer
await uut.addSubnetPeer(mockData.announceObj)
// Force circuit relay to be used.
uut.thisNode.relayData = mockData.mockRelayData
// Mock dependencies
sandbox.stub(uut.adapters.ipfs, 'getPeers').resolves(mockData.swarmPeers)
sandbox.stub(uut.adapters.ipfs, 'connectToPeer').resolves(true)
sandbox.stub(uut, 'isFreshPeer').returns(false)
// Connect to that peer.
const result = await uut.refreshPeerConnections()
assert.equal(result, true)
})
it('should catch and throw an error', async () => {
try {
await uut.createSelf({ type: 'node.js' })
// Add a peer
await uut.addSubnetPeer(mockData.announceObj)
// Force error
sandbox
.stub(uut.adapters.ipfs, 'getPeers')
.rejects(new Error('test error'))
// Connect to that peer.
await uut.refreshPeerConnections()
assert.fail('Unexpected code path')
} catch (err) {
// console.log('err: ', err)
assert.include(err.message, 'test error')
}
})
})
describe('#isFreshPeer', () => {
it('should return false if peer data has no broadcastedAt property', () => {
const announceObj = {
data: {}
}
const result = uut.isFreshPeer(announceObj)
assert.equal(result, false)
})
it('should return false if broadcast is older than 10 minutes', () => {
const now = new Date()
const fifteenMinutes = 15 * 60000
let fifteenMinutesAgo = now.getTime() - fifteenMinutes
fifteenMinutesAgo = new Date(fifteenMinutesAgo)
const announceObj = {
data: {
broadcastedAt: fifteenMinutesAgo.toISOString()
}
}
const result = uut.isFreshPeer(announceObj)
assert.equal(result, false)
})
it('should return true if broadcast is newer than 10 minutes', () => {
const now = new Date()
const fiveMinutes = 5 * 60000
let fiveMinutesAgo = now.getTime() - fiveMinutes
fiveMinutesAgo = new Date(fiveMinutesAgo)
const announceObj = {
data: {
broadcastedAt: fiveMinutesAgo.toISOString()
}
}
const result = uut.isFreshPeer(announceObj)
assert.equal(result, true)
})
})
describe('#enforceBlacklist', () => {
it('should disconnect from blacklisted peers', async () => {
await uut.createSelf({ type: 'node.js' })
// Set up test data
uut.thisNode.blacklistPeers = ['testId']
uut.thisNode.blacklistMultiaddrs = ['testId']
const result = await uut.enforceBlacklist()
assert.equal(result, true)
})
it('catch and throw an error', async () => {
try {
await uut.enforceBlacklist()
assert.fail('Unexpected code path')
} catch (err) {
// console.log(err)
assert.include(err.message, 'Cannot read')
}
})
})
describe('#enforceWhitelist', () => {
it('should disconnect from non-ipfs-coord peers', async () => {
await uut.createSelf({ type: 'node.js' })
// Mock dependencies
sandbox.stub(uut.adapters.ipfs, 'getPeers').resolves([{ peer: 'badId' }])
const spy1 = sandbox
.stub(uut.adapters.ipfs, 'disconnectFromPeer')
.resolves()
const result = await uut.enforceWhitelist()
// Assert that the method completed.
assert.equal(result, true)
// Assert that disconnectFromPeer() was called.
assert.equal(spy1.called, true)
})
it('should skip ipfs-coord peers', async () => {
await uut.createSelf({ type: 'node.js' })
uut.thisNode.peerData = [
{
from: 'goodId',
data: {
jsonLd: {
name: 'good-name'
}
}
}
]
// Mock dependencies
sandbox.stub(uut.adapters.ipfs, 'getPeers').resolves([{ peer: 'goodId' }])
const spy1 = sandbox
.stub(uut.adapters.ipfs, 'disconnectFromPeer')
.resolves()
const result = await uut.enforceWhitelist()
// Assert that the method completed.
assert.equal(result, true)
// Assert that disconnectFromPeer() was not called.
assert.equal(spy1.called, false)
})
it('should catch and throw errors', async () => {
try {
await uut.enforceWhitelist()
assert.fail('Unexpected code path')
} catch (err) {
// console.log(err)
assert.include(err.message, 'Cannot read')
}
})
})
})