@libp2p/interface-compliance-tests 6.4.16 → 6.5.0-8484de8a2

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