Skip to content
This repository was archived by the owner on Aug 1, 2023. It is now read-only.

Commit 3e89ad4

Browse files
vasco-santosAlan Shaw
authored and
Alan Shaw
committed
test: add ipns pubsub tests (#39)
* test: add ipns pubsub tests * fix: code review
1 parent 24cf14a commit 3e89ad4

File tree

4 files changed

+202
-0
lines changed

4 files changed

+202
-0
lines changed

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"devDependencies": {
3838
"aegir": "^18.1.0",
3939
"async": "^2.6.2",
40+
"base64url": "^3.0.0",
4041
"bl": "^3.0.0",
4142
"bs58": "^4.0.1",
4243
"chai": "^4.2.0",
@@ -55,12 +56,14 @@
5556
"ipfs-repo": "~0.26.1",
5657
"ipfs-unixfs": "~0.1.16",
5758
"ipfsd-ctl": "~0.42.2",
59+
"ipns": "~0.5.1",
5860
"is-ci": "^2.0.0",
5961
"left-pad": "^1.3.0",
6062
"libp2p-websocket-star-rendezvous": "~0.3.0",
6163
"lodash": "^4.17.11",
6264
"merge-options": "^1.0.1",
6365
"mocha": "^5.2.0",
66+
"multihashes": "~0.4.14",
6467
"ncp": "^2.0.0",
6568
"pretty-bytes": "^5.1.0",
6669
"random-fs": "^1.0.3",

test/ipns-pubsub.js

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
/* eslint-env mocha */
2+
'use strict'
3+
4+
const chai = require('chai')
5+
const dirtyChai = require('dirty-chai')
6+
const expect = chai.expect
7+
chai.use(dirtyChai)
8+
9+
const { fromB58String } = require('multihashes')
10+
const base64url = require('base64url')
11+
const ipns = require('ipns')
12+
13+
const parallel = require('async/parallel')
14+
const retry = require('async/retry')
15+
const series = require('async/series')
16+
17+
const DaemonFactory = require('ipfsd-ctl')
18+
19+
const waitFor = require('./utils/wait-for')
20+
21+
const config = {
22+
Addresses: {
23+
API: '/ip4/0.0.0.0/tcp/0',
24+
Gateway: '/ip4/0.0.0.0/tcp/0',
25+
Swarm: []
26+
}
27+
}
28+
29+
const namespace = '/record/'
30+
31+
const spawnJsDaemon = (callback) => {
32+
DaemonFactory.create({ type: 'js' })
33+
.spawn({
34+
disposable: true,
35+
args: ['--enable-namesys-pubsub'], // enable ipns over pubsub
36+
config
37+
}, callback)
38+
}
39+
40+
const spawnGoDaemon = (callback) => {
41+
DaemonFactory.create()
42+
.spawn({
43+
disposable: true,
44+
args: ['--enable-namesys-pubsub'], // enable ipns over pubsub
45+
config
46+
}, callback)
47+
}
48+
49+
const ipfsRef = '/ipfs/QmPFVLPmp9zv5Z5KUqLhe2EivAGccQW2r7M7jhVJGLZoZU'
50+
51+
describe('ipns-pubsub', () => {
52+
let nodeAId
53+
let nodeBId
54+
let nodes = []
55+
56+
// Spawn daemons
57+
before(function (done) {
58+
// CI takes longer to instantiate the daemon, so we need to increase the timeout
59+
this.timeout(80 * 1000)
60+
61+
series([
62+
(cb) => spawnGoDaemon(cb),
63+
(cb) => spawnJsDaemon(cb)
64+
], (err, daemons) => {
65+
expect(err).to.not.exist()
66+
nodes = daemons
67+
68+
done()
69+
})
70+
})
71+
72+
// Get node ids
73+
before(function (done) {
74+
this.timeout(100 * 1000)
75+
76+
parallel([
77+
(cb) => nodes[0].api.id(cb),
78+
(cb) => nodes[1].api.id(cb)
79+
], (err, ids) => {
80+
expect(err).to.not.exist()
81+
expect(ids).to.exist()
82+
expect(ids[0].id).to.exist()
83+
expect(ids[1].id).to.exist()
84+
85+
nodeAId = ids[0]
86+
nodeBId = ids[1]
87+
88+
nodes[0].api.swarm.connect(ids[1].addresses[0], (err) => {
89+
expect(err).to.not.exist()
90+
91+
console.log('wait for republish as we can receive the republish message first')
92+
setTimeout(done, 60000) // wait for republish as we can receive the republish message first
93+
})
94+
})
95+
})
96+
97+
after(function (done) {
98+
this.timeout(60 * 1000)
99+
parallel(nodes.map((node) => (cb) => node.stop(cb)), done)
100+
})
101+
102+
it('should get enabled state of pubsub', function (done) {
103+
nodes[0].api.name.pubsub.state((err, state) => {
104+
expect(err).to.not.exist()
105+
expect(state).to.exist()
106+
expect(state.enabled).to.equal(true)
107+
108+
done()
109+
})
110+
})
111+
112+
it('should publish the received record to a go node and a js subscriber should receive it', function (done) {
113+
this.timeout(300 * 1000)
114+
115+
subscribeToReceiveByPubsub(nodes[0], nodes[1], nodeAId.id, done)
116+
})
117+
118+
it('should publish the received record to a js node and a go subscriber should receive it', function (done) {
119+
this.timeout(350 * 1000)
120+
121+
subscribeToReceiveByPubsub(nodes[1], nodes[0], nodeBId.id, done)
122+
})
123+
})
124+
125+
const subscribeToReceiveByPubsub = (nodeA, nodeB, id, callback) => {
126+
let subscribed = false
127+
function checkMessage (msg) {
128+
subscribed = true
129+
}
130+
131+
const keys = ipns.getIdKeys(fromB58String(id))
132+
const topic = `${namespace}${base64url.encode(keys.routingKey.toBuffer())}`
133+
134+
// try to resolve a unpublished record (will subscribe it)
135+
nodeB.api.name.resolve(id, (err) => {
136+
expect(err).to.exist() // not found
137+
138+
series([
139+
(cb) => waitForPeerToSubscribe(nodeB.api, topic, cb),
140+
(cb) => nodeB.api.pubsub.subscribe(topic, checkMessage, cb),
141+
(cb) => nodeA.api.name.publish(ipfsRef, { resolve: false }, cb),
142+
(cb) => waitFor(() => subscribed === true, (50 * 1000), cb),
143+
(cb) => nodeB.api.name.resolve(id, cb)
144+
], (err, res) => {
145+
expect(err).to.not.exist()
146+
expect(res).to.exist()
147+
148+
expect(res[2].name).to.equal(id) // Published to Node A ID
149+
expect(res[4]).to.equal(ipfsRef)
150+
151+
callback()
152+
})
153+
})
154+
}
155+
156+
// Wait until a peer subscribes a topic
157+
const waitForPeerToSubscribe = (daemon, topic, callback) => {
158+
retry({
159+
times: 5,
160+
interval: 2000
161+
}, (next) => {
162+
daemon.pubsub.ls((error, res) => {
163+
if (error) {
164+
return next(error)
165+
}
166+
167+
if (!res || !res.length || !res.includes(topic)) {
168+
return next(new Error('Could not find subscription'))
169+
}
170+
171+
return next(null, res[0])
172+
})
173+
}, callback)
174+
}

test/node.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ require('./ipns')
1010
require('./kad-dht')
1111
require('./pin')
1212
require('./files')
13+
require('./ipns-pubsub')

test/utils/wait-for.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use strict'
2+
3+
/*
4+
* Wait for a condition to become true. When its true, callback is called.
5+
*/
6+
module.exports = (predicate, ttl, callback) => {
7+
if (typeof ttl === 'function') {
8+
callback = ttl
9+
ttl = Date.now() + (10 * 1000)
10+
} else {
11+
ttl = Date.now() + ttl
12+
}
13+
14+
const self = setInterval(() => {
15+
if (predicate()) {
16+
clearInterval(self)
17+
return callback()
18+
}
19+
if (Date.now() > ttl) {
20+
clearInterval(self)
21+
return callback(new Error('waitFor time expired'))
22+
}
23+
}, 50)
24+
}

0 commit comments

Comments
 (0)