@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,341 +1,408 @@
|
|
|
1
1
|
/* eslint max-nested-callbacks: ["error", 8] */
|
|
2
|
-
import {
|
|
2
|
+
import { abortableSource } from 'abortable-iterator';
|
|
3
3
|
import { expect } from 'aegir/chai';
|
|
4
4
|
import delay from 'delay';
|
|
5
5
|
import all from 'it-all';
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
6
|
+
import drain from 'it-drain';
|
|
7
|
+
import { duplexPair } from 'it-pair/duplex';
|
|
8
|
+
import { pipe } from 'it-pipe';
|
|
9
|
+
import { pbStream } from 'it-protobuf-stream';
|
|
10
|
+
import toBuffer from 'it-to-buffer';
|
|
11
|
+
import pDefer from 'p-defer';
|
|
8
12
|
import { Uint8ArrayList } from 'uint8arraylist';
|
|
9
13
|
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string';
|
|
10
14
|
import { Message } from './fixtures/pb/message.js';
|
|
11
15
|
function randomBuffer() {
|
|
12
16
|
return uint8ArrayFromString(Math.random().toString());
|
|
13
17
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
function infiniteRandom() {
|
|
19
|
+
let done = false;
|
|
20
|
+
const generator = {
|
|
21
|
+
[Symbol.asyncIterator]: () => {
|
|
22
|
+
return generator;
|
|
23
|
+
},
|
|
24
|
+
async next() {
|
|
25
|
+
await delay(10);
|
|
26
|
+
if (done instanceof Error) {
|
|
27
|
+
throw done;
|
|
28
|
+
}
|
|
29
|
+
if (done) {
|
|
30
|
+
return {
|
|
31
|
+
done: true,
|
|
32
|
+
value: undefined
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
done: false,
|
|
37
|
+
value: new Uint8ArrayList(randomBuffer())
|
|
38
|
+
};
|
|
39
|
+
},
|
|
40
|
+
async return() {
|
|
41
|
+
done = true;
|
|
42
|
+
return {
|
|
43
|
+
done: true,
|
|
44
|
+
value: undefined
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
async throw(err) {
|
|
48
|
+
done = err;
|
|
49
|
+
return {
|
|
50
|
+
done: true,
|
|
51
|
+
value: undefined
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
return generator;
|
|
19
56
|
}
|
|
20
57
|
export default (common) => {
|
|
21
58
|
describe('close', () => {
|
|
22
|
-
|
|
23
|
-
let inboundConnection;
|
|
24
|
-
let dialer;
|
|
25
|
-
let listener;
|
|
26
|
-
beforeEach(async () => {
|
|
27
|
-
[outboundConnection, inboundConnection] = multiaddrConnectionPair();
|
|
28
|
-
const dialerFactory = await common.setup();
|
|
29
|
-
dialer = dialerFactory.createStreamMuxer(outboundConnection);
|
|
30
|
-
const listenerFactory = await common.setup();
|
|
31
|
-
listener = listenerFactory.createStreamMuxer(inboundConnection);
|
|
32
|
-
});
|
|
33
|
-
afterEach(async () => {
|
|
34
|
-
await dialer?.close();
|
|
35
|
-
await listener?.close();
|
|
36
|
-
});
|
|
37
|
-
it('closing underlying MultiaddrConnection closes streams', async () => {
|
|
59
|
+
it('closing underlying socket closes streams', async () => {
|
|
38
60
|
let openedStreams = 0;
|
|
39
61
|
const expectedStreams = 5;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
62
|
+
const dialerFactory = await common.setup();
|
|
63
|
+
const dialer = dialerFactory.createStreamMuxer({
|
|
64
|
+
direction: 'outbound'
|
|
43
65
|
});
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if (!sendMore) {
|
|
52
|
-
await pEvent(stream, 'drain', {
|
|
53
|
-
rejectionEvents: [
|
|
54
|
-
'close'
|
|
55
|
-
]
|
|
56
|
-
});
|
|
57
|
-
}
|
|
66
|
+
// Listener is echo server :)
|
|
67
|
+
const listenerFactory = await common.setup();
|
|
68
|
+
const listener = listenerFactory.createStreamMuxer({
|
|
69
|
+
direction: 'inbound',
|
|
70
|
+
onIncomingStream: (stream) => {
|
|
71
|
+
openedStreams++;
|
|
72
|
+
void pipe(stream, stream);
|
|
58
73
|
}
|
|
74
|
+
});
|
|
75
|
+
const p = duplexPair();
|
|
76
|
+
void pipe(p[0], dialer, p[0]);
|
|
77
|
+
void pipe(p[1], listener, p[1]);
|
|
78
|
+
const streams = await Promise.all(Array(expectedStreams).fill(0).map(async () => dialer.newStream()));
|
|
79
|
+
void Promise.all(streams.map(async (stream) => {
|
|
80
|
+
await pipe(infiniteRandom(), stream, drain);
|
|
59
81
|
}));
|
|
60
82
|
expect(dialer.streams).to.have.lengthOf(expectedStreams);
|
|
61
83
|
// Pause, and then close the dialer
|
|
62
84
|
await delay(50);
|
|
63
|
-
await
|
|
64
|
-
await outboundConnection.close();
|
|
65
|
-
await delay(50);
|
|
85
|
+
await pipe(async function* () { }, dialer, drain);
|
|
66
86
|
expect(openedStreams).to.have.equal(expectedStreams);
|
|
67
87
|
expect(dialer.streams).to.have.lengthOf(0);
|
|
68
88
|
});
|
|
69
89
|
it('calling close closes streams', async () => {
|
|
70
90
|
let openedStreams = 0;
|
|
71
91
|
const expectedStreams = 5;
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
92
|
+
const dialerFactory = await common.setup();
|
|
93
|
+
const dialer = dialerFactory.createStreamMuxer({
|
|
94
|
+
direction: 'outbound'
|
|
75
95
|
});
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (!sendMore) {
|
|
84
|
-
await pEvent(stream, 'drain', {
|
|
85
|
-
rejectionEvents: [
|
|
86
|
-
'close'
|
|
87
|
-
]
|
|
88
|
-
});
|
|
89
|
-
}
|
|
96
|
+
// Listener is echo server :)
|
|
97
|
+
const listenerFactory = await common.setup();
|
|
98
|
+
const listener = listenerFactory.createStreamMuxer({
|
|
99
|
+
direction: 'inbound',
|
|
100
|
+
onIncomingStream: (stream) => {
|
|
101
|
+
openedStreams++;
|
|
102
|
+
void pipe(stream, stream).catch(() => { });
|
|
90
103
|
}
|
|
91
|
-
}))
|
|
92
|
-
.catch(() => {
|
|
93
|
-
// calling .send on a closed stream will throw so swallow any errors
|
|
94
104
|
});
|
|
105
|
+
const p = duplexPair();
|
|
106
|
+
void pipe(p[0], dialer, p[0]);
|
|
107
|
+
void pipe(p[1], listener, p[1]);
|
|
108
|
+
const streams = await Promise.all(Array(expectedStreams).fill(0).map(async () => dialer.newStream()));
|
|
109
|
+
void Promise.all(streams.map(async (stream) => {
|
|
110
|
+
await pipe(infiniteRandom(), stream, drain);
|
|
111
|
+
}));
|
|
95
112
|
expect(dialer.streams, 'dialer - number of opened streams should match number of calls to newStream').to.have.lengthOf(expectedStreams);
|
|
96
113
|
// Pause, and then close the dialer
|
|
97
114
|
await delay(50);
|
|
98
115
|
await dialer.close();
|
|
99
|
-
await delay(50);
|
|
100
116
|
expect(openedStreams, 'listener - number of opened streams should match number of calls to newStream').to.have.equal(expectedStreams);
|
|
101
117
|
expect(dialer.streams, 'all tracked streams should be deleted after the muxer has called close').to.have.lengthOf(0);
|
|
102
118
|
});
|
|
103
|
-
it('calling
|
|
119
|
+
it('calling close with an error aborts streams', async () => {
|
|
104
120
|
let openedStreams = 0;
|
|
105
121
|
const expectedStreams = 5;
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
122
|
+
const dialerFactory = await common.setup();
|
|
123
|
+
const dialer = dialerFactory.createStreamMuxer({
|
|
124
|
+
direction: 'outbound'
|
|
109
125
|
});
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
if (!sendMore) {
|
|
118
|
-
await pEvent(stream, 'drain', {
|
|
119
|
-
rejectionEvents: ['close']
|
|
120
|
-
});
|
|
121
|
-
}
|
|
126
|
+
// Listener is echo server :)
|
|
127
|
+
const listenerFactory = await common.setup();
|
|
128
|
+
const listener = listenerFactory.createStreamMuxer({
|
|
129
|
+
direction: 'inbound',
|
|
130
|
+
onIncomingStream: (stream) => {
|
|
131
|
+
openedStreams++;
|
|
132
|
+
void pipe(stream, stream).catch(() => { });
|
|
122
133
|
}
|
|
123
134
|
});
|
|
124
|
-
|
|
135
|
+
const p = duplexPair();
|
|
136
|
+
void pipe(p[0], dialer, p[0]);
|
|
137
|
+
void pipe(p[1], listener, p[1]);
|
|
138
|
+
const streams = await Promise.all(Array(expectedStreams).fill(0).map(async () => dialer.newStream()));
|
|
139
|
+
const streamPipes = streams.map(async (stream) => {
|
|
140
|
+
await pipe(infiniteRandom(), stream, drain);
|
|
141
|
+
});
|
|
142
|
+
expect(dialer.streams, 'dialer - number of opened streams should match number of calls to newStream').to.have.lengthOf(expectedStreams);
|
|
143
|
+
// Pause, and then close the dialer
|
|
144
|
+
await delay(50);
|
|
145
|
+
// close _with an error_
|
|
146
|
+
dialer.abort(new Error('Oh no!'));
|
|
125
147
|
const timeoutError = new Error('timeout');
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
setTimeout(() => {
|
|
138
|
-
reject(timeoutError);
|
|
139
|
-
}, 70);
|
|
140
|
-
})
|
|
141
|
-
]);
|
|
142
|
-
expect.fail('stream pipe with infinite source should never return');
|
|
143
|
-
}
|
|
144
|
-
catch (e) {
|
|
145
|
-
if (e === timeoutError) {
|
|
146
|
-
expect.fail('expected stream pipe to throw an error after muxer closed with error');
|
|
147
|
-
}
|
|
148
|
+
for (const pipe of streamPipes) {
|
|
149
|
+
try {
|
|
150
|
+
await Promise.race([
|
|
151
|
+
pipe,
|
|
152
|
+
new Promise((_resolve, reject) => setTimeout(() => { reject(timeoutError); }, 20))
|
|
153
|
+
]);
|
|
154
|
+
expect.fail('stream pipe with infinite source should never return');
|
|
155
|
+
}
|
|
156
|
+
catch (e) {
|
|
157
|
+
if (e === timeoutError) {
|
|
158
|
+
expect.fail('expected stream pipe to throw an error after muxer closed with error');
|
|
148
159
|
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
expect(openedStreams
|
|
152
|
-
expect(dialer.streams
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
expect(openedStreams, 'listener - number of opened streams should match number of calls to newStream').to.have.equal(expectedStreams);
|
|
163
|
+
expect(dialer.streams, 'all tracked streams should be deleted after the muxer has called close').to.have.lengthOf(0);
|
|
153
164
|
});
|
|
154
165
|
it('calling newStream after close throws an error', async () => {
|
|
166
|
+
const dialerFactory = await common.setup();
|
|
167
|
+
const dialer = dialerFactory.createStreamMuxer({
|
|
168
|
+
direction: 'outbound'
|
|
169
|
+
});
|
|
155
170
|
await dialer.close();
|
|
156
|
-
|
|
157
|
-
|
|
171
|
+
try {
|
|
172
|
+
await dialer.newStream();
|
|
173
|
+
expect.fail('newStream should throw if called after close');
|
|
174
|
+
}
|
|
175
|
+
catch (e) {
|
|
176
|
+
expect(dialer.streams, 'closed muxer should have no streams').to.have.lengthOf(0);
|
|
177
|
+
}
|
|
158
178
|
});
|
|
159
179
|
it('closing one of the muxed streams doesn\'t close others', async () => {
|
|
160
|
-
const
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
180
|
+
const p = duplexPair();
|
|
181
|
+
const dialerFactory = await common.setup();
|
|
182
|
+
const dialer = dialerFactory.createStreamMuxer({
|
|
183
|
+
direction: 'outbound'
|
|
184
|
+
});
|
|
185
|
+
// Listener is echo server :)
|
|
186
|
+
const listenerFactory = await common.setup();
|
|
187
|
+
const listener = listenerFactory.createStreamMuxer({
|
|
188
|
+
direction: 'inbound',
|
|
189
|
+
onIncomingStream: (stream) => {
|
|
190
|
+
void pipe(stream, stream).catch(() => { });
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
void pipe(p[0], dialer, p[0]);
|
|
194
|
+
void pipe(p[1], listener, p[1]);
|
|
195
|
+
const stream = await dialer.newStream();
|
|
196
|
+
const streams = await Promise.all(Array.from(Array(5), async () => dialer.newStream()));
|
|
197
|
+
let closed = false;
|
|
198
|
+
const controllers = [];
|
|
199
|
+
const streamResults = streams.map(async (stream) => {
|
|
200
|
+
const controller = new AbortController();
|
|
201
|
+
controllers.push(controller);
|
|
202
|
+
try {
|
|
203
|
+
const abortableRand = abortableSource(infiniteRandom(), controller.signal, {
|
|
204
|
+
abortName: 'TestAbortError'
|
|
205
|
+
});
|
|
206
|
+
await pipe(abortableRand, stream, drain);
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
if (err.name !== 'TestAbortError') {
|
|
210
|
+
throw err;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (!closed) {
|
|
214
|
+
throw new Error('stream should not have ended yet!');
|
|
166
215
|
}
|
|
167
216
|
});
|
|
168
|
-
|
|
169
|
-
await
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
await Promise.all(
|
|
177
|
-
pEvent(remoteStream, 'close'),
|
|
178
|
-
pEvent(localStream, 'close'),
|
|
179
|
-
localStream.close()
|
|
180
|
-
]);
|
|
181
|
-
expect(dialer.streams).to.have.lengthOf(streamCount - 1);
|
|
182
|
-
expect(listener.streams).to.have.lengthOf(streamCount - 1);
|
|
183
|
-
expect(dialer.streams.map(s => s.status)).to.deep.equal(new Array(streamCount - 1).fill('open'));
|
|
184
|
-
expect(listener.streams.map(s => s.status)).to.deep.equal(new Array(streamCount - 1).fill('open'));
|
|
217
|
+
// Pause, and then send some data and close the first stream
|
|
218
|
+
await delay(50);
|
|
219
|
+
await pipe([new Uint8ArrayList(randomBuffer())], stream, drain);
|
|
220
|
+
closed = true;
|
|
221
|
+
// Abort all the other streams later
|
|
222
|
+
await delay(50);
|
|
223
|
+
controllers.forEach(c => { c.abort(); });
|
|
224
|
+
// These should now all resolve without error
|
|
225
|
+
await Promise.all(streamResults);
|
|
185
226
|
});
|
|
186
227
|
it('can close a stream for writing', async () => {
|
|
187
|
-
const deferred =
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
228
|
+
const deferred = pDefer();
|
|
229
|
+
const p = duplexPair();
|
|
230
|
+
const dialerFactory = await common.setup();
|
|
231
|
+
const dialer = dialerFactory.createStreamMuxer({
|
|
232
|
+
direction: 'outbound'
|
|
233
|
+
});
|
|
234
|
+
const data = [randomBuffer(), randomBuffer()];
|
|
235
|
+
const listenerFactory = await common.setup();
|
|
236
|
+
const listener = listenerFactory.createStreamMuxer({
|
|
237
|
+
direction: 'inbound',
|
|
238
|
+
onIncomingStream: (stream) => {
|
|
239
|
+
void Promise.resolve().then(async () => {
|
|
192
240
|
// Immediate close for write
|
|
193
|
-
await
|
|
194
|
-
|
|
241
|
+
await stream.closeWrite();
|
|
242
|
+
const results = await pipe(stream, async (source) => {
|
|
243
|
+
const data = [];
|
|
244
|
+
for await (const chunk of source) {
|
|
245
|
+
data.push(chunk.slice());
|
|
246
|
+
}
|
|
247
|
+
return data;
|
|
195
248
|
});
|
|
196
|
-
|
|
197
|
-
return buf.subarray();
|
|
198
|
-
}));
|
|
199
|
-
expect(results).to.deep.equal(data);
|
|
249
|
+
expect(results).to.eql(data);
|
|
200
250
|
try {
|
|
201
|
-
|
|
251
|
+
await stream.sink([new Uint8ArrayList(randomBuffer())]);
|
|
202
252
|
}
|
|
203
253
|
catch (err) {
|
|
204
254
|
deferred.resolve(err);
|
|
205
255
|
}
|
|
206
|
-
|
|
207
|
-
}
|
|
208
|
-
catch (err) {
|
|
209
|
-
deferred.reject(err);
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
});
|
|
213
|
-
const stream = await dialer.createStream();
|
|
214
|
-
for (const buf of data) {
|
|
215
|
-
if (!stream.send(buf)) {
|
|
216
|
-
await pEvent(stream, 'drain', {
|
|
217
|
-
rejectionEvents: [
|
|
218
|
-
'close'
|
|
219
|
-
]
|
|
256
|
+
deferred.reject(new Error('should not support writing to closed writer'));
|
|
220
257
|
});
|
|
221
258
|
}
|
|
222
|
-
}
|
|
223
|
-
await stream.close({
|
|
224
|
-
signal: AbortSignal.timeout(1_000)
|
|
225
259
|
});
|
|
260
|
+
void pipe(p[0], dialer, p[0]);
|
|
261
|
+
void pipe(p[1], listener, p[1]);
|
|
262
|
+
const stream = await dialer.newStream();
|
|
263
|
+
await stream.sink(data);
|
|
226
264
|
const err = await deferred.promise;
|
|
227
265
|
expect(err).to.have.property('name', 'StreamStateError');
|
|
228
266
|
});
|
|
229
|
-
it('
|
|
230
|
-
|
|
231
|
-
|
|
267
|
+
it('can close a stream for reading', async () => {
|
|
268
|
+
const deferred = pDefer();
|
|
269
|
+
const p = duplexPair();
|
|
270
|
+
const dialerFactory = await common.setup();
|
|
271
|
+
const dialer = dialerFactory.createStreamMuxer({
|
|
272
|
+
direction: 'outbound'
|
|
273
|
+
});
|
|
274
|
+
const data = [randomBuffer(), randomBuffer()].map(d => new Uint8ArrayList(d));
|
|
275
|
+
const expected = toBuffer(data.map(d => d.subarray()));
|
|
276
|
+
const listenerFactory = await common.setup();
|
|
277
|
+
const listener = listenerFactory.createStreamMuxer({
|
|
278
|
+
direction: 'inbound',
|
|
279
|
+
onIncomingStream: (stream) => {
|
|
280
|
+
void all(stream.source).then(deferred.resolve, deferred.reject);
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
void pipe(p[0], dialer, p[0]);
|
|
284
|
+
void pipe(p[1], listener, p[1]);
|
|
285
|
+
const stream = await dialer.newStream();
|
|
286
|
+
await stream.closeRead();
|
|
287
|
+
// Source should be done
|
|
288
|
+
void Promise.resolve().then(async () => {
|
|
289
|
+
expect(await stream.source.next()).to.have.property('done', true);
|
|
290
|
+
await stream.sink(data);
|
|
232
291
|
});
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
292
|
+
const results = await deferred.promise;
|
|
293
|
+
expect(toBuffer(results.map(b => b.subarray()))).to.equalBytes(expected);
|
|
294
|
+
});
|
|
295
|
+
it('calls onStreamEnd for closed streams not previously written', async () => {
|
|
296
|
+
const deferred = pDefer();
|
|
297
|
+
const onStreamEnd = () => { deferred.resolve(); };
|
|
298
|
+
const dialerFactory = await common.setup();
|
|
299
|
+
const dialer = dialerFactory.createStreamMuxer({
|
|
300
|
+
direction: 'outbound',
|
|
301
|
+
onStreamEnd
|
|
237
302
|
});
|
|
303
|
+
const stream = await dialer.newStream();
|
|
238
304
|
await stream.close();
|
|
239
305
|
await deferred.promise;
|
|
240
306
|
});
|
|
241
|
-
it('
|
|
242
|
-
const deferred =
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
307
|
+
it('calls onStreamEnd for read and write closed streams not previously written', async () => {
|
|
308
|
+
const deferred = pDefer();
|
|
309
|
+
const onStreamEnd = () => { deferred.resolve(); };
|
|
310
|
+
const dialerFactory = await common.setup();
|
|
311
|
+
const dialer = dialerFactory.createStreamMuxer({
|
|
312
|
+
direction: 'outbound',
|
|
313
|
+
onStreamEnd
|
|
246
314
|
});
|
|
247
|
-
stream.
|
|
315
|
+
const stream = await dialer.newStream();
|
|
316
|
+
await stream.closeWrite();
|
|
317
|
+
await stream.closeRead();
|
|
248
318
|
await deferred.promise;
|
|
249
319
|
});
|
|
250
320
|
it('should wait for all data to be sent when closing streams', async () => {
|
|
251
|
-
const deferred =
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
321
|
+
const deferred = pDefer();
|
|
322
|
+
const p = duplexPair();
|
|
323
|
+
const dialerFactory = await common.setup();
|
|
324
|
+
const dialer = dialerFactory.createStreamMuxer({
|
|
325
|
+
direction: 'outbound'
|
|
326
|
+
});
|
|
327
|
+
const listenerFactory = await common.setup();
|
|
328
|
+
const listener = listenerFactory.createStreamMuxer({
|
|
329
|
+
direction: 'inbound',
|
|
330
|
+
onIncomingStream: (stream) => {
|
|
331
|
+
const pb = pbStream(stream);
|
|
332
|
+
void pb.read(Message)
|
|
333
|
+
.then(async (message) => {
|
|
334
|
+
deferred.resolve(message);
|
|
335
|
+
await pb.unwrap().close();
|
|
336
|
+
})
|
|
337
|
+
.catch(err => {
|
|
338
|
+
deferred.reject(err);
|
|
339
|
+
});
|
|
340
|
+
}
|
|
262
341
|
});
|
|
342
|
+
void pipe(p[0], dialer, p[0]);
|
|
343
|
+
void pipe(p[1], listener, p[1]);
|
|
263
344
|
const message = {
|
|
264
345
|
message: 'hello world',
|
|
265
346
|
value: 5,
|
|
266
347
|
flag: true
|
|
267
348
|
};
|
|
268
|
-
const stream = await dialer.
|
|
349
|
+
const stream = await dialer.newStream();
|
|
269
350
|
const pb = pbStream(stream);
|
|
270
351
|
await pb.write(message, Message);
|
|
271
|
-
await
|
|
352
|
+
await pb.unwrap().close();
|
|
272
353
|
await expect(deferred.promise).to.eventually.deep.equal(message);
|
|
273
354
|
});
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
]);
|
|
326
|
-
expect(dialer.streams).to.include(dialerStream, 'dialer did not store outbound stream');
|
|
327
|
-
expect(listener.streams).to.include(listenerStream, 'listener did not store inbound stream');
|
|
328
|
-
await listenerStream.close();
|
|
329
|
-
expect(dialer.streams).to.include(dialerStream, 'dialer removed outbound stream before fully closing');
|
|
330
|
-
expect(listener.streams).to.include(listenerStream, 'listener removed inbound stream before fully closing');
|
|
331
|
-
await Promise.all([
|
|
332
|
-
pEvent(listenerStream, 'close'),
|
|
333
|
-
dialerStream.close()
|
|
334
|
-
]);
|
|
335
|
-
await delay(10);
|
|
336
|
-
expect(dialer.streams).to.not.include(dialerStream, 'dialer did not remove outbound stream close');
|
|
337
|
-
expect(listener.streams).to.not.include(listenerStream, 'listener did not remove inbound stream after close');
|
|
338
|
-
});
|
|
355
|
+
/*
|
|
356
|
+
it('should abort closing a stream with outstanding data to read', async () => {
|
|
357
|
+
const deferred = pDefer<Message>()
|
|
358
|
+
|
|
359
|
+
const p = duplexPair<Uint8Array | Uint8ArrayList>()
|
|
360
|
+
const dialerFactory = await common.setup()
|
|
361
|
+
const dialer = dialerFactory.createStreamMuxer({ direction: 'outbound' })
|
|
362
|
+
|
|
363
|
+
const listenerFactory = await common.setup()
|
|
364
|
+
const listener = listenerFactory.createStreamMuxer({
|
|
365
|
+
direction: 'inbound',
|
|
366
|
+
onIncomingStream: (stream) => {
|
|
367
|
+
const pb = pbStream(stream)
|
|
368
|
+
|
|
369
|
+
void pb.read(Message)
|
|
370
|
+
.then(async message => {
|
|
371
|
+
await pb.write(message, Message)
|
|
372
|
+
await pb.unwrap().close()
|
|
373
|
+
deferred.resolve(message)
|
|
374
|
+
})
|
|
375
|
+
.catch(err => {
|
|
376
|
+
deferred.reject(err)
|
|
377
|
+
})
|
|
378
|
+
}
|
|
379
|
+
})
|
|
380
|
+
|
|
381
|
+
void pipe(p[0], dialer, p[0])
|
|
382
|
+
void pipe(p[1], listener, p[1])
|
|
383
|
+
|
|
384
|
+
const message = {
|
|
385
|
+
message: 'hello world',
|
|
386
|
+
value: 5,
|
|
387
|
+
flag: true
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const stream = await dialer.newStream()
|
|
391
|
+
|
|
392
|
+
const pb = pbStream(stream)
|
|
393
|
+
await pb.write(message, Message)
|
|
394
|
+
|
|
395
|
+
console.info('await write back')
|
|
396
|
+
await deferred.promise
|
|
397
|
+
|
|
398
|
+
// let message arrive
|
|
399
|
+
await delay(100)
|
|
400
|
+
|
|
401
|
+
// close should time out as message is never read
|
|
402
|
+
await expect(pb.unwrap().close()).to.eventually.be.rejected
|
|
403
|
+
.with.property('name', 'TimeoutError')
|
|
404
|
+
})
|
|
405
|
+
*/
|
|
339
406
|
});
|
|
340
407
|
};
|
|
341
408
|
//# sourceMappingURL=close-test.js.map
|