@libp2p/interface-compliance-tests 6.4.16 → 6.5.0-6059227cb
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/connection-encryption/index.d.ts.map +1 -1
- package/dist/src/connection-encryption/index.js +24 -15
- package/dist/src/connection-encryption/index.js.map +1 -1
- package/dist/src/stream-muxer/base-test.d.ts.map +1 -1
- package/dist/src/stream-muxer/base-test.js +62 -341
- package/dist/src/stream-muxer/base-test.js.map +1 -1
- package/dist/src/stream-muxer/close-test.d.ts.map +1 -1
- package/dist/src/stream-muxer/close-test.js +255 -305
- package/dist/src/stream-muxer/close-test.js.map +1 -1
- package/dist/src/stream-muxer/index.js +2 -2
- package/dist/src/stream-muxer/index.js.map +1 -1
- package/dist/src/stream-muxer/{mega-stress-test.d.ts → stream-test.d.ts} +2 -2
- package/dist/src/stream-muxer/stream-test.d.ts.map +1 -0
- package/dist/src/stream-muxer/stream-test.js +290 -0
- package/dist/src/stream-muxer/stream-test.js.map +1 -0
- package/dist/src/stream-muxer/stress-test.d.ts.map +1 -1
- package/dist/src/stream-muxer/stress-test.js +70 -16
- package/dist/src/stream-muxer/stress-test.js.map +1 -1
- package/dist/src/transport/index.d.ts.map +1 -1
- package/dist/src/transport/index.js +235 -205
- package/dist/src/transport/index.js.map +1 -1
- package/dist/src/transport/utils.d.ts.map +1 -1
- package/dist/src/transport/utils.js +3 -2
- package/dist/src/transport/utils.js.map +1 -1
- package/package.json +23 -51
- package/src/connection-encryption/index.ts +27 -20
- package/src/stream-muxer/base-test.ts +75 -409
- package/src/stream-muxer/close-test.ts +305 -327
- package/src/stream-muxer/index.ts +2 -2
- package/src/stream-muxer/stream-test.ts +381 -0
- package/src/stream-muxer/stress-test.ts +92 -18
- package/src/transport/index.ts +281 -241
- package/src/transport/utils.ts +3 -2
- package/dist/src/connection-encryption/utils/index.d.ts +0 -3
- package/dist/src/connection-encryption/utils/index.d.ts.map +0 -1
- package/dist/src/connection-encryption/utils/index.js +0 -21
- package/dist/src/connection-encryption/utils/index.js.map +0 -1
- package/dist/src/matchers.d.ts +0 -12
- package/dist/src/matchers.d.ts.map +0 -1
- package/dist/src/matchers.js +0 -14
- package/dist/src/matchers.js.map +0 -1
- package/dist/src/mocks/connection-manager.d.ts +0 -27
- package/dist/src/mocks/connection-manager.d.ts.map +0 -1
- package/dist/src/mocks/connection-manager.js +0 -147
- package/dist/src/mocks/connection-manager.js.map +0 -1
- package/dist/src/mocks/connection.d.ts +0 -41
- package/dist/src/mocks/connection.d.ts.map +0 -1
- package/dist/src/mocks/connection.js +0 -234
- package/dist/src/mocks/connection.js.map +0 -1
- package/dist/src/mocks/duplex.d.ts +0 -4
- package/dist/src/mocks/duplex.d.ts.map +0 -1
- package/dist/src/mocks/duplex.js +0 -9
- package/dist/src/mocks/duplex.js.map +0 -1
- package/dist/src/mocks/index.d.ts +0 -12
- package/dist/src/mocks/index.d.ts.map +0 -1
- package/dist/src/mocks/index.js +0 -8
- package/dist/src/mocks/index.js.map +0 -1
- package/dist/src/mocks/multiaddr-connection.d.ts +0 -17
- package/dist/src/mocks/multiaddr-connection.d.ts.map +0 -1
- package/dist/src/mocks/multiaddr-connection.js +0 -64
- package/dist/src/mocks/multiaddr-connection.js.map +0 -1
- package/dist/src/mocks/muxer.d.ts +0 -36
- package/dist/src/mocks/muxer.d.ts.map +0 -1
- package/dist/src/mocks/muxer.js +0 -234
- package/dist/src/mocks/muxer.js.map +0 -1
- package/dist/src/mocks/registrar.d.ts +0 -16
- package/dist/src/mocks/registrar.d.ts.map +0 -1
- package/dist/src/mocks/registrar.js +0 -66
- package/dist/src/mocks/registrar.js.map +0 -1
- package/dist/src/mocks/upgrader.d.ts +0 -9
- package/dist/src/mocks/upgrader.d.ts.map +0 -1
- package/dist/src/mocks/upgrader.js +0 -46
- package/dist/src/mocks/upgrader.js.map +0 -1
- package/dist/src/pubsub/api.d.ts +0 -6
- package/dist/src/pubsub/api.d.ts.map +0 -1
- package/dist/src/pubsub/api.js +0 -88
- package/dist/src/pubsub/api.js.map +0 -1
- package/dist/src/pubsub/connection-handlers.d.ts +0 -6
- package/dist/src/pubsub/connection-handlers.d.ts.map +0 -1
- package/dist/src/pubsub/connection-handlers.js +0 -329
- package/dist/src/pubsub/connection-handlers.js.map +0 -1
- package/dist/src/pubsub/emit-self.d.ts +0 -6
- package/dist/src/pubsub/emit-self.d.ts.map +0 -1
- package/dist/src/pubsub/emit-self.js +0 -80
- package/dist/src/pubsub/emit-self.js.map +0 -1
- package/dist/src/pubsub/index.d.ts +0 -18
- package/dist/src/pubsub/index.d.ts.map +0 -1
- package/dist/src/pubsub/index.js +0 -17
- package/dist/src/pubsub/index.js.map +0 -1
- package/dist/src/pubsub/messages.d.ts +0 -6
- package/dist/src/pubsub/messages.d.ts.map +0 -1
- package/dist/src/pubsub/messages.js +0 -48
- package/dist/src/pubsub/messages.js.map +0 -1
- package/dist/src/pubsub/multiple-nodes.d.ts +0 -6
- package/dist/src/pubsub/multiple-nodes.d.ts.map +0 -1
- package/dist/src/pubsub/multiple-nodes.js +0 -350
- package/dist/src/pubsub/multiple-nodes.js.map +0 -1
- package/dist/src/pubsub/two-nodes.d.ts +0 -6
- package/dist/src/pubsub/two-nodes.d.ts.map +0 -1
- package/dist/src/pubsub/two-nodes.js +0 -216
- package/dist/src/pubsub/two-nodes.js.map +0 -1
- package/dist/src/pubsub/utils.d.ts +0 -5
- package/dist/src/pubsub/utils.d.ts.map +0 -1
- package/dist/src/pubsub/utils.js +0 -27
- package/dist/src/pubsub/utils.js.map +0 -1
- package/dist/src/stream-muxer/mega-stress-test.d.ts.map +0 -1
- package/dist/src/stream-muxer/mega-stress-test.js +0 -11
- package/dist/src/stream-muxer/mega-stress-test.js.map +0 -1
- package/dist/src/stream-muxer/spawner.d.ts +0 -4
- package/dist/src/stream-muxer/spawner.d.ts.map +0 -1
- package/dist/src/stream-muxer/spawner.js +0 -37
- package/dist/src/stream-muxer/spawner.js.map +0 -1
- package/dist/typedoc-urls.json +0 -44
- package/src/connection-encryption/utils/index.ts +0 -27
- package/src/matchers.ts +0 -18
- package/src/mocks/connection-manager.ts +0 -216
- package/src/mocks/connection.ts +0 -307
- package/src/mocks/duplex.ts +0 -11
- package/src/mocks/index.ts +0 -11
- package/src/mocks/multiaddr-connection.ts +0 -80
- package/src/mocks/muxer.ts +0 -331
- package/src/mocks/registrar.ts +0 -86
- package/src/mocks/upgrader.ts +0 -65
- package/src/pubsub/api.ts +0 -116
- package/src/pubsub/connection-handlers.ts +0 -413
- package/src/pubsub/emit-self.ts +0 -99
- package/src/pubsub/index.ts +0 -34
- package/src/pubsub/messages.ts +0 -59
- package/src/pubsub/multiple-nodes.ts +0 -440
- package/src/pubsub/two-nodes.ts +0 -272
- package/src/pubsub/utils.ts +0 -34
- package/src/stream-muxer/mega-stress-test.ts +0 -14
- package/src/stream-muxer/spawner.ts +0 -55
package/src/transport/index.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { stop } from '@libp2p/interface'
|
|
1
|
+
import { stop, TimeoutError } from '@libp2p/interface'
|
|
2
|
+
import { prefixLogger } from '@libp2p/logger'
|
|
2
3
|
import { expect } from 'aegir/chai'
|
|
3
4
|
import delay from 'delay'
|
|
5
|
+
import all from 'it-all'
|
|
4
6
|
import drain from 'it-drain'
|
|
5
7
|
import { pushable } from 'it-pushable'
|
|
6
|
-
import pDefer from 'p-defer'
|
|
7
8
|
import { pEvent } from 'p-event'
|
|
8
9
|
import pRetry from 'p-retry'
|
|
9
10
|
import pWaitFor from 'p-wait-for'
|
|
10
11
|
import { raceSignal } from 'race-signal'
|
|
12
|
+
import { Uint8ArrayList } from 'uint8arraylist'
|
|
11
13
|
import { isValidTick } from '../is-valid-tick.js'
|
|
12
14
|
import { createPeer, getTransportManager, getUpgrader } from './utils.js'
|
|
13
15
|
import type { TestSetup } from '../index.js'
|
|
@@ -16,7 +18,6 @@ import type { Connection, Libp2p, Stream, StreamHandler } from '@libp2p/interfac
|
|
|
16
18
|
import type { Multiaddr } from '@multiformats/multiaddr'
|
|
17
19
|
import type { MultiaddrMatcher } from '@multiformats/multiaddr-matcher'
|
|
18
20
|
import type { Libp2pInit } from 'libp2p'
|
|
19
|
-
import type { DeferredPromise } from 'p-defer'
|
|
20
21
|
|
|
21
22
|
export interface TransportTestFixtures {
|
|
22
23
|
/**
|
|
@@ -48,34 +49,113 @@ export interface TransportTestFixtures {
|
|
|
48
49
|
|
|
49
50
|
async function getSetup (common: TestSetup<TransportTestFixtures>): Promise<{ dialer: Libp2p<{ echo: Echo }>, listener?: Libp2p<{ echo: Echo }>, dialAddrs: Multiaddr[], dialMultiaddrMatcher: MultiaddrMatcher, listenMultiaddrMatcher: MultiaddrMatcher }> {
|
|
50
51
|
const setup = await common.setup()
|
|
51
|
-
const dialer = await createPeer(
|
|
52
|
+
const dialer = await createPeer({
|
|
53
|
+
logger: prefixLogger('dialer'),
|
|
54
|
+
...setup.dialer
|
|
55
|
+
})
|
|
52
56
|
let listener
|
|
53
57
|
|
|
54
58
|
if (setup.listener != null) {
|
|
55
|
-
listener = await createPeer(
|
|
59
|
+
listener = await createPeer({
|
|
60
|
+
logger: prefixLogger('listener'),
|
|
61
|
+
...setup.listener
|
|
62
|
+
})
|
|
56
63
|
}
|
|
57
64
|
|
|
58
|
-
|
|
65
|
+
let dialAddrs = listener?.getMultiaddrs() ?? setup.dialAddrs
|
|
59
66
|
|
|
60
67
|
if (dialAddrs == null) {
|
|
61
68
|
throw new Error('Listener config or dial addresses must be specified')
|
|
62
69
|
}
|
|
63
70
|
|
|
71
|
+
dialAddrs = dialAddrs.filter(ma => setup.dialMultiaddrMatcher.exactMatch(ma))
|
|
72
|
+
|
|
73
|
+
if (dialAddrs.length === 0) {
|
|
74
|
+
throw new Error('Listener was not listening on any addresses that the dialMultiaddrMatcher matched')
|
|
75
|
+
}
|
|
76
|
+
|
|
64
77
|
return {
|
|
65
78
|
dialer,
|
|
66
79
|
listener,
|
|
67
|
-
dialAddrs
|
|
80
|
+
dialAddrs,
|
|
68
81
|
dialMultiaddrMatcher: setup.dialMultiaddrMatcher,
|
|
69
82
|
listenMultiaddrMatcher: setup.listenMultiaddrMatcher
|
|
70
83
|
}
|
|
71
84
|
}
|
|
72
85
|
|
|
73
86
|
export default (common: TestSetup<TransportTestFixtures>): void => {
|
|
87
|
+
describe('transport events', () => {
|
|
88
|
+
let dialer: Libp2p<{ echo: Echo }>
|
|
89
|
+
let listener: Libp2p<{ echo: Echo }> | undefined
|
|
90
|
+
let listenMultiaddrMatcher: MultiaddrMatcher
|
|
91
|
+
|
|
92
|
+
afterEach(async () => {
|
|
93
|
+
await stop(dialer, listener)
|
|
94
|
+
await common.teardown()
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it('emits listening', async function () {
|
|
98
|
+
({ dialer, listener, listenMultiaddrMatcher } = await getSetup(common))
|
|
99
|
+
|
|
100
|
+
if (listener == null) {
|
|
101
|
+
return this.skip()
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
await listener.stop()
|
|
105
|
+
|
|
106
|
+
const transportListeningPromise = Promise.withResolvers<void>()
|
|
107
|
+
|
|
108
|
+
listener.addEventListener('transport:listening', (event) => {
|
|
109
|
+
const transportListener = event.detail
|
|
110
|
+
|
|
111
|
+
if (transportListener.getAddrs().some(ma => listenMultiaddrMatcher.exactMatch(ma))) {
|
|
112
|
+
transportListeningPromise.resolve()
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
await listener.start()
|
|
117
|
+
|
|
118
|
+
await raceSignal(transportListeningPromise.promise, AbortSignal.timeout(1000), {
|
|
119
|
+
translateError: () => {
|
|
120
|
+
return new TimeoutError('Did not emit listening event')
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
it('emits close', async function () {
|
|
126
|
+
({ dialer, listener } = await getSetup(common))
|
|
127
|
+
|
|
128
|
+
if (listener == null) {
|
|
129
|
+
return this.skip()
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const transportManager = getTransportManager(listener)
|
|
133
|
+
const transportListener = transportManager.getListeners()
|
|
134
|
+
.filter(listener => listener.getAddrs().some(ma => listenMultiaddrMatcher.exactMatch(ma)))
|
|
135
|
+
.pop()
|
|
136
|
+
|
|
137
|
+
if (transportListener == null) {
|
|
138
|
+
throw new Error('Could not find address listener')
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const p = pEvent(transportListener, 'close')
|
|
142
|
+
|
|
143
|
+
await listener.stop()
|
|
144
|
+
|
|
145
|
+
await raceSignal(p, AbortSignal.timeout(1000), {
|
|
146
|
+
translateError: () => {
|
|
147
|
+
return new TimeoutError('Did not emit close event')
|
|
148
|
+
}
|
|
149
|
+
})
|
|
150
|
+
})
|
|
151
|
+
})
|
|
152
|
+
|
|
74
153
|
describe('interface-transport', () => {
|
|
75
154
|
let dialer: Libp2p<{ echo: Echo }>
|
|
76
155
|
let listener: Libp2p<{ echo: Echo }> | undefined
|
|
77
156
|
let dialAddrs: Multiaddr[]
|
|
78
157
|
let dialMultiaddrMatcher: MultiaddrMatcher
|
|
158
|
+
let listenMultiaddrMatcher: MultiaddrMatcher
|
|
79
159
|
|
|
80
160
|
afterEach(async () => {
|
|
81
161
|
await stop(dialer, listener)
|
|
@@ -90,7 +170,7 @@ export default (common: TestSetup<TransportTestFixtures>): void => {
|
|
|
90
170
|
signal: AbortSignal.timeout(5000)
|
|
91
171
|
})
|
|
92
172
|
|
|
93
|
-
expect(output).to.equalBytes(input)
|
|
173
|
+
expect(output.subarray()).to.equalBytes(input)
|
|
94
174
|
})
|
|
95
175
|
|
|
96
176
|
it('should listen on multiple addresses', async () => {
|
|
@@ -98,13 +178,16 @@ export default (common: TestSetup<TransportTestFixtures>): void => {
|
|
|
98
178
|
|
|
99
179
|
const input = Uint8Array.from([0, 1, 2, 3, 4])
|
|
100
180
|
|
|
101
|
-
await
|
|
181
|
+
const output1 = await dialer.services.echo.echo(dialAddrs[0], input, {
|
|
102
182
|
signal: AbortSignal.timeout(5000)
|
|
103
|
-
})
|
|
183
|
+
})
|
|
184
|
+
expect(output1.subarray()).to.equalBytes(input)
|
|
104
185
|
|
|
105
|
-
await
|
|
106
|
-
signal: AbortSignal.timeout(5000)
|
|
107
|
-
|
|
186
|
+
const output2 = await dialer.services.echo.echo(dialAddrs[1], input, {
|
|
187
|
+
signal: AbortSignal.timeout(5000),
|
|
188
|
+
force: true
|
|
189
|
+
})
|
|
190
|
+
expect(output2.subarray()).to.equalBytes(input)
|
|
108
191
|
})
|
|
109
192
|
|
|
110
193
|
it('can close connections', async () => {
|
|
@@ -131,16 +214,20 @@ export default (common: TestSetup<TransportTestFixtures>): void => {
|
|
|
131
214
|
})
|
|
132
215
|
|
|
133
216
|
it('should close all streams when the connection closes', async () => {
|
|
134
|
-
({ dialer, listener, dialAddrs } = await getSetup(common))
|
|
217
|
+
({ dialer, listener, dialAddrs, listenMultiaddrMatcher } = await getSetup(common))
|
|
135
218
|
|
|
136
|
-
let incomingConnectionPromise:
|
|
219
|
+
let incomingConnectionPromise: PromiseWithResolvers<Connection> | undefined
|
|
137
220
|
|
|
138
221
|
if (listener != null) {
|
|
139
|
-
incomingConnectionPromise =
|
|
222
|
+
incomingConnectionPromise = Promise.withResolvers<Connection>()
|
|
140
223
|
|
|
141
224
|
listener.addEventListener('connection:open', (event) => {
|
|
142
225
|
const conn = event.detail
|
|
143
226
|
|
|
227
|
+
if (!listenMultiaddrMatcher.matches(conn.remoteAddr)) {
|
|
228
|
+
return
|
|
229
|
+
}
|
|
230
|
+
|
|
144
231
|
if (conn.remotePeer.equals(dialer.peerId)) {
|
|
145
232
|
incomingConnectionPromise?.resolve(conn)
|
|
146
233
|
}
|
|
@@ -160,22 +247,29 @@ export default (common: TestSetup<TransportTestFixtures>): void => {
|
|
|
160
247
|
})
|
|
161
248
|
}
|
|
162
249
|
|
|
163
|
-
|
|
250
|
+
expect(connection).to.have.property('streams').that.has.lengthOf(5)
|
|
251
|
+
|
|
252
|
+
if (remoteConn != null) {
|
|
253
|
+
await pWaitFor(() => remoteConn.streams.filter(s => s.protocol === '/echo/1.0.0').length === 5, {
|
|
254
|
+
timeout: 5_000,
|
|
255
|
+
interval: 1_000
|
|
256
|
+
})
|
|
257
|
+
}
|
|
164
258
|
|
|
165
259
|
// Close the connection and verify all streams have been closed
|
|
166
|
-
await
|
|
260
|
+
await Promise.all([
|
|
261
|
+
pEvent(connection, 'close'),
|
|
262
|
+
pEvent(remoteConn ?? connection, 'close'),
|
|
263
|
+
connection.close()
|
|
264
|
+
])
|
|
167
265
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
})
|
|
266
|
+
expect(connection).to.have.property('status', 'closed')
|
|
267
|
+
expect(connection).to.have.property('streams').that.is.empty()
|
|
171
268
|
|
|
172
269
|
if (remoteConn != null) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
})
|
|
270
|
+
expect(remoteConn).to.have.property('status', 'closed')
|
|
271
|
+
expect(remoteConn).to.have.property('streams').that.is.empty()
|
|
176
272
|
}
|
|
177
|
-
|
|
178
|
-
expect(streams.find(stream => stream.status === 'open')).to.be.undefined()
|
|
179
273
|
})
|
|
180
274
|
|
|
181
275
|
it('should not handle connection if upgradeInbound rejects', async function () {
|
|
@@ -227,188 +321,137 @@ export default (common: TestSetup<TransportTestFixtures>): void => {
|
|
|
227
321
|
}
|
|
228
322
|
})
|
|
229
323
|
|
|
230
|
-
it('should handle one
|
|
324
|
+
it('should handle one small write', async function () {
|
|
231
325
|
const timeout = 120_000
|
|
232
326
|
this.timeout(timeout);
|
|
233
327
|
({ dialer, listener, dialAddrs } = await getSetup(common))
|
|
234
328
|
|
|
235
|
-
const
|
|
236
|
-
|
|
329
|
+
const connection = await dialer.dial(dialAddrs[0])
|
|
330
|
+
|
|
331
|
+
const input = new Uint8Array(1024).fill(5)
|
|
332
|
+
const output = await dialer.services.echo.echo(connection.remotePeer, input, {
|
|
237
333
|
signal: AbortSignal.timeout(timeout)
|
|
238
334
|
})
|
|
239
335
|
|
|
240
|
-
expect(output).to.equalBytes(input)
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
it('should handle many small writes', async function () {
|
|
244
|
-
const timeout = 360_000
|
|
245
|
-
this.timeout(timeout);
|
|
246
|
-
({ dialer, listener, dialAddrs } = await getSetup(common))
|
|
247
|
-
|
|
248
|
-
for (let i = 0; i < 2000; i++) {
|
|
249
|
-
const input = new Uint8Array(1024).fill(5)
|
|
250
|
-
const output = await dialer.services.echo.echo(dialAddrs[0], input, {
|
|
251
|
-
signal: AbortSignal.timeout(timeout)
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
expect(output).to.equalBytes(input)
|
|
255
|
-
}
|
|
336
|
+
expect(output.subarray()).to.equalBytes(input)
|
|
337
|
+
expect(connection.streams.filter(s => s.protocol === dialer.services.echo.protocol)).to.be.empty()
|
|
256
338
|
})
|
|
257
339
|
|
|
258
|
-
it('
|
|
259
|
-
const timeout =
|
|
340
|
+
it('should handle one big write', async function () {
|
|
341
|
+
const timeout = 540_000
|
|
260
342
|
this.timeout(timeout);
|
|
261
343
|
({ dialer, listener, dialAddrs } = await getSetup(common))
|
|
262
344
|
|
|
263
|
-
|
|
264
|
-
return this.skip()
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
const protocol = '/send-data/1.0.0'
|
|
268
|
-
const chunkSize = 1024
|
|
269
|
-
const bytes = chunkSize * 1024 * 10
|
|
270
|
-
const deferred = pDefer()
|
|
271
|
-
|
|
272
|
-
await listener.handle(protocol, ({ stream }) => {
|
|
273
|
-
Promise.resolve().then(async () => {
|
|
274
|
-
let read = 0
|
|
275
|
-
|
|
276
|
-
for await (const buf of stream.source) {
|
|
277
|
-
read += buf.byteLength
|
|
345
|
+
const connection = await dialer.dial(dialAddrs[0])
|
|
278
346
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
})
|
|
285
|
-
.catch(err => {
|
|
286
|
-
deferred.reject(err)
|
|
287
|
-
stream.abort(err)
|
|
288
|
-
})
|
|
347
|
+
const input = new Uint8Array(1024 * 1024 * 10).fill(5)
|
|
348
|
+
const output = await dialer.services.echo.echo(connection.remotePeer, input, {
|
|
349
|
+
signal: AbortSignal.timeout(timeout)
|
|
289
350
|
})
|
|
290
351
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
await stream.closeRead()
|
|
294
|
-
|
|
295
|
-
await stream.sink((async function * () {
|
|
296
|
-
for (let i = 0; i < bytes; i += chunkSize) {
|
|
297
|
-
yield new Uint8Array(chunkSize)
|
|
298
|
-
}
|
|
299
|
-
})())
|
|
300
|
-
|
|
301
|
-
await stream.close()
|
|
302
|
-
|
|
303
|
-
await deferred.promise
|
|
352
|
+
expect(output.subarray()).to.equalBytes(input)
|
|
353
|
+
expect(connection.streams.filter(s => s.protocol === dialer.services.echo.protocol)).to.be.empty()
|
|
304
354
|
})
|
|
305
355
|
|
|
306
|
-
it('
|
|
307
|
-
const timeout =
|
|
356
|
+
it('should handle many small writes', async function () {
|
|
357
|
+
const timeout = 360_000
|
|
308
358
|
this.timeout(timeout);
|
|
309
359
|
({ dialer, listener, dialAddrs } = await getSetup(common))
|
|
310
360
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
const protocol = '/receive-data/1.0.0'
|
|
316
|
-
const chunkSize = 1024
|
|
317
|
-
const bytes = chunkSize * 1024 * 10
|
|
318
|
-
const deferred = pDefer()
|
|
319
|
-
|
|
320
|
-
await listener.handle(protocol, ({ stream }) => {
|
|
321
|
-
Promise.resolve().then(async () => {
|
|
322
|
-
await stream.sink((async function * () {
|
|
323
|
-
for (let i = 0; i < bytes; i += chunkSize) {
|
|
324
|
-
yield new Uint8Array(chunkSize)
|
|
325
|
-
}
|
|
326
|
-
})())
|
|
361
|
+
const connection = await dialer.dial(dialAddrs[0])
|
|
362
|
+
const echoProtocol = dialer.services.echo.protocol
|
|
327
363
|
|
|
328
|
-
|
|
364
|
+
for (let i = 0; i < 2_000; i++) {
|
|
365
|
+
const input = new Uint8Array(1024).fill(5)
|
|
366
|
+
const output = await dialer.services.echo.echo(connection.remotePeer, input, {
|
|
367
|
+
signal: AbortSignal.timeout(timeout)
|
|
329
368
|
})
|
|
330
|
-
.catch(err => {
|
|
331
|
-
deferred.reject(err)
|
|
332
|
-
stream.abort(err)
|
|
333
|
-
})
|
|
334
|
-
})
|
|
335
|
-
|
|
336
|
-
const stream = await dialer.dialProtocol(dialAddrs[0], protocol)
|
|
337
|
-
|
|
338
|
-
await stream.closeWrite()
|
|
339
369
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
for await (const buf of stream.source) {
|
|
343
|
-
read += buf.byteLength
|
|
370
|
+
expect(output.subarray()).to.equalBytes(input)
|
|
371
|
+
expect(connection.streams.filter(s => s.protocol === echoProtocol)).to.be.empty()
|
|
344
372
|
}
|
|
345
|
-
|
|
346
|
-
expect(read).to.equal(bytes)
|
|
347
373
|
})
|
|
348
374
|
|
|
349
|
-
it('can close local stream
|
|
375
|
+
it('can close local stream while a remote stream is writing', async function () {
|
|
350
376
|
({ dialer, listener, dialAddrs } = await getSetup(common))
|
|
351
377
|
|
|
352
378
|
if (listener == null) {
|
|
353
379
|
return this.skip()
|
|
354
380
|
}
|
|
355
381
|
|
|
382
|
+
// 1. remote stream close read
|
|
383
|
+
// 2. local stream close write
|
|
384
|
+
// 3. remote stream close write
|
|
385
|
+
|
|
356
386
|
/**
|
|
357
387
|
* NodeA NodeB
|
|
358
388
|
* | <--- STOP_SENDING |
|
|
359
389
|
* | FIN ---> |
|
|
390
|
+
* | <--- DATA |
|
|
360
391
|
* | <--- FIN |
|
|
361
392
|
* | FIN_ACK ---> |
|
|
362
393
|
* | <--- FIN_ACK |
|
|
363
394
|
*/
|
|
364
395
|
|
|
365
|
-
const getRemoteStream =
|
|
396
|
+
const getRemoteStream = Promise.withResolvers<Stream>()
|
|
366
397
|
const protocol = '/close-local-while-remote-writes/1.0.0'
|
|
367
398
|
|
|
368
|
-
const streamHandler: StreamHandler = (
|
|
369
|
-
|
|
370
|
-
getRemoteStream.resolve(stream)
|
|
371
|
-
})
|
|
399
|
+
const streamHandler: StreamHandler = (stream) => {
|
|
400
|
+
getRemoteStream.resolve(stream)
|
|
372
401
|
}
|
|
373
402
|
|
|
374
|
-
await listener.handle(protocol,
|
|
375
|
-
streamHandler(info)
|
|
376
|
-
}, {
|
|
403
|
+
await listener.handle(protocol, streamHandler, {
|
|
377
404
|
runOnLimitedConnection: true
|
|
378
405
|
})
|
|
379
406
|
|
|
380
407
|
const connection = await dialer.dial(dialAddrs[0])
|
|
381
408
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
409
|
+
const [
|
|
410
|
+
localStream,
|
|
411
|
+
remoteStream
|
|
412
|
+
] = await Promise.all([
|
|
413
|
+
// open a stream on the echo protocol
|
|
414
|
+
connection.newStream(protocol, {
|
|
415
|
+
runOnLimitedConnection: true
|
|
416
|
+
}),
|
|
417
|
+
getRemoteStream.promise
|
|
418
|
+
])
|
|
419
|
+
|
|
420
|
+
// ignore incoming data
|
|
421
|
+
void drain(localStream)
|
|
422
|
+
|
|
423
|
+
// close the remote readable end
|
|
392
424
|
await remoteStream.closeRead()
|
|
393
425
|
|
|
394
|
-
//
|
|
426
|
+
// send data from the remote to the local
|
|
395
427
|
const remoteInputStream = pushable<Uint8Array>()
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
428
|
+
Promise.resolve().then(async () => {
|
|
429
|
+
for await (const buf of remoteInputStream) {
|
|
430
|
+
const sendMore = remoteStream.send(buf)
|
|
431
|
+
|
|
432
|
+
if (sendMore === false) {
|
|
433
|
+
await pEvent(remoteStream, 'drain', {
|
|
434
|
+
rejectionEvents: [
|
|
435
|
+
'close'
|
|
436
|
+
]
|
|
437
|
+
})
|
|
438
|
+
}
|
|
402
439
|
}
|
|
403
|
-
|
|
404
|
-
|
|
440
|
+
|
|
441
|
+
// close the remote writable end
|
|
442
|
+
await remoteStream.close()
|
|
405
443
|
})
|
|
406
444
|
|
|
407
|
-
|
|
408
|
-
|
|
445
|
+
await Promise.all([
|
|
446
|
+
// wait for remote to receive local FIN
|
|
447
|
+
pEvent(remoteStream, 'remoteCloseWrite'),
|
|
448
|
+
|
|
449
|
+
// wait to receive FIN_ACK
|
|
450
|
+
localStream.close()
|
|
451
|
+
])
|
|
409
452
|
|
|
410
|
-
//
|
|
411
|
-
|
|
453
|
+
// stop sending remote -> local
|
|
454
|
+
remoteInputStream.end()
|
|
412
455
|
|
|
413
456
|
// wait for remote to notice closure
|
|
414
457
|
await pRetry(() => {
|
|
@@ -417,11 +460,12 @@ export default (common: TestSetup<TransportTestFixtures>): void => {
|
|
|
417
460
|
}
|
|
418
461
|
})
|
|
419
462
|
|
|
420
|
-
|
|
463
|
+
// both ends should be closed
|
|
464
|
+
assertStreamClosed(localStream)
|
|
421
465
|
assertStreamClosed(remoteStream)
|
|
422
466
|
})
|
|
423
467
|
|
|
424
|
-
it('can close local stream for writing
|
|
468
|
+
it('can close local stream for writing while a remote stream is reading', async function () {
|
|
425
469
|
({ dialer, listener, dialAddrs } = await getSetup(common))
|
|
426
470
|
|
|
427
471
|
if (listener == null) {
|
|
@@ -430,62 +474,80 @@ export default (common: TestSetup<TransportTestFixtures>): void => {
|
|
|
430
474
|
|
|
431
475
|
/**
|
|
432
476
|
* NodeA NodeB
|
|
477
|
+
* | DATA ---> |
|
|
433
478
|
* | FIN ---> |
|
|
434
479
|
* | <--- FIN |
|
|
435
480
|
* | FIN_ACK ---> |
|
|
436
481
|
* | <--- FIN_ACK |
|
|
437
482
|
*/
|
|
438
483
|
|
|
439
|
-
const getRemoteStream =
|
|
484
|
+
const getRemoteStream = Promise.withResolvers<Stream>()
|
|
440
485
|
const protocol = '/close-local-while-remote-reads/1.0.0'
|
|
441
486
|
|
|
442
|
-
const streamHandler: StreamHandler = (
|
|
443
|
-
|
|
444
|
-
getRemoteStream.resolve(stream)
|
|
445
|
-
})
|
|
487
|
+
const streamHandler: StreamHandler = (stream) => {
|
|
488
|
+
getRemoteStream.resolve(stream)
|
|
446
489
|
}
|
|
447
490
|
|
|
448
|
-
await listener.handle(protocol,
|
|
449
|
-
streamHandler(info)
|
|
450
|
-
}, {
|
|
491
|
+
await listener.handle(protocol, streamHandler, {
|
|
451
492
|
runOnLimitedConnection: true
|
|
452
493
|
})
|
|
453
494
|
|
|
454
495
|
const connection = await dialer.dial(dialAddrs[0])
|
|
455
496
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
//
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
//
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
minTimeout: 100
|
|
497
|
+
const [
|
|
498
|
+
localStream,
|
|
499
|
+
remoteStream
|
|
500
|
+
] = await Promise.all([
|
|
501
|
+
// open a stream on the echo protocol
|
|
502
|
+
connection.newStream(protocol, {
|
|
503
|
+
runOnLimitedConnection: true
|
|
504
|
+
}),
|
|
505
|
+
getRemoteStream.promise
|
|
506
|
+
])
|
|
507
|
+
|
|
508
|
+
// ignore incoming data
|
|
509
|
+
void drain(remoteStream)
|
|
510
|
+
|
|
511
|
+
// close the remote stream writable end when the local sends a FIN
|
|
512
|
+
remoteStream.addEventListener('remoteCloseWrite', () => {
|
|
513
|
+
remoteStream.close()
|
|
514
|
+
.catch(err => {
|
|
515
|
+
remoteStream.abort(err)
|
|
516
|
+
})
|
|
477
517
|
})
|
|
478
518
|
|
|
479
|
-
// remote
|
|
480
|
-
|
|
519
|
+
// send data to the remote then close the stream
|
|
520
|
+
const data = [
|
|
521
|
+
Uint8Array.from([0, 1, 2, 3]),
|
|
522
|
+
Uint8Array.from([4, 5, 6, 7]),
|
|
523
|
+
Uint8Array.from([8, 9, 0, 1])
|
|
524
|
+
]
|
|
525
|
+
|
|
526
|
+
const [
|
|
527
|
+
remoteCloseEvent,
|
|
528
|
+
localCloseEvent
|
|
529
|
+
] = await Promise.all([
|
|
530
|
+
// wait for the remote to close
|
|
531
|
+
pEvent(remoteStream, 'close'),
|
|
532
|
+
pEvent(localStream, 'close'),
|
|
533
|
+
(async () => {
|
|
534
|
+
for (const buf of data) {
|
|
535
|
+
if (!localStream.send(buf)) {
|
|
536
|
+
await pEvent(localStream, 'drain', {
|
|
537
|
+
rejectionEvents: [
|
|
538
|
+
'close'
|
|
539
|
+
]
|
|
540
|
+
})
|
|
541
|
+
}
|
|
542
|
+
}
|
|
481
543
|
|
|
482
|
-
|
|
483
|
-
|
|
544
|
+
// close the local writable end
|
|
545
|
+
await localStream.close()
|
|
546
|
+
})()
|
|
547
|
+
])
|
|
484
548
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
// readable end should finish
|
|
488
|
-
await drain(stream.source)
|
|
549
|
+
expect(remoteCloseEvent).to.not.have.property('error', 'remote stream did not close cleanly')
|
|
550
|
+
expect(localCloseEvent).to.not.have.property('error', 'local stream did not close cleanly')
|
|
489
551
|
|
|
490
552
|
// wait for remote to notice closure
|
|
491
553
|
await pRetry(() => {
|
|
@@ -494,70 +556,50 @@ export default (common: TestSetup<TransportTestFixtures>): void => {
|
|
|
494
556
|
}
|
|
495
557
|
})
|
|
496
558
|
|
|
497
|
-
|
|
559
|
+
// both ends should be closed
|
|
560
|
+
assertStreamClosed(localStream)
|
|
498
561
|
assertStreamClosed(remoteStream)
|
|
499
562
|
})
|
|
500
|
-
})
|
|
501
|
-
|
|
502
|
-
describe('events', () => {
|
|
503
|
-
let dialer: Libp2p<{ echo: Echo }>
|
|
504
|
-
let listener: Libp2p<{ echo: Echo }> | undefined
|
|
505
|
-
let listenMultiaddrMatcher: MultiaddrMatcher
|
|
506
|
-
|
|
507
|
-
afterEach(async () => {
|
|
508
|
-
await stop(dialer, listener)
|
|
509
|
-
await common.teardown()
|
|
510
|
-
})
|
|
511
563
|
|
|
512
|
-
it('
|
|
513
|
-
|
|
564
|
+
it('can close a stream for writing but receive a large amount of data', async function () {
|
|
565
|
+
const timeout = 120_000
|
|
566
|
+
this.timeout(timeout);
|
|
567
|
+
({ dialer, listener, dialAddrs } = await getSetup(common))
|
|
514
568
|
|
|
515
569
|
if (listener == null) {
|
|
516
570
|
return this.skip()
|
|
517
571
|
}
|
|
518
572
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
const
|
|
522
|
-
|
|
523
|
-
listener.addEventListener('transport:listening', (event) => {
|
|
524
|
-
const transportListener = event.detail
|
|
573
|
+
const protocol = '/receive-data/1.0.0'
|
|
574
|
+
const chunkSize = 1024
|
|
575
|
+
const bytes = chunkSize * 1024 * 10
|
|
525
576
|
|
|
526
|
-
|
|
527
|
-
|
|
577
|
+
await listener.handle(protocol, async (stream) => {
|
|
578
|
+
for (let i = 0; i < bytes; i += chunkSize) {
|
|
579
|
+
const sendMore = stream.send(new Uint8Array(chunkSize))
|
|
580
|
+
|
|
581
|
+
if (!sendMore) {
|
|
582
|
+
await pEvent(stream, 'drain', {
|
|
583
|
+
rejectionEvents: [
|
|
584
|
+
'close'
|
|
585
|
+
]
|
|
586
|
+
})
|
|
587
|
+
}
|
|
528
588
|
}
|
|
529
|
-
})
|
|
530
589
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
await raceSignal(transportListeningPromise.promise, AbortSignal.timeout(1000), {
|
|
534
|
-
errorMessage: 'Did not emit listening event'
|
|
590
|
+
await stream.close()
|
|
535
591
|
})
|
|
536
|
-
})
|
|
537
|
-
|
|
538
|
-
it('emits close', async function () {
|
|
539
|
-
({ dialer, listener } = await getSetup(common))
|
|
540
|
-
|
|
541
|
-
if (listener == null) {
|
|
542
|
-
return this.skip()
|
|
543
|
-
}
|
|
544
592
|
|
|
545
|
-
const
|
|
546
|
-
const transportListener = transportManager.getListeners()
|
|
547
|
-
.filter(listener => listener.getAddrs().some(ma => listenMultiaddrMatcher.exactMatch(ma)))
|
|
548
|
-
.pop()
|
|
549
|
-
|
|
550
|
-
if (transportListener == null) {
|
|
551
|
-
throw new Error('Could not find address listener')
|
|
552
|
-
}
|
|
593
|
+
const stream = await dialer.dialProtocol(dialAddrs[0], protocol)
|
|
553
594
|
|
|
554
|
-
const
|
|
595
|
+
const [
|
|
596
|
+
output
|
|
597
|
+
] = await Promise.all([
|
|
598
|
+
all(stream),
|
|
599
|
+
stream.close()
|
|
600
|
+
])
|
|
555
601
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
await raceSignal(p, AbortSignal.timeout(1000), {
|
|
559
|
-
errorMessage: 'Did not emit close event'
|
|
560
|
-
})
|
|
602
|
+
expect(new Uint8ArrayList(...output).byteLength).to.equal(bytes)
|
|
561
603
|
})
|
|
562
604
|
})
|
|
563
605
|
}
|
|
@@ -568,6 +610,4 @@ function assertStreamClosed (stream: Stream): void {
|
|
|
568
610
|
expect(stream.writeStatus).to.equal('closed')
|
|
569
611
|
|
|
570
612
|
expect(stream.timeline.close).to.be.a('number')
|
|
571
|
-
expect(stream.timeline.closeRead).to.be.a('number')
|
|
572
|
-
expect(stream.timeline.closeWrite).to.be.a('number')
|
|
573
613
|
}
|