@onify/fake-amqplib 1.0.0 → 3.0.0

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/main.cjs ADDED
@@ -0,0 +1,763 @@
1
+ 'use strict';
2
+
3
+ var smqp = require('smqp');
4
+ var events = require('events');
5
+ var url = require('url');
6
+
7
+ const kSmqp = Symbol.for('smqp');
8
+ const kClosed = Symbol.for('closed');
9
+ const kDeliveryTag = Symbol.for('channel delivery tag');
10
+ const kPrefetch = Symbol.for('prefetch');
11
+ const kChannelPrefetch = Symbol.for('channel prefetch');
12
+
13
+ class AmqplibBroker extends smqp.Broker {
14
+ constructor(...args) {
15
+ super(...args);
16
+ this[kDeliveryTag] = 0;
17
+ }
18
+ _getNextDeliveryTag() {
19
+ return ++this[kDeliveryTag];
20
+ }
21
+ _getMessageByDeliveryTag(queue, deliveryTag) {
22
+ const q = this.getQueue(queue);
23
+ return q.messages.find((m) => m.fields.deliveryTag === deliveryTag);
24
+ }
25
+ _getChannelConsumers(channelName) {
26
+ return this.getConsumers().filter((f) => f.options.channelName === channelName);
27
+ }
28
+ }
29
+
30
+ class FakeAmqpError extends Error {
31
+ constructor(message, code, killChannel, killConnection) {
32
+ super(message);
33
+ this.code = code;
34
+ this._killChannel = killChannel;
35
+ this._killConnection = killConnection;
36
+ }
37
+ }
38
+
39
+ class FakeAmqpNotFoundError extends FakeAmqpError {
40
+ constructor(type, name, vhost, killConnection = false) {
41
+ super(`Channel closed by server: 404 (NOT-FOUND) with message "NOT_FOUND - no ${type} '${name}' in vhost '${vhost || '/'}'`, 404, true, killConnection);
42
+ }
43
+ }
44
+
45
+ class FakeAmqpUnknownDeliveryTag extends FakeAmqpError {
46
+ constructor(deliveryTag) {
47
+ super(`Channel closed by server: 406 (PRECONDITION-FAILED) with message "PRECONDITION_FAILED - unknown delivery tag ${deliveryTag}`, 406, true, false);
48
+ }
49
+ get _emit() {
50
+ return true;
51
+ }
52
+ }
53
+
54
+ function Message(smqpMessage, deliveryTag) {
55
+ this[kSmqp] = smqpMessage;
56
+ this.fields = { ...smqpMessage.fields, deliveryTag };
57
+ this.content = Buffer.from(smqpMessage.content);
58
+ this.properties = { ...smqpMessage.properties };
59
+ }
60
+
61
+ class FakeAmqplibChannel extends events.EventEmitter {
62
+ constructor(broker, connection) {
63
+ super();
64
+ this.connection = connection;
65
+
66
+ this[kPrefetch] = 10000;
67
+ this[kChannelPrefetch] = Infinity;
68
+ this[kClosed] = false;
69
+ const channelName = this._channelName = `channel-${generateId()}`;
70
+ this._version = connection._version;
71
+ this._broker = broker;
72
+
73
+ this._channelQueue = broker.assertQueue(`#${channelName}`);
74
+ this._emitReturn = this._emitReturn.bind(this);
75
+
76
+ broker.on('return', this._emitReturn);
77
+
78
+ this._createChannelMessage = this._createChannelMessage.bind(this);
79
+ this._calculateChannelCapacity = this._calculateChannelCapacity.bind(this);
80
+ }
81
+ get _closed() {
82
+ return this[kClosed];
83
+ }
84
+ assertExchange(...args) {
85
+ return this._callBroker(assertExchange, ...args);
86
+
87
+ function assertExchange(exchange, ...assertArgs) {
88
+ this.assertExchange(exchange, ...assertArgs);
89
+ return { exchange };
90
+ }
91
+ }
92
+ assertQueue(...args) {
93
+ const connection = this.connection;
94
+ return this._callBroker(assertQueue, ...args);
95
+
96
+ function assertQueue(queueName, ...assertArgs) {
97
+ const name = queueName ? queueName : `amqp.gen-${generateId()}`;
98
+ const options = typeof assertArgs[0] === 'object' ? assertArgs.shift() : {};
99
+ const queue = this.assertQueue(name, { ...options, _connectionId: connection._id }, ...assertArgs);
100
+ return {
101
+ queue: name,
102
+ messageCount: queue.messageCount,
103
+ consumerCount: queue.consumerCount,
104
+ };
105
+ }
106
+ }
107
+ bindExchange(destination, source, ...args) {
108
+ const broker = this._broker;
109
+ return Promise.all([ this.checkExchange(source), this.checkExchange(destination) ]).then(() => {
110
+ return this._callBroker(broker.bindExchange, source, destination, ...args);
111
+ });
112
+ }
113
+ bindQueue(queue, source, ...args) {
114
+ return Promise.all([ this.checkQueue(queue), this.checkExchange(source) ]).then(() => {
115
+ return this._callBroker(this._broker.bindQueue, queue, source, ...args);
116
+ });
117
+ }
118
+ checkExchange(name, ...args) {
119
+ const connPath = this.connection._url.pathname;
120
+ return this._callBroker(check, ...args);
121
+
122
+ function check() {
123
+ if (!this.getExchange(name)) throw new FakeAmqpNotFoundError('exchange', name, connPath);
124
+ return true;
125
+ }
126
+ }
127
+ checkQueue(name, ...args) {
128
+ const connPath = this.connection._url.pathname;
129
+ return this._callBroker(check, ...args);
130
+
131
+ function check() {
132
+ let queue;
133
+ if (!(queue = this.getQueue(name))) {
134
+ throw new FakeAmqpNotFoundError('queue', name, connPath);
135
+ }
136
+
137
+ return {
138
+ messageCount: queue.messageCount,
139
+ consumerCount: queue.consumerCount,
140
+ };
141
+ }
142
+ }
143
+ get(queue, ...args) {
144
+ const connPath = this.connection._url.pathname;
145
+ const createMessage = this._createChannelMessage;
146
+ return this._callBroker(getMessage, ...args);
147
+
148
+ function getMessage(...getargs) {
149
+ const q = this.getQueue(queue);
150
+ if (!q) throw new FakeAmqpNotFoundError('queue', queue, connPath);
151
+ const msg = q.get(...getargs) || false;
152
+ if (!msg) return msg;
153
+
154
+ return createMessage(msg, args[0]?.noAck);
155
+ }
156
+ }
157
+ deleteExchange(exchange, ...args) {
158
+ const connPath = this.connection._url.pathname;
159
+ return this._callBroker(check, ...args);
160
+
161
+ function check() {
162
+ const result = this.deleteExchange(exchange, ...args);
163
+ if (!result && this.owner.version < 3.2) throw new FakeAmqpNotFoundError('exchange', exchange, connPath);
164
+ return result;
165
+ }
166
+ }
167
+ deleteQueue(queue, ...args) {
168
+ const connPath = this.connection._url.pathname;
169
+ return this._callBroker(check, ...args);
170
+
171
+ function check() {
172
+ const result = this.deleteQueue(queue, ...args);
173
+ if (!result && this.owner.version < 3.2) throw new FakeAmqpNotFoundError('queue', queue, connPath);
174
+ return result;
175
+ }
176
+ }
177
+ publish(exchange, routingKey, content, options, callback) {
178
+ if (!Buffer.isBuffer(content)) throw new TypeError('content is not a buffer');
179
+ if (exchange === '') return this.sendToQueue(routingKey, content, options, callback);
180
+
181
+ const args = [ this._broker.publish, exchange, routingKey, content ];
182
+
183
+ args.push(options, callback);
184
+
185
+ this.checkExchange(exchange).then(() => {
186
+ return this._callBroker(...args);
187
+ }).catch((err) => {
188
+ this.emit('error', err);
189
+ });
190
+
191
+ return true;
192
+ }
193
+ purgeQueue(queue, ...args) {
194
+ const connPath = this.connection._url.pathname;
195
+ return this._callBroker(check, ...args);
196
+
197
+ function check() {
198
+ const result = this.purgeQueue(queue);
199
+ if (!result && this.owner.version < 3.2) throw new FakeAmqpNotFoundError('queue', queue, connPath);
200
+ return result === undefined ? undefined : { messageCount: result };
201
+ }
202
+ }
203
+ sendToQueue(queue, content, options, callback) {
204
+ if (!Buffer.isBuffer(content)) throw new TypeError('content is not a buffer');
205
+
206
+ const args = [ this._broker.sendToQueue, queue, content ];
207
+
208
+ args.push(options, callback);
209
+
210
+ this.checkQueue(queue).then(() => {
211
+ return this._callBroker(...args);
212
+ }).catch((err) => {
213
+ this.emit('error', err);
214
+ });
215
+
216
+ return true;
217
+ }
218
+ unbindExchange(destination, source, pattern, ...args) {
219
+ const connPath = this.connection._url.pathname;
220
+ return this._callBroker(check, ...args);
221
+
222
+ function check() {
223
+ const q = this.getExchange(destination);
224
+ if (!q) throw new FakeAmqpNotFoundError('exchange', destination);
225
+
226
+ const exchange = this.getExchange(source);
227
+ if (!exchange) throw new FakeAmqpNotFoundError('exchange', source);
228
+
229
+ const result = this.unbindExchange(source, destination, pattern);
230
+ if (!result && this.owner.version <= 3.2) throw new FakeAmqpNotFoundError('binding', pattern, connPath);
231
+
232
+ return true;
233
+ }
234
+ }
235
+ unbindQueue(queue, source, pattern, ...args) {
236
+ const connPath = this.connection._url.pathname;
237
+ return this._callBroker(check, ...args);
238
+
239
+ function check() {
240
+ const q = this.getQueue(queue);
241
+ if (!q) throw new FakeAmqpNotFoundError('queue', queue);
242
+
243
+ const exchange = this.getExchange(source);
244
+ if (!exchange) throw new FakeAmqpNotFoundError('exchange', source);
245
+
246
+ const binding = exchange.getBinding(queue, pattern);
247
+ if (!binding && this.owner.version <= 3.2) {
248
+ throw new FakeAmqpNotFoundError('binding', pattern, connPath, this.owner.version < 3.2);
249
+ }
250
+
251
+ this.unbindQueue(queue, source, pattern);
252
+ return true;
253
+ }
254
+ }
255
+ consume(queue, onMessage, options = {}, callback) {
256
+ const { _id: connId, _url: connUrl } = this.connection;
257
+ const createMessage = this._createChannelMessage;
258
+ const calculateCapacity = this._calculateChannelCapacity;
259
+ const channelName = this._channelName;
260
+ const prefetch = this[kPrefetch];
261
+
262
+ return this._callBroker(consume, callback);
263
+
264
+ function consume() {
265
+ const q = queue && this.getQueue(queue);
266
+ if (!q) {
267
+ throw new FakeAmqpNotFoundError('queue', queue, connUrl.pathname);
268
+ }
269
+
270
+ if (q.exclusive || (q.options.exclusive && q.options._connectionId !== connId)) {
271
+ throw new FakeAmqpError(`Channel closed by server: 403 (ACCESS-REFUSED) with message "ACCESS_REFUSED - queue '${queue}' in vhost '${connUrl.pathname}' in exclusive use"`, 403, true, true);
272
+ }
273
+
274
+ const consumer = this.consume(queue, onMessage && handler, {
275
+ ...options,
276
+ channelName,
277
+ prefetch: calculateCapacity(prefetch),
278
+ _consumerPrefetch: prefetch,
279
+ });
280
+
281
+ const capacityProp = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(consumer), 'capacity');
282
+ Object.defineProperty(consumer, 'capacity', {
283
+ get() {
284
+ return calculateCapacity(capacityProp.get.call(this));
285
+ },
286
+ });
287
+
288
+ return { consumerTag: consumer.consumerTag };
289
+ }
290
+
291
+ function handler(_, msg) {
292
+ onMessage(createMessage(msg, options.noAck));
293
+ }
294
+ }
295
+ cancel(consumerTag, ...args) {
296
+ return this._callBroker(this._broker.cancel, consumerTag, ...args);
297
+ }
298
+ close(callback) {
299
+ if (this[kClosed]) return;
300
+ this._teardown();
301
+ this.emit('close');
302
+ return resolveOrCallback(callback);
303
+ }
304
+ ack(message, allUpTo) {
305
+ const deliveryTag = message.fields.deliveryTag;
306
+ const channelMessage = this._broker._getMessageByDeliveryTag(this._channelQueue.name, deliveryTag);
307
+ const channelQ = this._channelQueue;
308
+
309
+ if (!allUpTo) this._callBroker(ackMessage);
310
+ else this._callBroker(ackAllUpToMessage);
311
+
312
+ function ackMessage() {
313
+ const msg = message[kSmqp];
314
+ if (!channelMessage || !msg.pending) {
315
+ throw new FakeAmqpUnknownDeliveryTag(message.fields.deliveryTag);
316
+ }
317
+
318
+ channelQ.ack(channelMessage, false);
319
+ this.ack(msg, false);
320
+ }
321
+
322
+ function ackAllUpToMessage() {
323
+ const msg = message[kSmqp];
324
+ if (!channelMessage || !msg.pending) {
325
+ throw new FakeAmqpUnknownDeliveryTag(message.fields.deliveryTag);
326
+ }
327
+
328
+ const brokerMessages = allUpToDeliveryTag(channelQ, deliveryTag, 'ack', false);
329
+ for (const brokerMessage of brokerMessages) {
330
+ brokerMessage.ack(false);
331
+ }
332
+
333
+ channelQ.ack(channelMessage, false);
334
+ this.ack(msg, false);
335
+ }
336
+ }
337
+ ackAll() {
338
+ const channelQ = this._channelQueue;
339
+ let msg;
340
+ const brokerMessages = [];
341
+ while ((msg = channelQ.get())) {
342
+ brokerMessages.push(msg.content[kSmqp]);
343
+ msg.ack();
344
+ }
345
+
346
+ for (const brokerMessage of brokerMessages) {
347
+ brokerMessage.ack();
348
+ }
349
+ }
350
+ reject(message, requeue = false) {
351
+ const deliveryTag = message.fields.deliveryTag;
352
+ const channelMessage = this._broker._getMessageByDeliveryTag(this._channelQueue.name, deliveryTag);
353
+ const channelQ = this._channelQueue;
354
+
355
+ this._callBroker(rejectMessage);
356
+
357
+ function rejectMessage() {
358
+ const msg = message[kSmqp];
359
+ if (!channelMessage || !msg.pending) {
360
+ throw new FakeAmqpUnknownDeliveryTag(deliveryTag);
361
+ }
362
+
363
+ channelQ.reject(channelMessage, false);
364
+ this.reject(msg, requeue);
365
+ }
366
+ }
367
+ nack(message, allUpTo = false, requeue = false) {
368
+ if (this.connection._version < 2.3) throw new Error(`Nack is not implemented in versions before 2.3 (${this.connection._version})`);
369
+
370
+ const deliveryTag = message.fields.deliveryTag;
371
+ const channelMessage = this._broker._getMessageByDeliveryTag(this._channelQueue.name, deliveryTag);
372
+ const channelQ = this._channelQueue;
373
+
374
+ if (!allUpTo) this._callBroker(nackMessage);
375
+ else this._callBroker(nackAllUpToMessage);
376
+
377
+ function nackMessage() {
378
+ const msg = message[kSmqp];
379
+ if (!channelMessage || !msg.pending) {
380
+ throw new FakeAmqpUnknownDeliveryTag(deliveryTag);
381
+ }
382
+
383
+ channelQ.nack(channelMessage, false, false);
384
+ this.nack(msg, false, requeue);
385
+ }
386
+
387
+ function nackAllUpToMessage() {
388
+ const msg = message[kSmqp];
389
+ if (!channelMessage || !msg.pending) {
390
+ throw new FakeAmqpUnknownDeliveryTag(deliveryTag);
391
+ }
392
+
393
+ const brokerMessages = allUpToDeliveryTag(channelQ, deliveryTag, 'nack', false, false);
394
+ for (const brokerMessage of brokerMessages) {
395
+ brokerMessage.nack(false, requeue);
396
+ }
397
+
398
+ channelMessage.nack(false, false);
399
+ this.nack(msg, false, requeue);
400
+ }
401
+ }
402
+ nackAll(requeue = true) {
403
+ const channelQ = this._channelQueue;
404
+ let msg;
405
+ const brokerMessages = [];
406
+ while ((msg = channelQ.get())) {
407
+ brokerMessages.push(msg.content[kSmqp]);
408
+ msg.reject(false);
409
+ }
410
+
411
+ for (const brokerMessage of brokerMessages) {
412
+ brokerMessage.reject(requeue);
413
+ }
414
+ }
415
+ prefetch(val, isChannelPrefetch) {
416
+ if (this.connection._version < 3.3) {
417
+ if (isChannelPrefetch !== undefined) {
418
+ return this.connection.close();
419
+ }
420
+ this[kChannelPrefetch] = val;
421
+ } else {
422
+ if (isChannelPrefetch) {
423
+ this[kChannelPrefetch] = val;
424
+ } else {
425
+ this[kPrefetch] = val;
426
+ }
427
+ }
428
+ }
429
+ _callBroker(fn, ...args) {
430
+ let [ poppedCb ] = args.slice(-1);
431
+ if (typeof poppedCb === 'function') args.splice(-1);
432
+ else poppedCb = null;
433
+
434
+ if (this.connection._closed) throw new FakeAmqpError('Connection is closed', 504);
435
+ if (this[kClosed]) throw new Error('Channel is closed');
436
+
437
+ return new Promise((resolve, reject) => {
438
+ try {
439
+ const result = fn.call(this._broker, ...args);
440
+ if (poppedCb) poppedCb(null, result);
441
+ return resolve(result);
442
+ } catch (err) {
443
+ if (err._killConnection) this.connection.close();
444
+ else if (err._killChannel) this._teardown();
445
+ if (err._emit) this.emit('error', err);
446
+ if (!poppedCb) return reject(err);
447
+ poppedCb(err);
448
+ return resolve();
449
+ }
450
+ });
451
+ }
452
+ _emitReturn({ fields, content, properties }) {
453
+ process.nextTick(() => {
454
+ this.emit('return', { fields, content, properties });
455
+ });
456
+ }
457
+ _createChannelMessage(smqpMessage, noAck) {
458
+ const deliveryTag = this._broker._getNextDeliveryTag();
459
+ const consumeMessage = new Message(smqpMessage, deliveryTag);
460
+ if (!noAck) {
461
+ const channelQ = this._channelQueue;
462
+ channelQ.queueMessage(consumeMessage.fields, consumeMessage);
463
+ }
464
+ return consumeMessage;
465
+ }
466
+ _teardown() {
467
+ this[kClosed] = true;
468
+ const channelName = this._channelName;
469
+ const broker = this._broker;
470
+ const channelConsumers = broker._getChannelConsumers(channelName);
471
+ channelConsumers.forEach((c) => broker.cancel(c.consumerTag));
472
+
473
+ let msg;
474
+ while ((msg = this._channelQueue.get())) {
475
+ msg.content[kSmqp].reject(true);
476
+ msg.reject(false);
477
+ }
478
+
479
+ broker.off('return', this._emitReturn);
480
+ }
481
+ _calculateChannelCapacity(consumerCapacity) {
482
+ const channelPrefetch = this[kChannelPrefetch];
483
+ if (channelPrefetch === Infinity) return consumerCapacity;
484
+
485
+ const channelCapacity = channelPrefetch - this._channelQueue.messageCount;
486
+
487
+ let capacity = consumerCapacity;
488
+ if (channelCapacity <= 0) capacity = 0;
489
+ else if (channelCapacity < capacity) capacity = channelCapacity;
490
+ return capacity;
491
+ }
492
+ }
493
+
494
+ class FakeAmqplibConfirmChannel extends FakeAmqplibChannel {
495
+ publish(exchange, routingKey, content, options, callback) {
496
+ if (!Buffer.isBuffer(content)) throw new TypeError('content is not a buffer');
497
+ if (exchange === '') return this.sendToQueue(routingKey, content, options, callback);
498
+
499
+ const args = [ this._broker.publish, exchange, routingKey, content ];
500
+
501
+ args.push(...addConfirmCallback(this._broker, options, callback));
502
+
503
+ this.checkExchange(exchange).then(() => {
504
+ return this._callBroker(...args);
505
+ }).catch((err) => {
506
+ this.emit('error', err);
507
+ });
508
+
509
+ return true;
510
+ }
511
+ sendToQueue(queue, content, options, callback) {
512
+ if (!Buffer.isBuffer(content)) throw new TypeError('content is not a buffer');
513
+
514
+ const args = [ this._broker.sendToQueue, queue, content ];
515
+
516
+ args.push(...addConfirmCallback(this._broker, options, callback));
517
+
518
+ this.checkQueue(queue).then(() => {
519
+ return this._callBroker(...args);
520
+ }).catch((err) => {
521
+ this.emit('error', err);
522
+ });
523
+
524
+ return true;
525
+ }
526
+ }
527
+
528
+ class FakeAmqplibConnection extends events.EventEmitter {
529
+ constructor(broker, version, amqpUrl) {
530
+ super();
531
+ this[kClosed] = false;
532
+ this._channels = [];
533
+ this._url = normalizeAmqpUrl(amqpUrl);
534
+ this._id = generateId();
535
+ this._broker = broker;
536
+ this._version = version;
537
+ }
538
+ get _closed() {
539
+ return this[kClosed];
540
+ }
541
+ get connection() {
542
+ return {
543
+ serverProperties: {
544
+ host: this._url.host,
545
+ product: 'RabbitMQ',
546
+ version: `${this._version.toString()}.0`,
547
+ platform: 'OS',
548
+ copyright: 'MIT',
549
+ information: 'fake',
550
+ },
551
+ };
552
+ }
553
+ createChannel(...args) {
554
+ const callback = args.slice(-1)[0];
555
+ if (this[kClosed]) return resolveOrCallback(callback, new FakeAmqpError('Connection closed: 504', 504));
556
+
557
+ const channel = new FakeAmqplibChannel(this._broker, this);
558
+ this._channels.push(channel);
559
+ return resolveOrCallback(callback, null, channel);
560
+ }
561
+ createConfirmChannel(...args) {
562
+ if (this[kClosed]) return resolveOrCallback(args.slice(-1)[0], new FakeAmqpError('Connection closed: 504', 504));
563
+
564
+ const channel = new FakeAmqplibConfirmChannel(this._broker, this);
565
+ this._channels.push(channel);
566
+ return resolveOrCallback(args.slice(-1)[0], null, channel);
567
+ }
568
+ close(...args) {
569
+ if (this[kClosed]) return resolveOrCallback(args.slice(-1)[0]);
570
+ this[kClosed] = true;
571
+
572
+ this._channels.splice(0).forEach((channel) => channel.close());
573
+
574
+ this.emit('close');
575
+
576
+ return resolveOrCallback(args.slice(-1)[0]);
577
+ }
578
+ }
579
+
580
+ function FakeAmqplib(minorVersion = '3.5') {
581
+ if (!(this instanceof FakeAmqplib)) {
582
+ return new FakeAmqplib(minorVersion);
583
+ }
584
+
585
+ this.version = Number(minorVersion);
586
+ this.connections = [];
587
+
588
+ this.connect = this.connect.bind(this);
589
+ this.connectSync = this.connectSync.bind(this);
590
+ this.resetMock = this.resetMock.bind(this);
591
+ this.setVersion = this.setVersion.bind(this);
592
+ }
593
+
594
+ FakeAmqplib.prototype.connect = function fakeConnect(amqpUrl, ...args) {
595
+ const connection = this.connectSync(amqpUrl, ...args);
596
+ return resolveOrCallback(args.slice(-1)[0], null, connection);
597
+ };
598
+
599
+ FakeAmqplib.prototype.connectSync = function fakeConnectSync(amqpUrl, ...args) {
600
+ const { _broker } = this.connections.find((conn) => compareConnectionString(conn._url, amqpUrl)) || {};
601
+ const broker = _broker || new AmqplibBroker(this);
602
+ const connection = new FakeAmqplibConnection(broker, this.version, amqpUrl, ...args);
603
+
604
+ const connections = this.connections;
605
+
606
+ connections.push(connection);
607
+
608
+ connection.once('close', () => {
609
+ const idx = connections.indexOf(connection);
610
+ if (idx > -1) connections.splice(idx, 1);
611
+ });
612
+
613
+ return connection;
614
+ };
615
+
616
+ FakeAmqplib.prototype.resetMock = function fakeResetMock() {
617
+ for (const connection of this.connections.splice(0)) {
618
+ connection._broker.reset();
619
+ }
620
+ };
621
+
622
+ FakeAmqplib.prototype.setVersion = function fakeSetVersion(minorVersion) {
623
+ const n = Number(minorVersion);
624
+ if (!isNaN(n)) this.version = n;
625
+ };
626
+
627
+ function resolveOrCallback(optionalCb, err, ...args) {
628
+ if (typeof optionalCb === 'function') optionalCb(err, ...args);
629
+ if (err) return Promise.reject(err);
630
+ return Promise.resolve(...args);
631
+ }
632
+
633
+ function generateId() {
634
+ return Math.random().toString(16).substring(2, 12);
635
+ }
636
+
637
+ function compareConnectionString(url1, url2) {
638
+ const parsedUrl1 = normalizeAmqpUrl(url1);
639
+ const parsedUrl2 = normalizeAmqpUrl(url2);
640
+
641
+ return parsedUrl1.host === parsedUrl2.host && parsedUrl1.pathname === parsedUrl2.pathname;
642
+ }
643
+
644
+ function normalizeAmqpUrl(url$1) {
645
+ if (!url$1) return new URL('amqp://localhost:5672/');
646
+ if (typeof url$1 === 'string') url$1 = new URL(url$1);
647
+
648
+ if (!(url$1 instanceof URL)) {
649
+ const {
650
+ protocol = 'amqp',
651
+ hostname = 'localhost',
652
+ port = 5672,
653
+ vhost = '/',
654
+ username,
655
+ password,
656
+ ...rest
657
+ } = url$1;
658
+ let auth = username;
659
+ if (auth && password) {
660
+ auth += `:${password}`;
661
+ }
662
+ url$1 = new URL(url.format({
663
+ protocol,
664
+ hostname,
665
+ port,
666
+ pathname: vhost,
667
+ slashes: true,
668
+ auth,
669
+ }));
670
+
671
+ for (const k in rest) {
672
+ switch (k) {
673
+ case 'locale':
674
+ case 'frameMax':
675
+ case 'heartbeat':
676
+ url$1.searchParams.set(k, rest[k]);
677
+ break;
678
+ }
679
+ }
680
+ }
681
+
682
+ if (!url$1.port) url$1.port = 5672;
683
+ if (!url$1.pathname) url$1.pathname = '/';
684
+ return url$1;
685
+ }
686
+
687
+ function addConfirmCallback(broker, options, callback) {
688
+ const confirm = `msg.${generateId()}`;
689
+ const consumerTag = `ct-${confirm}`;
690
+ options = { ...options, confirm };
691
+
692
+ broker.on('message.*', onConsumeMessage, { consumerTag });
693
+
694
+ let undelivered;
695
+ function onConsumeMessage(event) {
696
+ switch (event.name) {
697
+ case 'message.nack':
698
+ case 'message.undelivered':
699
+ undelivered = event.name;
700
+ break;
701
+ }
702
+ }
703
+
704
+ function confirmCallback() {
705
+ broker.off('message.*', consumerTag);
706
+ switch (undelivered) {
707
+ case 'message.nack':
708
+ return callback(new Error('message nacked'));
709
+ case 'message.undelivered':
710
+ throw callback(new Error('message undelivered'));
711
+ default:
712
+ return callback(null, true);
713
+ }
714
+ }
715
+
716
+ return [ options, confirmCallback ];
717
+ }
718
+
719
+ function allUpToDeliveryTag(q, deliveryTag, op, ...args) {
720
+ const brokerMessages = [];
721
+
722
+ const consumer = q.consume((_, cmsg) => {
723
+ const msgDeliveryTag = cmsg.fields.deliveryTag;
724
+ if (msgDeliveryTag >= deliveryTag) {
725
+ return q.cancel(cmsg.fields.consumerTag);
726
+ }
727
+ brokerMessages.push(cmsg.content[kSmqp]);
728
+ cmsg[op](...args);
729
+ }, { prefetch: Infinity });
730
+
731
+ consumer.cancel();
732
+
733
+ return brokerMessages;
734
+ }
735
+
736
+ const defaultFake = new FakeAmqplib('3.5');
737
+ const connections = defaultFake.connections;
738
+
739
+ function connect(amqpUrl, ...args) {
740
+ return defaultFake.connect(amqpUrl, ...args);
741
+ }
742
+
743
+ function connectSync(amqpUrl, ...args) {
744
+ return defaultFake.connectSync(amqpUrl, ...args);
745
+ }
746
+
747
+ function resetMock() {
748
+ return defaultFake.resetMock();
749
+ }
750
+
751
+ function setVersion(minorVersion) {
752
+ return defaultFake.setVersion(minorVersion);
753
+ }
754
+
755
+ exports.FakeAmqplib = FakeAmqplib;
756
+ exports.FakeAmqplibChannel = FakeAmqplibChannel;
757
+ exports.FakeAmqplibConfirmChannel = FakeAmqplibConfirmChannel;
758
+ exports.FakeAmqplibConnection = FakeAmqplibConnection;
759
+ exports.connect = connect;
760
+ exports.connectSync = connectSync;
761
+ exports.connections = connections;
762
+ exports.resetMock = resetMock;
763
+ exports.setVersion = setVersion;