amqplib 2.2.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,772 +0,0 @@
1
- const { describe, it, beforeEach, afterEach } = require('node:test');
2
- const assert = require('node:assert');
3
- const defs = require('../lib/defs');
4
- const Connection = require('../lib/connection').Connection;
5
- const HEARTBEAT = require('../lib/frame').HEARTBEAT;
6
- const HB_BUF = require('../lib/frame').HEARTBEAT_BUF;
7
- const OPEN_OPTS = require('./lib/data').OPEN_OPTS;
8
- const heartbeat = require('../lib/heartbeat');
9
- const { latch, handshake, runServer, socketPair } = require('./lib/util');
10
-
11
- const LOG_ERRORS = process.env.LOG_ERRORS;
12
-
13
- function connectionTest(client, server) {
14
- return (_t, done) => {
15
- const decrementLatch = latch(2, done);
16
- const pair = socketPair();
17
- const c = new Connection(pair.client);
18
- if (LOG_ERRORS) c.on('error', console.warn);
19
- client(c, decrementLatch);
20
-
21
- // NB only not a race here because the writes are synchronous
22
- const protocolHeader = pair.server.read(8);
23
- assert.deepEqual(Buffer.from(`AMQP${String.fromCharCode(0, 0, 9, 1)}`), protocolHeader);
24
-
25
- runServer(pair.server, (send, wait) => {
26
- server(send, wait, decrementLatch, pair.server);
27
- });
28
- };
29
- }
30
-
31
- describe('Connection', () => {
32
-
33
- describe('Connection errors', () => {
34
- it('socket close during open', (_t, done) => {
35
- // RabbitMQ itself will take at least 3 seconds to close the socket
36
- // in the event of a handshake problem. Instead of using a live
37
- // connection, I'm just going to pretend.
38
- const pair = socketPair();
39
- const conn = new Connection(pair.client);
40
- pair.server.on('readable', () => pair.server.end());
41
- conn.open({}, (err) => {
42
- assert.ok(err);
43
- assert.match(err.message, /Socket closed abruptly during opening handshake/);
44
- done();
45
- });
46
- });
47
-
48
- it('bad frame during open', (_t, done) => {
49
- const ss = socketPair();
50
- const conn = new (require('../lib/connection').Connection)(ss.client);
51
- ss.server.on('readable', () => {
52
- ss.server.write(Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]));
53
- });
54
- conn.open({}, (err) => {
55
- assert.ok(err);
56
- assert.match(err.message, /Invalid frame/);
57
- done();
58
- });
59
- });
60
- });
61
-
62
- describe('Connection open', () => {
63
- it('happy', connectionTest((c, cb) => {
64
- c.open(OPEN_OPTS, (err) => {
65
- assert.ifError(err);
66
- cb();
67
- })
68
- }, (send, wait, cb) => {
69
- handshake(send, wait)
70
- .then(cb, cb);
71
- }));
72
-
73
- it('wrong first frame', connectionTest((c, cb) => {
74
- c.open(OPEN_OPTS, (err) => {
75
- assert.ok(err);
76
- assert.match(err.message, /Expected ConnectionStart; got <ConnectionTune channel:0/);
77
- cb()
78
- });
79
- }, (send, _wait, cb) => {
80
- // bad server! bad! whatever were you thinking?
81
- send(defs.ConnectionTune, { channelMax: 0, heartbeat: 0, frameMax: 0 })
82
- cb();
83
- }));
84
-
85
- it('unexpected socket close', connectionTest((c, cb) => {
86
- c.open(OPEN_OPTS, (err) => {
87
- assert.ok(err);
88
- assert.match(err.message, /Socket closed abruptly during opening handshake/);
89
- cb();
90
- });
91
- }, (send, wait, cb, socket) => {
92
- send(defs.ConnectionStart, {
93
- versionMajor: 0,
94
- versionMinor: 9,
95
- serverProperties: {},
96
- mechanisms: Buffer.from('PLAIN'),
97
- locales: Buffer.from('en_US'),
98
- });
99
- return wait(defs.ConnectionStartOk)()
100
- .then(() => socket.end())
101
- .then(cb, cb);
102
- }));
103
- });
104
-
105
- describe('Connection running', () => {
106
- it('wrong frame on channel 0', connectionTest((c, cb) => {
107
- c.once('error', (err) => {
108
- assert.match(err.message, /Unexpected frame on channel 0/);
109
- cb()
110
- });
111
- c.open(OPEN_OPTS);
112
- }, (send, wait, cb) => {
113
- handshake(send, wait)
114
- // there's actually nothing that would plausibly be sent to a
115
- // just opened connection, so this is violating more than one
116
- // rule. Nonetheless.
117
- .then(() => send(defs.ChannelOpenOk, { channelId: Buffer.from('') }, 0))
118
- .then(wait(defs.ConnectionClose))
119
- .then((_close) => send(defs.ConnectionCloseOk, {}, 0))
120
- .then(cb, cb);
121
- }));
122
-
123
- it('unopened channel', connectionTest((c, cb) => {
124
- c.once('error', (err) => {
125
- assert.match(err.message, /Frame on unknown channel/);
126
- cb();
127
- });
128
- c.open(OPEN_OPTS);
129
- }, (send, wait, cb) => {
130
- handshake(send, wait)
131
- // there's actually nothing that would plausibly be sent to a
132
- // just opened connection, so this is violating more than one
133
- // rule. Nonetheless.
134
- .then(() => send(defs.ChannelOpenOk, { channelId: Buffer.from('') }, 3))
135
- .then(wait(defs.ConnectionClose))
136
- .then((_close) => send(defs.ConnectionCloseOk, {}, 0))
137
- .then(cb, cb);
138
- }));
139
-
140
- it('unexpected socket close', connectionTest((c, cb) => {
141
- const decrementLatch = latch(2, cb);
142
- c.on('error', (err) => {
143
- assert.match(err.message, /Unexpected close/);
144
- decrementLatch();
145
- });
146
- c.on('close', (err) => {
147
- assert.match(err.message, /Unexpected close/);
148
- decrementLatch();
149
- });
150
- c.open(OPEN_OPTS, (err) => {
151
- assert.ifError(err);
152
- c.sendHeartbeat();
153
- });
154
- }, (send, wait, cb, socket) => {
155
- handshake(send, wait)
156
- .then(wait())
157
- .then(() => socket.end())
158
- .then(cb, cb);
159
- }));
160
-
161
- it('connection.blocked', connectionTest((c, cb) => {
162
- c.on('blocked', (reason) => {
163
- assert.strictEqual(reason, 'felt like it');
164
- cb();
165
- });
166
- c.open(OPEN_OPTS);
167
- }, (send, wait, cb, _socket) => {
168
- handshake(send, wait)
169
- .then(() => send(defs.ConnectionBlocked, { reason: 'felt like it' }, 0))
170
- .then(cb, cb);
171
- }));
172
-
173
- it('connection.unblocked', connectionTest((c, cb) => {
174
- c.on('unblocked', () => cb());
175
- c.open(OPEN_OPTS);
176
- }, (send, wait, cb, _socket) => {
177
- handshake(send, wait)
178
- .then(() => send(defs.ConnectionUnblocked, {}, 0))
179
- .then(cb, cb);
180
- }));
181
- });
182
-
183
- describe('Connection close', () => {
184
- it('happy', connectionTest((c, cb) => {
185
- const decrementLatch = latch(2, cb);
186
- c.on('close', () => decrementLatch());
187
- c.open(OPEN_OPTS, (err) => {
188
- assert.ifError(err);
189
- c.close((err) => {
190
- assert.ifError(err);
191
- decrementLatch();
192
- });
193
- });
194
- }, (send, wait, cb) => {
195
- handshake(send, wait)
196
- .then(wait(defs.ConnectionClose))
197
- .then((_close) => send(defs.ConnectionCloseOk, {}))
198
- .then(cb, cb);
199
- }));
200
-
201
- it('interleaved close frames', connectionTest((c, cb) => {
202
- const decrementLatch = latch(2, cb);
203
- c.on('close', () => decrementLatch());
204
- c.open(OPEN_OPTS, (err) => {
205
- assert.ifError(err);
206
- c.close((err) => {
207
- assert.ifError(err);
208
- decrementLatch();
209
- });
210
- });
211
- }, (send, wait, cb) => {
212
- handshake(send, wait)
213
- .then(wait(defs.ConnectionClose))
214
- .then(() => send(defs.ConnectionClose, {
215
- replyText: 'Ha!',
216
- replyCode: defs.constants.REPLY_SUCCESS,
217
- methodId: 0,
218
- classId: 0,
219
- }))
220
- .then(wait(defs.ConnectionCloseOk))
221
- .then(() => send(defs.ConnectionCloseOk, {}))
222
- .then(cb, cb);
223
- }));
224
-
225
- it('server error close', connectionTest((c, cb) => {
226
- const decrementLatch = latch(2, cb);
227
- c.once('close', (err) => {
228
- assert.match(err.message, /Connection closed: 541 \(INTERNAL-ERROR\) with message "Begone"/);
229
- decrementLatch();
230
- });
231
- c.once('error', (err) => {
232
- assert.match(err.message, /Connection closed: 541 \(INTERNAL-ERROR\) with message "Begone"/);
233
- decrementLatch();
234
- });
235
- c.open(OPEN_OPTS);
236
- }, (send, wait, cb) => {
237
- handshake(send, wait)
238
- .then(() => send(defs.ConnectionClose, {
239
- replyText: 'Begone',
240
- replyCode: defs.constants.INTERNAL_ERROR,
241
- methodId: 0,
242
- classId: 0,
243
- }))
244
- .then(wait(defs.ConnectionCloseOk))
245
- .then(cb, cb);
246
- }));
247
-
248
- it('operator-intiated close', connectionTest((c, cb) => {
249
- c.once('close', (err) => {
250
- assert.match(err.message, /Connection closed: 320 \(CONNECTION-FORCED\) with message "Begone"/);
251
- cb();
252
- });
253
- c.once('error', (err) => assert.fail(`Unexepcted error: ${err.message}`));
254
- c.open(OPEN_OPTS);
255
- }, (send, wait, cb) => {
256
- handshake(send, wait)
257
- .then(() => send(defs.ConnectionClose, {
258
- replyText: 'Begone',
259
- replyCode: defs.constants.CONNECTION_FORCED,
260
- methodId: 0,
261
- classId: 0,
262
- }))
263
- .then(wait(defs.ConnectionCloseOk))
264
- .then(cb, cb);
265
- }));
266
-
267
- it('double close', connectionTest((c, cb) => {
268
- c.open(OPEN_OPTS, (err) => {
269
- assert.ifError(err);
270
- c.close();
271
- // NB no synchronisation, we do this straight away
272
- assert.throws(() => c.close());
273
- cb();
274
- });
275
- }, (send, wait, cb) => {
276
- handshake(send, wait)
277
- .then(wait(defs.ConnectionClose))
278
- .then(() => send(defs.ConnectionCloseOk, {}))
279
- .then(cb, cb);
280
- }));
281
-
282
- it('close while blocked closes immediately', connectionTest((c, cb) => {
283
- const decrementLatch = latch(2, cb);
284
- c.on('close', () => decrementLatch());
285
- c.open(OPEN_OPTS, (err) => {
286
- assert.ifError(err);
287
- c.once('blocked', () => {
288
- c.close((err) => {
289
- assert.ifError(err);
290
- decrementLatch();
291
- });
292
- });
293
- });
294
- }, (send, wait, cb) => {
295
- handshake(send, wait)
296
- .then(() => send(defs.ConnectionBlocked, { reason: 'memory' }, 0))
297
- .then(wait(defs.ConnectionClose))
298
- // deliberately do NOT send ConnectionCloseOk — client must close anyway
299
- .then(cb, cb);
300
- }));
301
- });
302
-
303
- describe('Event handler errors - without handler-event listener', () => {
304
- let prevUncaughtExceptionListeners;
305
-
306
- beforeEach(() => {
307
- prevUncaughtExceptionListeners = process.rawListeners('uncaughtException').slice();
308
- process.removeAllListeners('uncaughtException');
309
- });
310
-
311
- afterEach(() => {
312
- prevUncaughtExceptionListeners.forEach((h) => process.on('uncaughtException', h));
313
- heartbeat.UNITS_TO_MS = 1000;
314
- });
315
-
316
- it('throw in close handler from server-initiated close is swallowed without handler-error listener', connectionTest((c, cb) => {
317
- c.on('close', () => { throw new Error('user handler explodes'); });
318
- c.open(OPEN_OPTS);
319
- cb();
320
- }, (send, wait, cb) => {
321
- handshake(send, wait)
322
- .then(() => send(defs.ConnectionClose, {
323
- replyText: 'Begone',
324
- replyCode: defs.constants.CONNECTION_FORCED,
325
- methodId: 0,
326
- classId: 0,
327
- }))
328
- .then(wait(defs.ConnectionCloseOk))
329
- .then(cb, cb);
330
- }));
331
-
332
- it('throw in close handler from client-initiated close is swallowed without handler-error listener', connectionTest((c, cb) => {
333
- c.open(OPEN_OPTS, (err) => {
334
- assert.ifError(err);
335
- c.on('close', () => { throw new Error('user handler explodes on client close'); });
336
- c.close();
337
- cb();
338
- });
339
- }, (send, wait, cb) => {
340
- handshake(send, wait)
341
- .then(wait(defs.ConnectionClose))
342
- .then(() => send(defs.ConnectionCloseOk, {}))
343
- .then(cb, cb);
344
- }));
345
-
346
- it('throw in error handler becomes uncaught exception', connectionTest((c, cb) => {
347
- const expectedErr = new Error('user error handler explodes');
348
- process.once('uncaughtException', (err) => {
349
- assert.strictEqual(err, expectedErr);
350
- cb();
351
- });
352
- c.on('error', () => { throw expectedErr; });
353
- c.open(OPEN_OPTS);
354
- }, (send, wait, cb) => {
355
- handshake(send, wait)
356
- .then(() => send(defs.ConnectionClose, {
357
- replyText: 'Begone',
358
- replyCode: defs.constants.INTERNAL_ERROR,
359
- methodId: 0,
360
- classId: 0,
361
- }))
362
- .then(wait(defs.ConnectionCloseOk))
363
- .then(cb, cb);
364
- }));
365
-
366
- it('throw in blocked handler becomes uncaught exception', connectionTest((c, cb) => {
367
- const expectedErr = new Error('user blocked handler explodes');
368
- process.once('uncaughtException', (err) => {
369
- assert.strictEqual(err, expectedErr);
370
- cb();
371
- });
372
- c.on('blocked', () => { throw expectedErr; });
373
- c.open(OPEN_OPTS);
374
- }, (send, wait, cb) => {
375
- handshake(send, wait)
376
- .then(() => send(defs.ConnectionBlocked, { reason: 'memory' }, 0))
377
- .then(cb, cb);
378
- }));
379
-
380
- it('throw in unblocked handler becomes uncaught exception', connectionTest((c, cb) => {
381
- const expectedErr = new Error('user unblocked handler explodes');
382
- process.once('uncaughtException', (err) => {
383
- assert.strictEqual(err, expectedErr);
384
- cb();
385
- });
386
- c.on('unblocked', () => { throw expectedErr; });
387
- c.open(OPEN_OPTS);
388
- }, (send, wait, cb) => {
389
- handshake(send, wait)
390
- .then(() => send(defs.ConnectionUnblocked, {}, 0))
391
- .then(cb, cb);
392
- }));
393
-
394
- it('throw in update-secret-ok handler becomes uncaught exception', connectionTest((c, cb) => {
395
- const expectedErr = new Error('user update-secret-ok handler explodes');
396
- process.once('uncaughtException', (err) => {
397
- assert.strictEqual(err, expectedErr);
398
- cb();
399
- });
400
- c.open(OPEN_OPTS, (err) => {
401
- assert.ifError(err);
402
- c.on('update-secret-ok', () => { throw expectedErr; });
403
- c._updateSecret(Buffer.from('new secret'), 'reason', () => {});
404
- });
405
- }, (send, wait, cb) => {
406
- handshake(send, wait)
407
- .then(wait(defs.ConnectionUpdateSecret))
408
- .then(() => send(defs.ConnectionUpdateSecretOk, {}, 0))
409
- .then(cb, cb);
410
- }));
411
-
412
- it('throw in error handler from closeWithError becomes uncaught exception', connectionTest((c, cb) => {
413
- const expectedErr = new Error('user error handler explodes on closeWithError');
414
- process.once('uncaughtException', (err) => {
415
- assert.strictEqual(err, expectedErr);
416
- cb();
417
- });
418
- c.once('error', (err) => {
419
- assert.match(err.message, /Unexpected frame on channel 0/);
420
- throw expectedErr;
421
- });
422
- c.open(OPEN_OPTS);
423
- }, (send, wait, cb) => {
424
- handshake(send, wait)
425
- .then(() => send(defs.ChannelOpenOk, { channelId: Buffer.from('') }, 0))
426
- .then(cb, cb);
427
- }));
428
-
429
- it('throw in error handler from onSocketError', connectionTest((c, cb) => {
430
- const expectedErr = new Error('user error handler explodes on socket error');
431
- process.once('uncaughtException', (err) => {
432
- assert.strictEqual(err, expectedErr);
433
- cb();
434
- });
435
- c.once('error', (err) => {
436
- assert.match(err.message, /Unexpected close/);
437
- throw expectedErr;
438
- });
439
- c.open(OPEN_OPTS, (err) => {
440
- assert.ifError(err);
441
- c.sendHeartbeat();
442
- });
443
- }, (send, wait, cb, socket) => {
444
- handshake(send, wait)
445
- .then(wait())
446
- .then(() => socket.end())
447
- .then(cb, cb);
448
- }));
449
-
450
- it('throw in error handler from heartbeat timeout', connectionTest((c, cb) => {
451
- heartbeat.UNITS_TO_MS = 20;
452
- const expectedErr = new Error('user error handler explodes on heartbeat timeout');
453
- const opts = Object.create(OPEN_OPTS);
454
- opts.heartbeat = 1;
455
- process.once('uncaughtException', (err) => {
456
- assert.strictEqual(err, expectedErr);
457
- c.heartbeater.clear();
458
- cb();
459
- });
460
- c.on('error', (err) => {
461
- assert.match(err.message, /Heartbeat timeout/);
462
- throw expectedErr;
463
- });
464
- c.open(opts);
465
- }, (send, wait, cb) => {
466
- handshake(send, wait)
467
- .then(cb, cb);
468
- // conspicuously not sending anything ...
469
- }));
470
- });
471
-
472
- describe('Event handler errors - with handler-error listener', () => {
473
- let prevUncaughtExceptionListeners;
474
-
475
- beforeEach(() => {
476
- prevUncaughtExceptionListeners = process.rawListeners('uncaughtException').slice();
477
- process.removeAllListeners('uncaughtException');
478
- });
479
-
480
- afterEach(() => {
481
- prevUncaughtExceptionListeners.forEach((h) => process.on('uncaughtException', h));
482
- heartbeat.UNITS_TO_MS = 1000;
483
- });
484
-
485
- it('throw in close handler is delivered via handler-error event', connectionTest((c, cb) => {
486
- const expectedErr = new Error('user close handler explodes');
487
- c.on('handler-error', (err, event) => {
488
- assert.strictEqual(err, expectedErr);
489
- assert.strictEqual(event, 'close');
490
- cb();
491
- });
492
- c.on('close', () => { throw expectedErr; });
493
- c.open(OPEN_OPTS);
494
- }, (send, wait, cb) => {
495
- handshake(send, wait)
496
- .then(() => send(defs.ConnectionClose, {
497
- replyText: 'Begone',
498
- replyCode: defs.constants.CONNECTION_FORCED,
499
- methodId: 0,
500
- classId: 0,
501
- }))
502
- .then(wait(defs.ConnectionCloseOk))
503
- .then(cb, cb);
504
- }));
505
-
506
- it('throw in error handler is delivered via handler-error event', connectionTest((c, cb) => {
507
- const expectedErr = new Error('user error handler explodes');
508
- c.on('handler-error', (err, event) => {
509
- assert.strictEqual(err, expectedErr);
510
- assert.strictEqual(event, 'error');
511
- cb();
512
- });
513
- c.on('error', () => { throw expectedErr; });
514
- c.open(OPEN_OPTS);
515
- }, (send, wait, cb) => {
516
- handshake(send, wait)
517
- .then(() => send(defs.ConnectionClose, {
518
- replyText: 'Begone',
519
- replyCode: defs.constants.INTERNAL_ERROR,
520
- methodId: 0,
521
- classId: 0,
522
- }))
523
- .then(wait(defs.ConnectionCloseOk))
524
- .then(cb, cb);
525
- }));
526
-
527
- it('throw in blocked handler is delivered via handler-error event', connectionTest((c, cb) => {
528
- const expectedErr = new Error('user blocked handler explodes');
529
- c.on('handler-error', (err, event) => {
530
- assert.strictEqual(err, expectedErr);
531
- assert.strictEqual(event, 'blocked');
532
- cb();
533
- });
534
- c.on('blocked', () => { throw expectedErr; });
535
- c.open(OPEN_OPTS);
536
- }, (send, wait, cb) => {
537
- handshake(send, wait)
538
- .then(() => send(defs.ConnectionBlocked, { reason: 'memory' }, 0))
539
- .then(cb, cb);
540
- }));
541
-
542
- it('throw in unblocked handler is delivered via handler-error event', connectionTest((c, cb) => {
543
- const expectedErr = new Error('user unblocked handler explodes');
544
- c.on('handler-error', (err, event) => {
545
- assert.strictEqual(err, expectedErr);
546
- assert.strictEqual(event, 'unblocked');
547
- cb();
548
- });
549
- c.on('unblocked', () => { throw expectedErr; });
550
- c.open(OPEN_OPTS);
551
- }, (send, wait, cb) => {
552
- handshake(send, wait)
553
- .then(() => send(defs.ConnectionUnblocked, {}, 0))
554
- .then(cb, cb);
555
- }));
556
-
557
- it('throw in update-secret-ok handler is delivered via handler-error event', connectionTest((c, cb) => {
558
- const expectedErr = new Error('user update-secret-ok handler explodes');
559
- c.on('handler-error', (err, event) => {
560
- assert.strictEqual(err, expectedErr);
561
- assert.strictEqual(event, 'update-secret-ok');
562
- cb();
563
- });
564
- c.open(OPEN_OPTS, (err) => {
565
- assert.ifError(err);
566
- c.on('update-secret-ok', () => { throw expectedErr; });
567
- c._updateSecret(Buffer.from('new secret'), 'reason', () => {});
568
- });
569
- }, (send, wait, cb) => {
570
- handshake(send, wait)
571
- .then(wait(defs.ConnectionUpdateSecret))
572
- .then(() => send(defs.ConnectionUpdateSecretOk, {}, 0))
573
- .then(cb, cb);
574
- }));
575
-
576
- it('throw in error handler from heartbeat timeout is delivered via handler-error event', connectionTest((c, cb) => {
577
- heartbeat.UNITS_TO_MS = 20;
578
- const expectedErr = new Error('user error handler explodes on heartbeat timeout');
579
- const opts = Object.create(OPEN_OPTS);
580
- opts.heartbeat = 1;
581
- c.on('handler-error', (err, event) => {
582
- assert.strictEqual(err, expectedErr);
583
- assert.strictEqual(event, 'error');
584
- c.heartbeater.clear();
585
- cb();
586
- });
587
- c.on('error', (err) => {
588
- assert.match(err.message, /Heartbeat timeout/);
589
- throw expectedErr;
590
- });
591
- c.open(opts);
592
- }, (send, wait, cb) => {
593
- handshake(send, wait)
594
- .then(cb, cb);
595
- // conspicuously not sending anything ...
596
- }));
597
-
598
- it('throw in error handler from closeWithError is delivered via handler-error event', connectionTest((c, cb) => {
599
- const expectedErr = new Error('user error handler explodes on closeWithError');
600
- c.on('handler-error', (err, event) => {
601
- assert.strictEqual(err, expectedErr);
602
- assert.strictEqual(event, 'error');
603
- cb();
604
- });
605
- c.once('error', (err) => {
606
- assert.match(err.message, /Unexpected frame on channel 0/);
607
- throw expectedErr;
608
- });
609
- c.open(OPEN_OPTS);
610
- }, (send, wait, cb) => {
611
- handshake(send, wait)
612
- .then(() => send(defs.ChannelOpenOk, { channelId: Buffer.from('') }, 0))
613
- .then(cb, cb);
614
- }));
615
-
616
- it('throw in error handler from onSocketError is delivered via handler-error event', connectionTest((c, cb) => {
617
- const expectedErr = new Error('user error handler explodes on socket error');
618
- c.on('handler-error', (err, event) => {
619
- assert.strictEqual(err, expectedErr);
620
- assert.strictEqual(event, 'error');
621
- cb();
622
- });
623
- c.once('error', (err) => {
624
- assert.match(err.message, /Unexpected close/);
625
- throw expectedErr;
626
- });
627
- c.open(OPEN_OPTS, (err) => {
628
- assert.ifError(err);
629
- c.sendHeartbeat();
630
- });
631
- }, (send, wait, cb, socket) => {
632
- handshake(send, wait)
633
- .then(wait())
634
- .then(() => socket.end())
635
- .then(cb, cb);
636
- }));
637
-
638
- it('throw in handler-error handler becomes uncaught exception', connectionTest((c, cb) => {
639
- const expectedErr = new Error('handler-error handler explodes');
640
- process.once('uncaughtException', (err) => {
641
- assert.strictEqual(err, expectedErr);
642
- cb();
643
- });
644
- c.on('handler-error', () => { throw expectedErr; });
645
- c.on('blocked', () => { throw new Error('user blocked handler explodes'); });
646
- c.open(OPEN_OPTS);
647
- }, (send, wait, cb) => {
648
- handshake(send, wait)
649
- .then(() => send(defs.ConnectionBlocked, { reason: 'memory' }, 0))
650
- .then(cb, cb);
651
- }));
652
- });
653
-
654
- describe('heartbeats', () => {
655
-
656
- beforeEach(() => {
657
- heartbeat.UNITS_TO_MS = 20;
658
- });
659
-
660
- afterEach(() => {
661
- heartbeat.UNITS_TO_MS = 1000;
662
- });
663
-
664
- it('send heartbeat after open', connectionTest((c, cb) => {
665
- const opts = Object.create(OPEN_OPTS);
666
- opts.heartbeat = 1;
667
- // Don't leave the error waiting to happen for the next test
668
- c.on('error', (err) => {
669
- assert.match(err.message, /Heartbeat timeout/)
670
- });
671
- c.open(opts);
672
- cb()
673
- }, (send, wait, cb, socket) => {
674
- let timer;
675
- handshake(send, wait)
676
- .then(() => {
677
- timer = setInterval(() => socket.write(HB_BUF), heartbeat.UNITS_TO_MS);
678
- })
679
- .then(wait())
680
- .then((hb) => {
681
- assert.strictEqual(hb, HEARTBEAT);
682
- cb();
683
- }).finally(() => clearInterval(timer));
684
- }));
685
-
686
- it('detect lack of heartbeats', connectionTest((c, cb) => {
687
- const opts = Object.create(OPEN_OPTS);
688
- opts.heartbeat = 1;
689
- c.once('error', (err) => {
690
- assert.match(err.message, /Heartbeat timeout/)
691
- cb();
692
- });
693
- c.open(opts);
694
- }, (send, wait, cb, _socket) => {
695
- handshake(send, wait)
696
- .then(cb, cb);
697
- // conspicuously not sending anything ...
698
- }));
699
-
700
- it('without a heartbeat option, server suggested value is used', connectionTest((c, cb) => {
701
- // OPEN_OPTS.heartbeat is null — no preference set by client
702
- c.once('error', (err) => {
703
- assert.match(err.message, /Heartbeat timeout/);
704
- cb();
705
- });
706
- c.open(OPEN_OPTS, (err) => {
707
- assert.ifError(err);
708
- assert.strictEqual(c.heartbeat, 1);
709
- });
710
- }, (send, wait, cb) => {
711
- send(defs.ConnectionStart, {
712
- versionMajor: 0, versionMinor: 9,
713
- serverProperties: {},
714
- mechanisms: Buffer.from('PLAIN'),
715
- locales: Buffer.from('en_US'),
716
- });
717
- wait(defs.ConnectionStartOk)()
718
- .then(() => send(defs.ConnectionTune, { channelMax: 0, heartbeat: 1, frameMax: 0 }))
719
- .then(wait(defs.ConnectionTuneOk))
720
- .then(wait(defs.ConnectionOpen))
721
- .then(() => send(defs.ConnectionOpenOk, { knownHosts: '' }))
722
- .then(cb, cb);
723
- }));
724
-
725
- it('heartbeat:0 means no heartbeater is started', connectionTest((c, cb) => {
726
- const opts = Object.create(OPEN_OPTS);
727
- opts.heartbeat = 0;
728
- c.open(opts, (err) => {
729
- assert.ifError(err);
730
- assert.strictEqual(c.heartbeat, 0);
731
- assert.strictEqual(c.heartbeater, null);
732
- cb();
733
- });
734
- }, (send, wait, cb) => {
735
- send(defs.ConnectionStart, {
736
- versionMajor: 0, versionMinor: 9,
737
- serverProperties: {},
738
- mechanisms: Buffer.from('PLAIN'),
739
- locales: Buffer.from('en_US'),
740
- });
741
- wait(defs.ConnectionStartOk)()
742
- .then(() => send(defs.ConnectionTune, { channelMax: 0, heartbeat: 60, frameMax: 0 }))
743
- .then(wait(defs.ConnectionTuneOk))
744
- .then(wait(defs.ConnectionOpen))
745
- .then(() => send(defs.ConnectionOpenOk, { knownHosts: '' }))
746
- .then(cb, cb);
747
- }));
748
-
749
- it('heartbeat:0 disables heartbeats even if server suggests one', connectionTest((c, cb) => {
750
- const opts = Object.create(OPEN_OPTS);
751
- opts.heartbeat = 0;
752
- c.open(opts, cb);
753
- }, (send, wait, cb) => {
754
- send(defs.ConnectionStart, {
755
- versionMajor: 0, versionMinor: 9,
756
- serverProperties: {},
757
- mechanisms: Buffer.from('PLAIN'),
758
- locales: Buffer.from('en_US'),
759
- });
760
- wait(defs.ConnectionStartOk)()
761
- .then(() => send(defs.ConnectionTune, { channelMax: 0, heartbeat: 60, frameMax: 0 }))
762
- .then(wait(defs.ConnectionTuneOk))
763
- .then((tuneOk) => {
764
- assert.strictEqual(tuneOk.fields.heartbeat, 0);
765
- })
766
- .then(wait(defs.ConnectionOpen))
767
- .then(() => send(defs.ConnectionOpenOk, { knownHosts: '' }))
768
- .then(cb, cb);
769
- }));
770
- });
771
-
772
- });