@libp2p/interface-compliance-tests 6.5.0 → 7.0.0-55b7e5fea
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 -345
- 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 +254 -320
- 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 +25 -53
- package/src/connection-encryption/index.ts +27 -20
- package/src/stream-muxer/base-test.ts +75 -413
- package/src/stream-muxer/close-test.ts +305 -343
- 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 -236
- 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 -39
- 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 -309
- 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 -57
|
@@ -1,40 +1,102 @@
|
|
|
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
|
async function getSetup(common) {
|
|
14
16
|
const setup = await common.setup();
|
|
15
|
-
const dialer = await createPeer(
|
|
17
|
+
const dialer = await createPeer({
|
|
18
|
+
logger: prefixLogger('dialer'),
|
|
19
|
+
...setup.dialer
|
|
20
|
+
});
|
|
16
21
|
let listener;
|
|
17
22
|
if (setup.listener != null) {
|
|
18
|
-
listener = await createPeer(
|
|
23
|
+
listener = await createPeer({
|
|
24
|
+
logger: prefixLogger('listener'),
|
|
25
|
+
...setup.listener
|
|
26
|
+
});
|
|
19
27
|
}
|
|
20
|
-
|
|
28
|
+
let dialAddrs = listener?.getMultiaddrs() ?? setup.dialAddrs;
|
|
21
29
|
if (dialAddrs == null) {
|
|
22
30
|
throw new Error('Listener config or dial addresses must be specified');
|
|
23
31
|
}
|
|
32
|
+
dialAddrs = dialAddrs.filter(ma => setup.dialMultiaddrMatcher.exactMatch(ma));
|
|
33
|
+
if (dialAddrs.length === 0) {
|
|
34
|
+
throw new Error('Listener was not listening on any addresses that the dialMultiaddrMatcher matched');
|
|
35
|
+
}
|
|
24
36
|
return {
|
|
25
37
|
dialer,
|
|
26
38
|
listener,
|
|
27
|
-
dialAddrs
|
|
39
|
+
dialAddrs,
|
|
28
40
|
dialMultiaddrMatcher: setup.dialMultiaddrMatcher,
|
|
29
41
|
listenMultiaddrMatcher: setup.listenMultiaddrMatcher
|
|
30
42
|
};
|
|
31
43
|
}
|
|
32
44
|
export default (common) => {
|
|
45
|
+
describe('transport events', () => {
|
|
46
|
+
let dialer;
|
|
47
|
+
let listener;
|
|
48
|
+
let listenMultiaddrMatcher;
|
|
49
|
+
afterEach(async () => {
|
|
50
|
+
await stop(dialer, listener);
|
|
51
|
+
await common.teardown();
|
|
52
|
+
});
|
|
53
|
+
it('emits listening', async function () {
|
|
54
|
+
({ dialer, listener, listenMultiaddrMatcher } = await getSetup(common));
|
|
55
|
+
if (listener == null) {
|
|
56
|
+
return this.skip();
|
|
57
|
+
}
|
|
58
|
+
await listener.stop();
|
|
59
|
+
const transportListeningPromise = Promise.withResolvers();
|
|
60
|
+
listener.addEventListener('transport:listening', (event) => {
|
|
61
|
+
const transportListener = event.detail;
|
|
62
|
+
if (transportListener.getAddrs().some(ma => listenMultiaddrMatcher.exactMatch(ma))) {
|
|
63
|
+
transportListeningPromise.resolve();
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
await listener.start();
|
|
67
|
+
await raceSignal(transportListeningPromise.promise, AbortSignal.timeout(1000), {
|
|
68
|
+
translateError: () => {
|
|
69
|
+
return new TimeoutError('Did not emit listening event');
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
it('emits close', async function () {
|
|
74
|
+
({ dialer, listener } = await getSetup(common));
|
|
75
|
+
if (listener == null) {
|
|
76
|
+
return this.skip();
|
|
77
|
+
}
|
|
78
|
+
const transportManager = getTransportManager(listener);
|
|
79
|
+
const transportListener = transportManager.getListeners()
|
|
80
|
+
.filter(listener => listener.getAddrs().some(ma => listenMultiaddrMatcher.exactMatch(ma)))
|
|
81
|
+
.pop();
|
|
82
|
+
if (transportListener == null) {
|
|
83
|
+
throw new Error('Could not find address listener');
|
|
84
|
+
}
|
|
85
|
+
const p = pEvent(transportListener, 'close');
|
|
86
|
+
await listener.stop();
|
|
87
|
+
await raceSignal(p, AbortSignal.timeout(1000), {
|
|
88
|
+
translateError: () => {
|
|
89
|
+
return new TimeoutError('Did not emit close event');
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
});
|
|
33
94
|
describe('interface-transport', () => {
|
|
34
95
|
let dialer;
|
|
35
96
|
let listener;
|
|
36
97
|
let dialAddrs;
|
|
37
98
|
let dialMultiaddrMatcher;
|
|
99
|
+
let listenMultiaddrMatcher;
|
|
38
100
|
afterEach(async () => {
|
|
39
101
|
await stop(dialer, listener);
|
|
40
102
|
await common.teardown();
|
|
@@ -45,17 +107,20 @@ export default (common) => {
|
|
|
45
107
|
const output = await dialer.services.echo.echo(dialAddrs[0], input, {
|
|
46
108
|
signal: AbortSignal.timeout(5000)
|
|
47
109
|
});
|
|
48
|
-
expect(output).to.equalBytes(input);
|
|
110
|
+
expect(output.subarray()).to.equalBytes(input);
|
|
49
111
|
});
|
|
50
112
|
it('should listen on multiple addresses', async () => {
|
|
51
113
|
({ dialer, listener, dialAddrs } = await getSetup(common));
|
|
52
114
|
const input = Uint8Array.from([0, 1, 2, 3, 4]);
|
|
53
|
-
await
|
|
54
|
-
signal: AbortSignal.timeout(5000)
|
|
55
|
-
})).to.eventually.deep.equal(input);
|
|
56
|
-
await expect(dialer.services.echo.echo(dialAddrs[1], input, {
|
|
115
|
+
const output1 = await dialer.services.echo.echo(dialAddrs[0], input, {
|
|
57
116
|
signal: AbortSignal.timeout(5000)
|
|
58
|
-
})
|
|
117
|
+
});
|
|
118
|
+
expect(output1.subarray()).to.equalBytes(input);
|
|
119
|
+
const output2 = await dialer.services.echo.echo(dialAddrs[1], input, {
|
|
120
|
+
signal: AbortSignal.timeout(5000),
|
|
121
|
+
force: true
|
|
122
|
+
});
|
|
123
|
+
expect(output2.subarray()).to.equalBytes(input);
|
|
59
124
|
});
|
|
60
125
|
it('can close connections', async () => {
|
|
61
126
|
({ dialer, listener, dialAddrs } = await getSetup(common));
|
|
@@ -75,12 +140,15 @@ export default (common) => {
|
|
|
75
140
|
.with.property('name', 'AbortError');
|
|
76
141
|
});
|
|
77
142
|
it('should close all streams when the connection closes', async () => {
|
|
78
|
-
({ dialer, listener, dialAddrs } = await getSetup(common));
|
|
143
|
+
({ dialer, listener, dialAddrs, listenMultiaddrMatcher } = await getSetup(common));
|
|
79
144
|
let incomingConnectionPromise;
|
|
80
145
|
if (listener != null) {
|
|
81
|
-
incomingConnectionPromise =
|
|
146
|
+
incomingConnectionPromise = Promise.withResolvers();
|
|
82
147
|
listener.addEventListener('connection:open', (event) => {
|
|
83
148
|
const conn = event.detail;
|
|
149
|
+
if (!listenMultiaddrMatcher.matches(conn.remoteAddr)) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
84
152
|
if (conn.remotePeer.equals(dialer.peerId)) {
|
|
85
153
|
incomingConnectionPromise?.resolve(conn);
|
|
86
154
|
}
|
|
@@ -96,18 +164,25 @@ export default (common) => {
|
|
|
96
164
|
maxOutboundStreams: 5
|
|
97
165
|
});
|
|
98
166
|
}
|
|
99
|
-
|
|
100
|
-
// Close the connection and verify all streams have been closed
|
|
101
|
-
await connection.close();
|
|
102
|
-
await pWaitFor(() => connection.streams.length === 0, {
|
|
103
|
-
timeout: 5000
|
|
104
|
-
});
|
|
167
|
+
expect(connection).to.have.property('streams').that.has.lengthOf(5);
|
|
105
168
|
if (remoteConn != null) {
|
|
106
|
-
await pWaitFor(() => remoteConn.streams.length ===
|
|
107
|
-
timeout:
|
|
169
|
+
await pWaitFor(() => remoteConn.streams.filter(s => s.protocol === '/echo/1.0.0').length === 5, {
|
|
170
|
+
timeout: 5_000,
|
|
171
|
+
interval: 1_000
|
|
108
172
|
});
|
|
109
173
|
}
|
|
110
|
-
|
|
174
|
+
// Close the connection and verify all streams have been closed
|
|
175
|
+
await Promise.all([
|
|
176
|
+
pEvent(connection, 'close'),
|
|
177
|
+
pEvent(remoteConn ?? connection, 'close'),
|
|
178
|
+
connection.close()
|
|
179
|
+
]);
|
|
180
|
+
expect(connection).to.have.property('status', 'closed');
|
|
181
|
+
expect(connection).to.have.property('streams').that.is.empty();
|
|
182
|
+
if (remoteConn != null) {
|
|
183
|
+
expect(remoteConn).to.have.property('status', 'closed');
|
|
184
|
+
expect(remoteConn).to.have.property('streams').that.is.empty();
|
|
185
|
+
}
|
|
111
186
|
});
|
|
112
187
|
it('should not handle connection if upgradeInbound rejects', async function () {
|
|
113
188
|
({ dialer, listener, dialAddrs, dialMultiaddrMatcher } = await getSetup(common));
|
|
@@ -148,262 +223,219 @@ export default (common) => {
|
|
|
148
223
|
}
|
|
149
224
|
}
|
|
150
225
|
});
|
|
151
|
-
it('should handle one
|
|
226
|
+
it('should handle one small write', async function () {
|
|
152
227
|
const timeout = 120_000;
|
|
153
228
|
this.timeout(timeout);
|
|
154
229
|
({ dialer, listener, dialAddrs } = await getSetup(common));
|
|
230
|
+
const connection = await dialer.dial(dialAddrs[0]);
|
|
231
|
+
const input = new Uint8Array(1024).fill(5);
|
|
232
|
+
const output = await dialer.services.echo.echo(connection.remotePeer, input, {
|
|
233
|
+
signal: AbortSignal.timeout(timeout)
|
|
234
|
+
});
|
|
235
|
+
expect(output.subarray()).to.equalBytes(input);
|
|
236
|
+
expect(connection.streams.filter(s => s.protocol === dialer.services.echo.protocol)).to.be.empty();
|
|
237
|
+
});
|
|
238
|
+
it('should handle one big write', async function () {
|
|
239
|
+
const timeout = 540_000;
|
|
240
|
+
this.timeout(timeout);
|
|
241
|
+
({ dialer, listener, dialAddrs } = await getSetup(common));
|
|
242
|
+
const connection = await dialer.dial(dialAddrs[0]);
|
|
155
243
|
const input = new Uint8Array(1024 * 1024 * 10).fill(5);
|
|
156
|
-
const output = await dialer.services.echo.echo(
|
|
244
|
+
const output = await dialer.services.echo.echo(connection.remotePeer, input, {
|
|
157
245
|
signal: AbortSignal.timeout(timeout)
|
|
158
246
|
});
|
|
159
|
-
expect(output).to.equalBytes(input);
|
|
247
|
+
expect(output.subarray()).to.equalBytes(input);
|
|
248
|
+
expect(connection.streams.filter(s => s.protocol === dialer.services.echo.protocol)).to.be.empty();
|
|
160
249
|
});
|
|
161
250
|
it('should handle many small writes', async function () {
|
|
162
251
|
const timeout = 360_000;
|
|
163
252
|
this.timeout(timeout);
|
|
164
253
|
({ dialer, listener, dialAddrs } = await getSetup(common));
|
|
165
|
-
|
|
254
|
+
const connection = await dialer.dial(dialAddrs[0]);
|
|
255
|
+
const echoProtocol = dialer.services.echo.protocol;
|
|
256
|
+
for (let i = 0; i < 2_000; i++) {
|
|
166
257
|
const input = new Uint8Array(1024).fill(5);
|
|
167
|
-
const output = await dialer.services.echo.echo(
|
|
258
|
+
const output = await dialer.services.echo.echo(connection.remotePeer, input, {
|
|
168
259
|
signal: AbortSignal.timeout(timeout)
|
|
169
260
|
});
|
|
170
|
-
expect(output).to.equalBytes(input);
|
|
171
|
-
|
|
172
|
-
});
|
|
173
|
-
it('can close a stream for reading but send a large amount of data', async function () {
|
|
174
|
-
const timeout = 120_000;
|
|
175
|
-
this.timeout(timeout);
|
|
176
|
-
({ dialer, listener, dialAddrs } = await getSetup(common));
|
|
177
|
-
if (listener == null) {
|
|
178
|
-
return this.skip();
|
|
179
|
-
}
|
|
180
|
-
const protocol = '/send-data/1.0.0';
|
|
181
|
-
const chunkSize = 1024;
|
|
182
|
-
const bytes = chunkSize * 1024 * 10;
|
|
183
|
-
const deferred = pDefer();
|
|
184
|
-
await listener.handle(protocol, ({ stream }) => {
|
|
185
|
-
Promise.resolve().then(async () => {
|
|
186
|
-
let read = 0;
|
|
187
|
-
for await (const buf of stream.source) {
|
|
188
|
-
read += buf.byteLength;
|
|
189
|
-
if (read === bytes) {
|
|
190
|
-
deferred.resolve();
|
|
191
|
-
break;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
})
|
|
195
|
-
.catch(err => {
|
|
196
|
-
deferred.reject(err);
|
|
197
|
-
stream.abort(err);
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
const stream = await dialer.dialProtocol(dialAddrs[0], protocol);
|
|
201
|
-
await stream.closeRead();
|
|
202
|
-
await stream.sink((async function* () {
|
|
203
|
-
for (let i = 0; i < bytes; i += chunkSize) {
|
|
204
|
-
yield new Uint8Array(chunkSize);
|
|
205
|
-
}
|
|
206
|
-
})());
|
|
207
|
-
await stream.close();
|
|
208
|
-
await deferred.promise;
|
|
209
|
-
});
|
|
210
|
-
it('can close a stream for writing but receive a large amount of data', async function () {
|
|
211
|
-
const timeout = 120_000;
|
|
212
|
-
this.timeout(timeout);
|
|
213
|
-
({ dialer, listener, dialAddrs } = await getSetup(common));
|
|
214
|
-
if (listener == null) {
|
|
215
|
-
return this.skip();
|
|
216
|
-
}
|
|
217
|
-
const protocol = '/receive-data/1.0.0';
|
|
218
|
-
const chunkSize = 1024;
|
|
219
|
-
const bytes = chunkSize * 1024 * 10;
|
|
220
|
-
const deferred = pDefer();
|
|
221
|
-
await listener.handle(protocol, ({ stream }) => {
|
|
222
|
-
Promise.resolve().then(async () => {
|
|
223
|
-
await stream.sink((async function* () {
|
|
224
|
-
for (let i = 0; i < bytes; i += chunkSize) {
|
|
225
|
-
yield new Uint8Array(chunkSize);
|
|
226
|
-
}
|
|
227
|
-
})());
|
|
228
|
-
await stream.close();
|
|
229
|
-
})
|
|
230
|
-
.catch(err => {
|
|
231
|
-
deferred.reject(err);
|
|
232
|
-
stream.abort(err);
|
|
233
|
-
});
|
|
234
|
-
});
|
|
235
|
-
const stream = await dialer.dialProtocol(dialAddrs[0], protocol);
|
|
236
|
-
await stream.closeWrite();
|
|
237
|
-
let read = 0;
|
|
238
|
-
for await (const buf of stream.source) {
|
|
239
|
-
read += buf.byteLength;
|
|
261
|
+
expect(output.subarray()).to.equalBytes(input);
|
|
262
|
+
expect(connection.streams.filter(s => s.protocol === echoProtocol)).to.be.empty();
|
|
240
263
|
}
|
|
241
|
-
expect(read).to.equal(bytes);
|
|
242
264
|
});
|
|
243
|
-
it('can close local stream
|
|
265
|
+
it('can close local stream while a remote stream is writing', async function () {
|
|
244
266
|
({ dialer, listener, dialAddrs } = await getSetup(common));
|
|
245
267
|
if (listener == null) {
|
|
246
268
|
return this.skip();
|
|
247
269
|
}
|
|
270
|
+
// 1. remote stream close read
|
|
271
|
+
// 2. local stream close write
|
|
272
|
+
// 3. remote stream close write
|
|
248
273
|
/**
|
|
249
274
|
* NodeA NodeB
|
|
250
275
|
* | <--- STOP_SENDING |
|
|
251
276
|
* | FIN ---> |
|
|
277
|
+
* | <--- DATA |
|
|
252
278
|
* | <--- FIN |
|
|
253
279
|
* | FIN_ACK ---> |
|
|
254
280
|
* | <--- FIN_ACK |
|
|
255
281
|
*/
|
|
256
|
-
const getRemoteStream =
|
|
282
|
+
const getRemoteStream = Promise.withResolvers();
|
|
257
283
|
const protocol = '/close-local-while-remote-writes/1.0.0';
|
|
258
|
-
const streamHandler = (
|
|
259
|
-
|
|
260
|
-
getRemoteStream.resolve(stream);
|
|
261
|
-
});
|
|
284
|
+
const streamHandler = (stream) => {
|
|
285
|
+
getRemoteStream.resolve(stream);
|
|
262
286
|
};
|
|
263
|
-
await listener.handle(protocol,
|
|
264
|
-
streamHandler(info);
|
|
265
|
-
}, {
|
|
287
|
+
await listener.handle(protocol, streamHandler, {
|
|
266
288
|
runOnLimitedConnection: true
|
|
267
289
|
});
|
|
268
290
|
const connection = await dialer.dial(dialAddrs[0]);
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
//
|
|
291
|
+
const [localStream, remoteStream] = await Promise.all([
|
|
292
|
+
// open a stream on the echo protocol
|
|
293
|
+
connection.newStream(protocol, {
|
|
294
|
+
runOnLimitedConnection: true
|
|
295
|
+
}),
|
|
296
|
+
getRemoteStream.promise
|
|
297
|
+
]);
|
|
298
|
+
// ignore incoming data
|
|
299
|
+
void drain(localStream);
|
|
300
|
+
// close the remote readable end
|
|
277
301
|
await remoteStream.closeRead();
|
|
278
|
-
//
|
|
302
|
+
// send data from the remote to the local
|
|
279
303
|
const remoteInputStream = pushable();
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
304
|
+
Promise.resolve().then(async () => {
|
|
305
|
+
for await (const buf of remoteInputStream) {
|
|
306
|
+
const sendMore = remoteStream.send(buf);
|
|
307
|
+
if (sendMore === false) {
|
|
308
|
+
await pEvent(remoteStream, 'drain', {
|
|
309
|
+
rejectionEvents: [
|
|
310
|
+
'close'
|
|
311
|
+
]
|
|
312
|
+
});
|
|
313
|
+
}
|
|
285
314
|
}
|
|
286
|
-
|
|
287
|
-
|
|
315
|
+
// close the remote writable end
|
|
316
|
+
await remoteStream.close();
|
|
288
317
|
});
|
|
289
|
-
|
|
318
|
+
await Promise.all([
|
|
319
|
+
// wait for remote to receive local FIN
|
|
320
|
+
pEvent(remoteStream, 'remoteCloseWrite'),
|
|
321
|
+
// wait to receive FIN_ACK
|
|
322
|
+
localStream.close()
|
|
323
|
+
]);
|
|
324
|
+
// stop sending remote -> local
|
|
290
325
|
remoteInputStream.end();
|
|
291
|
-
// wait to receive FIN_ACK
|
|
292
|
-
await p;
|
|
293
326
|
// wait for remote to notice closure
|
|
294
327
|
await pRetry(() => {
|
|
295
328
|
if (remoteStream.status !== 'closed') {
|
|
296
329
|
throw new Error('Remote stream not closed');
|
|
297
330
|
}
|
|
298
331
|
});
|
|
299
|
-
|
|
332
|
+
// both ends should be closed
|
|
333
|
+
assertStreamClosed(localStream);
|
|
300
334
|
assertStreamClosed(remoteStream);
|
|
301
335
|
});
|
|
302
|
-
it('can close local stream for writing
|
|
336
|
+
it('can close local stream for writing while a remote stream is reading', async function () {
|
|
303
337
|
({ dialer, listener, dialAddrs } = await getSetup(common));
|
|
304
338
|
if (listener == null) {
|
|
305
339
|
return this.skip();
|
|
306
340
|
}
|
|
307
341
|
/**
|
|
308
342
|
* NodeA NodeB
|
|
343
|
+
* | DATA ---> |
|
|
309
344
|
* | FIN ---> |
|
|
310
345
|
* | <--- FIN |
|
|
311
346
|
* | FIN_ACK ---> |
|
|
312
347
|
* | <--- FIN_ACK |
|
|
313
348
|
*/
|
|
314
|
-
const getRemoteStream =
|
|
349
|
+
const getRemoteStream = Promise.withResolvers();
|
|
315
350
|
const protocol = '/close-local-while-remote-reads/1.0.0';
|
|
316
|
-
const streamHandler = (
|
|
317
|
-
|
|
318
|
-
getRemoteStream.resolve(stream);
|
|
319
|
-
});
|
|
351
|
+
const streamHandler = (stream) => {
|
|
352
|
+
getRemoteStream.resolve(stream);
|
|
320
353
|
};
|
|
321
|
-
await listener.handle(protocol,
|
|
322
|
-
streamHandler(info);
|
|
323
|
-
}, {
|
|
354
|
+
await listener.handle(protocol, streamHandler, {
|
|
324
355
|
runOnLimitedConnection: true
|
|
325
356
|
});
|
|
326
357
|
const connection = await dialer.dial(dialAddrs[0]);
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
//
|
|
335
|
-
|
|
336
|
-
//
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
}
|
|
343
|
-
}, {
|
|
344
|
-
minTimeout: 100
|
|
358
|
+
const [localStream, remoteStream] = await Promise.all([
|
|
359
|
+
// open a stream on the echo protocol
|
|
360
|
+
connection.newStream(protocol, {
|
|
361
|
+
runOnLimitedConnection: true
|
|
362
|
+
}),
|
|
363
|
+
getRemoteStream.promise
|
|
364
|
+
]);
|
|
365
|
+
// ignore incoming data
|
|
366
|
+
void drain(remoteStream);
|
|
367
|
+
// close the remote stream writable end when the local sends a FIN
|
|
368
|
+
remoteStream.addEventListener('remoteCloseWrite', () => {
|
|
369
|
+
remoteStream.close()
|
|
370
|
+
.catch(err => {
|
|
371
|
+
remoteStream.abort(err);
|
|
372
|
+
});
|
|
345
373
|
});
|
|
346
|
-
// remote
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
374
|
+
// send data to the remote then close the stream
|
|
375
|
+
const data = [
|
|
376
|
+
Uint8Array.from([0, 1, 2, 3]),
|
|
377
|
+
Uint8Array.from([4, 5, 6, 7]),
|
|
378
|
+
Uint8Array.from([8, 9, 0, 1])
|
|
379
|
+
];
|
|
380
|
+
const [remoteCloseEvent, localCloseEvent] = await Promise.all([
|
|
381
|
+
// wait for the remote to close
|
|
382
|
+
pEvent(remoteStream, 'close'),
|
|
383
|
+
pEvent(localStream, 'close'),
|
|
384
|
+
(async () => {
|
|
385
|
+
for (const buf of data) {
|
|
386
|
+
if (!localStream.send(buf)) {
|
|
387
|
+
await pEvent(localStream, 'drain', {
|
|
388
|
+
rejectionEvents: [
|
|
389
|
+
'close'
|
|
390
|
+
]
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
// close the local writable end
|
|
395
|
+
await localStream.close();
|
|
396
|
+
})()
|
|
397
|
+
]);
|
|
398
|
+
expect(remoteCloseEvent).to.not.have.property('error', 'remote stream did not close cleanly');
|
|
399
|
+
expect(localCloseEvent).to.not.have.property('error', 'local stream did not close cleanly');
|
|
354
400
|
// wait for remote to notice closure
|
|
355
401
|
await pRetry(() => {
|
|
356
402
|
if (remoteStream.status !== 'closed') {
|
|
357
403
|
throw new Error('Remote stream not closed');
|
|
358
404
|
}
|
|
359
405
|
});
|
|
360
|
-
|
|
406
|
+
// both ends should be closed
|
|
407
|
+
assertStreamClosed(localStream);
|
|
361
408
|
assertStreamClosed(remoteStream);
|
|
362
409
|
});
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
let listenMultiaddrMatcher;
|
|
368
|
-
afterEach(async () => {
|
|
369
|
-
await stop(dialer, listener);
|
|
370
|
-
await common.teardown();
|
|
371
|
-
});
|
|
372
|
-
it('emits listening', async function () {
|
|
373
|
-
({ dialer, listener, listenMultiaddrMatcher } = await getSetup(common));
|
|
410
|
+
it('can close a stream for writing but receive a large amount of data', async function () {
|
|
411
|
+
const timeout = 120_000;
|
|
412
|
+
this.timeout(timeout);
|
|
413
|
+
({ dialer, listener, dialAddrs } = await getSetup(common));
|
|
374
414
|
if (listener == null) {
|
|
375
415
|
return this.skip();
|
|
376
416
|
}
|
|
377
|
-
|
|
378
|
-
const
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
417
|
+
const protocol = '/receive-data/1.0.0';
|
|
418
|
+
const chunkSize = 1024;
|
|
419
|
+
const bytes = chunkSize * 1024 * 10;
|
|
420
|
+
await listener.handle(protocol, async (stream) => {
|
|
421
|
+
for (let i = 0; i < bytes; i += chunkSize) {
|
|
422
|
+
const sendMore = stream.send(new Uint8Array(chunkSize));
|
|
423
|
+
if (!sendMore) {
|
|
424
|
+
await pEvent(stream, 'drain', {
|
|
425
|
+
rejectionEvents: [
|
|
426
|
+
'close'
|
|
427
|
+
]
|
|
428
|
+
});
|
|
429
|
+
}
|
|
383
430
|
}
|
|
431
|
+
await stream.close();
|
|
384
432
|
});
|
|
385
|
-
await
|
|
386
|
-
await
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
({ dialer, listener } = await getSetup(common));
|
|
392
|
-
if (listener == null) {
|
|
393
|
-
return this.skip();
|
|
394
|
-
}
|
|
395
|
-
const transportManager = getTransportManager(listener);
|
|
396
|
-
const transportListener = transportManager.getListeners()
|
|
397
|
-
.filter(listener => listener.getAddrs().some(ma => listenMultiaddrMatcher.exactMatch(ma)))
|
|
398
|
-
.pop();
|
|
399
|
-
if (transportListener == null) {
|
|
400
|
-
throw new Error('Could not find address listener');
|
|
401
|
-
}
|
|
402
|
-
const p = pEvent(transportListener, 'close');
|
|
403
|
-
await listener.stop();
|
|
404
|
-
await raceSignal(p, AbortSignal.timeout(1000), {
|
|
405
|
-
errorMessage: 'Did not emit close event'
|
|
406
|
-
});
|
|
433
|
+
const stream = await dialer.dialProtocol(dialAddrs[0], protocol);
|
|
434
|
+
const [output] = await Promise.all([
|
|
435
|
+
all(stream),
|
|
436
|
+
stream.close()
|
|
437
|
+
]);
|
|
438
|
+
expect(new Uint8ArrayList(...output).byteLength).to.equal(bytes);
|
|
407
439
|
});
|
|
408
440
|
});
|
|
409
441
|
};
|
|
@@ -412,7 +444,5 @@ function assertStreamClosed(stream) {
|
|
|
412
444
|
expect(stream.readStatus).to.equal('closed');
|
|
413
445
|
expect(stream.writeStatus).to.equal('closed');
|
|
414
446
|
expect(stream.timeline.close).to.be.a('number');
|
|
415
|
-
expect(stream.timeline.closeRead).to.be.a('number');
|
|
416
|
-
expect(stream.timeline.closeWrite).to.be.a('number');
|
|
417
447
|
}
|
|
418
448
|
//# sourceMappingURL=index.js.map
|