diff --git a/.travis.yml b/.travis.yml index fdd1203c..b0136dec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,3 +10,10 @@ before_install: script: - npm run lint - npm test + +addons: + firefox: 'latest' + +before_script: + - export DISPLAY=:99.0 + - sh -e /etc/init.d/xvfb start diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 00000000..50ef8cb0 --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,52 @@ +module.exports = function (config) { + var path = require('path') + var nodeForgePath = path.resolve(__dirname, 'node_modules/peer-id/deps/forge.bundle.js') + + config.set({ + basePath: '', + frameworks: ['mocha'], + + files: [ + nodeForgePath, + 'tests/browser.js' + ], + + preprocessors: { + 'tests/*': ['webpack'] + }, + + webpack: { + resolve: { + extensions: ['', '.js', '.json'] + }, + externals: { + fs: '{}', + 'node-forge': 'forge' + }, + node: { + Buffer: true + }, + module: { + loaders: [ + { test: /\.json$/, loader: 'json' } + ] + } + }, + + webpackMiddleware: { + noInfo: true, + stats: { + colors: true + } + }, + reporters: ['spec'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: false, + browsers: process.env.TRAVIS ? ['Firefox'] : ['Chrome'], + captureTimeout: 60000, + browserNoActivityTimeout: 20000, + singleRun: true + }) +} diff --git a/package.json b/package.json index 3cda3a14..ecb670b3 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,9 @@ "description": "libp2p swarm implementation in Node.js", "main": "src/index.js", "scripts": { - "test": "mocha tests/*-test.js", + "test:node": "mocha tests/*-test.js", + "test:browser": "node tests/karma.js", + "test": "npm run test:node && npm run test:browser", "coverage": "istanbul cover --print both -- _mocha tests/*-test.js", "lint": "standard" }, @@ -30,8 +32,16 @@ }, "devDependencies": { "bl": "^1.1.2", + "buffer-loader": "0.0.1", "chai": "^3.5.0", "istanbul": "^0.4.2", + "json-loader": "^0.5.4", + "karma": "^0.13.22", + "karma-chrome-launcher": "^0.2.2", + "karma-firefox-launcher": "^0.1.7", + "karma-mocha": "^0.2.2", + "karma-spec-reporter": "0.0.24", + "karma-webpack": "^1.7.0", "libp2p-spdy": "^0.2.3", "libp2p-tcp": "^0.4.0", "libp2p-websockets": "^0.2.1", @@ -41,7 +51,8 @@ "peer-info": "^0.6.0", "pre-commit": "^1.1.2", "standard": "^6.0.7", - "stream-pair": "^1.0.3" + "stream-pair": "^1.0.3", + "webpack": "^2.1.0-beta.4" }, "dependencies": { "duplex-passthrough": "github:diasdavid/duplex-passthrough", diff --git a/src/identify.js b/src/identify.js index 0ef04ae9..078d8444 100644 --- a/src/identify.js +++ b/src/identify.js @@ -8,12 +8,18 @@ const multistream = require('multistream-select') const fs = require('fs') const path = require('path') -const pbStream = require('protocol-buffers-stream')( - fs.readFileSync(path.join(__dirname, 'identify.proto'))) const Info = require('peer-info') const Id = require('peer-id') const multiaddr = require('multiaddr') +const isNode = !global.window + +const identity = isNode + ? fs.readFileSync(path.join(__dirname, 'identify.proto')) + : require('buffer!./identify.proto') + +const pbStream = require('protocol-buffers-stream')(identity) + exports = module.exports exports.multicodec = '/ipfs/identify/1.0.0' diff --git a/tests/browser.js b/tests/browser.js new file mode 100644 index 00000000..5b679170 --- /dev/null +++ b/tests/browser.js @@ -0,0 +1,133 @@ +/* eslint-env mocha */ + +const expect = require('chai').expect +// const async = require('async') + +const multiaddr = require('multiaddr') +const PeerId = require('peer-id') +const Peer = require('peer-info') +const Swarm = require('../src') +const WebSockets = require('libp2p-websockets') +const bl = require('bl') + +const PEER_ID_SERVER_A = 'QmWg2L4Fucx1x4KXJTfKHGixBJvveubzcd7DdhB2Mqwfh1' +const PEER_ID_SERVER_B = 'QmRy1iU6BHmG5Hd8rnPhPL98cy1W1przUSTAMcGDq9yAAV' +const MULTIADDR_SERVER_A = '/ip4/127.0.0.1/tcp/9888/websockets' +const MULTIADDR_SERVER_B = '/ip4/127.0.0.1/tcp/9999/websockets' + +// random id to be used on the tests +const PEER_ID_A = 'QmYzgdesgjdvD3okTPGZT9NPmh1BuH5FfTVNKjsvaAprhb' + +describe('basics', () => { + it('throws on missing peerInfo', (done) => { + expect(Swarm).to.throw(Error) + done() + }) +}) + +describe('transport - websockets', function () { + this.timeout(10000) + + var swarm + var peerId = PeerId.createFromB58String(PEER_ID_A) + var peer = new Peer(peerId) + + before((done) => { + swarm = new Swarm(peer) + done() + }) + + it('add', (done) => { + swarm.transport.add('ws', new WebSockets(), () => { + expect(Object.keys(swarm.transports).length).to.equal(1) + done() + }) + }) + + it('dial', (done) => { + const conn = swarm.transport.dial('ws', multiaddr(MULTIADDR_SERVER_A), (err, conn) => { + expect(err).to.not.exist + }) + conn.pipe(bl((err, data) => { + expect(err).to.not.exist + expect(data.toString()).to.equal('hey') + done() + })) + conn.write('hey') + conn.end() + }) +}) + +describe('high level API - 1st without stream multiplexing (on websockets)', function () { + this.timeout(10000) + + var swarm + var peerSelf + var peerServerA + var peerServerB + + before((done) => { + const peerServerAId = PeerId.createFromB58String(PEER_ID_SERVER_A) + peerServerA = new Peer(peerServerAId) + const peerServerBId = PeerId.createFromB58String(PEER_ID_SERVER_B) + peerServerB = new Peer(peerServerBId) + const peerSelfId = PeerId.createFromB58String(PEER_ID_A) + peerSelf = new Peer(peerSelfId) + + peerServerA.multiaddr.add(multiaddr(MULTIADDR_SERVER_A)) + peerServerB.multiaddr.add(multiaddr(MULTIADDR_SERVER_B)) + + swarm = new Swarm(peerSelf) + + swarm.transport.add('ws', new WebSockets()) + expect(Object.keys(swarm.transports).length).to.equal(1) + done() + }) + + // after((done) => { + // swarm.close(done) + // }) + + it('dial using transport interface', (done) => { + const conn = swarm.transport.dial('ws', peerServerA.multiaddrs, (err, conn) => { + expect(err).to.not.exist + }) + + conn.pipe(bl((err, data) => { + expect(err).to.not.exist + expect(data.toString()).to.equal('hey') + done() + })) + conn.write('hey') + conn.end() + }) + + it('dial on protocol', (done) => { + swarm.dial(peerServerB, '/pineapple/1.0.0', (err, conn) => { + expect(err).to.not.exist + conn.pipe(bl((err, data) => { + expect(err).to.not.exist + expect(data.toString()).to.equal('yo') + done() + })) + conn.write('yo') + conn.end() + }) + }) + + it('dial to warm a conn', (done) => { + swarm.dial(peerServerB, (err) => { + expect(err).to.not.exist + done() + }) + }) + + it('dial on protocol, reuse warmed conn', (done) => { + swarm.dial(peerServerB, '/pineapple/1.0.0', (err, conn) => { + expect(err).to.not.exist + conn.end() + conn.on('data', () => {}) // let it flow.. let it flooooow + conn.on('end', done) + }) + }) +}) diff --git a/tests/karma.js b/tests/karma.js new file mode 100644 index 00000000..b86a2f81 --- /dev/null +++ b/tests/karma.js @@ -0,0 +1,66 @@ +const Server = require('karma').Server +const path = require('path') + +const Peer = require('peer-info') +const PeerId = require('peer-id') +const WebSockets = require('libp2p-websockets') +const Swarm = require('../src') +const multiaddr = require('multiaddr') + +const PEER_ID_SERVER_A = 'QmWg2L4Fucx1x4KXJTfKHGixBJvveubzcd7DdhB2Mqwfh1' +const PEER_ID_SERVER_B = 'QmRy1iU6BHmG5Hd8rnPhPL98cy1W1przUSTAMcGDq9yAAV' +const MULTIADDR_SERVER_A = '/ip4/127.0.0.1/tcp/9888/websockets' +const MULTIADDR_SERVER_B = '/ip4/127.0.0.1/tcp/9999/websockets' + +var swarmA +var peerA +var swarmB +var peerB + +function createServers (done) { + function createServerA (cb) { + const id = PeerId.createFromB58String(PEER_ID_SERVER_A) + peerA = new Peer(id) + peerA.multiaddr.add(multiaddr(MULTIADDR_SERVER_A)) + swarmA = new Swarm(peerA) + swarmA.transport.add('ws', new WebSockets()) + swarmA.transport.listen('ws', {}, (conn) => { + conn.pipe(conn) + }, cb) + } + + function createServerB (cb) { + const id = PeerId.createFromB58String(PEER_ID_SERVER_B) + peerB = new Peer(id) + peerB.multiaddr.add(multiaddr(MULTIADDR_SERVER_B)) + swarmB = new Swarm(peerB) + swarmB.transport.add('ws', new WebSockets()) + swarmB.handle('/pineapple/1.0.0', (conn) => { + conn.pipe(conn) + }) + swarmB.transport.listen('ws', {}, null, cb) + } + + var count = 0 + const ready = () => ++count === 2 ? done() : null + + createServerA(ready) + createServerB(ready) +} + +function stopServers (done) { + var count = 0 + const ready = () => ++count === 2 ? done() : null + + swarmA.transport.close('ws', ready) + swarmB.transport.close('ws', ready) +} + +function runTests (done) { + new Server({ + configFile: path.join(__dirname, '/../karma.conf.js'), + singleRun: true + }, done).start() +} + +createServers(() => runTests(() => stopServers(() => null)))