diff --git a/src/miscellaneous/dns.js b/src/miscellaneous/dns.js index 0da111f9..a8e2fe8a 100644 --- a/src/miscellaneous/dns.js +++ b/src/miscellaneous/dns.js @@ -8,7 +8,9 @@ module.exports = (createCommon, options) => { const it = getIt(options) const common = createCommon() - describe('.dns', () => { + describe('.dns', function () { + this.timeout(10 * 1000) + this.retries(3) let ipfs before(function (done) { @@ -30,20 +32,7 @@ module.exports = (createCommon, options) => { common.teardown(done) }) - it('should resolve a DNS link', function (done) { - this.timeout(20 * 1000) - this.retries(3) - - ipfs.dns('ipfs.io', { r: true }, (err, path) => { - expect(err).to.not.exist() - expect(path).to.exist() - done() - }) - }) - - // skipping because there is an error in https://ipfs.io/api/v0/dns?arg=ipfs.io - // unskip when it is resolved and the new version released: https://github.com/ipfs/go-ipfs/issues/6086 - it.skip('should non-recursively resolve ipfs.io', () => { + it('should non-recursively resolve ipfs.io', () => { return ipfs.dns('ipfs.io', { recursive: false }).then(res => { // matches pattern /ipns/ expect(res).to.match(/\/ipns\/.+$/) diff --git a/src/name/publish.js b/src/name/publish.js index ab9a6a72..a851aec2 100644 --- a/src/name/publish.js +++ b/src/name/publish.js @@ -12,7 +12,7 @@ module.exports = (createCommon, options) => { const it = getIt(options) const common = createCommon() - describe('.name.publish', function () { + describe('.name.publish offline', function () { const keyName = hat() let ipfs let nodeId @@ -43,7 +43,7 @@ module.exports = (createCommon, options) => { const value = fixture.cid - ipfs.name.publish(value, (err, res) => { + ipfs.name.publish(value, { 'allow-offline': true }, (err, res) => { expect(err).to.not.exist() expect(res).to.exist() expect(res.name).to.equal(nodeId) @@ -53,6 +53,13 @@ module.exports = (createCommon, options) => { }) }) + it('should publish correctly with the lifetime option and resolve', async () => { + const [{ path }] = await ipfs.add(Buffer.from('should publish correctly with the lifetime option and resolve')) + await ipfs.name.publish(path, { 'allow-offline': true, resolve: false, lifetime: '2h' }) + + return expect(await ipfs.name.resolve(`/ipns/${nodeId}`)).to.eq(`/ipfs/${path}`) + }) + it('should publish correctly when the file was not added but resolve is disabled', function (done) { this.timeout(50 * 1000) @@ -62,7 +69,8 @@ module.exports = (createCommon, options) => { resolve: false, lifetime: '1m', ttl: '10s', - key: 'self' + key: 'self', + 'allow-offline': true } ipfs.name.publish(value, options, (err, res) => { @@ -83,7 +91,8 @@ module.exports = (createCommon, options) => { resolve: false, lifetime: '24h', ttl: '10s', - key: keyName + key: keyName, + 'allow-offline': true } ipfs.key.gen(keyName, { type: 'rsa', size: 2048 }, function (err, key) { diff --git a/src/name/resolve.js b/src/name/resolve.js index 04978578..6002c249 100644 --- a/src/name/resolve.js +++ b/src/name/resolve.js @@ -2,28 +2,20 @@ /* eslint-env mocha */ 'use strict' -const hat = require('hat') - -const { fixture } = require('./utils') const { spawnNodeWithId } = require('../utils/spawn') const { getDescribe, getIt, expect } = require('../utils/mocha') +const delay = require('../utils/delay') module.exports = (createCommon, options) => { const describe = getDescribe(options) const it = getIt(options) - const common = createCommon() - describe('.name.resolve', function () { - const keyName = hat() + describe('.name.resolve offline', function () { + const common = createCommon() let ipfs let nodeId - let keyId 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() @@ -32,106 +24,157 @@ module.exports = (createCommon, options) => { ipfs = node nodeId = node.peerId.id - - ipfs.add(fixture.data, { pin: false }, done) + done() }) }) }) after((done) => common.teardown(done)) - it('should resolve a record with the default params after a publish', function (done) { - this.timeout(50 * 1000) + it('should resolve a record default options', async () => { + const [{ path }] = await ipfs.add(Buffer.from('should resolve a record default options')) - const value = fixture.cid + const { id: keyId } = await ipfs.key.gen('key-name-default', { type: 'rsa', size: 2048 }) - ipfs.name.publish(value, (err, res) => { - expect(err).to.not.exist() - expect(res).to.exist() + await ipfs.name.publish(path, { 'allow-offline': true }) + await ipfs.name.publish(`/ipns/${nodeId}`, { 'allow-offline': true, key: 'key-name-default' }) - ipfs.name.resolve(nodeId, (err, res) => { - expect(err).to.not.exist() - expect(res).to.exist() - expect(res.path).to.equal(`/ipfs/${value}`) + return expect(await ipfs.name.resolve(`/ipns/${keyId}`)) + .to.eq(`/ipfs/${path}`) + }) - done() - }) - }) + it('should resolve a record recursive === false', async () => { + const [{ path }] = await ipfs.add(Buffer.from('should resolve a record recursive === false')) + await ipfs.name.publish(path, { 'allow-offline': true }) + return expect(await ipfs.name.resolve(`/ipns/${nodeId}`, { recursive: false })) + .to.eq(`/ipfs/${path}`) }) - it('should not get the entry if its validity time expired', function (done) { - this.timeout(50 * 1000) + it('should resolve a record recursive === true', async () => { + const [{ path }] = await ipfs.add(Buffer.from('should resolve a record recursive === true')) - const value = fixture.cid - const publishOptions = { - resolve: true, - lifetime: '1ms', - ttl: '10s', - key: 'self' - } + const { id: keyId } = await ipfs.key.gen('key-name', { type: 'rsa', size: 2048 }) - ipfs.name.publish(value, publishOptions, (err, res) => { - expect(err).to.not.exist() - expect(res).to.exist() - - // guarantee that the record has an expired validity. - setTimeout(function () { - ipfs.name.resolve(nodeId, (err, res) => { - expect(err).to.exist() - expect(err.message).to.equal('record has expired') - expect(res).to.not.exist() - - done() - }) - }, 1) - }) + await ipfs.name.publish(path, { 'allow-offline': true }) + await ipfs.name.publish(`/ipns/${nodeId}`, { 'allow-offline': true, key: 'key-name' }) + + return expect(await ipfs.name.resolve(`/ipns/${keyId}`, { recursive: true })) + .to.eq(`/ipfs/${path}`) + }) + + it('should resolve a record default options with remainder', async () => { + const [{ path }] = await ipfs.add(Buffer.from('should resolve a record default options with remainder')) + + const { id: keyId } = await ipfs.key.gen('key-name-remainder-default', { type: 'rsa', size: 2048 }) + + await ipfs.name.publish(path, { 'allow-offline': true }) + await ipfs.name.publish(`/ipns/${nodeId}`, { 'allow-offline': true, key: 'key-name-remainder-default' }) + + return expect(await ipfs.name.resolve(`/ipns/${keyId}/remainder/file.txt`)) + .to.eq(`/ipfs/${path}/remainder/file.txt`) + }) + + it('should resolve a record recursive === false with remainder', async () => { + const [{ path }] = await ipfs.add(Buffer.from('should resolve a record recursive = false with remainder')) + await ipfs.name.publish(path, { 'allow-offline': true }) + return expect(await ipfs.name.resolve(`/ipns/${nodeId}/remainder/file.txt`, { recursive: false })) + .to.eq(`/ipfs/${path}/remainder/file.txt`) }) - it('should recursively resolve to an IPFS hash', function (done) { - this.timeout(100 * 1000) + it('should resolve a record recursive === true with remainder', async () => { + const [{ path }] = await ipfs.add(Buffer.from('should resolve a record recursive = true with remainder')) + + const { id: keyId } = await ipfs.key.gen('key-name-remainder', { type: 'rsa', size: 2048 }) - const value = fixture.cid + await ipfs.name.publish(path, { 'allow-offline': true }) + await ipfs.name.publish(`/ipns/${nodeId}`, { 'allow-offline': true, key: 'key-name-remainder' }) + + return expect(await ipfs.name.resolve(`/ipns/${keyId}/remainder/file.txt`, { recursive: true })) + .to.eq(`/ipfs/${path}/remainder/file.txt`) + }) + + it('should not get the entry if its validity time expired', async () => { const publishOptions = { - resolve: false, - lifetime: '24h', + lifetime: '100ms', ttl: '10s', - key: 'self' + 'allow-offline': true } - // Generate new key - ipfs.key.gen(keyName, { type: 'rsa', size: 2048 }, (err, key) => { - expect(err).to.not.exist() + // we add new data instead of re-using fixture to make sure lifetime handling doesn't break + const [{ path }] = await ipfs.add(Buffer.from('should not get the entry if its validity time expired')) + await ipfs.name.publish(path, publishOptions) + await delay(500) + // go only has 1 possible error https://github.com/ipfs/go-ipfs/blob/master/namesys/interface.go#L51 + // so here we just expect an Error and don't match the error type to expiration + try { + await ipfs.name.resolve(nodeId) + } catch (error) { + expect(error).to.exist() + } + }) + }) + + describe('.name.resolve dns', function () { + const common = createCommon() + let ipfs + this.retries(3) - keyId = key.id + before(function (done) { + common.setup((err, factory) => { + expect(err).to.not.exist() - // publish ipfs - ipfs.name.publish(value, publishOptions, (err, res) => { + spawnNodeWithId(factory, (err, node) => { expect(err).to.not.exist() - expect(res).to.exist() - publishOptions.key = keyName + ipfs = node + done() + }) + }) + }) - // publish ipns with the generated key - ipfs.name.publish(`/ipns/${nodeId}`, publishOptions, (err, res) => { - expect(err).to.not.exist() - expect(res).to.exist() + after((done) => common.teardown(done)) - const resolveOptions = { - nocache: false, - recursive: true - } + it('should resolve /ipns/ipfs.io', async () => { + return expect(await ipfs.name.resolve('/ipns/ipfs.io')) + .to.match(/\/ipfs\/.+$/) + }) - // recursive resolve (will get ipns first, and will resolve again to find the ipfs) - ipfs.name.resolve(keyId, resolveOptions, (err, res) => { - expect(err).to.not.exist() - expect(res).to.exist() - expect(res.path).to.equal(`/ipfs/${value}`) + it('should resolve /ipns/ipfs.io recursive === false', async () => { + return expect(await ipfs.name.resolve('/ipns/ipfs.io', { recursive: false })) + .to.match(/\/ipns\/.+$/) + }) - done() - }) - }) - }) - }) + it('should resolve /ipns/ipfs.io recursive === true', async () => { + return expect(await ipfs.name.resolve('/ipns/ipfs.io', { recursive: true })) + .to.match(/\/ipfs\/.+$/) + }) + + it('should resolve /ipns/ipfs.io with remainder', async () => { + return expect(await ipfs.name.resolve('/ipns/ipfs.io/images/ipfs-logo.svg')) + .to.match(/\/ipfs\/.+\/images\/ipfs-logo.svg$/) + }) + + it('should resolve /ipns/ipfs.io with remainder recursive === false', async () => { + return expect(await ipfs.name.resolve('/ipns/ipfs.io/images/ipfs-logo.svg', { recursive: false })) + .to.match(/\/ipns\/.+\/images\/ipfs-logo.svg$/) + }) + + it('should resolve /ipns/ipfs.io with remainder recursive === true', async () => { + return expect(await ipfs.name.resolve('/ipns/ipfs.io/images/ipfs-logo.svg', { recursive: true })) + .to.match(/\/ipfs\/.+\/images\/ipfs-logo.svg$/) + }) + + it('should fail to resolve /ipns/ipfs.a', async () => { + try { + await ipfs.name.resolve('ipfs.a') + } catch (error) { + expect(error).to.exist() + } + }) + + it('should resolve ipns path with hamt-shard recursive === true', async () => { + return expect(await ipfs.name.resolve('/ipns/tr.wikipedia-on-ipfs.org/wiki/Anasayfa.html', { recursive: true })) + .to.match(/\/ipfs\/.+$/) }) }) } diff --git a/src/pubsub/subscribe.js b/src/pubsub/subscribe.js index 06645c01..64436f60 100644 --- a/src/pubsub/subscribe.js +++ b/src/pubsub/subscribe.js @@ -51,7 +51,7 @@ module.exports = (createCommon, options) => { expect(msg.data.toString()).to.equal('hi') expect(msg).to.have.property('seqno') expect(Buffer.isBuffer(msg.seqno)).to.eql(true) - expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg.topicIDs[0]).to.eq(topic) expect(msg).to.have.property('from', ipfs1.peerId.id) ipfs1.pubsub.unsubscribe(topic, handler, (err) => { @@ -79,7 +79,7 @@ module.exports = (createCommon, options) => { expect(msg.data.toString()).to.equal('hi') expect(msg).to.have.property('seqno') expect(Buffer.isBuffer(msg.seqno)).to.eql(true) - expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg.topicIDs[0]).to.eq(topic) expect(msg).to.have.property('from', ipfs1.peerId.id) ipfs1.pubsub.unsubscribe(topic, handler, (err) => { @@ -107,7 +107,7 @@ module.exports = (createCommon, options) => { expect(msg.data.toString()).to.equal('hi') expect(msg).to.have.property('seqno') expect(Buffer.isBuffer(msg.seqno)).to.eql(true) - expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg.topicIDs[0]).to.eq(topic) expect(msg).to.have.property('from', ipfs1.peerId.id) ipfs1.pubsub.unsubscribe(topic, handler, (err) => { @@ -135,7 +135,7 @@ module.exports = (createCommon, options) => { expect(msg.data.toString()).to.equal('hi') expect(msg).to.have.property('seqno') expect(Buffer.isBuffer(msg.seqno)).to.eql(true) - expect(msg).to.have.property('topicIDs').eql([topic]) + expect(msg.topicIDs[0]).to.eq(topic) expect(msg).to.have.property('from', ipfs1.peerId.id) ipfs1.pubsub.unsubscribe(topic, handler, (err) => { diff --git a/src/utils/delay.js b/src/utils/delay.js new file mode 100644 index 00000000..0295cb6c --- /dev/null +++ b/src/utils/delay.js @@ -0,0 +1,20 @@ +'use strict' + +/** + * Promise version of setTimeout + * @example + * ```js + * async function something() { + * console.log("this might take some time...."); + * await delay(5000); + * console.log("done!") + * } + * + * something(); + * ``` + * @param {number} ms + * @return {Promise} + */ +const delay = ms => new Promise(resolve => setTimeout(resolve, ms)) + +module.exports = delay