diff --git a/package.json b/package.json index 10ebc0b3..5df408df 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,6 @@ "protons": "^1.0.1", "pull-length-prefixed": "^1.3.0", "pull-stream": "^3.6.2", - "safe-buffer": "^5.1.1", "varint": "^5.0.0", "xor-distance": "^1.0.0" }, @@ -66,7 +65,7 @@ "datastore-level": "~0.7.0", "dirty-chai": "^2.0.1", "interface-connection": "~0.3.2", - "libp2p-multiplex": "~0.5.1", + "libp2p-mplex": "~0.6.0", "libp2p-switch": "~0.37.0", "libp2p-tcp": "~0.11.6", "lodash": "^4.17.5", diff --git a/src/rpc/handlers/find-node.js b/src/rpc/handlers/find-node.js index a0829a37..af2e286d 100644 --- a/src/rpc/handlers/find-node.js +++ b/src/rpc/handlers/find-node.js @@ -4,7 +4,6 @@ const waterfall = require('async/waterfall') const Message = require('../../message') const utils = require('../../utils') -const Buffer = require('safe-buffer').Buffer module.exports = (dht) => { const log = utils.logger(dht.peerInfo.id, 'rpc:find-node') diff --git a/test/kad-dht.spec.js b/test/kad-dht.spec.js index bcd4fd0b..65328500 100644 --- a/test/kad-dht.spec.js +++ b/test/kad-dht.spec.js @@ -12,22 +12,97 @@ const retry = require('async/retry') const each = require('async/each') const waterfall = require('async/waterfall') const random = require('lodash.random') -const Buffer = require('safe-buffer').Buffer const _ = require('lodash') const Record = require('libp2p-record').Record const PeerBook = require('peer-book') const Switch = require('libp2p-switch') const TCP = require('libp2p-tcp') -const Multiplex = require('libp2p-multiplex') +const Mplex = require('libp2p-mplex') const KadDHT = require('../src') const kadUtils = require('../src/utils') const c = require('../src/constants') -const utils = require('./utils') -const makePeers = utils.makePeers -const setupDHT = utils.setupDHT -const makeValues = utils.makeValues +const createPeerInfo = require('./utils/create-peer-info') +const createValues = require('./utils/create-values') +const TestDHT = require('./utils/test-dht') + +// connect two dhts +function connectNoSync (a, b, callback) { + const target = _.cloneDeep(b.peerInfo) + target.id._pubKey = target.id.pubKey + target.id._privKey = null + a.switch.dial(target, callback) +} + +function find (a, b, cb) { + retry({ times: 50, interval: 100 }, (cb) => { + a.routingTable.find(b.peerInfo.id, (err, match) => { + if (err) { + return cb(err) + } + if (!match) { + return cb(new Error('not found')) + } + + try { + expect(a.peerBook.get(b.peerInfo).multiaddrs.toArray()[0].toString()) + .to.eql(b.peerInfo.multiaddrs.toArray()[0].toString()) + } catch (err) { + return cb(err) + } + + cb() + }) + }, cb) +} + +// connect two dhts and wait for them to have each other +// in their routing table +function connect (a, b, callback) { + series([ + (cb) => connectNoSync(a, b, cb), + (cb) => find(a, b, cb), + (cb) => find(b, a, cb) + ], (err) => callback(err)) +} + +function bootstrap (dhts) { + dhts.forEach((dht) => { + dht._bootstrap(3, 10000) + }) +} + +function waitForWellFormedTables (dhts, minPeers, avgPeers, maxTimeout, callback) { + timeout((cb) => { + retry({ times: 50, interval: 200 }, (cb) => { + let totalPeers = 0 + + const ready = dhts.map((dht) => { + const rtlen = dht.routingTable.size + totalPeers += rtlen + if (minPeers > 0 && rtlen < minPeers) { + return false + } + const actualAvgPeers = totalPeers / dhts.length + if (avgPeers > 0 && actualAvgPeers < avgPeers) { + return false + } + return true + }) + + const done = ready.every(Boolean) + cb(done ? null : new Error('not done yet')) + }, cb) + }, maxTimeout)(callback) +} + +function countDiffPeers (a, b) { + const s = new Set() + a.forEach((p) => s.add(p.toB58String())) + + return b.filter((p) => !s.has(p.toB58String())).length +} describe('KadDHT', () => { let peerInfos @@ -37,8 +112,8 @@ describe('KadDHT', () => { this.timeout(10 * 1000) parallel([ - (cb) => makePeers(3, cb), - (cb) => makeValues(20, cb) + (cb) => createPeerInfo(3, cb), + (cb) => createValues(20, cb) ], (err, res) => { expect(err).to.not.exist() peerInfos = res[0] @@ -47,17 +122,10 @@ describe('KadDHT', () => { }) }) - // Give the nodes some time to finish request - afterEach(function (done) { - this.timeout(10 * 1000) - - utils.teardown(done) - }) - it('create', () => { const sw = new Switch(peerInfos[0], new PeerBook()) sw.transport.add('tcp', new TCP()) - sw.connection.addStreamMuxer(Multiplex) + sw.connection.addStreamMuxer(Mplex) sw.connection.reuse() const dht = new KadDHT(sw, { kBucketSize: 5 }) @@ -69,8 +137,9 @@ describe('KadDHT', () => { it('put - get', function (done) { this.timeout(10 * 1000) + const tdht = new TestDHT() - times(2, (i, cb) => setupDHT(cb), (err, dhts) => { + tdht.spawn(2, (err, dhts) => { expect(err).to.not.exist() const dhtA = dhts[0] const dhtB = dhts[1] @@ -83,16 +152,24 @@ describe('KadDHT', () => { expect(res).to.eql(Buffer.from('world')) cb() } - ], done) + ], (err) => { + expect(err).to.not.exist() + tdht.teardown(done) + }) }) }) it('provides', function (done) { this.timeout(20 * 1000) - setupDHTs(4, (err, dhts, addrs, ids) => { + const tdht = new TestDHT() + + tdht.spawn(4, (err, dhts) => { expect(err).to.not.exist() - waterfall([ + const addrs = dhts.map((d) => d.peerInfo.multiaddrs.toArray()[0]) + const ids = dhts.map((d) => d.peerInfo.id) + + series([ (cb) => connect(dhts[0], dhts[1], cb), (cb) => connect(dhts[1], dhts[2], cb), (cb) => connect(dhts[2], dhts[3], cb), @@ -109,26 +186,30 @@ describe('KadDHT', () => { expect(provs[0].id.id).to.be.eql(ids[3].id) expect( provs[0].multiaddrs.toArray()[0].toString() - ).to.be.eql( + ).to.equal( addrs[3].toString() ) cb() }) }, cb) } - ], done) + ], (err) => { + expect(err).to.not.exist() + tdht.teardown(done) + }) }) }) - it('bootstrap', function (done) { + it('random-walk', function (done) { this.timeout(40 * 1000) const nDHTs = 20 + const tdht = new TestDHT() - setupDHTs(nDHTs, (err, dhts) => { + tdht.spawn(nDHTs, (err, dhts) => { expect(err).to.not.exist() - waterfall([ + series([ // ring connect (cb) => times(nDHTs, (i, cb) => { connect(dhts[i], dhts[(i + 1) % nDHTs], cb) @@ -138,14 +219,20 @@ describe('KadDHT', () => { waitForWellFormedTables(dhts, 7, 0, 20 * 1000, cb) cb() } - ], done) + ], (err) => { + expect(err).to.not.exist() + tdht.teardown(done) + }) }) }) it('layered get', function (done) { this.timeout(40 * 1000) - setupDHTs(4, (err, dhts) => { + const nDHTs = 4 + const tdht = new TestDHT() + + tdht.spawn(nDHTs, (err, dhts) => { expect(err).to.not.exist() waterfall([ @@ -153,25 +240,33 @@ describe('KadDHT', () => { (cb) => connect(dhts[1], dhts[2], cb), (cb) => connect(dhts[2], dhts[3], cb), (cb) => dhts[3].put( - new Buffer('/v/hello'), - new Buffer('world'), + Buffer.from('/v/hello'), + Buffer.from('world'), cb ), - (cb) => dhts[0].get(new Buffer('/v/hello'), 1000, cb), + (cb) => dhts[0].get(Buffer.from('/v/hello'), 1000, cb), (res, cb) => { - expect(res).to.be.eql(new Buffer('world')) + expect(res).to.eql(Buffer.from('world')) cb() } - ], done) + ], (err) => { + expect(err).to.not.exist() + tdht.teardown(done) + }) }) }) it.skip('findPeer', function (done) { this.timeout(40 * 1000) - setupDHTs(4, (err, dhts, addrs, ids) => { + const nDHTs = 4 + const tdht = new TestDHT() + + tdht.spawn(nDHTs, (err, dhts) => { expect(err).to.not.exist() + const ids = dhts.map((d) => d.peerInfo.id) + waterfall([ (cb) => connect(dhts[0], dhts[1], cb), (cb) => connect(dhts[1], dhts[2], cb), @@ -181,17 +276,20 @@ describe('KadDHT', () => { expect(res.id.isEqual(ids[3])).to.eql(true) cb() } - ], done) + ], (err) => { + expect(err).to.not.exist() + tdht.teardown(done) + }) }) }) it('connect by id to with address in the peerbook ', function (done) { this.timeout(20 * 1000) - parallel([ - (cb) => setupDHT(cb), - (cb) => setupDHT(cb) - ], (err, dhts) => { + const nDHTs = 2 + const tdht = new TestDHT() + + tdht.spawn(nDHTs, (err, dhts) => { expect(err).to.not.exist() const dhtA = dhts[0] const dhtB = dhts[1] @@ -204,7 +302,10 @@ describe('KadDHT', () => { parallel([ (cb) => dhtA.switch.dial(peerB.id, cb), (cb) => dhtB.switch.dial(peerA.id, cb) - ], done) + ], (err) => { + expect(err).to.not.exist() + tdht.teardown(done) + }) }) }) @@ -212,9 +313,14 @@ describe('KadDHT', () => { it.skip('find peer query', function (done) { this.timeout(40 * 1000) - setupDHTs(101, (err, dhts, addrs, ids) => { + const nDHTs = 101 + const tdht = new TestDHT() + + tdht.spawn(nDHTs, (err, dhts) => { expect(err).to.not.exist() + const ids = dhts.map((d) => d.peerInfo.id) + const guy = dhts[0] const others = dhts.slice(1) const val = Buffer.from('foobar') @@ -264,7 +370,10 @@ describe('KadDHT', () => { }) }) }) - ], done) + ], (err) => { + expect(err).to.not.exist() + tdht.teardown(done) + }) }) }) @@ -272,7 +381,9 @@ describe('KadDHT', () => { this.timeout(40 * 1000) const nDHTs = 30 - setupDHTs(nDHTs, (err, dhts) => { + const tdht = new TestDHT() + + tdht.spawn(nDHTs, (err, dhts) => { expect(err).to.not.exist() // ring connect @@ -284,7 +395,7 @@ describe('KadDHT', () => { ], (err, res) => { expect(err).to.not.exist() expect(res[1]).to.have.length(c.K) - done() + tdht.teardown(done) }) }) }) @@ -293,13 +404,19 @@ describe('KadDHT', () => { it('already known', function (done) { this.timeout(20 * 1000) - setupDHTs(2, (err, dhts, addrs, ids) => { + const nDHTs = 2 + const tdht = new TestDHT() + + tdht.spawn(nDHTs, (err, dhts) => { expect(err).to.not.exist() + + const ids = dhts.map((d) => d.peerInfo.id) + dhts[0].peerBook.put(dhts[1].peerInfo) dhts[0].getPublicKey(ids[1], (err, key) => { expect(err).to.not.exist() expect(key).to.be.eql(dhts[1].peerInfo.id.pubKey) - done() + tdht.teardown(done) }) }) }) @@ -307,9 +424,14 @@ describe('KadDHT', () => { it('connected node', function (done) { this.timeout(40 * 1000) - setupDHTs(2, (err, dhts, addrs, ids) => { + const nDHTs = 2 + const tdht = new TestDHT() + + tdht.spawn(nDHTs, (err, dhts) => { expect(err).to.not.exist() + const ids = dhts.map((d) => d.peerInfo.id) + waterfall([ (cb) => connect(dhts[0], dhts[1], cb), (cb) => { @@ -323,7 +445,10 @@ describe('KadDHT', () => { expect(key.equals(dhts[1].peerInfo.id.pubKey)).to.eql(true) cb() } - ], done) + ], (err) => { + expect(err).to.not.exist() + tdht.teardown(done) + }) }) }) }) @@ -331,7 +456,7 @@ describe('KadDHT', () => { it('_nearestPeersToQuery', (done) => { const sw = new Switch(peerInfos[0], new PeerBook()) sw.transport.add('tcp', new TCP()) - sw.connection.addStreamMuxer(Multiplex) + sw.connection.addStreamMuxer(Mplex) sw.connection.reuse() const dht = new KadDHT(sw) @@ -349,7 +474,7 @@ describe('KadDHT', () => { it('_betterPeersToQuery', (done) => { const sw = new Switch(peerInfos[0], new PeerBook()) sw.transport.add('tcp', new TCP()) - sw.connection.addStreamMuxer(Multiplex) + sw.connection.addStreamMuxer(Mplex) sw.connection.reuse() const dht = new KadDHT(sw) @@ -371,7 +496,7 @@ describe('KadDHT', () => { it('invalid record (missing public key)', (done) => { const sw = new Switch(peerInfos[0], new PeerBook()) sw.transport.add('tcp', new TCP()) - sw.connection.addStreamMuxer(Multiplex) + sw.connection.addStreamMuxer(Mplex) sw.connection.reuse() const dht = new KadDHT(sw) @@ -396,7 +521,7 @@ describe('KadDHT', () => { it('valid record - signed', (done) => { const sw = new Switch(peerInfos[0], new PeerBook()) sw.transport.add('tcp', new TCP()) - sw.connection.addStreamMuxer(Multiplex) + sw.connection.addStreamMuxer(Mplex) sw.connection.reuse() const dht = new KadDHT(sw) @@ -417,7 +542,7 @@ describe('KadDHT', () => { it('valid record - not signed', (done) => { const sw = new Switch(peerInfos[0], new PeerBook()) sw.transport.add('tcp', new TCP()) - sw.connection.addStreamMuxer(Multiplex) + sw.connection.addStreamMuxer(Mplex) sw.connection.reuse() const dht = new KadDHT(sw) @@ -436,89 +561,3 @@ describe('KadDHT', () => { }) }) }) - -function setupDHTs (n, callback) { - times(n, (i, cb) => setupDHT(cb), (err, dhts) => { - if (err) { - return callback(err) - } - callback(null, dhts, dhts.map((d) => d.peerInfo.multiaddrs.toArray()[0]), dhts.map((d) => d.peerInfo.id)) - }) -} - -// connect two dhts -function connectNoSync (a, b, callback) { - const target = _.cloneDeep(b.peerInfo) - target.id._pubKey = target.id.pubKey - target.id._privKey = null - a.switch.dial(target, callback) -} - -function find (a, b, cb) { - retry({ times: 50, interval: 100 }, (cb) => { - a.routingTable.find(b.peerInfo.id, (err, match) => { - if (err) { - return cb(err) - } - if (!match) { - return cb(new Error('not found')) - } - - try { - expect(a.peerBook.get(b.peerInfo).multiaddrs.toArray()[0].toString()) - .to.eql(b.peerInfo.multiaddrs.toArray()[0].toString()) - } catch (err) { - return cb(err) - } - - cb() - }) - }, cb) -} - -// connect two dhts and wait for them to have each other -// in their routing table -function connect (a, b, callback) { - series([ - (cb) => connectNoSync(a, b, cb), - (cb) => find(a, b, cb), - (cb) => find(b, a, cb) - ], (err) => callback(err)) -} - -function bootstrap (dhts) { - dhts.forEach((dht) => { - dht._bootstrap(3, 10000) - }) -} - -function waitForWellFormedTables (dhts, minPeers, avgPeers, maxTimeout, callback) { - timeout((cb) => { - retry({ times: 50, interval: 200 }, (cb) => { - let totalPeers = 0 - - const ready = dhts.map((dht) => { - const rtlen = dht.routingTable.size - totalPeers += rtlen - if (minPeers > 0 && rtlen < minPeers) { - return false - } - const actualAvgPeers = totalPeers / dhts.length - if (avgPeers > 0 && actualAvgPeers < avgPeers) { - return false - } - return true - }) - - const done = ready.every(Boolean) - cb(done ? null : new Error('not done yet')) - }, cb) - }, maxTimeout)(callback) -} - -function countDiffPeers (a, b) { - const s = new Set() - a.forEach((p) => s.add(p.toB58String())) - - return b.filter((p) => !s.has(p.toB58String())).length -} diff --git a/test/utils.spec.js b/test/kad-utils.spec.js similarity index 91% rename from test/utils.spec.js rename to test/kad-utils.spec.js index 46ef1f7e..59a8d81b 100644 --- a/test/utils.spec.js +++ b/test/kad-utils.spec.js @@ -10,9 +10,9 @@ const distance = require('xor-distance') const waterfall = require('async/waterfall') const utils = require('../src/utils') -const makePeers = require('./utils').makePeers +const createPeerInfo = require('./utils/create-peer-info') -describe('utils', () => { +describe('kad utils', () => { describe('bufferToKey', () => { it('returns the base32 encoded key of the buffer', () => { const buf = Buffer.from('hello world') @@ -20,11 +20,8 @@ describe('utils', () => { const key = utils.bufferToKey(buf) const enc = new base32.Encoder() - expect( - key.toString() - ).to.be.eql( - '/' + enc.write(buf).finalize() - ) + expect(key.toString()) + .to.equal('/' + enc.write(buf).finalize()) }) }) @@ -68,7 +65,7 @@ describe('utils', () => { (out, cb) => { expect( out.map((m) => m.toB58String()) - ).to.be.eql([ + ).to.eql([ ids[0], ids[3], ids[2], @@ -98,7 +95,7 @@ describe('utils', () => { describe('keyForPublicKey', () => { it('works', (done) => { - makePeers(1, (err, peers) => { + createPeerInfo(1, (err, peers) => { expect(err).to.not.exist() expect(utils.keyForPublicKey(peers[0].id)) @@ -112,7 +109,7 @@ describe('utils', () => { it('round trips', function (done) { this.timeout(40 * 1000) - makePeers(50, (err, peers) => { + createPeerInfo(50, (err, peers) => { expect(err).to.not.exist() peers.forEach((p, i) => { diff --git a/test/limited-peer-list.spec.js b/test/limited-peer-list.spec.js index 89ff9bd2..fbbf2210 100644 --- a/test/limited-peer-list.spec.js +++ b/test/limited-peer-list.spec.js @@ -7,7 +7,7 @@ const expect = chai.expect const LimitedPeerList = require('../src/limited-peer-list') -const makePeers = require('./utils').makePeers +const createPeerInfo = require('./utils/create-peer-info') describe('LimitedPeerList', () => { let peers @@ -15,7 +15,7 @@ describe('LimitedPeerList', () => { before(function (done) { this.timeout(10 * 1000) - makePeers(5, (err, p) => { + createPeerInfo(5, (err, p) => { if (err) { return done(err) } diff --git a/test/message.spec.js b/test/message.spec.js index eb719ff4..9bb9fa18 100644 --- a/test/message.spec.js +++ b/test/message.spec.js @@ -64,7 +64,7 @@ describe('Message', () => { expect(dec.key).to.be.eql(msg.key) expect(dec.clusterLevel).to.be.eql(msg.clusterLevel) expect(dec.record.serialize()).to.be.eql(record.serialize()) - expect(dec.record.key).to.be.eql(Buffer.from('hello')) + expect(dec.record.key).to.eql(Buffer.from('hello')) expect(dec.closerPeers).to.have.length(5) dec.closerPeers.forEach((peer, i) => { diff --git a/test/network.spec.js b/test/network.spec.js index 1eea00c5..300a65e0 100644 --- a/test/network.spec.js +++ b/test/network.spec.js @@ -12,12 +12,12 @@ const Buffer = require('safe-buffer').Buffer const PeerBook = require('peer-book') const Switch = require('libp2p-switch') const TCP = require('libp2p-tcp') -const Multiplex = require('libp2p-multiplex') +const Mplex = require('libp2p-mplex') const KadDHT = require('../src') const Message = require('../src/message') -const makePeers = require('./utils').makePeers +const createPeerInfo = require('./utils/create-peer-info') describe('Network', () => { let dht @@ -25,7 +25,7 @@ describe('Network', () => { before(function (done) { this.timeout(10 * 1000) - makePeers(3, (err, result) => { + createPeerInfo(3, (err, result) => { if (err) { return done(err) } @@ -33,7 +33,7 @@ describe('Network', () => { peerInfos = result const sw = new Switch(peerInfos[0], new PeerBook()) sw.transport.add('tcp', new TCP()) - sw.connection.addStreamMuxer(Multiplex) + sw.connection.addStreamMuxer(Mplex) sw.connection.reuse() dht = new KadDHT(sw) diff --git a/test/peer-list.spec.js b/test/peer-list.spec.js index 77708dcd..8deb5c2c 100644 --- a/test/peer-list.spec.js +++ b/test/peer-list.spec.js @@ -7,13 +7,13 @@ const expect = chai.expect const PeerList = require('../src/peer-list') -const makePeers = require('./utils').makePeers +const createPeerInfo = require('./utils/create-peer-info') describe('PeerList', () => { let peers before((done) => { - makePeers(3, (err, p) => { + createPeerInfo(3, (err, p) => { if (err) { return done(err) } diff --git a/test/providers.spec.js b/test/providers.spec.js index d0154d10..a7618a9b 100644 --- a/test/providers.spec.js +++ b/test/providers.spec.js @@ -17,18 +17,18 @@ const range = require('lodash.range') const LevelStore = require('datastore-level') const path = require('path') const os = require('os') -const Buffer = require('safe-buffer').Buffer const Providers = require('../src/providers') -const util = require('./utils') +const createPeerInfo = require('./utils/create-peer-info') +const createValues = require('./utils/create-values') describe('Providers', () => { let infos before(function (done) { this.timeout(10 * 1000) - util.makePeers(3, (err, peers) => { + createPeerInfo(3, (err, peers) => { if (err) { return done(err) } @@ -131,8 +131,8 @@ describe('Providers', () => { console.log('starting') waterfall([ (cb) => parallel([ - (cb) => util.makeValues(100, cb), - (cb) => util.makePeers(600, cb) + (cb) => createValues(100, cb), + (cb) => createPeerInfo(600, cb) ], cb), (res, cb) => { console.log('got values and peers') diff --git a/test/query.spec.js b/test/query.spec.js index 46e196dd..acd3f7fe 100644 --- a/test/query.spec.js +++ b/test/query.spec.js @@ -4,16 +4,15 @@ const chai = require('chai') chai.use(require('dirty-chai')) const expect = chai.expect -const Buffer = require('safe-buffer').Buffer const PeerBook = require('peer-book') const Switch = require('libp2p-switch') const TCP = require('libp2p-tcp') -const Multiplex = require('libp2p-multiplex') +const Mplex = require('libp2p-mplex') const DHT = require('../src') const Query = require('../src/query') -const makePeers = require('./utils').makePeers +const createPeerInfo = require('./utils/create-peer-info') describe('Query', () => { let peerInfos @@ -21,7 +20,7 @@ describe('Query', () => { before(function (done) { this.timeout(5 * 1000) - makePeers(3, (err, result) => { + createPeerInfo(3, (err, result) => { if (err) { return done(err) } @@ -29,7 +28,7 @@ describe('Query', () => { peerInfos = result const sw = new Switch(peerInfos[0], new PeerBook()) sw.transport.add('tcp', new TCP()) - sw.connection.addStreamMuxer(Multiplex) + sw.connection.addStreamMuxer(Mplex) sw.connection.reuse() dht = new DHT(sw) diff --git a/test/routing.spec.js b/test/routing.spec.js index 87a11f32..79a085f6 100644 --- a/test/routing.spec.js +++ b/test/routing.spec.js @@ -7,15 +7,15 @@ const expect = chai.expect const PeerId = require('peer-id') const map = require('async/map') const each = require('async/each') -const waterfall = require('async/waterfall') +const series = require('async/series') const range = require('lodash.range') const random = require('lodash.random') const RoutingTable = require('../src/routing') -const utils = require('../src/utils') +const kadUtils = require('../src/utils') -function createPeers (n, callback) { - map(range(n), (i, cb) => PeerId.create({bits: 1024}, cb), callback) +function createPeerId (n, callback) { + map(range(n), (i, cb) => PeerId.create({bits: 512}, cb), callback) } describe('Routing Table', () => { @@ -24,7 +24,7 @@ describe('Routing Table', () => { beforeEach(function (done) { this.timeout(20 * 1000) - PeerId.create((err, id) => { + PeerId.create({ bits: 512 }, (err, id) => { expect(err).to.not.exist() table = new RoutingTable(id, 20) done() @@ -34,17 +34,17 @@ describe('Routing Table', () => { it('add', function (done) { this.timeout(20 * 1000) - createPeers(20, (err, peers) => { + createPeerId(20, (err, ids) => { expect(err).to.not.exist() - waterfall([ + series([ (cb) => each(range(1000), (n, cb) => { - table.add(peers[random(peers.length - 1)], cb) + table.add(ids[random(ids.length - 1)], cb) }, cb), (cb) => each(range(20), (n, cb) => { - const id = peers[random(peers.length - 1)] + const id = ids[random(ids.length - 1)] - utils.convertPeerId(id, (err, key) => { + kadUtils.convertPeerId(id, (err, key) => { expect(err).to.not.exist() expect(table.closestPeers(key, 5).length) .to.be.above(0) @@ -55,19 +55,18 @@ describe('Routing Table', () => { }) }) - // TODO fix a callback that is being called twice, making this test fail - it.skip('remove', function (done) { + it('remove', function (done) { this.timeout(20 * 1000) - createPeers(10, (err, peers) => { + createPeerId(10, (err, peers) => { expect(err).to.not.exist() let k - waterfall([ + series([ (cb) => each(peers, (peer, cbEach) => table.add(peer, cbEach), cb), (cb) => { const id = peers[2] - utils.convertPeerId(id, (err, key) => { + kadUtils.convertPeerId(id, (err, key) => { expect(err).to.not.exist() k = key expect(table.closestPeers(key, 10)).to.have.length(10) @@ -87,13 +86,13 @@ describe('Routing Table', () => { it('closestPeer', function (done) { this.timeout(10 * 1000) - createPeers(4, (err, peers) => { + createPeerId(4, (err, peers) => { expect(err).to.not.exist() - waterfall([ + series([ (cb) => each(peers, (peer, cb) => table.add(peer, cb), cb), (cb) => { const id = peers[2] - utils.convertPeerId(id, (err, key) => { + kadUtils.convertPeerId(id, (err, key) => { expect(err).to.not.exist() expect(table.closestPeer(key)).to.eql(id) cb() @@ -103,17 +102,16 @@ describe('Routing Table', () => { }) }) - // TODO fix a callback that is being called twice, making this test fail - it.skip('closestPeers', function (done) { + it('closestPeers', function (done) { this.timeout(20 * 1000) - createPeers(18, (err, peers) => { + createPeerId(18, (err, peers) => { expect(err).to.not.exist() - waterfall([ + series([ (cb) => each(peers, (peer, cb) => table.add(peer, cb), cb), (cb) => { const id = peers[2] - utils.convertPeerId(id, (err, key) => { + kadUtils.convertPeerId(id, (err, key) => { expect(err).to.not.exist() expect(table.closestPeers(key, 15)).to.have.length(15) cb() diff --git a/test/rpc/handlers/add-provider.spec.js b/test/rpc/handlers/add-provider.spec.js index 8336b3f7..fa9fa4d2 100644 --- a/test/rpc/handlers/add-provider.spec.js +++ b/test/rpc/handlers/add-provider.spec.js @@ -8,21 +8,24 @@ const expect = chai.expect const parallel = require('async/parallel') const waterfall = require('async/waterfall') const _ = require('lodash') -const Buffer = require('safe-buffer').Buffer const Message = require('../../../src/message') const handler = require('../../../src/rpc/handlers/add-provider') -const util = require('../../utils') + +const createPeerInfo = require('../../utils/create-peer-info') +const createValues = require('../../utils/create-values') +const TestDHT = require('../../utils/test-dht') describe('rpc - handlers - AddProvider', () => { let peers let values + let tdht let dht before((done) => { parallel([ - (cb) => util.makePeers(3, cb), - (cb) => util.makeValues(2, cb) + (cb) => createPeerInfo(3, cb), + (cb) => createValues(2, cb) ], (err, res) => { expect(err).to.not.exist() peers = res[0] @@ -31,16 +34,20 @@ describe('rpc - handlers - AddProvider', () => { }) }) - afterEach((done) => util.teardown(done)) - beforeEach((done) => { - util.setupDHT((err, res) => { + tdht = new TestDHT() + + tdht.spawn(1, (err, dhts) => { expect(err).to.not.exist() - dht = res + dht = dhts[0] done() }) }) + afterEach((done) => { + tdht.teardown(done) + }) + describe('invalid messages', () => { const tests = [{ message: new Message(Message.TYPES.ADD_PROVIDER, Buffer.alloc(0), 0), @@ -103,9 +110,7 @@ describe('rpc - handlers - AddProvider', () => { (provs, cb) => { expect(provs).to.have.length(1) expect(provs[0].id).to.eql(sender.id.id) - expect( - dht.peerBook.has(sender.id) - ).to.be.eql(false) + expect(dht.peerBook.has(sender.id)).to.equal(false) cb() } ], done) diff --git a/test/rpc/handlers/find-node.spec.js b/test/rpc/handlers/find-node.spec.js index 16448dda..985a794b 100644 --- a/test/rpc/handlers/find-node.spec.js +++ b/test/rpc/handlers/find-node.spec.js @@ -5,36 +5,43 @@ const chai = require('chai') chai.use(require('dirty-chai')) const expect = chai.expect const waterfall = require('async/waterfall') -const Buffer = require('safe-buffer').Buffer const Message = require('../../../src/message') const handler = require('../../../src/rpc/handlers/find-node') -const util = require('../../utils') const T = Message.TYPES.FIND_NODE +const createPeerInfo = require('../../utils/create-peer-info') +// const createValues = require('../../utils/create-values') +const TestDHT = require('../../utils/test-dht') + describe('rpc - handlers - FindNode', () => { let peers + let tdht let dht before((done) => { - util.makePeers(3, (err, res) => { + createPeerInfo(3, (err, res) => { expect(err).to.not.exist() peers = res done() }) }) - afterEach((done) => util.teardown(done)) - beforeEach((done) => { - util.setupDHT((err, res) => { + tdht = new TestDHT() + + tdht.spawn(1, (err, dhts) => { expect(err).to.not.exist() - dht = res + dht = dhts[0] done() }) }) + afterEach((done) => { + tdht.teardown(done) + }) + it('returns self, if asked for self', (done) => { const msg = new Message(T, dht.peerInfo.id.id, 0) diff --git a/test/rpc/handlers/get-providers.spec.js b/test/rpc/handlers/get-providers.spec.js index 89805383..48e77822 100644 --- a/test/rpc/handlers/get-providers.spec.js +++ b/test/rpc/handlers/get-providers.spec.js @@ -6,24 +6,27 @@ chai.use(require('dirty-chai')) const expect = chai.expect const parallel = require('async/parallel') const waterfall = require('async/waterfall') -const Buffer = require('safe-buffer').Buffer const Message = require('../../../src/message') const utils = require('../../../src/utils') const handler = require('../../../src/rpc/handlers/get-providers') -const util = require('../../utils') const T = Message.TYPES.GET_PROVIDERS +const createPeerInfo = require('../../utils/create-peer-info') +const createValues = require('../../utils/create-values') +const TestDHT = require('../../utils/test-dht') + describe('rpc - handlers - GetProviders', () => { let peers let values + let tdht let dht before((done) => { parallel([ - (cb) => util.makePeers(3, cb), - (cb) => util.makeValues(2, cb) + (cb) => createPeerInfo(3, cb), + (cb) => createValues(2, cb) ], (err, res) => { expect(err).to.not.exist() peers = res[0] @@ -32,16 +35,20 @@ describe('rpc - handlers - GetProviders', () => { }) }) - afterEach((done) => util.teardown(done)) - beforeEach((done) => { - util.setupDHT((err, res) => { + tdht = new TestDHT() + + tdht.spawn(1, (err, dhts) => { expect(err).to.not.exist() - dht = res + dht = dhts[0] done() }) }) + afterEach((done) => { + tdht.teardown(done) + }) + it('errors with an invalid key ', (done) => { const msg = new Message(T, Buffer.from('hello'), 0) diff --git a/test/rpc/handlers/get-value.spec.js b/test/rpc/handlers/get-value.spec.js index bfc61737..48e682cd 100644 --- a/test/rpc/handlers/get-value.spec.js +++ b/test/rpc/handlers/get-value.spec.js @@ -5,36 +5,43 @@ const chai = require('chai') chai.use(require('dirty-chai')) const expect = chai.expect const waterfall = require('async/waterfall') -const Buffer = require('safe-buffer').Buffer const Message = require('../../../src/message') const handler = require('../../../src/rpc/handlers/get-value') const utils = require('../../../src/utils') -const util = require('../../utils') const T = Message.TYPES.GET_VALUE +const createPeerInfo = require('../../utils/create-peer-info') +// const createValues = require('../../utils/create-values') +const TestDHT = require('../../utils/test-dht') + describe('rpc - handlers - GetValue', () => { let peers + let tdht let dht before((done) => { - util.makePeers(2, (err, res) => { + createPeerInfo(2, (err, res) => { expect(err).to.not.exist() peers = res done() }) }) - afterEach((done) => util.teardown(done)) - beforeEach((done) => { - util.setupDHT((err, res) => { + tdht = new TestDHT() + + tdht.spawn(1, (err, dhts) => { expect(err).to.not.exist() - dht = res + dht = dhts[0] done() }) }) + afterEach((done) => { + tdht.teardown(done) + }) + it('errors when missing key', (done) => { const msg = new Message(T, Buffer.alloc(0), 0) diff --git a/test/rpc/handlers/ping.spec.js b/test/rpc/handlers/ping.spec.js index b1558583..f8c7d45f 100644 --- a/test/rpc/handlers/ping.spec.js +++ b/test/rpc/handlers/ping.spec.js @@ -4,36 +4,41 @@ const chai = require('chai') chai.use(require('dirty-chai')) const expect = chai.expect -const Buffer = require('safe-buffer').Buffer const Message = require('../../../src/message') const handler = require('../../../src/rpc/handlers/ping') -const util = require('../../utils') - const T = Message.TYPES.PING +const createPeerInfo = require('../../utils/create-peer-info') +const TestDHT = require('../../utils/test-dht') + describe('rpc - handlers - Ping', () => { let peers + let tdht let dht before((done) => { - util.makePeers(2, (err, res) => { + createPeerInfo(2, (err, res) => { expect(err).to.not.exist() peers = res done() }) }) - afterEach((done) => util.teardown(done)) - beforeEach((done) => { - util.setupDHT((err, res) => { + tdht = new TestDHT() + + tdht.spawn(1, (err, dhts) => { expect(err).to.not.exist() - dht = res + dht = dhts[0] done() }) }) + afterEach((done) => { + tdht.teardown(done) + }) + it('replies with the same message', (done) => { const msg = new Message(T, Buffer.from('hello'), 5) diff --git a/test/rpc/handlers/put-value.spec.js b/test/rpc/handlers/put-value.spec.js index 84c67c5f..eb8bbf70 100644 --- a/test/rpc/handlers/put-value.spec.js +++ b/test/rpc/handlers/put-value.spec.js @@ -6,38 +6,44 @@ const chai = require('chai') chai.use(require('dirty-chai')) const expect = chai.expect const Record = require('libp2p-record').Record -const Buffer = require('safe-buffer').Buffer const Message = require('../../../src/message') const handler = require('../../../src/rpc/handlers/put-value') const utils = require('../../../src/utils') -const util = require('../../utils') +const createPeerInfo = require('../../utils/create-peer-info') +// const createValues = require('../../utils/create-values') +const TestDHT = require('../../utils/test-dht') const T = Message.TYPES.PUT_VALUE describe('rpc - handlers - PutValue', () => { let peers + let tdht let dht before((done) => { - util.makePeers(2, (err, res) => { + createPeerInfo(2, (err, res) => { expect(err).to.not.exist() peers = res done() }) }) - afterEach((done) => util.teardown(done)) - beforeEach((done) => { - util.setupDHT((err, res) => { + tdht = new TestDHT() + + tdht.spawn(1, (err, dhts) => { expect(err).to.not.exist() - dht = res + dht = dhts[0] done() }) }) + afterEach((done) => { + tdht.teardown(done) + }) + it('errors on missing record', (done) => { const msg = new Message(T, Buffer.from('hello'), 5) handler(dht)(peers[0], msg, (err, response) => { diff --git a/test/rpc/index.spec.js b/test/rpc/index.spec.js index 5ab6ecfc..16627267 100644 --- a/test/rpc/index.spec.js +++ b/test/rpc/index.spec.js @@ -10,19 +10,19 @@ const Connection = require('interface-connection').Connection const PeerBook = require('peer-book') const Switch = require('libp2p-switch') const TCP = require('libp2p-tcp') -const Multiplex = require('libp2p-multiplex') +const Mplex = require('libp2p-mplex') const Message = require('../../src/message') const KadDHT = require('../../src') const rpc = require('../../src/rpc') -const makePeers = require('../utils').makePeers +const createPeerInfo = require('../utils/create-peer-info') describe('rpc', () => { let peerInfos before((done) => { - makePeers(2, (err, peers) => { + createPeerInfo(2, (err, peers) => { if (err) { return done(err) } @@ -36,7 +36,7 @@ describe('rpc', () => { it('calls back with the response', (done) => { const sw = new Switch(peerInfos[0], new PeerBook()) sw.transport.add('tcp', new TCP()) - sw.connection.addStreamMuxer(Multiplex) + sw.connection.addStreamMuxer(Mplex) sw.connection.reuse() const dht = new KadDHT(sw, { kBucketSize: 5 }) diff --git a/test/utils/create-peer-info.js b/test/utils/create-peer-info.js new file mode 100644 index 00000000..b26d33ba --- /dev/null +++ b/test/utils/create-peer-info.js @@ -0,0 +1,15 @@ +'use strict' + +const times = require('async/times') +const PeerId = require('peer-id') +const PeerInfo = require('peer-info') + +// Creates multiple PeerInfos +function createPeerInfo (n, callback) { + times(n, (i, cb) => PeerId.create({bits: 512}, cb), (err, ids) => { + if (err) { return callback(err) } + callback(null, ids.map((i) => new PeerInfo(i))) + }) +} + +module.exports = createPeerInfo diff --git a/test/utils/create-values.js b/test/utils/create-values.js new file mode 100644 index 00000000..00fdb45b --- /dev/null +++ b/test/utils/create-values.js @@ -0,0 +1,20 @@ +'use strict' + +const times = require('async/times') +const multihashing = require('multihashing-async') +const waterfall = require('async/waterfall') +const CID = require('cids') +const crypto = require('libp2p-crypto') + +function createValues (n, callback) { + times(n, (i, cb) => { + const bytes = crypto.randomBytes(32) + + waterfall([ + (cb) => multihashing(bytes, 'sha2-256', cb), + (h, cb) => cb(null, {cid: new CID(h), value: bytes}) + ], cb) + }, callback) +} + +module.exports = createValues diff --git a/test/utils/index.js b/test/utils/index.js deleted file mode 100644 index 67c75ad1..00000000 --- a/test/utils/index.js +++ /dev/null @@ -1,92 +0,0 @@ -'use strict' - -const times = require('async/times') -const each = require('async/each') -const series = require('async/series') -const setImmediate = require('async/setImmediate') -const multihashing = require('multihashing-async') -const waterfall = require('async/waterfall') -const CID = require('cids') -const PeerId = require('peer-id') -const PeerInfo = require('peer-info') -const PeerBook = require('peer-book') -const crypto = require('libp2p-crypto') -const Switch = require('libp2p-switch') -const TCP = require('libp2p-tcp') -const Multiplex = require('libp2p-multiplex') - -const KadDHT = require('../../src') - -// Creates multiple PeerInfos -exports.makePeers = (n, callback) => { - times(n, (i, cb) => PeerId.create({bits: 1024}, cb), (err, ids) => { - if (err) { - return callback(err) - } - callback(null, ids.map((i) => new PeerInfo(i))) - }) -} - -// TODO break this setupDHT to be a self contained thing. -let nodes = [] - -exports.setupDHT = (callback) => { - exports.makePeers(1, (err, peers) => { - if (err) { - return callback(err) - } - - const p = peers[0] - p.multiaddrs.add('/ip4/0.0.0.0/tcp/0') - - const sw = new Switch(p, new PeerBook()) - sw.transport.add('tcp', new TCP()) - sw.connection.addStreamMuxer(Multiplex) - sw.connection.reuse() - - const dht = new KadDHT(sw) - - dht.validators.v = { - func (key, publicKey, callback) { - setImmediate(callback) - }, - sign: false - } - - dht.selectors.v = (k, records) => 0 - - series([ - (cb) => sw.start(cb), - (cb) => dht.start(cb) - ], (err) => { - if (err) { - return callback(err) - } - nodes.push(dht) - callback(null, dht) - }) - }) -} - -exports.teardown = (callback) => { - each(nodes, (n, cb) => { - series([ - (cb) => n.stop(cb), - (cb) => n.switch.stop(cb) - ], cb) - }, (err) => { - nodes = [] - callback(err) - }) -} - -exports.makeValues = (n, callback) => { - times(n, (i, cb) => { - const bytes = crypto.randomBytes(32) - - waterfall([ - (cb) => multihashing(bytes, 'sha2-256', cb), - (h, cb) => cb(null, {cid: new CID(h), value: bytes}) - ], cb) - }, callback) -} diff --git a/test/utils/test-dht.js b/test/utils/test-dht.js new file mode 100644 index 00000000..5351008b --- /dev/null +++ b/test/utils/test-dht.js @@ -0,0 +1,75 @@ +'use strict' + +const each = require('async/each') +const series = require('async/series') +const setImmediate = require('async/setImmediate') +const PeerBook = require('peer-book') +const Switch = require('libp2p-switch') +const TCP = require('libp2p-tcp') +const Mplex = require('libp2p-mplex') +const times = require('async/times') + +const createPeerInfo = require('./create-peer-info') + +const KadDHT = require('../../src') + +class TestDHT { + constructor () { + this.nodes = [] + } + + spawn (n, callback) { + times(n, (i, cb) => this._spawnOne(cb), (err, dhts) => { + if (err) { return callback(err) } + callback(null, dhts) + }) + } + + _spawnOne (callback) { + createPeerInfo(1, (err, peers) => { + if (err) { return callback(err) } + + const p = peers[0] + p.multiaddrs.add('/ip4/127.0.0.1/tcp/0') + + const sw = new Switch(p, new PeerBook()) + sw.transport.add('tcp', new TCP()) + sw.connection.addStreamMuxer(Mplex) + sw.connection.reuse() + + const dht = new KadDHT(sw) + + dht.validators.v = { + func (key, publicKey, callback) { + setImmediate(callback) + }, + sign: false + } + + dht.selectors.v = (k, records) => 0 + + series([ + (cb) => sw.start(cb), + (cb) => dht.start(cb) + ], (err) => { + if (err) { return callback(err) } + this.nodes.push(dht) + callback(null, dht) + }) + }) + } + + teardown (callback) { + each(this.nodes, (n, cb) => { + series([ + (cb) => n.stop(cb), + (cb) => n.switch.stop(cb) + ], cb) + }, (err) => { + this.nodes = [] + callback(err) + }) + } +} + +module.exports = TestDHT