amqplib
Version:
An AMQP 0-9-1 (e.g., RabbitMQ) library and client.
156 lines (132 loc) • 4.87 kB
JavaScript
const { describe, it, afterEach } = require('node:test');
const assert = require('node:assert');
const net = require('node:net');
const connect = require('../lib/connect').connect;
const defs = require('../lib/defs');
const { plain, amqplain } = require('../lib/credentials')
const { latch, runServer } = require('./lib/util');
describe('Connect', () => {
describe('Connect API', () => {
let connection;
afterEach((_t, done) => {
if (connection) connection.close(() => done())
else done();
});
it('Connection refused', (_t, done) => {
connect('amqp://localhost:23450', {}, (err) => {
assert.strictEqual(err.code, 'ECONNREFUSED');
done();
});
});
// %% this ought to fail the promise, rather than throwing an error
it('bad URL', (_t, done) => {
assert.throws(() => connect('blurble'), (err) => {
assert.match(err.message, /Expected amqp: or amqps: as the protocol/);
return true;
});
done();
});
it('wrongly typed open option', (_t, done) => {
connect('amqp://localhost?frameMax=NOT_A_NUMBER', {}, (err) => {
assert.match(err.message, /Field 'frameMax' is the wrong type/);
done();
});
});
it('serverProperties', (_t, done) => {
connect({ protocol: 'amqp', hostname: 'localhost' }, {}, (err, _connection) => {
connection = _connection;
assert.ifError(err);
assert.equal(connection.serverProperties.product, 'RabbitMQ');
done();
});
});
it('using custom heartbeat option', (_t, done) => {
connect({ heartbeat: 20 }, {}, (err, _connection) => {
assert.ifError(err);
connection = _connection;
assert.strictEqual(connection.heartbeat, 20);
done();
});
});
it('wrongly typed heartbeat option', (_t, done) => {
connect('amqp://localhost?heartbeat=NOT_A_NUMBER', {}, (err) => {
assert.match(err.message, /Field 'heartbeat' is the wrong type/);
done();
});
});
it('using plain credentials', (_t, done) => {
connect('amqp://localhost', { credentials: plain('guest', 'guest') }, (err, _connection) => {
assert.ifError(err);
connection = _connection;
done();
});
});
it('using amqplain credentials', (_t, done) => {
connect('amqp://localhost', { credentials: amqplain('guest', 'guest') }, (err, _connection) => {
assert.ifError(err);
connection = _connection;
done();
});
});
it('ipv6', (_t, done) => {
connect('amqp://[::1]', {}, (err, _connection) => {
assert.ifError(err);
connection = _connection;
done();
});
});
it('using unsupported mechanism', (_t, done) => {
const credentials = { mechanism: 'UNSUPPORTED', response: () => Buffer.from('') };
connect('amqp://localhost', { credentials }, (err) => {
assert.match(err.message, /SASL mechanism UNSUPPORTED is not provided by the server/);
done();
});
});
it('with a given connection timeout', (_t, done) => {
const timeoutServer = net.createServer(() => { }).listen(31991);
connect('amqp://localhost:31991', { timeout: 50 }, (err) => {
timeoutServer.close();
assert.match(err.message, /ETIMEDOUT/);
done();
});
});
});
describe('Errors on connect', () => {
let server;
afterEach(() => {
if (server) server.close();
});
it('closes underlying connection on authentication error', (_t, done) => {
const decrementLatch = latch(2, done);
server = net.createServer((socket) => {
socket.once('data', (protocolHeader) => {
assert.deepStrictEqual(protocolHeader, Buffer.from(`AMQP${String.fromCharCode(0, 0, 9, 1)}`));
runServer(socket, (send, wait) => {
send(defs.ConnectionStart, {
versionMajor: 0,
versionMinor: 9,
serverProperties: {},
mechanisms: Buffer.from('PLAIN'),
locales: Buffer.from('en_US'),
});
wait(defs.ConnectionStartOk)().then(() => {
send(defs.ConnectionClose, {
replyCode: 403,
replyText: 'ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN',
classId: 0,
methodId: 0,
});
});
});
});
// Wait for the connection to be closed after the authentication error
socket.once('end', () => decrementLatch());
});
server.listen(0);
connect(`amqp://localhost:${server.address().port}`, {}, (err) => {
assert.match(err.message, /Handshake terminated by server: 403 \(ACCESS-REFUSED\)/);
decrementLatch();
});
});
});
});