@libp2p/interface-compliance-tests 3.0.7 → 4.0.0-5ffa7a74
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -3
- package/dist/src/connection/index.d.ts +5 -0
- package/dist/src/connection/index.d.ts.map +1 -0
- package/dist/src/connection/index.js +150 -0
- package/dist/src/connection/index.js.map +1 -0
- package/dist/src/connection-encryption/index.d.ts +5 -0
- package/dist/src/connection-encryption/index.d.ts.map +1 -0
- package/dist/src/connection-encryption/index.js +71 -0
- package/dist/src/connection-encryption/index.js.map +1 -0
- package/dist/src/connection-encryption/utils/index.d.ts +3 -0
- package/dist/src/connection-encryption/utils/index.d.ts.map +1 -0
- package/dist/src/connection-encryption/utils/index.js +19 -0
- package/dist/src/connection-encryption/utils/index.js.map +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/is-valid-tick.d.ts.map +1 -1
- package/dist/src/is-valid-tick.js.map +1 -1
- package/dist/src/mocks/connection-encrypter.d.ts +3 -0
- package/dist/src/mocks/connection-encrypter.d.ts.map +1 -0
- package/dist/src/mocks/connection-encrypter.js +98 -0
- package/dist/src/mocks/connection-encrypter.js.map +1 -0
- package/dist/src/mocks/connection-gater.d.ts +3 -0
- package/dist/src/mocks/connection-gater.d.ts.map +1 -0
- package/dist/src/mocks/connection-gater.js +17 -0
- package/dist/src/mocks/connection-gater.js.map +1 -0
- package/dist/src/mocks/connection-manager.d.ts +29 -0
- package/dist/src/mocks/connection-manager.d.ts.map +1 -0
- package/dist/src/mocks/connection-manager.js +145 -0
- package/dist/src/mocks/connection-manager.js.map +1 -0
- package/dist/src/mocks/connection.d.ts +32 -0
- package/dist/src/mocks/connection.d.ts.map +1 -0
- package/dist/src/mocks/connection.js +167 -0
- package/dist/src/mocks/connection.js.map +1 -0
- package/dist/src/mocks/duplex.d.ts +3 -0
- package/dist/src/mocks/duplex.d.ts.map +1 -0
- package/dist/src/mocks/duplex.js +9 -0
- package/dist/src/mocks/duplex.js.map +1 -0
- package/dist/src/mocks/index.d.ts +13 -0
- package/dist/src/mocks/index.d.ts.map +1 -0
- package/dist/src/mocks/index.js +11 -0
- package/dist/src/mocks/index.js.map +1 -0
- package/dist/src/mocks/metrics.d.ts +3 -0
- package/dist/src/mocks/metrics.d.ts.map +1 -0
- package/dist/src/mocks/metrics.js +115 -0
- package/dist/src/mocks/metrics.js.map +1 -0
- package/dist/src/mocks/multiaddr-connection.d.ts +17 -0
- package/dist/src/mocks/multiaddr-connection.d.ts.map +1 -0
- package/dist/src/mocks/multiaddr-connection.js +60 -0
- package/dist/src/mocks/multiaddr-connection.js.map +1 -0
- package/dist/src/mocks/muxer.d.ts +36 -0
- package/dist/src/mocks/muxer.d.ts.map +1 -0
- package/dist/src/mocks/muxer.js +213 -0
- package/dist/src/mocks/muxer.js.map +1 -0
- package/dist/src/mocks/peer-discovery.d.ts +22 -0
- package/dist/src/mocks/peer-discovery.d.ts.map +1 -0
- package/dist/src/mocks/peer-discovery.js +47 -0
- package/dist/src/mocks/peer-discovery.js.map +1 -0
- package/dist/src/mocks/registrar.d.ts +18 -0
- package/dist/src/mocks/registrar.d.ts.map +1 -0
- package/dist/src/mocks/registrar.js +66 -0
- package/dist/src/mocks/registrar.js.map +1 -0
- package/dist/src/mocks/upgrader.d.ts +10 -0
- package/dist/src/mocks/upgrader.d.ts.map +1 -0
- package/dist/src/mocks/upgrader.js +31 -0
- package/dist/src/mocks/upgrader.js.map +1 -0
- package/dist/src/peer-discovery/index.d.ts +5 -0
- package/dist/src/peer-discovery/index.d.ts.map +1 -0
- package/dist/src/peer-discovery/index.js +66 -0
- package/dist/src/peer-discovery/index.js.map +1 -0
- package/dist/src/pubsub/api.d.ts +6 -0
- package/dist/src/pubsub/api.d.ts.map +1 -0
- package/dist/src/pubsub/api.js +87 -0
- package/dist/src/pubsub/api.js.map +1 -0
- package/dist/src/pubsub/connection-handlers.d.ts +6 -0
- package/dist/src/pubsub/connection-handlers.d.ts.map +1 -0
- package/dist/src/pubsub/connection-handlers.js +329 -0
- package/dist/src/pubsub/connection-handlers.js.map +1 -0
- package/dist/src/pubsub/emit-self.d.ts +6 -0
- package/dist/src/pubsub/emit-self.d.ts.map +1 -0
- package/dist/src/pubsub/emit-self.js +80 -0
- package/dist/src/pubsub/emit-self.js.map +1 -0
- package/dist/src/pubsub/index.d.ts +18 -0
- package/dist/src/pubsub/index.d.ts.map +1 -0
- package/dist/src/pubsub/index.js +17 -0
- package/dist/src/pubsub/index.js.map +1 -0
- package/dist/src/pubsub/messages.d.ts +6 -0
- package/dist/src/pubsub/messages.d.ts.map +1 -0
- package/dist/src/pubsub/messages.js +48 -0
- package/dist/src/pubsub/messages.js.map +1 -0
- package/dist/src/pubsub/multiple-nodes.d.ts +6 -0
- package/dist/src/pubsub/multiple-nodes.d.ts.map +1 -0
- package/dist/src/pubsub/multiple-nodes.js +350 -0
- package/dist/src/pubsub/multiple-nodes.js.map +1 -0
- package/dist/src/pubsub/two-nodes.d.ts +6 -0
- package/dist/src/pubsub/two-nodes.d.ts.map +1 -0
- package/dist/src/pubsub/two-nodes.js +217 -0
- package/dist/src/pubsub/two-nodes.js.map +1 -0
- package/dist/src/pubsub/utils.d.ts +6 -0
- package/dist/src/pubsub/utils.d.ts.map +1 -0
- package/dist/src/pubsub/utils.js +22 -0
- package/dist/src/pubsub/utils.js.map +1 -0
- package/dist/src/stream-muxer/base-test.d.ts +5 -0
- package/dist/src/stream-muxer/base-test.d.ts.map +1 -0
- package/dist/src/stream-muxer/base-test.js +153 -0
- package/dist/src/stream-muxer/base-test.js.map +1 -0
- package/dist/src/stream-muxer/close-test.d.ts +5 -0
- package/dist/src/stream-muxer/close-test.d.ts.map +1 -0
- package/dist/src/stream-muxer/close-test.js +357 -0
- package/dist/src/stream-muxer/close-test.js.map +1 -0
- package/dist/src/stream-muxer/fixtures/pb/message.d.ts +13 -0
- package/dist/src/stream-muxer/fixtures/pb/message.d.ts.map +1 -0
- package/dist/src/stream-muxer/fixtures/pb/message.js +67 -0
- package/dist/src/stream-muxer/fixtures/pb/message.js.map +1 -0
- package/dist/src/stream-muxer/index.d.ts +5 -0
- package/dist/src/stream-muxer/index.d.ts.map +1 -0
- package/dist/src/stream-muxer/index.js +13 -0
- package/dist/src/stream-muxer/index.js.map +1 -0
- package/dist/src/stream-muxer/mega-stress-test.d.ts +5 -0
- package/dist/src/stream-muxer/mega-stress-test.d.ts.map +1 -0
- package/dist/src/stream-muxer/mega-stress-test.js +11 -0
- package/dist/src/stream-muxer/mega-stress-test.js.map +1 -0
- package/dist/src/stream-muxer/spawner.d.ts +4 -0
- package/dist/src/stream-muxer/spawner.d.ts.map +1 -0
- package/dist/src/stream-muxer/spawner.js +37 -0
- package/dist/src/stream-muxer/spawner.js.map +1 -0
- package/dist/src/stream-muxer/stress-test.d.ts +5 -0
- package/dist/src/stream-muxer/stress-test.d.ts.map +1 -0
- package/dist/src/stream-muxer/stress-test.js +23 -0
- package/dist/src/stream-muxer/stress-test.js.map +1 -0
- package/dist/src/transport/dial-test.d.ts +5 -0
- package/dist/src/transport/dial-test.d.ts.map +1 -0
- package/dist/src/transport/dial-test.js +98 -0
- package/dist/src/transport/dial-test.js.map +1 -0
- package/dist/src/transport/filter-test.d.ts +5 -0
- package/dist/src/transport/filter-test.d.ts.map +1 -0
- package/dist/src/transport/filter-test.js +18 -0
- package/dist/src/transport/filter-test.js.map +1 -0
- package/dist/src/transport/index.d.ts +15 -0
- package/dist/src/transport/index.d.ts.map +1 -0
- package/dist/src/transport/index.js +11 -0
- package/dist/src/transport/index.js.map +1 -0
- package/dist/src/transport/listen-test.d.ts +5 -0
- package/dist/src/transport/listen-test.d.ts.map +1 -0
- package/dist/src/transport/listen-test.js +152 -0
- package/dist/src/transport/listen-test.js.map +1 -0
- package/package.json +74 -97
- package/src/connection/index.ts +182 -0
- package/src/connection-encryption/index.ts +97 -0
- package/src/connection-encryption/utils/index.ts +24 -0
- package/src/index.ts +0 -1
- package/src/is-valid-tick.ts +0 -1
- package/src/mocks/connection-encrypter.ts +113 -0
- package/src/mocks/connection-gater.ts +18 -0
- package/src/mocks/connection-manager.ts +211 -0
- package/src/mocks/connection.ts +226 -0
- package/src/mocks/duplex.ts +10 -0
- package/src/mocks/index.ts +12 -0
- package/src/mocks/metrics.ts +162 -0
- package/src/mocks/multiaddr-connection.ts +76 -0
- package/src/mocks/muxer.ts +303 -0
- package/src/mocks/peer-discovery.ts +60 -0
- package/src/mocks/registrar.ts +88 -0
- package/src/mocks/upgrader.ts +49 -0
- package/src/peer-discovery/index.ts +90 -0
- package/src/pubsub/api.ts +114 -0
- package/src/pubsub/connection-handlers.ts +413 -0
- package/src/pubsub/emit-self.ts +99 -0
- package/src/pubsub/index.ts +34 -0
- package/src/pubsub/messages.ts +59 -0
- package/src/pubsub/multiple-nodes.ts +440 -0
- package/src/pubsub/two-nodes.ts +273 -0
- package/src/pubsub/utils.ts +29 -0
- package/src/stream-muxer/base-test.ts +196 -0
- package/src/stream-muxer/close-test.ts +442 -0
- package/src/stream-muxer/fixtures/pb/message.proto +7 -0
- package/src/stream-muxer/fixtures/pb/message.ts +87 -0
- package/src/stream-muxer/index.ts +15 -0
- package/src/stream-muxer/mega-stress-test.ts +14 -0
- package/src/stream-muxer/spawner.ts +55 -0
- package/src/stream-muxer/stress-test.ts +27 -0
- package/src/transport/dial-test.ts +124 -0
- package/src/transport/filter-test.ts +25 -0
- package/src/transport/index.ts +25 -0
- package/src/transport/listen-test.ts +191 -0
- package/dist/typedoc-urls.json +0 -3
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
/* eslint max-nested-callbacks: ["error", 6] */
|
|
2
|
+
import { start, stop } from '@libp2p/interface/startable'
|
|
3
|
+
import { expect } from 'aegir/chai'
|
|
4
|
+
import delay from 'delay'
|
|
5
|
+
import pDefer from 'p-defer'
|
|
6
|
+
import pWaitFor from 'p-wait-for'
|
|
7
|
+
import sinon from 'sinon'
|
|
8
|
+
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
|
|
9
|
+
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
|
|
10
|
+
import { mockNetwork } from '../mocks/index.js'
|
|
11
|
+
import { createComponents, waitForSubscriptionUpdate } from './utils.js'
|
|
12
|
+
import type { PubSubArgs, PubSubComponents } from './index.js'
|
|
13
|
+
import type { TestSetup } from '../index.js'
|
|
14
|
+
import type { Message, PubSub } from '@libp2p/interface/pubsub'
|
|
15
|
+
|
|
16
|
+
export default (common: TestSetup<PubSub, PubSubArgs>): void => {
|
|
17
|
+
describe('pubsub with multiple nodes', function () {
|
|
18
|
+
describe('every peer subscribes to the topic', () => {
|
|
19
|
+
describe('line', () => {
|
|
20
|
+
// line
|
|
21
|
+
// ◉────◉────◉
|
|
22
|
+
// a b c
|
|
23
|
+
let psA: PubSub
|
|
24
|
+
let psB: PubSub
|
|
25
|
+
let psC: PubSub
|
|
26
|
+
let componentsA: PubSubComponents
|
|
27
|
+
let componentsB: PubSubComponents
|
|
28
|
+
let componentsC: PubSubComponents
|
|
29
|
+
|
|
30
|
+
// Create and start pubsub nodes
|
|
31
|
+
beforeEach(async () => {
|
|
32
|
+
mockNetwork.reset()
|
|
33
|
+
|
|
34
|
+
componentsA = await createComponents()
|
|
35
|
+
componentsB = await createComponents()
|
|
36
|
+
componentsC = await createComponents()
|
|
37
|
+
|
|
38
|
+
psA = componentsA.pubsub = await common.setup({
|
|
39
|
+
components: componentsA,
|
|
40
|
+
init: {
|
|
41
|
+
emitSelf: true
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
psB = componentsB.pubsub = await common.setup({
|
|
45
|
+
components: componentsB,
|
|
46
|
+
init: {
|
|
47
|
+
emitSelf: true
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
psC = componentsC.pubsub = await common.setup({
|
|
51
|
+
components: componentsC,
|
|
52
|
+
init: {
|
|
53
|
+
emitSelf: true
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
// Start pubsub modes
|
|
58
|
+
await start(...Object.values(componentsA), ...Object.values(componentsB), ...Object.values(componentsC))
|
|
59
|
+
|
|
60
|
+
// Connect nodes
|
|
61
|
+
await componentsA.connectionManager.openConnection(componentsB.peerId)
|
|
62
|
+
await componentsB.connectionManager.openConnection(componentsC.peerId)
|
|
63
|
+
|
|
64
|
+
// Wait for peers to be ready in pubsub
|
|
65
|
+
await pWaitFor(() =>
|
|
66
|
+
psA.getPeers().length === 1 &&
|
|
67
|
+
psC.getPeers().length === 1 &&
|
|
68
|
+
psA.getPeers().length === 1
|
|
69
|
+
)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
afterEach(async () => {
|
|
73
|
+
sinon.restore()
|
|
74
|
+
await stop(...Object.values(componentsA), ...Object.values(componentsB), ...Object.values(componentsC))
|
|
75
|
+
await common.teardown()
|
|
76
|
+
mockNetwork.reset()
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it('subscribe to the topic on node a', async () => {
|
|
80
|
+
const topic = 'Z'
|
|
81
|
+
|
|
82
|
+
psA.subscribe(topic)
|
|
83
|
+
expect(psA.getTopics()).to.deep.equal([topic])
|
|
84
|
+
|
|
85
|
+
await waitForSubscriptionUpdate(psB, componentsA.peerId)
|
|
86
|
+
|
|
87
|
+
expect(psB.getPeers().length).to.equal(2)
|
|
88
|
+
expect(psB.getSubscribers(topic).map(p => p.toString())).to.deep.equal([componentsA.peerId.toString()])
|
|
89
|
+
|
|
90
|
+
expect(psC.getPeers().length).to.equal(1)
|
|
91
|
+
expect(psC.getSubscribers(topic)).to.be.empty()
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it('subscribe to the topic on node b', async () => {
|
|
95
|
+
const topic = 'Z'
|
|
96
|
+
psB.subscribe(topic)
|
|
97
|
+
expect(psB.getTopics()).to.deep.equal([topic])
|
|
98
|
+
|
|
99
|
+
await Promise.all([
|
|
100
|
+
waitForSubscriptionUpdate(psA, componentsB.peerId),
|
|
101
|
+
waitForSubscriptionUpdate(psC, componentsB.peerId)
|
|
102
|
+
])
|
|
103
|
+
|
|
104
|
+
expect(psA.getPeers().length).to.equal(1)
|
|
105
|
+
expect(psA.getSubscribers(topic).map(p => p.toString())).to.deep.equal([componentsB.peerId.toString()])
|
|
106
|
+
|
|
107
|
+
expect(psC.getPeers().length).to.equal(1)
|
|
108
|
+
expect(psC.getSubscribers(topic).map(p => p.toString())).to.deep.equal([componentsB.peerId.toString()])
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
it('subscribe to the topic on node c', async () => {
|
|
112
|
+
const topic = 'Z'
|
|
113
|
+
const defer = pDefer()
|
|
114
|
+
|
|
115
|
+
psC.subscribe(topic)
|
|
116
|
+
expect(psC.getTopics()).to.deep.equal([topic])
|
|
117
|
+
|
|
118
|
+
psB.addEventListener('subscription-change', () => {
|
|
119
|
+
expect(psA.getPeers().length).to.equal(1)
|
|
120
|
+
expect(psB.getPeers().length).to.equal(2)
|
|
121
|
+
expect(psB.getSubscribers(topic).map(p => p.toString())).to.deep.equal([componentsC.peerId.toString()])
|
|
122
|
+
|
|
123
|
+
defer.resolve()
|
|
124
|
+
}, {
|
|
125
|
+
once: true
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
return defer.promise
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
it('publish on node a', async () => {
|
|
132
|
+
const topic = 'Z'
|
|
133
|
+
const defer = pDefer()
|
|
134
|
+
|
|
135
|
+
psA.subscribe(topic)
|
|
136
|
+
psB.subscribe(topic)
|
|
137
|
+
psC.subscribe(topic)
|
|
138
|
+
|
|
139
|
+
await Promise.all([
|
|
140
|
+
waitForSubscriptionUpdate(psA, componentsB.peerId),
|
|
141
|
+
waitForSubscriptionUpdate(psB, componentsA.peerId),
|
|
142
|
+
waitForSubscriptionUpdate(psC, componentsB.peerId)
|
|
143
|
+
])
|
|
144
|
+
|
|
145
|
+
// GossipSub needs time to build the mesh overlay
|
|
146
|
+
await delay(1000)
|
|
147
|
+
|
|
148
|
+
let counter = 0
|
|
149
|
+
|
|
150
|
+
psA.addEventListener('message', incMsg)
|
|
151
|
+
psB.addEventListener('message', incMsg)
|
|
152
|
+
psC.addEventListener('message', incMsg)
|
|
153
|
+
|
|
154
|
+
const result = await psA.publish(topic, uint8ArrayFromString('hey'))
|
|
155
|
+
|
|
156
|
+
expect(result).to.have.property('recipients').with.property('length').greaterThanOrEqual(1)
|
|
157
|
+
|
|
158
|
+
function incMsg (evt: CustomEvent<Message>): void {
|
|
159
|
+
const msg = evt.detail
|
|
160
|
+
|
|
161
|
+
if (msg.topic !== topic) {
|
|
162
|
+
return
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
expect(uint8ArrayToString(msg.data)).to.equal('hey')
|
|
166
|
+
check()
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function check (): void {
|
|
170
|
+
if (++counter === 3) {
|
|
171
|
+
psA.removeEventListener('message', incMsg)
|
|
172
|
+
psB.removeEventListener('message', incMsg)
|
|
173
|
+
psC.removeEventListener('message', incMsg)
|
|
174
|
+
defer.resolve()
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return defer.promise
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
// since the topology is the same, just the publish
|
|
182
|
+
// gets sent by other peer, we reused the same peers
|
|
183
|
+
describe('1 level tree', () => {
|
|
184
|
+
// 1 level tree
|
|
185
|
+
// ┌◉┐
|
|
186
|
+
// │b│
|
|
187
|
+
// ◉─┘ └─◉
|
|
188
|
+
// a c
|
|
189
|
+
|
|
190
|
+
it('publish on node b', async () => {
|
|
191
|
+
const topic = 'Z'
|
|
192
|
+
const defer = pDefer()
|
|
193
|
+
let counter = 0
|
|
194
|
+
|
|
195
|
+
psA.subscribe(topic)
|
|
196
|
+
psB.subscribe(topic)
|
|
197
|
+
psC.subscribe(topic)
|
|
198
|
+
|
|
199
|
+
await Promise.all([
|
|
200
|
+
waitForSubscriptionUpdate(psA, componentsB.peerId),
|
|
201
|
+
waitForSubscriptionUpdate(psB, componentsA.peerId),
|
|
202
|
+
waitForSubscriptionUpdate(psC, componentsB.peerId)
|
|
203
|
+
])
|
|
204
|
+
|
|
205
|
+
// GossipSub needs time to build the mesh overlay
|
|
206
|
+
await delay(1000)
|
|
207
|
+
|
|
208
|
+
psA.addEventListener('message', incMsg)
|
|
209
|
+
psB.addEventListener('message', incMsg)
|
|
210
|
+
psC.addEventListener('message', incMsg)
|
|
211
|
+
|
|
212
|
+
await psB.publish(topic, uint8ArrayFromString('hey'))
|
|
213
|
+
|
|
214
|
+
function incMsg (evt: CustomEvent<Message>): void {
|
|
215
|
+
const msg = evt.detail
|
|
216
|
+
|
|
217
|
+
if (msg.topic !== topic) {
|
|
218
|
+
return
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
expect(uint8ArrayToString(msg.data)).to.equal('hey')
|
|
222
|
+
check()
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function check (): void {
|
|
226
|
+
if (++counter === 3) {
|
|
227
|
+
psA.removeEventListener('message', incMsg)
|
|
228
|
+
psB.removeEventListener('message', incMsg)
|
|
229
|
+
psC.removeEventListener('message', incMsg)
|
|
230
|
+
defer.resolve()
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return defer.promise
|
|
235
|
+
})
|
|
236
|
+
})
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
describe('2 level tree', () => {
|
|
240
|
+
// 2 levels tree
|
|
241
|
+
// ┌◉┐
|
|
242
|
+
// │c│
|
|
243
|
+
// ┌◉─┘ └─◉┐
|
|
244
|
+
// │b d│
|
|
245
|
+
// ◉─┘ └─◉
|
|
246
|
+
// a
|
|
247
|
+
let psA: PubSub
|
|
248
|
+
let psB: PubSub
|
|
249
|
+
let psC: PubSub
|
|
250
|
+
let psD: PubSub
|
|
251
|
+
let psE: PubSub
|
|
252
|
+
let componentsA: PubSubComponents
|
|
253
|
+
let componentsB: PubSubComponents
|
|
254
|
+
let componentsC: PubSubComponents
|
|
255
|
+
let componentsD: PubSubComponents
|
|
256
|
+
let componentsE: PubSubComponents
|
|
257
|
+
|
|
258
|
+
// Create and start pubsub nodes
|
|
259
|
+
beforeEach(async () => {
|
|
260
|
+
mockNetwork.reset()
|
|
261
|
+
|
|
262
|
+
componentsA = await createComponents()
|
|
263
|
+
componentsB = await createComponents()
|
|
264
|
+
componentsC = await createComponents()
|
|
265
|
+
componentsD = await createComponents()
|
|
266
|
+
componentsE = await createComponents()
|
|
267
|
+
|
|
268
|
+
psA = componentsA.pubsub = await common.setup({
|
|
269
|
+
components: componentsA,
|
|
270
|
+
init: {
|
|
271
|
+
emitSelf: true
|
|
272
|
+
}
|
|
273
|
+
})
|
|
274
|
+
psB = componentsB.pubsub = await common.setup({
|
|
275
|
+
components: componentsB,
|
|
276
|
+
init: {
|
|
277
|
+
emitSelf: true
|
|
278
|
+
}
|
|
279
|
+
})
|
|
280
|
+
psC = componentsC.pubsub = await common.setup({
|
|
281
|
+
components: componentsC,
|
|
282
|
+
init: {
|
|
283
|
+
emitSelf: true
|
|
284
|
+
}
|
|
285
|
+
})
|
|
286
|
+
psD = componentsD.pubsub = await common.setup({
|
|
287
|
+
components: componentsD,
|
|
288
|
+
init: {
|
|
289
|
+
emitSelf: true
|
|
290
|
+
}
|
|
291
|
+
})
|
|
292
|
+
psE = componentsE.pubsub = await common.setup({
|
|
293
|
+
components: componentsE,
|
|
294
|
+
init: {
|
|
295
|
+
emitSelf: true
|
|
296
|
+
}
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
// Start pubsub nodes
|
|
300
|
+
await start(
|
|
301
|
+
...Object.values(componentsA),
|
|
302
|
+
...Object.values(componentsB),
|
|
303
|
+
...Object.values(componentsC),
|
|
304
|
+
...Object.values(componentsD),
|
|
305
|
+
...Object.values(componentsE)
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
// connect nodes
|
|
309
|
+
await componentsA.connectionManager.openConnection(componentsB.peerId)
|
|
310
|
+
await componentsB.connectionManager.openConnection(componentsC.peerId)
|
|
311
|
+
await componentsC.connectionManager.openConnection(componentsD.peerId)
|
|
312
|
+
await componentsD.connectionManager.openConnection(componentsE.peerId)
|
|
313
|
+
|
|
314
|
+
// Wait for peers to be ready in pubsub
|
|
315
|
+
await pWaitFor(() =>
|
|
316
|
+
psA.getPeers().length === 1 &&
|
|
317
|
+
psB.getPeers().length === 2 &&
|
|
318
|
+
psC.getPeers().length === 2 &&
|
|
319
|
+
psD.getPeers().length === 2 &&
|
|
320
|
+
psE.getPeers().length === 1
|
|
321
|
+
)
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
afterEach(async () => {
|
|
325
|
+
await stop(
|
|
326
|
+
...Object.values(componentsA),
|
|
327
|
+
...Object.values(componentsB),
|
|
328
|
+
...Object.values(componentsC),
|
|
329
|
+
...Object.values(componentsD),
|
|
330
|
+
...Object.values(componentsE)
|
|
331
|
+
)
|
|
332
|
+
await common.teardown()
|
|
333
|
+
mockNetwork.reset()
|
|
334
|
+
})
|
|
335
|
+
|
|
336
|
+
it('subscribes', () => {
|
|
337
|
+
psA.subscribe('Z')
|
|
338
|
+
expect(psA.getTopics()).to.deep.equal(['Z'])
|
|
339
|
+
psB.subscribe('Z')
|
|
340
|
+
expect(psB.getTopics()).to.deep.equal(['Z'])
|
|
341
|
+
psC.subscribe('Z')
|
|
342
|
+
expect(psC.getTopics()).to.deep.equal(['Z'])
|
|
343
|
+
psD.subscribe('Z')
|
|
344
|
+
expect(psD.getTopics()).to.deep.equal(['Z'])
|
|
345
|
+
psE.subscribe('Z')
|
|
346
|
+
expect(psE.getTopics()).to.deep.equal(['Z'])
|
|
347
|
+
})
|
|
348
|
+
|
|
349
|
+
it('publishes from c', async function () {
|
|
350
|
+
const defer = pDefer()
|
|
351
|
+
let counter = 0
|
|
352
|
+
const topic = 'Z'
|
|
353
|
+
|
|
354
|
+
psA.subscribe(topic)
|
|
355
|
+
psA.addEventListener('message', incMsg)
|
|
356
|
+
psB.subscribe(topic)
|
|
357
|
+
psB.addEventListener('message', incMsg)
|
|
358
|
+
psC.subscribe(topic)
|
|
359
|
+
psC.addEventListener('message', incMsg)
|
|
360
|
+
psD.subscribe(topic)
|
|
361
|
+
psD.addEventListener('message', incMsg)
|
|
362
|
+
psE.subscribe(topic)
|
|
363
|
+
psE.addEventListener('message', incMsg)
|
|
364
|
+
|
|
365
|
+
await Promise.all([
|
|
366
|
+
waitForSubscriptionUpdate(psA, componentsB.peerId),
|
|
367
|
+
waitForSubscriptionUpdate(psB, componentsA.peerId),
|
|
368
|
+
waitForSubscriptionUpdate(psC, componentsB.peerId),
|
|
369
|
+
waitForSubscriptionUpdate(psD, componentsC.peerId),
|
|
370
|
+
waitForSubscriptionUpdate(psE, componentsD.peerId)
|
|
371
|
+
])
|
|
372
|
+
|
|
373
|
+
// GossipSub needs time to build the mesh overlay
|
|
374
|
+
await delay(1000)
|
|
375
|
+
|
|
376
|
+
await psC.publish('Z', uint8ArrayFromString('hey from c'))
|
|
377
|
+
|
|
378
|
+
function incMsg (evt: CustomEvent<Message>): void {
|
|
379
|
+
const msg = evt.detail
|
|
380
|
+
|
|
381
|
+
if (msg.topic !== topic) {
|
|
382
|
+
return
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
expect(uint8ArrayToString(msg.data)).to.equal('hey from c')
|
|
386
|
+
check()
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function check (): void {
|
|
390
|
+
if (++counter === 5) {
|
|
391
|
+
psA.unsubscribe('Z')
|
|
392
|
+
psB.unsubscribe('Z')
|
|
393
|
+
psC.unsubscribe('Z')
|
|
394
|
+
psD.unsubscribe('Z')
|
|
395
|
+
psE.unsubscribe('Z')
|
|
396
|
+
defer.resolve()
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
return defer.promise
|
|
401
|
+
})
|
|
402
|
+
})
|
|
403
|
+
})
|
|
404
|
+
|
|
405
|
+
describe('only some nodes subscribe the networks', () => {
|
|
406
|
+
describe('line', () => {
|
|
407
|
+
// line
|
|
408
|
+
// ◉────◎────◉
|
|
409
|
+
// a b c
|
|
410
|
+
|
|
411
|
+
before(() => { })
|
|
412
|
+
after(() => { })
|
|
413
|
+
})
|
|
414
|
+
|
|
415
|
+
describe('1 level tree', () => {
|
|
416
|
+
// 1 level tree
|
|
417
|
+
// ┌◉┐
|
|
418
|
+
// │b│
|
|
419
|
+
// ◎─┘ └─◉
|
|
420
|
+
// a c
|
|
421
|
+
|
|
422
|
+
before(() => { })
|
|
423
|
+
after(() => { })
|
|
424
|
+
})
|
|
425
|
+
|
|
426
|
+
describe('2 level tree', () => {
|
|
427
|
+
// 2 levels tree
|
|
428
|
+
// ┌◉┐
|
|
429
|
+
// │c│
|
|
430
|
+
// ┌◎─┘ └─◉┐
|
|
431
|
+
// │b d│
|
|
432
|
+
// ◉─┘ └─◎
|
|
433
|
+
// a e
|
|
434
|
+
|
|
435
|
+
before(() => { })
|
|
436
|
+
after(() => { })
|
|
437
|
+
})
|
|
438
|
+
})
|
|
439
|
+
})
|
|
440
|
+
}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/* eslint max-nested-callbacks: ["error", 6] */
|
|
2
|
+
import { TopicValidatorResult } from '@libp2p/interface/pubsub'
|
|
3
|
+
import { start, stop } from '@libp2p/interface/startable'
|
|
4
|
+
import { expect } from 'aegir/chai'
|
|
5
|
+
import pDefer from 'p-defer'
|
|
6
|
+
import pWaitFor from 'p-wait-for'
|
|
7
|
+
import sinon from 'sinon'
|
|
8
|
+
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
|
|
9
|
+
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
|
|
10
|
+
import { mockNetwork } from '../mocks/index.js'
|
|
11
|
+
import { createComponents, waitForSubscriptionUpdate } from './utils.js'
|
|
12
|
+
import type { PubSubArgs, PubSubComponents } from './index.js'
|
|
13
|
+
import type { TestSetup } from '../index.js'
|
|
14
|
+
import type { Message, PubSub } from '@libp2p/interface/pubsub'
|
|
15
|
+
|
|
16
|
+
const topic = 'foo'
|
|
17
|
+
|
|
18
|
+
function shouldNotHappen (): void {
|
|
19
|
+
expect.fail()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default (common: TestSetup<PubSub, PubSubArgs>): void => {
|
|
23
|
+
describe('pubsub with two nodes', () => {
|
|
24
|
+
let psA: PubSub
|
|
25
|
+
let psB: PubSub
|
|
26
|
+
let componentsA: PubSubComponents
|
|
27
|
+
let componentsB: PubSubComponents
|
|
28
|
+
|
|
29
|
+
// Create pubsub nodes and connect them
|
|
30
|
+
beforeEach(async () => {
|
|
31
|
+
mockNetwork.reset()
|
|
32
|
+
|
|
33
|
+
componentsA = await createComponents()
|
|
34
|
+
componentsB = await createComponents()
|
|
35
|
+
|
|
36
|
+
psA = componentsA.pubsub = await common.setup({
|
|
37
|
+
components: componentsA,
|
|
38
|
+
init: {
|
|
39
|
+
emitSelf: true
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
psB = componentsB.pubsub = await common.setup({
|
|
43
|
+
components: componentsB,
|
|
44
|
+
init: {
|
|
45
|
+
emitSelf: false
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
// Start pubsub and connect nodes
|
|
50
|
+
await start(...Object.values(componentsA), ...Object.values(componentsB))
|
|
51
|
+
|
|
52
|
+
expect(psA.getPeers()).to.be.empty()
|
|
53
|
+
expect(psB.getPeers()).to.be.empty()
|
|
54
|
+
|
|
55
|
+
await componentsA.connectionManager.openConnection(componentsB.peerId)
|
|
56
|
+
|
|
57
|
+
// Wait for peers to be ready in pubsub
|
|
58
|
+
await pWaitFor(() => psA.getPeers().length === 1 && psB.getPeers().length === 1)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
afterEach(async () => {
|
|
62
|
+
sinon.restore()
|
|
63
|
+
await stop(...Object.values(componentsA), ...Object.values(componentsB))
|
|
64
|
+
await common.teardown()
|
|
65
|
+
mockNetwork.reset()
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('Subscribe to a topic in nodeA', async () => {
|
|
69
|
+
const defer = pDefer()
|
|
70
|
+
|
|
71
|
+
psB.addEventListener('subscription-change', (evt) => {
|
|
72
|
+
const { peerId: changedPeerId, subscriptions: changedSubs } = evt.detail
|
|
73
|
+
expect(psA.getTopics()).to.deep.equal([topic])
|
|
74
|
+
expect(psB.getPeers()).to.have.lengthOf(1)
|
|
75
|
+
expect(psB.getSubscribers(topic).map(p => p.toString())).to.deep.equal([componentsA.peerId.toString()])
|
|
76
|
+
expect(changedPeerId).to.deep.equal(psB.getPeers()[0])
|
|
77
|
+
expect(changedSubs).to.have.lengthOf(1)
|
|
78
|
+
expect(changedSubs[0].topic).to.equal(topic)
|
|
79
|
+
expect(changedSubs[0].subscribe).to.equal(true)
|
|
80
|
+
defer.resolve()
|
|
81
|
+
}, {
|
|
82
|
+
once: true
|
|
83
|
+
})
|
|
84
|
+
psA.subscribe(topic)
|
|
85
|
+
|
|
86
|
+
return defer.promise
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('Publish to a topic in nodeA', async () => {
|
|
90
|
+
const defer = pDefer()
|
|
91
|
+
|
|
92
|
+
psA.addEventListener('message', (evt) => {
|
|
93
|
+
if (evt.detail.topic === topic) {
|
|
94
|
+
const msg = evt.detail
|
|
95
|
+
expect(uint8ArrayToString(msg.data)).to.equal('hey')
|
|
96
|
+
psB.removeEventListener('message', shouldNotHappen)
|
|
97
|
+
defer.resolve()
|
|
98
|
+
}
|
|
99
|
+
}, {
|
|
100
|
+
once: true
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
psA.subscribe(topic)
|
|
104
|
+
psB.subscribe(topic)
|
|
105
|
+
|
|
106
|
+
await Promise.all([
|
|
107
|
+
waitForSubscriptionUpdate(psA, componentsB.peerId),
|
|
108
|
+
waitForSubscriptionUpdate(psB, componentsA.peerId)
|
|
109
|
+
])
|
|
110
|
+
|
|
111
|
+
await psA.publish(topic, uint8ArrayFromString('hey'))
|
|
112
|
+
|
|
113
|
+
return defer.promise
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
it('Publish to a topic in nodeB', async () => {
|
|
117
|
+
const defer = pDefer()
|
|
118
|
+
|
|
119
|
+
psA.addEventListener('message', (evt) => {
|
|
120
|
+
if (evt.detail.topic !== topic) {
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const msg = evt.detail
|
|
125
|
+
psA.addEventListener('message', (evt) => {
|
|
126
|
+
if (evt.detail.topic === topic) {
|
|
127
|
+
shouldNotHappen()
|
|
128
|
+
}
|
|
129
|
+
}, {
|
|
130
|
+
once: true
|
|
131
|
+
})
|
|
132
|
+
expect(uint8ArrayToString(msg.data)).to.equal('banana')
|
|
133
|
+
|
|
134
|
+
setTimeout(() => {
|
|
135
|
+
psA.removeEventListener('message')
|
|
136
|
+
psB.removeEventListener('message')
|
|
137
|
+
|
|
138
|
+
defer.resolve()
|
|
139
|
+
}, 100)
|
|
140
|
+
}, {
|
|
141
|
+
once: true
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
psB.addEventListener('message', shouldNotHappen)
|
|
145
|
+
|
|
146
|
+
psA.subscribe(topic)
|
|
147
|
+
psB.subscribe(topic)
|
|
148
|
+
|
|
149
|
+
await Promise.all([
|
|
150
|
+
waitForSubscriptionUpdate(psA, componentsB.peerId),
|
|
151
|
+
waitForSubscriptionUpdate(psB, componentsA.peerId)
|
|
152
|
+
])
|
|
153
|
+
|
|
154
|
+
await psB.publish(topic, uint8ArrayFromString('banana'))
|
|
155
|
+
|
|
156
|
+
return defer.promise
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it('validate topic message', async () => {
|
|
160
|
+
const defer = pDefer()
|
|
161
|
+
|
|
162
|
+
psA.subscribe(topic)
|
|
163
|
+
|
|
164
|
+
psB.topicValidators.set(topic, (peer, message) => {
|
|
165
|
+
if (!peer.equals(componentsA.peerId)) {
|
|
166
|
+
defer.reject(new Error('Invalid peer id in topic validator fn'))
|
|
167
|
+
return TopicValidatorResult.Reject
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (uint8ArrayToString(message.data) !== 'hey') {
|
|
171
|
+
defer.reject(new Error('Invalid message in topic validator fn'))
|
|
172
|
+
return TopicValidatorResult.Reject
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
defer.resolve()
|
|
176
|
+
return TopicValidatorResult.Accept
|
|
177
|
+
})
|
|
178
|
+
psB.subscribe(topic)
|
|
179
|
+
|
|
180
|
+
await Promise.all([
|
|
181
|
+
waitForSubscriptionUpdate(psA, componentsB.peerId),
|
|
182
|
+
waitForSubscriptionUpdate(psB, componentsA.peerId)
|
|
183
|
+
])
|
|
184
|
+
|
|
185
|
+
await psA.publish(topic, uint8ArrayFromString('hey'))
|
|
186
|
+
|
|
187
|
+
return defer.promise
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
it('Publish 10 msg to a topic in nodeB', async () => {
|
|
191
|
+
const defer = pDefer()
|
|
192
|
+
let counter = 0
|
|
193
|
+
|
|
194
|
+
psB.addEventListener('message', shouldNotHappen)
|
|
195
|
+
psA.addEventListener('message', receivedMsg)
|
|
196
|
+
|
|
197
|
+
function receivedMsg (evt: CustomEvent<Message>): void {
|
|
198
|
+
const msg = evt.detail
|
|
199
|
+
if (msg.type === 'unsigned') {
|
|
200
|
+
expect(uint8ArrayToString(msg.data)).to.equal('banana')
|
|
201
|
+
expect(msg.topic).to.be.equal(topic)
|
|
202
|
+
} else {
|
|
203
|
+
expect(uint8ArrayToString(msg.data)).to.equal('banana')
|
|
204
|
+
expect(msg.from.toString()).to.equal(componentsB.peerId.toString())
|
|
205
|
+
expect(msg.sequenceNumber).to.be.a('BigInt')
|
|
206
|
+
expect(msg.topic).to.be.equal(topic)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (++counter === 10) {
|
|
210
|
+
psA.removeEventListener('message', receivedMsg)
|
|
211
|
+
psB.removeEventListener('message', shouldNotHappen)
|
|
212
|
+
|
|
213
|
+
defer.resolve()
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
psA.subscribe(topic)
|
|
218
|
+
psB.subscribe(topic)
|
|
219
|
+
|
|
220
|
+
await Promise.all([
|
|
221
|
+
waitForSubscriptionUpdate(psA, componentsB.peerId),
|
|
222
|
+
waitForSubscriptionUpdate(psB, componentsA.peerId)
|
|
223
|
+
])
|
|
224
|
+
|
|
225
|
+
await Promise.all(
|
|
226
|
+
Array.from({ length: 10 }, async (_, i) => {
|
|
227
|
+
await psB.publish(topic, uint8ArrayFromString('banana'))
|
|
228
|
+
})
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
return defer.promise
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
it('Unsubscribe from topic in nodeA', async () => {
|
|
235
|
+
const defer = pDefer()
|
|
236
|
+
let callCount = 0
|
|
237
|
+
|
|
238
|
+
psB.addEventListener('subscription-change', (evt) => {
|
|
239
|
+
callCount++
|
|
240
|
+
|
|
241
|
+
if (callCount === 1) {
|
|
242
|
+
// notice subscribe
|
|
243
|
+
const { peerId: changedPeerId, subscriptions: changedSubs } = evt.detail
|
|
244
|
+
expect(psB.getPeers()).to.have.lengthOf(1)
|
|
245
|
+
expect(psB.getTopics()).to.be.empty()
|
|
246
|
+
expect(changedPeerId).to.deep.equal(psB.getPeers()[0])
|
|
247
|
+
expect(changedSubs).to.have.lengthOf(1)
|
|
248
|
+
expect(changedSubs[0].topic).to.equal(topic)
|
|
249
|
+
expect(changedSubs[0].subscribe).to.equal(true)
|
|
250
|
+
} else {
|
|
251
|
+
// notice unsubscribe
|
|
252
|
+
const { peerId: changedPeerId, subscriptions: changedSubs } = evt.detail
|
|
253
|
+
expect(psB.getPeers()).to.have.lengthOf(1)
|
|
254
|
+
expect(psB.getTopics()).to.be.empty()
|
|
255
|
+
expect(changedPeerId).to.deep.equal(psB.getPeers()[0])
|
|
256
|
+
expect(changedSubs).to.have.lengthOf(1)
|
|
257
|
+
expect(changedSubs[0].topic).to.equal(topic)
|
|
258
|
+
expect(changedSubs[0].subscribe).to.equal(false)
|
|
259
|
+
|
|
260
|
+
defer.resolve()
|
|
261
|
+
}
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
psA.subscribe(topic)
|
|
265
|
+
expect(psA.getTopics()).to.not.be.empty()
|
|
266
|
+
|
|
267
|
+
psA.unsubscribe(topic)
|
|
268
|
+
expect(psA.getTopics()).to.be.empty()
|
|
269
|
+
|
|
270
|
+
return defer.promise
|
|
271
|
+
})
|
|
272
|
+
})
|
|
273
|
+
}
|