--- /dev/null
+/* eslint-env mocha */
+/* eslint-disable node/no-unpublished-require */
+'use strict';
+const assert = require('assert');
+const sinon = require('sinon');
+const Base = require('../../lib/base');
+const amqp = require('amqplib');
+const { StubLogger } = require('@squeep/test-helper');
+
+describe('Base', function () {
+ let logger, options, base;
+ const expectedException = new Error('oh no');
+
+ beforeEach(function () {
+ logger = new StubLogger()
+ logger._reset();
+ options = {
+ amqp: {
+ url: 'amqp://user:password@rabbitmq.int:5672',
+ },
+ };
+ sinon.stub(amqp, 'connect').resolves({
+ createConfirmChannel: sinon.stub().resolves({
+ on: sinon.stub(),
+ checkQueue: sinon.stub(),
+ assertExchange: sinon.stub(),
+ assertQueue: sinon.stub(),
+ bindQueue: sinon.stub(),
+ prefetch: sinon.stub(),
+ consume: sinon.stub(),
+ recover: sinon.stub(),
+ close: sinon.stub(),
+ }),
+ connection: {
+ stream: {
+ writable: true,
+ },
+ },
+ on: sinon.stub(),
+ close: sinon.stub(),
+ });
+ base = new Base(logger, options);
+ });
+
+ afterEach(function () {
+ sinon.restore();
+ });
+
+ describe('connect', function () {
+ beforeEach(function () {
+ sinon.stub(base, '_connectAMQP');
+ sinon.stub(base, 'close');
+ });
+ it('covers success', async function () {
+ await base.connect();
+ assert(base._connectAMQP.called);
+ });
+ it('covers failure', async function () {
+ base._connectAMQP.rejects(expectedException);
+ await assert.rejects(base.connect(), expectedException);
+ assert(base._connectAMQP.called);
+ assert(base.close.called);
+ assert(base.logger.error.called);
+ });
+ }); // connect
+
+ describe('_connectAMQP', function () {
+ beforeEach(function () {
+ sinon.stub(base, '_establishAMQPConnection');
+ sinon.stub(base, '_establishAMQPChannel');
+ });
+ it('covers', async function () {
+ await base._connectAMQP();
+ assert(base._establishAMQPConnection.called);
+ assert(base._establishAMQPChannel.called);
+ });
+ }); // _connectAMQP
+
+ describe('_establishAMQPConnection', function () {
+ it('covers success', async function () {
+ await base._establishAMQPConnection();
+ assert(amqp.connect.called);
+ assert(base.connection.on.called);
+ });
+ it('covers failure', async function () {
+ amqp.connect.rejects(expectedException);
+ await assert.rejects(base._establishAMQPConnection(), expectedException);
+ });
+ }); // _establishAMQPConnection
+
+ describe('_establishAMQPChannel', function () {
+ beforeEach(async function () {
+ await base._establishAMQPConnection();
+ });
+ it('covers success', async function () {
+ await base._establishAMQPChannel();
+ assert(base.connection.createConfirmChannel.called);
+ assert(base.channel.on.called);
+ });
+ it('covers failure', async function () {
+ base.connection.createConfirmChannel.rejects(expectedException);
+ await assert.rejects(base._establishAMQPChannel(), expectedException);
+ });
+ }); // _establishAMQPChannel
+
+ describe('AMQP Event Handlers', function () {
+ let fatalErr, nonFatalErr;
+ beforeEach(function () {
+ fatalErr = {
+ code: 501,
+ };
+ nonFatalErr = {
+ code: 200,
+ };
+ base.connection = {};
+ base.channel = {};
+ base.queueConsumerTags = { 'consumer': 'placeholder' };
+ });
+ describe('_eventAMQPConnectionClose', function () {
+ it('fatal behavior', function () {
+ base._eventAMQPConnectionClose(fatalErr);
+ assert.strictEqual(base.connection, undefined);
+ assert.strictEqual(base.channel, undefined);
+ assert(base.logger.error.called);
+ });
+ it('non-fatal behavior', function () {
+ base._eventAMQPConnectionClose(nonFatalErr);
+ assert.strictEqual(base.connection, undefined);
+ assert.strictEqual(base.channel, undefined);
+ assert(base.logger.debug.called);
+ });
+ }); // _eventAMQPConnectionClose
+
+ describe('_eventAMQPConnectionError', function () {
+ it('logs event', function () {
+ base._eventAMQPConnectionError(fatalErr);
+ assert(base.logger.error.called);
+ });
+ }); // _eventAMQPConnectionError
+
+ describe('_eventAMQPConnectionBlocked', function () {
+ it('logs event', function () {
+ const reason = 'because';
+ base._eventAMQPConnectionBlocked(reason);
+ assert(base.logger.debug.called);
+ });
+ }); // _eventAMQPConnectionBlocked
+
+ describe('_eventAMQPConnectionUnblocked', function () {
+ it('logs event', function () {
+ base._eventAMQPConnectionUnblocked();
+ assert(base.logger.debug.called);
+ });
+ }); // _eventAMQPConnectionUnblocked
+
+ describe('_eventAMQPChannelClose', function () {
+ it('logs event', function () {
+ base._eventAMQPChannelClose();
+ assert(base.logger.debug.called);
+ });
+ it('logs fatal event', function () {
+ base._eventAMQPChannelClose(fatalErr);
+ assert(base.logger.error.called);
+ });
+ }); // _eventAMQPChannelClose
+
+ describe('_eventAMQPChannelError', function () {
+ it('logs event', function () {
+ base._eventAMQPChannelError(fatalErr);
+ assert(base.logger.error.called);
+ });
+ }); // _eventAMQPChannelError
+
+ describe('_eventAMQPChannelReturn', function () {
+ it('logs event', function () {
+ const msg = 'msg';
+ base._eventAMQPChannelReturn(msg);
+ assert(base.logger.error.called);
+ });
+ }); // _eventAMQPChannelReturn
+
+ describe('_eventAMQPChannelDrain', function () {
+ it('logs event', function () {
+ base._eventAMQPChannelDrain();
+ assert(base.logger.debug.called);
+ });
+ }); // _eventAMQPChannelDrain
+ }); // AMQP Event Handlers
+
+ describe('AMQP Plumbing Naming', function () {
+ let name, prefix;
+ beforeEach(function () {
+ name = 'name';
+ prefix = base.options.prefix;
+ });
+ function _expectedParts(optionNames = []) {
+ const expected = [name];
+ optionNames.forEach((name) => {
+ if (base.options[name]) {
+ expected.push(...base.options[name].split('.'));
+ }
+ }); // eslint-disable-line security/detect-object-injection
+ return expected;
+ }
+ function _assertParts(value, expectedParts, splitter = '.') {
+ const parts = value.split(splitter);
+ expectedParts.forEach((part) => assert(parts.includes(part), `missing ${part} expected [${expectedParts}] got [${parts}]`));
+ }
+ function _assertNoPrefix(value, splitter = '.') {
+ const parts = value.split(splitter);
+ assert(!parts.includes(prefix));
+ }
+
+ describe('_exchangeName', function () {
+ it('names exchange', function () {
+ const expectedParts = _expectedParts(['prefix']);
+ const result = base._exchangeName(name);
+ _assertParts(result, expectedParts);
+ });
+ it('covers no prefix', function () {
+ const expectedParts = _expectedParts([]);
+ base.options.prefix = undefined;
+ const result = base._exchangeName(name);
+ _assertParts(result, expectedParts);
+ _assertNoPrefix(result);
+ });
+ }); // _exchangeName
+
+ describe('_retryExchangeName', function () {
+ it('names retry exchange', function () {
+ const expectedParts = _expectedParts(['prefix', 'retrySuffix']);
+ const result = base._retryExchangeName(name);
+ _assertParts(result, expectedParts);
+ });
+ it('covers no prefix', function () {
+ const expectedParts = _expectedParts(['retrySuffix']);
+ base.options.prefix = undefined;
+ const result = base._retryExchangeName(name);
+ _assertParts(result, expectedParts);
+ _assertNoPrefix(result);
+ });
+ }); // _retryExchangeName
+
+ describe('_queueName', function () {
+ it('names queue', function () {
+ const expectedParts = _expectedParts(['prefix', 'queueSuffix']);
+ const result = base._queueName(name);
+ _assertParts(result, expectedParts);
+ });
+ it('covers no prefix', function () {
+ const expectedParts = _expectedParts(['queueSuffix']);
+ base.options.prefix = undefined;
+ const result = base._queueName(name);
+ _assertParts(result, expectedParts);
+ _assertNoPrefix(result);
+ });
+ }); // _queueName
+
+ describe('_retryQueueName', function () {
+ it('names retry queue', function () {
+ const expectedParts = _expectedParts(['prefix', 'retrySuffix', 'queueSuffix']);
+ const result = base._retryQueueName(name);
+ _assertParts(result, expectedParts);
+ });
+ it('covers no prefix', function () {
+ const expectedParts = _expectedParts(['retrySuffix', 'queueSuffix']);
+ base.options.prefix = undefined;
+ const result = base._retryQueueName(name);
+ _assertParts(result, expectedParts);
+ _assertNoPrefix(result);
+ });
+ }); // _retryQueueName
+
+ describe('_retryQueuePolicyName', function () {
+ it('names retry wildcard queue for ttl policy', function () {
+ const expectedParts = _expectedParts(['prefix', 'retrySuffix', 'queueSuffix']);
+ expectedParts.shift();
+ expectedParts.push('.*');
+ const result = base._retryQueuePolicyName(name);
+ _assertParts(result, expectedParts, '\\.');
+ });
+ it('covers no prefix', function () {
+ const expectedParts = _expectedParts(['retrySuffix', 'queueSuffix']);
+ base.options.prefix = undefined;
+ expectedParts.shift();
+ expectedParts.push('.*');
+ const result = base._retryQueuePolicyName(name);
+ _assertParts(result, expectedParts, '\\.');
+ _assertNoPrefix(result, '\\.');
+ });
+ });
+ }); // AMQP Plumbing Naming
+
+ describe('establishAMQPPlumbing', function () {
+ beforeEach(async function () {
+ await base.connect();
+ sinon.stub(base, 'close');
+ });
+ it('covers success', async function () {
+ await base.establishAMQPPlumbing();
+ assert(base.channel.assertExchange.called);
+ assert(base.channel.assertQueue.called);
+ assert(base.channel.bindQueue.called);
+ });
+ it('covers failure', async function () {
+ base.channel.assertQueue.rejects(expectedException);
+ await assert.rejects(base.establishAMQPPlumbing(), expectedException);
+ assert(base.close.called);
+ });
+ }); // establishAMQPPlumbing
+
+ describe('close', function () {
+ let channelRecoverStub, channelCloseStub, connectionCloseStub;
+ beforeEach(async function () {
+ await base.connect();
+ channelRecoverStub = base.channel.recover;
+ channelCloseStub = base.channel.close;
+ connectionCloseStub = base.connection.close;
+ });
+ it('closes active connection and channel', async function () {
+ await base.close();
+ assert(channelRecoverStub.called);
+ assert(channelCloseStub.called);
+ assert(connectionCloseStub.called);
+ });
+ it('covers no active channel', async function () {
+ base.channel = undefined;
+ await base.close();
+ assert(channelRecoverStub.notCalled);
+ assert(channelCloseStub.notCalled);
+ assert(connectionCloseStub.called);
+ });
+ it('covers no active connection or channel', async function () {
+ base.channel = undefined;
+ base.connection = undefined;
+ await base.close();
+ assert(channelRecoverStub.notCalled);
+ assert(channelCloseStub.notCalled);
+ assert(connectionCloseStub.notCalled);
+ });
+ it('covers failure', async function () {
+ channelCloseStub.rejects(expectedException);
+ await assert.rejects(base.close(), expectedException);
+ });
+ }); // close
+
+ describe('health', function () {
+ beforeEach(async function () {
+ await base._establishAMQPConnection();
+ });
+ it('checks connection is writable', function () {
+ const result = base.health();
+ assert.strictEqual(result, true);
+ });
+ }); // health
+
+ describe('policyCommand', function () {
+ it('covers', function () {
+ const result = base.policyCommand();
+ assert(result);
+ });
+ }); // policyCommand
+
+}); // Base
\ No newline at end of file