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