amqplib 2.1.0 → 2.2.1

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.
@@ -1,918 +0,0 @@
1
- const { describe, it, beforeEach, afterEach } = require('node:test');
2
- const assert = require('node:assert');
3
- const promisify = require('node:util').promisify;
4
- const Channel = require('../lib/channel').Channel;
5
- const Connection = require('../lib/connection').Connection;
6
- const util = require('./lib/util');
7
- const latch = util.latch;
8
- const completes = util.completes;
9
- const handshake = util.handshake;
10
- const defs = require('../lib/defs');
11
- const OPEN_OPTS = require('./lib/data').OPEN_OPTS;
12
-
13
- const LOG_ERRORS = process.env.LOG_ERRORS;
14
-
15
- function baseChannelTest(client, server) {
16
- return (_t, done) => {
17
- const decrementLatch = latch(2, done);
18
- const pair = util.socketPair();
19
- const c = new Connection(pair.client);
20
-
21
- if (LOG_ERRORS) c.on('error', console.warn);
22
-
23
- c.open(OPEN_OPTS, (err, _ok) => {
24
- if (err === null) client(c, decrementLatch);
25
- else decrementLatch(err);
26
- });
27
-
28
- pair.server.read(8); // discard the protocol header
29
- util.runServer(pair.server, (send, wait) => {
30
- handshake(send, wait).then(() => {
31
- server(send, wait, decrementLatch);
32
- }, decrementLatch);
33
- });
34
- };
35
- }
36
-
37
- function channelTest(client, server) {
38
- return baseChannelTest(
39
- (conn, done) => {
40
- const ch = new Channel(conn);
41
- if (LOG_ERRORS) ch.on('error', console.warn);
42
- client(ch, done, conn);
43
- },
44
- (send, wait, done) => {
45
- channel_handshake(send, wait)
46
- .then((ch) => server(send, wait, done, ch))
47
- .then(null, done); // so you can return a promise to let
48
- // errors bubble out
49
- },
50
- );
51
- }
52
-
53
- function channel_handshake(send, wait) {
54
- return wait(defs.ChannelOpen)().then((open) => {
55
- assert.notEqual(0, open.channel);
56
- send(defs.ChannelOpenOk, { channelId: Buffer.from('') }, open.channel);
57
- return open.channel;
58
- });
59
- }
60
-
61
- // fields for deliver and publish and get-ok
62
- const DELIVER_FIELDS = {
63
- consumerTag: 'fake',
64
- deliveryTag: 1,
65
- redelivered: false,
66
- exchange: 'foo',
67
- routingKey: 'bar',
68
- replyCode: defs.constants.NO_ROUTE,
69
- replyText: 'derp',
70
- };
71
-
72
- function open(ch) {
73
- ch.allocate();
74
- return promisify((cb) => {
75
- ch._rpc(defs.ChannelOpen, { outOfBand: '' }, defs.ChannelOpenOk, cb);
76
- })();
77
- }
78
-
79
- describe('Channel', () => {
80
-
81
- describe('channel open and close', () => {
82
- it('open', channelTest(
83
- (ch, cb) => open(ch).then((ok) => {
84
- assert.equal(ok.id, defs.ChannelOpenOk);
85
- cb();
86
- }),
87
- (_send, _wait, cb) => cb()
88
- ));
89
-
90
- it('bad server', baseChannelTest(
91
- (c, cb) => {
92
- const ch = new Channel(c);
93
- assert.rejects(() => open(ch), (err) => {
94
- assert.match(err.message, /Expected ChannelOpenOk; got <ChannelCloseOk channel:1>/);
95
- return true;
96
- }).then(() => cb());
97
- }, (send, wait, cb) =>
98
- wait(defs.ChannelOpen)()
99
- .then((open) => send(defs.ChannelCloseOk, {}, open.channel))
100
- .then(cb)
101
- )
102
- );
103
-
104
- it('open, close', channelTest(
105
- (ch, cb) => {
106
- open(ch)
107
- .then(() => new Promise((resolve) => {
108
- ch.closeBecause('Bye', defs.constants.REPLY_SUCCESS, resolve);
109
- }))
110
- .then(cb);
111
- }, (send, wait, cb, ch) =>
112
- wait(defs.ChannelClose)()
113
- .then((_close) => send(defs.ChannelCloseOk, {}, ch))
114
- .then(cb)
115
- )
116
- );
117
-
118
- it('server close', channelTest(
119
- (ch, cb) => {
120
- ch.once('error', (err) => {
121
- assert.match(err.message, /Channel closed by server: 504 \(CHANNEL-ERROR\)/);
122
- assert.strictEqual(504, err.code);
123
- assert.strictEqual(0, err.classId);
124
- assert.strictEqual(0, err.methodId);
125
- cb();
126
- });
127
- open(ch);
128
- }, (send, wait, cb, ch) => {
129
- send(defs.ChannelClose, {
130
- replyText: 'Forced close',
131
- replyCode: defs.constants.CHANNEL_ERROR,
132
- classId: 0,
133
- methodId: 0,
134
- }, ch);
135
- wait(defs.ChannelCloseOk)().then(cb);
136
- }));
137
-
138
- it('overlapping channel/server close', channelTest(
139
- (ch, cb, conn) => {
140
- const decrementLatch = latch(2, cb);
141
- conn.once('error', (err) => {
142
- assert.match(err.message, /Connection closed: 541 \(INTERNAL-ERROR\)/);
143
- decrementLatch();
144
- });
145
- ch.on('close', (err) => {
146
- assert.ifError(err);
147
- decrementLatch();
148
- });
149
- open(ch)
150
- .then(() => ch.closeBecause('Bye', defs.constants.REPLY_SUCCESS));
151
- }, (send, wait, cb, _ch) => {
152
- wait(defs.ChannelClose)()
153
- .then(() => send(defs.ConnectionClose, {
154
- replyText: 'Got there first',
155
- replyCode: defs.constants.INTERNAL_ERROR,
156
- classId: 0,
157
- methodId: 0,
158
- }, 0)
159
- )
160
- .then(wait(defs.ConnectionCloseOk))
161
- .then(cb);
162
- }));
163
-
164
- it('double close', channelTest((ch, cb) => {
165
- open(ch)
166
- .then(() => {
167
- ch.closeBecause('First close', defs.constants.REPLY_SUCCESS);
168
- // NB no synchronisation, we do this straight away
169
- assert.throws(() => {
170
- ch.closeBecause('Second close', defs.constants.REPLY_SUCCESS);
171
- }, (err) => {
172
- assert.match(err.message, /Channel closing/);
173
- return true;
174
- });
175
- })
176
- .then(cb);
177
- }, (send, wait, cb, ch) => {
178
- wait(defs.ChannelClose)()
179
- .then(() => send(defs.ChannelCloseOk, {}, ch))
180
- .then(cb);
181
- }));
182
- });
183
-
184
- describe('channel machinery', () => {
185
- it('RPC', channelTest((ch, cb) => {
186
- const decrementLatch = latch(3, cb);
187
- open(ch)
188
- .then(() => {
189
- const fields = { prefetchCount: 10, prefetchSize: 0, global: false };
190
- ch._rpc(defs.BasicQos, fields, defs.BasicQosOk, decrementLatch);
191
- ch._rpc(defs.BasicQos, fields, defs.BasicQosOk, decrementLatch);
192
- ch._rpc(defs.BasicQos, fields, defs.BasicQosOk, decrementLatch);
193
- })
194
- }, (send, wait, cb, ch) => {
195
- function sendOk() {
196
- send(defs.BasicQosOk, {}, ch);
197
- }
198
-
199
- return wait(defs.BasicQos)()
200
- .then(sendOk)
201
- .then(wait(defs.BasicQos))
202
- .then(sendOk)
203
- .then(wait(defs.BasicQos))
204
- .then(sendOk)
205
- .then(cb);
206
- }));
207
-
208
- it('Bad RPC', channelTest(
209
- (ch, cb) => {
210
- // We want to see the RPC rejected and the channel closed (with an error)
211
- const decrementLatch = latch(2, cb);
212
- ch.once('error', (err) => {
213
- assert.match(err.message, /Expected BasicRecoverOk; got <BasicGetEmpty channel:1>/);
214
- assert.strictEqual(505, err.code);
215
- assert.strictEqual(60, err.classId);
216
- assert.strictEqual(72, err.methodId);
217
- decrementLatch();
218
- });
219
-
220
- open(ch).then(() => {
221
- ch._rpc(defs.BasicRecover, { requeue: true }, defs.BasicRecoverOk, (err) => {
222
- assert.match(err.message, /Expected BasicRecoverOk; got <BasicGetEmpty channel:1>/);
223
- decrementLatch();
224
- });
225
- }, decrementLatch);
226
- },
227
- (send, wait, cb, ch) =>
228
- wait()()
229
- .then(() => send(defs.BasicGetEmpty, { clusterId: '' }, ch))
230
- // oh wait! that was wrong! expect a channel close
231
- .then(wait(defs.ChannelClose))
232
- .then(() => send(defs.ChannelCloseOk, {}, ch))
233
- .then(cb),
234
- ));
235
-
236
- it('RPC on closed channel', channelTest(
237
- (ch, cb) => {
238
- open(ch);
239
-
240
- const close = new Promise((resolve) => {
241
- ch.once('error', (err) => {
242
- assert.match(err.message, /Channel closed by server: 504 \(CHANNEL-ERROR\)/);
243
- assert.strictEqual(504, err.code);
244
- assert.strictEqual(0, err.classId);
245
- assert.strictEqual(0, err.methodId);
246
- resolve();
247
- });
248
- });
249
-
250
- function failureCb(resolve, reject) {
251
- return (err) => {
252
- if (err !== null) resolve();
253
- else reject();
254
- };
255
- }
256
-
257
- const fail1 = new Promise((resolve, reject) =>
258
- ch._rpc(defs.BasicRecover, { requeue: true }, defs.BasicRecoverOk, failureCb(resolve, reject)),
259
- );
260
-
261
- const fail2 = new Promise((resolve, reject) =>
262
- ch._rpc(defs.BasicRecover, { requeue: true }, defs.BasicRecoverOk, failureCb(resolve, reject)),
263
- );
264
-
265
- Promise.all([close, fail1, fail2]).then(cb);
266
- },
267
- (send, wait, cb, ch) => {
268
- wait(defs.BasicRecover)()
269
- .then(() => {
270
- send(defs.ChannelClose, {
271
- replyText: 'Nuh-uh!',
272
- replyCode: defs.constants.CHANNEL_ERROR,
273
- methodId: 0,
274
- classId: 0,
275
- }, ch);
276
- return wait(defs.ChannelCloseOk);
277
- })
278
- .then(cb);
279
- },
280
- ));
281
-
282
- it('publish all < single chunk threshold', channelTest(
283
- (ch, cb) => {
284
- open(ch)
285
- .then(() => {
286
- ch.sendMessage({
287
- exchange: 'foo',
288
- routingKey: 'bar',
289
- mandatory: false,
290
- immediate: false,
291
- ticket: 0,
292
- }, {}, Buffer.from('foobar'));
293
- })
294
- .then(cb);
295
- },
296
- (_send, wait, cb, _ch) => {
297
- wait(defs.BasicPublish)()
298
- .then(wait(defs.BasicProperties))
299
- .then(wait()) // content frame
300
- .then((f) => {
301
- assert.equal('foobar', f.content.toString());
302
- })
303
- .then(cb);
304
- },
305
- ));
306
-
307
- it('publish content > single chunk threshold', channelTest(
308
- (ch, cb) => {
309
- open(ch);
310
- completes(() => {
311
- ch.sendMessage(
312
- {
313
- exchange: 'foo',
314
- routingKey: 'bar',
315
- mandatory: false,
316
- immediate: false,
317
- ticket: 0,
318
- },
319
- {},
320
- Buffer.alloc(3000),
321
- );
322
- }, cb);
323
- }, (_send, wait, cb, _ch) => {
324
- wait(defs.BasicPublish)()
325
- .then(wait(defs.BasicProperties))
326
- .then(wait()) // content frame
327
- .then((f) => {
328
- assert.equal(3000, f.content.length);
329
- })
330
- .then(cb);
331
- }
332
- ));
333
-
334
- it('publish method & headers > threshold', channelTest(
335
- (ch, cb) => {
336
- open(ch);
337
- completes(() => {
338
- ch.sendMessage({
339
- exchange: 'foo',
340
- routingKey: 'bar',
341
- mandatory: false,
342
- immediate: false,
343
- ticket: 0,
344
- }, {
345
- headers: { foo: Buffer.alloc(3000) },
346
- }, Buffer.from('foobar'));
347
- }, cb);
348
- }, (_send, wait, cb, _ch) => {
349
- wait(defs.BasicPublish)()
350
- .then(wait(defs.BasicProperties))
351
- .then(wait()) // content frame
352
- .then((f) => {
353
- assert.equal('foobar', f.content.toString());
354
- })
355
- .then(cb);
356
- }
357
- ));
358
-
359
- it('publish zero-length message', channelTest((ch, cb) => {
360
- open(ch);
361
- completes(() => {
362
- ch.sendMessage({
363
- exchange: 'foo',
364
- routingKey: 'bar',
365
- mandatory: false,
366
- immediate: false,
367
- ticket: 0,
368
- }, {}, Buffer.alloc(0));
369
- ch.sendMessage({
370
- exchange: 'foo',
371
- routingKey: 'bar',
372
- mandatory: false,
373
- immediate: false,
374
- ticket: 0,
375
- }, {}, Buffer.alloc(0));
376
- }, cb);
377
- }, (_send, wait, cb, _ch) => {
378
- wait(defs.BasicPublish)()
379
- .then(wait(defs.BasicProperties))
380
- // no content frame for a zero-length message
381
- .then(wait(defs.BasicPublish))
382
- .then(cb);
383
- }));
384
-
385
- it('delivery', channelTest((ch, cb) => {
386
- open(ch);
387
- ch.on('delivery', (m) => {
388
- completes(() => {
389
- assert.equal('barfoo', m.content.toString());
390
- }, cb);
391
- });
392
- }, (send, _wait, cb, ch) => {
393
- completes(() => {
394
- send(defs.BasicDeliver, DELIVER_FIELDS, ch, Buffer.from('barfoo'));
395
- }, cb);
396
- }));
397
-
398
- it('zero byte msg', channelTest(
399
- (ch, cb) => {
400
- open(ch);
401
- ch.on('delivery', (m) => {
402
- completes(() => {
403
- assert.deepEqual(Buffer.alloc(0), m.content);
404
- }, cb);
405
- });
406
- },
407
- (send, _wait, cb, ch) => {
408
- completes(() => {
409
- send(defs.BasicDeliver, DELIVER_FIELDS, ch, Buffer.from(''));
410
- }, cb);
411
- }
412
- ));
413
-
414
- it('bad delivery', channelTest((ch, cb) => {
415
- const decrementLatch = latch(2, cb);
416
- ch.on('error', (err) => {
417
- assert.match(err.message, /Expected headers frame after delivery/);
418
- assert.strictEqual(505, err.code);
419
- assert.strictEqual(60, err.classId);
420
- assert.strictEqual(60, err.methodId);
421
- decrementLatch();
422
- });
423
- ch.on('close', decrementLatch);
424
- open(ch);
425
- }, (send, wait, cb, ch) => {
426
- send(defs.BasicDeliver, DELIVER_FIELDS, ch);
427
- // now send another deliver without having sent the content
428
- send(defs.BasicDeliver, DELIVER_FIELDS, ch);
429
- return wait(defs.ChannelClose)()
430
- .then(() => send(defs.ChannelCloseOk, {}, ch))
431
- .then(cb);
432
- }));
433
-
434
- it('bad content send', channelTest((ch, cb) => {
435
- completes(() => {
436
- open(ch);
437
- assert.throws(() => {
438
- ch.sendMessage({ routingKey: 'foo', exchange: 'amq.direct' }, {}, null);
439
- }, (err) => {
440
- assert.match(err.message, /content is not a buffer/);
441
- return true;
442
- });
443
- }, cb);
444
- }, (_send, _wait, cb, _ch) => cb()));
445
-
446
- it('bad properties send', channelTest((ch, cb) => {
447
- completes(() => {
448
- open(ch);
449
- assert.throws(() => {
450
- ch.sendMessage({ routingKey: 'foo', exchange: 'amq.direct' }, { contentEncoding: 7 }, Buffer.from('foobar'));
451
- }, (err) => {
452
- assert.match(err.message, /Field 'contentEncoding' is the wrong type/);
453
- return true;
454
- });
455
- }, cb);
456
- }, (_send, _wait, cb, _ch) => cb()));
457
-
458
- it('bad consumer', channelTest((ch, cb) => {
459
- const decrementLatch = latch(2, cb);
460
- ch.on('delivery', () => {
461
- throw new Error('I am a bad consumer');
462
- });
463
- ch.on('error', (err) => {
464
- assert.match(err.message, /I am a bad consumer/);
465
- assert.strictEqual(541, err.code);
466
- assert.strictEqual(undefined, err.classId);
467
- assert.strictEqual(undefined, err.methodId);
468
- decrementLatch();
469
- });
470
- ch.on('close', decrementLatch);
471
- open(ch);
472
- }, (send, wait, cb, ch) => {
473
- send(defs.BasicDeliver, DELIVER_FIELDS, ch, Buffer.from('barfoo'));
474
- return wait(defs.ChannelClose)()
475
- .then(() => send(defs.ChannelCloseOk, {}, ch))
476
- .then(cb);
477
- }));
478
-
479
- it('bad send in consumer', channelTest((ch, cb) => {
480
- const decrementLatch = latch(2, cb);
481
- ch.on('delivery', () => {
482
- ch.sendMessage({ routingKey: 'foo', exchange: 'amq.direct' }, {}, null); // can't send null
483
- });
484
- ch.on('error', (err) => {
485
- assert.match(err.message, /content is not a buffer/);
486
- assert.strictEqual(541, err.code);
487
- assert.strictEqual(undefined, err.classId);
488
- assert.strictEqual(undefined, err.methodId);
489
- decrementLatch();
490
- });
491
- ch.on('close', decrementLatch);
492
- open(ch);
493
- }, (send, wait, cb, ch) => {
494
- const decrementLatch = latch(2, cb);
495
- completes(() => {
496
- send(defs.BasicDeliver, DELIVER_FIELDS, ch, Buffer.from('barfoo'));
497
- }, decrementLatch);
498
- return wait(defs.ChannelClose)()
499
- .then(() => send(defs.ChannelCloseOk, {}, ch))
500
- .then(decrementLatch);
501
- }));
502
-
503
- it('return', channelTest((ch, cb) => {
504
- ch.on('return', (m) => {
505
- completes(() => {
506
- assert.equal('barfoo', m.content.toString());
507
- }, cb);
508
- });
509
- open(ch);
510
- }, (send, _wait, cb, ch) => {
511
- completes(() => {
512
- send(defs.BasicReturn, DELIVER_FIELDS, ch, Buffer.from('barfoo'));
513
- }, cb);
514
- }));
515
-
516
- it('cancel', channelTest((ch, cb) => {
517
- ch.on('cancel', (f) => {
518
- completes(() => {
519
- assert.equal('product of society', f.consumerTag);
520
- }, cb);
521
- });
522
- open(ch);
523
- }, (send, _wait, cb, ch) => {
524
- completes(() => {
525
- send(defs.BasicCancel, {
526
- consumerTag: 'product of society',
527
- nowait: false,
528
- }, ch);
529
- }, cb);
530
- }));
531
-
532
- function confirmTest(variety, method) {
533
- return it(`confirm ${variety}`, channelTest((ch, done) => {
534
- ch.on(variety, (f) => {
535
- completes(() => {
536
- assert.equal(1, f.deliveryTag);
537
- }, done);
538
- });
539
- open(ch);
540
- }, (send, _wait, done, ch) => {
541
- completes(() => {
542
- send(method, {
543
- deliveryTag: 1,
544
- multiple: false,
545
- }, ch);
546
- }, done);
547
- }));
548
- }
549
-
550
- confirmTest('ack', defs.BasicAck);
551
- confirmTest('nack', defs.BasicNack);
552
-
553
- it('out-of-order acks', channelTest((ch, cb) => {
554
- const decrementLatch = latch(3, () => {
555
- completes(() => {
556
- assert.equal(0, ch.unconfirmed.length);
557
- assert.equal(4, ch.lwm);
558
- }, cb);
559
- });
560
- ch.pushConfirmCallback(decrementLatch);
561
- ch.pushConfirmCallback(decrementLatch);
562
- ch.pushConfirmCallback(decrementLatch);
563
- open(ch);
564
- }, (send, _wait, cb, ch) => {
565
- completes(() => {
566
- send(defs.BasicAck, { deliveryTag: 2, multiple: false }, ch);
567
- send(defs.BasicAck, { deliveryTag: 3, multiple: false }, ch);
568
- send(defs.BasicAck, { deliveryTag: 1, multiple: false }, ch);
569
- }, cb);
570
- }));
571
-
572
- it('not all out-of-order acks', channelTest((ch, cb) => {
573
- const decrementLatch = latch(2, () => {
574
- completes(() => {
575
- assert.equal(1, ch.unconfirmed.length);
576
- assert.equal(3, ch.lwm);
577
- }, cb);
578
- });
579
- ch.pushConfirmCallback(decrementLatch); // tag = 1
580
- ch.pushConfirmCallback(decrementLatch); // tag = 2
581
- ch.pushConfirmCallback(() => {
582
- assert.fail('Confirm callback should not be called');
583
- });
584
- open(ch);
585
- }, (send, _wait, cb, ch) => {
586
- completes(() => {
587
- send(defs.BasicAck, { deliveryTag: 2, multiple: false }, ch);
588
- send(defs.BasicAck, { deliveryTag: 1, multiple: false }, ch);
589
- }, cb);
590
- }));
591
-
592
- // Regression test for https://github.com/amqp-node/amqplib/issues/191
593
- // pushConfirmCallback stores `false` for publishes with no callback.
594
- // The close drain used `while (cb)` which stops at the first `false`,
595
- // silently dropping all callbacks that follow it.
596
- it('invokes all pending callbacks on close even when some publishes had no callback', channelTest((ch, cb) => {
597
- let called = 0;
598
- const countErr = (err) => { if (err) called++; };
599
- ch.pushConfirmCallback(countErr); // tag = 1 — has callback
600
- ch.pushConfirmCallback(null); // tag = 2 — no callback, stored as `false`
601
- ch.pushConfirmCallback(countErr); // tag = 3 — has callback, dropped by while(cb) bug
602
- open(ch).then(() => {
603
- ch.toClosed('test close');
604
- completes(() => {
605
- assert.equal(2, called);
606
- }, cb);
607
- }, cb);
608
- }, (_send, _wait, cb) => {
609
- cb();
610
- }));
611
- });
612
-
613
- describe('Event handler errors - without handler-error listener', () => {
614
- let prevUncaughtExceptionListeners;
615
-
616
- beforeEach(() => {
617
- prevUncaughtExceptionListeners = process.rawListeners('uncaughtException').slice();
618
- process.removeAllListeners('uncaughtException');
619
- });
620
-
621
- afterEach(() => {
622
- prevUncaughtExceptionListeners.forEach((h) => process.on('uncaughtException', h));
623
- });
624
-
625
- it('throw in close handler kills the connection without handler-error listener', channelTest((ch, cb, conn) => {
626
- const expectedErr = new Error('user close handler explodes');
627
- let connErrorSeen = false;
628
- // The throw propagates to acceptLoop → frameError → onSocketError → connection.emit('error')
629
- conn.on('error', (err) => {
630
- assert.strictEqual(err, expectedErr);
631
- connErrorSeen = true;
632
- });
633
- // The ChannelCloseOk buffered before the kill is flushed by the mux after the
634
- // stream is ended, producing ERR_STREAM_PUSH_AFTER_EOF. Absorb it and use it
635
- // as the signal to end the test, since it fires after the conn error.
636
- process.once('uncaughtException', (err) => {
637
- assert.strictEqual(err.code, 'ERR_STREAM_PUSH_AFTER_EOF');
638
- assert.ok(connErrorSeen);
639
- cb();
640
- });
641
- ch.once('error', (err) => { assert.match(err.message, /Channel closed by server/); });
642
- ch.on('close', () => { throw expectedErr; });
643
- open(ch);
644
- }, (send, _wait, cb, ch) => {
645
- completes(() => {
646
- send(defs.ChannelClose, {
647
- replyText: 'Forced close',
648
- replyCode: defs.constants.CHANNEL_ERROR,
649
- classId: 0,
650
- methodId: 0,
651
- }, ch);
652
- }, cb);
653
- }));
654
-
655
- it('throw in error handler becomes uncaught exception', channelTest((ch, cb) => {
656
- const expectedErr = new Error('user error handler explodes');
657
- process.once('uncaughtException', (err) => {
658
- assert.strictEqual(err, expectedErr);
659
- cb();
660
- });
661
- ch.on('error', () => { throw expectedErr; });
662
- open(ch);
663
- }, (send, wait, cb, ch) => {
664
- send(defs.ChannelClose, {
665
- replyText: 'Forced close',
666
- replyCode: defs.constants.CHANNEL_ERROR,
667
- classId: 0,
668
- methodId: 0,
669
- }, ch);
670
- wait(defs.ChannelCloseOk)().then(cb, cb);
671
- }));
672
-
673
- it('throw in drain handler becomes uncaught exception', channelTest((ch, cb) => {
674
- const expectedErr = new Error('user drain handler explodes');
675
- process.once('uncaughtException', (err) => {
676
- assert.strictEqual(err, expectedErr);
677
- cb();
678
- });
679
- ch.on('drain', () => { throw expectedErr; });
680
- // Call outside a Promise chain so the throw becomes an uncaughtException
681
- open(ch).then(() => setImmediate(() => ch.onBufferDrain()));
682
- }, (_send, _wait, cb) => { cb(); }));
683
-
684
- it('throw in ack handler becomes uncaught exception', channelTest((ch, cb) => {
685
- const expectedErr = new Error('user ack handler explodes');
686
- process.once('uncaughtException', (err) => {
687
- assert.strictEqual(err, expectedErr);
688
- cb();
689
- });
690
- ch.on('ack', () => { throw expectedErr; });
691
- open(ch);
692
- }, (send, _wait, cb, ch) => {
693
- completes(() => {
694
- send(defs.BasicAck, { deliveryTag: 1, multiple: false }, ch);
695
- }, cb);
696
- }));
697
-
698
- it('throw in nack handler becomes uncaught exception', channelTest((ch, cb) => {
699
- const expectedErr = new Error('user nack handler explodes');
700
- process.once('uncaughtException', (err) => {
701
- assert.strictEqual(err, expectedErr);
702
- cb();
703
- });
704
- ch.on('nack', () => { throw expectedErr; });
705
- open(ch);
706
- }, (send, _wait, cb, ch) => {
707
- completes(() => {
708
- send(defs.BasicNack, { deliveryTag: 1, multiple: false, requeue: false }, ch);
709
- }, cb);
710
- }));
711
-
712
- it('throw in cancel handler becomes uncaught exception', channelTest((ch, cb) => {
713
- const expectedErr = new Error('user cancel handler explodes');
714
- process.once('uncaughtException', (err) => {
715
- assert.strictEqual(err, expectedErr);
716
- cb();
717
- });
718
- ch.on('cancel', () => { throw expectedErr; });
719
- open(ch);
720
- }, (send, _wait, cb, ch) => {
721
- completes(() => {
722
- send(defs.BasicCancel, { consumerTag: 'tag', nowait: false }, ch);
723
- }, cb);
724
- }));
725
-
726
- it('throw in delivery handler closes channel with error', channelTest((ch, cb) => {
727
- // acceptMessageFrame catches the throw and routes it to closeWithError,
728
- // which fires channel 'error' then 'close' — it does NOT become an uncaughtException.
729
- const expectedErr = new Error('user delivery handler explodes');
730
- const decrementLatch = latch(2, cb);
731
- ch.on('error', (err) => {
732
- assert.strictEqual(err, expectedErr);
733
- decrementLatch();
734
- });
735
- ch.on('close', decrementLatch);
736
- ch.on('delivery', () => { throw expectedErr; });
737
- open(ch);
738
- }, (send, wait, cb, ch) => {
739
- send(defs.BasicDeliver, DELIVER_FIELDS, ch, Buffer.from('hello'));
740
- wait(defs.ChannelClose)()
741
- .then(() => send(defs.ChannelCloseOk, {}, ch))
742
- .then(cb, cb);
743
- }));
744
-
745
- it('throw in return handler closes channel with error', channelTest((ch, cb) => {
746
- // acceptMessageFrame catches the throw and routes it to closeWithError.
747
- const expectedErr = new Error('user return handler explodes');
748
- const decrementLatch = latch(2, cb);
749
- ch.on('error', (err) => {
750
- assert.strictEqual(err, expectedErr);
751
- decrementLatch();
752
- });
753
- ch.on('close', decrementLatch);
754
- ch.on('return', () => { throw expectedErr; });
755
- open(ch);
756
- }, (send, wait, cb, ch) => {
757
- send(defs.BasicReturn, DELIVER_FIELDS, ch, Buffer.from('hello'));
758
- wait(defs.ChannelClose)()
759
- .then(() => send(defs.ChannelCloseOk, {}, ch))
760
- .then(cb, cb);
761
- }));
762
- });
763
-
764
- describe('Event handler errors - with handler-error listener', () => {
765
- let prevUncaughtExceptionListeners;
766
-
767
- beforeEach(() => {
768
- prevUncaughtExceptionListeners = process.rawListeners('uncaughtException').slice();
769
- process.removeAllListeners('uncaughtException');
770
- });
771
-
772
- afterEach(() => {
773
- prevUncaughtExceptionListeners.forEach((h) => process.on('uncaughtException', h));
774
- });
775
-
776
- it('throw in close handler is delivered via handler-error event', channelTest((ch, cb) => {
777
- const expectedErr = new Error('user close handler explodes');
778
- ch.on('handler-error', (err, event) => {
779
- assert.strictEqual(err, expectedErr);
780
- assert.strictEqual(event, 'close');
781
- cb();
782
- });
783
- // A server-initiated ChannelClose always fires 'error' before 'close' (line 291 in channel.js).
784
- // Handle it so only the throw from the close handler reaches handler-error.
785
- ch.once('error', (err) => { assert.match(err.message, /Channel closed by server/); });
786
- ch.on('close', () => { throw expectedErr; });
787
- open(ch);
788
- }, (send, wait, cb, ch) => {
789
- send(defs.ChannelClose, {
790
- replyText: 'Forced close',
791
- replyCode: defs.constants.CHANNEL_ERROR,
792
- classId: 0,
793
- methodId: 0,
794
- }, ch);
795
- wait(defs.ChannelCloseOk)().then(cb, cb);
796
- }));
797
-
798
- it('throw in error handler is delivered via handler-error event', channelTest((ch, cb) => {
799
- const expectedErr = new Error('user error handler explodes');
800
- ch.on('handler-error', (err, event) => {
801
- assert.strictEqual(err, expectedErr);
802
- assert.strictEqual(event, 'error');
803
- cb();
804
- });
805
- ch.on('error', () => { throw expectedErr; });
806
- open(ch);
807
- }, (send, wait, cb, ch) => {
808
- send(defs.ChannelClose, {
809
- replyText: 'Forced close',
810
- replyCode: defs.constants.CHANNEL_ERROR,
811
- classId: 0,
812
- methodId: 0,
813
- }, ch);
814
- wait(defs.ChannelCloseOk)().then(cb, cb);
815
- }));
816
-
817
- it('throw in drain handler is delivered via handler-error event', channelTest((ch, cb) => {
818
- const expectedErr = new Error('user drain handler explodes');
819
- ch.on('handler-error', (err, event) => {
820
- assert.strictEqual(err, expectedErr);
821
- assert.strictEqual(event, 'drain');
822
- cb();
823
- });
824
- ch.on('drain', () => { throw expectedErr; });
825
- open(ch).then(() => setImmediate(() => ch.onBufferDrain()));
826
- }, (_send, _wait, cb) => { cb(); }));
827
-
828
- it('throw in ack handler is delivered via handler-error event', channelTest((ch, cb) => {
829
- const expectedErr = new Error('user ack handler explodes');
830
- ch.on('handler-error', (err, event) => {
831
- assert.strictEqual(err, expectedErr);
832
- assert.strictEqual(event, 'ack');
833
- cb();
834
- });
835
- ch.on('ack', () => { throw expectedErr; });
836
- open(ch);
837
- }, (send, _wait, cb, ch) => {
838
- completes(() => {
839
- send(defs.BasicAck, { deliveryTag: 1, multiple: false }, ch);
840
- }, cb);
841
- }));
842
-
843
- it('throw in nack handler is delivered via handler-error event', channelTest((ch, cb) => {
844
- const expectedErr = new Error('user nack handler explodes');
845
- ch.on('handler-error', (err, event) => {
846
- assert.strictEqual(err, expectedErr);
847
- assert.strictEqual(event, 'nack');
848
- cb();
849
- });
850
- ch.on('nack', () => { throw expectedErr; });
851
- open(ch);
852
- }, (send, _wait, cb, ch) => {
853
- completes(() => {
854
- send(defs.BasicNack, { deliveryTag: 1, multiple: false, requeue: false }, ch);
855
- }, cb);
856
- }));
857
-
858
- it('throw in cancel handler is delivered via handler-error event', channelTest((ch, cb) => {
859
- const expectedErr = new Error('user cancel handler explodes');
860
- ch.on('handler-error', (err, event) => {
861
- assert.strictEqual(err, expectedErr);
862
- assert.strictEqual(event, 'cancel');
863
- cb();
864
- });
865
- ch.on('cancel', () => { throw expectedErr; });
866
- open(ch);
867
- }, (send, _wait, cb, ch) => {
868
- completes(() => {
869
- send(defs.BasicCancel, { consumerTag: 'tag', nowait: false }, ch);
870
- }, cb);
871
- }));
872
-
873
- it('throw in delivery handler is delivered via handler-error event', channelTest((ch, cb) => {
874
- const expectedErr = new Error('user delivery handler explodes');
875
- ch.on('handler-error', (err, event) => {
876
- assert.strictEqual(err, expectedErr);
877
- assert.strictEqual(event, 'delivery');
878
- cb();
879
- });
880
- ch.on('delivery', () => { throw expectedErr; });
881
- open(ch);
882
- }, (send, _wait, cb, ch) => {
883
- completes(() => {
884
- send(defs.BasicDeliver, DELIVER_FIELDS, ch, Buffer.from('hello'));
885
- }, cb);
886
- }));
887
-
888
- it('throw in return handler is delivered via handler-error event', channelTest((ch, cb) => {
889
- const expectedErr = new Error('user return handler explodes');
890
- ch.on('handler-error', (err, event) => {
891
- assert.strictEqual(err, expectedErr);
892
- assert.strictEqual(event, 'return');
893
- cb();
894
- });
895
- ch.on('return', () => { throw expectedErr; });
896
- open(ch);
897
- }, (send, _wait, cb, ch) => {
898
- completes(() => {
899
- send(defs.BasicReturn, DELIVER_FIELDS, ch, Buffer.from('hello'));
900
- }, cb);
901
- }));
902
-
903
- it('throw in handler-error handler becomes uncaught exception', channelTest((ch, cb) => {
904
- const expectedErr = new Error('handler-error handler explodes');
905
- process.once('uncaughtException', (err) => {
906
- assert.strictEqual(err, expectedErr);
907
- cb();
908
- });
909
- ch.on('handler-error', () => { throw expectedErr; });
910
- ch.on('ack', () => { throw new Error('user ack handler explodes'); });
911
- open(ch);
912
- }, (send, _wait, cb, ch) => {
913
- completes(() => {
914
- send(defs.BasicAck, { deliveryTag: 1, multiple: false }, ch);
915
- }, cb);
916
- }));
917
- });
918
- });