@gasbuddy/configured-rabbitmq-client
Version:
A configuration driven RabbitMQ client
174 lines (159 loc) • 5.21 kB
JavaScript
import tap from 'tap';
import net from 'net';
import bluebird from 'bluebird';
import RabbitMQClient from '../src/index';
const mqConfig = {
hostname: process.env.RABBIT_HOST || 'rabbitmq',
port: process.env.RABBIT_PORT || 5672,
username: process.env.RABBIT_USER || 'guest',
password: process.env.RABBIT_PASSWORD || 'guest',
logging: {
level: 2,
},
};
function configWithExchangeGroups(exchangeGroups) {
return {
...mqConfig,
config: {
exchangeGroups,
},
};
}
const ctx = { logger: console };
tap.test('wait for rabbit', async (t) => {
for (let i = 0; i < 10; i += 1) {
let connected = false;
// eslint-disable-next-line no-await-in-loop
await new Promise((accept) => {
const s = new net.Socket();
s.once('error', () => {
if (!connected) {
t.ok(true, `Waiting for RabbitMQ response from ${mqConfig.hostname}:${mqConfig.port}`);
setTimeout(accept, 2500);
}
});
s.connect({
host: mqConfig.hostname,
port: mqConfig.port,
}, () => {
connected = true;
s.end();
setTimeout(accept, 2500);
});
});
if (connected) {
t.ok(true, `RabbitMQ found on ${mqConfig.host}:${mqConfig.port}`);
return;
}
}
t.fail('Could not connect to RabbitMQ');
});
tap.test('test exchange group retry', async (t) => {
const retryCount = 5;
t.plan((retryCount + 3) + retryCount);
const mq = new RabbitMQClient(ctx, configWithExchangeGroups({
test: {
retries: retryCount,
retryDelay: 250,
keys: 'testkey',
},
}));
await mq.start(ctx);
let counter = 0;
const errorMessage = 'retry again';
await new Promise(async (accept) => {
await mq.subscribe('test', 'testkey',
async (context, message) => {
if (counter > 0) {
t.equal(message.properties.headers.error, errorMessage, 'Previous error message is written to message headers');
} else {
t.equal(RabbitMQClient.activeMessages.size, 1, 'Should have 1 active message');
}
counter += 1;
t.ok(true, `Recieved messsage for the ${counter} time.`);
if (counter === retryCount + 1) {
await message.ack();
accept();
}
throw new Error(errorMessage);
});
await mq.publish('test', 'testkey', {});
}).then(async () => {
t.equal(RabbitMQClient.activeMessages.size, 0, 'Should have 0 active message');
await mq.stop(ctx);
});
});
tap.test('test routing key reuse', async (t) => {
const mq = new RabbitMQClient(ctx, configWithExchangeGroups({
one: {
keys: 'number',
},
two: {
keys: 'number',
},
}));
await mq.start(ctx);
let receivedOne = 0;
let receivedTwo = 0;
await (async () => {
await mq.subscribe('one', 'number', async (context, message) => {
receivedOne += 1;
await message.ack();
});
await mq.subscribe('two', 'number', async (context, message) => {
receivedTwo += 1;
await message.ack();
});
await mq.publish('one', 'number', {});
await mq.publish('two', 'number', {});
await mq.publish('two', 'number', {});
await bluebird.delay(250);
})();
t.strictEqual(receivedOne, 1, 'Should have received exactly one message on the one handler.');
t.strictEqual(receivedTwo, 2, 'Should have received exactly two messages on the two handler.');
await mq.stop(ctx);
});
tap.test('test delivery_mode pass thru', async (t) => {
const retryCount = 2;
const retryDelay = 380;
const mq = new RabbitMQClient(ctx, configWithExchangeGroups({
persistent: {
retries: retryCount,
retryDelay,
persistent: true,
perMessageTtl: true,
keys: 'one',
},
}));
await mq.start(ctx);
let lastMsgDelivery = null;
await new Promise(async (accept) => {
await mq.subscribe('persistent', 'one',
async (context, message) => {
const deliveryTime = (new Date()).getTime();
if (!message.properties.headers.retryCount) {
t.strictEqual(message.properties.deliveryMode, 2, 'Persistent message should have deliveryMode=2');
} else {
const deliveryDelay = deliveryTime - lastMsgDelivery;
t.ok(deliveryDelay >= retryDelay && deliveryDelay < retryDelay + 10, 'Retry delivery should respect retryDelay within a margin of 10ms');
t.strictEqual(message.properties.deliveryMode, 2, 'Persistent message retries should retain deliveryMode=2');
}
lastMsgDelivery = deliveryTime;
throw new Error('error');
});
const failTimeout = setTimeout(() => {
t.ok(false, 'Should have a message in the rejected queue after 5s');
accept();
}, 5000);
await mq.subscribe('persistent.rejected.q', 'one',
async (context, message) => {
t.strictEqual(message.properties.deliveryMode, 2, 'Rejected persistent message should retain deliveryMode=2');
message.ack();
clearTimeout(failTimeout);
accept();
});
await mq.publish('persistent', 'one', {});
});
t.equal(RabbitMQClient.activeMessages.size, 0, 'Should have 0 active message');
await mq.stop(ctx);
});