UNPKG

stompit

Version:

STOMP client library for node.js

361 lines (277 loc) 12.4 kB
/*jslint node: true, indent: 2, camelcase: true, esversion: 9 */ const { ConnectFailover } = require('../lib/index'); const parseFailoverUri = require('../lib/connect-failover/parseFailoverUri'); const parseServerUri = require('../lib/connect-failover/parseServerUri'); const MemorySocket = require('../lib/util/MemorySocket'); const Server = require('../lib/Server'); const assert = require('assert'); var createConnector = function(name, options) { options = options || {}; var connector = { name: name, connects: 0, connectAfter: options.connectAfter || 0, connectError: options.connectError, failAfter: options.failAfter || Infinity }; var connect = function(options, callback) { connector.connects += 1; var serverSocket = new MemorySocket(); var server = new Server(serverSocket); if (options.connectError) { server.setCommandHandler("CONNECT", function() { server.sendError(options.connectError).end(); }); server.on('error', function(){}); } var socket = serverSocket.getPeerSocket(); socket.connectOptions = options; var error; if (connector.connects < connector.connectAfter || connector.connects >= connector.failAfter) { error = new Error('unable to connect'); } process.nextTick(function() { if (error) { socket.emit('error', error); } else { callback(); } }); return socket; }; connector.connect = connect; return connector; }; var getConnectorName = function(client) { return client.getTransportSocket().connectOptions.name; }; var createBrokenConnector = function(connectAfterFailedAttempts) { return createConnector(null, { connectAfter: connectAfterFailedAttempts }); }; var defaultOptions = { initialReconnectDelay: 10, maxReconnectDelay: 1500, useExponentialBackOff: true, reconnectDelayExponent: 2.0, maxReconnects: -1, randomize: true }; describe('ConnectFailover', function() { describe('#connect', function() { it('should connect to the primary server first', function(done) { var failover = new ConnectFailover([ createConnector('primary'), createConnector('secondary') ], defaultOptions); failover.connect(function(error, client) { assert(!error); assert(getConnectorName(client) === 'primary'); done(); }); }); it('should reconnect', function(done) { var failover = new ConnectFailover([ createConnector(), createConnector() ], defaultOptions); var lastClient = null; failover.connect(function(error, client, reconnect) { if (lastClient !== null) { assert(lastClient !== client); done(); return; } lastClient = client; reconnect(); }); }); it('should reconnect to the next server', function(done) { var failover = new ConnectFailover([ createConnector(0), createConnector(1), createConnector(2) ], Object.assign(defaultOptions, { randomize: false })); var index = 0; var maxIndex = 2; failover.connect(function(error, client, reconnect) { assert(!error); assert(getConnectorName(client) == index); index += 1; if (index == maxIndex) { done(); return; } reconnect(); }); }); it('should stop reconnecting after 3 failed connects for each server', function(done) { var servers = [ createConnector(1, { connectAfter: Infinity }), createConnector(2, { connectAfter: Infinity }) ]; var failover = new ConnectFailover(servers, Object.assign(defaultOptions, { maxReconnects: 3, useExponentialBackOff: false, initialReconnectDelay: 1 })); var connects = 0; failover.connect(function(error, client, reconnect) { assert(error); assert.equal(servers[0].connects, 3); assert.equal(servers[1].connects, 3); done(); }); }); it('should connect after 8 failed attempts', function(done) { var failover = new ConnectFailover([ createConnector(null, { connectAfter: 8 }) ], Object.assign(defaultOptions, { maxReconnects: -1, initialReconnectDelay: 1, useExponentialBackOff: false })); failover.connect(function(error, client) { assert(!error); done(); }); }); it('should give up trying to connect after a number of failed attempts', function(done) { var failover = new ConnectFailover([ createConnector(null, { connectAfter: Infinity }) ], Object.assign(defaultOptions, { maxReconnects: 2, initialReconnectDelay: 1, useExponentialBackOff: false })); failover.connect(function(error, client) { assert(error); done(); }); }); it('should give up on application connect error', function(done) { var failover = new ConnectFailover([ createConnector(null, { connectError: 'invalid login' }) ], Object.assign(defaultOptions, { maxReconnects: -1 })); failover.connect(function(error, client) { assert(error); done(); }); }); }); describe("#_parseConnectFailoverUri", function() { var parse = parseFailoverUri; it('should parse a simple uri', function() { var ret = parse('failover:(primary,secondary)'); assert(typeof ret === 'object'); assert(ret.servers.length === 2); assert(ret.servers[0] === 'primary'); assert(ret.servers[1] === 'secondary'); }); it('should parse a server list', function() { var ret = parse('primary,secondary'); assert(typeof ret === 'object'); assert(ret.servers.length === 2); assert(ret.servers[0] === 'primary'); assert(ret.servers[1] === 'secondary'); }); it('should parse query string', function() { var ret = parse('failover:(primary)?var1=val1&var2=val2'); assert(typeof ret === 'object'); assert(typeof ret.options === 'object'); assert(ret.options.var1 === 'val1'); assert(ret.options.var2 === 'val2'); }); it('parse query string variable into string', function() { var ret = parse('failover:(primary)?var1=1,2'); assert(ret.options.var1 === '1,2'); }); it('should accept an empty query string', function() { var ret = parse('failover:(primary)?'); assert(ret.servers.length === 1 && ret.servers[0] === 'primary'); }); it('should cast values of known options', function() { var ret = parse('failover:(primary)?initialReconnectDelay=10&maxReconnectDelay=30000&useExponentialBackOff=true&maxReconnects=-1&randomize=true'); assert(ret.options.initialReconnectDelay === 10); assert(ret.options.maxReconnectDelay === 30000); assert(ret.options.useExponentialBackOff === true); assert(ret.options.maxReconnects === -1); assert(ret.options.randomize === true); assert(parse('failover:(primary)?randomize=TRUE').options.randomize === true); assert(parse('failover:(primary)?randomize=1').options.randomize === true); assert(parse('failover:(primary)?randomize=FALSE').options.randomize === false); assert(parse('failover:(primary)?randomize=0').options.randomize === false); }); it('should throw an error for invalid values of known options', function() { var expectParseError = function(source) { var thrown = false; try{ parse(source); }catch(e) { thrown = true; } assert(thrown); }; expectParseError('failover:(sasf)?initialReconnectDelay=zvxvsdf'); expectParseError('failover:(sasf)?initialReconnectDelay=-2'); expectParseError('failover:(sasf)?maxReconnectDelay=asdf'); expectParseError('failover:(sasf)?maxReconnectDelay=-34'); expectParseError('failover:(sasf)?useExponentialBackOff=asdf'); expectParseError('failover:(sasf)?maxReconnects=asdf'); expectParseError('failover:(sasf)?maxReconnects=-34'); expectParseError('failover:(sasf)?randomize=asdf'); }); }); describe('#_parseServerUri', function() { var parse = parseServerUri; it('should parse a typical uri', function() { var ret = parse('tcp://localhost:61613'); assert(typeof ret === 'object'); assert(ret.host === 'localhost'); assert(ret.port === 61613); }); it('should parse without a scheme', function() { var ret = parse('localhost:1234'); assert(typeof ret === 'object'); assert(ret.host === 'localhost'); assert(ret.port === 1234); }); it('should parse without a port', function() { var ret = parse('localhost'); assert(ret.host === 'localhost'); assert(ret.port === void 0); }); it('should parse login and passcode', function() { var ret = parse('user:pass@localhost:123'); assert(ret.connectHeaders.login === 'user'); assert(ret.connectHeaders.passcode === 'pass'); assert(ret.host === 'localhost'); assert(ret.port === 123); ret = parse('tcp://user:pass@localhost'); assert(ret.connectHeaders.login === 'user'); assert(ret.connectHeaders.passcode === 'pass'); assert(ret.host === 'localhost'); assert(ret.port === void 0); }); it('should ignore leading and trailing whitespace', function() { assert(parse(' localhost \t').host === 'localhost'); }); }); });