From b8b2d931e65a21920445d29d72b6e57ce2079f27 Mon Sep 17 00:00:00 2001 From: Vasco Santos Date: Thu, 30 May 2019 15:06:24 +0100 Subject: [PATCH] chore: enable some browser tests (#80) --- .aegir.js | 71 +++++++ .travis.yml | 16 ++ package.json | 7 + test/{2-nodes.js => 2-nodes.spec.js} | 28 +-- test/fixtures/test-peer.json | 5 + ...ltiple-nodes.js => multiple-nodes.spec.js} | 189 +++++++++--------- test/node.js | 4 - test/pubsub.spec.js | 2 +- test/utils/browser-bundle.js | 31 +++ test/utils/constants.js | 40 ++++ test/{utils.js => utils/index.js} | 4 +- test/{ => utils}/nodejs-bundle.js | 2 + 12 files changed, 287 insertions(+), 112 deletions(-) create mode 100644 .aegir.js rename test/{2-nodes.js => 2-nodes.spec.js} (94%) create mode 100644 test/fixtures/test-peer.json rename test/{multiple-nodes.js => multiple-nodes.spec.js} (67%) delete mode 100644 test/node.js create mode 100644 test/utils/browser-bundle.js create mode 100644 test/utils/constants.js rename test/{utils.js => utils/index.js} (87%) rename test/{ => utils}/nodejs-bundle.js (89%) diff --git a/.aegir.js b/.aegir.js new file mode 100644 index 0000000000..1cbcf2b54b --- /dev/null +++ b/.aegir.js @@ -0,0 +1,71 @@ +'use strict' + +const pull = require('pull-stream') +const parallel = require('async/parallel') +const WebSocketStarRendezvous = require('libp2p-websocket-star-rendezvous') + +const Node = require('./test/utils/nodejs-bundle.js') +const { + getPeerRelay, + WS_RENDEZVOUS_MULTIADDR +} = require('./test/utils/constants') + +let wsRendezvous +let node + +const before = (done) => { + parallel([ + (cb) => { + WebSocketStarRendezvous.start({ + port: WS_RENDEZVOUS_MULTIADDR.nodeAddress().port, + refreshPeerListIntervalMS: 1000, + strictMultiaddr: false, + cryptoChallenge: true + }, (err, _server) => { + if (err) { + return cb(err) + } + wsRendezvous = _server + cb() + }) + }, + (cb) => { + getPeerRelay((err, peerInfo) => { + if (err) { + return done(err) + } + + node = new Node({ + peerInfo, + config: { + relay: { + enabled: true, + hop: { + enabled: true, + active: true + } + } + } + }) + + node.handle('/echo/1.0.0', (_, conn) => pull(conn, conn)) + node.start(cb) + }) + } + ], done) +} + +const after = (done) => { + setTimeout(() => + parallel( + [node, wsRendezvous].map((s) => (cb) => s.stop(cb)), + done), + 2000) +} + +module.exports = { + hooks: { + pre: before, + post: after + } +} diff --git a/.travis.yml b/.travis.yml index 32d81f9f49..e0d74ff547 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,5 +24,21 @@ jobs: - npx aegir dep-check -- -i wrtc -i electron-webrtc - npm run lint + - stage: test + name: chrome + addons: + chrome: stable + script: + - npx aegir test -t browser + - npx aegir test -t webworker + + - stage: test + name: firefox + addons: + firefox: latest + script: + - npx aegir test -t browser -- --browsers FirefoxHeadless + - npx aegir test -t webworker -- --browsers FirefoxHeadless + notifications: email: false diff --git a/package.json b/package.json index 4cdd12c924..5985597ee8 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,9 @@ "coverage": "aegir coverage", "coverage-publish": "aegir coverage --provider coveralls" }, + "browser": { + "test/utils/nodejs-bundle": "./test/utils/browser-bundle.js" + }, "files": [ "src", "dist" @@ -46,12 +49,16 @@ "benchmark": "^2.1.4", "chai": "^4.2.0", "chai-spies": "^1.0.0", + "detect-node": "^2.0.4", "dirty-chai": "^2.0.1", "libp2p": "~0.24.4", "libp2p-secio": "~0.11.1", "libp2p-spdy": "~0.13.3", "libp2p-tcp": "~0.13.0", + "libp2p-websocket-star": "~0.10.2", + "libp2p-websocket-star-rendezvous": "~0.3.0", "lodash": "^4.17.11", + "multiaddr": "^6.0.6", "peer-id": "~0.12.2", "peer-info": "~0.15.1", "sinon": "^7.3.2" diff --git a/test/2-nodes.js b/test/2-nodes.spec.js similarity index 94% rename from test/2-nodes.js rename to test/2-nodes.spec.js index eb5caf4b43..7901a42c21 100644 --- a/test/2-nodes.js +++ b/test/2-nodes.spec.js @@ -25,8 +25,8 @@ describe('basics between 2 nodes', () => { before((done) => { series([ - (cb) => createNode('/ip4/127.0.0.1/tcp/0', cb), - (cb) => createNode('/ip4/127.0.0.1/tcp/0', cb) + (cb) => createNode(cb), + (cb) => createNode(cb) ], (err, nodes) => { if (err) { return done(err) @@ -209,8 +209,8 @@ describe('basics between 2 nodes', () => { before((done) => { parallel([ - (cb) => createNode('/ip4/127.0.0.1/tcp/0', cb), - (cb) => createNode('/ip4/127.0.0.1/tcp/0', cb) + (cb) => createNode(cb), + (cb) => createNode(cb) ], (err, nodes) => { expect(err).to.not.exist() @@ -285,8 +285,8 @@ describe('basics between 2 nodes', () => { before((done) => { series([ - (cb) => createNode('/ip4/127.0.0.1/tcp/0', cb), - (cb) => createNode('/ip4/127.0.0.1/tcp/0', cb) + (cb) => createNode(cb), + (cb) => createNode(cb) ], (cb, nodes) => { nodeA = nodes[0] nodeB = nodes[1] @@ -352,8 +352,8 @@ describe('basics between 2 nodes', () => { before((done) => { series([ - (cb) => createNode('/ip4/127.0.0.1/tcp/0', cb), - (cb) => createNode('/ip4/127.0.0.1/tcp/0', cb) + (cb) => createNode(cb), + (cb) => createNode(cb) ], (cb, nodes) => { nodeA = nodes[0] nodeB = nodes[1] @@ -403,8 +403,8 @@ describe('basics between 2 nodes', () => { sandbox = chai.spy.sandbox() series([ - (cb) => createNode('/ip4/127.0.0.1/tcp/0', cb), - (cb) => createNode('/ip4/127.0.0.1/tcp/0', cb) + (cb) => createNode(cb), + (cb) => createNode(cb) ], (err, nodes) => { if (err) return done(err) @@ -464,8 +464,8 @@ describe('basics between 2 nodes', () => { sandbox = chai.spy.sandbox() series([ - (cb) => createNode('/ip4/127.0.0.1/tcp/0', cb), - (cb) => createNode('/ip4/127.0.0.1/tcp/0', cb) + (cb) => createNode(cb), + (cb) => createNode(cb) ], (err, nodes) => { if (err) return done(err) @@ -536,8 +536,8 @@ describe('basics between 2 nodes', () => { sandbox = chai.spy.sandbox() series([ - (cb) => createNode('/ip4/127.0.0.1/tcp/0', cb), - (cb) => createNode('/ip4/127.0.0.1/tcp/0', cb) + (cb) => createNode(cb), + (cb) => createNode(cb) ], (err, nodes) => { if (err) return done(err) diff --git a/test/fixtures/test-peer.json b/test/fixtures/test-peer.json new file mode 100644 index 0000000000..105046aa65 --- /dev/null +++ b/test/fixtures/test-peer.json @@ -0,0 +1,5 @@ +{ + "id": "Qmex1SSsueWFsUfjdkugJ5zhcnjddAt8TxcnDLUXKD9Sx7", + "privKey": "CAASqAkwggSkAgEAAoIBAQCXzV127CvVHOGMzvsn/U+/32JM58KA6k0FSCCeNFzNowiDS/vV5eezGN5AFoxsF6icWLoaczz7l9RdVD+I/t6PEt9X7XUdrDCtSS8WmAcCgvZWSSf7yAd3jT4GSZDUIgIEeRZsERDt/yVqTLwsZ1G9dMIeh8sbf2zwjTXZIWaRM6o4lq3DYFfzLvJUXlJodxPogU7l7nLkITPUv+yQAMcVHizbNwJvwiETKYeUj73/m/wEPAlnFESexDstxNiIwE/FH8Ao50QPZRO6E6Jb0hhYSI/4CLRdrzDFm/Vzplei3Wr2DokSROaNyeG37VAueyA+pDqn84um+L9uXLwbv5FbAgMBAAECggEAdBUzV/GaQ0nmoQrWvOnUxmFIho7kCjkh1NwnNVPNc+Msa1r7pcI9wJNPwap8j1w4L/cZuYhOJgcg+o2mWFiuULKZ4F9Ro/M89gZ038457g2/2pPu43c/Xoi/2YcAHXg0Gr+OCe2zCIyITBWKAFqyAzL6DubAxrJW2Ezj1LrZ+EZgMyzbh/go/eEGSJaaGkINeAkY144DqDWWWvzyhKhryipsGkZGEkVy9xJgMEI3ipVvuPez2XAvoyyeuinBBLe+Z2vY5G50XXzbIMhIQGLncHf9MwTv6wt1ilyOSLOXK0BoQbB76J3R3is5dSULXXP9r8VocjLBEkmBuf4FXAKzoQKBgQDNNS4F1XE1gxD8LPkL+aB/hi6eVHVPhr+w0I/9ATikcLGeUfBM2Gd6cZRPFtNVrv1p6ZF1D1UyGDknGbDBSQd9wLUgb0fDoo3jKYMGWq6G+VvaP5rzWQeBV8YV2EhSmUk1i6kiYe2ZE8WyrPie7iwpQIY60e2A8Ly0GKZiBZUcHQKBgQC9YDAVsGnEHFVFkTDpvw5HwEzCgTb2A3NgkGY3rTYZ7L6AFjqCYmUwFB8Fmbyc4kdFWNh8wfmq5Qrvl49NtaeukiqWKUUlB8uPdztB1P0IahA2ks0owStZlRifmwfgYyMd4xE17lhaOgQQJZZPxmP0F6mdOvb3YJafNURCdMS51wKBgEvvIM+h0tmFXXSjQ6kNvzlRMtD92ccKysYn9xAdMpOO6/r0wSH+dhQWEVZO0PcE4NsfReb2PIVj90ojtIdhebcr5xpQc1LORQjJJKXmSmzBux6AqNrhl+hhzXfp56FA/Zkly/lgGWaqrV5XqUxOP+Mn8EO1yNgMvRc7g94DyNB1AoGBAKLBuXHalXwDsdHBUB2Eo3xNLGt6bEcRfia+0+sEBdxQGQWylQScFkU09dh1YaIf44sZKa5HdBFJGpYCVxo9hmjFnK5Dt/Z0daHOonIY4INLzLVqg8KECoLKXkhGEIXsDjFQhukn+G1LMVTDSSU055DQiWjlVX4UWD9qo0jOXIkvAoGBAMP50p2X6PsWWZUuuR7i1JOJHRyQZPWdHh9p8SSLnCtEpHYZfJr4INXNmhnSiB/3TUnHix2vVKjosjMTCk/CjfzXV2H41WPOLZ2/Pi3SxCicWIRj4kCcWhkEuIF2jGkg1+jmNiCl/zNMaBOAIP3QbDPtqOWbYlPd2YIzdj6WQ6R4", + "pubKey": "CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCXzV127CvVHOGMzvsn/U+/32JM58KA6k0FSCCeNFzNowiDS/vV5eezGN5AFoxsF6icWLoaczz7l9RdVD+I/t6PEt9X7XUdrDCtSS8WmAcCgvZWSSf7yAd3jT4GSZDUIgIEeRZsERDt/yVqTLwsZ1G9dMIeh8sbf2zwjTXZIWaRM6o4lq3DYFfzLvJUXlJodxPogU7l7nLkITPUv+yQAMcVHizbNwJvwiETKYeUj73/m/wEPAlnFESexDstxNiIwE/FH8Ao50QPZRO6E6Jb0hhYSI/4CLRdrzDFm/Vzplei3Wr2DokSROaNyeG37VAueyA+pDqn84um+L9uXLwbv5FbAgMBAAE=" +} \ No newline at end of file diff --git a/test/multiple-nodes.js b/test/multiple-nodes.spec.js similarity index 67% rename from test/multiple-nodes.js rename to test/multiple-nodes.spec.js index a4825c913b..12bbc1b6e2 100644 --- a/test/multiple-nodes.js +++ b/test/multiple-nodes.spec.js @@ -7,6 +7,8 @@ chai.use(require('dirty-chai')) const expect = chai.expect const parallel = require('async/parallel') +const isNode = require('detect-node') + const FloodSub = require('../src') const utils = require('./utils') const first = utils.first @@ -198,110 +200,115 @@ describe('multiple nodes (more than 2)', () => { }) }) - describe('2 level tree', () => { - // 2 levels tree - // ┌◉┐ - // │c│ - // ┌◉─┘ └─◉┐ - // │b d│ - // ◉─┘ └─◉ - // a e - - let a - let b - let c - let d - let e + if (isNode) { + // TODO enable for browser + describe('2 level tree', () => { + // 2 levels tree + // ┌◉┐ + // │c│ + // ┌◉─┘ └─◉┐ + // │b d│ + // ◉─┘ └─◉ + // a e + + let a + let b + let c + let d + let e + + before((done) => { + parallel([ + (cb) => spawnPubSubNode(cb), + (cb) => spawnPubSubNode(cb), + (cb) => spawnPubSubNode(cb), + (cb) => spawnPubSubNode(cb), + (cb) => spawnPubSubNode(cb) + ], (err, nodes) => { + if (err) { + return done(err) + } + a = nodes[0] + b = nodes[1] + c = nodes[2] + d = nodes[3] + e = nodes[4] - before((done) => { - parallel([ - (cb) => spawnPubSubNode(cb), - (cb) => spawnPubSubNode(cb), - (cb) => spawnPubSubNode(cb), - (cb) => spawnPubSubNode(cb), - (cb) => spawnPubSubNode(cb) - ], (err, nodes) => { - if (err) { - return done(err) - } - a = nodes[0] - b = nodes[1] - c = nodes[2] - d = nodes[3] - e = nodes[4] + done() + }) + }) - done() + after((done) => { + // note: setTimeout to avoid the tests finishing + // before swarm does its dials + setTimeout(() => { + parallel([ + (cb) => a.libp2p.stop(cb), + (cb) => b.libp2p.stop(cb), + (cb) => c.libp2p.stop(cb), + (cb) => d.libp2p.stop(cb), + (cb) => e.libp2p.stop(cb) + ], done) + }, 1000) }) - }) - after((done) => { - // note: setTimeout to avoid the tests finishing - // before swarm does its dials - setTimeout(() => { + it('establish the connections', function (done) { + this.timeout(30 * 1000) parallel([ - (cb) => a.libp2p.stop(cb), - (cb) => b.libp2p.stop(cb), - (cb) => c.libp2p.stop(cb), - (cb) => d.libp2p.stop(cb), - (cb) => e.libp2p.stop(cb) - ], done) - }, 1000) - }) - - it('establish the connections', (done) => { - parallel([ - (cb) => a.libp2p.dial(b.libp2p.peerInfo, cb), - (cb) => b.libp2p.dial(c.libp2p.peerInfo, cb), - (cb) => c.libp2p.dial(d.libp2p.peerInfo, cb), - (cb) => d.libp2p.dial(e.libp2p.peerInfo, cb) - ], (err) => { - expect(err).to.not.exist() - // wait for the pubsub pipes to be established - setTimeout(done, 2000) + (cb) => a.libp2p.dial(b.libp2p.peerInfo, cb), + (cb) => b.libp2p.dial(c.libp2p.peerInfo, cb), + (cb) => c.libp2p.dial(d.libp2p.peerInfo, cb), + (cb) => d.libp2p.dial(e.libp2p.peerInfo, cb) + ], (err) => { + expect(err).to.not.exist() + // wait for the pubsub pipes to be established + setTimeout(done, 10000) + }) }) - }) - it('subscribes', () => { - a.ps.subscribe('Z') - expectSet(a.ps.subscriptions, ['Z']) - b.ps.subscribe('Z') - expectSet(b.ps.subscriptions, ['Z']) - c.ps.subscribe('Z') - expectSet(c.ps.subscriptions, ['Z']) - d.ps.subscribe('Z') - expectSet(d.ps.subscriptions, ['Z']) - e.ps.subscribe('Z') - expectSet(e.ps.subscriptions, ['Z']) - }) + it('subscribes', () => { + a.ps.subscribe('Z') + expectSet(a.ps.subscriptions, ['Z']) + b.ps.subscribe('Z') + expectSet(b.ps.subscriptions, ['Z']) + c.ps.subscribe('Z') + expectSet(c.ps.subscriptions, ['Z']) + d.ps.subscribe('Z') + expectSet(d.ps.subscriptions, ['Z']) + e.ps.subscribe('Z') + expectSet(e.ps.subscriptions, ['Z']) + }) - it('publishes from c', (done) => { - let counter = 0 + it('publishes from c', function (done) { + this.timeout(30 * 1000) + let counter = 0 - a.ps.on('Z', incMsg) - b.ps.on('Z', incMsg) - c.ps.on('Z', incMsg) - d.ps.on('Z', incMsg) - e.ps.on('Z', incMsg) + a.ps.on('Z', incMsg) + b.ps.on('Z', incMsg) + c.ps.on('Z', incMsg) + d.ps.on('Z', incMsg) + e.ps.on('Z', incMsg) - c.ps.publish('Z', Buffer.from('hey from c')) + c.ps.publish('Z', Buffer.from('hey from c')) - function incMsg (msg) { - expect(msg.data.toString()).to.equal('hey from c') - check() - } + function incMsg (msg) { + expect(msg.data.toString()).to.equal('hey from c') + check() + } - function check () { - if (++counter === 5) { - a.ps.removeListener('Z', incMsg) - b.ps.removeListener('Z', incMsg) - c.ps.removeListener('Z', incMsg) - d.ps.removeListener('Z', incMsg) - e.ps.removeListener('Z', incMsg) - done() + function check () { + if (++counter === 5) { + a.ps.removeListener('Z', incMsg) + b.ps.removeListener('Z', incMsg) + c.ps.removeListener('Z', incMsg) + d.ps.removeListener('Z', incMsg) + e.ps.removeListener('Z', incMsg) + done() + } } - } + }) }) - }) + } }) describe('only some nodes subscribe the networks', () => { @@ -341,7 +348,7 @@ describe('multiple nodes (more than 2)', () => { }) function spawnPubSubNode (callback) { - createNode('/ip4/127.0.0.1/tcp/0', (err, node) => { + createNode((err, node) => { if (err) { return callback(err) } diff --git a/test/node.js b/test/node.js deleted file mode 100644 index ac25f09366..0000000000 --- a/test/node.js +++ /dev/null @@ -1,4 +0,0 @@ -'use strict' - -require('./2-nodes.js') -require('./multiple-nodes.js') diff --git a/test/pubsub.spec.js b/test/pubsub.spec.js index 6b9e7c548f..ba3e1ba621 100644 --- a/test/pubsub.spec.js +++ b/test/pubsub.spec.js @@ -16,7 +16,7 @@ describe('pubsub', () => { let libp2p before((done) => { - createNode('/ip4/127.0.0.1/tcp/0', (err, node) => { + createNode((err, node) => { expect(err).to.not.exist() libp2p = node floodsub = new Floodsub(libp2p) diff --git a/test/utils/browser-bundle.js b/test/utils/browser-bundle.js new file mode 100644 index 0000000000..117e0a0e19 --- /dev/null +++ b/test/utils/browser-bundle.js @@ -0,0 +1,31 @@ +'use strict' + +const WebSocketStar = require('libp2p-websocket-star') +const spdy = require('libp2p-spdy') +const secio = require('libp2p-secio') +const libp2p = require('libp2p') + +const { WS_STAR_MULTIADDR } = require('./constants') + +class Node extends libp2p { + constructor ({ peerInfo, peerBook }) { + const starOpts = { id: peerInfo.id } + const wsStar = new WebSocketStar(starOpts) + + peerInfo.multiaddrs.add(WS_STAR_MULTIADDR) + + const modules = { + transport: [wsStar], + streamMuxer: [spdy], + connEncryption: [secio] + } + + super({ + modules, + peerInfo, + peerBook + }) + } +} + +module.exports = Node diff --git a/test/utils/constants.js b/test/utils/constants.js new file mode 100644 index 0000000000..a836a03c43 --- /dev/null +++ b/test/utils/constants.js @@ -0,0 +1,40 @@ +'use strict' + +const PeerId = require('peer-id') +const PeerInfo = require('peer-info') +const nextTick = require('async/nextTick') +const peerJSON = require('../fixtures/test-peer') +const multiaddr = require('multiaddr') + +let peerRelay = null + +/** + * Creates a `PeerInfo` that can be used across testing. Once the + * relay `PeerInfo` has been requested, it will be reused for each + * additional request. + * + * This is currently being used to create a relay on test bootstrapping + * so that it can be used by browser nodes during their test suite. This + * is necessary for running a TCP node during browser tests. + * @private + * @param {function(error, PeerInfo)} callback + * @returns {void} + */ +module.exports.getPeerRelay = (callback) => { + if (peerRelay) return nextTick(callback, null, peerRelay) + + PeerId.createFromJSON(peerJSON, (err, peerId) => { + if (err) { + return callback(err) + } + peerRelay = new PeerInfo(peerId) + + peerRelay.multiaddrs.add('/ip4/127.0.0.1/tcp/9200/ws') + peerRelay.multiaddrs.add('/ip4/127.0.0.1/tcp/9245') + + callback(null, peerRelay) + }) +} + +module.exports.WS_STAR_MULTIADDR = multiaddr('/ip4/127.0.0.1/tcp/14444/ws/p2p-websocket-star/') +module.exports.WS_RENDEZVOUS_MULTIADDR = multiaddr('/ip4/127.0.0.1/tcp/14444/wss') diff --git a/test/utils.js b/test/utils/index.js similarity index 87% rename from test/utils.js rename to test/utils/index.js index caa37ef468..5b61800c46 100644 --- a/test/utils.js +++ b/test/utils/index.js @@ -3,6 +3,7 @@ const PeerId = require('peer-id') const PeerInfo = require('peer-info') const Node = require('./nodejs-bundle') + const waterfall = require('async/waterfall') const expect = require('chai').expect @@ -12,12 +13,11 @@ exports.expectSet = (set, subs) => { expect(Array.from(set.values())).to.eql(subs) } -exports.createNode = (maddr, callback) => { +exports.createNode = (callback) => { waterfall([ (cb) => PeerId.create({ bits: 1024 }, cb), (id, cb) => PeerInfo.create(id, cb), (peerInfo, cb) => { - peerInfo.multiaddrs.add(maddr) cb(null, new Node({ peerInfo })) }, (node, cb) => node.start((err) => cb(err, node)) diff --git a/test/nodejs-bundle.js b/test/utils/nodejs-bundle.js similarity index 89% rename from test/nodejs-bundle.js rename to test/utils/nodejs-bundle.js index c5e840a84d..ef572d1dc5 100644 --- a/test/nodejs-bundle.js +++ b/test/utils/nodejs-bundle.js @@ -13,6 +13,8 @@ class Node extends libp2p { connEncryption: [secio] } + peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/0') + super({ modules, peerInfo,