From 61966c097759c51ce2180ba8736e3dc903776ae4 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 17 Nov 2017 12:28:43 +1300 Subject: [PATCH 01/25] test: enable pubsub tests --- test/cli/pubsub.js | 2 +- test/http-api/interface/pubsub.js | 3 --- test/http-api/spec/pubsub.js | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/test/cli/pubsub.js b/test/cli/pubsub.js index 703b83a5b0..49c6786093 100644 --- a/test/cli/pubsub.js +++ b/test/cli/pubsub.js @@ -14,7 +14,7 @@ const createTempNode = '' const repoPath = require('./index').repoPath const ipfs = require('../utils/ipfs-exec')(repoPath) -describe.skip('pubsub', () => { +describe('pubsub', () => { const topicA = 'nonscentsA' const topicB = 'nonscentsB' const topicC = 'nonscentsC' diff --git a/test/http-api/interface/pubsub.js b/test/http-api/interface/pubsub.js index 968227c83b..ab474fac9f 100644 --- a/test/http-api/interface/pubsub.js +++ b/test/http-api/interface/pubsub.js @@ -2,8 +2,6 @@ 'use strict' -// TODO needs: https://github.com/ipfs/js-ipfs-api/pull/493 -/* const test = require('interface-ipfs-core') const FactoryClient = require('./../../utils/ipfs-factory-daemon') @@ -20,4 +18,3 @@ const common = { } test.pubsub(common) -*/ diff --git a/test/http-api/spec/pubsub.js b/test/http-api/spec/pubsub.js index 245b6d153c..c109bf8893 100644 --- a/test/http-api/spec/pubsub.js +++ b/test/http-api/spec/pubsub.js @@ -10,7 +10,7 @@ const createTempNode = '' // TODO migrate to use ipfs-factory-daemon module.exports = (http) => { - describe.skip('/pubsub', () => { + describe('/pubsub', () => { let api let tmpNode From 534d8493489d272b81dc672f8b9d6c5944399c16 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 17 Nov 2017 15:21:43 +1300 Subject: [PATCH 02/25] fix: generate meaniful error when pubsub is called and not enabled --- src/core/components/no-floodsub.js | 25 +++++++++++++++++++++++++ src/core/components/start.js | 11 +++++------ src/core/components/stop.js | 8 +------- 3 files changed, 31 insertions(+), 13 deletions(-) create mode 100644 src/core/components/no-floodsub.js diff --git a/src/core/components/no-floodsub.js b/src/core/components/no-floodsub.js new file mode 100644 index 0000000000..923c978c30 --- /dev/null +++ b/src/core/components/no-floodsub.js @@ -0,0 +1,25 @@ +'use strict' + +const EventEmitter = require('events') + +function fail() { + throw new Error('The daemon must be run with \'--enable-pubsub-experiment\'') +} + +class NoFloodSub extends EventEmitter { + constructor () { + super() + + this.peers = new Map() + this.subscriptions = new Set() + } + + start (callback) { callback() } + stop (callback) { callback() } + publish () { fail() } + subscribe () { fail() } + unsubscribe () { fail() } + +} + +module.exports = NoFloodSub diff --git a/src/core/components/start.js b/src/core/components/start.js index 54ff3c9833..9575c3e3c6 100644 --- a/src/core/components/start.js +++ b/src/core/components/start.js @@ -3,6 +3,7 @@ const series = require('async/series') const Bitswap = require('ipfs-bitswap') const FloodSub = require('libp2p-floodsub') +const NoFloodSub = require('./no-floodsub') const setImmediate = require('async/setImmediate') const promisify = require('promisify-es6') @@ -50,12 +51,10 @@ module.exports = (self) => { self._bitswap.start() self._blockService.setExchange(self._bitswap) - if (self._options.EXPERIMENTAL.pubsub) { - self._pubsub = new FloodSub(self._libp2pNode) - self._pubsub.start(done) - } else { - done() - } + self._pubsub = self._options.EXPERIMENTAL.pubsub + ? new FloodSub(self._libp2pNode) + : new NoFloodSub() + self._pubsub.start(done) }) }) } diff --git a/src/core/components/stop.js b/src/core/components/stop.js index e9d508d10b..8c05aaeb6c 100644 --- a/src/core/components/stop.js +++ b/src/core/components/stop.js @@ -30,13 +30,7 @@ module.exports = (self) => { self._bitswap.stop() series([ - (cb) => { - if (self._options.EXPERIMENTAL.pubsub) { - self._pubsub.stop(cb) - } else { - cb() - } - }, + (cb) => self._pubsub.stop(cb), (cb) => self.libp2p.stop(cb), (cb) => self._repo.close(cb) ], done) From 12ec8d2286114fdb4ffcdc47c93e644236d6ab76 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 17 Nov 2017 16:42:59 +1300 Subject: [PATCH 03/25] test: enable pubsub for factory daemon --- test/utils/ipfs-factory-daemon/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/utils/ipfs-factory-daemon/index.js b/test/utils/ipfs-factory-daemon/index.js index 9c7a61ce73..b67ea40727 100644 --- a/test/utils/ipfs-factory-daemon/index.js +++ b/test/utils/ipfs-factory-daemon/index.js @@ -52,7 +52,9 @@ class Factory { }) }, (cb) => { - daemon = new HttpApi(repoPath, config) + daemon = new HttpApi(repoPath, config, { + enablePubsubExperiment: true, + }) daemon.repoPath = repoPath this.daemonsSpawned.push(daemon) From 1e9f260c51c3498c1c5c61a02b9cb614dd1420c2 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 17 Nov 2017 12:28:43 +1300 Subject: [PATCH 04/25] test: enable pubsub tests --- test/cli/pubsub.js | 2 +- test/http-api/interface/pubsub.js | 3 --- test/http-api/spec/pubsub.js | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/test/cli/pubsub.js b/test/cli/pubsub.js index 703b83a5b0..49c6786093 100644 --- a/test/cli/pubsub.js +++ b/test/cli/pubsub.js @@ -14,7 +14,7 @@ const createTempNode = '' const repoPath = require('./index').repoPath const ipfs = require('../utils/ipfs-exec')(repoPath) -describe.skip('pubsub', () => { +describe('pubsub', () => { const topicA = 'nonscentsA' const topicB = 'nonscentsB' const topicC = 'nonscentsC' diff --git a/test/http-api/interface/pubsub.js b/test/http-api/interface/pubsub.js index 968227c83b..ab474fac9f 100644 --- a/test/http-api/interface/pubsub.js +++ b/test/http-api/interface/pubsub.js @@ -2,8 +2,6 @@ 'use strict' -// TODO needs: https://github.com/ipfs/js-ipfs-api/pull/493 -/* const test = require('interface-ipfs-core') const FactoryClient = require('./../../utils/ipfs-factory-daemon') @@ -20,4 +18,3 @@ const common = { } test.pubsub(common) -*/ diff --git a/test/http-api/spec/pubsub.js b/test/http-api/spec/pubsub.js index 245b6d153c..c109bf8893 100644 --- a/test/http-api/spec/pubsub.js +++ b/test/http-api/spec/pubsub.js @@ -10,7 +10,7 @@ const createTempNode = '' // TODO migrate to use ipfs-factory-daemon module.exports = (http) => { - describe.skip('/pubsub', () => { + describe('/pubsub', () => { let api let tmpNode From 15ab7a2e8366043264508dd86b56bd0c4750d5f6 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 17 Nov 2017 15:21:43 +1300 Subject: [PATCH 05/25] fix: generate meaniful error when pubsub is called and not enabled --- src/core/components/no-floodsub.js | 25 +++++++++++++++++++++++++ src/core/components/start.js | 11 +++++------ src/core/components/stop.js | 8 +------- 3 files changed, 31 insertions(+), 13 deletions(-) create mode 100644 src/core/components/no-floodsub.js diff --git a/src/core/components/no-floodsub.js b/src/core/components/no-floodsub.js new file mode 100644 index 0000000000..923c978c30 --- /dev/null +++ b/src/core/components/no-floodsub.js @@ -0,0 +1,25 @@ +'use strict' + +const EventEmitter = require('events') + +function fail() { + throw new Error('The daemon must be run with \'--enable-pubsub-experiment\'') +} + +class NoFloodSub extends EventEmitter { + constructor () { + super() + + this.peers = new Map() + this.subscriptions = new Set() + } + + start (callback) { callback() } + stop (callback) { callback() } + publish () { fail() } + subscribe () { fail() } + unsubscribe () { fail() } + +} + +module.exports = NoFloodSub diff --git a/src/core/components/start.js b/src/core/components/start.js index 54ff3c9833..9575c3e3c6 100644 --- a/src/core/components/start.js +++ b/src/core/components/start.js @@ -3,6 +3,7 @@ const series = require('async/series') const Bitswap = require('ipfs-bitswap') const FloodSub = require('libp2p-floodsub') +const NoFloodSub = require('./no-floodsub') const setImmediate = require('async/setImmediate') const promisify = require('promisify-es6') @@ -50,12 +51,10 @@ module.exports = (self) => { self._bitswap.start() self._blockService.setExchange(self._bitswap) - if (self._options.EXPERIMENTAL.pubsub) { - self._pubsub = new FloodSub(self._libp2pNode) - self._pubsub.start(done) - } else { - done() - } + self._pubsub = self._options.EXPERIMENTAL.pubsub + ? new FloodSub(self._libp2pNode) + : new NoFloodSub() + self._pubsub.start(done) }) }) } diff --git a/src/core/components/stop.js b/src/core/components/stop.js index 3a2dd8c04f..6ac0dc91a3 100644 --- a/src/core/components/stop.js +++ b/src/core/components/stop.js @@ -31,13 +31,7 @@ module.exports = (self) => { self._bitswap.stop() series([ - (cb) => { - if (self._options.EXPERIMENTAL.pubsub) { - self._pubsub.stop(cb) - } else { - cb() - } - }, + (cb) => self._pubsub.stop(cb), (cb) => self.libp2p.stop(cb), (cb) => self._repo.close(cb) ], done) From dc5166ca840a542ed81f56da45fab3f790281fd5 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 17 Nov 2017 16:42:59 +1300 Subject: [PATCH 06/25] test: enable pubsub for factory daemon --- test/utils/ipfs-factory-daemon/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/utils/ipfs-factory-daemon/index.js b/test/utils/ipfs-factory-daemon/index.js index 9c7a61ce73..b67ea40727 100644 --- a/test/utils/ipfs-factory-daemon/index.js +++ b/test/utils/ipfs-factory-daemon/index.js @@ -52,7 +52,9 @@ class Factory { }) }, (cb) => { - daemon = new HttpApi(repoPath, config) + daemon = new HttpApi(repoPath, config, { + enablePubsubExperiment: true, + }) daemon.repoPath = repoPath this.daemonsSpawned.push(daemon) From 718645d57bc1892ea9b387ed8d5a9713bf238720 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 17 Nov 2017 23:36:57 +1300 Subject: [PATCH 07/25] fiix(pubsub-subscribe): stop HAPI gzip from buffering our streamed response --- src/http/api/resources/pubsub.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/http/api/resources/pubsub.js b/src/http/api/resources/pubsub.js index 8d35abce97..0d9022fdaf 100644 --- a/src/http/api/resources/pubsub.js +++ b/src/http/api/resources/pubsub.js @@ -47,6 +47,7 @@ exports.subscribe = { reply(res) .header('X-Chunked-Output', '1') + .header('content-encoding', 'identity') // stop gzip from buffering, see https://github.com/hapijs/hapi/issues/2975 .header('content-type', 'application/json') }) } From 533d8038f04d528b3362c74fff8de1a46f0dca43 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sat, 18 Nov 2017 15:18:00 +1300 Subject: [PATCH 08/25] test: fix spec/pubsub --- test/fixtures/go-ipfs-repo/version | 2 +- test/http-api/index.js | 5 ++++- test/http-api/spec/pubsub.js | 19 +------------------ 3 files changed, 6 insertions(+), 20 deletions(-) diff --git a/test/fixtures/go-ipfs-repo/version b/test/fixtures/go-ipfs-repo/version index 7ed6ff82de..62f9457511 100644 --- a/test/fixtures/go-ipfs-repo/version +++ b/test/fixtures/go-ipfs-repo/version @@ -1 +1 @@ -5 +6 \ No newline at end of file diff --git a/test/http-api/index.js b/test/http-api/index.js index e2c7f34ce3..3508b1bb80 100644 --- a/test/http-api/index.js +++ b/test/http-api/index.js @@ -19,7 +19,10 @@ describe('HTTP API', () => { let http = {} before((done) => { - http.api = new API(repoTests) + const options = { + enablePubsubExperiment: true + } + http.api = new API(repoTests, null, options) ncp(repoExample, repoTests, (err) => { expect(err).to.not.exist() diff --git a/test/http-api/spec/pubsub.js b/test/http-api/spec/pubsub.js index c109bf8893..cf4dad7f58 100644 --- a/test/http-api/spec/pubsub.js +++ b/test/http-api/spec/pubsub.js @@ -6,9 +6,7 @@ const chai = require('chai') const dirtyChai = require('dirty-chai') const expect = chai.expect chai.use(dirtyChai) -const createTempNode = '' -// TODO migrate to use ipfs-factory-daemon module.exports = (http) => { describe('/pubsub', () => { let api @@ -18,23 +16,8 @@ module.exports = (http) => { const topic = 'nonScents' const topicNotSubscribed = 'somethingRandom' - before((done) => { + before(() => { api = http.api.server.select('API') - - createTempNode(47, (err, _ipfs) => { - expect(err).to.not.exist() - tmpNode = _ipfs - tmpNode.goOnline((err) => { - expect(err).to.not.exist() - done() - }) - }) - }) - - after((done) => { - setTimeout(() => { - tmpNode.goOffline(done) - }, 1000) }) describe('/sub', () => { From 08955a235a15b57ccb37dc7b9e354cf21a71d17c Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sat, 18 Nov 2017 15:40:28 +1300 Subject: [PATCH 09/25] fix: lint errors --- src/core/components/no-floodsub.js | 3 +-- test/http-api/spec/pubsub.js | 1 - test/utils/ipfs-factory-daemon/index.js | 4 ++-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/core/components/no-floodsub.js b/src/core/components/no-floodsub.js index 923c978c30..95db571f5f 100644 --- a/src/core/components/no-floodsub.js +++ b/src/core/components/no-floodsub.js @@ -2,7 +2,7 @@ const EventEmitter = require('events') -function fail() { +function fail () { throw new Error('The daemon must be run with \'--enable-pubsub-experiment\'') } @@ -19,7 +19,6 @@ class NoFloodSub extends EventEmitter { publish () { fail() } subscribe () { fail() } unsubscribe () { fail() } - } module.exports = NoFloodSub diff --git a/test/http-api/spec/pubsub.js b/test/http-api/spec/pubsub.js index cf4dad7f58..9c69427246 100644 --- a/test/http-api/spec/pubsub.js +++ b/test/http-api/spec/pubsub.js @@ -10,7 +10,6 @@ chai.use(dirtyChai) module.exports = (http) => { describe('/pubsub', () => { let api - let tmpNode const buf = Buffer.from('some message') const topic = 'nonScents' diff --git a/test/utils/ipfs-factory-daemon/index.js b/test/utils/ipfs-factory-daemon/index.js index b67ea40727..6b6ab1e1ba 100644 --- a/test/utils/ipfs-factory-daemon/index.js +++ b/test/utils/ipfs-factory-daemon/index.js @@ -52,8 +52,8 @@ class Factory { }) }, (cb) => { - daemon = new HttpApi(repoPath, config, { - enablePubsubExperiment: true, + daemon = new HttpApi(repoPath, config, { + enablePubsubExperiment: true }) daemon.repoPath = repoPath this.daemonsSpawned.push(daemon) From c5fda151c1ab9074f0afa4007cd8d5fdc765f10d Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sat, 18 Nov 2017 20:57:14 +1300 Subject: [PATCH 10/25] test: tests js/go pubsub interop --- test/interop/pubsub.js | 117 +++++++++++++++++++--- test/utils/interop-daemon-spawner/go.js | 3 +- test/utils/interop-daemon-spawner/js.js | 7 +- test/utils/interop-daemon-spawner/util.js | 2 +- 4 files changed, 108 insertions(+), 21 deletions(-) diff --git a/test/interop/pubsub.js b/test/interop/pubsub.js index b76f21967f..8e0a19a3b4 100644 --- a/test/interop/pubsub.js +++ b/test/interop/pubsub.js @@ -11,7 +11,24 @@ const parallel = require('async/parallel') const GODaemon = require('../utils/interop-daemon-spawner/go') const JSDaemon = require('../utils/interop-daemon-spawner/js') -describe('pubsub', () => { +/* + * Wait for a condition to become true. When its true, callback is called. + */ +function waitFor (predicate, callback) { + const ttl = Date.now() + (2 * 1000) + const self = setInterval(() => { + if (predicate()) { + clearInterval(self) + callback() + } + if (Date.now() > ttl) { + clearInterval(self) + callback(new Error("waitFor time expired")) + } + }, 500) +} + +describe('pubsub', function () { let jsD let goD let jsId @@ -34,47 +51,115 @@ describe('pubsub', () => { }) after((done) => { - series([ + parallel([ (cb) => goD.stop(cb), (cb) => jsD.stop(cb) ], done) }) it('make connections', (done) => { - parallel([ + series([ (cb) => jsD.api.id(cb), (cb) => goD.api.id(cb) ], (err, ids) => { expect(err).to.not.exist() - jsId = ids[0].ID - goId = ids[0].ID + jsId = ids[0].id + goId = ids[1].id - console.log('jsId:', jsId) - console.log('goId:', goId) + const jsLocalAddr = ids[0].addresses.find(a => a.includes('127.0.0.1')) + const goLocalAddr = ids[1].addresses.find(a => a.includes('127.0.0.1')) parallel([ - (cb) => jsD.api.swarm.connect(ids[1].addresses[0], cb), - (cb) => goD.api.swarm.connect(ids[0].addresses[0], cb) + (cb) => jsD.api.swarm.connect(goLocalAddr, cb), + (cb) => goD.api.swarm.connect(jsLocalAddr, cb) ], done) }) }) - it.skip('publish from JS, subscribe on Go', (done) => { - // TODO write this test + it('publish from Go, subscribe on Go', (done) => { + const topic = 'pubsub-go-go' + const data = Buffer.from('hello world') + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString()).to.equal(data.toString()) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + // TODO: expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', goId) + } + + series([ + (cb) => goD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => goD.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb) + ], done) + }) + + it('publish from JS, subscribe on JS', (done) => { + const topic = 'pubsub-js-js' + const data = Buffer.from('hello world') + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString()).to.equal(data.toString()) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', jsId) + } + + series([ + (cb) => jsD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => jsD.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb) + ], done) + }) + + it('publish from JS, subscribe on Go', (done) => { + const topic = 'pubsub-js-go' + const data = Buffer.from('hello world') + let n = 0 + + function checkMessage (msg) { + console.log('check message', msg) + ++n + expect(msg.data.toString()).to.equal(data.toString()) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', jsId) + } + + series([ + (cb) => goD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => jsD.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb) + ], done) }) - it.skip('publish from Go, subscribe on JS', (done) => { + it('publish from Go, subscribe on JS', (done) => { const topic = 'pubsub-go-js' const data = Buffer.from('hello world') + let n = 0 - function checkMessage () { - console.log('check message', arguments) + function checkMessage (msg) { + console.log('check message', msg) + ++n + expect(msg.data.toString()).to.equal(data.toString()) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', goId) } series([ - cb => jsD.api.pubsub.subscribe(topic, checkMessage, cb), - cb => goD.api.pubsub.publish(topic, data, cb) + (cb) => jsD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => goD.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb), ], done) }) }) diff --git a/test/utils/interop-daemon-spawner/go.js b/test/utils/interop-daemon-spawner/go.js index 92a04ca99e..8010724d81 100644 --- a/test/utils/interop-daemon-spawner/go.js +++ b/test/utils/interop-daemon-spawner/go.js @@ -40,8 +40,7 @@ class GoDaemon { this.node = node this.node.setConfig('Bootstrap', '[]', cb) }, - (res, cb) => this.node.startDaemon(cb), - // (res, cb) => this.node.startDaemon(this.flags, cb), + (res, cb) => this.node.startDaemon(this.flags, cb), (api, cb) => { this.api = api diff --git a/test/utils/interop-daemon-spawner/js.js b/test/utils/interop-daemon-spawner/js.js index e96850c82b..bd376ff892 100644 --- a/test/utils/interop-daemon-spawner/js.js +++ b/test/utils/interop-daemon-spawner/js.js @@ -37,14 +37,17 @@ class JsDaemon extends EventEmitter { this.path = opts.path || tmpDir() this._started = false + const extras = { + enablePubsubExperiment: true + } if (this.init) { const p = portConfig(this.port) this.node = new HttpApi(this.path, { Bootstrap: [], Addresses: p - }) + }, extras) } else { - this.node = new HttpApi(this.path) + this.node = new HttpApi(this.path, null, extras) } this.node.start(this.init, (err) => { diff --git a/test/utils/interop-daemon-spawner/util.js b/test/utils/interop-daemon-spawner/util.js index 256f857f0c..c0ca77a338 100644 --- a/test/utils/interop-daemon-spawner/util.js +++ b/test/utils/interop-daemon-spawner/util.js @@ -7,7 +7,7 @@ const path = require('path') exports.tmpDir = (prefix) => { return path.join( os.tmpdir(), - prefix || 'tmp', + prefix || 'js-ipfs-interop', crypto.randomBytes(32).toString('hex') ) } From c7c27a3be3e75ac89622e98bad5f9b73bc4f6795 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Tue, 21 Nov 2017 01:00:03 +1300 Subject: [PATCH 11/25] test: pubsub interop tests --- test/interop/node.js | 1 + test/interop/pubsub-go.js | 134 ++++++++++++++++++++++++++++++++++++++ test/interop/pubsub-js.js | 132 +++++++++++++++++++++++++++++++++++++ test/interop/pubsub.js | 66 +++++++++++++++++-- 4 files changed, 326 insertions(+), 7 deletions(-) create mode 100644 test/interop/pubsub-go.js create mode 100644 test/interop/pubsub-js.js diff --git a/test/interop/node.js b/test/interop/node.js index 7e4a513445..a2e415b87a 100644 --- a/test/interop/node.js +++ b/test/interop/node.js @@ -6,3 +6,4 @@ require('./exchange-files') require('./circuit-relay') require('./kad-dht') require('./pubsub') +require('./pubsub-go') diff --git a/test/interop/pubsub-go.js b/test/interop/pubsub-go.js new file mode 100644 index 0000000000..86f8488648 --- /dev/null +++ b/test/interop/pubsub-go.js @@ -0,0 +1,134 @@ +/* eslint-env mocha */ +'use strict' + +const chai = require('chai') +const dirtyChai = require('dirty-chai') +const expect = chai.expect +chai.use(dirtyChai) +const series = require('async/series') +const parallel = require('async/parallel') + +const GODaemon = require('../utils/interop-daemon-spawner/go') + +/* + * Wait for a condition to become true. When its true, callback is called. + */ +function waitFor (predicate, callback) { + const ttl = Date.now() + (2 * 1000) + const self = setInterval(() => { + if (predicate()) { + clearInterval(self) + return callback() + } + if (Date.now() > ttl) { + clearInterval(self) + return callback(new Error("waitFor time expired")) + } + }, 500) +} + +describe('pubsub GO 2 GO', function () { + this.timeout(4 * 1000) + + let go1D + let go2D + let go1Id + let go2Id + + before(function (done) { + this.timeout(50 * 1000) + + go1D = new GODaemon({ + disposable: true, + init: true, + flags: ['--enable-pubsub-experiment'] + }) + go2D = new GODaemon({ + disposable: true, + init: true, + flags: ['--enable-pubsub-experiment'] + }) + + parallel([ + (cb) => go1D.start(cb), + (cb) => go2D.start(cb) + ], (done)) + }) + + after((done) => { + parallel([ + (cb) => go1D.stop(cb), + (cb) => go2D.stop(cb) + ], done) + }) + + it('make connections', (done) => { + series([ + (cb) => go1D.api.id(cb), + (cb) => go2D.api.id(cb) + ], (err, ids) => { + expect(err).to.not.exist() + + go1Id = ids[0].id + go2Id = ids[1].id + + const go1LocalAddr = ids[0].addresses.find(a => a.includes('127.0.0.1')) + const go2LocalAddr = ids[1].addresses.find(a => a.includes('127.0.0.1')) + + parallel([ + (cb) => go1D.api.swarm.connect(go2LocalAddr, cb), + (cb) => go2D.api.swarm.connect(go1LocalAddr, cb), + (cb) => setTimeout(() => { + cb() + }, 1000) + ], done) + }) + }) + + it('publish from Go2, subscribe on Go1', (done) => { + const topic = 'pubsub-go2-go1' + const data = Buffer.from('hello world') + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString()).to.equal(data.toString()) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', go2Id) + } + + series([ + (cb) => go1D.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => setTimeout(() => { cb() }, 500), + (cb) => go2D.api.pubsub.publish(topic, data, cb), + (cb) => go2D.api.pubsub.publish(topic, data, cb), + (cb) => go2D.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 3, cb) + ], done) + }) + + it('publish binary data', (done) => { + const topic = 'pubsub-binary-go1-go2' + const data = Buffer.from('00010203040506070809', 'hex') + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString('hex')).to.equal(data.toString('hex')) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', go2Id) + } + + series([ + (cb) => go1D.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => setTimeout(() => { cb() }, 500), + (cb) => go2D.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb) + ], done) + }) + +}) diff --git a/test/interop/pubsub-js.js b/test/interop/pubsub-js.js new file mode 100644 index 0000000000..252ac6daf9 --- /dev/null +++ b/test/interop/pubsub-js.js @@ -0,0 +1,132 @@ +/* eslint-env mocha */ +'use strict' + +const chai = require('chai') +const dirtyChai = require('dirty-chai') +const expect = chai.expect +chai.use(dirtyChai) +const series = require('async/series') +const parallel = require('async/parallel') + +const JSDaemon = require('../utils/interop-daemon-spawner/js') + +/* + * Wait for a condition to become true. When its true, callback is called. + */ +function waitFor (predicate, callback) { + const ttl = Date.now() + (2 * 1000) + const self = setInterval(() => { + if (predicate()) { + clearInterval(self) + return callback() + } + if (Date.now() > ttl) { + clearInterval(self) + return callback(new Error("waitFor time expired")) + } + }, 500) +} + +describe('pubsub JS 2 JS', function () { + this.timeout(4 * 1000) + + let js1D + let js2D + let js1Id + let js2Id + + before(function (done) { + this.timeout(50 * 1000) + + js1D = new JSDaemon() + js2D = new JSDaemon({ + disposable: true, + init: true, + port: 2 + }) + + parallel([ + (cb) => js1D.start(cb), + (cb) => js2D.start(cb) + ], (done)) + }) + + after(function (done) { + this.timeout(10 * 1000) + + parallel([ + (cb) => js1D.stop(cb), + (cb) => js2D.stop(cb) + ], done) + }) + + it('make connections', (done) => { + series([ + (cb) => js1D.api.id(cb), + (cb) => js2D.api.id(cb) + ], (err, ids) => { + expect(err).to.not.exist() + + js1Id = ids[0].id + js2Id = ids[1].id + + const js1LocalAddr = ids[0].addresses.find(a => a.includes('127.0.0.1')) + const js2LocalAddr = ids[1].addresses.find(a => a.includes('127.0.0.1')) + + parallel([ + (cb) => js1D.api.swarm.connect(js2LocalAddr, cb), + (cb) => js2D.api.swarm.connect(js1LocalAddr, cb), + (cb) => setTimeout(() => { + cb() + }, 1000) + ], done) + }) + }) + + it('publish from JS2, subscribe on JS1', (done) => { + const topic = 'pubsub-js2-js1' + const data = Buffer.from('hello world') + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString()).to.equal(data.toString()) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', js2Id) + } + + series([ + (cb) => js1D.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => setTimeout(() => { cb() }, 500), + (cb) => js2D.api.pubsub.publish(topic, data, cb), + (cb) => js2D.api.pubsub.publish(topic, data, cb), + (cb) => js2D.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 3, cb) + ], done) + }) + + it('publish binary data', (done) => { + const topic = 'pubsub-binary-js1-js2' + const data = Buffer.from('00010203040506070809', 'hex') + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString('hex')).to.equal(data.toString('hex')) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', js2Id) + } + + series([ + (cb) => js1D.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => setTimeout(() => { cb() }, 500), + (cb) => js2D.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb) + ], done) + }) + +}) diff --git a/test/interop/pubsub.js b/test/interop/pubsub.js index 8e0a19a3b4..0f91022cf4 100644 --- a/test/interop/pubsub.js +++ b/test/interop/pubsub.js @@ -19,16 +19,18 @@ function waitFor (predicate, callback) { const self = setInterval(() => { if (predicate()) { clearInterval(self) - callback() + return callback() } if (Date.now() > ttl) { clearInterval(self) - callback(new Error("waitFor time expired")) + return callback(new Error("waitFor time expired")) } }, 500) } describe('pubsub', function () { + this.timeout(4 * 1000) + let jsD let goD let jsId @@ -50,7 +52,9 @@ describe('pubsub', function () { ], (done)) }) - after((done) => { + after(function (done) { + this.timeout(50 * 1000) + parallel([ (cb) => goD.stop(cb), (cb) => jsD.stop(cb) @@ -72,7 +76,10 @@ describe('pubsub', function () { parallel([ (cb) => jsD.api.swarm.connect(goLocalAddr, cb), - (cb) => goD.api.swarm.connect(jsLocalAddr, cb) + (cb) => goD.api.swarm.connect(jsLocalAddr, cb), + (cb) => setTimeout(() => { + cb() + }, 1000) ], done) }) }) @@ -87,7 +94,7 @@ describe('pubsub', function () { expect(msg.data.toString()).to.equal(data.toString()) expect(msg).to.have.property('seqno') expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) - // TODO: expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('topicIDs').eql([topic]) expect(msg).to.have.property('from', goId) } @@ -125,7 +132,6 @@ describe('pubsub', function () { let n = 0 function checkMessage (msg) { - console.log('check message', msg) ++n expect(msg.data.toString()).to.equal(data.toString()) expect(msg).to.have.property('seqno') @@ -136,6 +142,7 @@ describe('pubsub', function () { series([ (cb) => goD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => setTimeout(() => { cb() }, 500), (cb) => jsD.api.pubsub.publish(topic, data, cb), (cb) => waitFor(() => n === 1, cb) ], done) @@ -147,7 +154,6 @@ describe('pubsub', function () { let n = 0 function checkMessage (msg) { - console.log('check message', msg) ++n expect(msg.data.toString()).to.equal(data.toString()) expect(msg).to.have.property('seqno') @@ -158,8 +164,54 @@ describe('pubsub', function () { series([ (cb) => jsD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => setTimeout(() => { cb() }, 500), (cb) => goD.api.pubsub.publish(topic, data, cb), (cb) => waitFor(() => n === 1, cb), ], done) }) + + describe.skip('binary data', () => { + it('publish from Go, subscribe on Go', (done) => { + const topic = 'pubsub-binary-go-go' + const data = Buffer.from('00010203040506070809', 'hex') + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString('hex')).to.equal(data.toString('hex')) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', goId) + } + + series([ + (cb) => goD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => goD.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb) + ], done) + }) + + it('publish from JS, subscribe on Go', (done) => { + const topic = 'pubsub-binary-js-go' + const data = Buffer.from('00010203040506070809', 'hex') + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString('hex')).to.equal(data.toString('hex')) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', goId) + } + + series([ + (cb) => goD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => jsD.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb) + ], done) + }) + + }) }) From 8c7eaf0945f082646f37b694df82f16b5a8e8dce Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 17 Nov 2017 12:28:43 +1300 Subject: [PATCH 12/25] test: enable pubsub tests --- test/cli/pubsub.js | 2 +- test/http-api/interface/pubsub.js | 3 --- test/http-api/spec/pubsub.js | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/test/cli/pubsub.js b/test/cli/pubsub.js index 703b83a5b0..49c6786093 100644 --- a/test/cli/pubsub.js +++ b/test/cli/pubsub.js @@ -14,7 +14,7 @@ const createTempNode = '' const repoPath = require('./index').repoPath const ipfs = require('../utils/ipfs-exec')(repoPath) -describe.skip('pubsub', () => { +describe('pubsub', () => { const topicA = 'nonscentsA' const topicB = 'nonscentsB' const topicC = 'nonscentsC' diff --git a/test/http-api/interface/pubsub.js b/test/http-api/interface/pubsub.js index 968227c83b..ab474fac9f 100644 --- a/test/http-api/interface/pubsub.js +++ b/test/http-api/interface/pubsub.js @@ -2,8 +2,6 @@ 'use strict' -// TODO needs: https://github.com/ipfs/js-ipfs-api/pull/493 -/* const test = require('interface-ipfs-core') const FactoryClient = require('./../../utils/ipfs-factory-daemon') @@ -20,4 +18,3 @@ const common = { } test.pubsub(common) -*/ diff --git a/test/http-api/spec/pubsub.js b/test/http-api/spec/pubsub.js index 245b6d153c..c109bf8893 100644 --- a/test/http-api/spec/pubsub.js +++ b/test/http-api/spec/pubsub.js @@ -10,7 +10,7 @@ const createTempNode = '' // TODO migrate to use ipfs-factory-daemon module.exports = (http) => { - describe.skip('/pubsub', () => { + describe('/pubsub', () => { let api let tmpNode From 6c89ce467ddda7fd05efe58fdfbb773256d2bcdd Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 17 Nov 2017 15:21:43 +1300 Subject: [PATCH 13/25] fix: generate meaniful error when pubsub is called and not enabled --- src/core/components/no-floodsub.js | 25 +++++++++++++++++++++++++ src/core/components/start.js | 11 +++++------ src/core/components/stop.js | 8 +------- 3 files changed, 31 insertions(+), 13 deletions(-) create mode 100644 src/core/components/no-floodsub.js diff --git a/src/core/components/no-floodsub.js b/src/core/components/no-floodsub.js new file mode 100644 index 0000000000..923c978c30 --- /dev/null +++ b/src/core/components/no-floodsub.js @@ -0,0 +1,25 @@ +'use strict' + +const EventEmitter = require('events') + +function fail() { + throw new Error('The daemon must be run with \'--enable-pubsub-experiment\'') +} + +class NoFloodSub extends EventEmitter { + constructor () { + super() + + this.peers = new Map() + this.subscriptions = new Set() + } + + start (callback) { callback() } + stop (callback) { callback() } + publish () { fail() } + subscribe () { fail() } + unsubscribe () { fail() } + +} + +module.exports = NoFloodSub diff --git a/src/core/components/start.js b/src/core/components/start.js index 54ff3c9833..9575c3e3c6 100644 --- a/src/core/components/start.js +++ b/src/core/components/start.js @@ -3,6 +3,7 @@ const series = require('async/series') const Bitswap = require('ipfs-bitswap') const FloodSub = require('libp2p-floodsub') +const NoFloodSub = require('./no-floodsub') const setImmediate = require('async/setImmediate') const promisify = require('promisify-es6') @@ -50,12 +51,10 @@ module.exports = (self) => { self._bitswap.start() self._blockService.setExchange(self._bitswap) - if (self._options.EXPERIMENTAL.pubsub) { - self._pubsub = new FloodSub(self._libp2pNode) - self._pubsub.start(done) - } else { - done() - } + self._pubsub = self._options.EXPERIMENTAL.pubsub + ? new FloodSub(self._libp2pNode) + : new NoFloodSub() + self._pubsub.start(done) }) }) } diff --git a/src/core/components/stop.js b/src/core/components/stop.js index 3a2dd8c04f..6ac0dc91a3 100644 --- a/src/core/components/stop.js +++ b/src/core/components/stop.js @@ -31,13 +31,7 @@ module.exports = (self) => { self._bitswap.stop() series([ - (cb) => { - if (self._options.EXPERIMENTAL.pubsub) { - self._pubsub.stop(cb) - } else { - cb() - } - }, + (cb) => self._pubsub.stop(cb), (cb) => self.libp2p.stop(cb), (cb) => self._repo.close(cb) ], done) From 63a7c5b8887cc2f6eb5dd6a5891b3f79b8596c2d Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 17 Nov 2017 16:42:59 +1300 Subject: [PATCH 14/25] test: enable pubsub for factory daemon --- test/utils/ipfs-factory-daemon/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/utils/ipfs-factory-daemon/index.js b/test/utils/ipfs-factory-daemon/index.js index 9c7a61ce73..b67ea40727 100644 --- a/test/utils/ipfs-factory-daemon/index.js +++ b/test/utils/ipfs-factory-daemon/index.js @@ -52,7 +52,9 @@ class Factory { }) }, (cb) => { - daemon = new HttpApi(repoPath, config) + daemon = new HttpApi(repoPath, config, { + enablePubsubExperiment: true, + }) daemon.repoPath = repoPath this.daemonsSpawned.push(daemon) From 3d3363fd8e3122cd9c37cceb73ed325d1d23288a Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 17 Nov 2017 23:36:57 +1300 Subject: [PATCH 15/25] fiix(pubsub-subscribe): stop HAPI gzip from buffering our streamed response --- src/http/api/resources/pubsub.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/http/api/resources/pubsub.js b/src/http/api/resources/pubsub.js index 6aa1ad6f82..3f77557c7e 100644 --- a/src/http/api/resources/pubsub.js +++ b/src/http/api/resources/pubsub.js @@ -48,6 +48,7 @@ exports.subscribe = { reply(res) .header('X-Chunked-Output', '1') + .header('content-encoding', 'identity') // stop gzip from buffering, see https://github.com/hapijs/hapi/issues/2975 .header('content-type', 'application/json') }) } From 42ceb4b3c8683a7e5329e7fdf1b83dcb7cf2771e Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sat, 18 Nov 2017 15:18:00 +1300 Subject: [PATCH 16/25] test: fix spec/pubsub --- test/http-api/index.js | 5 ++++- test/http-api/spec/pubsub.js | 19 +------------------ 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/test/http-api/index.js b/test/http-api/index.js index e2c7f34ce3..3508b1bb80 100644 --- a/test/http-api/index.js +++ b/test/http-api/index.js @@ -19,7 +19,10 @@ describe('HTTP API', () => { let http = {} before((done) => { - http.api = new API(repoTests) + const options = { + enablePubsubExperiment: true + } + http.api = new API(repoTests, null, options) ncp(repoExample, repoTests, (err) => { expect(err).to.not.exist() diff --git a/test/http-api/spec/pubsub.js b/test/http-api/spec/pubsub.js index c109bf8893..cf4dad7f58 100644 --- a/test/http-api/spec/pubsub.js +++ b/test/http-api/spec/pubsub.js @@ -6,9 +6,7 @@ const chai = require('chai') const dirtyChai = require('dirty-chai') const expect = chai.expect chai.use(dirtyChai) -const createTempNode = '' -// TODO migrate to use ipfs-factory-daemon module.exports = (http) => { describe('/pubsub', () => { let api @@ -18,23 +16,8 @@ module.exports = (http) => { const topic = 'nonScents' const topicNotSubscribed = 'somethingRandom' - before((done) => { + before(() => { api = http.api.server.select('API') - - createTempNode(47, (err, _ipfs) => { - expect(err).to.not.exist() - tmpNode = _ipfs - tmpNode.goOnline((err) => { - expect(err).to.not.exist() - done() - }) - }) - }) - - after((done) => { - setTimeout(() => { - tmpNode.goOffline(done) - }, 1000) }) describe('/sub', () => { From b12e688ed4123eeb765ae096ce58767993d991a7 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sat, 18 Nov 2017 15:40:28 +1300 Subject: [PATCH 17/25] fix: lint errors --- src/core/components/no-floodsub.js | 3 +-- test/http-api/spec/pubsub.js | 1 - test/utils/ipfs-factory-daemon/index.js | 4 ++-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/core/components/no-floodsub.js b/src/core/components/no-floodsub.js index 923c978c30..95db571f5f 100644 --- a/src/core/components/no-floodsub.js +++ b/src/core/components/no-floodsub.js @@ -2,7 +2,7 @@ const EventEmitter = require('events') -function fail() { +function fail () { throw new Error('The daemon must be run with \'--enable-pubsub-experiment\'') } @@ -19,7 +19,6 @@ class NoFloodSub extends EventEmitter { publish () { fail() } subscribe () { fail() } unsubscribe () { fail() } - } module.exports = NoFloodSub diff --git a/test/http-api/spec/pubsub.js b/test/http-api/spec/pubsub.js index cf4dad7f58..9c69427246 100644 --- a/test/http-api/spec/pubsub.js +++ b/test/http-api/spec/pubsub.js @@ -10,7 +10,6 @@ chai.use(dirtyChai) module.exports = (http) => { describe('/pubsub', () => { let api - let tmpNode const buf = Buffer.from('some message') const topic = 'nonScents' diff --git a/test/utils/ipfs-factory-daemon/index.js b/test/utils/ipfs-factory-daemon/index.js index b67ea40727..6b6ab1e1ba 100644 --- a/test/utils/ipfs-factory-daemon/index.js +++ b/test/utils/ipfs-factory-daemon/index.js @@ -52,8 +52,8 @@ class Factory { }) }, (cb) => { - daemon = new HttpApi(repoPath, config, { - enablePubsubExperiment: true, + daemon = new HttpApi(repoPath, config, { + enablePubsubExperiment: true }) daemon.repoPath = repoPath this.daemonsSpawned.push(daemon) From bc0e1bd933decdb7c02d44bcfeefa64adfd706b6 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sat, 18 Nov 2017 20:57:14 +1300 Subject: [PATCH 18/25] test: tests js/go pubsub interop --- test/interop/pubsub.js | 117 +++++++++++++++++++--- test/utils/interop-daemon-spawner/go.js | 3 +- test/utils/interop-daemon-spawner/js.js | 7 +- test/utils/interop-daemon-spawner/util.js | 2 +- 4 files changed, 108 insertions(+), 21 deletions(-) diff --git a/test/interop/pubsub.js b/test/interop/pubsub.js index b76f21967f..8e0a19a3b4 100644 --- a/test/interop/pubsub.js +++ b/test/interop/pubsub.js @@ -11,7 +11,24 @@ const parallel = require('async/parallel') const GODaemon = require('../utils/interop-daemon-spawner/go') const JSDaemon = require('../utils/interop-daemon-spawner/js') -describe('pubsub', () => { +/* + * Wait for a condition to become true. When its true, callback is called. + */ +function waitFor (predicate, callback) { + const ttl = Date.now() + (2 * 1000) + const self = setInterval(() => { + if (predicate()) { + clearInterval(self) + callback() + } + if (Date.now() > ttl) { + clearInterval(self) + callback(new Error("waitFor time expired")) + } + }, 500) +} + +describe('pubsub', function () { let jsD let goD let jsId @@ -34,47 +51,115 @@ describe('pubsub', () => { }) after((done) => { - series([ + parallel([ (cb) => goD.stop(cb), (cb) => jsD.stop(cb) ], done) }) it('make connections', (done) => { - parallel([ + series([ (cb) => jsD.api.id(cb), (cb) => goD.api.id(cb) ], (err, ids) => { expect(err).to.not.exist() - jsId = ids[0].ID - goId = ids[0].ID + jsId = ids[0].id + goId = ids[1].id - console.log('jsId:', jsId) - console.log('goId:', goId) + const jsLocalAddr = ids[0].addresses.find(a => a.includes('127.0.0.1')) + const goLocalAddr = ids[1].addresses.find(a => a.includes('127.0.0.1')) parallel([ - (cb) => jsD.api.swarm.connect(ids[1].addresses[0], cb), - (cb) => goD.api.swarm.connect(ids[0].addresses[0], cb) + (cb) => jsD.api.swarm.connect(goLocalAddr, cb), + (cb) => goD.api.swarm.connect(jsLocalAddr, cb) ], done) }) }) - it.skip('publish from JS, subscribe on Go', (done) => { - // TODO write this test + it('publish from Go, subscribe on Go', (done) => { + const topic = 'pubsub-go-go' + const data = Buffer.from('hello world') + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString()).to.equal(data.toString()) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + // TODO: expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', goId) + } + + series([ + (cb) => goD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => goD.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb) + ], done) + }) + + it('publish from JS, subscribe on JS', (done) => { + const topic = 'pubsub-js-js' + const data = Buffer.from('hello world') + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString()).to.equal(data.toString()) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', jsId) + } + + series([ + (cb) => jsD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => jsD.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb) + ], done) + }) + + it('publish from JS, subscribe on Go', (done) => { + const topic = 'pubsub-js-go' + const data = Buffer.from('hello world') + let n = 0 + + function checkMessage (msg) { + console.log('check message', msg) + ++n + expect(msg.data.toString()).to.equal(data.toString()) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', jsId) + } + + series([ + (cb) => goD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => jsD.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb) + ], done) }) - it.skip('publish from Go, subscribe on JS', (done) => { + it('publish from Go, subscribe on JS', (done) => { const topic = 'pubsub-go-js' const data = Buffer.from('hello world') + let n = 0 - function checkMessage () { - console.log('check message', arguments) + function checkMessage (msg) { + console.log('check message', msg) + ++n + expect(msg.data.toString()).to.equal(data.toString()) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', goId) } series([ - cb => jsD.api.pubsub.subscribe(topic, checkMessage, cb), - cb => goD.api.pubsub.publish(topic, data, cb) + (cb) => jsD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => goD.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb), ], done) }) }) diff --git a/test/utils/interop-daemon-spawner/go.js b/test/utils/interop-daemon-spawner/go.js index 92a04ca99e..8010724d81 100644 --- a/test/utils/interop-daemon-spawner/go.js +++ b/test/utils/interop-daemon-spawner/go.js @@ -40,8 +40,7 @@ class GoDaemon { this.node = node this.node.setConfig('Bootstrap', '[]', cb) }, - (res, cb) => this.node.startDaemon(cb), - // (res, cb) => this.node.startDaemon(this.flags, cb), + (res, cb) => this.node.startDaemon(this.flags, cb), (api, cb) => { this.api = api diff --git a/test/utils/interop-daemon-spawner/js.js b/test/utils/interop-daemon-spawner/js.js index e96850c82b..bd376ff892 100644 --- a/test/utils/interop-daemon-spawner/js.js +++ b/test/utils/interop-daemon-spawner/js.js @@ -37,14 +37,17 @@ class JsDaemon extends EventEmitter { this.path = opts.path || tmpDir() this._started = false + const extras = { + enablePubsubExperiment: true + } if (this.init) { const p = portConfig(this.port) this.node = new HttpApi(this.path, { Bootstrap: [], Addresses: p - }) + }, extras) } else { - this.node = new HttpApi(this.path) + this.node = new HttpApi(this.path, null, extras) } this.node.start(this.init, (err) => { diff --git a/test/utils/interop-daemon-spawner/util.js b/test/utils/interop-daemon-spawner/util.js index 256f857f0c..c0ca77a338 100644 --- a/test/utils/interop-daemon-spawner/util.js +++ b/test/utils/interop-daemon-spawner/util.js @@ -7,7 +7,7 @@ const path = require('path') exports.tmpDir = (prefix) => { return path.join( os.tmpdir(), - prefix || 'tmp', + prefix || 'js-ipfs-interop', crypto.randomBytes(32).toString('hex') ) } From fb726a7f4dbb6af6541378358e387e05abd5ba1e Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Tue, 21 Nov 2017 01:00:03 +1300 Subject: [PATCH 19/25] test: pubsub interop tests --- test/interop/node.js | 1 + test/interop/pubsub-go.js | 134 ++++++++++++++++++++++++++++++++++++++ test/interop/pubsub-js.js | 132 +++++++++++++++++++++++++++++++++++++ test/interop/pubsub.js | 66 +++++++++++++++++-- 4 files changed, 326 insertions(+), 7 deletions(-) create mode 100644 test/interop/pubsub-go.js create mode 100644 test/interop/pubsub-js.js diff --git a/test/interop/node.js b/test/interop/node.js index 7e4a513445..a2e415b87a 100644 --- a/test/interop/node.js +++ b/test/interop/node.js @@ -6,3 +6,4 @@ require('./exchange-files') require('./circuit-relay') require('./kad-dht') require('./pubsub') +require('./pubsub-go') diff --git a/test/interop/pubsub-go.js b/test/interop/pubsub-go.js new file mode 100644 index 0000000000..86f8488648 --- /dev/null +++ b/test/interop/pubsub-go.js @@ -0,0 +1,134 @@ +/* eslint-env mocha */ +'use strict' + +const chai = require('chai') +const dirtyChai = require('dirty-chai') +const expect = chai.expect +chai.use(dirtyChai) +const series = require('async/series') +const parallel = require('async/parallel') + +const GODaemon = require('../utils/interop-daemon-spawner/go') + +/* + * Wait for a condition to become true. When its true, callback is called. + */ +function waitFor (predicate, callback) { + const ttl = Date.now() + (2 * 1000) + const self = setInterval(() => { + if (predicate()) { + clearInterval(self) + return callback() + } + if (Date.now() > ttl) { + clearInterval(self) + return callback(new Error("waitFor time expired")) + } + }, 500) +} + +describe('pubsub GO 2 GO', function () { + this.timeout(4 * 1000) + + let go1D + let go2D + let go1Id + let go2Id + + before(function (done) { + this.timeout(50 * 1000) + + go1D = new GODaemon({ + disposable: true, + init: true, + flags: ['--enable-pubsub-experiment'] + }) + go2D = new GODaemon({ + disposable: true, + init: true, + flags: ['--enable-pubsub-experiment'] + }) + + parallel([ + (cb) => go1D.start(cb), + (cb) => go2D.start(cb) + ], (done)) + }) + + after((done) => { + parallel([ + (cb) => go1D.stop(cb), + (cb) => go2D.stop(cb) + ], done) + }) + + it('make connections', (done) => { + series([ + (cb) => go1D.api.id(cb), + (cb) => go2D.api.id(cb) + ], (err, ids) => { + expect(err).to.not.exist() + + go1Id = ids[0].id + go2Id = ids[1].id + + const go1LocalAddr = ids[0].addresses.find(a => a.includes('127.0.0.1')) + const go2LocalAddr = ids[1].addresses.find(a => a.includes('127.0.0.1')) + + parallel([ + (cb) => go1D.api.swarm.connect(go2LocalAddr, cb), + (cb) => go2D.api.swarm.connect(go1LocalAddr, cb), + (cb) => setTimeout(() => { + cb() + }, 1000) + ], done) + }) + }) + + it('publish from Go2, subscribe on Go1', (done) => { + const topic = 'pubsub-go2-go1' + const data = Buffer.from('hello world') + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString()).to.equal(data.toString()) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', go2Id) + } + + series([ + (cb) => go1D.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => setTimeout(() => { cb() }, 500), + (cb) => go2D.api.pubsub.publish(topic, data, cb), + (cb) => go2D.api.pubsub.publish(topic, data, cb), + (cb) => go2D.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 3, cb) + ], done) + }) + + it('publish binary data', (done) => { + const topic = 'pubsub-binary-go1-go2' + const data = Buffer.from('00010203040506070809', 'hex') + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString('hex')).to.equal(data.toString('hex')) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', go2Id) + } + + series([ + (cb) => go1D.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => setTimeout(() => { cb() }, 500), + (cb) => go2D.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb) + ], done) + }) + +}) diff --git a/test/interop/pubsub-js.js b/test/interop/pubsub-js.js new file mode 100644 index 0000000000..252ac6daf9 --- /dev/null +++ b/test/interop/pubsub-js.js @@ -0,0 +1,132 @@ +/* eslint-env mocha */ +'use strict' + +const chai = require('chai') +const dirtyChai = require('dirty-chai') +const expect = chai.expect +chai.use(dirtyChai) +const series = require('async/series') +const parallel = require('async/parallel') + +const JSDaemon = require('../utils/interop-daemon-spawner/js') + +/* + * Wait for a condition to become true. When its true, callback is called. + */ +function waitFor (predicate, callback) { + const ttl = Date.now() + (2 * 1000) + const self = setInterval(() => { + if (predicate()) { + clearInterval(self) + return callback() + } + if (Date.now() > ttl) { + clearInterval(self) + return callback(new Error("waitFor time expired")) + } + }, 500) +} + +describe('pubsub JS 2 JS', function () { + this.timeout(4 * 1000) + + let js1D + let js2D + let js1Id + let js2Id + + before(function (done) { + this.timeout(50 * 1000) + + js1D = new JSDaemon() + js2D = new JSDaemon({ + disposable: true, + init: true, + port: 2 + }) + + parallel([ + (cb) => js1D.start(cb), + (cb) => js2D.start(cb) + ], (done)) + }) + + after(function (done) { + this.timeout(10 * 1000) + + parallel([ + (cb) => js1D.stop(cb), + (cb) => js2D.stop(cb) + ], done) + }) + + it('make connections', (done) => { + series([ + (cb) => js1D.api.id(cb), + (cb) => js2D.api.id(cb) + ], (err, ids) => { + expect(err).to.not.exist() + + js1Id = ids[0].id + js2Id = ids[1].id + + const js1LocalAddr = ids[0].addresses.find(a => a.includes('127.0.0.1')) + const js2LocalAddr = ids[1].addresses.find(a => a.includes('127.0.0.1')) + + parallel([ + (cb) => js1D.api.swarm.connect(js2LocalAddr, cb), + (cb) => js2D.api.swarm.connect(js1LocalAddr, cb), + (cb) => setTimeout(() => { + cb() + }, 1000) + ], done) + }) + }) + + it('publish from JS2, subscribe on JS1', (done) => { + const topic = 'pubsub-js2-js1' + const data = Buffer.from('hello world') + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString()).to.equal(data.toString()) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', js2Id) + } + + series([ + (cb) => js1D.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => setTimeout(() => { cb() }, 500), + (cb) => js2D.api.pubsub.publish(topic, data, cb), + (cb) => js2D.api.pubsub.publish(topic, data, cb), + (cb) => js2D.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 3, cb) + ], done) + }) + + it('publish binary data', (done) => { + const topic = 'pubsub-binary-js1-js2' + const data = Buffer.from('00010203040506070809', 'hex') + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString('hex')).to.equal(data.toString('hex')) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', js2Id) + } + + series([ + (cb) => js1D.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => setTimeout(() => { cb() }, 500), + (cb) => js2D.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb) + ], done) + }) + +}) diff --git a/test/interop/pubsub.js b/test/interop/pubsub.js index 8e0a19a3b4..0f91022cf4 100644 --- a/test/interop/pubsub.js +++ b/test/interop/pubsub.js @@ -19,16 +19,18 @@ function waitFor (predicate, callback) { const self = setInterval(() => { if (predicate()) { clearInterval(self) - callback() + return callback() } if (Date.now() > ttl) { clearInterval(self) - callback(new Error("waitFor time expired")) + return callback(new Error("waitFor time expired")) } }, 500) } describe('pubsub', function () { + this.timeout(4 * 1000) + let jsD let goD let jsId @@ -50,7 +52,9 @@ describe('pubsub', function () { ], (done)) }) - after((done) => { + after(function (done) { + this.timeout(50 * 1000) + parallel([ (cb) => goD.stop(cb), (cb) => jsD.stop(cb) @@ -72,7 +76,10 @@ describe('pubsub', function () { parallel([ (cb) => jsD.api.swarm.connect(goLocalAddr, cb), - (cb) => goD.api.swarm.connect(jsLocalAddr, cb) + (cb) => goD.api.swarm.connect(jsLocalAddr, cb), + (cb) => setTimeout(() => { + cb() + }, 1000) ], done) }) }) @@ -87,7 +94,7 @@ describe('pubsub', function () { expect(msg.data.toString()).to.equal(data.toString()) expect(msg).to.have.property('seqno') expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) - // TODO: expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('topicIDs').eql([topic]) expect(msg).to.have.property('from', goId) } @@ -125,7 +132,6 @@ describe('pubsub', function () { let n = 0 function checkMessage (msg) { - console.log('check message', msg) ++n expect(msg.data.toString()).to.equal(data.toString()) expect(msg).to.have.property('seqno') @@ -136,6 +142,7 @@ describe('pubsub', function () { series([ (cb) => goD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => setTimeout(() => { cb() }, 500), (cb) => jsD.api.pubsub.publish(topic, data, cb), (cb) => waitFor(() => n === 1, cb) ], done) @@ -147,7 +154,6 @@ describe('pubsub', function () { let n = 0 function checkMessage (msg) { - console.log('check message', msg) ++n expect(msg.data.toString()).to.equal(data.toString()) expect(msg).to.have.property('seqno') @@ -158,8 +164,54 @@ describe('pubsub', function () { series([ (cb) => jsD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => setTimeout(() => { cb() }, 500), (cb) => goD.api.pubsub.publish(topic, data, cb), (cb) => waitFor(() => n === 1, cb), ], done) }) + + describe.skip('binary data', () => { + it('publish from Go, subscribe on Go', (done) => { + const topic = 'pubsub-binary-go-go' + const data = Buffer.from('00010203040506070809', 'hex') + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString('hex')).to.equal(data.toString('hex')) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', goId) + } + + series([ + (cb) => goD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => goD.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb) + ], done) + }) + + it('publish from JS, subscribe on Go', (done) => { + const topic = 'pubsub-binary-js-go' + const data = Buffer.from('00010203040506070809', 'hex') + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString('hex')).to.equal(data.toString('hex')) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', goId) + } + + series([ + (cb) => goD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => jsD.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb) + ], done) + }) + + }) }) From 5bc9ce24890d55ad9acf3284c7ef2324f1174c7c Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Tue, 21 Nov 2017 16:24:36 +1300 Subject: [PATCH 20/25] test: more tests with different data types Note that binary data from JS to GO fails --- test/interop/pubsub.js | 290 +++++++++++++++++++++++++++++------------ 1 file changed, 210 insertions(+), 80 deletions(-) diff --git a/test/interop/pubsub.js b/test/interop/pubsub.js index 0f91022cf4..ec15fa7804 100644 --- a/test/interop/pubsub.js +++ b/test/interop/pubsub.js @@ -83,97 +83,184 @@ describe('pubsub', function () { ], done) }) }) - - it('publish from Go, subscribe on Go', (done) => { - const topic = 'pubsub-go-go' + + describe('ascii data', () => { const data = Buffer.from('hello world') - let n = 0 - - function checkMessage (msg) { - ++n - expect(msg.data.toString()).to.equal(data.toString()) - expect(msg).to.have.property('seqno') - expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) - expect(msg).to.have.property('topicIDs').eql([topic]) - expect(msg).to.have.property('from', goId) - } - series([ - (cb) => goD.api.pubsub.subscribe(topic, checkMessage, cb), - (cb) => goD.api.pubsub.publish(topic, data, cb), - (cb) => waitFor(() => n === 1, cb) - ], done) - }) + it('publish from Go, subscribe on Go', (done) => { + const topic = 'pubsub-go-go' + let n = 0 - it('publish from JS, subscribe on JS', (done) => { - const topic = 'pubsub-js-js' - const data = Buffer.from('hello world') - let n = 0 - - function checkMessage (msg) { - ++n - expect(msg.data.toString()).to.equal(data.toString()) - expect(msg).to.have.property('seqno') - expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) - expect(msg).to.have.property('topicIDs').eql([topic]) - expect(msg).to.have.property('from', jsId) - } + function checkMessage (msg) { + ++n + expect(msg.data.toString()).to.equal(data.toString()) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', goId) + } - series([ - (cb) => jsD.api.pubsub.subscribe(topic, checkMessage, cb), - (cb) => jsD.api.pubsub.publish(topic, data, cb), - (cb) => waitFor(() => n === 1, cb) - ], done) - }) + series([ + (cb) => goD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => goD.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb) + ], done) + }) - it('publish from JS, subscribe on Go', (done) => { - const topic = 'pubsub-js-go' - const data = Buffer.from('hello world') - let n = 0 - - function checkMessage (msg) { - ++n - expect(msg.data.toString()).to.equal(data.toString()) - expect(msg).to.have.property('seqno') - expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) - expect(msg).to.have.property('topicIDs').eql([topic]) - expect(msg).to.have.property('from', jsId) - } + it('publish from JS, subscribe on JS', (done) => { + const topic = 'pubsub-js-js' + let n = 0 - series([ - (cb) => goD.api.pubsub.subscribe(topic, checkMessage, cb), - (cb) => setTimeout(() => { cb() }, 500), - (cb) => jsD.api.pubsub.publish(topic, data, cb), - (cb) => waitFor(() => n === 1, cb) - ], done) + function checkMessage (msg) { + ++n + expect(msg.data.toString()).to.equal(data.toString()) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', jsId) + } + + series([ + (cb) => jsD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => jsD.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb) + ], done) + }) + + it('publish from JS, subscribe on Go', (done) => { + const topic = 'pubsub-js-go' + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString()).to.equal(data.toString()) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', jsId) + } + + series([ + (cb) => goD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => setTimeout(() => { cb() }, 500), + (cb) => jsD.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb) + ], done) + }) + + it('publish from Go, subscribe on JS', (done) => { + const topic = 'pubsub-go-js' + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString()).to.equal(data.toString()) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', goId) + } + + series([ + (cb) => jsD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => setTimeout(() => { cb() }, 500), + (cb) => goD.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb), + ], done) + }) }) - it('publish from Go, subscribe on JS', (done) => { - const topic = 'pubsub-go-js' - const data = Buffer.from('hello world') - let n = 0 - - function checkMessage (msg) { - ++n - expect(msg.data.toString()).to.equal(data.toString()) - expect(msg).to.have.property('seqno') - expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) - expect(msg).to.have.property('topicIDs').eql([topic]) - expect(msg).to.have.property('from', goId) - } + describe('non-ascii data', () => { + const data = Buffer.from('你好世界') - series([ - (cb) => jsD.api.pubsub.subscribe(topic, checkMessage, cb), - (cb) => setTimeout(() => { cb() }, 500), - (cb) => goD.api.pubsub.publish(topic, data, cb), - (cb) => waitFor(() => n === 1, cb), - ], done) + it('publish from Go, subscribe on Go', (done) => { + const topic = 'pubsub-non-ascii-go-go' + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString()).to.equal(data.toString()) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', goId) + } + + series([ + (cb) => goD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => goD.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb) + ], done) + }) + + it('publish from JS, subscribe on JS', (done) => { + const topic = 'pubsub-non-ascii-js-js' + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString()).to.equal(data.toString()) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', jsId) + } + + series([ + (cb) => jsD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => jsD.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb) + ], done) + }) + + it('publish from JS, subscribe on Go', (done) => { + const topic = 'pubsub-non-ascii-js-go' + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString()).to.equal(data.toString()) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', jsId) + } + + series([ + (cb) => goD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => setTimeout(() => { cb() }, 500), + (cb) => jsD.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb) + ], done) + }) + + it('publish from Go, subscribe on JS', (done) => { + const topic = 'pubsub-non-ascii-go-js' + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString()).to.equal(data.toString()) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', goId) + } + + series([ + (cb) => jsD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => setTimeout(() => { cb() }, 500), + (cb) => goD.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb), + ], done) + }) }) - describe.skip('binary data', () => { + describe('binary data', () => { + const data = Buffer.from('a36161636179656162830103056164a16466666666f400010203040506070809', 'hex') + it('publish from Go, subscribe on Go', (done) => { const topic = 'pubsub-binary-go-go' - const data = Buffer.from('00010203040506070809', 'hex') let n = 0 function checkMessage (msg) { @@ -187,6 +274,28 @@ describe('pubsub', function () { series([ (cb) => goD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => setTimeout(() => { cb() }, 500), + (cb) => goD.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb) + ], done) + }) + + it('publish from Go, subscribe on JS', (done) => { + const topic = 'pubsub-binary-go-js' + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString('hex')).to.equal(data.toString('hex')) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', goId) + } + + series([ + (cb) => jsD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => setTimeout(() => { cb() }, 500), (cb) => goD.api.pubsub.publish(topic, data, cb), (cb) => waitFor(() => n === 1, cb) ], done) @@ -194,7 +303,6 @@ describe('pubsub', function () { it('publish from JS, subscribe on Go', (done) => { const topic = 'pubsub-binary-js-go' - const data = Buffer.from('00010203040506070809', 'hex') let n = 0 function checkMessage (msg) { @@ -203,11 +311,33 @@ describe('pubsub', function () { expect(msg).to.have.property('seqno') expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) expect(msg).to.have.property('topicIDs').eql([topic]) - expect(msg).to.have.property('from', goId) + expect(msg).to.have.property('from', jsId) } series([ (cb) => goD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => setTimeout(() => { cb() }, 500), + (cb) => jsD.api.pubsub.publish(topic, data, cb), + (cb) => waitFor(() => n === 1, cb) + ], done) + }) + + it('publish from JS, subscribe on JS', (done) => { + const topic = 'pubsub-binary-js-js' + let n = 0 + + function checkMessage (msg) { + ++n + expect(msg.data.toString('hex')).to.equal(data.toString('hex')) + expect(msg).to.have.property('seqno') + expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) + expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg).to.have.property('from', jsId) + } + + series([ + (cb) => jsD.api.pubsub.subscribe(topic, checkMessage, cb), + (cb) => setTimeout(() => { cb() }, 500), (cb) => jsD.api.pubsub.publish(topic, data, cb), (cb) => waitFor(() => n === 1, cb) ], done) From 9d83fa32707f502843c9f7021a113b421a087fab Mon Sep 17 00:00:00 2001 From: Pedro Teixeira Date: Tue, 21 Nov 2017 15:15:28 +0000 Subject: [PATCH 21/25] HTTP API server: parsing query string as binary in pubsub publish --- package.json | 1 + src/http/api/resources/pubsub.js | 7 +++++-- test/interop/pubsub.js | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 5c8bb5f8c3..3fbca02589 100644 --- a/package.json +++ b/package.json @@ -93,6 +93,7 @@ }, "dependencies": { "async": "^2.6.0", + "binary-querystring": "^0.1.1", "bl": "^1.2.1", "boom": "^7.1.1", "bs58": "^4.0.1", diff --git a/src/http/api/resources/pubsub.js b/src/http/api/resources/pubsub.js index 3f77557c7e..7b57eb47a9 100644 --- a/src/http/api/resources/pubsub.js +++ b/src/http/api/resources/pubsub.js @@ -2,6 +2,7 @@ const PassThrough = require('stream').PassThrough const bs58 = require('bs58') +const binaryQueryString = require('binary-querystring') exports = module.exports @@ -58,7 +59,9 @@ exports.publish = { handler: (request, reply) => { const arg = request.query.arg const topic = arg[0] - const buf = arg[1] + + const rawArgs = binaryQueryString(request.url.search) + const buf = rawArgs.arg[1] const ipfs = request.server.app.ipfs @@ -70,7 +73,7 @@ exports.publish = { return reply(new Error('Missing buf')) } - ipfs.pubsub.publish(topic, Buffer.from(String(buf)), (err) => { + ipfs.pubsub.publish(topic, buf, (err) => { if (err) { return reply(new Error(`Failed to publish to topic ${topic}: ${err}`)) } diff --git a/test/interop/pubsub.js b/test/interop/pubsub.js index ec15fa7804..74085e5ed2 100644 --- a/test/interop/pubsub.js +++ b/test/interop/pubsub.js @@ -83,7 +83,7 @@ describe('pubsub', function () { ], done) }) }) - + describe('ascii data', () => { const data = Buffer.from('hello world') @@ -258,7 +258,7 @@ describe('pubsub', function () { describe('binary data', () => { const data = Buffer.from('a36161636179656162830103056164a16466666666f400010203040506070809', 'hex') - + it('publish from Go, subscribe on Go', (done) => { const topic = 'pubsub-binary-go-go' let n = 0 From fc724e170eb51115fcc75c83d6393fc2e1f25ab3 Mon Sep 17 00:00:00 2001 From: Pedro Teixeira Date: Tue, 21 Nov 2017 16:29:34 +0000 Subject: [PATCH 22/25] HTTP API: pubsub: publish should fail gracefully when no argument is given --- src/http/api/resources/pubsub.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/http/api/resources/pubsub.js b/src/http/api/resources/pubsub.js index 7b57eb47a9..ce37d8f2d1 100644 --- a/src/http/api/resources/pubsub.js +++ b/src/http/api/resources/pubsub.js @@ -61,7 +61,7 @@ exports.publish = { const topic = arg[0] const rawArgs = binaryQueryString(request.url.search) - const buf = rawArgs.arg[1] + const buf = rawArgs.arg && rawArgs.arg[1] const ipfs = request.server.app.ipfs From 7b5dc81fc458bfaed53caa6a7ec0ca5d054e9109 Mon Sep 17 00:00:00 2001 From: David Dias Date: Wed, 22 Nov 2017 08:44:43 +0000 Subject: [PATCH 23/25] chore: update deps --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 3fbca02589..6797c077f6 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ }, "homepage": "https://github.com/ipfs/js-ipfs#readme", "devDependencies": { - "aegir": "^12.1.3", + "aegir": "^12.2.0", "buffer-loader": "0.0.1", "chai": "^4.1.2", "delay": "^2.0.0", @@ -76,7 +76,7 @@ "form-data": "^2.3.1", "gulp": "^3.9.1", "hat": "0.0.3", - "interface-ipfs-core": "~0.36.6", + "interface-ipfs-core": "~0.36.7", "ipfsd-ctl": "~0.24.1", "left-pad": "^1.2.0", "lodash": "^4.17.4", @@ -122,7 +122,7 @@ "joi": "^13.0.2", "libp2p": "~0.13.1", "libp2p-circuit": "~0.1.4", - "libp2p-floodsub": "~0.11.1", + "libp2p-floodsub": "~0.12.1", "libp2p-kad-dht": "~0.6.0", "libp2p-mdns": "~0.9.1", "libp2p-multiplex": "~0.5.0", From 0c98a48fa53751c989ba2e0eacbe4921ed66f45a Mon Sep 17 00:00:00 2001 From: David Dias Date: Wed, 22 Nov 2017 09:13:40 +0000 Subject: [PATCH 24/25] chore: update deps --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 6797c077f6..563f9edb04 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "gulp": "^3.9.1", "hat": "0.0.3", "interface-ipfs-core": "~0.36.7", - "ipfsd-ctl": "~0.24.1", + "ipfsd-ctl": "~0.25.0", "left-pad": "^1.2.0", "lodash": "^4.17.4", "mocha": "^4.0.1", @@ -93,7 +93,7 @@ }, "dependencies": { "async": "^2.6.0", - "binary-querystring": "^0.1.1", + "binary-querystring": "~0.1.2", "bl": "^1.2.1", "boom": "^7.1.1", "bs58": "^4.0.1", @@ -108,7 +108,7 @@ "hapi": "^16.6.2", "hapi-set-header": "^1.0.2", "hoek": "^5.0.2", - "ipfs-api": "^17.1.0", + "ipfs-api": "^17.1.1", "ipfs-bitswap": "~0.17.4", "ipfs-block": "~0.6.1", "ipfs-block-service": "~0.13.0", From 18179d72cdb45512b40e252d005a7023093df278 Mon Sep 17 00:00:00 2001 From: David Dias Date: Wed, 22 Nov 2017 09:35:39 +0000 Subject: [PATCH 25/25] last pass --- package.json | 4 +- test/interop/pubsub-go.js | 134 -------------------------------------- test/interop/pubsub-js.js | 132 ------------------------------------- test/interop/pubsub.js | 8 +-- test/interop/repo.js | 2 +- 5 files changed, 7 insertions(+), 273 deletions(-) delete mode 100644 test/interop/pubsub-go.js delete mode 100644 test/interop/pubsub-js.js diff --git a/package.json b/package.json index 563f9edb04..4a353ee6bf 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "test:unit:node:gateway": "aegir test -t node -f test/gateway/index.js", "test:unit:node:cli": "aegir test -t node -f test/cli/index.js", "test:unit:browser": "aegir test -t browser --no-cors", - "test:interop": "IPFS_TEST=interop aegir test -t node -t browser -f test/interop", + "test:interop": "IPFS_TEST=interop aegir test -t node -f test/interop", "test:interop:node": "IPFS_TEST=interop aegir test -t node -f test/interop/node.js", "test:interop:browser": "IPFS_TEST=interop aegir test -t browser -f test/interop/browser.js", "test:bootstrapers": "IPFS_TEST=bootstrapers aegir test -t browser -f test/bootstrapers.js", @@ -77,7 +77,7 @@ "gulp": "^3.9.1", "hat": "0.0.3", "interface-ipfs-core": "~0.36.7", - "ipfsd-ctl": "~0.25.0", + "ipfsd-ctl": "~0.25.1", "left-pad": "^1.2.0", "lodash": "^4.17.4", "mocha": "^4.0.1", diff --git a/test/interop/pubsub-go.js b/test/interop/pubsub-go.js deleted file mode 100644 index 86f8488648..0000000000 --- a/test/interop/pubsub-go.js +++ /dev/null @@ -1,134 +0,0 @@ -/* eslint-env mocha */ -'use strict' - -const chai = require('chai') -const dirtyChai = require('dirty-chai') -const expect = chai.expect -chai.use(dirtyChai) -const series = require('async/series') -const parallel = require('async/parallel') - -const GODaemon = require('../utils/interop-daemon-spawner/go') - -/* - * Wait for a condition to become true. When its true, callback is called. - */ -function waitFor (predicate, callback) { - const ttl = Date.now() + (2 * 1000) - const self = setInterval(() => { - if (predicate()) { - clearInterval(self) - return callback() - } - if (Date.now() > ttl) { - clearInterval(self) - return callback(new Error("waitFor time expired")) - } - }, 500) -} - -describe('pubsub GO 2 GO', function () { - this.timeout(4 * 1000) - - let go1D - let go2D - let go1Id - let go2Id - - before(function (done) { - this.timeout(50 * 1000) - - go1D = new GODaemon({ - disposable: true, - init: true, - flags: ['--enable-pubsub-experiment'] - }) - go2D = new GODaemon({ - disposable: true, - init: true, - flags: ['--enable-pubsub-experiment'] - }) - - parallel([ - (cb) => go1D.start(cb), - (cb) => go2D.start(cb) - ], (done)) - }) - - after((done) => { - parallel([ - (cb) => go1D.stop(cb), - (cb) => go2D.stop(cb) - ], done) - }) - - it('make connections', (done) => { - series([ - (cb) => go1D.api.id(cb), - (cb) => go2D.api.id(cb) - ], (err, ids) => { - expect(err).to.not.exist() - - go1Id = ids[0].id - go2Id = ids[1].id - - const go1LocalAddr = ids[0].addresses.find(a => a.includes('127.0.0.1')) - const go2LocalAddr = ids[1].addresses.find(a => a.includes('127.0.0.1')) - - parallel([ - (cb) => go1D.api.swarm.connect(go2LocalAddr, cb), - (cb) => go2D.api.swarm.connect(go1LocalAddr, cb), - (cb) => setTimeout(() => { - cb() - }, 1000) - ], done) - }) - }) - - it('publish from Go2, subscribe on Go1', (done) => { - const topic = 'pubsub-go2-go1' - const data = Buffer.from('hello world') - let n = 0 - - function checkMessage (msg) { - ++n - expect(msg.data.toString()).to.equal(data.toString()) - expect(msg).to.have.property('seqno') - expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) - expect(msg).to.have.property('topicIDs').eql([topic]) - expect(msg).to.have.property('from', go2Id) - } - - series([ - (cb) => go1D.api.pubsub.subscribe(topic, checkMessage, cb), - (cb) => setTimeout(() => { cb() }, 500), - (cb) => go2D.api.pubsub.publish(topic, data, cb), - (cb) => go2D.api.pubsub.publish(topic, data, cb), - (cb) => go2D.api.pubsub.publish(topic, data, cb), - (cb) => waitFor(() => n === 3, cb) - ], done) - }) - - it('publish binary data', (done) => { - const topic = 'pubsub-binary-go1-go2' - const data = Buffer.from('00010203040506070809', 'hex') - let n = 0 - - function checkMessage (msg) { - ++n - expect(msg.data.toString('hex')).to.equal(data.toString('hex')) - expect(msg).to.have.property('seqno') - expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) - expect(msg).to.have.property('topicIDs').eql([topic]) - expect(msg).to.have.property('from', go2Id) - } - - series([ - (cb) => go1D.api.pubsub.subscribe(topic, checkMessage, cb), - (cb) => setTimeout(() => { cb() }, 500), - (cb) => go2D.api.pubsub.publish(topic, data, cb), - (cb) => waitFor(() => n === 1, cb) - ], done) - }) - -}) diff --git a/test/interop/pubsub-js.js b/test/interop/pubsub-js.js deleted file mode 100644 index 252ac6daf9..0000000000 --- a/test/interop/pubsub-js.js +++ /dev/null @@ -1,132 +0,0 @@ -/* eslint-env mocha */ -'use strict' - -const chai = require('chai') -const dirtyChai = require('dirty-chai') -const expect = chai.expect -chai.use(dirtyChai) -const series = require('async/series') -const parallel = require('async/parallel') - -const JSDaemon = require('../utils/interop-daemon-spawner/js') - -/* - * Wait for a condition to become true. When its true, callback is called. - */ -function waitFor (predicate, callback) { - const ttl = Date.now() + (2 * 1000) - const self = setInterval(() => { - if (predicate()) { - clearInterval(self) - return callback() - } - if (Date.now() > ttl) { - clearInterval(self) - return callback(new Error("waitFor time expired")) - } - }, 500) -} - -describe('pubsub JS 2 JS', function () { - this.timeout(4 * 1000) - - let js1D - let js2D - let js1Id - let js2Id - - before(function (done) { - this.timeout(50 * 1000) - - js1D = new JSDaemon() - js2D = new JSDaemon({ - disposable: true, - init: true, - port: 2 - }) - - parallel([ - (cb) => js1D.start(cb), - (cb) => js2D.start(cb) - ], (done)) - }) - - after(function (done) { - this.timeout(10 * 1000) - - parallel([ - (cb) => js1D.stop(cb), - (cb) => js2D.stop(cb) - ], done) - }) - - it('make connections', (done) => { - series([ - (cb) => js1D.api.id(cb), - (cb) => js2D.api.id(cb) - ], (err, ids) => { - expect(err).to.not.exist() - - js1Id = ids[0].id - js2Id = ids[1].id - - const js1LocalAddr = ids[0].addresses.find(a => a.includes('127.0.0.1')) - const js2LocalAddr = ids[1].addresses.find(a => a.includes('127.0.0.1')) - - parallel([ - (cb) => js1D.api.swarm.connect(js2LocalAddr, cb), - (cb) => js2D.api.swarm.connect(js1LocalAddr, cb), - (cb) => setTimeout(() => { - cb() - }, 1000) - ], done) - }) - }) - - it('publish from JS2, subscribe on JS1', (done) => { - const topic = 'pubsub-js2-js1' - const data = Buffer.from('hello world') - let n = 0 - - function checkMessage (msg) { - ++n - expect(msg.data.toString()).to.equal(data.toString()) - expect(msg).to.have.property('seqno') - expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) - expect(msg).to.have.property('topicIDs').eql([topic]) - expect(msg).to.have.property('from', js2Id) - } - - series([ - (cb) => js1D.api.pubsub.subscribe(topic, checkMessage, cb), - (cb) => setTimeout(() => { cb() }, 500), - (cb) => js2D.api.pubsub.publish(topic, data, cb), - (cb) => js2D.api.pubsub.publish(topic, data, cb), - (cb) => js2D.api.pubsub.publish(topic, data, cb), - (cb) => waitFor(() => n === 3, cb) - ], done) - }) - - it('publish binary data', (done) => { - const topic = 'pubsub-binary-js1-js2' - const data = Buffer.from('00010203040506070809', 'hex') - let n = 0 - - function checkMessage (msg) { - ++n - expect(msg.data.toString('hex')).to.equal(data.toString('hex')) - expect(msg).to.have.property('seqno') - expect(Buffer.isBuffer(msg.seqno)).to.be.eql(true) - expect(msg).to.have.property('topicIDs').eql([topic]) - expect(msg).to.have.property('from', js2Id) - } - - series([ - (cb) => js1D.api.pubsub.subscribe(topic, checkMessage, cb), - (cb) => setTimeout(() => { cb() }, 500), - (cb) => js2D.api.pubsub.publish(topic, data, cb), - (cb) => waitFor(() => n === 1, cb) - ], done) - }) - -}) diff --git a/test/interop/pubsub.js b/test/interop/pubsub.js index 74085e5ed2..a69aacb37e 100644 --- a/test/interop/pubsub.js +++ b/test/interop/pubsub.js @@ -8,7 +8,7 @@ chai.use(dirtyChai) const series = require('async/series') const parallel = require('async/parallel') -const GODaemon = require('../utils/interop-daemon-spawner/go') +const GoDaemon = require('../utils/interop-daemon-spawner/go') const JSDaemon = require('../utils/interop-daemon-spawner/js') /* @@ -23,13 +23,13 @@ function waitFor (predicate, callback) { } if (Date.now() > ttl) { clearInterval(self) - return callback(new Error("waitFor time expired")) + return callback(new Error('waitFor time expired')) } }, 500) } describe('pubsub', function () { - this.timeout(4 * 1000) + this.timeout(5 * 1000) let jsD let goD @@ -39,7 +39,7 @@ describe('pubsub', function () { before(function (done) { this.timeout(50 * 1000) - goD = new GODaemon({ + goD = new GoDaemon({ disposable: true, init: true, flags: ['--enable-pubsub-experiment'] diff --git a/test/interop/repo.js b/test/interop/repo.js index bd981d0ff9..4956b0d543 100644 --- a/test/interop/repo.js +++ b/test/interop/repo.js @@ -24,7 +24,7 @@ function catAndCheck (daemon, hash, data, callback) { }) } -describe('repo', () => { +describe.only('repo', () => { it('read repo: go -> js', (done) => { const dir = os.tmpdir() + '/' + Math.ceil(Math.random() * 10000) const data = crypto.randomBytes(1024 * 5)