X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=test%2Flib%2Fbase.js;fp=test%2Flib%2Fbase.js;h=a7844e5ac6f1b47fc1690715b086b007f84b7588;hb=174280d3f44ba13dac0b26d42d968189a4f4fa93;hp=0000000000000000000000000000000000000000;hpb=67905316ada5ee4668306506705f4ee2a5f407f0;p=squeep-amqp-helper diff --git a/test/lib/base.js b/test/lib/base.js new file mode 100644 index 0000000..a7844e5 --- /dev/null +++ b/test/lib/base.js @@ -0,0 +1,364 @@ +/* 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