From ce4ce9ace2e4fc5e692d38574c9abea87926e0a2 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Tue, 13 Feb 2018 11:21:38 +1300 Subject: [PATCH 1/4] feat(bootstrap): add the spec --- SPEC/BOOTSTRAP.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 SPEC/BOOTSTRAP.md diff --git a/SPEC/BOOTSTRAP.md b/SPEC/BOOTSTRAP.md new file mode 100644 index 000000000..a009d18a2 --- /dev/null +++ b/SPEC/BOOTSTRAP.md @@ -0,0 +1,43 @@ +Bootstrap API +============= + +> Manipulates the `bootstrap list`, which contains + the addresses of the bootstrap nodes. These are the trusted peers from + which to learn about other peers in the network. + +> Only edit this list if you understand the risks of adding or removing nodes from this list. + +#### `add` + +> Add a peer address to the bootstrap list + +##### `Go` **WIP** + +##### `JavaScript` - ipfs.bootstrap.add(addr, [opts,] callback) + +- `addr` is a [multiaddr](https://github.com/multiformats/js-multiaddr) to a peer node +- `opts.default` if true, add the default peers to the list +- `callback` must follow `function (err, res) {}` signature, where `err` is an error if the operation was not successful. `res.Peers` is an array of added addresses. + +#### `list` + +> List all peer addresses in the bootstrap list + +##### `Go` **WIP** + +##### `JavaScript` - ipfs.bootstrap.list(callback) + +- `callback` must follow `function (err, res) {}` signature, where `err` is an error if the operation was not successful. `res.Peers` is an array of addresses. + + +#### `rm` + +> Remove a peer address from the bootstrap list + +##### `Go` **WIP** + +##### `JavaScript` - ipfs.bootstrap.rm(peer, [opt,] callback) + +- `addr` is a [multiaddr](https://github.com/multiformats/js-multiaddr) to a peer node +- `opts.all` if true, remove all peers from the list +- `callback` must follow `function (err, res) {}` signature, where `err` is an error if the operation was not successful. `res.Peers` is an array of removed addresses. From 1c13231494008e7e44cae4a1a7f3332b16d17ba7 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Thu, 15 Feb 2018 17:19:19 +1300 Subject: [PATCH 2/4] test: add the bootstrap tests --- js/src/bootstrap.js | 203 ++++++++++++++++++++++++++++++++++++++++++++ js/src/index.js | 1 + 2 files changed, 204 insertions(+) create mode 100644 js/src/bootstrap.js diff --git a/js/src/bootstrap.js b/js/src/bootstrap.js new file mode 100644 index 000000000..a330b6637 --- /dev/null +++ b/js/src/bootstrap.js @@ -0,0 +1,203 @@ +/* eslint-env mocha */ +/* eslint max-nested-callbacks: ["error", 8] */ +'use strict' + +const chai = require('chai') +const dirtyChai = require('dirty-chai') +const expect = chai.expect +chai.use(dirtyChai) + +const invalidArg = 'this/Is/So/Invalid/' +const validIp4 = '/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z' + +module.exports = (common) => { + describe('.bootstrap', function () { + + let ipfs + let peers + + before(function (done) { + // CI takes longer to instantiate the daemon, so we need to increase the + // timeout for the before step + this.timeout(60 * 1000) + + common.setup((err, factory) => { + expect(err).to.not.exist() + factory.spawnNode((err, node) => { + expect(err).to.not.exist() + ipfs = node + done() + }) + }) + }) + + after((done) => common.teardown(done)) + + describe('Callback API', function () { + this.timeout(100 * 1000) + + describe('.add', () => { + it('returns an error when called with an invalid arg', (done) => { + ipfs.bootstrap.add(invalidArg, (err) => { + expect(err).to.be.an.instanceof(Error) + done() + }) + }) + + it('returns a list of containing the bootstrap peer when called with a valid arg (ip4)', (done) => { + ipfs.bootstrap.add(validIp4, (err, res) => { + expect(err).to.not.exist() + expect(res).to.be.eql({ Peers: [validIp4] }) + peers = res.Peers + expect(peers).to.exist() + expect(peers.length).to.eql(1) + done() + }) + }) + + it('returns a list of bootstrap peers when called with the default option', (done) => { + ipfs.bootstrap.add({ default: true }, (err, res) => { + expect(err).to.not.exist() + peers = res.Peers + expect(peers).to.exist() + expect(peers.length).to.above(1) + done() + }) + }) + }) + + describe('.list', () => { + it('returns a list of peers', (done) => { + ipfs.bootstrap.list((err, res) => { + expect(err).to.not.exist() + peers = res.Peers + expect(peers).to.exist() + done() + }) + }) + }) + + describe('.rm', () => { + it('returns an error when called with an invalid arg', (done) => { + ipfs.bootstrap.rm(invalidArg, (err) => { + expect(err).to.be.an.instanceof(Error) + done() + }) + }) + + it('returns empty list because no peers removed when called without an arg or options', (done) => { + ipfs.bootstrap.rm(null, (err, res) => { + expect(err).to.not.exist() + peers = res.Peers + expect(peers).to.exist() + expect(peers.length).to.eql(0) + done() + }) + }) + + it('returns list containing the peer removed when called with a valid arg (ip4)', (done) => { + ipfs.bootstrap.rm(null, (err, res) => { + expect(err).to.not.exist() + peers = res.Peers + expect(peers).to.exist() + expect(peers.length).to.eql(0) + done() + }) + }) + + it('returns list of all peers removed when all option is passed', (done) => { + ipfs.bootstrap.rm(null, { all: true }, (err, res) => { + expect(err).to.not.exist() + peers = res.Peers + expect(peers).to.exist() + done() + }) + }) + }) + }) + + describe('Promise API', function () { + this.timeout(100 * 1000) + + describe('.add', () => { + it('returns an error when called without args or options', () => { + return ipfs.bootstrap.add(null) + .catch((err) => { + expect(err).to.be.an.instanceof(Error) + }) + }) + + it('returns an error when called with an invalid arg', () => { + return ipfs.bootstrap.add(invalidArg) + .catch((err) => { + expect(err).to.be.an.instanceof(Error) + }) + }) + + it('returns a list of peers when called with a valid arg (ip4)', () => { + return ipfs.bootstrap.add(validIp4) + .then((res) => { + expect(res).to.be.eql({ Peers: [validIp4] }) + peers = res.Peers + expect(peers).to.exist() + expect(peers.length).to.eql(1) + }) + }) + + it('returns a list of default peers when called with the default option', () => { + return ipfs.bootstrap.add(null, { default: true }) + .then((res) => { + peers = res.Peers + expect(peers).to.exist() + expect(peers.length).to.above(1) + }) + }) + }) + + describe('.list', () => { + it('returns a list of peers', () => { + return ipfs.bootstrap.list() + .then((res) => { + peers = res.Peers + expect(peers).to.exist() + }) + }) + }) + + describe('.rm', () => { + it('returns an error when called with an invalid arg', () => { + return ipfs.bootstrap.rm(invalidArg) + .catch((err) => { + expect(err).to.be.an.instanceof(Error) + }) + }) + + it('returns empty list when called without an arg or options', () => { + return ipfs.bootstrap.rm(null) + .then((res) => { + peers = res.Peers + expect(peers).to.exist() + expect(peers.length).to.eql(0) + }) + }) + + it('returns list containing the peer removed when called with a valid arg (ip4)', () => { + return ipfs.bootstrap.rm(null) + .then((res) => { + peers = res.Peers + expect(peers).to.exist() + expect(peers.length).to.eql(0) + }) + }) + + it('returns list of all peers removed when all option is passed', () => { + return ipfs.bootstrap.rm(null, { all: true }) + .then((res) => { + peers = res.Peers + expect(peers).to.exist() + }) + }) + }) + }) + }) +} diff --git a/js/src/index.js b/js/src/index.js index 53beb2acd..9f527e190 100644 --- a/js/src/index.js +++ b/js/src/index.js @@ -15,3 +15,4 @@ exports.pubsub = require('./pubsub') exports.key = require('./key') exports.stats = require('./stats') exports.repo = require('./repo') +exports.bootstrap = require('./bootstrap') From c7852b7baf2e4b1427ae001670ef5d7db1cc212e Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Thu, 15 Feb 2018 18:48:58 +1300 Subject: [PATCH 3/4] fix: bootstrap add test --- js/src/bootstrap.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/bootstrap.js b/js/src/bootstrap.js index a330b6637..9d52be939 100644 --- a/js/src/bootstrap.js +++ b/js/src/bootstrap.js @@ -56,7 +56,7 @@ module.exports = (common) => { }) it('returns a list of bootstrap peers when called with the default option', (done) => { - ipfs.bootstrap.add({ default: true }, (err, res) => { + ipfs.bootstrap.add(null, { default: true }, (err, res) => { expect(err).to.not.exist() peers = res.Peers expect(peers).to.exist() From c769f0d6e3465d43804b4e32ed3661e4acfa72bd Mon Sep 17 00:00:00 2001 From: David Dias Date: Thu, 15 Feb 2018 10:41:35 +0100 Subject: [PATCH 4/4] chore: dedup tests --- js/src/bootstrap.js | 199 +++++++++++++------------------------------- 1 file changed, 56 insertions(+), 143 deletions(-) diff --git a/js/src/bootstrap.js b/js/src/bootstrap.js index 9d52be939..cb81ddbf2 100644 --- a/js/src/bootstrap.js +++ b/js/src/bootstrap.js @@ -12,6 +12,7 @@ const validIp4 = '/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrS module.exports = (common) => { describe('.bootstrap', function () { + this.timeout(100 * 1000) let ipfs let peers @@ -33,169 +34,81 @@ module.exports = (common) => { after((done) => common.teardown(done)) - describe('Callback API', function () { - this.timeout(100 * 1000) - - describe('.add', () => { - it('returns an error when called with an invalid arg', (done) => { - ipfs.bootstrap.add(invalidArg, (err) => { - expect(err).to.be.an.instanceof(Error) - done() - }) - }) - - it('returns a list of containing the bootstrap peer when called with a valid arg (ip4)', (done) => { - ipfs.bootstrap.add(validIp4, (err, res) => { - expect(err).to.not.exist() - expect(res).to.be.eql({ Peers: [validIp4] }) - peers = res.Peers - expect(peers).to.exist() - expect(peers.length).to.eql(1) - done() - }) - }) - - it('returns a list of bootstrap peers when called with the default option', (done) => { - ipfs.bootstrap.add(null, { default: true }, (err, res) => { - expect(err).to.not.exist() - peers = res.Peers - expect(peers).to.exist() - expect(peers.length).to.above(1) - done() - }) + describe('.add', () => { + it('returns an error when called with an invalid arg', (done) => { + ipfs.bootstrap.add(invalidArg, (err) => { + expect(err).to.be.an.instanceof(Error) + done() }) }) - describe('.list', () => { - it('returns a list of peers', (done) => { - ipfs.bootstrap.list((err, res) => { - expect(err).to.not.exist() - peers = res.Peers - expect(peers).to.exist() - done() - }) + it('returns a list of containing the bootstrap peer when called with a valid arg (ip4)', (done) => { + ipfs.bootstrap.add(validIp4, (err, res) => { + expect(err).to.not.exist() + expect(res).to.be.eql({ Peers: [validIp4] }) + peers = res.Peers + expect(peers).to.exist() + expect(peers.length).to.eql(1) + done() }) }) - describe('.rm', () => { - it('returns an error when called with an invalid arg', (done) => { - ipfs.bootstrap.rm(invalidArg, (err) => { - expect(err).to.be.an.instanceof(Error) - done() - }) - }) - - it('returns empty list because no peers removed when called without an arg or options', (done) => { - ipfs.bootstrap.rm(null, (err, res) => { - expect(err).to.not.exist() - peers = res.Peers - expect(peers).to.exist() - expect(peers.length).to.eql(0) - done() - }) - }) - - it('returns list containing the peer removed when called with a valid arg (ip4)', (done) => { - ipfs.bootstrap.rm(null, (err, res) => { - expect(err).to.not.exist() - peers = res.Peers - expect(peers).to.exist() - expect(peers.length).to.eql(0) - done() - }) - }) - - it('returns list of all peers removed when all option is passed', (done) => { - ipfs.bootstrap.rm(null, { all: true }, (err, res) => { - expect(err).to.not.exist() - peers = res.Peers - expect(peers).to.exist() - done() - }) + it('returns a list of bootstrap peers when called with the default option', (done) => { + ipfs.bootstrap.add(null, { default: true }, (err, res) => { + expect(err).to.not.exist() + peers = res.Peers + expect(peers).to.exist() + expect(peers.length).to.above(1) + done() }) }) }) - describe('Promise API', function () { - this.timeout(100 * 1000) - - describe('.add', () => { - it('returns an error when called without args or options', () => { - return ipfs.bootstrap.add(null) - .catch((err) => { - expect(err).to.be.an.instanceof(Error) - }) - }) - - it('returns an error when called with an invalid arg', () => { - return ipfs.bootstrap.add(invalidArg) - .catch((err) => { - expect(err).to.be.an.instanceof(Error) - }) - }) - - it('returns a list of peers when called with a valid arg (ip4)', () => { - return ipfs.bootstrap.add(validIp4) - .then((res) => { - expect(res).to.be.eql({ Peers: [validIp4] }) - peers = res.Peers - expect(peers).to.exist() - expect(peers.length).to.eql(1) - }) - }) - - it('returns a list of default peers when called with the default option', () => { - return ipfs.bootstrap.add(null, { default: true }) - .then((res) => { - peers = res.Peers - expect(peers).to.exist() - expect(peers.length).to.above(1) - }) + describe('.list', () => { + it('returns a list of peers', (done) => { + ipfs.bootstrap.list((err, res) => { + expect(err).to.not.exist() + peers = res.Peers + expect(peers).to.exist() + done() }) }) + }) - describe('.list', () => { - it('returns a list of peers', () => { - return ipfs.bootstrap.list() - .then((res) => { - peers = res.Peers - expect(peers).to.exist() - }) + describe('.rm', () => { + it('returns an error when called with an invalid arg', (done) => { + ipfs.bootstrap.rm(invalidArg, (err) => { + expect(err).to.be.an.instanceof(Error) + done() }) }) - describe('.rm', () => { - it('returns an error when called with an invalid arg', () => { - return ipfs.bootstrap.rm(invalidArg) - .catch((err) => { - expect(err).to.be.an.instanceof(Error) - }) - }) - - it('returns empty list when called without an arg or options', () => { - return ipfs.bootstrap.rm(null) - .then((res) => { - peers = res.Peers - expect(peers).to.exist() - expect(peers.length).to.eql(0) - }) + it('returns empty list because no peers removed when called without an arg or options', (done) => { + ipfs.bootstrap.rm(null, (err, res) => { + expect(err).to.not.exist() + peers = res.Peers + expect(peers).to.exist() + expect(peers.length).to.eql(0) + done() }) + }) - it('returns list containing the peer removed when called with a valid arg (ip4)', () => { - return ipfs.bootstrap.rm(null) - .then((res) => { - peers = res.Peers - expect(peers).to.exist() - expect(peers.length).to.eql(0) - }) + it('returns list containing the peer removed when called with a valid arg (ip4)', (done) => { + ipfs.bootstrap.rm(null, (err, res) => { + expect(err).to.not.exist() + peers = res.Peers + expect(peers).to.exist() + expect(peers.length).to.eql(0) + done() }) + }) - it('returns list of all peers removed when all option is passed', () => { - return ipfs.bootstrap.rm(null, { all: true }) - .then((res) => { - peers = res.Peers - expect(peers).to.exist() - }) + it('returns list of all peers removed when all option is passed', (done) => { + ipfs.bootstrap.rm(null, { all: true }, (err, res) => { + expect(err).to.not.exist() + peers = res.Peers + expect(peers).to.exist() + done() }) }) })