@libp2p/interface-compliance-tests 3.0.7 → 4.0.0

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.
Files changed (184) hide show
  1. package/README.md +12 -3
  2. package/dist/src/connection/index.d.ts +5 -0
  3. package/dist/src/connection/index.d.ts.map +1 -0
  4. package/dist/src/connection/index.js +150 -0
  5. package/dist/src/connection/index.js.map +1 -0
  6. package/dist/src/connection-encryption/index.d.ts +5 -0
  7. package/dist/src/connection-encryption/index.d.ts.map +1 -0
  8. package/dist/src/connection-encryption/index.js +71 -0
  9. package/dist/src/connection-encryption/index.js.map +1 -0
  10. package/dist/src/connection-encryption/utils/index.d.ts +3 -0
  11. package/dist/src/connection-encryption/utils/index.d.ts.map +1 -0
  12. package/dist/src/connection-encryption/utils/index.js +19 -0
  13. package/dist/src/connection-encryption/utils/index.js.map +1 -0
  14. package/dist/src/index.d.ts.map +1 -1
  15. package/dist/src/is-valid-tick.d.ts.map +1 -1
  16. package/dist/src/is-valid-tick.js.map +1 -1
  17. package/dist/src/mocks/connection-encrypter.d.ts +3 -0
  18. package/dist/src/mocks/connection-encrypter.d.ts.map +1 -0
  19. package/dist/src/mocks/connection-encrypter.js +98 -0
  20. package/dist/src/mocks/connection-encrypter.js.map +1 -0
  21. package/dist/src/mocks/connection-gater.d.ts +3 -0
  22. package/dist/src/mocks/connection-gater.d.ts.map +1 -0
  23. package/dist/src/mocks/connection-gater.js +17 -0
  24. package/dist/src/mocks/connection-gater.js.map +1 -0
  25. package/dist/src/mocks/connection-manager.d.ts +29 -0
  26. package/dist/src/mocks/connection-manager.d.ts.map +1 -0
  27. package/dist/src/mocks/connection-manager.js +145 -0
  28. package/dist/src/mocks/connection-manager.js.map +1 -0
  29. package/dist/src/mocks/connection.d.ts +32 -0
  30. package/dist/src/mocks/connection.d.ts.map +1 -0
  31. package/dist/src/mocks/connection.js +167 -0
  32. package/dist/src/mocks/connection.js.map +1 -0
  33. package/dist/src/mocks/duplex.d.ts +3 -0
  34. package/dist/src/mocks/duplex.d.ts.map +1 -0
  35. package/dist/src/mocks/duplex.js +9 -0
  36. package/dist/src/mocks/duplex.js.map +1 -0
  37. package/dist/src/mocks/index.d.ts +13 -0
  38. package/dist/src/mocks/index.d.ts.map +1 -0
  39. package/dist/src/mocks/index.js +11 -0
  40. package/dist/src/mocks/index.js.map +1 -0
  41. package/dist/src/mocks/metrics.d.ts +3 -0
  42. package/dist/src/mocks/metrics.d.ts.map +1 -0
  43. package/dist/src/mocks/metrics.js +115 -0
  44. package/dist/src/mocks/metrics.js.map +1 -0
  45. package/dist/src/mocks/multiaddr-connection.d.ts +17 -0
  46. package/dist/src/mocks/multiaddr-connection.d.ts.map +1 -0
  47. package/dist/src/mocks/multiaddr-connection.js +60 -0
  48. package/dist/src/mocks/multiaddr-connection.js.map +1 -0
  49. package/dist/src/mocks/muxer.d.ts +36 -0
  50. package/dist/src/mocks/muxer.d.ts.map +1 -0
  51. package/dist/src/mocks/muxer.js +213 -0
  52. package/dist/src/mocks/muxer.js.map +1 -0
  53. package/dist/src/mocks/peer-discovery.d.ts +22 -0
  54. package/dist/src/mocks/peer-discovery.d.ts.map +1 -0
  55. package/dist/src/mocks/peer-discovery.js +47 -0
  56. package/dist/src/mocks/peer-discovery.js.map +1 -0
  57. package/dist/src/mocks/registrar.d.ts +18 -0
  58. package/dist/src/mocks/registrar.d.ts.map +1 -0
  59. package/dist/src/mocks/registrar.js +66 -0
  60. package/dist/src/mocks/registrar.js.map +1 -0
  61. package/dist/src/mocks/upgrader.d.ts +10 -0
  62. package/dist/src/mocks/upgrader.d.ts.map +1 -0
  63. package/dist/src/mocks/upgrader.js +31 -0
  64. package/dist/src/mocks/upgrader.js.map +1 -0
  65. package/dist/src/peer-discovery/index.d.ts +5 -0
  66. package/dist/src/peer-discovery/index.d.ts.map +1 -0
  67. package/dist/src/peer-discovery/index.js +66 -0
  68. package/dist/src/peer-discovery/index.js.map +1 -0
  69. package/dist/src/pubsub/api.d.ts +6 -0
  70. package/dist/src/pubsub/api.d.ts.map +1 -0
  71. package/dist/src/pubsub/api.js +87 -0
  72. package/dist/src/pubsub/api.js.map +1 -0
  73. package/dist/src/pubsub/connection-handlers.d.ts +6 -0
  74. package/dist/src/pubsub/connection-handlers.d.ts.map +1 -0
  75. package/dist/src/pubsub/connection-handlers.js +329 -0
  76. package/dist/src/pubsub/connection-handlers.js.map +1 -0
  77. package/dist/src/pubsub/emit-self.d.ts +6 -0
  78. package/dist/src/pubsub/emit-self.d.ts.map +1 -0
  79. package/dist/src/pubsub/emit-self.js +80 -0
  80. package/dist/src/pubsub/emit-self.js.map +1 -0
  81. package/dist/src/pubsub/index.d.ts +18 -0
  82. package/dist/src/pubsub/index.d.ts.map +1 -0
  83. package/dist/src/pubsub/index.js +17 -0
  84. package/dist/src/pubsub/index.js.map +1 -0
  85. package/dist/src/pubsub/messages.d.ts +6 -0
  86. package/dist/src/pubsub/messages.d.ts.map +1 -0
  87. package/dist/src/pubsub/messages.js +48 -0
  88. package/dist/src/pubsub/messages.js.map +1 -0
  89. package/dist/src/pubsub/multiple-nodes.d.ts +6 -0
  90. package/dist/src/pubsub/multiple-nodes.d.ts.map +1 -0
  91. package/dist/src/pubsub/multiple-nodes.js +350 -0
  92. package/dist/src/pubsub/multiple-nodes.js.map +1 -0
  93. package/dist/src/pubsub/two-nodes.d.ts +6 -0
  94. package/dist/src/pubsub/two-nodes.d.ts.map +1 -0
  95. package/dist/src/pubsub/two-nodes.js +217 -0
  96. package/dist/src/pubsub/two-nodes.js.map +1 -0
  97. package/dist/src/pubsub/utils.d.ts +6 -0
  98. package/dist/src/pubsub/utils.d.ts.map +1 -0
  99. package/dist/src/pubsub/utils.js +22 -0
  100. package/dist/src/pubsub/utils.js.map +1 -0
  101. package/dist/src/stream-muxer/base-test.d.ts +5 -0
  102. package/dist/src/stream-muxer/base-test.d.ts.map +1 -0
  103. package/dist/src/stream-muxer/base-test.js +153 -0
  104. package/dist/src/stream-muxer/base-test.js.map +1 -0
  105. package/dist/src/stream-muxer/close-test.d.ts +5 -0
  106. package/dist/src/stream-muxer/close-test.d.ts.map +1 -0
  107. package/dist/src/stream-muxer/close-test.js +357 -0
  108. package/dist/src/stream-muxer/close-test.js.map +1 -0
  109. package/dist/src/stream-muxer/fixtures/pb/message.d.ts +13 -0
  110. package/dist/src/stream-muxer/fixtures/pb/message.d.ts.map +1 -0
  111. package/dist/src/stream-muxer/fixtures/pb/message.js +67 -0
  112. package/dist/src/stream-muxer/fixtures/pb/message.js.map +1 -0
  113. package/dist/src/stream-muxer/index.d.ts +5 -0
  114. package/dist/src/stream-muxer/index.d.ts.map +1 -0
  115. package/dist/src/stream-muxer/index.js +13 -0
  116. package/dist/src/stream-muxer/index.js.map +1 -0
  117. package/dist/src/stream-muxer/mega-stress-test.d.ts +5 -0
  118. package/dist/src/stream-muxer/mega-stress-test.d.ts.map +1 -0
  119. package/dist/src/stream-muxer/mega-stress-test.js +11 -0
  120. package/dist/src/stream-muxer/mega-stress-test.js.map +1 -0
  121. package/dist/src/stream-muxer/spawner.d.ts +4 -0
  122. package/dist/src/stream-muxer/spawner.d.ts.map +1 -0
  123. package/dist/src/stream-muxer/spawner.js +37 -0
  124. package/dist/src/stream-muxer/spawner.js.map +1 -0
  125. package/dist/src/stream-muxer/stress-test.d.ts +5 -0
  126. package/dist/src/stream-muxer/stress-test.d.ts.map +1 -0
  127. package/dist/src/stream-muxer/stress-test.js +23 -0
  128. package/dist/src/stream-muxer/stress-test.js.map +1 -0
  129. package/dist/src/transport/dial-test.d.ts +5 -0
  130. package/dist/src/transport/dial-test.d.ts.map +1 -0
  131. package/dist/src/transport/dial-test.js +98 -0
  132. package/dist/src/transport/dial-test.js.map +1 -0
  133. package/dist/src/transport/filter-test.d.ts +5 -0
  134. package/dist/src/transport/filter-test.d.ts.map +1 -0
  135. package/dist/src/transport/filter-test.js +18 -0
  136. package/dist/src/transport/filter-test.js.map +1 -0
  137. package/dist/src/transport/index.d.ts +15 -0
  138. package/dist/src/transport/index.d.ts.map +1 -0
  139. package/dist/src/transport/index.js +11 -0
  140. package/dist/src/transport/index.js.map +1 -0
  141. package/dist/src/transport/listen-test.d.ts +5 -0
  142. package/dist/src/transport/listen-test.d.ts.map +1 -0
  143. package/dist/src/transport/listen-test.js +152 -0
  144. package/dist/src/transport/listen-test.js.map +1 -0
  145. package/package.json +74 -97
  146. package/src/connection/index.ts +182 -0
  147. package/src/connection-encryption/index.ts +97 -0
  148. package/src/connection-encryption/utils/index.ts +24 -0
  149. package/src/index.ts +0 -1
  150. package/src/is-valid-tick.ts +0 -1
  151. package/src/mocks/connection-encrypter.ts +113 -0
  152. package/src/mocks/connection-gater.ts +18 -0
  153. package/src/mocks/connection-manager.ts +211 -0
  154. package/src/mocks/connection.ts +226 -0
  155. package/src/mocks/duplex.ts +10 -0
  156. package/src/mocks/index.ts +12 -0
  157. package/src/mocks/metrics.ts +162 -0
  158. package/src/mocks/multiaddr-connection.ts +76 -0
  159. package/src/mocks/muxer.ts +303 -0
  160. package/src/mocks/peer-discovery.ts +60 -0
  161. package/src/mocks/registrar.ts +88 -0
  162. package/src/mocks/upgrader.ts +49 -0
  163. package/src/peer-discovery/index.ts +90 -0
  164. package/src/pubsub/api.ts +114 -0
  165. package/src/pubsub/connection-handlers.ts +413 -0
  166. package/src/pubsub/emit-self.ts +99 -0
  167. package/src/pubsub/index.ts +34 -0
  168. package/src/pubsub/messages.ts +59 -0
  169. package/src/pubsub/multiple-nodes.ts +440 -0
  170. package/src/pubsub/two-nodes.ts +273 -0
  171. package/src/pubsub/utils.ts +29 -0
  172. package/src/stream-muxer/base-test.ts +196 -0
  173. package/src/stream-muxer/close-test.ts +442 -0
  174. package/src/stream-muxer/fixtures/pb/message.proto +7 -0
  175. package/src/stream-muxer/fixtures/pb/message.ts +87 -0
  176. package/src/stream-muxer/index.ts +15 -0
  177. package/src/stream-muxer/mega-stress-test.ts +14 -0
  178. package/src/stream-muxer/spawner.ts +55 -0
  179. package/src/stream-muxer/stress-test.ts +27 -0
  180. package/src/transport/dial-test.ts +124 -0
  181. package/src/transport/filter-test.ts +25 -0
  182. package/src/transport/index.ts +25 -0
  183. package/src/transport/listen-test.ts +191 -0
  184. 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
+ }