Skip to content
Permalink
Newer
Older
100644 142 lines (120 sloc) 4.67 KB
1
/* eslint-env mocha */
2
3
import PeerID from 'peer-id'
4
import { base58btc } from 'multiformats/bases/base58'
5
import { getIdKeys } from 'ipns'
6
import last from 'it-last'
7
import pRetry from 'p-retry'
8
import { waitFor } from './utils/wait-for.js'
9
import { expect } from 'aegir/utils/chai.js'
10
import { daemonFactory } from './utils/daemon-factory.js'
11
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
14
args: ['--enable-namesys-pubsub'] // enable ipns over pubsub
17
const retryOptions = {
21
const namespace = '/record/'
22
23
const ipfsRef = '/ipfs/QmPFVLPmp9zv5Z5KUqLhe2EivAGccQW2r7M7jhVJGLZoZU'
24
25
describe('ipns-pubsub', function () {
26
let nodes = []
27
let factory
28
29
before(async () => {
30
factory = await daemonFactory()
31
})
32
33
// Spawn daemons
34
before('create the nodes', async function () {
35
this.timeout(20e3)
37
factory.spawn({
39
test: true,
40
...daemonsOptions
41
}),
42
factory.spawn({
44
test: true,
45
...daemonsOptions
46
}),
47
// TODO: go-ipfs needs two nodes in the DHT to be able to publish a record
48
// Remove this when js-ipfs has a DHT
49
factory.spawn({
50
type: 'go',
51
test: true,
52
...daemonsOptions
53
})
57
// Connect nodes and wait for republish
58
before('connect the nodes', async function () {
59
this.timeout(10e3)
60
// TODO: go-ipfs needs two nodes in the DHT to be able to publish a record
61
// Remove the second connect when js-ipfs runs a DHT server
62
await Promise.all([
63
nodes[0].api.swarm.connect(nodes[1].api.peerId.addresses[0]),
64
nodes[0].api.swarm.connect(nodes[2].api.peerId.addresses[0])
65
])
68
after(() => factory.clean())
70
it('should get enabled state of pubsub', async function () {
71
for (const node of nodes) {
72
const state = await node.api.name.pubsub.state()
73
expect(state).to.exist()
74
expect(state.enabled).to.equal(true)
75
}
78
it('should publish the received record to a go node and a js subscriber should receive it', async function () {
79
// TODO find out why JS doesn't resolve, might be just missing a DHT
80
await Promise.all([
81
subscribeToReceiveByPubsub(nodes[0], nodes[1], nodes[0].api.peerId.id, nodes[1].api.peerId.id),
82
expect(last(nodes[1].api.name.resolve(nodes[0].api.peerId.id, { stream: false }))).to.eventually.be.rejected.with(/was not found in the network/)
83
])
86
it('should publish the received record to a js node and a go subscriber should receive it', async function () {
87
await Promise.all([
88
subscribeToReceiveByPubsub(nodes[1], nodes[0], nodes[1].api.peerId.id, nodes[0].api.peerId.id),
89
last(nodes[0].api.name.resolve(nodes[1].api.peerId.id, { stream: false }))
90
])
91
})
92
})
93
94
// * IPNS resolve subscription test
95
// * 1) name.resolve() , which subscribes the topic
96
// * 2) wait to guarantee the subscription
97
// * 3) subscribe again just to know until when to wait (inside the scope of the test)
98
// * 4) wait for the other peer to get notified of the subscription
99
// * 5) publish new ipns record
100
// * 6) wait until the record is received in the test scope subscribe
101
// * 7) resolve ipns record
102
const subscribeToReceiveByPubsub = async (nodeA, nodeB, idA, idB) => {
103
let subscribed = false
104
function checkMessage (msg) {
105
subscribed = true
106
}
107
108
const keys = getIdKeys(base58btc.decode(`z${idA}`))
109
const topic = `${namespace}${uint8ArrayToString(keys.routingKey.uint8Array(), 'base64url')}`
111
await waitForPeerToSubscribe(nodeB.api, topic)
112
await nodeB.api.pubsub.subscribe(topic, checkMessage)
113
await waitForNotificationOfSubscription(nodeA.api, topic, idB)
114
const res1 = await nodeA.api.name.publish(ipfsRef, { resolve: false })
115
await waitFor(() => subscribed === true, (50 * 1000))
116
const res2 = await last(nodeB.api.name.resolve(idA))
118
expect(PeerID.parse(res1.name).toString()).to.equal(PeerID.parse(idA).toString()) // Published to Node A ID
119
expect(res2).to.equal(ipfsRef)
122
// wait until a peer know about other peer to subscribe a topic
123
const waitForNotificationOfSubscription = (daemon, topic, peerId) => pRetry(async () => {
124
const res = await daemon.pubsub.peers(topic)
125
126
if (!res || !res.length || !res.includes(peerId)) {
127
throw new Error('Could not find peer subscribing')
128
}
129
}, retryOptions)
131
// Wait until a peer subscribes a topic
132
const waitForPeerToSubscribe = async (daemon, topic) => {
133
await pRetry(async () => {
134
const res = await daemon.pubsub.ls()
135
136
if (!res || !res.length || !res.includes(topic)) {
137
throw new Error(`Could not find subscription to ${topic} in "${JSON.stringify(res)}"`)
138
}
139
140
return res[0]
141
}, retryOptions)