diff --git a/.travis.yml b/.travis.yml index dd9e44efb0..68f6dd805b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,8 +14,6 @@ script: - npm test - npm run coverage -addons: - firefox: 'latest' before_script: - export DISPLAY=:99.0 @@ -23,3 +21,14 @@ before_script: after_success: - npm run coverage-publish + +env: + - CXX=g++-4.8 + +addons: + firefox: 'latest' + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.8 diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000000..1660ef766f --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,41 @@ +'use strict' + +const gulp = require('gulp') +const parallel = require('run-parallel') +const series = require('run-series') +const createTempNode = require('./test/utils/temp-node') +const API = require('./src/http-api') + +let nodes = [] + +function startNode (num, done) { + createTempNode(num, (err, node) => { + if (err) throw err + + const api = new API(node.repo.path()) + nodes.push(api) + api.start(done) + }) +} + +gulp.task('libnode:start', (done) => { + nodes = [] + parallel([ + (cb) => startNode(7, cb), + (cb) => startNode(8, cb), + (cb) => startNode(9, cb) + ], done) +}) + +gulp.task('libnode:stop', (done) => { + series(nodes.map((node) => (cb) => { + setTimeout(() => node.stop(cb), 500) + }), done) +}) + +gulp.task('test:browser:before', ['libnode:start']) +gulp.task('test:node:before', ['libnode:start']) +gulp.task('test:browser:after', ['libnode:stop']) +gulp.task('test:node:after', ['libnode:stop']) + +require('aegir/gulp')(gulp) diff --git a/package.json b/package.json index 98114eaaee..afcb210858 100644 --- a/package.json +++ b/package.json @@ -9,14 +9,14 @@ "jsnext:main": "src/core/index.js", "scripts": { "lint": "aegir-lint", - "coverage": "aegir-coverage", - "test": "aegir-test", - "test:node": "aegir-test node", - "test:browser": "aegir-test browser", - "build": "aegir-build", - "release": "aegir-release", - "release:minor": "aegir-release --type minor", - "release:major": "aegir-release --type major", + "coverage": "gulp coverage", + "test": "gulp test", + "test:node": "gulp test:node", + "test:browser": "gulp test:browser", + "build": "gulp build", + "release": "gulp release", + "release:minor": "gulp release --type minor", + "release:major": "gulp release --type major", "coverage-publish": "aegir-coverage publish" }, "pre-commit": [ @@ -38,12 +38,13 @@ "homepage": "https://github.com/ipfs/js-ipfs#readme", "devDependencies": { "aegir": "^3.0.1", - "async": "^2.0.0-rc.4", "buffer-loader": "0.0.1", "chai": "^3.5.0", "expose-loader": "^0.7.1", "form-data": "^1.0.0-rc3", + "gulp": "^3.9.1", "idb-plus-blob-store": "^1.1.2", + "libp2p-ipfs-browser": "^0.2.0", "lodash": "^4.11.2", "mocha": "^2.4.5", "ncp": "^2.0.0", @@ -63,6 +64,7 @@ "glob": "^7.0.3", "hapi": "^13.3.0", "ipfs-api": "^3.0.2", + "ipfs-bitswap": "^0.2.0", "ipfs-block": "^0.3.0", "ipfs-block-service": "^0.4.0", "ipfs-merkle-dag": "^0.5.0", @@ -71,29 +73,32 @@ "ipfs-unixfs-engine": "^0.6.1", "joi": "^8.0.5", "libp2p-ipfs": "^0.3.3", - "libp2p-swarm": "^0.12.5", + "libp2p-swarm": "^0.12.11", "lodash.get": "^4.2.1", "lodash.set": "^4.1.0", "multiaddr": "^1.4.1", "path-exists": "^3.0.0", - "peer-book": "0.1.0", + "peer-book": "^0.1.1", "peer-id": "^0.6.6", "peer-info": "^0.6.2", "readable-stream": "1.1.13", "ronin": "^0.3.11", + "run-parallel": "^1.1.6", + "run-parallel-limit": "^1.0.3", + "run-series": "^1.1.4", + "run-waterfall": "^1.1.3", "temp": "^0.8.3" }, "aegir": { "webpack": { "resolve": { "alias": { - "node-forge": "../../../node_modules/peer-id/vendor/forge.bundle.js" + "node-forge": "../../../node_modules/peer-id/vendor/forge.bundle.js", + "libp2p-ipfs": "libp2p-ipfs-browser" } }, "externals": { "fs": "{}", - "ipfs-data-importing": "{ import: {} }", - "libp2p-ipfs": "{}", "mkdirp": "{}" } } diff --git a/src/cli/commands/bitswap/stat.js b/src/cli/commands/bitswap/stat.js new file mode 100644 index 0000000000..e3643ad218 --- /dev/null +++ b/src/cli/commands/bitswap/stat.js @@ -0,0 +1,38 @@ +'use strict' + +const Command = require('ronin').Command +const utils = require('../../utils') + +module.exports = Command.extend({ + desc: 'Show some diagnostic information on the bitswap agent.', + + options: { + }, + + run: () => { + utils.getIPFS((err, ipfs) => { + if (err) { + throw err + } + + ipfs.bitswap.stat((err, stats) => { + if (err) { + throw err + } + + stats.Wantlist = stats.Wantlist || [] + stats.Peers = stats.Peers || [] + + console.log(` +bitswap status + blocks received: ${stats.BlocksReceived} + dup blocks received: ${stats.DupBlksReceived} + dup data received: ${stats.DupDataReceived}B + wantlist [${stats.Wantlist.length} keys] + ${stats.Wantlist.join('\n ')} + partners [${stats.Peers.length}] + ${stats.Peers.join('\n ')}`) + }) + }) + } +}) diff --git a/src/cli/commands/bitswap/unwant.js b/src/cli/commands/bitswap/unwant.js new file mode 100644 index 0000000000..e09ea250cc --- /dev/null +++ b/src/cli/commands/bitswap/unwant.js @@ -0,0 +1,24 @@ +'use strict' + +const Command = require('ronin').Command +const utils = require('../../utils') + +module.exports = Command.extend({ + desc: 'Remove a given block from your wantlist.', + + options: { + key: { + required: true + } + }, + + run: (key) => { + utils.getIPFS((err, ipfs) => { + if (err) { + throw err + } + + throw new Error('Not implemented yet') + }) + } +}) diff --git a/src/cli/commands/bitswap/wantlist.js b/src/cli/commands/bitswap/wantlist.js new file mode 100644 index 0000000000..daebad04e0 --- /dev/null +++ b/src/cli/commands/bitswap/wantlist.js @@ -0,0 +1,27 @@ +'use strict' + +const Command = require('ronin').Command +const utils = require('../../utils') + +module.exports = Command.extend({ + desc: 'Print out all blocks currently on the bitswap wantlist for the local peer.', + + options: { + }, + + run: () => { + utils.getIPFS((err, ipfs) => { + if (err) { + throw err + } + + ipfs.bitswap.wantlist((err, res) => { + if (err) { + throw err + } + + res.Keys.forEach((k) => console.log(k)) + }) + }) + } +}) diff --git a/src/cli/commands/config/edit.js b/src/cli/commands/config/edit.js index 5bcfde40cc..b510f1e640 100644 --- a/src/cli/commands/config/edit.js +++ b/src/cli/commands/config/edit.js @@ -4,7 +4,7 @@ const Command = require('ronin').Command const spawn = require('child_process').spawn const fs = require('fs') const temp = require('temp') -const async = require('async') +const waterfall = require('run-waterfall') const debug = require('debug') const log = debug('cli:config') log.error = debug('cli:config:error') @@ -99,7 +99,7 @@ module.exports = Command.extend({ }) } - async.waterfall([ + waterfall([ getConfig, saveTempConfig, openEditor, diff --git a/src/cli/commands/files/add.js b/src/cli/commands/files/add.js index 080ed22be3..f69a8b700f 100644 --- a/src/cli/commands/files/add.js +++ b/src/cli/commands/files/add.js @@ -7,7 +7,7 @@ const log = debug('cli:version') log.error = debug('cli:version:error') const bs58 = require('bs58') const fs = require('fs') -const async = require('async') +const parallelLimit = require('run-parallel-limit') const path = require('path') const glob = require('glob') @@ -69,7 +69,7 @@ module.exports = Command.extend({ }) if (res.length !== 0) { const index = inPath.lastIndexOf('/') - async.eachLimit(res, 10, (element, callback) => { + parallelLimit(res.map((element) => (callback) => { if (!fs.statSync(element).isDirectory()) { i.write({ path: element.substring(index + 1, element.length), @@ -77,7 +77,7 @@ module.exports = Command.extend({ }) } callback() - }, (err) => { + }), 10, (err) => { if (err) { throw err } diff --git a/src/core/index.js b/src/core/index.js index e40ba515f7..e6d1d3be32 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -7,6 +7,9 @@ const PeerBook = require('peer-book') const defaultRepo = require('./default-repo') +const goOnline = require('./ipfs/go-online') +const goOffline = require('./ipfs/go-offline') +const isOnline = require('./ipfs/is-online') const load = require('./ipfs/load') const version = require('./ipfs/version') const id = require('./ipfs/id') @@ -18,6 +21,7 @@ const block = require('./ipfs/block') const object = require('./ipfs/object') const libp2p = require('./ipfs/libp2p') const files = require('./ipfs/files') +const bitswap = require('./ipfs/bitswap') exports = module.exports = IPFS @@ -32,12 +36,16 @@ function IPFS (repoInstance) { } this._repo = repoInstance - this._blockS = new BlockService(this._repo) - this._dagS = new DAGService(this._blockS) this._peerInfoBook = new PeerBook() this._peerInfo = null this._libp2pNode = null + this._bitswap = null + this._blockS = new BlockService(this._repo) + this._dagS = new DAGService(this._blockS) + this.goOnline = goOnline(this) + this.goOffline = goOffline(this) + this.isOnline = isOnline(this) this.load = load(this) this.version = version(this) this.id = id(this) @@ -49,4 +57,5 @@ function IPFS (repoInstance) { this.object = object(this) this.libp2p = libp2p(this) this.files = files(this) + this.bitswap = bitswap(this) } diff --git a/src/core/ipfs/bitswap.js b/src/core/ipfs/bitswap.js new file mode 100644 index 0000000000..ada2ecb29e --- /dev/null +++ b/src/core/ipfs/bitswap.js @@ -0,0 +1,42 @@ +'use strict' + +const bs58 = require('bs58') + +const OFFLINE_ERROR = require('../utils').OFFLINE_ERROR + +function formatWantlist (list) { + return Array.from(list).map((el) => { + return bs58.encode(new Buffer(el[0], 'hex')) + }) +} + +module.exports = function bitswap (self) { + return { + wantlist: () => { + if (!self.isOnline()) { + throw OFFLINE_ERROR + } + + const list = self._bitswap.getWantlist() + return formatWantlist(list) + }, + stat: () => { + if (!self.isOnline()) { + throw OFFLINE_ERROR + } + + const stats = self._bitswap.stat() + stats.wantlist = formatWantlist(stats.wantlist) + stats.peers = stats.peers.map((id) => id.toB58String()) + + return stats + }, + unwant: (key) => { + if (!self.isOnline()) { + throw OFFLINE_ERROR + } + + // TODO: implement when https://github.com/ipfs/js-ipfs-bitswap/pull/10 is merged + } + } +} diff --git a/src/core/ipfs/go-offline.js b/src/core/ipfs/go-offline.js new file mode 100644 index 0000000000..4b3858adf3 --- /dev/null +++ b/src/core/ipfs/go-offline.js @@ -0,0 +1,9 @@ +'use strict' + +module.exports = function goOffline (self) { + return (cb) => { + self._blockS.goOffline() + self._bitswap.stop() + self.libp2p.stop(cb) + } +} diff --git a/src/core/ipfs/go-online.js b/src/core/ipfs/go-online.js new file mode 100644 index 0000000000..236359b466 --- /dev/null +++ b/src/core/ipfs/go-online.js @@ -0,0 +1,27 @@ +'use strict' + +const series = require('run-series') +const Bitswap = require('ipfs-bitswap') + +module.exports = function goOnline (self) { + return (cb) => { + series([ + self.load, + self.libp2p.start + ], (err) => { + if (err) { + return cb(err) + } + + self._bitswap = new Bitswap( + self._peerInfo, + self._libp2pNode, + self._repo.datastore, + self._peerInfoBook + ) + self._bitswap.start() + self._blockS.goOnline(self._bitswap) + cb() + }) + } +} diff --git a/src/core/ipfs/id.js b/src/core/ipfs/id.js index 835fc79327..d322b02d51 100644 --- a/src/core/ipfs/id.js +++ b/src/core/ipfs/id.js @@ -16,7 +16,7 @@ module.exports = function id (self) { callback(null, { ID: self._peerInfo.id.toB58String(), PublicKey: self._peerInfo.id.pubKey.toString('base64'), - Addresses: self._peerInfo.multiaddrs.map((ma) => { return ma.toString() }), + Addresses: self._peerInfo.multiaddrs.map((ma) => { return ma.toString() }).sort(), AgentVersion: 'js-ipfs', ProtocolVersion: '9000' }) diff --git a/src/core/ipfs/init.js b/src/core/ipfs/init.js index 2d8ee2e117..e0a020919e 100644 --- a/src/core/ipfs/init.js +++ b/src/core/ipfs/init.js @@ -5,7 +5,7 @@ const BlockService = require('ipfs-block-service') const DagService = require('ipfs-merkle-dag').DAGService const path = require('path') const glob = require('glob') -const async = require('async') +const parallelLimit = require('run-parallel-limit') const Readable = require('stream').Readable const fs = require('fs') const Importer = require('ipfs-unixfs-engine').importer @@ -17,7 +17,7 @@ module.exports = function init (self) { opts.bits = opts.bits || 2048 // Pre-set config values. - var config = require('../../init-files/default-config.json') + var config = JSON.parse(fs.readFileSync(path.join(__dirname, '../../init-files/default-config.json')).toString()) // Verify repo does not yet exist. self._repo.exists((err, exists) => { @@ -85,7 +85,7 @@ module.exports = function init (self) { throw err } const index = __dirname.lastIndexOf('/') - async.eachLimit(res, 10, (element, callback) => { + parallelLimit(res.map((element) => (callback) => { const addPath = element.substring(index + 1, element.length) if (!fs.statSync(element).isDirectory()) { const rs = new Readable() @@ -95,7 +95,7 @@ module.exports = function init (self) { i.write(filePair) } callback() - }, (err) => { + }), 10, (err) => { if (err) { throw err } diff --git a/src/core/ipfs/is-online.js b/src/core/ipfs/is-online.js new file mode 100644 index 0000000000..5c07edb4e3 --- /dev/null +++ b/src/core/ipfs/is-online.js @@ -0,0 +1,7 @@ +'use strict' + +module.exports = function isOnline (self) { + return () => { + return self._bitswap && self._libp2pNode + } +} diff --git a/src/core/ipfs/libp2p.js b/src/core/ipfs/libp2p.js index 7548438397..9a7569015f 100644 --- a/src/core/ipfs/libp2p.js +++ b/src/core/ipfs/libp2p.js @@ -5,9 +5,9 @@ const PeerInfo = require('peer-info') const multiaddr = require('multiaddr') const Libp2pNode = require('libp2p-ipfs').Node -module.exports = function libp2p (self) { - const OFFLINE_ERROR = new Error('This command must be run in online mode. Try running \'ipfs daemon\' first.') +const OFFLINE_ERROR = require('../utils').OFFLINE_ERROR +module.exports = function libp2p (self) { return { start: (callback) => { self._libp2pNode = new Libp2pNode(self._peerInfo) @@ -24,7 +24,7 @@ module.exports = function libp2p (self) { }, swarm: { peers: (callback) => { - if (!self._libp2pNode) { + if (!self.isOnline()) { return callback(OFFLINE_ERROR) } @@ -32,21 +32,21 @@ module.exports = function libp2p (self) { }, // all the addrs we know addrs: (callback) => { - if (!self._libp2pNode) { + if (!self.isOnline()) { return callback(OFFLINE_ERROR) } // TODO throw new Error('Not implemented') }, localAddrs: (callback) => { - if (!self._libp2pNode) { + if (!self.isOnline()) { return callback(OFFLINE_ERROR) } callback(null, self._peerInfo.multiaddrs) }, connect: (ma, callback) => { - if (!self._libp2pNode) { + if (!self.isOnline()) { return callback(OFFLINE_ERROR) } @@ -57,9 +57,8 @@ module.exports = function libp2p (self) { const id = peerId.createFromB58String(idStr[1]) const peer = new PeerInfo(id) - ma = ma.toString().replace(/\/ipfs\/(.*)/, '') // FIXME remove this when multiaddr supports ipfs - peer.multiaddr.add(multiaddr(ma)) + self._peerInfoBook.put(peer) self._libp2pNode.swarm.dial(peer, (err) => { @@ -67,7 +66,7 @@ module.exports = function libp2p (self) { }) }, disconnect: (callback) => { - if (!self._libp2pNode) { + if (!self.isOnline()) { return callback(OFFLINE_ERROR) } diff --git a/src/core/ipfs/load.js b/src/core/ipfs/load.js index dc9cc0a506..9573620581 100644 --- a/src/core/ipfs/load.js +++ b/src/core/ipfs/load.js @@ -10,12 +10,12 @@ module.exports = function load (self) { return (callback) => { utils.ifRepoExists(self._repo, (err) => { if (err) { - throw err + return callback(err) } self._repo.config.get((err, config) => { if (err) { - throw err + return callback(err) } const pid = peerId.createFromPrivKey(config.Identity.PrivKey) self._peerInfo = new PeerInfo(pid) diff --git a/src/core/utils.js b/src/core/utils.js index 4924d754f6..6278eba9ed 100644 --- a/src/core/utils.js +++ b/src/core/utils.js @@ -13,3 +13,5 @@ exports.ifRepoExists = (repo, cb) => { cb() }) } + +exports.OFFLINE_ERROR = new Error('This command must be run in online mode. Try running \'ipfs daemon\' first.') diff --git a/src/http-api/index.js b/src/http-api/index.js index 6289a1e12b..b9b5c98b9a 100644 --- a/src/http-api/index.js +++ b/src/http-api/index.js @@ -1,15 +1,18 @@ 'use strict' +const parallel = require('run-parallel') const Hapi = require('hapi') -const IPFS = require('../core') const debug = require('debug') const fs = require('fs') const path = require('path') -const log = debug('api') -log.error = debug('api:error') const IPFSRepo = require('ipfs-repo') const fsbs = require('fs-blob-store') +const log = debug('api') +log.error = debug('api:error') + +const IPFS = require('../core') + exports = module.exports = function HttpApi (repo) { this.ipfs = null this.server = null @@ -26,7 +29,7 @@ exports = module.exports = function HttpApi (repo) { this.ipfs.load(() => { const repoPath = this.ipfs.repo.path() const apiPath = path.join(repoPath, 'api') - console.log('Finished loading') + try { fs.statSync(apiPath) console.log('This repo is currently being used by another daemon') @@ -70,7 +73,7 @@ exports = module.exports = function HttpApi (repo) { // load routes require('./routes')(this.server) - this.ipfs.libp2p.start(() => { + this.ipfs.goOnline(() => { this.server.start((err) => { if (err) { return callback(err) @@ -89,15 +92,17 @@ exports = module.exports = function HttpApi (repo) { this.stop = (callback) => { const repoPath = this.ipfs.repo.path() fs.unlinkSync(path.join(repoPath, 'api')) - let counter = 0 - this.server.stop(closed) - this.ipfs.libp2p.stop(closed) + console.log('Stopping server') - function closed () { - if (++counter === 2) { - callback() + parallel([ + (cb) => this.server.stop(cb), + (cb) => this.ipfs.goOffline(cb) + ], (err) => { + if (err) { + console.log('There were errors stopping') } - } + callback() + }) } } diff --git a/src/http-api/resources/bitswap.js b/src/http-api/resources/bitswap.js new file mode 100644 index 0000000000..b4d941322d --- /dev/null +++ b/src/http-api/resources/bitswap.js @@ -0,0 +1,46 @@ +'use strict' + +const boom = require('boom') + +const parseKey = require('./block').parseKey + +exports = module.exports + +exports.wantlist = (request, reply) => { + let list + try { + list = request.server.app.ipfs.bitswap.wantlist() + } catch (err) { + return reply(boom.badRequest(err)) + } + + reply({ + Keys: list + }) +} + +exports.stat = (request, reply) => { + let stats + try { + stats = request.server.app.ipfs.bitswap.stat() + } catch (err) { + return reply(boom.badRequest(err)) + } + + reply({ + BlocksReceived: stats.blocksReceived, + Wantlist: stats.wantlist, + Peers: stats.peers, + DupBlksReceived: stats.dupBlksReceived, + DupDataReceived: stats.dupDataReceived + }) +} + +exports.unwant = { + // uses common parseKey method that returns a `key` + parseArgs: parseKey, + + handler: (request, reply) => { + reply(boom.badRequrest(new Error('Not implemented yet'))) + } +} diff --git a/src/http-api/resources/index.js b/src/http-api/resources/index.js index 036e09b212..920d576aa9 100644 --- a/src/http-api/resources/index.js +++ b/src/http-api/resources/index.js @@ -8,3 +8,4 @@ exports.object = require('./object') exports.config = require('./config') exports.block = require('./block') exports.swarm = require('./swarm') +exports.bitswap = require('./bitswap') diff --git a/src/http-api/resources/object.js b/src/http-api/resources/object.js index 2dc8891189..ae4728cc07 100644 --- a/src/http-api/resources/object.js +++ b/src/http-api/resources/object.js @@ -351,11 +351,21 @@ exports.patchAddLink = { return reply("Arguments 'root', 'name' & 'ref' are required").code(400).takeover() } + const error = (msg) => reply({ + Message: msg, + Code: 0 + }).code(500).takeover() + + if (!request.query.arg[0]) { + return error('cannot create link with no root') + } + if (!request.query.arg[1]) { - return reply({ - Message: 'cannot create link with no name!', - Code: 0 - }).code(500).takeover() + return error('cannot create link with no name!') + } + + if (!request.query.arg[2]) { + return error('cannot create link with no ref') } try { @@ -366,10 +376,7 @@ exports.patchAddLink = { }) } catch (err) { log.error(err) - return reply({ - Message: 'invalid ipfs ref path', - Code: 0 - }).code(500).takeover() + return error('invalid ipfs ref path') } }, diff --git a/src/http-api/routes/bitswap.js b/src/http-api/routes/bitswap.js new file mode 100644 index 0000000000..23c75b9a86 --- /dev/null +++ b/src/http-api/routes/bitswap.js @@ -0,0 +1,34 @@ +'use strict' + +const resources = require('./../resources') + +module.exports = (server) => { + const api = server.select('API') + + api.route({ + method: '*', + path: '/api/v0/bitswap/wantlist', + config: { + handler: resources.bitswap.wantlist + } + }) + + api.route({ + method: '*', + path: '/api/v0/bitswap/stat', + config: { + handler: resources.bitswap.stat + } + }) + + api.route({ + method: '*', + path: '/api/v0/bitswap/unwant', + config: { + pre: [ + { method: resources.bitswap.unwant.parseArgs, assign: 'args' } + ], + handler: resources.bitswap.unwant.handler + } + }) +} diff --git a/src/http-api/routes/index.js b/src/http-api/routes/index.js index de8e27bf85..6b21f38389 100644 --- a/src/http-api/routes/index.js +++ b/src/http-api/routes/index.js @@ -9,4 +9,5 @@ module.exports = (server) => { // require('./repo')(server) require('./config')(server) require('./swarm')(server) + require('./bitswap')(server) } diff --git a/test/cli-tests/test-bitswap.js b/test/cli-tests/test-bitswap.js new file mode 100644 index 0000000000..baec2e6356 --- /dev/null +++ b/test/cli-tests/test-bitswap.js @@ -0,0 +1,82 @@ +/* eslint-env mocha */ +'use strict' + +const expect = require('chai').expect +const nexpect = require('nexpect') +const Block = require('ipfs-block') +const _ = require('lodash') +const bs58 = require('bs58') + +const HttpAPI = require('../../src/http-api') +const createTempNode = require('../utils/temp-node') +const repoPath = require('./index').repoPath + +describe('bitswap', function () { + this.timeout(20000) + const env = _.clone(process.env) + env.IPFS_PATH = repoPath + + let ipfs + + before((done) => { + createTempNode(4, (err, _ipfs) => { + expect(err).to.not.exist + ipfs = _ipfs + ipfs.goOnline(done) + }) + }) + + describe('api running', () => { + const block = new Block('hello') + const key = bs58.encode(block.key) + + let httpAPI + + before((done) => { + httpAPI = new HttpAPI(repoPath) + httpAPI.start(done) + }) + + after((done) => { + httpAPI.stop(done) + }) + + it('wantlist', (done) => { + const api = httpAPI.server.select('API') + + api.inject({ + method: 'GET', + url: `/api/v0/block/get?arg=${key}` + }, (res) => {}) + + nexpect.spawn('node', [process.cwd() + '/src/cli/bin.js', 'bitswap', 'wantlist'], {env}) + .run((err, stdout, exitcode) => { + expect(err).to.not.exist + // expect(exitcode).to.equal(0) + expect(stdout).to.be.eql([ + key + ]) + done() + }) + }) + + it('stat', (done) => { + nexpect.spawn('node', [process.cwd() + '/src/cli/bin.js', 'bitswap', 'stat'], {env}) + .run((err, stdout, exitcode) => { + expect(err).to.not.exist + expect(exitcode).to.equal(0) + expect(stdout).to.be.eql([ + 'bitswap status', + ' blocks received: 0', + ' dup blocks received: 0', + ' dup data received: 0B', + ' wantlist [1 keys]', + ` ${key}`, + ' partners [0]', + ' ' + ]) + done() + }) + }) + }) +}) diff --git a/test/cli-tests/test-commands.js b/test/cli-tests/test-commands.js index efb656d58a..d1a2c31ca3 100644 --- a/test/cli-tests/test-commands.js +++ b/test/cli-tests/test-commands.js @@ -10,7 +10,7 @@ describe('commands', () => { .run((err, stdout, exitcode) => { expect(err).to.not.exist expect(exitcode).to.equal(0) - expect(stdout.length).to.equal(47) + expect(stdout.length).to.equal(50) done() }) }) diff --git a/test/cli-tests/test-config.js b/test/cli-tests/test-config.js index 263bf29be8..bad738937b 100644 --- a/test/cli-tests/test-config.js +++ b/test/cli-tests/test-config.js @@ -127,7 +127,9 @@ describe('config', () => { }) after((done) => { + console.log('stopping') httpAPI.stop((err) => { + console.log('stopped') expect(err).to.not.exist done() }) diff --git a/test/cli-tests/test-id.js b/test/cli-tests/test-id.js index 2511dae654..6e092e8bff 100644 --- a/test/cli-tests/test-id.js +++ b/test/cli-tests/test-id.js @@ -15,20 +15,18 @@ describe('id', () => { it('get the id', (done) => { nexpect.spawn('node', [process.cwd() + '/src/cli/bin.js', 'id'], {env}) .run((err, stdout, exitcode) => { - var expected = [ "{ ID: 'QmQ2zigjQikYnyYUSXZydNXrDRhBut2mubwJBaLXobMt3A',", + expect( + stdout + ).to.be.eql([ + "{ ID: 'QmQ2zigjQikYnyYUSXZydNXrDRhBut2mubwJBaLXobMt3A',", " PublicKey: 'CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2SKo/HMFZeBml1AF3XijzrxrfQXdJzjePBZAbdxqKR1Mc6juRHXij6HXYPjlAk01BhF1S3Ll4Lwi0cAHhggf457sMg55UWyeGKeUv0ucgvCpBwlR5cQ020i0MgzjPWOLWq1rtvSbNcAi2ZEVn6+Q2EcHo3wUvWRtLeKz+DZSZfw2PEDC+DGPJPl7f8g7zl56YymmmzH9liZLNrzg/qidokUv5u1pdGrcpLuPNeTODk0cqKB+OUbuKj9GShYECCEjaybJDl9276oalL9ghBtSeEv20kugatTvYy590wFlJkkvyl+nPxIH0EEYMKK9XRWlu9XYnoSfboiwcv8M3SlsjAgMBAAE=',", - " Addresses: [ '/ip4/0.0.0.0/tcp/0'],", + ' Addresses: ', + " [ '/ip4/127.0.0.1/tcp/9990/websockets',", + " '/ip4/127.0.0.1/tcp/9999' ],", " AgentVersion: 'js-ipfs',", - " ProtocolVersion: '9000' }" ] + " ProtocolVersion: '9000' }" + ]) - expect(stdout[0]).to.equal(expected[0]) - expect(stdout[1]).to.equal(expected[1]) - // expect(stdout[2]).to.equal(expected[2]) - expect(stdout[3]).to.equal(expected[3]) - expect(stdout[4]).to.equal(expected[4]) - expect(stdout[5]).to.equal(expected[5]) - expect(stdout[6]).to.equal(expected[6]) - expect(stdout[7]).to.equal(expected[7]) expect(err).to.not.exist expect(exitcode).to.equal(0) done() @@ -57,21 +55,18 @@ describe('id', () => { it('get the id', (done) => { nexpect.spawn('node', [process.cwd() + '/src/cli/bin.js', 'id'], {env}) .run((err, stdout, exitcode) => { - var expected = [ + expect( + stdout + ).to.be.eql([ "{ ID: 'QmQ2zigjQikYnyYUSXZydNXrDRhBut2mubwJBaLXobMt3A',", " PublicKey: 'CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2SKo/HMFZeBml1AF3XijzrxrfQXdJzjePBZAbdxqKR1Mc6juRHXij6HXYPjlAk01BhF1S3Ll4Lwi0cAHhggf457sMg55UWyeGKeUv0ucgvCpBwlR5cQ020i0MgzjPWOLWq1rtvSbNcAi2ZEVn6+Q2EcHo3wUvWRtLeKz+DZSZfw2PEDC+DGPJPl7f8g7zl56YymmmzH9liZLNrzg/qidokUv5u1pdGrcpLuPNeTODk0cqKB+OUbuKj9GShYECCEjaybJDl9276oalL9ghBtSeEv20kugatTvYy590wFlJkkvyl+nPxIH0EEYMKK9XRWlu9XYnoSfboiwcv8M3SlsjAgMBAAE=',", - " Addresses: [ '/ip4/0.0.0.0/tcp/0' ],", + ' Addresses: ', + " [ '/ip4/127.0.0.1/tcp/9990/websockets',", + " '/ip4/127.0.0.1/tcp/9999' ],", " AgentVersion: 'js-ipfs',", - " ProtocolVersion: '9000' }" ] + " ProtocolVersion: '9000' }" + ]) - expect(stdout[0]).to.equal(expected[0]) - expect(stdout[1]).to.equal(expected[1]) - // expect(stdout[2]).to.equal(expected[2]) - expect(stdout[3]).to.equal(expected[3]) - expect(stdout[4]).to.equal(expected[4]) - expect(stdout[5]).to.equal(expected[5]) - expect(stdout[6]).to.equal(expected[6]) - expect(stdout[7]).to.equal(expected[7]) expect(err).to.not.exist expect(exitcode).to.equal(0) done() diff --git a/test/cli-tests/test-init.js b/test/cli-tests/test-init.js index a2a810ac03..4eeb9e2e3a 100644 --- a/test/cli-tests/test-init.js +++ b/test/cli-tests/test-init.js @@ -9,7 +9,7 @@ const _ = require('lodash') const clean = require('../utils/clean') describe('init', function () { - this.timeout(10000) + this.timeout(60 * 1000) const env = _.clone(process.env) const repoExistsSync = (p) => ( fs.existsSync(path.join(env.IPFS_PATH, p)) diff --git a/test/cli-tests/test-swarm.js b/test/cli-tests/test-swarm.js index 8276589642..629cc381af 100644 --- a/test/cli-tests/test-swarm.js +++ b/test/cli-tests/test-swarm.js @@ -17,18 +17,17 @@ describe('swarm', function () { var ipfsAddr before((done) => { - createTempNode(8, (err, _ipfs) => { + createTempNode(1, (err, _ipfs) => { expect(err).to.not.exist ipfs = _ipfs - ipfs.libp2p.start(done) - }) - }) - - before((done) => { - ipfs.id((err, res) => { - expect(err).to.not.exist - ipfsAddr = `${res.Addresses[0]}/ipfs/${res.ID}` - done() + ipfs.goOnline((err) => { + expect(err).to.not.exist + ipfs.id((err, res) => { + expect(err).to.not.exist + ipfsAddr = `${res.Addresses[0]}/ipfs/${res.ID}` + done() + }) + }) }) }) diff --git a/test/core-tests/browser.js b/test/core-tests/browser.js index cd9b91b9e9..52a62e1368 100644 --- a/test/core-tests/browser.js +++ b/test/core-tests/browser.js @@ -1,7 +1,7 @@ /* eslint-env mocha */ 'use strict' -const async = require('async') +const series = require('run-series') const store = require('idb-plus-blob-store') const _ = require('lodash') @@ -29,7 +29,7 @@ describe('IPFS Repo Tests on the Browser', function () { const mainBlob = store('ipfs') const blocksBlob = store('ipfs/blocks') - async.eachSeries(repoData, (file, cb) => { + series(repoData.map((file) => (cb) => { if (_.startsWith(file.key, 'datastore/')) { return cb() } @@ -41,7 +41,7 @@ describe('IPFS Repo Tests on the Browser', function () { blob.createWriteStream({ key: key }).end(file.value, cb) - }, done) + }), done) }) it('--', () => { diff --git a/test/core-tests/test-bitswap.js b/test/core-tests/test-bitswap.js new file mode 100644 index 0000000000..f0536c5645 --- /dev/null +++ b/test/core-tests/test-bitswap.js @@ -0,0 +1,239 @@ +/* eslint-env mocha */ +'use strict' + +const expect = require('chai').expect +const _ = require('lodash') +const series = require('run-series') +const waterfall = require('run-waterfall') +const parallel = require('run-parallel') +const Block = require('ipfs-block') +const bs58 = require('bs58') +const bl = require('bl') +const API = require('ipfs-api') +const multiaddr = require('multiaddr') + +const IPFS = require('../../src/core') + +function makeBlock () { + return new Block(`IPFS is awesome ${Math.random()}`) +} + +describe('bitswap', () => { + let ipfs + + beforeEach((done) => { + ipfs = new IPFS(require('./repo-path')) + ipfs.load(done) + }) + + describe('connections', () => { + function connectNodesSingle (node1, node2, done) { + node1.id((err, res) => { + expect(err).to.not.exist + const addr = res.Addresses + .map((addr) => multiaddr(addr)) + .filter((addr) => { + return _.includes(addr.protoNames(), 'websockets') + })[0] + + let target = addr.encapsulate(multiaddr(`/ipfs/${res.ID}`)).toString() + + target = target.replace('0.0.0.0', '127.0.0.1') + const swarm = node2.libp2p ? node2.libp2p.swarm : node2.swarm + swarm.connect(target, done) + }) + } + + function connectNodes (node1, node2, done) { + series([ + (cb) => connectNodesSingle(node1, node2, cb), + (cb) => setTimeout(() => { + // need timeout so we wait for identify to happen + // in the browsers + connectNodesSingle(node2, node1, cb) + }, 100) + ], done) + } + + function addNode (num, done) { + const apiUrl = `/ip4/127.0.0.1/tcp/1100${num}` + const node = new API(apiUrl) + + connectNodes(node, ipfs, (err) => { + done(err, node) + }) + } + + describe('fetches a remote block', () => { + beforeEach((done) => { + ipfs.goOnline(done) + }) + + afterEach((done) => { + setTimeout(() => ipfs.goOffline(done), 500) + }) + + it('2 peers', (done) => { + const block = makeBlock() + let node + series([ + // 0. Start node + (cb) => addNode(9, (err, _ipfs) => { + node = _ipfs + cb(err) + }), + (cb) => node.block.put(block.data, cb), + (cb) => { + ipfs.block.get(block.key, (err, b) => { + expect(err).to.not.exist + expect(b.data.toString()).to.be.eql(block.data.toString()) + cb() + }) + } + ], done) + }) + + it('3 peers', function (done) { + this.timeout(60 * 1000) + + const blocks = _.range(6).map((i) => makeBlock()) + const keys = blocks.map((b) => b.key) + const nodes = [] + series([ + (cb) => addNode(8, (err, _ipfs) => { + nodes.push(_ipfs) + cb(err) + }), + (cb) => addNode(7, (err, _ipfs) => { + nodes.push(_ipfs) + cb(err) + }), + (cb) => connectNodes(nodes[0], nodes[1], cb), + (cb) => nodes[0].block.put(blocks[0].data, cb), + (cb) => nodes[0].block.put(blocks[1].data, cb), + (cb) => nodes[1].block.put(blocks[2].data, cb), + (cb) => nodes[1].block.put(blocks[3].data, cb), + (cb) => ipfs.block.put(blocks[4], cb), + (cb) => ipfs.block.put(blocks[5], cb), + // 3. Fetch blocks on all nodes + (cb) => parallel(_.range(6).map((i) => (cbI) => { + const toMh = (k) => bs58.encode(k).toString() + const check = (n, k, callback) => { + n.block.get(k, (err, b) => { + expect(err).to.not.exist + expect( + (b.data || b).toString() + ).to.be.eql( + blocks[i].data.toString() + ) + callback() + }) + } + + series([ + (cbJ) => check(nodes[0], toMh(keys[i]), cbJ), + (cbJ) => check(nodes[1], toMh(keys[i]), cbJ), + (cbJ) => check(ipfs, keys[i], cbJ) + ], cbI) + }), cb) + ], done) + }) + }) + + // wont work without http-api for add + describe.skip('fetches a remote file', () => { + beforeEach((done) => { + ipfs.goOnline(done) + }) + + it('2 peers', (done) => { + const file = new Buffer('I love IPFS <3') + + let node + waterfall([ + // 0. Start node + (cb) => addNode(9, (err, _ipfs) => { + node = _ipfs + cb(err) + }), + // 1. Add file to tmp instance + (cb) => node.add([{path: 'awesome.txt', content: file}], cb), + // 2. Request file from local instance + (val, cb) => { + const hash = bs58.encode(val[0].multihash).toString() + + ipfs.files.cat(hash, (err, res) => { + expect(err).to.not.exist + res.on('file', (data) => { + data.stream.pipe(bl((err, bldata) => { + expect(err).to.not.exist + expect(bldata.toString()).to.equal('I love IPFS <3') + cb() + })) + }) + }) + }, + (cb) => setTimeout(() => node.goOffline(cb), 1000) + ], done) + }) + }) + }) + + describe('commands', () => { + describe('wantlist', (done) => { + it('throws if offline', () => { + expect( + () => ipfs.bitswap.wantlist() + ).to.throw(/online/) + }) + + it('returns an array of wanted blocks', (done) => { + ipfs.goOnline((err) => { + expect(err).to.not.exist + + expect( + ipfs.bitswap.wantlist() + ).to.be.eql( + [] + ) + + ipfs.goOffline(done) + }) + }) + + describe('stat', () => { + it('throws if offline', () => { + expect( + () => ipfs.bitswap.stat() + ).to.throw(/online/) + }) + + it('returns the stats', (done) => { + ipfs.goOnline((err) => { + expect(err).to.not.exist + + let stats = ipfs.bitswap.stat() + + expect(stats).to.have.keys([ + 'blocksReceived', + 'wantlist', + 'peers', + 'dupDataReceived', + 'dupBlksReceived' + ]) + + ipfs.goOffline(done) + }) + }) + }) + + describe('unwant', () => { + it('throws if offline', () => { + expect( + () => ipfs.bitswap.unwant('my key') + ).to.throw(/online/) + }) + }) + }) + }) +}) diff --git a/test/core-tests/test-config.js b/test/core-tests/test-config.js index c870c4969f..22157c726b 100644 --- a/test/core-tests/test-config.js +++ b/test/core-tests/test-config.js @@ -16,7 +16,7 @@ describe('config', () => { GCPeriod: '', Params: null, NoSync: false }, - Addresses: { Swarm: [ '/ip4/0.0.0.0/tcp/0' ], + Addresses: { Swarm: [ '/ip4/127.0.0.1/tcp/9999', '/ip4/127.0.0.1/tcp/9990/websockets' ], API: '/ip4/127.0.0.1/tcp/6001', Gateway: '/ip4/127.0.0.1/tcp/0' }, Mounts: { IPFS: '/ipfs', IPNS: '/ipns', FuseAllowOther: false }, diff --git a/test/core-tests/test-id.js b/test/core-tests/test-id.js index fc6e4f397b..3ab5837268 100644 --- a/test/core-tests/test-id.js +++ b/test/core-tests/test-id.js @@ -16,9 +16,13 @@ describe('id', () => { it('get id', (done) => { ipfs.id((err, id) => { expect(err).to.not.exist - expect(id).to.deep.equal({ ID: 'QmQ2zigjQikYnyYUSXZydNXrDRhBut2mubwJBaLXobMt3A', + expect(id).to.deep.equal({ + ID: 'QmQ2zigjQikYnyYUSXZydNXrDRhBut2mubwJBaLXobMt3A', PublicKey: 'CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2SKo/HMFZeBml1AF3XijzrxrfQXdJzjePBZAbdxqKR1Mc6juRHXij6HXYPjlAk01BhF1S3Ll4Lwi0cAHhggf457sMg55UWyeGKeUv0ucgvCpBwlR5cQ020i0MgzjPWOLWq1rtvSbNcAi2ZEVn6+Q2EcHo3wUvWRtLeKz+DZSZfw2PEDC+DGPJPl7f8g7zl56YymmmzH9liZLNrzg/qidokUv5u1pdGrcpLuPNeTODk0cqKB+OUbuKj9GShYECCEjaybJDl9276oalL9ghBtSeEv20kugatTvYy590wFlJkkvyl+nPxIH0EEYMKK9XRWlu9XYnoSfboiwcv8M3SlsjAgMBAAE=', - Addresses: [ '/ip4/0.0.0.0/tcp/0' ], + Addresses: [ + '/ip4/127.0.0.1/tcp/9990/websockets', + '/ip4/127.0.0.1/tcp/9999' + ], AgentVersion: 'js-ipfs', ProtocolVersion: '9000' }) diff --git a/test/core-tests/test-swarm-node.js b/test/core-tests/test-swarm-node.js index 424e9ad2e0..56ee09c800 100644 --- a/test/core-tests/test-swarm-node.js +++ b/test/core-tests/test-swarm-node.js @@ -13,11 +13,11 @@ describe('swarm', function () { var ipfsAAddr before((done) => { - createTempNode(3, (err, ipfs) => { + createTempNode(2, (err, ipfs) => { expect(err).to.not.exist ipfsA = ipfs - createTempNode(4, (err, ipfs) => { + createTempNode(3, (err, ipfs) => { expect(err).to.not.exist ipfsB = ipfs done() @@ -34,9 +34,9 @@ describe('swarm', function () { }) it('start', (done) => { - ipfsA.libp2p.start((err) => { + ipfsA.goOnline((err) => { expect(err).to.not.exist - ipfsB.libp2p.start((err) => { + ipfsB.goOnline((err) => { expect(err).to.not.exist done() }) @@ -61,7 +61,7 @@ describe('swarm', function () { it('localAddrs', (done) => { ipfsB.libp2p.swarm.localAddrs((err, res) => { expect(err).to.not.exist - expect(res.length).to.equal(1) + expect(res.length).to.equal(2) done() }) }) @@ -69,9 +69,9 @@ describe('swarm', function () { it.skip('disconnect', (done) => {}) it.skip('stop', (done) => { - ipfsA.libp2p.stop((err) => { + ipfsA.goOffline((err) => { expect(err).to.not.exist - done() + ipfsB.goOffline(done) }) }) }) diff --git a/test/go-ipfs-repo/config b/test/go-ipfs-repo/config index 3abd82e380..69bec61203 100644 --- a/test/go-ipfs-repo/config +++ b/test/go-ipfs-repo/config @@ -1 +1 @@ -{"Identity":{"PeerID":"QmQ2zigjQikYnyYUSXZydNXrDRhBut2mubwJBaLXobMt3A","PrivKey":"CAASpgkwggSiAgEAAoIBAQC2SKo/HMFZeBml1AF3XijzrxrfQXdJzjePBZAbdxqKR1Mc6juRHXij6HXYPjlAk01BhF1S3Ll4Lwi0cAHhggf457sMg55UWyeGKeUv0ucgvCpBwlR5cQ020i0MgzjPWOLWq1rtvSbNcAi2ZEVn6+Q2EcHo3wUvWRtLeKz+DZSZfw2PEDC+DGPJPl7f8g7zl56YymmmzH9liZLNrzg/qidokUv5u1pdGrcpLuPNeTODk0cqKB+OUbuKj9GShYECCEjaybJDl9276oalL9ghBtSeEv20kugatTvYy590wFlJkkvyl+nPxIH0EEYMKK9XRWlu9XYnoSfboiwcv8M3SlsjAgMBAAECggEAZtju/bcKvKFPz0mkHiaJcpycy9STKphorpCT83srBVQi59CdFU6Mj+aL/xt0kCPMVigJw8P3/YCEJ9J+rS8BsoWE+xWUEsJvtXoT7vzPHaAtM3ci1HZd302Mz1+GgS8Epdx+7F5p80XAFLDUnELzOzKftvWGZmWfSeDnslwVONkL/1VAzwKy7Ce6hk4SxRE7l2NE2OklSHOzCGU1f78ZzVYKSnS5Ag9YrGjOAmTOXDbKNKN/qIorAQ1bovzGoCwx3iGIatQKFOxyVCyO1PsJYT7JO+kZbhBWRRE+L7l+ppPER9bdLFxs1t5CrKc078h+wuUr05S1P1JjXk68pk3+kQKBgQDeK8AR11373Mzib6uzpjGzgNRMzdYNuExWjxyxAzz53NAR7zrPHvXvfIqjDScLJ4NcRO2TddhXAfZoOPVH5k4PJHKLBPKuXZpWlookCAyENY7+Pd55S8r+a+MusrMagYNljb5WbVTgN8cgdpim9lbbIFlpN6SZaVjLQL3J8TWH6wKBgQDSChzItkqWX11CNstJ9zJyUE20I7LrpyBJNgG1gtvz3ZMUQCn3PxxHtQzN9n1P0mSSYs+jBKPuoSyYLt1wwe10/lpgL4rkKWU3/m1Myt0tveJ9WcqHh6tzcAbb/fXpUFT/o4SWDimWkPkuCb+8j//2yiXk0a/T2f36zKMuZvujqQKBgC6B7BAQDG2H2B/ijofp12ejJU36nL98gAZyqOfpLJ+FeMz4TlBDQ+phIMhnHXA5UkdDapQ+zA3SrFk+6yGk9Vw4Hf46B+82SvOrSbmnMa+PYqKYIvUzR4gg34rL/7AhwnbEyD5hXq4dHwMNsIDq+l2elPjwm/U9V0gdAl2+r50HAoGALtsKqMvhv8HucAMBPrLikhXP/8um8mMKFMrzfqZ+otxfHzlhI0L08Bo3jQrb0Z7ByNY6M8epOmbCKADsbWcVre/AAY0ZkuSZK/CaOXNX/AhMKmKJh8qAOPRY02LIJRBCpfS4czEdnfUhYV/TYiFNnKRj57PPYZdTzUsxa/yVTmECgYBr7slQEjb5Onn5mZnGDh+72BxLNdgwBkhO0OCdpdISqk0F0Pxby22DFOKXZEpiyI9XYP1C8wPiJsShGm2yEwBPWXnrrZNWczaVuCbXHrZkWQogBDG3HGXNdU4MAWCyiYlyinIBpPpoAJZSzpGLmWbMWh28+RJS6AQX6KHrK1o2uw=="},"Datastore":{"Type":"","Path":"","StorageMax":"","StorageGCWatermark":0,"GCPeriod":"","Params":null,"NoSync":false},"Addresses":{"Swarm":["/ip4/0.0.0.0/tcp/0"],"API":"/ip4/127.0.0.1/tcp/6001","Gateway":"/ip4/127.0.0.1/tcp/0"},"Mounts":{"IPFS":"/ipfs","IPNS":"/ipns","FuseAllowOther":false},"Version":{"Current":"0.4.0-dev","Check":"error","CheckDate":"0001-01-01T00:00:00Z","CheckPeriod":"172800000000000","AutoUpdate":"minor"},"Discovery":{"MDNS":{"Enabled":true,"Interval":10}},"Ipns":{"RepublishPeriod":"","RecordLifetime":"","ResolveCacheSize":128},"Bootstrap":["/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ","/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z","/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM","/ip4/162.243.248.213/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm","/ip4/128.199.219.111/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu","/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64","/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd","/ip4/178.62.61.185/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3","/ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx"],"Tour":{"Last":""},"Gateway":{"HTTPHeaders":null,"RootRedirect":"","Writable":false},"SupernodeRouting":{"Servers":["/ip4/104.236.176.52/tcp/4002/ipfs/QmXdb7tWTxdFEQEFgWBqkuYSrZd3mXrC7HxkD4krGNYx2U","/ip4/104.236.179.241/tcp/4002/ipfs/QmVRqViDByUxjUMoPnjurjKvZhaEMFDtK35FJXHAM4Lkj6","/ip4/104.236.151.122/tcp/4002/ipfs/QmSZwGx8Tn8tmcM4PtDJaMeUQNRhNFdBLVGPzRiNaRJtFH","/ip4/162.243.248.213/tcp/4002/ipfs/QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP","/ip4/128.199.219.111/tcp/4002/ipfs/Qmb3brdCYmKG1ycwqCbo6LUwWxTuo3FisnJV2yir7oN92R","/ip4/104.236.76.40/tcp/4002/ipfs/QmdRBCV8Cz2dGhoKLkD3YjPwVFECmqADQkx5ZteF2c6Fy4","/ip4/178.62.158.247/tcp/4002/ipfs/QmUdiMPci7YoEUBkyFZAh2pAbjqcPr7LezyiPD2artLw3v","/ip4/178.62.61.185/tcp/4002/ipfs/QmVw6fGNqBixZE4bewRLT2VXX7fAHUHs8JyidDiJ1P7RUN"]},"API":{"HTTPHeaders":null},"Swarm":{"AddrFilters":null},"Log":{"MaxSizeMB":250,"MaxBackups":1,"MaxAgeDays":0}} +{"Identity":{"PeerID":"QmQ2zigjQikYnyYUSXZydNXrDRhBut2mubwJBaLXobMt3A","PrivKey":"CAASpgkwggSiAgEAAoIBAQC2SKo/HMFZeBml1AF3XijzrxrfQXdJzjePBZAbdxqKR1Mc6juRHXij6HXYPjlAk01BhF1S3Ll4Lwi0cAHhggf457sMg55UWyeGKeUv0ucgvCpBwlR5cQ020i0MgzjPWOLWq1rtvSbNcAi2ZEVn6+Q2EcHo3wUvWRtLeKz+DZSZfw2PEDC+DGPJPl7f8g7zl56YymmmzH9liZLNrzg/qidokUv5u1pdGrcpLuPNeTODk0cqKB+OUbuKj9GShYECCEjaybJDl9276oalL9ghBtSeEv20kugatTvYy590wFlJkkvyl+nPxIH0EEYMKK9XRWlu9XYnoSfboiwcv8M3SlsjAgMBAAECggEAZtju/bcKvKFPz0mkHiaJcpycy9STKphorpCT83srBVQi59CdFU6Mj+aL/xt0kCPMVigJw8P3/YCEJ9J+rS8BsoWE+xWUEsJvtXoT7vzPHaAtM3ci1HZd302Mz1+GgS8Epdx+7F5p80XAFLDUnELzOzKftvWGZmWfSeDnslwVONkL/1VAzwKy7Ce6hk4SxRE7l2NE2OklSHOzCGU1f78ZzVYKSnS5Ag9YrGjOAmTOXDbKNKN/qIorAQ1bovzGoCwx3iGIatQKFOxyVCyO1PsJYT7JO+kZbhBWRRE+L7l+ppPER9bdLFxs1t5CrKc078h+wuUr05S1P1JjXk68pk3+kQKBgQDeK8AR11373Mzib6uzpjGzgNRMzdYNuExWjxyxAzz53NAR7zrPHvXvfIqjDScLJ4NcRO2TddhXAfZoOPVH5k4PJHKLBPKuXZpWlookCAyENY7+Pd55S8r+a+MusrMagYNljb5WbVTgN8cgdpim9lbbIFlpN6SZaVjLQL3J8TWH6wKBgQDSChzItkqWX11CNstJ9zJyUE20I7LrpyBJNgG1gtvz3ZMUQCn3PxxHtQzN9n1P0mSSYs+jBKPuoSyYLt1wwe10/lpgL4rkKWU3/m1Myt0tveJ9WcqHh6tzcAbb/fXpUFT/o4SWDimWkPkuCb+8j//2yiXk0a/T2f36zKMuZvujqQKBgC6B7BAQDG2H2B/ijofp12ejJU36nL98gAZyqOfpLJ+FeMz4TlBDQ+phIMhnHXA5UkdDapQ+zA3SrFk+6yGk9Vw4Hf46B+82SvOrSbmnMa+PYqKYIvUzR4gg34rL/7AhwnbEyD5hXq4dHwMNsIDq+l2elPjwm/U9V0gdAl2+r50HAoGALtsKqMvhv8HucAMBPrLikhXP/8um8mMKFMrzfqZ+otxfHzlhI0L08Bo3jQrb0Z7ByNY6M8epOmbCKADsbWcVre/AAY0ZkuSZK/CaOXNX/AhMKmKJh8qAOPRY02LIJRBCpfS4czEdnfUhYV/TYiFNnKRj57PPYZdTzUsxa/yVTmECgYBr7slQEjb5Onn5mZnGDh+72BxLNdgwBkhO0OCdpdISqk0F0Pxby22DFOKXZEpiyI9XYP1C8wPiJsShGm2yEwBPWXnrrZNWczaVuCbXHrZkWQogBDG3HGXNdU4MAWCyiYlyinIBpPpoAJZSzpGLmWbMWh28+RJS6AQX6KHrK1o2uw=="},"Datastore":{"Type":"","Path":"","StorageMax":"","StorageGCWatermark":0,"GCPeriod":"","Params":null,"NoSync":false},"Addresses":{"Swarm":["/ip4/127.0.0.1/tcp/9999", "/ip4/127.0.0.1/tcp/9990/websockets"],"API":"/ip4/127.0.0.1/tcp/6001","Gateway":"/ip4/127.0.0.1/tcp/0"},"Mounts":{"IPFS":"/ipfs","IPNS":"/ipns","FuseAllowOther":false},"Version":{"Current":"0.4.0-dev","Check":"error","CheckDate":"0001-01-01T00:00:00Z","CheckPeriod":"172800000000000","AutoUpdate":"minor"},"Discovery":{"MDNS":{"Enabled":true,"Interval":10}},"Ipns":{"RepublishPeriod":"","RecordLifetime":"","ResolveCacheSize":128},"Bootstrap":["/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ","/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z","/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM","/ip4/162.243.248.213/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm","/ip4/128.199.219.111/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu","/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64","/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd","/ip4/178.62.61.185/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3","/ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx"],"Tour":{"Last":""},"Gateway":{"HTTPHeaders":null,"RootRedirect":"","Writable":false},"SupernodeRouting":{"Servers":["/ip4/104.236.176.52/tcp/4002/ipfs/QmXdb7tWTxdFEQEFgWBqkuYSrZd3mXrC7HxkD4krGNYx2U","/ip4/104.236.179.241/tcp/4002/ipfs/QmVRqViDByUxjUMoPnjurjKvZhaEMFDtK35FJXHAM4Lkj6","/ip4/104.236.151.122/tcp/4002/ipfs/QmSZwGx8Tn8tmcM4PtDJaMeUQNRhNFdBLVGPzRiNaRJtFH","/ip4/162.243.248.213/tcp/4002/ipfs/QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP","/ip4/128.199.219.111/tcp/4002/ipfs/Qmb3brdCYmKG1ycwqCbo6LUwWxTuo3FisnJV2yir7oN92R","/ip4/104.236.76.40/tcp/4002/ipfs/QmdRBCV8Cz2dGhoKLkD3YjPwVFECmqADQkx5ZteF2c6Fy4","/ip4/178.62.158.247/tcp/4002/ipfs/QmUdiMPci7YoEUBkyFZAh2pAbjqcPr7LezyiPD2artLw3v","/ip4/178.62.61.185/tcp/4002/ipfs/QmVw6fGNqBixZE4bewRLT2VXX7fAHUHs8JyidDiJ1P7RUN"]},"API":{"HTTPHeaders":null},"Swarm":{"AddrFilters":null},"Log":{"MaxSizeMB":250,"MaxBackups":1,"MaxAgeDays":0}} diff --git a/test/http-api-tests/test-bitswap.js b/test/http-api-tests/test-bitswap.js new file mode 100644 index 0000000000..60785afbb8 --- /dev/null +++ b/test/http-api-tests/test-bitswap.js @@ -0,0 +1,51 @@ +/* eslint-env mocha */ +'use strict' + +const expect = require('chai').expect + +module.exports = (httpAPI) => { + describe('bitswap', function () { + this.timeout(20000) + describe('commands', () => { + let api + before(() => { + api = httpAPI.server.select('API') + }) + + it('wantlist', (done) => { + api.inject({ + method: 'GET', + url: '/api/v0/bitswap/wantlist' + }, (res) => { + expect(res.statusCode).to.equal(200) + expect(res.result).to.have.property('Keys') + + // TODO test that there actual values in there + done() + }) + }) + + it('stat', (done) => { + api.inject({ + method: 'GET', + url: '/api/v0/bitswap/stat' + }, (res) => { + expect(res.statusCode).to.equal(200) + + expect(res.result).to.have.keys([ + 'BlocksReceived', + 'Wantlist', + 'Peers', + 'DupBlksReceived', + 'DupDataReceived' + ]) + // TODO test that there actual values in there + done() + }) + }) + + it.skip('unwant', () => { + }) + }) + }) +} diff --git a/test/http-api-tests/test-swarm.js b/test/http-api-tests/test-swarm.js index 73610825a9..d3d3cd281f 100644 --- a/test/http-api-tests/test-swarm.js +++ b/test/http-api-tests/test-swarm.js @@ -18,21 +18,20 @@ module.exports = (httpAPI) => { createTempNode(6, (err, _ipfs) => { expect(err).to.not.exist ipfs = _ipfs - ipfs.libp2p.start(done) - }) - }) - - before((done) => { - ipfs.id((err, res) => { - expect(err).to.not.exist - ipfsAddr = `${res.Addresses[0]}/ipfs/${res.ID}` - done() + ipfs.goOnline((err) => { + expect(err).to.not.exist + ipfs.id((err, res) => { + expect(err).to.not.exist + ipfsAddr = `${res.Addresses[0]}/ipfs/${res.ID}` + done() + }) + }) }) }) after((done) => { setTimeout(() => { - ipfs.libp2p.stop(done) + ipfs.goOffline(done) }, 1000) }) @@ -102,24 +101,22 @@ module.exports = (httpAPI) => { var ipfsAddr before((done) => { - createTempNode(7, (err, _ipfs) => { + createTempNode(5, (err, _ipfs) => { expect(err).to.not.exist ipfs = _ipfs - ipfs.libp2p.start(done) - }) - }) - - before((done) => { - ipfs.id((err, res) => { - expect(err).to.not.exist - ipfsAddr = `${res.Addresses[0]}/ipfs/${res.ID}` - done() + ipfs.goOnline(() => { + ipfs.id((err, res) => { + expect(err).to.not.exist + ipfsAddr = `${res.Addresses[0]}/ipfs/${res.ID}` + done() + }) + }) }) }) after((done) => { setTimeout(() => { - ipfs.libp2p.stop(done) + ipfs.goOffline(done) }, 1000) }) diff --git a/test/utils/temp-node.js b/test/utils/temp-node.js index 3ba5692e6c..444b750ad5 100644 --- a/test/utils/temp-node.js +++ b/test/utils/temp-node.js @@ -11,7 +11,8 @@ function setAddresses (repo, num, callback) { expect(err).to.not.exist config.Addresses = { Swarm: [ - `/ip4/127.0.0.1/tcp/1000${num}` + `/ip4/127.0.0.1/tcp/1000${num}`, + `/ip4/127.0.0.1/tcp/1001${num}/websockets` ], API: `/ip4/127.0.0.1/tcp/1100${num}`, Gateway: `/ip4/127.0.0.1/tcp/1200${num}`