@libp2p/interface-compliance-tests 6.5.0 → 7.0.0-049bfa0fa
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 +23 -51
- 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,104 +1,80 @@
|
|
|
1
1
|
/* eslint max-nested-callbacks: ["error", 8] */
|
|
2
|
-
import {
|
|
2
|
+
import { multiaddrConnectionPair, echo, pbStream } from '@libp2p/utils'
|
|
3
3
|
import { expect } from 'aegir/chai'
|
|
4
4
|
import delay from 'delay'
|
|
5
5
|
import all from 'it-all'
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
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'
|
|
6
|
+
import map from 'it-map'
|
|
7
|
+
import { pEvent } from 'p-event'
|
|
12
8
|
import { Uint8ArrayList } from 'uint8arraylist'
|
|
13
9
|
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
|
|
14
10
|
import { Message } from './fixtures/pb/message.js'
|
|
15
11
|
import type { TestSetup } from '../index.js'
|
|
16
|
-
import type { StreamMuxerFactory } from '@libp2p/interface'
|
|
12
|
+
import type { MultiaddrConnection, Stream, StreamMuxer, StreamMuxerFactory } from '@libp2p/interface'
|
|
17
13
|
|
|
18
14
|
function randomBuffer (): Uint8Array {
|
|
19
15
|
return uint8ArrayFromString(Math.random().toString())
|
|
20
16
|
}
|
|
21
17
|
|
|
22
|
-
function infiniteRandom (): AsyncGenerator<Uint8ArrayList, void, unknown> {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
},
|
|
29
|
-
async next () {
|
|
30
|
-
await delay(10)
|
|
31
|
-
|
|
32
|
-
if (done instanceof Error) {
|
|
33
|
-
throw done
|
|
34
|
-
}
|
|
18
|
+
async function * infiniteRandom (): AsyncGenerator<Uint8ArrayList, void, unknown> {
|
|
19
|
+
while (true) {
|
|
20
|
+
await delay(10)
|
|
21
|
+
yield new Uint8ArrayList(randomBuffer())
|
|
22
|
+
}
|
|
23
|
+
}
|
|
35
24
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
25
|
+
export default (common: TestSetup<StreamMuxerFactory>): void => {
|
|
26
|
+
describe('close', () => {
|
|
27
|
+
let outboundConnection: MultiaddrConnection
|
|
28
|
+
let inboundConnection: MultiaddrConnection
|
|
29
|
+
let dialer: StreamMuxer
|
|
30
|
+
let listener: StreamMuxer
|
|
42
31
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
value: new Uint8ArrayList(randomBuffer())
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
async return (): Promise<IteratorReturnResult<void>> {
|
|
49
|
-
done = true
|
|
32
|
+
beforeEach(async () => {
|
|
33
|
+
[outboundConnection, inboundConnection] = multiaddrConnectionPair()
|
|
50
34
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
value: undefined
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
async throw (err: Error): Promise<IteratorReturnResult<void>> {
|
|
57
|
-
done = err
|
|
35
|
+
const dialerFactory = await common.setup()
|
|
36
|
+
dialer = dialerFactory.createStreamMuxer(outboundConnection)
|
|
58
37
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
38
|
+
const listenerFactory = await common.setup()
|
|
39
|
+
listener = listenerFactory.createStreamMuxer(inboundConnection)
|
|
40
|
+
})
|
|
65
41
|
|
|
66
|
-
|
|
67
|
-
|
|
42
|
+
afterEach(async () => {
|
|
43
|
+
await dialer?.close()
|
|
44
|
+
await listener?.close()
|
|
45
|
+
})
|
|
68
46
|
|
|
69
|
-
|
|
70
|
-
describe('close', () => {
|
|
71
|
-
it('closing underlying socket closes streams', async () => {
|
|
47
|
+
it('closing underlying MultiaddrConnection closes streams', async () => {
|
|
72
48
|
let openedStreams = 0
|
|
73
49
|
const expectedStreams = 5
|
|
74
|
-
const dialerFactory = await common.setup()
|
|
75
|
-
const dialer = dialerFactory.createStreamMuxer({
|
|
76
|
-
direction: 'outbound'
|
|
77
|
-
})
|
|
78
50
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const listener = listenerFactory.createStreamMuxer({
|
|
82
|
-
direction: 'inbound',
|
|
83
|
-
onIncomingStream: (stream) => {
|
|
84
|
-
openedStreams++
|
|
85
|
-
void pipe(stream, stream)
|
|
86
|
-
}
|
|
87
|
-
})
|
|
51
|
+
listener.addEventListener('stream', (evt) => {
|
|
52
|
+
openedStreams++
|
|
88
53
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
void pipe(p[1], listener, p[1])
|
|
54
|
+
echo(evt.detail)
|
|
55
|
+
})
|
|
92
56
|
|
|
93
|
-
const streams = await Promise.all(
|
|
57
|
+
const streams = await Promise.all(
|
|
58
|
+
Array(expectedStreams).fill(0).map(async () => dialer.createStream())
|
|
59
|
+
)
|
|
94
60
|
|
|
95
61
|
void Promise.all(
|
|
96
62
|
streams.map(async stream => {
|
|
97
|
-
await
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
63
|
+
for await (const buf of infiniteRandom()) {
|
|
64
|
+
if (stream.status !== 'open') {
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const sendMore = stream.send(buf)
|
|
69
|
+
|
|
70
|
+
if (!sendMore) {
|
|
71
|
+
await pEvent(stream, 'drain', {
|
|
72
|
+
rejectionEvents: [
|
|
73
|
+
'close'
|
|
74
|
+
]
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
}
|
|
102
78
|
})
|
|
103
79
|
)
|
|
104
80
|
|
|
@@ -106,7 +82,9 @@ export default (common: TestSetup<StreamMuxerFactory>): void => {
|
|
|
106
82
|
|
|
107
83
|
// Pause, and then close the dialer
|
|
108
84
|
await delay(50)
|
|
109
|
-
await
|
|
85
|
+
await inboundConnection.close()
|
|
86
|
+
await outboundConnection.close()
|
|
87
|
+
await delay(50)
|
|
110
88
|
|
|
111
89
|
expect(openedStreams).to.have.equal(expectedStreams)
|
|
112
90
|
expect(dialer.streams).to.have.lengthOf(0)
|
|
@@ -115,36 +93,37 @@ export default (common: TestSetup<StreamMuxerFactory>): void => {
|
|
|
115
93
|
it('calling close closes streams', async () => {
|
|
116
94
|
let openedStreams = 0
|
|
117
95
|
const expectedStreams = 5
|
|
118
|
-
const dialerFactory = await common.setup()
|
|
119
|
-
const dialer = dialerFactory.createStreamMuxer({
|
|
120
|
-
direction: 'outbound'
|
|
121
|
-
})
|
|
122
96
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const listener = listenerFactory.createStreamMuxer({
|
|
126
|
-
direction: 'inbound',
|
|
127
|
-
onIncomingStream: (stream) => {
|
|
128
|
-
openedStreams++
|
|
129
|
-
void pipe(stream, stream).catch(() => {})
|
|
130
|
-
}
|
|
131
|
-
})
|
|
97
|
+
listener.addEventListener('stream', (evt) => {
|
|
98
|
+
openedStreams++
|
|
132
99
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
void pipe(p[1], listener, p[1])
|
|
100
|
+
echo(evt.detail)
|
|
101
|
+
})
|
|
136
102
|
|
|
137
|
-
const streams = await Promise.all(Array(expectedStreams).fill(0).map(async () => dialer.
|
|
103
|
+
const streams = await Promise.all(Array(expectedStreams).fill(0).map(async () => dialer.createStream()))
|
|
138
104
|
|
|
139
105
|
void Promise.all(
|
|
140
106
|
streams.map(async stream => {
|
|
141
|
-
await
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
107
|
+
for await (const buf of infiniteRandom()) {
|
|
108
|
+
if (stream.status !== 'open') {
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const sendMore = stream.send(buf)
|
|
113
|
+
|
|
114
|
+
if (!sendMore) {
|
|
115
|
+
await pEvent(stream, 'drain', {
|
|
116
|
+
rejectionEvents: [
|
|
117
|
+
'close'
|
|
118
|
+
]
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
}
|
|
146
122
|
})
|
|
147
123
|
)
|
|
124
|
+
.catch(() => {
|
|
125
|
+
// calling .send on a closed stream will throw so swallow any errors
|
|
126
|
+
})
|
|
148
127
|
|
|
149
128
|
expect(dialer.streams, 'dialer - number of opened streams should match number of calls to newStream').to.have.lengthOf(expectedStreams)
|
|
150
129
|
|
|
@@ -153,346 +132,329 @@ export default (common: TestSetup<StreamMuxerFactory>): void => {
|
|
|
153
132
|
|
|
154
133
|
await dialer.close()
|
|
155
134
|
|
|
135
|
+
await delay(50)
|
|
136
|
+
|
|
156
137
|
expect(openedStreams, 'listener - number of opened streams should match number of calls to newStream').to.have.equal(expectedStreams)
|
|
157
138
|
expect(dialer.streams, 'all tracked streams should be deleted after the muxer has called close').to.have.lengthOf(0)
|
|
158
139
|
})
|
|
159
140
|
|
|
160
|
-
it('calling
|
|
141
|
+
it('calling abort aborts streams', async () => {
|
|
161
142
|
let openedStreams = 0
|
|
162
143
|
const expectedStreams = 5
|
|
163
|
-
const dialerFactory = await common.setup()
|
|
164
|
-
const dialer = dialerFactory.createStreamMuxer({
|
|
165
|
-
direction: 'outbound'
|
|
166
|
-
})
|
|
167
144
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const listener = listenerFactory.createStreamMuxer({
|
|
171
|
-
direction: 'inbound',
|
|
172
|
-
onIncomingStream: (stream) => {
|
|
173
|
-
openedStreams++
|
|
174
|
-
void pipe(stream, stream).catch(() => {})
|
|
175
|
-
}
|
|
176
|
-
})
|
|
145
|
+
listener.addEventListener('stream', (evt) => {
|
|
146
|
+
openedStreams++
|
|
177
147
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
void pipe(p[1], listener, p[1])
|
|
148
|
+
echo(evt.detail)
|
|
149
|
+
})
|
|
181
150
|
|
|
182
|
-
const streams = await Promise.all(
|
|
151
|
+
const streams = await Promise.all(
|
|
152
|
+
Array(expectedStreams).fill(0).map(async () => dialer.createStream())
|
|
153
|
+
)
|
|
183
154
|
|
|
184
155
|
const streamPipes = streams.map(async stream => {
|
|
185
|
-
await
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
)
|
|
190
|
-
})
|
|
156
|
+
for await (const buf of infiniteRandom()) {
|
|
157
|
+
if (stream.writeStatus !== 'writable') {
|
|
158
|
+
break
|
|
159
|
+
}
|
|
191
160
|
|
|
192
|
-
|
|
161
|
+
const sendMore = stream.send(buf)
|
|
193
162
|
|
|
194
|
-
|
|
195
|
-
|
|
163
|
+
if (!sendMore) {
|
|
164
|
+
await pEvent(stream, 'drain', {
|
|
165
|
+
rejectionEvents: ['close']
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
})
|
|
196
170
|
|
|
197
|
-
|
|
198
|
-
dialer.abort(new Error('Oh no!'))
|
|
171
|
+
expect(dialer.streams).to.have.lengthOf(expectedStreams, 'dialer - number of opened streams should match number of calls to createStream')
|
|
199
172
|
|
|
200
173
|
const timeoutError = new Error('timeout')
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
174
|
+
|
|
175
|
+
await Promise.all([
|
|
176
|
+
// Pause, and then close the dialer
|
|
177
|
+
delay(50).then(() => {
|
|
178
|
+
// close _with an error_
|
|
179
|
+
dialer.abort(new Error('Oh no!'))
|
|
180
|
+
}),
|
|
181
|
+
...streamPipes.map(async pipe => {
|
|
182
|
+
try {
|
|
183
|
+
await Promise.race([
|
|
184
|
+
pipe,
|
|
185
|
+
new Promise((resolve, reject) => {
|
|
186
|
+
setTimeout(() => {
|
|
187
|
+
reject(timeoutError)
|
|
188
|
+
}, 70)
|
|
189
|
+
})
|
|
190
|
+
])
|
|
191
|
+
expect.fail('stream pipe with infinite source should never return')
|
|
192
|
+
} catch (e) {
|
|
193
|
+
if (e === timeoutError) {
|
|
194
|
+
expect.fail('expected stream pipe to throw an error after muxer closed with error')
|
|
195
|
+
}
|
|
211
196
|
}
|
|
212
|
-
}
|
|
213
|
-
|
|
197
|
+
})
|
|
198
|
+
])
|
|
214
199
|
|
|
215
|
-
expect(openedStreams, 'listener - number of opened streams should match number of calls to
|
|
216
|
-
expect(dialer.streams, 'all tracked streams should be deleted after the muxer has called close')
|
|
200
|
+
expect(openedStreams).to.equal(expectedStreams, 'listener - number of opened streams should match number of calls to createStream')
|
|
201
|
+
expect(dialer.streams).to.have.lengthOf(0, 'all tracked streams should be deleted after the muxer has called close')
|
|
217
202
|
})
|
|
218
203
|
|
|
219
204
|
it('calling newStream after close throws an error', async () => {
|
|
220
|
-
const dialerFactory = await common.setup()
|
|
221
|
-
const dialer = dialerFactory.createStreamMuxer({
|
|
222
|
-
direction: 'outbound'
|
|
223
|
-
})
|
|
224
|
-
|
|
225
205
|
await dialer.close()
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
await dialer.newStream()
|
|
229
|
-
expect.fail('newStream should throw if called after close')
|
|
230
|
-
} catch (e) {
|
|
231
|
-
expect(dialer.streams, 'closed muxer should have no streams').to.have.lengthOf(0)
|
|
232
|
-
}
|
|
206
|
+
await expect(dialer.createStream()).to.eventually.rejected.with.property('name', 'MuxerClosedError')
|
|
207
|
+
expect(dialer.streams).to.have.lengthOf(0, 'closed muxer should have no streams')
|
|
233
208
|
})
|
|
234
209
|
|
|
235
210
|
it('closing one of the muxed streams doesn\'t close others', async () => {
|
|
236
|
-
const
|
|
237
|
-
const
|
|
238
|
-
const dialer = dialerFactory.createStreamMuxer({
|
|
239
|
-
direction: 'outbound'
|
|
240
|
-
})
|
|
211
|
+
const streamCount = 5
|
|
212
|
+
const allStreamsOpen = Promise.withResolvers<void>()
|
|
241
213
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
void pipe(stream, stream).catch(() => {})
|
|
214
|
+
listener.addEventListener('stream', (evt) => {
|
|
215
|
+
echo(evt.detail).catch(() => {})
|
|
216
|
+
|
|
217
|
+
if (listener.streams.length === streamCount) {
|
|
218
|
+
allStreamsOpen.resolve()
|
|
248
219
|
}
|
|
249
220
|
})
|
|
250
221
|
|
|
251
|
-
|
|
252
|
-
|
|
222
|
+
const streams = await Promise.all(
|
|
223
|
+
Array.from(Array(streamCount), async () => dialer.createStream())
|
|
224
|
+
)
|
|
225
|
+
await allStreamsOpen.promise
|
|
253
226
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
let closed = false
|
|
257
|
-
const controllers: AbortController[] = []
|
|
227
|
+
expect(dialer.streams).to.have.lengthOf(streamCount)
|
|
228
|
+
expect(listener.streams).to.have.lengthOf(streamCount)
|
|
258
229
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
controllers.push(controller)
|
|
230
|
+
expect(dialer.streams.map(s => s.status)).to.deep.equal(new Array(streamCount).fill('open'))
|
|
231
|
+
expect(listener.streams.map(s => s.status)).to.deep.equal(new Array(streamCount).fill('open'))
|
|
262
232
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
abortName: 'TestAbortError'
|
|
266
|
-
})
|
|
267
|
-
await pipe(abortableRand, stream, drain)
|
|
268
|
-
} catch (err: any) {
|
|
269
|
-
if (err.name !== 'TestAbortError') { throw err }
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
if (!closed) { throw new Error('stream should not have ended yet!') }
|
|
273
|
-
})
|
|
233
|
+
const localStream = streams[0]
|
|
234
|
+
const remoteStream = listener.streams[0]
|
|
274
235
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
236
|
+
await Promise.all([
|
|
237
|
+
pEvent(remoteStream, 'close'),
|
|
238
|
+
pEvent(localStream, 'close'),
|
|
239
|
+
localStream.close()
|
|
240
|
+
])
|
|
279
241
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
controllers.forEach(c => { c.abort() })
|
|
242
|
+
expect(dialer.streams).to.have.lengthOf(streamCount - 1)
|
|
243
|
+
expect(listener.streams).to.have.lengthOf(streamCount - 1)
|
|
283
244
|
|
|
284
|
-
|
|
285
|
-
|
|
245
|
+
expect(dialer.streams.map(s => s.status)).to.deep.equal(new Array(streamCount - 1).fill('open'))
|
|
246
|
+
expect(listener.streams.map(s => s.status)).to.deep.equal(new Array(streamCount - 1).fill('open'))
|
|
286
247
|
})
|
|
287
248
|
|
|
288
249
|
it('can close a stream for writing', async () => {
|
|
289
|
-
const deferred =
|
|
290
|
-
|
|
291
|
-
const p = duplexPair<Uint8Array | Uint8ArrayList>()
|
|
292
|
-
const dialerFactory = await common.setup()
|
|
293
|
-
const dialer = dialerFactory.createStreamMuxer({
|
|
294
|
-
direction: 'outbound'
|
|
295
|
-
})
|
|
296
|
-
const data = [randomBuffer(), randomBuffer()]
|
|
250
|
+
const deferred = Promise.withResolvers<Error>()
|
|
251
|
+
const data = [Uint8Array.from([0, 1, 2, 3, 4]), Uint8Array.from([5, 6, 7, 8, 9])]
|
|
297
252
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
onIncomingStream: (stream) => {
|
|
302
|
-
void Promise.resolve().then(async () => {
|
|
253
|
+
listener.addEventListener('stream', (evt) => {
|
|
254
|
+
void Promise.resolve().then(async () => {
|
|
255
|
+
try {
|
|
303
256
|
// Immediate close for write
|
|
304
|
-
await
|
|
305
|
-
|
|
306
|
-
const results = await pipe(stream, async (source) => {
|
|
307
|
-
const data = []
|
|
308
|
-
for await (const chunk of source) {
|
|
309
|
-
data.push(chunk.slice())
|
|
310
|
-
}
|
|
311
|
-
return data
|
|
257
|
+
await evt.detail.close({
|
|
258
|
+
signal: AbortSignal.timeout(1_000)
|
|
312
259
|
})
|
|
313
|
-
|
|
260
|
+
|
|
261
|
+
const results = await all(map(evt.detail, (buf) => {
|
|
262
|
+
return buf.subarray()
|
|
263
|
+
}))
|
|
264
|
+
|
|
265
|
+
expect(results).to.deep.equal(data)
|
|
314
266
|
|
|
315
267
|
try {
|
|
316
|
-
|
|
268
|
+
evt.detail.send(randomBuffer())
|
|
317
269
|
} catch (err: any) {
|
|
318
270
|
deferred.resolve(err)
|
|
319
271
|
}
|
|
320
272
|
|
|
321
|
-
|
|
322
|
-
})
|
|
323
|
-
|
|
273
|
+
throw new Error('should not support writing to closed writer')
|
|
274
|
+
} catch (err) {
|
|
275
|
+
deferred.reject(err)
|
|
276
|
+
}
|
|
277
|
+
})
|
|
324
278
|
})
|
|
325
279
|
|
|
326
|
-
|
|
327
|
-
void pipe(p[1], listener, p[1])
|
|
328
|
-
|
|
329
|
-
const stream = await dialer.newStream()
|
|
330
|
-
await stream.sink(data)
|
|
331
|
-
|
|
332
|
-
const err = await deferred.promise
|
|
333
|
-
expect(err).to.have.property('name', 'StreamStateError')
|
|
334
|
-
})
|
|
335
|
-
|
|
336
|
-
it('can close a stream for reading', async () => {
|
|
337
|
-
const deferred = pDefer<Uint8ArrayList[]>()
|
|
338
|
-
const p = duplexPair<Uint8Array | Uint8ArrayList>()
|
|
339
|
-
const dialerFactory = await common.setup()
|
|
340
|
-
const dialer = dialerFactory.createStreamMuxer({
|
|
341
|
-
direction: 'outbound'
|
|
342
|
-
})
|
|
343
|
-
const data = [randomBuffer(), randomBuffer()].map(d => new Uint8ArrayList(d))
|
|
344
|
-
const expected = toBuffer(data.map(d => d.subarray()))
|
|
280
|
+
const stream = await dialer.createStream()
|
|
345
281
|
|
|
346
|
-
const
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
282
|
+
for (const buf of data) {
|
|
283
|
+
if (!stream.send(buf)) {
|
|
284
|
+
await pEvent(stream, 'drain', {
|
|
285
|
+
rejectionEvents: [
|
|
286
|
+
'close'
|
|
287
|
+
]
|
|
288
|
+
})
|
|
351
289
|
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
void pipe(p[0], dialer, p[0])
|
|
355
|
-
void pipe(p[1], listener, p[1])
|
|
356
|
-
|
|
357
|
-
const stream = await dialer.newStream()
|
|
358
|
-
await stream.closeRead()
|
|
290
|
+
}
|
|
359
291
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
expect(await stream.source.next()).to.have.property('done', true)
|
|
363
|
-
await stream.sink(data)
|
|
292
|
+
await stream.close({
|
|
293
|
+
signal: AbortSignal.timeout(1_000)
|
|
364
294
|
})
|
|
365
295
|
|
|
366
|
-
const
|
|
367
|
-
expect(
|
|
296
|
+
const err = await deferred.promise
|
|
297
|
+
expect(err).to.have.property('name', 'StreamStateError')
|
|
368
298
|
})
|
|
369
299
|
|
|
370
|
-
it('
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
const onStreamEnd = (): void => { deferred.resolve() }
|
|
374
|
-
const dialerFactory = await common.setup()
|
|
375
|
-
const dialer = dialerFactory.createStreamMuxer({
|
|
376
|
-
direction: 'outbound',
|
|
377
|
-
onStreamEnd
|
|
300
|
+
it('should emit a close event for closed streams not previously written', async () => {
|
|
301
|
+
listener.addEventListener('stream', async (evt) => {
|
|
302
|
+
void evt.detail.close()
|
|
378
303
|
})
|
|
379
304
|
|
|
380
|
-
const
|
|
305
|
+
const deferred = Promise.withResolvers<void>()
|
|
306
|
+
const stream = await dialer.createStream()
|
|
307
|
+
stream.addEventListener('close', () => {
|
|
308
|
+
deferred.resolve()
|
|
309
|
+
})
|
|
381
310
|
|
|
382
311
|
await stream.close()
|
|
383
312
|
await deferred.promise
|
|
384
313
|
})
|
|
385
314
|
|
|
386
|
-
it('
|
|
387
|
-
const deferred =
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
const dialer = dialerFactory.createStreamMuxer({
|
|
392
|
-
direction: 'outbound',
|
|
393
|
-
onStreamEnd
|
|
315
|
+
it('should emit a close event for aborted streams not previously written', async () => {
|
|
316
|
+
const deferred = Promise.withResolvers<void>()
|
|
317
|
+
const stream = await dialer.createStream()
|
|
318
|
+
stream.addEventListener('close', () => {
|
|
319
|
+
deferred.resolve()
|
|
394
320
|
})
|
|
395
321
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
await stream.closeWrite()
|
|
399
|
-
await stream.closeRead()
|
|
322
|
+
stream.abort(new Error('Urk!'))
|
|
400
323
|
await deferred.promise
|
|
401
324
|
})
|
|
402
325
|
|
|
403
326
|
it('should wait for all data to be sent when closing streams', async () => {
|
|
404
|
-
const deferred =
|
|
327
|
+
const deferred = Promise.withResolvers<Message>()
|
|
405
328
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
const dialer = dialerFactory.createStreamMuxer({
|
|
409
|
-
direction: 'outbound'
|
|
410
|
-
})
|
|
329
|
+
listener.addEventListener('stream', (evt) => {
|
|
330
|
+
const pb = pbStream(evt.detail)
|
|
411
331
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
deferred.resolve(message)
|
|
421
|
-
await pb.unwrap().close()
|
|
422
|
-
})
|
|
423
|
-
.catch(err => {
|
|
424
|
-
deferred.reject(err)
|
|
425
|
-
})
|
|
426
|
-
}
|
|
332
|
+
void pb.read(Message)
|
|
333
|
+
.then(async message => {
|
|
334
|
+
deferred.resolve(message)
|
|
335
|
+
await evt.detail.close()
|
|
336
|
+
})
|
|
337
|
+
.catch(err => {
|
|
338
|
+
deferred.reject(err)
|
|
339
|
+
})
|
|
427
340
|
})
|
|
428
341
|
|
|
429
|
-
void pipe(p[0], dialer, p[0])
|
|
430
|
-
void pipe(p[1], listener, p[1])
|
|
431
|
-
|
|
432
342
|
const message = {
|
|
433
343
|
message: 'hello world',
|
|
434
344
|
value: 5,
|
|
435
345
|
flag: true
|
|
436
346
|
}
|
|
437
347
|
|
|
438
|
-
const stream = await dialer.
|
|
348
|
+
const stream = await dialer.createStream()
|
|
439
349
|
|
|
440
350
|
const pb = pbStream(stream)
|
|
441
351
|
await pb.write(message, Message)
|
|
442
|
-
await
|
|
352
|
+
await stream.close()
|
|
443
353
|
|
|
444
354
|
await expect(deferred.promise).to.eventually.deep.equal(message)
|
|
445
355
|
})
|
|
446
|
-
/*
|
|
447
|
-
it('should abort closing a stream with outstanding data to read', async () => {
|
|
448
|
-
const deferred = pDefer<Message>()
|
|
449
356
|
|
|
450
|
-
|
|
451
|
-
const
|
|
452
|
-
|
|
357
|
+
it('should remove a stream in the streams list after aborting', async () => {
|
|
358
|
+
const [
|
|
359
|
+
listenerStream,
|
|
360
|
+
dialerStream
|
|
361
|
+
] = await Promise.all([
|
|
362
|
+
pEvent<'stream', CustomEvent<Stream>>(listener, 'stream').then(evt => evt.detail),
|
|
363
|
+
dialer.createStream()
|
|
364
|
+
])
|
|
365
|
+
|
|
366
|
+
expect(dialer.streams).to.include(dialerStream, 'dialer did not store outbound stream')
|
|
367
|
+
expect(listener.streams).to.include(listenerStream, 'listener did not store inbound stream')
|
|
368
|
+
|
|
369
|
+
await Promise.all([
|
|
370
|
+
pEvent(listenerStream, 'close'),
|
|
371
|
+
// eslint-disable-next-line @typescript-eslint/await-thenable
|
|
372
|
+
dialerStream.abort(new Error('Urk!'))
|
|
373
|
+
])
|
|
374
|
+
|
|
375
|
+
expect(dialer.streams).to.not.include(dialerStream, 'dialer did not remove outbound stream close')
|
|
376
|
+
expect(listener.streams).to.not.include(listenerStream, 'listener did not remove inbound stream after close')
|
|
377
|
+
})
|
|
453
378
|
|
|
454
|
-
|
|
455
|
-
const
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
await pb.write(message, Message)
|
|
463
|
-
await pb.unwrap().close()
|
|
464
|
-
deferred.resolve(message)
|
|
465
|
-
})
|
|
466
|
-
.catch(err => {
|
|
467
|
-
deferred.reject(err)
|
|
468
|
-
})
|
|
469
|
-
}
|
|
470
|
-
})
|
|
379
|
+
it('should remove a stream in the streams list after closing', async () => {
|
|
380
|
+
const [
|
|
381
|
+
listenerStream,
|
|
382
|
+
dialerStream
|
|
383
|
+
] = await Promise.all([
|
|
384
|
+
pEvent<'stream', CustomEvent<Stream>>(listener, 'stream').then(evt => evt.detail),
|
|
385
|
+
dialer.createStream()
|
|
386
|
+
])
|
|
471
387
|
|
|
472
|
-
|
|
473
|
-
|
|
388
|
+
expect(dialer.streams).to.include(dialerStream, 'dialer did not store outbound stream')
|
|
389
|
+
expect(listener.streams).to.include(listenerStream, 'listener did not store inbound stream')
|
|
474
390
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
}
|
|
391
|
+
await Promise.all([
|
|
392
|
+
dialerStream.close(),
|
|
393
|
+
listenerStream.close()
|
|
394
|
+
])
|
|
480
395
|
|
|
481
|
-
|
|
396
|
+
await delay(10)
|
|
482
397
|
|
|
483
|
-
|
|
484
|
-
|
|
398
|
+
expect(dialer.streams).to.not.include(dialerStream, 'dialer did not remove outbound stream close')
|
|
399
|
+
expect(listener.streams).to.not.include(listenerStream, 'listener did not remove inbound stream after close')
|
|
400
|
+
})
|
|
485
401
|
|
|
486
|
-
|
|
487
|
-
|
|
402
|
+
it('should not remove a half-closed outbound stream', async () => {
|
|
403
|
+
const [
|
|
404
|
+
listenerStream,
|
|
405
|
+
dialerStream
|
|
406
|
+
] = await Promise.all([
|
|
407
|
+
pEvent<'stream', CustomEvent<Stream>>(listener, 'stream').then(evt => evt.detail),
|
|
408
|
+
dialer.createStream()
|
|
409
|
+
])
|
|
410
|
+
|
|
411
|
+
await dialerStream.close()
|
|
412
|
+
|
|
413
|
+
expect(dialer.streams).to.include(dialerStream, 'dialer did not store outbound stream')
|
|
414
|
+
expect(listener.streams).to.include(listenerStream, 'listener did not store inbound stream')
|
|
415
|
+
})
|
|
416
|
+
|
|
417
|
+
it('should not remove a half-closed inbound stream', async () => {
|
|
418
|
+
const [
|
|
419
|
+
listenerStream,
|
|
420
|
+
dialerStream
|
|
421
|
+
] = await Promise.all([
|
|
422
|
+
pEvent<'stream', CustomEvent<Stream>>(listener, 'stream').then(evt => evt.detail),
|
|
423
|
+
dialer.createStream()
|
|
424
|
+
])
|
|
488
425
|
|
|
489
|
-
|
|
490
|
-
|
|
426
|
+
await listenerStream.close()
|
|
427
|
+
|
|
428
|
+
expect(dialer.streams).to.include(dialerStream, 'dialer did not store outbound stream')
|
|
429
|
+
expect(listener.streams).to.include(listenerStream, 'listener did not store inbound stream')
|
|
430
|
+
})
|
|
431
|
+
|
|
432
|
+
it('should remove a stream half closed from both ends', async () => {
|
|
433
|
+
const [
|
|
434
|
+
listenerStream,
|
|
435
|
+
dialerStream
|
|
436
|
+
] = await Promise.all([
|
|
437
|
+
pEvent<'stream', CustomEvent<Stream>>(listener, 'stream').then(evt => evt.detail),
|
|
438
|
+
dialer.createStream()
|
|
439
|
+
])
|
|
440
|
+
|
|
441
|
+
expect(dialer.streams).to.include(dialerStream, 'dialer did not store outbound stream')
|
|
442
|
+
expect(listener.streams).to.include(listenerStream, 'listener did not store inbound stream')
|
|
443
|
+
|
|
444
|
+
await listenerStream.close()
|
|
445
|
+
|
|
446
|
+
expect(dialer.streams).to.include(dialerStream, 'dialer removed outbound stream before fully closing')
|
|
447
|
+
expect(listener.streams).to.include(listenerStream, 'listener removed inbound stream before fully closing')
|
|
448
|
+
|
|
449
|
+
await Promise.all([
|
|
450
|
+
pEvent(listenerStream, 'close'),
|
|
451
|
+
dialerStream.close()
|
|
452
|
+
])
|
|
453
|
+
|
|
454
|
+
await delay(10)
|
|
491
455
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
.with.property('name', 'TimeoutError')
|
|
456
|
+
expect(dialer.streams).to.not.include(dialerStream, 'dialer did not remove outbound stream close')
|
|
457
|
+
expect(listener.streams).to.not.include(listenerStream, 'listener did not remove inbound stream after close')
|
|
495
458
|
})
|
|
496
|
-
*/
|
|
497
459
|
})
|
|
498
460
|
}
|