UNPKG

mqlight

Version:
528 lines (484 loc) 16.3 kB
/* %Z% %W% %I% %E% %U% */ /* * <copyright * notice="lm-source-program" * pids="5725-P60" * years="2013,2014" * crc="3568777996" > * Licensed Materials - Property of IBM * * 5725-P60 * * (C) Copyright IBM Corp. 2014 * * US Government Users Restricted Rights - Use, duplication or * disclosure restricted by GSA ADP Schedule Contract with * IBM Corp. * </copyright> */ /* jslint node: true */ /* jshint -W083,-W097 */ 'use strict'; /** @const {string} enable unittest mode in mqlight.js */ process.env.NODE_ENV = 'unittest'; var stubproton = require('./stubs/stubproton'); var mqlight = require('../mqlight'); var testCase = require('nodeunit').testCase; /** * Test a calling client.unsubscribe(...) with too few arguments (no arguments) * causes an Error to be thrown. * @param {object} test the unittest interface */ module.exports.test_unsubscribe_too_few_arguments = function(test) { var opts = { id: 'test_unsubscribe_too_few_arguments', service: 'amqp://host' }; var client = mqlight.createClient(opts, function() { test.throws(function() { client.unsubscribe(); }, TypeError); client.stop(function() { test.done(); }); }); }; /** * Test that calling client.unsubscribe(...) with too many arguments results in * the additional arguments being ignored. * @param {object} test the unittest interface */ module.exports.test_unsubscribe_too_many_arguments = function(test) { var opts = { id: 'test_unsubscribe_too_many_arguments', service: 'amqp://host' }; var client = mqlight.createClient(opts, function() { test.doesNotThrow(function() { client.subscribe('/foo', 'share1', function() { client.unsubscribe('/foo', 'share1', {}, function() {}, 'stowaway'); client.stop(function() { test.done(); }); }); }); }); }; /** * Test that the callback argument to client.unsubscribe(...) must be a * function * * @param {object} test the unittest interface */ module.exports.test_unsubscribe_callback_must_be_function = function(test) { var opts = { id: 'test_unsubscribe_callback_must_be_function', service: 'amqp://host' }; var client = mqlight.createClient(opts, function() { test.throws(function() { client.unsubscribe('/foo1', 'share', {}, 7); }, TypeError); test.doesNotThrow(function() { client.subscribe('/foo2', function() { client.unsubscribe('/foo2', function() { client.subscribe('/foo3', 'share', function() { client.unsubscribe('/foo3', 'share', function() { client.subscribe('/foo4', 'share', function() { client.unsubscribe('/foo4', 'share', {}, function() { client.stop(function() { test.done(); }); }); }); }); }); }); }); }); }); }; // /** // * Test that unsubscribe correctly interprets its parameters. This can be // * tricky for two and three parameter invocations where there is the // * potential for ambiguity between what is a share name and what is the // * options object. // * // * @param {object} test the unittest interface // */ // module.exports.test_unsubscribe_parameters = function(test) { // var client; // var service = 'amqp://host:5672'; // var pattern = '/pattern'; // var currentCallbackInvocations = 0; // var expectedCallbackInvocations = 0; // var cb = function() { // ++currentCallbackInvocations; // }; // var share = 'share'; // var object = {}; // var testNum = 0; // // // Data to drive the test with. 'args' is the argument list to pass into // // the unsubscribe function. The 'share', 'object' and 'callback' properties // // indicate the expected interpretation of 'args'. // var data = [{args: [pattern + '0']}, // {args: [pattern + '1', cb], callback: cb}, // {args: [pattern + '2', share], share: share}, // {args: [pattern + '3', object], object: object}, // {args: [pattern + '4', share, cb], share: share, callback: cb}, // {args: [pattern + '5', object, cb], object: object, callback: cb}, // {args: [pattern + '6', share, object], // share: share, object: object}, // {args: [pattern + '7', 7], share: 7}, // {args: [pattern + '8', 'boo'], share: 'boo'}, // {args: [pattern + '9', {}], object: {}}, // {args: [pattern + '10', 7, cb], share: 7, callback: cb}, // {args: [pattern + '11', {}, cb], object: {}, callback: cb}, // {args: [pattern + '12', [], []], share: [], object: []}, // {args: [pattern + '13', share, object, cb], // share: share, object: object, callback: cb}]; // // // Count up the expected number of callback invocations, so the test can // // wait for these to complete. // for (var i = 0; i < data.length; ++i) { // if (data[i].callback) ++expectedCallbackInvocations; // } // // // Replace the messenger unsubscribe method with our own implementation // // that simply records the address that mqlight.js tries to unsubscribe from. // var lastUnsubscribedAddress; // var savedUnsubscribeFunction = stubproton.receiver.detach; // stubproton.receiver.detach = function(address) { // lastUnsubscribedAddress = address; // // var expectedAddress = // // service + '/' + // ((data[testNum].share) ? // ('share:' + data[testNum].share + ':') : 'private:') + // pattern + testNum; // // test.deepEqual(lastUnsubscribedAddress, expectedAddress); // // if (testNum < data.length - 1) { // process.nextTick(function() { // runTests(++testNum); // }); // } else { // // Restore the saved messenger unsubscribe implementation // stubproton.receiver.detach = savedUnsubscribeFunction; // client.stop(); // } // return savedUnsubscribeFunction(); // }; // // var runTests = function(i) { // var clientUnsubscribeMethod = client.unsubscribe; // var clientSubscribeMethod = client.subscribe; // lastUnsubscribedAddress = undefined; // clientSubscribeMethod.apply(client, [pattern + i, // ('share' in data[i]) ? data[i].args[1] : undefined, {}, function() { // clientUnsubscribeMethod.apply(client, data[i].args); // }] // ); // }; // // client = mqlight.createClient({ // id: 'test_unsubscribe_parameters', // service: service // }, function() { // runTests(testNum); // }); // // // Callbacks passed into unsubscribe(...) are scheduled to be run once // // outside of the main loop - so use setImmediate(...) to schedule checking // // for test completion. // var testIsDone = function() { // if (currentCallbackInvocations === expectedCallbackInvocations) { // test.done(); // } else { // setImmediate(testIsDone); // } // }; // testIsDone(); // }; /** * Test that the callback (invoked when the unsubscribe operation completes * successfully) specifies the right number of arguments, and is invoked with * 'this' set to reference the client that the corresponding invocation of * unsubscribe(...) was made against. * @param {object} test the unittest interface */ module.exports.test_unsubscribe_ok_callback = function(test) { var client = mqlight.createClient({ id: 'test_unsubscribe_ok_callback', service: 'amqp://host' }); client.on('started', function() { client.subscribe('/foo', function() { client.unsubscribe('/foo', function() { test.equals(arguments.length, 3); test.deepEqual(arguments[0], null); // error argument test.deepEqual(arguments[1], '/foo'); // topic pattern argument test.deepEqual(arguments[2], undefined); // share argument test.ok(this === client); client.subscribe('/foo2', 'share', function() { client.unsubscribe('/foo2', 'share', function() { test.equals(arguments.length, 3); test.deepEqual(arguments[0], null); // error argument test.deepEqual(arguments[1], '/foo2'); // topic pattern argument test.deepEqual(arguments[2], 'share'); // share argument test.ok(this === client); client.stop(); }); }); }); }); }); client.on('stopped', test.done); }; /** * Test that trying to remove a subscription, while the client is in * stopped state, throws an Error. * * @param {object} test the unittest interface */ module.exports.test_unsubscribe_when_stopped = function(test) { var client = mqlight.createClient({id: 'test_unsubscribe_when_stopped', service: 'amqp://host'}); client.stop(); client.on('stopped', function() { test.throws(function() { client.unsubscribe('/foo'); }, mqlight.StoppedError); test.done(); }); }; /** * Test that trying to remove a subscription that does not exist throws an * Error. * * @param {object} test the unittest interface */ module.exports.test_unsubscribe_when_not_subscribed = function(test) { var client = mqlight.createClient({ id : 'test_unsubscribe_when_not_subscribed', service : 'amqp://host'}); client.on('started', function() { client.subscribe('/bar'); test.throws(function() { client.unsubscribe('/foo'); }, mqlight.UnsubscribedError); client.stop(test.done); }); }; /** * Test that calling the unsubscribe(...) method returns, as a value, the * client object that the method was invoked on (for method chaining purposes). * * @param {object} test the unittest interface */ module.exports.test_unsubscribe_returns_client = function(test) { var client = mqlight.createClient({id: 'test_unsubscribe_returns_client', service: 'amqp://host'}, function() { client.subscribe('/foo', function() { test.deepEqual(client.unsubscribe('/foo'), client); client.stop(function(){ test.done(); }); }); }); }; /** * Test a variety of valid and invalid patterns. Invalid patterns * should result in the client.unsubscribe(...) method throwing a TypeError. * @param {object} test the unittest interface */ module.exports.test_unsubscribe_topics = function(test) { var data = [{valid: false, pattern: ''}, {valid: false, pattern: undefined}, {valid: false, pattern: null}, {valid: true, pattern: 1234}, {valid: true, pattern: function() {}}, {valid: true, pattern: 'kittens'}, {valid: true, pattern: '/kittens'}, {valid: true, pattern: '+'}, {valid: true, pattern: '#'}, {valid: true, pattern: '/#'}, {valid: true, pattern: '/+'}]; var client = mqlight.createClient({id: 'test_unsubscribe_topics', service: 'amqp://host'}); var runTests = function (i) { if (i === data.length) { client.stop(function(){ test.done(); }); return; } if (data[i].valid) { test.doesNotThrow(function() { client.subscribe(data[i].pattern, function() { client.unsubscribe(data[i].pattern, function() { runTests(i + 1); }); }); }); } else { test.throws(function() { client.unsubscribe(data[i].pattern); }, TypeError, 'pattern should have been rejected: ' + data[i].pattern); runTests(i + 1); } }; client.once('started', function() { runTests(0); }); }; /** * Tests a variety of valid and invalid share names to check that they are * accepted or rejected (by throwing an Error) as appropriate. * @param {object} test the unittest interface */ module.exports.test_unsubscribe_share_names = function(test) { var data = [{valid: true, share: 'abc'}, {valid: true, share: 7}, {valid: false, share: ':'}, {valid: false, share: 'a:'}, {valid: false, share: ':a'}]; var client = mqlight.createClient({ id: 'test_unsubscribe_share_names', service: 'amqp://host' }); var runTests = function(i) { if (i === data.length) { client.stop(function() { test.done(); }); return; } if (data[i].valid) { test.doesNotThrow(function() { client.subscribe('/foo', data[i].share, function() { client.unsubscribe('/foo', data[i].share, function() { runTests(i + 1); }); }); }); } else { test.throws(function() { client.unsubscribe('/foo', data[i].share); }, mqlight.InvalidArgumentError, i); runTests(i + 1); } }; client.on('started', function() { runTests(0); }); }; /** * Test a variety of valid and invalid options values. Invalid options * should result in the client.unsubscribe(...) method throwing a TypeError. * <p> * Note that this test just checks that the options parameter is only * accepted when it is of the correct type. The actual validation of * individual options will be in separate tests. * @param {object} test the unittest interface */ module.exports.test_unsubscribe_options = function(test) { var data = [{valid: false, options: ''}, {valid: true, options: undefined}, {valid: true, options: null}, {valid: false, options: function() {}}, {valid: false, options: '1'}, {valid: false, options: 2}, {valid: false, options: true}, {valid: true, options: {}}, {valid: true, options: data}, {valid: true, options: { a: 1 } }]; var client = mqlight.createClient({id: 'test_unsubscribe_options', service: 'amqp://host'}); var runTests = function(i) { if (i === data.length) { client.stop(function() { test.done(); }); return; } if (data[i].valid) { test.doesNotThrow( function() { client.subscribe('testpattern', 'share', function() { client.unsubscribe('testpattern', 'share', data[i].options, function() { runTests(i + 1); }); }); } ); } else { test.throws( function() { client.unsubscribe('testpattern', 'share', data[i].options, function() {}); }, TypeError, 'options should have been rejected: ' + data[i].options ); runTests(i + 1); } }; client.on('started', function() { runTests(0); }); }; /** * Test a variety of valid and invalid ttl options. Invalid ttl values should * result in the client.unsubscribe(...) method throwing a TypeError. * * @param {object} test the unittest interface */ module.exports.test_unsubscribe_ttl_validity = function(test) { var data = [ {valid: false, ttl: undefined}, {valid: false, ttl: function() {}}, {valid: false, ttl: -9007199254740992}, {valid: false, ttl: -NaN}, {valid: false, ttl: NaN}, {valid: false, ttl: -Infinity}, {valid: false, ttl: Infinity}, {valid: false, ttl: -1}, {valid: false, ttl: 1}, {valid: false, ttl: 9007199254740992}, {valid: true, ttl: 0}, {valid: true, ttl: null}, // treated as 0 {valid: true, ttl: ''} // treated as 0 ]; var client = mqlight.createClient({id: 'test_unsubscribe_ttl_validity', service: 'amqp://host'}); var runTests = function(i) { if (i === data.length) { client.stop(function() { test.done(); }); return; } var opts = { ttl: data[i].ttl }; if (data[i].valid) { test.doesNotThrow(function() { client.subscribe('testpattern', function() { client.unsubscribe('testpattern', opts, function() { runTests(i + 1); }); }); }); } else { test.throws(function() { client.unsubscribe('testpattern', opts); }, RangeError, 'ttl should have been rejected: ' + data[i].ttl); runTests(i + 1); } }; client.on('started', function() { runTests(0); }); };