2017-07-04 11:43:45 +01:00
/* eslint-env mocha */
/* eslint max-nested-callbacks: ["error", 8] */
'use strict'
const chai = require ( 'chai' )
chai . use ( require ( 'dirty-chai' ) )
const expect = chai . expect
const parallel = require ( 'async/parallel' )
const _times = require ( 'lodash.times' )
2018-10-19 16:28:28 +02:00
const DelegatedPeerRouter = require ( 'libp2p-delegated-peer-routing' )
const sinon = require ( 'sinon' )
const nock = require ( 'nock' )
2018-06-28 10:06:25 +02:00
const createNode = require ( './utils/create-node' )
2017-07-04 11:43:45 +01:00
describe ( '.peerRouting' , ( ) => {
2018-10-19 16:28:28 +02:00
describe ( 'via the dht' , ( ) => {
let nodeA
let nodeB
let nodeC
let nodeD
let nodeE
before ( 'create the outer ring of connections' , ( done ) => {
const tasks = _times ( 5 , ( ) => ( cb ) => {
2019-01-29 17:57:09 +00:00
createNode ( '/ip4/0.0.0.0/tcp/0' , ( err , node ) => {
2018-10-19 16:28:28 +02:00
expect ( err ) . to . not . exist ( )
node . start ( ( err ) => cb ( err , node ) )
} )
} )
parallel ( tasks , ( err , nodes ) => {
2017-07-04 11:43:45 +01:00
expect ( err ) . to . not . exist ( )
2018-10-19 16:28:28 +02:00
nodeA = nodes [ 0 ]
nodeB = nodes [ 1 ]
nodeC = nodes [ 2 ]
nodeD = nodes [ 3 ]
nodeE = nodes [ 4 ]
parallel ( [
( cb ) => nodeA . dial ( nodeB . peerInfo , cb ) ,
( cb ) => nodeB . dial ( nodeC . peerInfo , cb ) ,
( cb ) => nodeC . dial ( nodeD . peerInfo , cb ) ,
( cb ) => nodeD . dial ( nodeE . peerInfo , cb ) ,
( cb ) => nodeE . dial ( nodeA . peerInfo , cb )
] , ( err ) => {
expect ( err ) . to . not . exist ( )
// Give the kbucket time to fill in the dht
setTimeout ( done , 250 )
} )
2017-07-04 11:43:45 +01:00
} )
} )
2018-10-19 16:28:28 +02:00
after ( ( done ) => {
2017-07-04 11:43:45 +01:00
parallel ( [
2018-10-19 16:28:28 +02:00
( cb ) => nodeA . stop ( cb ) ,
( cb ) => nodeB . stop ( cb ) ,
( cb ) => nodeC . stop ( cb ) ,
( cb ) => nodeD . stop ( cb ) ,
( cb ) => nodeE . stop ( cb )
2017-07-04 11:43:45 +01:00
] , done )
} )
2018-10-19 16:28:28 +02:00
it ( 'should use the nodes dht' , ( done ) => {
const stub = sinon . stub ( nodeA . _dht , 'findPeer' ) . callsFake ( ( ) => {
stub . restore ( )
done ( )
} )
nodeA . peerRouting . findPeer ( )
} )
describe ( 'connected in an el ring' , ( ) => {
it ( 'should be able to find a peer we are not directly connected to' , ( done ) => {
parallel ( [
( cb ) => nodeA . dial ( nodeC . peerInfo . id , cb ) ,
( cb ) => nodeB . dial ( nodeD . peerInfo . id , cb ) ,
( cb ) => nodeC . dial ( nodeE . peerInfo . id , cb )
] , ( err ) => {
if ( err ) throw err
expect ( err ) . to . not . exist ( )
nodeB . peerRouting . findPeer ( nodeE . peerInfo . id , ( err , peerInfo ) => {
expect ( err ) . to . not . exist ( )
expect ( nodeE . peerInfo . id . toB58String ( ) ) . to . equal ( peerInfo . id . toB58String ( ) )
done ( )
} )
} )
} )
} )
2017-07-04 11:43:45 +01:00
} )
2018-10-19 16:28:28 +02:00
describe ( 'via a delegate' , ( ) => {
let nodeA
let delegate
before ( ( done ) => {
parallel ( [
// Create the node using the delegate
( cb ) => {
delegate = new DelegatedPeerRouter ( {
host : 'ipfs.io' ,
protocol : 'https' ,
port : '443'
} )
createNode ( '/ip4/0.0.0.0/tcp/0' , {
modules : {
peerRouting : [ delegate ]
2019-01-29 17:57:09 +00:00
} ,
config : {
dht : {
enabled : false
}
2018-10-19 16:28:28 +02:00
}
} , ( err , node ) => {
expect ( err ) . to . not . exist ( )
nodeA = node
nodeA . start ( cb )
} )
}
] , done )
2017-07-04 11:43:45 +01:00
} )
2018-10-19 16:28:28 +02:00
after ( ( done ) => nodeA . stop ( done ) )
afterEach ( ( ) => nock . cleanAll ( ) )
it ( 'should use the delegate router to find peers' , ( done ) => {
const stub = sinon . stub ( delegate , 'findPeer' ) . callsFake ( ( ) => {
stub . restore ( )
2017-07-04 11:43:45 +01:00
done ( )
} )
2018-10-19 16:28:28 +02:00
nodeA . peerRouting . findPeer ( )
2017-07-04 11:43:45 +01:00
} )
2018-10-19 16:28:28 +02:00
it ( 'should be able to find a peer' , ( done ) => {
const peerKey = 'QmTp9VkYvnHyrqKQuFPiuZkiX9gPcqj6x5LJ1rmWuSySnL'
const mockApi = nock ( 'https://ipfs.io' )
. post ( '/api/v0/dht/findpeer' )
. query ( {
arg : peerKey ,
timeout : '30000ms' ,
'stream-channels' : true
} )
. reply ( 200 , ` {"Extra":"","ID":"some other id","Responses":null,"Type":0} \n {"Extra":"","ID":"","Responses":[{"Addrs":["/ip4/127.0.0.1/tcp/4001"],"ID":" ${ peerKey } "}],"Type":2} \n ` , [
'Content-Type' , 'application/json' ,
'X-Chunked-Output' , '1'
] )
nodeA . peerRouting . findPeer ( peerKey , ( err , peerInfo ) => {
2017-07-04 11:43:45 +01:00
expect ( err ) . to . not . exist ( )
2018-10-19 16:28:28 +02:00
expect ( peerInfo . id . toB58String ( ) ) . to . equal ( peerKey )
expect ( mockApi . isDone ( ) ) . to . equal ( true )
2017-07-04 11:43:45 +01:00
done ( )
} )
} )
2018-10-19 16:28:28 +02:00
it ( 'should error when a peer cannot be found' , ( done ) => {
const peerKey = 'key of a peer not on the network'
const mockApi = nock ( 'https://ipfs.io' )
. post ( '/api/v0/dht/findpeer' )
. query ( {
arg : peerKey ,
timeout : '30000ms' ,
'stream-channels' : true
} )
. reply ( 200 , ` {"Extra":"","ID":"some other id","Responses":null,"Type":6} \n {"Extra":"","ID":"yet another id","Responses":null,"Type":0} \n {"Extra":"routing:not found","ID":"","Responses":null,"Type":3} \n ` , [
'Content-Type' , 'application/json' ,
'X-Chunked-Output' , '1'
] )
nodeA . peerRouting . findPeer ( peerKey , ( err , peerInfo ) => {
expect ( err ) . to . exist ( )
expect ( peerInfo ) . to . not . exist ( )
expect ( mockApi . isDone ( ) ) . to . equal ( true )
2017-07-04 11:43:45 +01:00
done ( )
} )
} )
2018-10-19 16:28:28 +02:00
it ( 'should handle errors from the api' , ( done ) => {
const peerKey = 'key of a peer not on the network'
const mockApi = nock ( 'https://ipfs.io' )
. post ( '/api/v0/dht/findpeer' )
. query ( {
arg : peerKey ,
timeout : '30000ms' ,
'stream-channels' : true
} )
. reply ( 502 )
nodeA . peerRouting . findPeer ( peerKey , ( err , peerInfo ) => {
expect ( err ) . to . exist ( )
expect ( peerInfo ) . to . not . exist ( )
expect ( mockApi . isDone ( ) ) . to . equal ( true )
2017-07-04 11:43:45 +01:00
done ( )
} )
} )
} )
2018-10-19 16:28:28 +02:00
describe ( 'via the dht and a delegate' , ( ) => {
let nodeA
let delegate
before ( ( done ) => {
parallel ( [
// Create the node using the delegate
( cb ) => {
delegate = new DelegatedPeerRouter ( {
host : 'ipfs.io' ,
protocol : 'https' ,
port : '443'
} )
createNode ( '/ip4/0.0.0.0/tcp/0' , {
modules : {
peerRouting : [ delegate ]
}
} , ( err , node ) => {
expect ( err ) . to . not . exist ( )
nodeA = node
nodeA . start ( cb )
} )
}
] , done )
} )
after ( ( done ) => nodeA . stop ( done ) )
describe ( 'findPeer' , ( ) => {
it ( 'should only use the dht if it finds the peer' , ( done ) => {
const results = [ true ]
const dhtStub = sinon . stub ( nodeA . _dht , 'findPeer' ) . callsArgWith ( 2 , null , results )
const delegateStub = sinon . stub ( delegate , 'findPeer' ) . throws ( ( ) => {
return new Error ( 'the delegate should not have been called' )
} )
nodeA . peerRouting . findPeer ( 'a peer id' , ( err , results ) => {
expect ( err ) . to . not . exist ( )
expect ( results ) . to . equal ( results )
expect ( dhtStub . calledOnce ) . to . equal ( true )
expect ( delegateStub . notCalled ) . to . equal ( true )
delegateStub . restore ( )
dhtStub . restore ( )
done ( )
} )
} )
it ( 'should use the delegate if the dht fails to find the peer' , ( done ) => {
const results = [ true ]
const dhtStub = sinon . stub ( nodeA . _dht , 'findPeer' ) . callsArgWith ( 2 , null , undefined )
const delegateStub = sinon . stub ( delegate , 'findPeer' ) . callsArgWith ( 2 , null , results )
nodeA . peerRouting . findPeer ( 'a peer id' , ( err , results ) => {
expect ( err ) . to . not . exist ( )
expect ( results ) . to . deep . equal ( results )
expect ( dhtStub . calledOnce ) . to . equal ( true )
expect ( delegateStub . calledOnce ) . to . equal ( true )
delegateStub . restore ( )
dhtStub . restore ( )
done ( )
} )
} )
} )
} )
2018-11-05 13:56:45 +01:00
describe ( 'no routers' , ( ) => {
let nodeA
before ( ( done ) => {
2019-01-29 17:57:09 +00:00
createNode ( '/ip4/0.0.0.0/tcp/0' , {
config : {
dht : {
enabled : false
}
}
} , ( err , node ) => {
2018-11-05 13:56:45 +01:00
expect ( err ) . to . not . exist ( )
nodeA = node
done ( )
} )
} )
it ( '.findPeer should return an error with no options' , ( done ) => {
nodeA . peerRouting . findPeer ( 'a cid' , ( err ) => {
expect ( err ) . to . exist ( )
done ( )
} )
} )
it ( '.findPeer should return an error with options' , ( done ) => {
nodeA . peerRouting . findPeer ( 'a cid' , { maxTimeout : 5000 } , ( err ) => {
expect ( err ) . to . exist ( )
done ( )
} )
} )
} )
2017-07-04 11:43:45 +01:00
} )