mqrpc
Version:
💫 Easy RPC over RabbitMQ
98 lines (97 loc) • 4.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const ava_1 = require("ava");
const sinon = require("sinon");
const _config_1 = require("../../_config");
const AmqpClient_1 = require("../../../lib/AmqpClient");
const comms_1 = require("../../../lib/RpcServer/comms");
const errors_1 = require("../../../lib/RpcServer/errors");
const sampleMessage = {
fields: { deliveryTag: 1234567890987654321 },
properties: { replyTo: 'amqp.rabbitmq.reply-to', correlationId: '123456' }
};
const amqpClient = new AmqpClient_1.default({ amqpUrl: _config_1.AMQP_URL });
ava_1.default.before(() => amqpClient.init());
ava_1.default.after.always(() => amqpClient.term());
ava_1.default.beforeEach(t => t.context.sandbox = sinon.sandbox.create());
ava_1.default.afterEach.always(t => t.context.sandbox.restore());
ava_1.default.serial('[unit] #reply acks the given message', async (t) => {
const spy = t.context.sandbox.spy(amqpClient.channel, 'ack');
await comms_1.reply(amqpClient.channel, sampleMessage);
sinon.assert.calledWith(spy, sampleMessage);
t.pass();
});
ava_1.default.serial('[unit] #reply publishes to the given replyTo with the given correlationId', async (t) => {
const spy = t.context.sandbox.spy(amqpClient.channel, 'publish');
await comms_1.reply(amqpClient.channel, sampleMessage);
sinon.assert.calledWith(spy, '', 'amqp.rabbitmq.reply-to', sinon.match.any, { correlationId: '123456', deliveryMode: undefined });
t.pass();
});
ava_1.default.serial('[unit] #reply serializes the response as JSON', async (t) => {
t.plan(5);
const spy = t.context.sandbox.spy(amqpClient.channel, 'publish');
await comms_1.reply(amqpClient.channel, sampleMessage, { meaning: 42 });
const contentMatcher = sinon.match((content) => {
t.true(content instanceof Buffer);
const json = JSON.parse(content.toString());
t.is(json.type, 'reply');
t.truthy(json.reply);
t.deepEqual(json.reply, { meaning: 42 });
t.is(json.error, undefined);
return true;
});
sinon.assert.calledWith(spy, sinon.match.string, sinon.match.string, contentMatcher, sinon.match.any);
});
ava_1.default.serial('[unit] #reply handles undefined responses', async (t) => {
const spy = t.context.sandbox.spy(amqpClient.channel, 'publish');
await comms_1.reply(amqpClient.channel, sampleMessage);
sinon.assert.calledWith(spy, sinon.match.string, sinon.match.string, sinon.match({}), sinon.match.any);
t.pass();
});
ava_1.default.serial('[unit] #reply handles null responses', async (t) => {
t.plan(1);
const spy = t.context.sandbox.spy(amqpClient.channel, 'publish');
await comms_1.reply(amqpClient.channel, sampleMessage, null);
const contentMatcher = sinon.match((content) => {
t.is(JSON.parse(content.toString()).reply, null);
return true;
});
sinon.assert.calledWith(spy, sinon.match.string, sinon.match.string, contentMatcher, sinon.match.any);
});
ava_1.default.serial('[unit] #reply sends error responses under an error key', async (t) => {
t.plan(4);
const spy = t.context.sandbox.spy(amqpClient.channel, 'publish');
await comms_1.reply(amqpClient.channel, sampleMessage, new errors_1.NoSuchProcedure('oops'));
const contentMatcher = sinon.match((content) => {
const json = JSON.parse(content.toString());
t.is(json.reply, undefined);
t.is(json.type, 'error');
t.truthy(json.error);
t.deepEqual(json.error, { name: 'NoSuchProcedure', message: 'No procedure named "oops" has been registered' });
return true;
});
sinon.assert.calledWith(spy, sinon.match.string, sinon.match.string, contentMatcher, sinon.match.any);
});
ava_1.default.serial('[unit] #reply serializes errors according to their own implementation', async (t) => {
t.plan(4);
const spy = t.context.sandbox.spy(amqpClient.channel, 'publish');
const error = new Error('oops');
await comms_1.reply(amqpClient.channel, sampleMessage, new errors_1.ProcedureFailed(error));
const contentMatcher = sinon.match((content) => {
const json = JSON.parse(content.toString());
t.is(json.reply, undefined);
t.is(json.type, 'error');
t.truthy(json.error);
t.deepEqual(json.error, {
name: 'ProcedureFailed',
message: 'Operation failed with error: oops',
cause: {
name: 'Error',
message: 'oops',
stack: error.stack
}
});
return true;
});
sinon.assert.calledWith(spy, sinon.match.string, sinon.match.string, contentMatcher, sinon.match.any);
});