@libp2p/interface-compliance-tests 0.0.0 → 1.0.2

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 (177) hide show
  1. package/LICENSE +4 -0
  2. package/README.md +25 -0
  3. package/dist/src/connection/connection.d.ts +5 -0
  4. package/dist/src/connection/connection.d.ts.map +1 -0
  5. package/dist/src/connection/connection.js +148 -0
  6. package/dist/src/connection/connection.js.map +1 -0
  7. package/dist/src/connection/index.d.ts +5 -0
  8. package/dist/src/connection/index.d.ts.map +1 -0
  9. package/dist/src/connection/index.js +5 -0
  10. package/dist/src/connection/index.js.map +1 -0
  11. package/dist/src/crypto/index.d.ts +5 -0
  12. package/dist/src/crypto/index.d.ts.map +1 -0
  13. package/dist/src/crypto/index.js +78 -0
  14. package/dist/src/crypto/index.js.map +1 -0
  15. package/dist/src/index.d.ts +5 -0
  16. package/dist/src/index.d.ts.map +1 -0
  17. package/dist/src/index.js +2 -0
  18. package/dist/src/index.js.map +1 -0
  19. package/dist/src/peer-discovery/index.d.ts +6 -0
  20. package/dist/src/peer-discovery/index.d.ts.map +1 -0
  21. package/dist/src/peer-discovery/index.js +63 -0
  22. package/dist/src/peer-discovery/index.js.map +1 -0
  23. package/dist/src/pubsub/api.d.ts +6 -0
  24. package/dist/src/pubsub/api.d.ts.map +1 -0
  25. package/dist/src/pubsub/api.js +65 -0
  26. package/dist/src/pubsub/api.js.map +1 -0
  27. package/dist/src/pubsub/connection-handlers.d.ts +6 -0
  28. package/dist/src/pubsub/connection-handlers.d.ts.map +1 -0
  29. package/dist/src/pubsub/connection-handlers.js +279 -0
  30. package/dist/src/pubsub/connection-handlers.js.map +1 -0
  31. package/dist/src/pubsub/emit-self.d.ts +6 -0
  32. package/dist/src/pubsub/emit-self.d.ts.map +1 -0
  33. package/dist/src/pubsub/emit-self.js +51 -0
  34. package/dist/src/pubsub/emit-self.js.map +1 -0
  35. package/dist/src/pubsub/index.d.ts +6 -0
  36. package/dist/src/pubsub/index.d.ts.map +1 -0
  37. package/dist/src/pubsub/index.js +17 -0
  38. package/dist/src/pubsub/index.js.map +1 -0
  39. package/dist/src/pubsub/messages.d.ts +6 -0
  40. package/dist/src/pubsub/messages.d.ts.map +1 -0
  41. package/dist/src/pubsub/messages.js +93 -0
  42. package/dist/src/pubsub/messages.js.map +1 -0
  43. package/dist/src/pubsub/multiple-nodes.d.ts +6 -0
  44. package/dist/src/pubsub/multiple-nodes.d.ts.map +1 -0
  45. package/dist/src/pubsub/multiple-nodes.js +283 -0
  46. package/dist/src/pubsub/multiple-nodes.js.map +1 -0
  47. package/dist/src/pubsub/two-nodes.d.ts +6 -0
  48. package/dist/src/pubsub/two-nodes.d.ts.map +1 -0
  49. package/dist/src/pubsub/two-nodes.js +127 -0
  50. package/dist/src/pubsub/two-nodes.js.map +1 -0
  51. package/dist/src/pubsub/utils.d.ts +3 -0
  52. package/dist/src/pubsub/utils.d.ts.map +1 -0
  53. package/dist/src/pubsub/utils.js +11 -0
  54. package/dist/src/pubsub/utils.js.map +1 -0
  55. package/dist/src/record/index.d.ts +5 -0
  56. package/dist/src/record/index.d.ts.map +1 -0
  57. package/dist/src/record/index.js +25 -0
  58. package/dist/src/record/index.js.map +1 -0
  59. package/dist/src/stream-muxer/base-test.d.ts +5 -0
  60. package/dist/src/stream-muxer/base-test.d.ts.map +1 -0
  61. package/dist/src/stream-muxer/base-test.js +123 -0
  62. package/dist/src/stream-muxer/base-test.js.map +1 -0
  63. package/dist/src/stream-muxer/close-test.d.ts +5 -0
  64. package/dist/src/stream-muxer/close-test.d.ts.map +1 -0
  65. package/dist/src/stream-muxer/close-test.js +103 -0
  66. package/dist/src/stream-muxer/close-test.js.map +1 -0
  67. package/dist/src/stream-muxer/index.d.ts +5 -0
  68. package/dist/src/stream-muxer/index.d.ts.map +1 -0
  69. package/dist/src/stream-muxer/index.js +13 -0
  70. package/dist/src/stream-muxer/index.js.map +1 -0
  71. package/dist/src/stream-muxer/mega-stress-test.d.ts +5 -0
  72. package/dist/src/stream-muxer/mega-stress-test.d.ts.map +1 -0
  73. package/dist/src/stream-muxer/mega-stress-test.js +8 -0
  74. package/dist/src/stream-muxer/mega-stress-test.js.map +1 -0
  75. package/dist/src/stream-muxer/spawner.d.ts +4 -0
  76. package/dist/src/stream-muxer/spawner.d.ts.map +1 -0
  77. package/dist/src/stream-muxer/spawner.js +32 -0
  78. package/dist/src/stream-muxer/spawner.js.map +1 -0
  79. package/dist/src/stream-muxer/stress-test.d.ts +5 -0
  80. package/dist/src/stream-muxer/stress-test.d.ts.map +1 -0
  81. package/dist/src/stream-muxer/stress-test.js +21 -0
  82. package/dist/src/stream-muxer/stress-test.js.map +1 -0
  83. package/dist/src/topology/multicodec-topology.d.ts +5 -0
  84. package/dist/src/topology/multicodec-topology.d.ts.map +1 -0
  85. package/dist/src/topology/multicodec-topology.js +109 -0
  86. package/dist/src/topology/multicodec-topology.js.map +1 -0
  87. package/dist/src/topology/topology.d.ts +5 -0
  88. package/dist/src/topology/topology.d.ts.map +1 -0
  89. package/dist/src/topology/topology.js +29 -0
  90. package/dist/src/topology/topology.js.map +1 -0
  91. package/dist/src/transport/dial-test.d.ts +5 -0
  92. package/dist/src/transport/dial-test.d.ts.map +1 -0
  93. package/dist/src/transport/dial-test.js +78 -0
  94. package/dist/src/transport/dial-test.js.map +1 -0
  95. package/dist/src/transport/filter-test.d.ts +5 -0
  96. package/dist/src/transport/filter-test.d.ts.map +1 -0
  97. package/dist/src/transport/filter-test.js +19 -0
  98. package/dist/src/transport/filter-test.js.map +1 -0
  99. package/dist/src/transport/index.d.ts +18 -0
  100. package/dist/src/transport/index.d.ts.map +1 -0
  101. package/dist/src/transport/index.js +11 -0
  102. package/dist/src/transport/index.js.map +1 -0
  103. package/dist/src/transport/listen-test.d.ts +5 -0
  104. package/dist/src/transport/listen-test.d.ts.map +1 -0
  105. package/dist/src/transport/listen-test.js +116 -0
  106. package/dist/src/transport/listen-test.js.map +1 -0
  107. package/dist/src/transport/utils/index.d.ts +8 -0
  108. package/dist/src/transport/utils/index.d.ts.map +1 -0
  109. package/dist/src/transport/utils/index.js +104 -0
  110. package/dist/src/transport/utils/index.js.map +1 -0
  111. package/dist/src/utils/peers.d.ts +7 -0
  112. package/dist/src/utils/peers.d.ts.map +1 -0
  113. package/dist/src/utils/peers.js +26 -0
  114. package/dist/src/utils/peers.js.map +1 -0
  115. package/dist/test/connection/index.spec.d.ts +2 -0
  116. package/dist/test/connection/index.spec.d.ts.map +1 -0
  117. package/dist/test/connection/index.spec.js +71 -0
  118. package/dist/test/connection/index.spec.js.map +1 -0
  119. package/dist/test/crypto/index.spec.d.ts +2 -0
  120. package/dist/test/crypto/index.spec.d.ts.map +1 -0
  121. package/dist/test/crypto/index.spec.js +11 -0
  122. package/dist/test/crypto/index.spec.js.map +1 -0
  123. package/dist/test/crypto/mock-crypto.d.ts +4 -0
  124. package/dist/test/crypto/mock-crypto.d.ts.map +1 -0
  125. package/dist/test/crypto/mock-crypto.js +93 -0
  126. package/dist/test/crypto/mock-crypto.js.map +1 -0
  127. package/dist/test/peer-discovery/index.spec.d.ts +2 -0
  128. package/dist/test/peer-discovery/index.spec.d.ts.map +1 -0
  129. package/dist/test/peer-discovery/index.spec.js +18 -0
  130. package/dist/test/peer-discovery/index.spec.js.map +1 -0
  131. package/dist/test/peer-discovery/mock-discovery.d.ts +20 -0
  132. package/dist/test/peer-discovery/mock-discovery.d.ts.map +1 -0
  133. package/dist/test/peer-discovery/mock-discovery.js +39 -0
  134. package/dist/test/peer-discovery/mock-discovery.js.map +1 -0
  135. package/dist/test/topology/mock-peer-store.d.ts +12 -0
  136. package/dist/test/topology/mock-peer-store.d.ts.map +1 -0
  137. package/dist/test/topology/mock-peer-store.js +18 -0
  138. package/dist/test/topology/mock-peer-store.js.map +1 -0
  139. package/dist/test/topology/multicodec-topology.spec.d.ts +2 -0
  140. package/dist/test/topology/multicodec-topology.spec.d.ts.map +1 -0
  141. package/dist/test/topology/multicodec-topology.spec.js +45 -0
  142. package/dist/test/topology/multicodec-topology.spec.js.map +1 -0
  143. package/dist/test/topology/topology.spec.d.ts +2 -0
  144. package/dist/test/topology/topology.spec.d.ts.map +1 -0
  145. package/dist/test/topology/topology.spec.js +21 -0
  146. package/dist/test/topology/topology.spec.js.map +1 -0
  147. package/dist/tsconfig.tsbuildinfo +1 -0
  148. package/package.json +203 -4
  149. package/src/connection/README.md +256 -0
  150. package/src/connection/connection.ts +178 -0
  151. package/src/connection/index.ts +7 -0
  152. package/src/crypto/index.ts +104 -0
  153. package/src/index.ts +5 -0
  154. package/src/peer-discovery/index.ts +87 -0
  155. package/src/pubsub/api.ts +89 -0
  156. package/src/pubsub/connection-handlers.ts +356 -0
  157. package/src/pubsub/emit-self.ts +67 -0
  158. package/src/pubsub/index.ts +20 -0
  159. package/src/pubsub/messages.ts +111 -0
  160. package/src/pubsub/multiple-nodes.ts +353 -0
  161. package/src/pubsub/two-nodes.ts +175 -0
  162. package/src/pubsub/utils.ts +13 -0
  163. package/src/record/index.ts +32 -0
  164. package/src/stream-muxer/base-test.ts +155 -0
  165. package/src/stream-muxer/close-test.ts +124 -0
  166. package/src/stream-muxer/index.ts +15 -0
  167. package/src/stream-muxer/mega-stress-test.ts +11 -0
  168. package/src/stream-muxer/spawner.ts +52 -0
  169. package/src/stream-muxer/stress-test.ts +24 -0
  170. package/src/topology/multicodec-topology.ts +136 -0
  171. package/src/topology/topology.ts +38 -0
  172. package/src/transport/dial-test.ts +98 -0
  173. package/src/transport/filter-test.ts +26 -0
  174. package/src/transport/index.ts +29 -0
  175. package/src/transport/listen-test.ts +152 -0
  176. package/src/transport/utils/index.ts +123 -0
  177. package/src/utils/peers.ts +25 -0
@@ -0,0 +1,155 @@
1
+ import { expect } from 'aegir/utils/chai.js'
2
+ // @ts-expect-error no types
3
+ import pair from 'it-pair/duplex.js'
4
+ import { pipe } from 'it-pipe'
5
+ import { collect, map, consume } from 'streaming-iterables'
6
+ import defer from 'p-defer'
7
+ import type { DeferredPromise } from 'p-defer'
8
+ import type { TestSetup } from '../index.js'
9
+ import type { Muxer, MuxerOptions, MuxedStream } from '@libp2p/interfaces/stream-muxer'
10
+ import { isValidTick } from '../transport/utils/index.js'
11
+
12
+ function close (stream: MuxedStream) {
13
+ return pipe([], stream, consume)
14
+ }
15
+
16
+ export default (common: TestSetup<Muxer, MuxerOptions>) => {
17
+ describe('base', () => {
18
+ it('Open a stream from the dialer', async () => {
19
+ const p = pair()
20
+ const dialer = await common.setup()
21
+ const onStreamPromise: DeferredPromise<MuxedStream> = defer()
22
+ const onStreamEndPromise: DeferredPromise<MuxedStream> = defer()
23
+
24
+ const listener = await common.setup({
25
+ onStream: stream => {
26
+ onStreamPromise.resolve(stream)
27
+ },
28
+ onStreamEnd: stream => {
29
+ onStreamEndPromise.resolve(stream)
30
+ }
31
+ })
32
+
33
+ pipe(p[0], dialer, p[0])
34
+ pipe(p[1], listener, p[1])
35
+
36
+ const conn = dialer.newStream()
37
+ expect(dialer.streams).to.include(conn)
38
+ expect(isValidTick(conn.timeline.open)).to.equal(true)
39
+
40
+ const stream = await onStreamPromise.promise
41
+ expect(isValidTick(stream.timeline.open)).to.equal(true)
42
+ // Make sure the stream is being tracked
43
+ expect(listener.streams).to.include(stream)
44
+ close(stream)
45
+
46
+ // Make sure stream is closed properly
47
+ const endedStream = await onStreamEndPromise.promise
48
+ expect(listener.streams).to.not.include(endedStream)
49
+
50
+ if (endedStream.timeline.close == null) {
51
+ throw new Error('timeline had no close time')
52
+ }
53
+
54
+ // Make sure the stream is removed from tracking
55
+ expect(isValidTick(endedStream.timeline.close)).to.equal(true)
56
+
57
+ await close(conn)
58
+
59
+ // ensure we have no streams left
60
+ expect(dialer.streams).to.have.length(0)
61
+ expect(listener.streams).to.have.length(0)
62
+ })
63
+
64
+ it('Open a stream from the listener', async () => {
65
+ const p = pair()
66
+ const onStreamPromise: DeferredPromise<MuxedStream> = defer()
67
+ const dialer = await common.setup({
68
+ onStream: stream => {
69
+ onStreamPromise.resolve(stream)
70
+ }
71
+ })
72
+
73
+ const listener = await common.setup()
74
+
75
+ pipe(p[0], dialer, p[0])
76
+ pipe(p[1], listener, p[1])
77
+
78
+ const conn = listener.newStream()
79
+
80
+ const stream = await onStreamPromise.promise
81
+ expect(isValidTick(stream.timeline.open)).to.equal(true)
82
+ expect(listener.streams).to.include(conn)
83
+ expect(isValidTick(conn.timeline.open)).to.equal(true)
84
+ await close(stream)
85
+
86
+ await close(conn)
87
+ })
88
+
89
+ it('Open a stream on both sides', async () => {
90
+ const p = pair()
91
+ const onDialerStreamPromise: DeferredPromise<MuxedStream> = defer()
92
+ const onListenerStreamPromise: DeferredPromise<MuxedStream> = defer()
93
+ const dialer = await common.setup({
94
+ onStream: stream => {
95
+ onDialerStreamPromise.resolve(stream)
96
+ }
97
+ })
98
+ const listener = await common.setup({
99
+ onStream: stream => {
100
+ onListenerStreamPromise.resolve(stream)
101
+ }
102
+ })
103
+
104
+ pipe(p[0], dialer, p[0])
105
+ pipe(p[1], listener, p[1])
106
+
107
+ const listenerConn = listener.newStream()
108
+ const dialerConn = dialer.newStream()
109
+
110
+ const dialerStream = await onDialerStreamPromise.promise
111
+ const listenerStream = await onListenerStreamPromise.promise
112
+
113
+ await close(dialerStream)
114
+ await close(listenerStream)
115
+
116
+ await close(dialerConn)
117
+ await close(listenerConn)
118
+ })
119
+
120
+ it('Open a stream on one side, write, open a stream on the other side', async () => {
121
+ const toString = map((c: string) => c.slice().toString())
122
+ const p = pair()
123
+ const onDialerStreamPromise: DeferredPromise<MuxedStream> = defer()
124
+ const onListenerStreamPromise: DeferredPromise<MuxedStream> = defer()
125
+ const dialer = await common.setup({
126
+ onStream: stream => {
127
+ onDialerStreamPromise.resolve(stream)
128
+ }
129
+ })
130
+ const listener = await common.setup({
131
+ onStream: stream => {
132
+ onListenerStreamPromise.resolve(stream)
133
+ }
134
+ })
135
+
136
+ pipe(p[0], dialer, p[0])
137
+ pipe(p[1], listener, p[1])
138
+
139
+ const dialerConn = dialer.newStream()
140
+ const listenerConn = listener.newStream()
141
+
142
+ pipe(['hey'], dialerConn)
143
+ pipe(['hello'], listenerConn)
144
+
145
+ const listenerStream = await onListenerStreamPromise.promise
146
+ const dialerStream = await onDialerStreamPromise.promise
147
+
148
+ const listenerChunks = await pipe(listenerStream, toString, collect)
149
+ expect(listenerChunks).to.be.eql(['hey'])
150
+
151
+ const dialerChunks = await pipe(dialerStream, toString, collect)
152
+ expect(dialerChunks).to.be.eql(['hello'])
153
+ })
154
+ })
155
+ }
@@ -0,0 +1,124 @@
1
+ /* eslint max-nested-callbacks: ["error", 8] */
2
+ // @ts-expect-error no types
3
+ import pair from 'it-pair/duplex.js'
4
+ import { pipe } from 'it-pipe'
5
+ import { consume } from 'streaming-iterables'
6
+ import { source, duplex } from 'abortable-iterator'
7
+ import AbortController from 'abort-controller'
8
+ import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
9
+ import type { TestSetup } from '../index.js'
10
+ import type { Muxer, MuxerOptions } from '@libp2p/interfaces/stream-muxer'
11
+ import type { Connection } from '@libp2p/interfaces/connection'
12
+
13
+ async function pause (ms: number) {
14
+ return await new Promise(resolve => setTimeout(resolve, ms))
15
+ }
16
+
17
+ function randomBuffer () {
18
+ return uint8ArrayFromString(Math.random().toString())
19
+ }
20
+
21
+ const infiniteRandom = {
22
+ [Symbol.asyncIterator]: async function * () {
23
+ while (true) {
24
+ yield randomBuffer()
25
+ await pause(10)
26
+ }
27
+ }
28
+ }
29
+
30
+ export default (common: TestSetup<Muxer, MuxerOptions>) => {
31
+ describe('close', () => {
32
+ it('closing underlying socket closes streams (tcp)', async () => {
33
+ const mockConn = (muxer: Muxer): Connection => {
34
+ // @ts-expect-error not all Connection methods are implemented
35
+ const connection: Connection = {
36
+ newStream: async (multicodecs) => {
37
+ return {
38
+ protocol: multicodecs[0],
39
+ stream: muxer.newStream(`${multicodecs[0]}`)
40
+ }
41
+ }
42
+ }
43
+
44
+ return connection
45
+ }
46
+
47
+ const mockUpgrade = async (maConn: any) => {
48
+ const muxer = await common.setup({
49
+ onStream: (stream) => {
50
+ pipe(stream, stream)
51
+ }
52
+ })
53
+ pipe(maConn, muxer, maConn)
54
+ return mockConn(muxer)
55
+ }
56
+
57
+ const [local, remote] = pair()
58
+ const controller = new AbortController()
59
+ const abortableRemote = duplex(remote, controller.signal, {
60
+ returnOnAbort: true
61
+ })
62
+
63
+ await mockUpgrade(abortableRemote)
64
+ const dialerConn = await mockUpgrade(local)
65
+
66
+ const s1 = await dialerConn.newStream([''])
67
+ const s2 = await dialerConn.newStream([''])
68
+
69
+ // close the remote in a bit
70
+ setTimeout(() => controller.abort(), 50)
71
+
72
+ const s1Result = pipe(infiniteRandom, s1, consume)
73
+ const s2Result = pipe(infiniteRandom, s2, consume)
74
+
75
+ // test is complete when all muxed streams have closed
76
+ await s1Result
77
+ await s2Result
78
+ })
79
+
80
+ it('closing one of the muxed streams doesn\'t close others', async () => {
81
+ const p = pair()
82
+ const dialer = await common.setup()
83
+
84
+ // Listener is echo server :)
85
+ const listener = await common.setup({
86
+ onStream: (stream) => pipe(stream, stream)
87
+ })
88
+
89
+ pipe(p[0], dialer, p[0])
90
+ pipe(p[1], listener, p[1])
91
+
92
+ const stream = dialer.newStream()
93
+ const streams = Array.from(Array(5), () => dialer.newStream())
94
+ let closed = false
95
+ const controllers: AbortController[] = []
96
+
97
+ const streamResults = streams.map(async stream => {
98
+ const controller = new AbortController()
99
+ controllers.push(controller)
100
+
101
+ try {
102
+ const abortableRand = source(infiniteRandom, controller.signal, { abortCode: 'ERR_TEST_ABORT' })
103
+ await pipe(abortableRand, stream, consume)
104
+ } catch (err: any) {
105
+ if (err.code !== 'ERR_TEST_ABORT') throw err
106
+ }
107
+
108
+ if (!closed) throw new Error('stream should not have ended yet!')
109
+ })
110
+
111
+ // Pause, and then send some data and close the first stream
112
+ await pause(50)
113
+ await pipe([randomBuffer()], stream, consume)
114
+ closed = true
115
+
116
+ // Abort all the other streams later
117
+ await pause(50)
118
+ controllers.forEach(c => c.abort())
119
+
120
+ // These should now all resolve without error
121
+ await Promise.all(streamResults)
122
+ })
123
+ })
124
+ }
@@ -0,0 +1,15 @@
1
+ import baseTest from './base-test.js'
2
+ import closeTest from './close-test.js'
3
+ import stressTest from './stress-test.js'
4
+ import megaStressTest from './mega-stress-test.js'
5
+ import type { TestSetup } from '../index.js'
6
+ import type { Muxer } from '@libp2p/interfaces/stream-muxer'
7
+
8
+ export default (common: TestSetup<Muxer>) => {
9
+ describe('interface-stream-muxer', () => {
10
+ baseTest(common)
11
+ closeTest(common)
12
+ stressTest(common)
13
+ megaStressTest(common)
14
+ })
15
+ }
@@ -0,0 +1,11 @@
1
+ import spawn from './spawner'
2
+ import type { TestSetup } from '../index.js'
3
+ import type { Muxer, MuxerOptions } from '@libp2p/interfaces/stream-muxer'
4
+
5
+ export default (common: TestSetup<Muxer, MuxerOptions>) => {
6
+ const createMuxer = async (opts?: MuxerOptions) => await common.setup(opts)
7
+
8
+ describe.skip('mega stress test', function () {
9
+ it('10,000 streams with 10,000 msg', async () => await spawn(createMuxer, 10000, 10000, 5000))
10
+ })
11
+ }
@@ -0,0 +1,52 @@
1
+ import { expect } from 'aegir/utils/chai.js'
2
+ // @ts-expect-error no types
3
+ import pair from 'it-pair/duplex.js'
4
+ import { pipe } from 'it-pipe'
5
+ import pLimit from 'p-limit'
6
+ import { collect, consume } from 'streaming-iterables'
7
+ import type { Muxer, MuxerOptions } from '@libp2p/interfaces/stream-muxer'
8
+
9
+ export default async (createMuxer: (options?: MuxerOptions) => Promise<Muxer>, nStreams: number, nMsg: number, limit?: number) => {
10
+ const [dialerSocket, listenerSocket] = pair()
11
+
12
+ const msg = 'simple msg'
13
+
14
+ const listener = await createMuxer({
15
+ onStream: async (stream) => {
16
+ await pipe(
17
+ stream,
18
+ consume
19
+ )
20
+
21
+ pipe([], stream)
22
+ }
23
+ })
24
+
25
+ const dialer = await createMuxer()
26
+
27
+ pipe(listenerSocket, listener, listenerSocket)
28
+ pipe(dialerSocket, dialer, dialerSocket)
29
+
30
+ const spawnStream = async () => {
31
+ const stream = dialer.newStream()
32
+ expect(stream).to.exist // eslint-disable-line
33
+
34
+ const res = await pipe(
35
+ (function * () {
36
+ for (let i = 0; i < nMsg; i++) {
37
+ yield new Promise(resolve => resolve(msg))
38
+ }
39
+ })(),
40
+ stream,
41
+ collect
42
+ )
43
+
44
+ expect(res).to.be.eql([])
45
+ }
46
+
47
+ const limiter = pLimit(limit ?? Infinity)
48
+
49
+ await Promise.all(
50
+ Array.from(Array(nStreams), async () => await limiter(async () => await spawnStream()))
51
+ )
52
+ }
@@ -0,0 +1,24 @@
1
+ import spawn from './spawner'
2
+ import type { TestSetup } from '../index.js'
3
+ import type { Muxer, MuxerOptions } from '@libp2p/interfaces/stream-muxer'
4
+
5
+ export default (common: TestSetup<Muxer, MuxerOptions>) => {
6
+ const createMuxer = async (opts?: MuxerOptions) => await common.setup(opts)
7
+
8
+ describe('stress test', () => {
9
+ it('1 stream with 1 msg', async () => await spawn(createMuxer, 1, 1))
10
+ it('1 stream with 10 msg', async () => await spawn(createMuxer, 1, 10))
11
+ it('1 stream with 100 msg', async () => await spawn(createMuxer, 1, 100))
12
+ it('10 streams with 1 msg', async () => await spawn(createMuxer, 10, 1))
13
+ it('10 streams with 10 msg', async () => await spawn(createMuxer, 10, 10))
14
+ it('10 streams with 100 msg', async () => await spawn(createMuxer, 10, 100))
15
+ it('100 streams with 1 msg', async () => await spawn(createMuxer, 100, 1))
16
+ it('100 streams with 10 msg', async () => await spawn(createMuxer, 100, 10))
17
+ it('100 streams with 100 msg', async () => await spawn(createMuxer, 100, 100))
18
+ it('1000 streams with 1 msg', async () => await spawn(createMuxer, 1000, 1))
19
+ it('1000 streams with 10 msg', async () => await spawn(createMuxer, 1000, 10))
20
+ it('1000 streams with 100 msg', async function () {
21
+ return await spawn(createMuxer, 1000, 100)
22
+ })
23
+ })
24
+ }
@@ -0,0 +1,136 @@
1
+ import { expect } from 'aegir/utils/chai.js'
2
+ import sinon from 'sinon'
3
+ import * as PeerIdFactory from '@libp2p/peer-id-factory'
4
+ import peers from '../utils/peers.js'
5
+ import type { TestSetup } from '../index.js'
6
+ import type { MulticodecTopology } from '@libp2p/interfaces/topology'
7
+ import type { PeerId } from '@libp2p/interfaces/peer-id'
8
+
9
+ export default (test: TestSetup<MulticodecTopology>) => {
10
+ describe('multicodec topology', () => {
11
+ let topology: MulticodecTopology, id: PeerId
12
+
13
+ beforeEach(async () => {
14
+ topology = await test.setup()
15
+
16
+ id = await PeerIdFactory.createFromJSON(peers[0])
17
+ })
18
+
19
+ afterEach(async () => {
20
+ sinon.restore()
21
+ await test.teardown()
22
+ })
23
+
24
+ it('should have properties set', () => {
25
+ expect(topology.multicodecs).to.exist()
26
+ expect(topology.peers).to.exist()
27
+ })
28
+
29
+ it('should trigger "onDisconnect" on peer disconnected', () => {
30
+ // @ts-expect-error protected property
31
+ sinon.spy(topology, '_onDisconnect')
32
+ topology.disconnect(id)
33
+
34
+ expect(topology).to.have.nested.property('_onDisconnect.callCount', 1)
35
+ })
36
+
37
+ it('should update peers on protocol change', async () => {
38
+ // @ts-expect-error protected property
39
+ sinon.spy(topology, '_updatePeers')
40
+ expect(topology.peers.size).to.eql(0)
41
+
42
+ // @ts-expect-error protected property
43
+ const peerStore = topology._registrar.peerStore
44
+
45
+ const id2 = await PeerIdFactory.createFromJSON(peers[1])
46
+ peerStore.peers.set(id2.toString(), {
47
+ id: id2,
48
+ protocols: Array.from(topology.multicodecs)
49
+ })
50
+
51
+ peerStore.emit('change:protocols', {
52
+ peerId: id2,
53
+ protocols: Array.from(topology.multicodecs)
54
+ })
55
+
56
+ expect(topology).to.have.nested.property('_updatePeers.callCount', 1)
57
+ expect(topology.peers.size).to.eql(1)
58
+ })
59
+
60
+ it('should disconnect if peer no longer supports a protocol', async () => {
61
+ // @ts-expect-error protected property
62
+ sinon.spy(topology, '_onDisconnect')
63
+ expect(topology.peers.size).to.eql(0)
64
+
65
+ // @ts-expect-error protected property
66
+ const peerStore = topology._registrar.peerStore
67
+
68
+ const id2 = await PeerIdFactory.createFromJSON(peers[1])
69
+ peerStore.peers.set(id2.toString(), {
70
+ id: id2,
71
+ protocols: Array.from(topology.multicodecs)
72
+ })
73
+
74
+ peerStore.emit('change:protocols', {
75
+ peerId: id2,
76
+ protocols: Array.from(topology.multicodecs)
77
+ })
78
+
79
+ expect(topology.peers.size).to.eql(1)
80
+
81
+ peerStore.peers.set(id2.toString(), {
82
+ id: id2,
83
+ protocols: []
84
+ })
85
+ // Peer does not support the protocol anymore
86
+ peerStore.emit('change:protocols', {
87
+ peerId: id2,
88
+ protocols: []
89
+ })
90
+
91
+ expect(topology.peers.size).to.eql(1)
92
+ expect(topology).to.have.nested.property('_onDisconnect.callCount', 1)
93
+ // @ts-expect-error protected property
94
+ expect(topology._onDisconnect.calledWith(id2)).to.equal(true)
95
+ })
96
+
97
+ it('should trigger "onConnect" when a peer connects and has one of the topology multicodecs in its known protocols', () => {
98
+ // @ts-expect-error protected property
99
+ sinon.spy(topology, '_onConnect')
100
+ // @ts-expect-error protected property
101
+ sinon.stub(topology._registrar.peerStore.protoBook, 'get').returns(topology.multicodecs)
102
+ // @ts-expect-error protected property
103
+ topology._registrar.connectionManager.emit('peer:connect', {
104
+ remotePeer: id
105
+ })
106
+
107
+ expect(topology).to.have.nested.property('_onConnect.callCount', 1)
108
+ })
109
+
110
+ it('should not trigger "onConnect" when a peer connects and has none of the topology multicodecs in its known protocols', () => {
111
+ // @ts-expect-error protected property
112
+ sinon.spy(topology, '_onConnect')
113
+ // @ts-expect-error protected property
114
+ sinon.stub(topology._registrar.peerStore.protoBook, 'get').returns([])
115
+ // @ts-expect-error protected property
116
+ topology._registrar.connectionManager.emit('peer:connect', {
117
+ remotePeer: id
118
+ })
119
+
120
+ expect(topology).to.have.nested.property('_onConnect.callCount', 0)
121
+ })
122
+
123
+ it('should not trigger "onConnect" when a peer connects and its protocols are not known', () => {
124
+ // @ts-expect-error protected property
125
+ sinon.spy(topology, '_onConnect')
126
+ // @ts-expect-error protected property
127
+ sinon.stub(topology._registrar.peerStore.protoBook, 'get').returns(undefined)
128
+ // @ts-expect-error protected property
129
+ topology._registrar.connectionManager.emit('peer:connect', {
130
+ remotePeer: id
131
+ })
132
+
133
+ expect(topology).to.have.nested.property('_onConnect.callCount', 0)
134
+ })
135
+ })
136
+ }
@@ -0,0 +1,38 @@
1
+ import { expect } from 'aegir/utils/chai.js'
2
+ import sinon from 'sinon'
3
+ import * as PeerIdFactory from '@libp2p/peer-id-factory'
4
+ import peers from '../utils/peers.js'
5
+ import type { TestSetup } from '../index.js'
6
+ import type { Topology } from '@libp2p/interfaces/topology'
7
+ import type { PeerId } from '@libp2p/interfaces/peer-id'
8
+
9
+ export default (test: TestSetup<Topology>) => {
10
+ describe('topology', () => {
11
+ let topology: Topology, id: PeerId
12
+
13
+ beforeEach(async () => {
14
+ topology = await test.setup()
15
+
16
+ id = await PeerIdFactory.createFromJSON(peers[0])
17
+ })
18
+
19
+ afterEach(async () => {
20
+ sinon.restore()
21
+ await test.teardown()
22
+ })
23
+
24
+ it('should have properties set', () => {
25
+ expect(topology.min).to.exist()
26
+ expect(topology.max).to.exist()
27
+ expect(topology.peers).to.exist()
28
+ })
29
+
30
+ it('should trigger "onDisconnect" on peer disconnected', () => {
31
+ // @ts-expect-error protected property
32
+ sinon.spy(topology, '_onDisconnect')
33
+ topology.disconnect(id)
34
+
35
+ expect(topology).to.have.nested.property('_onDisconnect.callCount', 1)
36
+ })
37
+ })
38
+ }
@@ -0,0 +1,98 @@
1
+ import { expect } from 'aegir/utils/chai.js'
2
+ import { isValidTick, mockUpgrader } from './utils/index.js'
3
+ // @ts-expect-error no types
4
+ import goodbye from 'it-goodbye'
5
+ import { collect } from 'streaming-iterables'
6
+ import { pipe } from 'it-pipe'
7
+ import AbortController from 'abort-controller'
8
+ import { AbortError } from '@libp2p/interfaces/errors'
9
+ import sinon from 'sinon'
10
+ import type { TestSetup } from '../index.js'
11
+ import type { Transport, Listener } from '@libp2p/interfaces/transport'
12
+ import type { TransportTestFixtures, SetupArgs, Connector } from './index.js'
13
+ import type { Multiaddr } from '@multiformats/multiaddr'
14
+
15
+ export default (common: TestSetup<TransportTestFixtures, SetupArgs>) => {
16
+ describe('dial', () => {
17
+ const upgrader = mockUpgrader()
18
+ let addrs: Multiaddr[]
19
+ let transport: Transport<any, any>
20
+ let connector: Connector
21
+ let listener: Listener
22
+
23
+ before(async () => {
24
+ ({ addrs, transport, connector } = await common.setup({ upgrader }))
25
+ })
26
+
27
+ after(async () => {
28
+ await common.teardown()
29
+ })
30
+
31
+ beforeEach(async () => {
32
+ listener = transport.createListener({})
33
+ return await listener.listen(addrs[0])
34
+ })
35
+
36
+ afterEach(async () => {
37
+ sinon.restore()
38
+ connector.restore()
39
+ return await listener.close()
40
+ })
41
+
42
+ it('simple', async () => {
43
+ const upgradeSpy = sinon.spy(upgrader, 'upgradeOutbound')
44
+ const conn = await transport.dial(addrs[0])
45
+ const { stream } = await conn.newStream(['/hello'])
46
+ const s = goodbye({ source: ['hey'], sink: collect })
47
+
48
+ const result = await pipe(s, stream, s)
49
+
50
+ expect(upgradeSpy.callCount).to.equal(1)
51
+ await expect(upgradeSpy.getCall(0).returnValue).to.eventually.equal(conn)
52
+ expect(result.length).to.equal(1)
53
+ expect(result[0].toString()).to.equal('hey')
54
+ await conn.close()
55
+ })
56
+
57
+ it('can close connections', async () => {
58
+ const upgradeSpy = sinon.spy(upgrader, 'upgradeOutbound')
59
+ const conn = await transport.dial(addrs[0])
60
+
61
+ expect(upgradeSpy.callCount).to.equal(1)
62
+ await expect(upgradeSpy.getCall(0).returnValue).to.eventually.equal(conn)
63
+ await conn.close()
64
+ expect(isValidTick(conn.stat.timeline.close)).to.equal(true)
65
+ })
66
+
67
+ it('to non existent listener', async () => {
68
+ const upgradeSpy = sinon.spy(upgrader, 'upgradeOutbound')
69
+
70
+ await expect(transport.dial(addrs[1])).to.eventually.be.rejected()
71
+ expect(upgradeSpy.callCount).to.equal(0)
72
+ })
73
+
74
+ it('abort before dialing throws AbortError', async () => {
75
+ const upgradeSpy = sinon.spy(upgrader, 'upgradeOutbound')
76
+ const controller = new AbortController()
77
+ controller.abort()
78
+ const conn = transport.dial(addrs[0], { signal: controller.signal })
79
+
80
+ await expect(conn).to.eventually.be.rejected().with.property('code', AbortError.code)
81
+ expect(upgradeSpy.callCount).to.equal(0)
82
+ })
83
+
84
+ it('abort while dialing throws AbortError', async () => {
85
+ const upgradeSpy = sinon.spy(upgrader, 'upgradeOutbound')
86
+ // Add a delay to connect() so that we can abort while the dial is in
87
+ // progress
88
+ connector.delay(100)
89
+
90
+ const controller = new AbortController()
91
+ const conn = transport.dial(addrs[0], { signal: controller.signal })
92
+ setTimeout(() => controller.abort(), 50)
93
+
94
+ await expect(conn).to.eventually.be.rejected().with.property('code', AbortError.code)
95
+ expect(upgradeSpy.callCount).to.equal(0)
96
+ })
97
+ })
98
+ }
@@ -0,0 +1,26 @@
1
+ import { expect } from 'aegir/utils/chai.js'
2
+ import { mockUpgrader } from './utils/index.js'
3
+ import type { TestSetup } from '../index.js'
4
+ import type { Transport } from '@libp2p/interfaces/transport'
5
+ import type { TransportTestFixtures, SetupArgs } from './index.js'
6
+ import type { Multiaddr } from '@multiformats/multiaddr'
7
+
8
+ export default (common: TestSetup<TransportTestFixtures, SetupArgs>) => {
9
+ describe('filter', () => {
10
+ let addrs: Multiaddr[]
11
+ let transport: Transport<any, any>
12
+
13
+ before(async () => {
14
+ ({ addrs, transport } = await common.setup({ upgrader: mockUpgrader() }))
15
+ })
16
+
17
+ after(async () => {
18
+ await common.teardown()
19
+ })
20
+
21
+ it('filters addresses', () => {
22
+ const filteredAddrs = transport.filter(addrs)
23
+ expect(filteredAddrs).to.eql(addrs)
24
+ })
25
+ })
26
+ }