@libp2p/interface-compliance-tests 6.1.8 → 6.1.9

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 (66) hide show
  1. package/dist/src/matchers.d.ts +6 -0
  2. package/dist/src/matchers.d.ts.map +1 -1
  3. package/dist/src/matchers.js +6 -0
  4. package/dist/src/matchers.js.map +1 -1
  5. package/dist/src/mocks/index.d.ts +0 -2
  6. package/dist/src/mocks/index.d.ts.map +1 -1
  7. package/dist/src/mocks/index.js +0 -2
  8. package/dist/src/mocks/index.js.map +1 -1
  9. package/dist/src/mocks/muxer.d.ts +8 -3
  10. package/dist/src/mocks/muxer.d.ts.map +1 -1
  11. package/dist/src/mocks/muxer.js +15 -6
  12. package/dist/src/mocks/muxer.js.map +1 -1
  13. package/dist/src/mocks/upgrader.d.ts.map +1 -1
  14. package/dist/src/mocks/upgrader.js +0 -1
  15. package/dist/src/mocks/upgrader.js.map +1 -1
  16. package/dist/src/transport/index.d.ts +23 -10
  17. package/dist/src/transport/index.d.ts.map +1 -1
  18. package/dist/src/transport/index.js +418 -6
  19. package/dist/src/transport/index.js.map +1 -1
  20. package/dist/src/transport/utils.d.ts +17 -0
  21. package/dist/src/transport/utils.d.ts.map +1 -0
  22. package/dist/src/transport/utils.js +63 -0
  23. package/dist/src/transport/utils.js.map +1 -0
  24. package/dist/typedoc-urls.json +1 -6
  25. package/package.json +11 -10
  26. package/src/matchers.ts +6 -0
  27. package/src/mocks/index.ts +0 -2
  28. package/src/mocks/muxer.ts +24 -10
  29. package/src/mocks/upgrader.ts +1 -3
  30. package/src/transport/index.ts +570 -16
  31. package/src/transport/utils.ts +76 -0
  32. package/dist/src/connection/index.d.ts +0 -5
  33. package/dist/src/connection/index.d.ts.map +0 -1
  34. package/dist/src/connection/index.js +0 -135
  35. package/dist/src/connection/index.js.map +0 -1
  36. package/dist/src/mocks/connection-gater.d.ts +0 -3
  37. package/dist/src/mocks/connection-gater.d.ts.map +0 -1
  38. package/dist/src/mocks/connection-gater.js +0 -17
  39. package/dist/src/mocks/connection-gater.js.map +0 -1
  40. package/dist/src/mocks/metrics.d.ts +0 -3
  41. package/dist/src/mocks/metrics.d.ts.map +0 -1
  42. package/dist/src/mocks/metrics.js +0 -286
  43. package/dist/src/mocks/metrics.js.map +0 -1
  44. package/dist/src/mocks/peer-discovery.d.ts +0 -21
  45. package/dist/src/mocks/peer-discovery.d.ts.map +0 -1
  46. package/dist/src/mocks/peer-discovery.js +0 -47
  47. package/dist/src/mocks/peer-discovery.js.map +0 -1
  48. package/dist/src/transport/dial-test.d.ts +0 -5
  49. package/dist/src/transport/dial-test.d.ts.map +0 -1
  50. package/dist/src/transport/dial-test.js +0 -99
  51. package/dist/src/transport/dial-test.js.map +0 -1
  52. package/dist/src/transport/filter-test.d.ts +0 -5
  53. package/dist/src/transport/filter-test.d.ts.map +0 -1
  54. package/dist/src/transport/filter-test.js +0 -24
  55. package/dist/src/transport/filter-test.js.map +0 -1
  56. package/dist/src/transport/listen-test.d.ts +0 -5
  57. package/dist/src/transport/listen-test.d.ts.map +0 -1
  58. package/dist/src/transport/listen-test.js +0 -154
  59. package/dist/src/transport/listen-test.js.map +0 -1
  60. package/src/connection/index.ts +0 -166
  61. package/src/mocks/connection-gater.ts +0 -18
  62. package/src/mocks/metrics.ts +0 -385
  63. package/src/mocks/peer-discovery.ts +0 -59
  64. package/src/transport/dial-test.ts +0 -125
  65. package/src/transport/filter-test.ts +0 -32
  66. package/src/transport/listen-test.ts +0 -192
@@ -1,27 +1,581 @@
1
- import dial from './dial-test.js'
2
- import filter from './filter-test.js'
3
- import listen from './listen-test.js'
1
+ import { stop } from '@libp2p/interface'
2
+ import { expect } from 'aegir/chai'
3
+ import delay from 'delay'
4
+ import drain from 'it-drain'
5
+ import { pushable } from 'it-pushable'
6
+ import pDefer from 'p-defer'
7
+ import { pEvent } from 'p-event'
8
+ import pRetry from 'p-retry'
9
+ import pWaitFor from 'p-wait-for'
10
+ import { raceSignal } from 'race-signal'
11
+ import { isValidTick } from '../is-valid-tick.js'
12
+ import { createPeer, getTransportManager, getUpgrader, slowNetwork } from './utils.js'
4
13
  import type { TestSetup } from '../index.js'
5
- import type { Transport } from '@libp2p/interface'
14
+ import type { Echo } from '@libp2p/echo'
15
+ import type { Connection, Libp2p, Stream, StreamHandler } from '@libp2p/interface'
6
16
  import type { Multiaddr } from '@multiformats/multiaddr'
17
+ import type { MultiaddrMatcher } from '@multiformats/multiaddr-matcher'
18
+ import type { Libp2pInit } from 'libp2p'
19
+ import type { DeferredPromise } from 'p-defer'
7
20
 
8
- export interface Connector {
9
- delay(ms: number): void
10
- restore(): void
21
+ export interface TransportTestFixtures {
22
+ /**
23
+ * Addresses that will be used to dial listeners - both addresses must resolve
24
+ * to the same node
25
+ */
26
+ dialAddrs?: [Multiaddr, Multiaddr]
27
+
28
+ /**
29
+ * Filter out any addresses that cannot be dialed by the transport
30
+ */
31
+ dialMultiaddrMatcher: MultiaddrMatcher
32
+
33
+ /**
34
+ * Filter out any addresses that cannot be listened on by the transport
35
+ */
36
+ listenMultiaddrMatcher: MultiaddrMatcher
37
+
38
+ /**
39
+ * Config that creates a libp2p node that can dial a listener
40
+ */
41
+ dialer: Libp2pInit
42
+
43
+ /**
44
+ * Config that creates a libp2p node that can accept dials
45
+ */
46
+ listener?: Libp2pInit
11
47
  }
12
48
 
13
- export interface TransportTestFixtures {
14
- listenAddrs: Multiaddr[]
15
- dialAddrs: Multiaddr[]
16
- dialer: Transport
17
- listener: Transport
18
- connector: Connector
49
+ async function getSetup (common: TestSetup<TransportTestFixtures>): Promise<{ dialer: Libp2p<{ echo: Echo }>, listener?: Libp2p<{ echo: Echo }>, dialAddrs: Multiaddr[], dialMultiaddrMatcher: MultiaddrMatcher, listenMultiaddrMatcher: MultiaddrMatcher }> {
50
+ const setup = await common.setup()
51
+ const dialer = await createPeer(setup.dialer)
52
+ let listener
53
+
54
+ if (setup.listener != null) {
55
+ listener = await createPeer(setup.listener)
56
+ }
57
+
58
+ const dialAddrs = listener?.getMultiaddrs() ?? setup.dialAddrs
59
+
60
+ if (dialAddrs == null) {
61
+ throw new Error('Listener config or dial addresses must be specified')
62
+ }
63
+
64
+ return {
65
+ dialer,
66
+ listener,
67
+ dialAddrs: dialAddrs.filter(ma => setup.dialMultiaddrMatcher.exactMatch(ma)),
68
+ dialMultiaddrMatcher: setup.dialMultiaddrMatcher,
69
+ listenMultiaddrMatcher: setup.listenMultiaddrMatcher
70
+ }
19
71
  }
20
72
 
21
73
  export default (common: TestSetup<TransportTestFixtures>): void => {
22
74
  describe('interface-transport', () => {
23
- dial(common)
24
- listen(common)
25
- filter(common)
75
+ let dialer: Libp2p<{ echo: Echo }>
76
+ let listener: Libp2p<{ echo: Echo }> | undefined
77
+ let dialAddrs: Multiaddr[]
78
+ let dialMultiaddrMatcher: MultiaddrMatcher
79
+
80
+ afterEach(async () => {
81
+ await stop(dialer, listener)
82
+ await common.teardown()
83
+ })
84
+
85
+ it('simple', async () => {
86
+ ({ dialer, listener, dialAddrs } = await getSetup(common))
87
+
88
+ const input = Uint8Array.from([0, 1, 2, 3, 4])
89
+ const output = await dialer.services.echo.echo(dialAddrs[0], input, {
90
+ signal: AbortSignal.timeout(5000)
91
+ })
92
+
93
+ expect(output).to.equalBytes(input)
94
+ })
95
+
96
+ it('should listen on multiple addresses', async () => {
97
+ ({ dialer, listener, dialAddrs } = await getSetup(common))
98
+
99
+ const input = Uint8Array.from([0, 1, 2, 3, 4])
100
+
101
+ await expect(dialer.services.echo.echo(dialAddrs[0], input, {
102
+ signal: AbortSignal.timeout(5000)
103
+ })).to.eventually.deep.equal(input)
104
+
105
+ await expect(dialer.services.echo.echo(dialAddrs[1], input, {
106
+ signal: AbortSignal.timeout(5000)
107
+ })).to.eventually.deep.equal(input)
108
+ })
109
+
110
+ it('can close connections', async () => {
111
+ ({ dialer, listener, dialAddrs } = await getSetup(common))
112
+
113
+ const conn = await dialer.dial(dialAddrs[0], {
114
+ signal: AbortSignal.timeout(5000)
115
+ })
116
+
117
+ await conn.close()
118
+ expect(isValidTick(conn.timeline.close)).to.equal(true)
119
+ })
120
+
121
+ it('abort before dialing throws AbortError', async () => {
122
+ ({ dialer, listener, dialAddrs } = await getSetup(common))
123
+
124
+ const controller = new AbortController()
125
+ controller.abort()
126
+
127
+ await expect(dialer.dial(dialAddrs[0], {
128
+ signal: controller.signal
129
+ })).to.eventually.be.rejected()
130
+ .with.property('name', 'AbortError')
131
+ })
132
+
133
+ it('abort while dialing throws AbortError', async () => {
134
+ ({ dialer, listener, dialAddrs } = await getSetup(common))
135
+ slowNetwork(dialer, 100)
136
+
137
+ const controller = new AbortController()
138
+ setTimeout(() => { controller.abort() }, 50)
139
+
140
+ await expect(dialer.dial(dialAddrs[0], {
141
+ signal: controller.signal
142
+ })).to.eventually.be.rejected()
143
+ .with.property('name', 'AbortError')
144
+ })
145
+
146
+ it('should close all streams when the connection closes', async () => {
147
+ ({ dialer, listener, dialAddrs } = await getSetup(common))
148
+
149
+ let incomingConnectionPromise: DeferredPromise<Connection> | undefined
150
+
151
+ if (listener != null) {
152
+ incomingConnectionPromise = pDefer<Connection>()
153
+
154
+ listener.addEventListener('connection:open', (event) => {
155
+ const conn = event.detail
156
+
157
+ if (conn.remotePeer.equals(dialer.peerId)) {
158
+ incomingConnectionPromise?.resolve(conn)
159
+ }
160
+ })
161
+ }
162
+
163
+ const connection = await dialer.dial(dialAddrs[0])
164
+ let remoteConn: Connection | undefined
165
+
166
+ if (incomingConnectionPromise != null) {
167
+ remoteConn = await incomingConnectionPromise.promise
168
+ }
169
+
170
+ for (let i = 0; i < 5; i++) {
171
+ await connection.newStream('/echo/1.0.0', {
172
+ maxOutboundStreams: 5
173
+ })
174
+ }
175
+
176
+ const streams = connection.streams
177
+
178
+ // Close the connection and verify all streams have been closed
179
+ await connection.close()
180
+
181
+ await pWaitFor(() => connection.streams.length === 0, {
182
+ timeout: 5000
183
+ })
184
+
185
+ if (remoteConn != null) {
186
+ await pWaitFor(() => remoteConn.streams.length === 0, {
187
+ timeout: 5000
188
+ })
189
+ }
190
+
191
+ expect(streams.find(stream => stream.status === 'open')).to.be.undefined()
192
+ })
193
+
194
+ it('should not handle connection if upgradeInbound rejects', async function () {
195
+ ({ dialer, listener, dialAddrs, dialMultiaddrMatcher } = await getSetup(common))
196
+
197
+ if (listener == null) {
198
+ return this.skip()
199
+ }
200
+
201
+ const upgrader = getUpgrader(listener)
202
+ upgrader.upgradeInbound = async () => {
203
+ await delay(100)
204
+ throw new Error('Oh noes!')
205
+ }
206
+
207
+ await expect(dialer.dial(dialAddrs[0])).to.eventually.be.rejected
208
+ .with.property('name', 'EncryptionFailedError')
209
+
210
+ expect(dialer.getConnections().filter(conn => {
211
+ return dialMultiaddrMatcher.exactMatch(conn.remoteAddr)
212
+ })).to.have.lengthOf(0)
213
+
214
+ if (listener != null) {
215
+ const remoteConnections = listener.getConnections(dialer.peerId)
216
+ .filter(conn => dialMultiaddrMatcher.exactMatch(conn.remoteAddr))
217
+ expect(remoteConnections).to.have.lengthOf(0)
218
+ }
219
+ })
220
+
221
+ it('should omit peerid in listening addresses', async function () {
222
+ ({ dialer, listener, dialAddrs } = await getSetup(common))
223
+
224
+ if (listener == null) {
225
+ return this.skip()
226
+ }
227
+
228
+ const tm = getTransportManager(listener)
229
+ const transportListeners = tm.getListeners()
230
+
231
+ for (const transportListener of transportListeners) {
232
+ for (const ma of transportListener.getAddrs()) {
233
+ expect(ma.toString()).to.not.include(`/p2p/${listener.peerId}`)
234
+ }
235
+ }
236
+ })
237
+
238
+ it('should handle one big write', async function () {
239
+ const timeout = 120_000
240
+ this.timeout(timeout);
241
+ ({ dialer, listener, dialAddrs } = await getSetup(common))
242
+
243
+ const input = new Uint8Array(1024 * 1024 * 10).fill(5)
244
+ const output = await dialer.services.echo.echo(dialAddrs[0], input, {
245
+ signal: AbortSignal.timeout(timeout)
246
+ })
247
+
248
+ expect(output).to.equalBytes(input)
249
+ })
250
+
251
+ it('should handle many small writes', async function () {
252
+ const timeout = 120_000
253
+ this.timeout(timeout);
254
+ ({ dialer, listener, dialAddrs } = await getSetup(common))
255
+
256
+ for (let i = 0; i < 2000; i++) {
257
+ const input = new Uint8Array(1024).fill(5)
258
+ const output = await dialer.services.echo.echo(dialAddrs[0], input, {
259
+ signal: AbortSignal.timeout(timeout)
260
+ })
261
+
262
+ expect(output).to.equalBytes(input)
263
+ }
264
+ })
265
+
266
+ it('can close a stream for reading but send a large amount of data', async function () {
267
+ const timeout = 120_000
268
+ this.timeout(timeout);
269
+ ({ dialer, listener, dialAddrs } = await getSetup(common))
270
+
271
+ if (listener == null) {
272
+ return this.skip()
273
+ }
274
+
275
+ const protocol = '/send-data/1.0.0'
276
+ const chunkSize = 1024
277
+ const bytes = chunkSize * 1024 * 10
278
+ const deferred = pDefer()
279
+
280
+ await listener.handle(protocol, ({ stream }) => {
281
+ Promise.resolve().then(async () => {
282
+ let read = 0
283
+
284
+ for await (const buf of stream.source) {
285
+ read += buf.byteLength
286
+
287
+ if (read === bytes) {
288
+ deferred.resolve()
289
+ break
290
+ }
291
+ }
292
+ })
293
+ .catch(err => {
294
+ deferred.reject(err)
295
+ stream.abort(err)
296
+ })
297
+ })
298
+
299
+ const stream = await dialer.dialProtocol(dialAddrs[0], protocol)
300
+
301
+ await stream.closeRead()
302
+
303
+ await stream.sink((async function * () {
304
+ for (let i = 0; i < bytes; i += chunkSize) {
305
+ yield new Uint8Array(chunkSize)
306
+ }
307
+ })())
308
+
309
+ await stream.close()
310
+
311
+ await deferred.promise
312
+ })
313
+
314
+ it('can close a stream for writing but receive a large amount of data', async function () {
315
+ const timeout = 120_000
316
+ this.timeout(timeout);
317
+ ({ dialer, listener, dialAddrs } = await getSetup(common))
318
+
319
+ if (listener == null) {
320
+ return this.skip()
321
+ }
322
+
323
+ const protocol = '/receive-data/1.0.0'
324
+ const chunkSize = 1024
325
+ const bytes = chunkSize * 1024 * 10
326
+ const deferred = pDefer()
327
+
328
+ await listener.handle(protocol, ({ stream }) => {
329
+ Promise.resolve().then(async () => {
330
+ await stream.sink((async function * () {
331
+ for (let i = 0; i < bytes; i += chunkSize) {
332
+ yield new Uint8Array(chunkSize)
333
+ }
334
+ })())
335
+
336
+ await stream.close()
337
+ })
338
+ .catch(err => {
339
+ deferred.reject(err)
340
+ stream.abort(err)
341
+ })
342
+ })
343
+
344
+ const stream = await dialer.dialProtocol(dialAddrs[0], protocol)
345
+
346
+ await stream.closeWrite()
347
+
348
+ let read = 0
349
+
350
+ for await (const buf of stream.source) {
351
+ read += buf.byteLength
352
+ }
353
+
354
+ expect(read).to.equal(bytes)
355
+ })
356
+
357
+ it('can close local stream for writing and reading while a remote stream is writing', async function () {
358
+ ({ dialer, listener, dialAddrs } = await getSetup(common))
359
+
360
+ if (listener == null) {
361
+ return this.skip()
362
+ }
363
+
364
+ /**
365
+ * NodeA NodeB
366
+ * | <--- STOP_SENDING |
367
+ * | FIN ---> |
368
+ * | <--- FIN |
369
+ * | FIN_ACK ---> |
370
+ * | <--- FIN_ACK |
371
+ */
372
+
373
+ const getRemoteStream = pDefer<Stream>()
374
+ const protocol = '/close-local-while-remote-writes/1.0.0'
375
+
376
+ const streamHandler: StreamHandler = ({ stream }) => {
377
+ void Promise.resolve().then(async () => {
378
+ getRemoteStream.resolve(stream)
379
+ })
380
+ }
381
+
382
+ await listener.handle(protocol, (info) => {
383
+ streamHandler(info)
384
+ }, {
385
+ runOnLimitedConnection: true
386
+ })
387
+
388
+ const connection = await dialer.dial(dialAddrs[0])
389
+
390
+ // open a stream on the echo protocol
391
+ const stream = await connection.newStream(protocol, {
392
+ runOnLimitedConnection: true
393
+ })
394
+
395
+ // close the write end immediately
396
+ const p = stream.closeWrite()
397
+
398
+ const remoteStream = await getRemoteStream.promise
399
+ // close the readable end of the remote stream
400
+ await remoteStream.closeRead()
401
+
402
+ // keep the remote write end open, this should delay the FIN_ACK reply to the local stream
403
+ const remoteInputStream = pushable<Uint8Array>()
404
+ void remoteStream.sink(remoteInputStream)
405
+
406
+ // wait for remote to receive local close-write
407
+ await pRetry(() => {
408
+ if (remoteStream.readStatus !== 'closed') {
409
+ throw new Error('Remote stream read status ' + remoteStream.readStatus)
410
+ }
411
+ }, {
412
+ minTimeout: 100
413
+ })
414
+
415
+ // remote closes write
416
+ remoteInputStream.end()
417
+
418
+ // wait to receive FIN_ACK
419
+ await p
420
+
421
+ // wait for remote to notice closure
422
+ await pRetry(() => {
423
+ if (remoteStream.status !== 'closed') {
424
+ throw new Error('Remote stream not closed')
425
+ }
426
+ })
427
+
428
+ assertStreamClosed(stream)
429
+ assertStreamClosed(remoteStream)
430
+ })
431
+
432
+ it('can close local stream for writing and reading while a remote stream is writing using source/sink', async function () {
433
+ ({ dialer, listener, dialAddrs } = await getSetup(common))
434
+
435
+ if (listener == null) {
436
+ return this.skip()
437
+ }
438
+
439
+ /**
440
+ * NodeA NodeB
441
+ * | FIN ---> |
442
+ * | <--- FIN |
443
+ * | FIN_ACK ---> |
444
+ * | <--- FIN_ACK |
445
+ */
446
+
447
+ const getRemoteStream = pDefer<Stream>()
448
+ const protocol = '/close-local-while-remote-reads/1.0.0'
449
+
450
+ const streamHandler: StreamHandler = ({ stream }) => {
451
+ void Promise.resolve().then(async () => {
452
+ getRemoteStream.resolve(stream)
453
+ })
454
+ }
455
+
456
+ await listener.handle(protocol, (info) => {
457
+ streamHandler(info)
458
+ }, {
459
+ runOnLimitedConnection: true
460
+ })
461
+
462
+ const connection = await dialer.dial(dialAddrs[0])
463
+
464
+ // open a stream on the echo protocol
465
+ const stream = await connection.newStream(protocol, {
466
+ runOnLimitedConnection: true
467
+ })
468
+
469
+ // keep the remote write end open, this should delay the FIN_ACK reply to the local stream
470
+ const p = stream.sink([])
471
+
472
+ const remoteStream = await getRemoteStream.promise
473
+ // close the readable end of the remote stream
474
+ await remoteStream.closeRead()
475
+ // readable end should finish
476
+ await drain(remoteStream.source)
477
+
478
+ // wait for remote to receive local close-write
479
+ await pRetry(() => {
480
+ if (remoteStream.readStatus !== 'closed') {
481
+ throw new Error('Remote stream read status ' + remoteStream.readStatus)
482
+ }
483
+ }, {
484
+ minTimeout: 100
485
+ })
486
+
487
+ // remote closes write
488
+ await remoteStream.sink([])
489
+
490
+ // wait to receive FIN_ACK
491
+ await p
492
+
493
+ // close read end of stream
494
+ await stream.closeRead()
495
+ // readable end should finish
496
+ await drain(stream.source)
497
+
498
+ // wait for remote to notice closure
499
+ await pRetry(() => {
500
+ if (remoteStream.status !== 'closed') {
501
+ throw new Error('Remote stream not closed')
502
+ }
503
+ })
504
+
505
+ assertStreamClosed(stream)
506
+ assertStreamClosed(remoteStream)
507
+ })
508
+ })
509
+
510
+ describe('events', () => {
511
+ let dialer: Libp2p<{ echo: Echo }>
512
+ let listener: Libp2p<{ echo: Echo }> | undefined
513
+ let listenMultiaddrMatcher: MultiaddrMatcher
514
+
515
+ afterEach(async () => {
516
+ await stop(dialer, listener)
517
+ await common.teardown()
518
+ })
519
+
520
+ it('emits listening', async function () {
521
+ ({ dialer, listener, listenMultiaddrMatcher } = await getSetup(common))
522
+
523
+ if (listener == null) {
524
+ return this.skip()
525
+ }
526
+
527
+ await listener.stop()
528
+
529
+ const transportListeningPromise = pDefer()
530
+
531
+ listener.addEventListener('transport:listening', (event) => {
532
+ const transportListener = event.detail
533
+
534
+ if (transportListener.getAddrs().some(ma => listenMultiaddrMatcher.exactMatch(ma))) {
535
+ transportListeningPromise.resolve()
536
+ }
537
+ })
538
+
539
+ await listener.start()
540
+
541
+ await raceSignal(transportListeningPromise.promise, AbortSignal.timeout(1000), {
542
+ errorMessage: 'Did not emit listening event'
543
+ })
544
+ })
545
+
546
+ it('emits close', async function () {
547
+ ({ dialer, listener } = await getSetup(common))
548
+
549
+ if (listener == null) {
550
+ return this.skip()
551
+ }
552
+
553
+ const transportManager = getTransportManager(listener)
554
+ const transportListener = transportManager.getListeners()
555
+ .filter(listener => listener.getAddrs().some(ma => listenMultiaddrMatcher.exactMatch(ma)))
556
+ .pop()
557
+
558
+ if (transportListener == null) {
559
+ throw new Error('Could not find address listener')
560
+ }
561
+
562
+ const p = pEvent(transportListener, 'close')
563
+
564
+ await listener.stop()
565
+
566
+ await raceSignal(p, AbortSignal.timeout(1000), {
567
+ errorMessage: 'Did not emit close event'
568
+ })
569
+ })
26
570
  })
27
571
  }
572
+
573
+ function assertStreamClosed (stream: Stream): void {
574
+ expect(stream.status).to.equal('closed')
575
+ expect(stream.readStatus).to.equal('closed')
576
+ expect(stream.writeStatus).to.equal('closed')
577
+
578
+ expect(stream.timeline.close).to.be.a('number')
579
+ expect(stream.timeline.closeRead).to.be.a('number')
580
+ expect(stream.timeline.closeWrite).to.be.a('number')
581
+ }
@@ -0,0 +1,76 @@
1
+ /* eslint-env mocha */
2
+
3
+ import { echo } from '@libp2p/echo'
4
+ import { memory } from '@libp2p/memory'
5
+ import { plaintext } from '@libp2p/plaintext'
6
+ import delay from 'delay'
7
+ import map from 'it-map'
8
+ import { createLibp2p } from 'libp2p'
9
+ import { mockMuxer } from '../mocks/muxer.js'
10
+ import type { Echo } from '@libp2p/echo'
11
+ import type { Libp2p, Upgrader } from '@libp2p/interface'
12
+ import type { TransportManager } from '@libp2p/interface-internal'
13
+ import type { Libp2pOptions } from 'libp2p'
14
+
15
+ export async function createPeer (config: Partial<Libp2pOptions> = {}): Promise<Libp2p<{ echo: Echo }>> {
16
+ return createLibp2p({
17
+ transports: [
18
+ memory()
19
+ ],
20
+ connectionEncrypters: [
21
+ plaintext()
22
+ ],
23
+ streamMuxers: [
24
+ () => mockMuxer()
25
+ ],
26
+ connectionGater: {
27
+ denyDialMultiaddr: () => false
28
+ },
29
+ ...config,
30
+ services: {
31
+ ...config.services,
32
+ echo: echo({
33
+ maxInboundStreams: 5
34
+ })
35
+ }
36
+ })
37
+ }
38
+
39
+ /**
40
+ * Monkey patch the upgrader in the passed libp2p to add latency to any
41
+ * multiaddr connections upgraded to connections - this is to work with
42
+ * transports that have their own muxers/encrypters and do not support
43
+ * connection protection
44
+ */
45
+ export function slowNetwork (libp2p: any, latency: number): void {
46
+ const upgrader: Upgrader = getUpgrader(libp2p)
47
+
48
+ const originalUpgradeInbound = upgrader.upgradeInbound.bind(upgrader)
49
+ const originalUpgradeOutbound = upgrader.upgradeOutbound.bind(upgrader)
50
+
51
+ upgrader.upgradeInbound = async (maConn, opts) => {
52
+ maConn.source = map(maConn.source, async (buf) => {
53
+ await delay(latency)
54
+ return buf
55
+ })
56
+
57
+ return originalUpgradeInbound(maConn, opts)
58
+ }
59
+
60
+ upgrader.upgradeOutbound = async (maConn, opts) => {
61
+ maConn.source = map(maConn.source, async (buf) => {
62
+ await delay(latency)
63
+ return buf
64
+ })
65
+
66
+ return originalUpgradeOutbound(maConn, opts)
67
+ }
68
+ }
69
+
70
+ export function getUpgrader (libp2p: any): Upgrader {
71
+ return libp2p.components.upgrader
72
+ }
73
+
74
+ export function getTransportManager (libp2p: any): TransportManager {
75
+ return libp2p.components.transportManager
76
+ }
@@ -1,5 +0,0 @@
1
- import type { TestSetup } from '../index.js';
2
- import type { Connection } from '@libp2p/interface';
3
- declare const _default: (test: TestSetup<Connection>) => void;
4
- export default _default;
5
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/connection/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;+BAE7B,UAAU,UAAU,CAAC,KAAG,IAAI;AAAlD,wBAgKC"}