@libp2p/interface-compliance-tests 3.0.7-ea8a0637 → 3.0.7-eabf6f36

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 (183) hide show
  1. package/README.md +9 -0
  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 +72 -5
  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
@@ -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
+ }
@@ -0,0 +1,29 @@
1
+ import { EventEmitter } from '@libp2p/interface/events'
2
+ import { createEd25519PeerId } from '@libp2p/peer-id-factory'
3
+ import { pEvent } from 'p-event'
4
+ import pWaitFor from 'p-wait-for'
5
+ import { mockConnectionManager, mockRegistrar, mockNetwork } from '../mocks/index.js'
6
+ import type { MockNetworkComponents } from '../mocks/index.js'
7
+ import type { PeerId } from '@libp2p/interface/peer-id'
8
+ import type { PubSub, SubscriptionChangeData } from '@libp2p/interface/pubsub'
9
+
10
+ export async function waitForSubscriptionUpdate (a: PubSub, b: PeerId): Promise<void> {
11
+ await pWaitFor(async () => {
12
+ const event = await pEvent<'subscription-change', CustomEvent<SubscriptionChangeData>>(a, 'subscription-change')
13
+
14
+ return event.detail.peerId.equals(b)
15
+ })
16
+ }
17
+
18
+ export async function createComponents (): Promise<MockNetworkComponents> {
19
+ const components: any = {
20
+ peerId: await createEd25519PeerId(),
21
+ registrar: mockRegistrar(),
22
+ events: new EventEmitter()
23
+ }
24
+ components.connectionManager = mockConnectionManager(components)
25
+
26
+ mockNetwork.addNode(components)
27
+
28
+ return components
29
+ }
@@ -0,0 +1,196 @@
1
+ import { expect } from 'aegir/chai'
2
+ import all from 'it-all'
3
+ import drain from 'it-drain'
4
+ import map from 'it-map'
5
+ import { duplexPair } from 'it-pair/duplex'
6
+ import { pipe } from 'it-pipe'
7
+ import defer from 'p-defer'
8
+ import { Uint8ArrayList } from 'uint8arraylist'
9
+ import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
10
+ import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
11
+ import { isValidTick } from '../is-valid-tick.js'
12
+ import type { TestSetup } from '../index.js'
13
+ import type { Stream } from '@libp2p/interface/connection'
14
+ import type { StreamMuxerFactory } from '@libp2p/interface/stream-muxer'
15
+ import type { Source, Duplex } from 'it-stream-types'
16
+ import type { DeferredPromise } from 'p-defer'
17
+
18
+ async function drainAndClose (stream: Duplex<any>): Promise<void> {
19
+ await pipe([], stream, drain)
20
+ }
21
+
22
+ export default (common: TestSetup<StreamMuxerFactory>): void => {
23
+ describe('base', () => {
24
+ it('Open a stream from the dialer', async () => {
25
+ const p = duplexPair<Uint8Array>()
26
+ const dialerFactory = await common.setup()
27
+ const dialer = dialerFactory.createStreamMuxer({ direction: 'outbound' })
28
+ const onStreamPromise: DeferredPromise<Stream> = defer()
29
+ const onStreamEndPromise: DeferredPromise<Stream> = defer()
30
+
31
+ const listenerFactory = await common.setup()
32
+ const listener = listenerFactory.createStreamMuxer({
33
+ direction: 'inbound',
34
+ onIncomingStream: (stream) => {
35
+ onStreamPromise.resolve(stream)
36
+ },
37
+ onStreamEnd: (stream) => {
38
+ onStreamEndPromise.resolve(stream)
39
+ }
40
+ })
41
+
42
+ void pipe(p[0], dialer, p[0])
43
+ void pipe(p[1], listener, p[1])
44
+
45
+ const conn = await dialer.newStream()
46
+ expect(dialer.streams).to.include(conn)
47
+ expect(isValidTick(conn.timeline.open)).to.equal(true)
48
+
49
+ void drainAndClose(conn)
50
+
51
+ const stream = await onStreamPromise.promise
52
+ expect(isValidTick(stream.timeline.open)).to.equal(true)
53
+ // Make sure the stream is being tracked
54
+ expect(listener.streams).to.include(stream)
55
+
56
+ void drainAndClose(stream)
57
+
58
+ // Make sure stream is closed properly
59
+ const endedStream = await onStreamEndPromise.promise
60
+ expect(listener.streams).to.not.include(endedStream)
61
+
62
+ if (endedStream.timeline.close == null) {
63
+ throw new Error('timeline had no close time')
64
+ }
65
+
66
+ // Make sure the stream is removed from tracking
67
+ expect(isValidTick(endedStream.timeline.close)).to.equal(true)
68
+
69
+ await drainAndClose(dialer)
70
+ await drainAndClose(listener)
71
+
72
+ // ensure we have no streams left
73
+ expect(dialer.streams).to.have.length(0)
74
+ expect(listener.streams).to.have.length(0)
75
+ })
76
+
77
+ it('Open a stream from the listener', async () => {
78
+ const p = duplexPair<Uint8Array>()
79
+ const onStreamPromise: DeferredPromise<Stream> = defer()
80
+ const dialerFactory = await common.setup()
81
+ const dialer = dialerFactory.createStreamMuxer({
82
+ direction: 'outbound',
83
+ onIncomingStream: (stream: Stream) => {
84
+ onStreamPromise.resolve(stream)
85
+ }
86
+ })
87
+
88
+ const listenerFactory = await common.setup()
89
+ const listener = listenerFactory.createStreamMuxer({ direction: 'inbound' })
90
+
91
+ void pipe(p[0], dialer, p[0])
92
+ void pipe(p[1], listener, p[1])
93
+
94
+ const conn = await listener.newStream()
95
+
96
+ void drainAndClose(conn)
97
+
98
+ const stream = await onStreamPromise.promise
99
+ expect(isValidTick(stream.timeline.open)).to.equal(true)
100
+ expect(listener.streams).to.include(conn)
101
+ expect(isValidTick(conn.timeline.open)).to.equal(true)
102
+ void drainAndClose(stream)
103
+
104
+ await drainAndClose(dialer)
105
+ await drainAndClose(listener)
106
+ })
107
+
108
+ it('Open a stream on both sides', async () => {
109
+ const p = duplexPair<Uint8Array>()
110
+ const onDialerStreamPromise: DeferredPromise<Stream> = defer()
111
+ const onListenerStreamPromise: DeferredPromise<Stream> = defer()
112
+ const dialerFactory = await common.setup()
113
+ const dialer = dialerFactory.createStreamMuxer({
114
+ direction: 'outbound',
115
+ onIncomingStream: (stream) => {
116
+ onDialerStreamPromise.resolve(stream)
117
+ }
118
+ })
119
+
120
+ const listenerFactory = await common.setup()
121
+ const listener = listenerFactory.createStreamMuxer({
122
+ direction: 'inbound',
123
+ onIncomingStream: (stream) => {
124
+ onListenerStreamPromise.resolve(stream)
125
+ }
126
+ })
127
+
128
+ void pipe(p[0], dialer, p[0])
129
+ void pipe(p[1], listener, p[1])
130
+
131
+ const dialerInitiatorStream = await dialer.newStream()
132
+ const listenerInitiatorStream = await listener.newStream()
133
+
134
+ await Promise.all([
135
+ drainAndClose(dialerInitiatorStream),
136
+ drainAndClose(listenerInitiatorStream),
137
+ onDialerStreamPromise.promise.then(async stream => { await drainAndClose(stream) }),
138
+ onListenerStreamPromise.promise.then(async stream => { await drainAndClose(stream) })
139
+ ])
140
+
141
+ await Promise.all([
142
+ drainAndClose(dialer),
143
+ drainAndClose(listener)
144
+ ])
145
+ })
146
+
147
+ it('Open a stream on one side, write, open a stream on the other side', async () => {
148
+ const toString = (source: Source<Uint8ArrayList>): AsyncGenerator<string> => map(source, (u) => uint8ArrayToString(u.subarray()))
149
+ const p = duplexPair<Uint8Array>()
150
+ const onDialerStreamPromise: DeferredPromise<Stream> = defer()
151
+ const onListenerStreamPromise: DeferredPromise<Stream> = defer()
152
+ const dialerFactory = await common.setup()
153
+ const dialer = dialerFactory.createStreamMuxer({
154
+ direction: 'outbound',
155
+ onIncomingStream: (stream) => {
156
+ onDialerStreamPromise.resolve(stream)
157
+ }
158
+ })
159
+ const listenerFactory = await common.setup()
160
+ const listener = listenerFactory.createStreamMuxer({
161
+ direction: 'inbound',
162
+ onIncomingStream: (stream) => {
163
+ onListenerStreamPromise.resolve(stream)
164
+ }
165
+ })
166
+
167
+ void pipe(p[0], dialer, p[0])
168
+ void pipe(p[1], listener, p[1])
169
+
170
+ const dialerConn = await dialer.newStream()
171
+ const listenerConn = await listener.newStream()
172
+
173
+ void pipe([new Uint8ArrayList(uint8ArrayFromString('hey'))], dialerConn)
174
+ void pipe([new Uint8ArrayList(uint8ArrayFromString('hello'))], listenerConn)
175
+
176
+ const [
177
+ dialerStream,
178
+ listenerStream
179
+ ] = await Promise.all([
180
+ onDialerStreamPromise.promise,
181
+ onListenerStreamPromise.promise
182
+ ])
183
+
184
+ const [
185
+ listenerChunks,
186
+ dialerChunks
187
+ ] = await Promise.all([
188
+ pipe(listenerStream, toString, async (source) => all(source)),
189
+ pipe(dialerStream, toString, async (source) => all(source))
190
+ ])
191
+
192
+ expect(listenerChunks).to.be.eql(['hey'])
193
+ expect(dialerChunks).to.be.eql(['hello'])
194
+ })
195
+ })
196
+ }