diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..cf846143 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +node_modules/** +reports/** +.eslintrc.js \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..9ebc48d1 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,290 @@ +module.exports = { + "env": { + "node": true + }, + "extends": "eslint:recommended", + "rules": { + "accessor-pairs": "error", + "array-bracket-spacing": [ + "error", + "never" + ], + "array-callback-return": "error", + "arrow-body-style": "error", + "arrow-parens": "error", + "arrow-spacing": "error", + "block-scoped-var": "off", + "block-spacing": [ + "error", + "always" + ], + "brace-style": [ + "error", + "1tbs", + { + "allowSingleLine": true + } + ], + "callback-return": "off", + "camelcase": "off", + "capitalized-comments": "off", + "class-methods-use-this": "error", + "comma-dangle": "off", + "comma-spacing": [ + "error", + { + "after": true, + "before": false + } + ], + "comma-style": [ + "error", + "last" + ], + "complexity": "off", + "computed-property-spacing": [ + "error", + "never" + ], + "consistent-return": "off", + "consistent-this": "off", + "curly": "error", + "default-case": "off", + "dot-location": "error", + "dot-notation": "error", + "eol-last": "error", + "eqeqeq": "off", + "func-call-spacing": "error", + "func-name-matching": "error", + "func-names": [ + "error", + "never" + ], + "func-style": "off", + "generator-star-spacing": "error", + "global-require": "error", + "guard-for-in": "off", + "handle-callback-err": "error", + "id-blacklist": "error", + "id-length": "off", + "id-match": "error", + "indent": "off", + "init-declarations": "off", + "jsx-quotes": "error", + "key-spacing": "off", + "keyword-spacing": "off", + "line-comment-position": "off", + "linebreak-style": [ + "error", + "unix" + ], + "lines-around-comment": "error", + "lines-around-directive": "off", + "max-depth": "off", + "max-len": "off", + "max-lines": "off", + "max-nested-callbacks": "error", + "max-params": "off", + "max-statements": "off", + "max-statements-per-line": "off", + "multiline-ternary": [ + "error", + "never" + ], + "new-cap": "error", + "new-parens": "error", + "newline-after-var": "off", + "newline-before-return": "off", + "newline-per-chained-call": "error", + "no-alert": "error", + "no-array-constructor": "error", + "no-await-in-loop": "error", + "no-bitwise": "error", + "no-caller": "error", + "no-catch-shadow": "error", + "no-compare-neg-zero": "error", + "no-cond-assign": [ + "error", + "except-parens" + ], + "no-confusing-arrow": "error", + "no-continue": "error", + "no-div-regex": "error", + "no-duplicate-imports": "error", + "no-else-return": "off", + "no-empty-function": "error", + "no-eq-null": "error", + "no-eval": "error", + "no-extend-native": "error", + "no-extra-bind": "error", + "no-extra-label": "error", + "no-extra-parens": "off", + "no-floating-decimal": "error", + "no-implicit-globals": "error", + "no-implied-eval": "error", + "no-inline-comments": "off", + "no-inner-declarations": [ + "error", + "functions" + ], + "no-invalid-this": "error", + "no-iterator": "error", + "no-label-var": "error", + "no-labels": "error", + "no-lone-blocks": "error", + "no-lonely-if": "off", + "no-loop-func": "off", + "no-magic-numbers": "off", + "no-mixed-operators": "error", + "no-mixed-requires": "error", + "no-multi-assign": "off", + "no-multi-spaces": "off", + "no-multi-str": "error", + "no-multiple-empty-lines": "error", + "no-native-reassign": "error", + "no-negated-condition": "off", + "no-negated-in-lhs": "error", + "no-nested-ternary": "error", + "no-new": "error", + "no-new-func": "error", + "no-new-object": "error", + "no-new-require": "error", + "no-new-wrappers": "error", + "no-octal-escape": "error", + "no-param-reassign": "off", + "no-path-concat": "error", + "no-plusplus": "off", + "no-process-env": "error", + "no-process-exit": "error", + "no-proto": "error", + "no-prototype-builtins": "off", + "no-restricted-globals": "error", + "no-restricted-imports": "error", + "no-restricted-modules": "error", + "no-restricted-properties": "error", + "no-restricted-syntax": "error", + "no-return-assign": "error", + "no-return-await": "error", + "no-script-url": "error", + "no-self-compare": "error", + "no-sequences": "error", + "no-shadow": "off", + "no-shadow-restricted-names": "error", + "no-spaced-func": "error", + "no-sync": "error", + "no-tabs": "off", + "no-template-curly-in-string": "error", + "no-ternary": "off", + "no-throw-literal": "error", + "no-trailing-spaces": [ + "error", + { + "skipBlankLines": true + } + ], + "no-undef-init": "error", + "no-undefined": "off", + "no-underscore-dangle": "error", + "no-unmodified-loop-condition": "error", + "no-unneeded-ternary": "error", + "no-unused-expressions": "error", + "no-unused-vars": [ + "error", + { + "args": "none" + } + ], + "no-use-before-define": "off", + "no-useless-call": "error", + "no-useless-computed-key": "error", + "no-useless-concat": "error", + "no-useless-constructor": "error", + "no-useless-escape": "error", + "no-useless-rename": "error", + "no-useless-return": "error", + "no-var": "off", + "no-void": "error", + "no-warning-comments": "off", + "no-whitespace-before-property": "error", + "no-with": "error", + "nonblock-statement-body-position": "error", + "object-curly-newline": "off", + "object-curly-spacing": "off", + "object-property-newline": [ + "error", + { + "allowMultiplePropertiesPerLine": true + } + ], + "object-shorthand": "off", + "one-var": "off", + "one-var-declaration-per-line": [ + "error", + "initializations" + ], + "operator-assignment": [ + "error", + "always" + ], + "operator-linebreak": "error", + "padded-blocks": "off", + "prefer-arrow-callback": "off", + "prefer-const": "error", + "prefer-destructuring": [ + "error", + { + "array": false, + "object": false + } + ], + "prefer-numeric-literals": "error", + "prefer-promise-reject-errors": "error", + "prefer-reflect": "off", + "prefer-rest-params": "error", + "prefer-spread": "error", + "prefer-template": "off", + "quote-props": "off", + "quotes": "off", + "radix": [ + "error", + "always" + ], + "require-await": "error", + "require-jsdoc": "off", + "rest-spread-spacing": "error", + "semi": "error", + "semi-spacing": [ + "error", + { + "after": true, + "before": false + } + ], + "sort-imports": "error", + "sort-keys": "off", + "sort-vars": "off", + "space-before-blocks": "off", + "space-before-function-paren": "off", + "space-in-parens": [ + "error", + "never" + ], + "space-infix-ops": "off", + "space-unary-ops": "error", + "spaced-comment": "off", + "strict": "error", + "symbol-description": "error", + "template-curly-spacing": "error", + "template-tag-spacing": "error", + "unicode-bom": [ + "error", + "never" + ], + "valid-jsdoc": "off", + "vars-on-top": "off", + "wrap-iife": "error", + "wrap-regex": "error", + "yield-star-spacing": "error", + "yoda": "off" + } +}; \ No newline at end of file diff --git a/.npmignore b/.npmignore index 552f1971..a69cffb1 100644 --- a/.npmignore +++ b/.npmignore @@ -21,5 +21,8 @@ examples/ test/ .istanbul.yml .travis.yml +.eslintrc.js +.eslintignore +crockford.jscsrc Makefile TODO diff --git a/Makefile b/Makefile index 647d9a9c..76579c88 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ lint: - ./node_modules/.bin/jshint ./test ./index.js ./lib/nats.js + ./node_modules/.bin/eslint ./test ./lib/nats.js ./examples ./benchmark test: @NODE_ENV=test ./node_modules/.bin/mocha -c\ diff --git a/benchmark/.eslintrc b/benchmark/.eslintrc new file mode 100644 index 00000000..d824037a --- /dev/null +++ b/benchmark/.eslintrc @@ -0,0 +1,6 @@ +{ + "rules": { + "no-process-exit": "off", + "no-console": "off" + } +} \ No newline at end of file diff --git a/benchmark/pub_perf.js b/benchmark/pub_perf.js index a79e8403..0b2e4268 100644 --- a/benchmark/pub_perf.js +++ b/benchmark/pub_perf.js @@ -1,3 +1,4 @@ +"use strict"; var nats = require('../lib/nats').connect(); @@ -12,23 +13,23 @@ console.log('Publish Performance Test'); nats.on('connect', function() { - var start = new Date(); + var start = new Date(); - var invalid2octet = new Buffer('\xc3\x28', 'binary'); + var invalid2octet = new Buffer('\xc3\x28', 'binary'); - for (var i=0; i [msg]'); - process.exit(); + console.log('Usage: node-pub [msg]'); + process.exit(); } nats.publish(subject, msg, function() { - console.log('Published [' + subject + '] : "' + msg + '"'); - process.exit(); + console.log('Published [' + subject + '] : "' + msg + '"'); + process.exit(); }); diff --git a/examples/node-sub b/examples/node-sub index 52f7c56b..8fd99606 100755 --- a/examples/node-sub +++ b/examples/node-sub @@ -3,27 +3,27 @@ /* jslint node: true */ 'use strict'; -var nats = require ('nats').connect(); +var nats = require('nats').connect(); nats.on('error', function(e) { - console.log('Error [' + nats.options.url + ']: ' + e); - process.exit(); + console.log('Error [' + nats.options.url + ']: ' + e); + process.exit(); }); nats.on('close', function() { - console.log('CLOSED'); - process.exit(); + console.log('CLOSED'); + process.exit(); }); var subject = process.argv[2]; if (!subject) { - console.log('Usage: node-sub '); - process.exit(); + console.log('Usage: node-sub '); + process.exit(); } console.log('Listening on [' + subject + ']'); nats.subscribe(subject, function(msg) { - console.log('Received "' + msg + '"'); + console.log('Received "' + msg + '"'); }); diff --git a/lib/nats.js b/lib/nats.js index 77299098..85720e6c 100644 --- a/lib/nats.js +++ b/lib/nats.js @@ -11,23 +11,21 @@ /** * Module Dependencies */ - -var net = require('net'), - tls = require('tls'), - url = require('url'), - util = require('util'), +var net = require('net'), + tls = require('tls'), + url = require('url'), + util = require('util'), events = require('events'), - nuid = require('nuid'); + nuid = require('nuid'); /** * Constants */ - var VERSION = '0.7.20', DEFAULT_PORT = 4222, - DEFAULT_PRE = 'nats://localhost:', - DEFAULT_URI = DEFAULT_PRE + DEFAULT_PORT, + DEFAULT_PRE = 'nats://localhost:', + DEFAULT_URI = DEFAULT_PRE + DEFAULT_PORT, MAX_CONTROL_LINE_SIZE = 512, @@ -36,18 +34,18 @@ var VERSION = '0.7.20', AWAITING_MSG_PAYLOAD = 1, // Reconnect Parameters, 2 sec wait, 10 tries - DEFAULT_RECONNECT_TIME_WAIT = 2*1000, + DEFAULT_RECONNECT_TIME_WAIT = 2 * 1000, DEFAULT_MAX_RECONNECT_ATTEMPTS = 10, // Protocol //CONTROL_LINE = /^(.*)\r\n/, // TODO: remove / never used - MSG = /^MSG\s+([^\s\r\n]+)\s+([^\s\r\n]+)\s+(([^\s\r\n]+)[^\S\r\n]+)?(\d+)\r\n/i, - OK = /^\+OK\s*\r\n/i, - ERR = /^-ERR\s+('.+')?\r\n/i, - PING = /^PING\r\n/i, - PONG = /^PONG\r\n/i, - INFO = /^INFO\s+([^\r\n]+)\r\n/i, + MSG = /^MSG\s+([^\s\r\n]+)\s+([^\s\r\n]+)\s+(([^\s\r\n]+)[^\S\r\n]+)?(\d+)\r\n/i, + OK = /^\+OK\s*\r\n/i, + ERR = /^-ERR\s+('.+')?\r\n/i, + PING = /^PING\r\n/i, + PONG = /^PONG\r\n/i, + INFO = /^INFO\s+([^\r\n]+)\r\n/i, SUBRE = /^SUB\s+([^\r\n]+)\r\n/i, CR_LF = '\r\n', @@ -57,12 +55,12 @@ var VERSION = '0.7.20', // Protocol //PUB = 'PUB', // TODO: remove / never used - SUB = 'SUB', - UNSUB = 'UNSUB', + SUB = 'SUB', + UNSUB = 'UNSUB', CONNECT = 'CONNECT', // Responses - PING_REQUEST = 'PING' + CR_LF, + PING_REQUEST = 'PING' + CR_LF, PONG_RESPONSE = 'PONG' + CR_LF, // Errors @@ -101,16 +99,16 @@ var VERSION = '0.7.20', FLUSH_THRESHOLD = 65536; - function NatsError(message, code, chainedError) { +function NatsError(message, code, chainedError) { Error.captureStackTrace(this, this.constructor); this.name = this.constructor.name; this.message = message; this.code = code; this.chainedError = chainedError; - } +} - util.inherits(NatsError, Error); - exports.NatsError = NatsError; +util.inherits(NatsError, Error); +exports.NatsError = NatsError; /** * Library Version @@ -138,10 +136,9 @@ exports.REQ_TIMEOUT = REQ_TIMEOUT; * Create a properly formatted inbox subject. * * @api public -*/ - + */ var createInbox = exports.createInbox = function() { - return ("_INBOX." + nuid.next()); + return ("_INBOX." + nuid.next()); }; /** @@ -150,12 +147,11 @@ var createInbox = exports.createInbox = function() { * @param {Mixed} opts * @api public */ - function Client(opts) { - events.EventEmitter.call(this); - this.parseOptions(opts); - this.initState(); - this.createConnection(); + events.EventEmitter.call(this); + this.parseOptions(opts); + this.initState(); + this.createConnection(); } /** @@ -167,15 +163,13 @@ function Client(opts) { * * @api public */ - exports.connect = function(opts) { - return new Client(opts); + return new Client(opts); }; /** * Connected clients are event emitters. */ - util.inherits(Client, events.EventEmitter); /** @@ -183,26 +177,25 @@ util.inherits(Client, events.EventEmitter); * * @api public */ - Client.prototype.createInbox = createInbox; Client.prototype.assignOption = function(opts, prop, assign) { - if (assign === undefined) { - assign = prop; - } - if (opts[prop] !== undefined) { - this.options[assign] = opts[prop]; - } + if (assign === undefined) { + assign = prop; + } + if (opts[prop] !== undefined) { + this.options[assign] = opts[prop]; + } }; function shuffle(array) { - for (var i = array.length - 1; i > 0; i--) { - var j = Math.floor(Math.random() * (i + 1)); - var temp = array[i]; - array[i] = array[j]; - array[j] = temp; - } - return array; + for (var i = array.length - 1; i > 0; i--) { + var j = Math.floor(Math.random() * (i + 1)); + var temp = array[i]; + array[i] = array[j]; + array[j] = temp; + } + return array; } /** @@ -211,107 +204,105 @@ function shuffle(array) { * @param {Mixed} opts * @api private */ - Client.prototype.parseOptions = function(opts) { - var options = this.options = { - 'verbose' : false, - 'pedantic' : false, - 'reconnect' : true, - 'maxReconnectAttempts' : DEFAULT_MAX_RECONNECT_ATTEMPTS, - 'reconnectTimeWait' : DEFAULT_RECONNECT_TIME_WAIT, - 'encoding' : 'utf8', - 'tls' : false, - 'waitOnFirstConnect' : false, - }; - - if (undefined === opts) { - options.url = DEFAULT_URI; - } else if ('number' === typeof opts) { - options.url = DEFAULT_PRE + opts; - } else if ('string' === typeof opts) { - options.url = opts; - } else if ('object' === typeof opts) { - if (opts.port !== undefined) { - options.url = DEFAULT_PRE + opts.port; + var options = this.options = { + 'verbose': false, + 'pedantic': false, + 'reconnect': true, + 'maxReconnectAttempts': DEFAULT_MAX_RECONNECT_ATTEMPTS, + 'reconnectTimeWait': DEFAULT_RECONNECT_TIME_WAIT, + 'encoding': 'utf8', + 'tls': false, + 'waitOnFirstConnect': false, + }; + + if (undefined === opts) { + options.url = DEFAULT_URI; + } else if ('number' === typeof opts) { + options.url = DEFAULT_PRE + opts; + } else if ('string' === typeof opts) { + options.url = opts; + } else if ('object' === typeof opts) { + if (opts.port !== undefined) { + options.url = DEFAULT_PRE + opts.port; + } + // Pull out various options here + this.assignOption(opts, 'url'); + this.assignOption(opts, 'uri', 'url'); + this.assignOption(opts, 'user'); + this.assignOption(opts, 'pass'); + this.assignOption(opts, 'token'); + this.assignOption(opts, 'password', 'pass'); + this.assignOption(opts, 'verbose'); + this.assignOption(opts, 'pedantic'); + this.assignOption(opts, 'reconnect'); + this.assignOption(opts, 'maxReconnectAttempts'); + this.assignOption(opts, 'reconnectTimeWait'); + this.assignOption(opts, 'servers'); + this.assignOption(opts, 'urls', 'servers'); + this.assignOption(opts, 'noRandomize'); + this.assignOption(opts, 'NoRandomize', 'noRandomize'); + this.assignOption(opts, 'dontRandomize', 'noRandomize'); + this.assignOption(opts, 'encoding'); + this.assignOption(opts, 'tls'); + this.assignOption(opts, 'secure', 'tls'); + this.assignOption(opts, 'name'); + this.assignOption(opts, 'client', 'name'); + this.assignOption(opts, 'yieldTime'); + this.assignOption(opts, 'waitOnFirstConnect'); + this.assignOption(opts, 'json'); + this.assignOption(opts, 'preserveBuffers'); } - // Pull out various options here - this.assignOption(opts, 'url'); - this.assignOption(opts, 'uri', 'url'); - this.assignOption(opts, 'user'); - this.assignOption(opts, 'pass'); - this.assignOption(opts, 'token'); - this.assignOption(opts, 'password', 'pass'); - this.assignOption(opts, 'verbose'); - this.assignOption(opts, 'pedantic'); - this.assignOption(opts, 'reconnect'); - this.assignOption(opts, 'maxReconnectAttempts'); - this.assignOption(opts, 'reconnectTimeWait'); - this.assignOption(opts, 'servers'); - this.assignOption(opts, 'urls', 'servers'); - this.assignOption(opts, 'noRandomize'); - this.assignOption(opts, 'NoRandomize', 'noRandomize'); - this.assignOption(opts, 'dontRandomize', 'noRandomize'); - this.assignOption(opts, 'encoding'); - this.assignOption(opts, 'tls'); - this.assignOption(opts, 'secure', 'tls'); - this.assignOption(opts, 'name'); - this.assignOption(opts, 'client', 'name'); - this.assignOption(opts, 'yieldTime'); - this.assignOption(opts, 'waitOnFirstConnect'); - this.assignOption(opts, 'json'); - this.assignOption(opts, 'preserveBuffers'); - } - - var client = this; - - // Set user/pass as needed if in options. - client.user = options.user; - client.pass = options.pass; - - // Set token as needed if in options. - client.token = options.token; - - // Authentication - make sure authentication is valid. - if (client.user && client.token) { - throw(new NatsError(BAD_AUTHENTICATION_MSG, BAD_AUTHENTICATION)); - } - - // Encoding - make sure its valid. - if (Buffer.isEncoding(options.encoding)) { - client.encoding = options.encoding; - } else { - throw new NatsError(INVALID_ENCODING_MSG_PREFIX + options.encoding, INVALID_ENCODING); - } - // For cluster support - client.servers = []; - - if (Array.isArray(options.servers)) { - options.servers.forEach(function(server) { - client.servers.push(new Server(url.parse(server))); - }); - } else { - if (undefined === options.url) { - options.url = DEFAULT_URI; + + var client = this; + + // Set user/pass as needed if in options. + client.user = options.user; + client.pass = options.pass; + + // Set token as needed if in options. + client.token = options.token; + + // Authentication - make sure authentication is valid. + if (client.user && client.token) { + throw (new NatsError(BAD_AUTHENTICATION_MSG, BAD_AUTHENTICATION)); + } + + // Encoding - make sure its valid. + if (Buffer.isEncoding(options.encoding)) { + client.encoding = options.encoding; + } else { + throw new NatsError(INVALID_ENCODING_MSG_PREFIX + options.encoding, INVALID_ENCODING); + } + // For cluster support + client.servers = []; + + if (Array.isArray(options.servers)) { + options.servers.forEach(function(server) { + client.servers.push(new Server(url.parse(server))); + }); + } else { + if (undefined === options.url) { + options.url = DEFAULT_URI; + } + client.servers.push(new Server(url.parse(options.url))); } - client.servers.push(new Server(url.parse(options.url))); - } - // Randomize if needed - if (options.noRandomize !== true) { - shuffle(client.servers); - } + // Randomize if needed + if (options.noRandomize !== true) { + shuffle(client.servers); + } }; /** * Create a new server. * * @api private -*/ - + */ function Server(url) { - this.url = url; - this.didConnect = false; - this.reconnects = 0; + this.url = url; + this.didConnect = false; + this.reconnects = 0; } /** @@ -321,80 +312,77 @@ function Server(url) { * if they were set in options use that as override. * * @api private -*/ - + */ Client.prototype.selectServer = function() { - var client = this; - var server = client.servers.shift(); - - // Place in client context. - client.currentServer = server; - client.url = server.url; - if ('auth' in server.url && !!server.url.auth) { - var auth = server.url.auth.split(':'); - if (auth.length !== 1) { - if (client.options.user === undefined) { - client.user = auth[0]; - } - if (client.options.pass === undefined) { - client.pass = auth[1]; - } - } else { - if (client.options.token === undefined) { - client.token = auth[0]; - } + var client = this; + var server = client.servers.shift(); + + // Place in client context. + client.currentServer = server; + client.url = server.url; + if ('auth' in server.url && !!server.url.auth) { + var auth = server.url.auth.split(':'); + if (auth.length !== 1) { + if (client.options.user === undefined) { + client.user = auth[0]; + } + if (client.options.pass === undefined) { + client.pass = auth[1]; + } + } else { + if (client.options.token === undefined) { + client.token = auth[0]; + } + } } - } - client.servers.push(server); + client.servers.push(server); }; /** * Check for TLS configuration mismatch. * * @api private -*/ - + */ Client.prototype.checkTLSMismatch = function() { - if (this.info.tls_required === true && - this.options.tls === false) { - this.emit('error', new NatsError(SECURE_CONN_REQ_MSG, SECURE_CONN_REQ)); - this.closeStream(); - return true; - } + if (this.info.tls_required === true && + this.options.tls === false) { + this.emit('error', new NatsError(SECURE_CONN_REQ_MSG, SECURE_CONN_REQ)); + this.closeStream(); + return true; + } - if (this.info.tls_required === false && - this.options.tls !== false) { - this.emit('error', new NatsError(NON_SECURE_CONN_REQ_MSG, NON_SECURE_CONN_REQ)); - this.closeStream(); - return true; - } + if (this.info.tls_required === false && + this.options.tls !== false) { + this.emit('error', new NatsError(NON_SECURE_CONN_REQ_MSG, NON_SECURE_CONN_REQ)); + this.closeStream(); + return true; + } - if (this.info.tls_verify === true && - this.options.tls.cert === undefined) { - this.emit('error', new NatsError(CLIENT_CERT_REQ_MSG, CLIENT_CERT_REQ)); - this.closeStream(); - return true; - } - return false; + if (this.info.tls_verify === true && + this.options.tls.cert === undefined) { + this.emit('error', new NatsError(CLIENT_CERT_REQ_MSG, CLIENT_CERT_REQ)); + this.closeStream(); + return true; + } + return false; }; /** * Callback for first flush/connect. * * @api private -*/ - + */ Client.prototype.connectCB = function() { - var wasReconnecting = this.reconnecting; - var event = (wasReconnecting === true) ? 'reconnect' : 'connect'; - this.reconnecting = false; - this.reconnects = 0; - this.wasConnected = true; - this.currentServer.didConnect = true; + var wasReconnecting = this.reconnecting; + var event = (wasReconnecting === true) ? 'reconnect' : 'connect'; + this.reconnecting = false; + this.reconnects = 0; + this.wasConnected = true; + this.currentServer.didConnect = true; - this.emit(event, this); + this.emit(event, this); - this.flushPending(); + this.flushPending(); }; @@ -402,73 +390,72 @@ Client.prototype.connectCB = function() { * Properly setup a stream event handlers. * * @api private -*/ - + */ Client.prototype.setupHandlers = function() { - var client = this; - var stream = client.stream; - - if (undefined === stream) { - return; - } - - stream.on('connect', function() { - client.connected = true; - }); - - stream.on('close', function(hadError) { - client.closeStream(); - client.emit('disconnect'); - if (client.closed === true || - client.options.reconnect === false || - ((client.reconnects >= client.options.maxReconnectAttempts) && client.options.maxReconnectAttempts !== -1)) { - client.emit('close'); - } else { - client.scheduleReconnect(); - } - }); + var client = this; + var stream = client.stream; - stream.on('error', function(exception) { - // If we were connected just return, close event will process - if (client.wasConnected === true && client.currentServer.didConnect === true) { - return; + if (undefined === stream) { + return; } - // if the current server did not connect at all, and we in - // general have not connected to any server, remove it from - // this list. Unless overidden - if (client.wasConnected === false && client.currentServer.didConnect === false) { - // We can override this behavior with waitOnFirstConnect, which will - // treat it like a reconnect scenario. - if (client.options.waitOnFirstConnect) { - // Pretend to move us into a reconnect state. - client.currentServer.didConnect = true; - } else { - client.servers.splice(client.servers.length-1, 1); - } - } + stream.on('connect', function() { + client.connected = true; + }); - // Only bubble up error if we never had connected - // to the server and we only have one. - if (client.wasConnected === false && client.servers.length === 0) { - client.emit('error', new NatsError(CONN_ERR_MSG_PREFIX + exception, CONN_ERR, exception)); - } - client.closeStream(); - }); - - stream.on('data', function (data) { - // If inbound exists, concat them together. We try to avoid this for split - // messages, so this should only really happen for a split control line. - // Long term answer is hand rolled parser and not regexp. - if (client.inbound) { - client.inbound = Buffer.concat([client.inbound, data]); - } else { - client.inbound = data; - } + stream.on('close', function(hadError) { + client.closeStream(); + client.emit('disconnect'); + if (client.closed === true || + client.options.reconnect === false || + ((client.reconnects >= client.options.maxReconnectAttempts) && client.options.maxReconnectAttempts !== -1)) { + client.emit('close'); + } else { + client.scheduleReconnect(); + } + }); + + stream.on('error', function(exception) { + // If we were connected just return, close event will process + if (client.wasConnected === true && client.currentServer.didConnect === true) { + return; + } - // Process the inbound queue. - client.processInbound(); - }); + // if the current server did not connect at all, and we in + // general have not connected to any server, remove it from + // this list. Unless overidden + if (client.wasConnected === false && client.currentServer.didConnect === false) { + // We can override this behavior with waitOnFirstConnect, which will + // treat it like a reconnect scenario. + if (client.options.waitOnFirstConnect) { + // Pretend to move us into a reconnect state. + client.currentServer.didConnect = true; + } else { + client.servers.splice(client.servers.length - 1, 1); + } + } + + // Only bubble up error if we never had connected + // to the server and we only have one. + if (client.wasConnected === false && client.servers.length === 0) { + client.emit('error', new NatsError(CONN_ERR_MSG_PREFIX + exception, CONN_ERR, exception)); + } + client.closeStream(); + }); + + stream.on('data', function(data) { + // If inbound exists, concat them together. We try to avoid this for split + // messages, so this should only really happen for a split control line. + // Long term answer is hand rolled parser and not regexp. + if (client.inbound) { + client.inbound = Buffer.concat([client.inbound, data]); + } else { + client.inbound = data; + } + + // Process the inbound queue. + client.processInbound(); + }); }; /** @@ -476,94 +463,92 @@ Client.prototype.setupHandlers = function() { * INFO message and after TLS is established if necessary. * * @api private -*/ - + */ Client.prototype.sendConnect = function() { - // Queue the connect command. - var cs = { - 'lang' : 'node', - 'version' : VERSION, - 'verbose' : this.options.verbose, - 'pedantic': this.options.pedantic, - 'protocol': 1, - }; - if (this.user !== undefined) { - cs.user = this.user; - cs.pass = this.pass; - } - if (this.token !== undefined) { - cs.auth_token = this.token; - } - if (this.options.name !== undefined) { - cs.name = this.options.name; - } - // If we enqueued requests before we received INFO from the server, or we - // reconnected, there be other data pending, write this immediately instead - // of adding it to the queue. - this.stream.write(CONNECT + SPC + JSON.stringify(cs) + CR_LF); + // Queue the connect command. + var cs = { + 'lang': 'node', + 'version': VERSION, + 'verbose': this.options.verbose, + 'pedantic': this.options.pedantic, + 'protocol': 1, + }; + if (this.user !== undefined) { + cs.user = this.user; + cs.pass = this.pass; + } + if (this.token !== undefined) { + cs.auth_token = this.token; + } + if (this.options.name !== undefined) { + cs.name = this.options.name; + } + // If we enqueued requests before we received INFO from the server, or we + // reconnected, there be other data pending, write this immediately instead + // of adding it to the queue. + this.stream.write(CONNECT + SPC + JSON.stringify(cs) + CR_LF); }; /** * Properly setup a stream connection with proper events. * * @api private -*/ - + */ Client.prototype.createConnection = function() { - // Commands may have been queued during reconnect. Discard everything except: - // 1) ping requests with a pong callback - // 2) publish requests - // - // Rationale: CONNECT and SUBs are written directly upon connecting, any PONG - // response is no longer relevant, and any UNSUB will be accounted for when we - // sync our SUBs. Without this, users of the client may miss state transitions - // via callbacks, would have to track the client's internal connection state, - // and may have to double buffer messages (which we are already doing) if they - // wanted to ensure their messages reach the server. - var pong = []; - var pend = []; - var pSize = 0; - var client = this; - if (client.pending !== null) { - var pongIndex = 0; - client.pending.forEach(function(cmd) { - var cmdLen = Buffer.isBuffer(cmd) ? cmd.length : Buffer.byteLength(cmd); - if (cmd === PING_REQUEST && client.pongs !== null && pongIndex < client.pongs.length) { - // filter out any useless ping requests (no pong callback, nop flush) - var p = client.pongs[pongIndex++]; - if (p !== undefined) { - pend.push(cmd); - pSize += cmdLen; - pong.push(p); - } - } else if (cmd.length > 3 && cmd[0] == 'P' && cmd[1] == 'U' && cmd[2] == 'B') { - pend.push(cmd); - pSize += cmdLen; - } - }); - } - this.pongs = pong; - this.pending = pend; - this.pSize = pSize; + // Commands may have been queued during reconnect. Discard everything except: + // 1) ping requests with a pong callback + // 2) publish requests + // + // Rationale: CONNECT and SUBs are written directly upon connecting, any PONG + // response is no longer relevant, and any UNSUB will be accounted for when we + // sync our SUBs. Without this, users of the client may miss state transitions + // via callbacks, would have to track the client's internal connection state, + // and may have to double buffer messages (which we are already doing) if they + // wanted to ensure their messages reach the server. + var pong = []; + var pend = []; + var pSize = 0; + var client = this; + if (client.pending !== null) { + var pongIndex = 0; + client.pending.forEach(function(cmd) { + var cmdLen = Buffer.isBuffer(cmd) ? cmd.length : Buffer.byteLength(cmd); + if (cmd === PING_REQUEST && client.pongs !== null && pongIndex < client.pongs.length) { + // filter out any useless ping requests (no pong callback, nop flush) + var p = client.pongs[pongIndex++]; + if (p !== undefined) { + pend.push(cmd); + pSize += cmdLen; + pong.push(p); + } + } else if (cmd.length > 3 && cmd[0] === 'P' && cmd[1] === 'U' && cmd[2] === 'B') { + pend.push(cmd); + pSize += cmdLen; + } + }); + } + this.pongs = pong; + this.pending = pend; + this.pSize = pSize; - this.pstate = AWAITING_CONTROL; + this.pstate = AWAITING_CONTROL; - // Clear info processing. - this.info = null; - this.infoReceived = false; + // Clear info processing. + this.info = null; + this.infoReceived = false; - // Select a server to connect to. - this.selectServer(); + // Select a server to connect to. + this.selectServer(); // See #45 if we have a stream release the listeners - // otherwise in addition to the leak events will fire fire - if(this.stream) { - this.stream.removeAllListeners(); - this.stream.end(); - } + // otherwise in addition to the leak events will fire fire + if (this.stream) { + this.stream.removeAllListeners(); + this.stream.end(); + } // Create the stream this.stream = net.createConnection(this.url.port, this.url.hostname); - // Setup the proper handlers. - this.setupHandlers(); + // Setup the proper handlers. + this.setupHandlers(); }; /** @@ -571,16 +556,15 @@ Client.prototype.createConnection = function() { * * @api private */ - Client.prototype.initState = function() { - this.ssid = 1; - this.subs = {}; - this.reconnects = 0; - this.connected = false; - this.wasConnected = false; - this.reconnecting = false; - this.server = null; - this.pending = []; + this.ssid = 1; + this.subs = {}; + this.reconnects = 0; + this.connected = false; + this.wasConnected = false; + this.reconnecting = false; + this.server = null; + this.pending = []; }; /** @@ -588,17 +572,16 @@ Client.prototype.initState = function() { * * @api public */ - Client.prototype.close = function() { - this.closed = true; - this.removeAllListeners(); - this.closeStream(); - this.ssid = -1; - this.subs = null; - this.pstate = -1; - this.pongs = null; - this.pending = null; - this.pSize = 0; + this.closed = true; + this.removeAllListeners(); + this.closeStream(); + this.ssid = -1; + this.subs = null; + this.pstate = -1; + this.pongs = null; + this.pending = null; + this.pSize = 0; }; /** @@ -606,20 +589,19 @@ Client.prototype.close = function() { * * @api private */ - Client.prototype.closeStream = function() { - if (this.stream !== null) { - this.stream.end(); - this.stream.destroy(); - this.stream = null; - } - if (this.connected === true || this.closed === true) { - this.pongs = null; - this.pending = null; - this.pSize = 0; - this.connected = false; - } - this.inbound = null; + if (this.stream !== null) { + this.stream.end(); + this.stream.destroy(); + this.stream = null; + } + if (this.connected === true || this.closed === true) { + this.pongs = null; + this.pending = null; + this.pSize = 0; + this.connected = false; + } + this.inbound = null; }; /** @@ -627,48 +609,47 @@ Client.prototype.closeStream = function() { * * @api private */ - Client.prototype.flushPending = function() { - if (this.connected === false || - this.pending === null || - this.pending.length === 0 || - this.infoReceived !== true) { - return; - } - - var client = this; - var write = function(data) { - client.pending = []; - client.pSize = 0; - return client.stream.write(data); - }; - if (!this.pBufs) { - // All strings, fastest for now. - return write(this.pending.join(EMPTY)); - } else { - // We have some or all Buffers. Figure out if we can optimize. - var allBufs = true; - for (var i=0; i < this.pending.length; i++){ - if (!Buffer.isBuffer(this.pending[i])) { - allBufs = false; - break; - } + if (this.connected === false || + this.pending === null || + this.pending.length === 0 || + this.infoReceived !== true) { + return; } - // If all buffers, concat together and write once. - if (allBufs) { - return write(Buffer.concat(this.pending, this.pSize)); + + var client = this; + var write = function(data) { + client.pending = []; + client.pSize = 0; + return client.stream.write(data); + }; + if (!this.pBufs) { + // All strings, fastest for now. + return write(this.pending.join(EMPTY)); } else { - // We have a mix, so write each one individually. - var pending = this.pending; - this.pending = []; - this.pSize = 0; - var result = true; - for (i=0; i < pending.length; i++){ - result = this.stream.write(pending[i]) && result; - } - return result; + // We have some or all Buffers. Figure out if we can optimize. + var allBufs = true; + for (var i = 0; i < this.pending.length; i++) { + if (!Buffer.isBuffer(this.pending[i])) { + allBufs = false; + break; + } + } + // If all buffers, concat together and write once. + if (allBufs) { + return write(Buffer.concat(this.pending, this.pSize)); + } else { + // We have a mix, so write each one individually. + var pending = this.pending; + this.pending = []; + this.pSize = 0; + var result = true; + for (i = 0; i < pending.length; i++) { + result = this.stream.write(pending[i]) && result; + } + return result; + } } - } }; /** @@ -677,17 +658,16 @@ Client.prototype.flushPending = function() { * * @api private */ - Client.prototype.stripPendingSubs = function() { - var pending = this.pending; - this.pending = []; - this.pSize = 0; - for (var i=0; i < pending.length; i++){ - if (!SUBRE.test(pending[i])) { - // Re-queue the command. - this.sendCommand(pending[i]); + var pending = this.pending; + this.pending = []; + this.pSize = 0; + for (var i = 0; i < pending.length; i++) { + if (!SUBRE.test(pending[i])) { + // Re-queue the command. + this.sendCommand(pending[i]); + } } - } }; /** @@ -695,33 +675,34 @@ Client.prototype.stripPendingSubs = function() { * * @api private */ - Client.prototype.sendCommand = function(cmd) { - // Buffer to cut down on system calls, increase throughput. - // When receive gets faster, should make this Buffer based.. - - if (this.closed || this.pending === null) { return; } - - this.pending.push(cmd); - if (!Buffer.isBuffer(cmd)) { - this.pSize += Buffer.byteLength(cmd); - } else { - this.pSize += cmd.length; - this.pBufs = true; - } - - if (this.connected === true) { - // First one let's setup flush.. - if (this.pending.length === 1) { - var self = this; - setImmediate(function() { - self.flushPending(); - }); - } else if (this.pSize > FLUSH_THRESHOLD) { - // Flush in place when threshold reached.. - this.flushPending(); + // Buffer to cut down on system calls, increase throughput. + // When receive gets faster, should make this Buffer based.. + + if (this.closed || this.pending === null) { + return; + } + + this.pending.push(cmd); + if (!Buffer.isBuffer(cmd)) { + this.pSize += Buffer.byteLength(cmd); + } else { + this.pSize += cmd.length; + this.pBufs = true; + } + + if (this.connected === true) { + // First one let's setup flush.. + if (this.pending.length === 1) { + var self = this; + setImmediate(function() { + self.flushPending(); + }); + } else if (this.pSize > FLUSH_THRESHOLD) { + // Flush in place when threshold reached.. + this.flushPending(); + } } - } }; /** @@ -729,24 +710,23 @@ Client.prototype.sendCommand = function(cmd) { * * @api private */ - Client.prototype.sendSubscriptions = function() { - var protos = ""; - for (var sid in this.subs) { - if (this.subs.hasOwnProperty(sid)) { - var sub = this.subs[sid]; - var proto; - if (sub.qgroup) { - proto = [SUB, sub.subject, sub.qgroup, sid + CR_LF]; - } else { - proto = [SUB, sub.subject, sid + CR_LF]; - } - protos += proto.join(SPC); + var protos = ""; + for (var sid in this.subs) { + if (this.subs.hasOwnProperty(sid)) { + var sub = this.subs[sid]; + var proto; + if (sub.qgroup) { + proto = [SUB, sub.subject, sub.qgroup, sid + CR_LF]; + } else { + proto = [SUB, sub.subject, sid + CR_LF]; + } + protos += proto.join(SPC); + } + } + if (protos.length > 0) { + this.stream.write(protos); } - } - if (protos.length > 0) { - this.stream.write(protos); - } }; /** @@ -754,209 +734,214 @@ Client.prototype.sendSubscriptions = function() { * * @api private */ - Client.prototype.processInbound = function() { - var client = this; - - // Hold any regex matches. - var m; - - // For optional yield - var start; - - if(! client.stream) { - // if we are here, the stream was reaped and errors raised - // if we continue. - return; - } - // unpause if needed. - // FIXME(dlc) client.stream.isPaused() causes 0.10 to fail - client.stream.resume(); - - /* jshint -W083 */ - - if (client.options.yieldTime !== undefined) { - start = Date.now(); - } - - while (!client.closed && client.inbound && client.inbound.length > 0) { - switch (client.pstate) { - - case AWAITING_CONTROL: - // Regex only works on strings, so convert once to be more efficient. - // Long term answer is a hand rolled parser, not regex. - var buf = client.inbound.toString('binary', 0, MAX_CONTROL_LINE_SIZE); - if ((m = MSG.exec(buf)) !== null) { - client.payload = { - subj : m[1], - sid : parseInt(m[2], 10), - reply : m[4], - size : parseInt(m[5], 10) - }; - client.payload.psize = client.payload.size + CR_LF_LEN; - client.pstate = AWAITING_MSG_PAYLOAD; - } else if ((m = OK.exec(buf)) !== null) { - // Ignore for now.. - } else if ((m = ERR.exec(buf)) !== null) { - client.processErr(m[1]); - return; - } else if ((m = PONG.exec(buf)) !== null) { - var cb = client.pongs && client.pongs.shift(); - if (cb) { cb(); } // FIXME: Should we check for exceptions? - } else if ((m = PING.exec(buf)) !== null) { - client.sendCommand(PONG_RESPONSE); - } else if ((m = INFO.exec(buf)) !== null) { - client.info = JSON.parse(m[1]); - // Check on TLS mismatch. - if (client.checkTLSMismatch() === true) { - return; - } - - // Always try to read the connect_urls from info - if(client.info.connect_urls && client.info.connect_urls.length > 0) { - // don't add duplicates - var known = []; - client.servers.forEach(function(server) { - known.push(server.url.href); - }); - // add new ones - var toAdd = []; - client.info.connect_urls.forEach(function(server) { - var u = 'nats://' + server; - if(known.indexOf(u) === -1) { - toAdd.push(new Server(url.parse(u))); - } - }); + var client = this; - if(toAdd.length > 0) { - if(client.options.noRandomize !== true) { - shuffle(toAdd); - } - toAdd.forEach(function(s) { - client.servers.push(s); - }); - } - } - - // Process first INFO - if (client.infoReceived === false) { - // Switch over to TLS as needed. - if (client.options.tls !== false && - client.stream.encrypted !== true) { - var tlsOpts = {socket: client.stream}; - if ('object' === typeof client.options.tls) { - for (var key in client.options.tls) { - tlsOpts[key] = client.options.tls[key]; - } - } - // if we have a stream, this is from an old connection, reap it - if(client.stream) { - client.stream.removeAllListeners(); - client.stream.end(); - } - client.stream = tls.connect(tlsOpts, function() { - client.flushPending(); - }); - client.setupHandlers(); - } - - // Send the connect message and subscriptions immediately - client.sendConnect(); - client.sendSubscriptions(); - - client.pongs.unshift(function() { client.connectCB(); }); - client.stream.write(PING_REQUEST); - - // Mark as received - client.infoReceived = true; - client.stripPendingSubs(); - client.flushPending(); - } - } else { - // FIXME, check line length for something weird. - // Nothing here yet, return - return; - } - break; - - case AWAITING_MSG_PAYLOAD: - - // If we do not have the complete message, hold onto the chunks - // and assemble when we have all we need. This optimizes for - // when we parse a large buffer down to a small number of bytes, - // then we receive a large chunk. This avoids a big copy with a - // simple concat above. - if (client.inbound.length < client.payload.psize) { - if (undefined === client.payload.chunks) { - client.payload.chunks = []; - } - client.payload.chunks.push(client.inbound); - client.payload.psize -= client.inbound.length; - client.inbound = null; - return; - } - - // If we are here we have the complete message. - // Check to see if we have existing chunks - if (client.payload.chunks) { - - client.payload.chunks.push(client.inbound.slice(0, client.payload.psize)); - // don't append trailing control characters - var mbuf = Buffer.concat(client.payload.chunks, client.payload.size); - - if (client.options.preserveBuffers) { - client.payload.msg = mbuf; - } else { - client.payload.msg = mbuf.toString(client.encoding); - } + // Hold any regex matches. + var m; - } else { + // For optional yield + var start; - if (client.options.preserveBuffers) { - client.payload.msg = client.inbound.slice(0, client.payload.size); - } else { - client.payload.msg = client.inbound.toString(client.encoding, 0, client.payload.size); - } + if (!client.stream) { + // if we are here, the stream was reaped and errors raised + // if we continue. + return; + } + // unpause if needed. + // FIXME(dlc) client.stream.isPaused() causes 0.10 to fail + client.stream.resume(); + + /* jshint -W083 */ - } - - // Eat the size of the inbound that represents the message. - if (client.inbound.length === client.payload.psize) { - client.inbound = null; - } else { - client.inbound = client.inbound.slice(client.payload.psize); - } - - // process the message - client.processMsg(); - - // Reset - client.pstate = AWAITING_CONTROL; - client.payload = null; - - // Check to see if we have an option to yield for other events after yieldTime. - if (start !== undefined) { - if ((Date.now() - start) > client.options.yieldTime) { - client.stream.pause(); - setImmediate(client.processInbound.bind(this)); - return; - } - } - break; + if (client.options.yieldTime !== undefined) { + start = Date.now(); } - // This is applicable for a regex match to eat the bytes we used from a control line. - if (m && !this.closed) { - // Chop inbound - var psize = m[0].length; - if (psize >= client.inbound.length) { - client.inbound = null; - } else { - client.inbound = client.inbound.slice(psize); - } + while (!client.closed && client.inbound && client.inbound.length > 0) { + switch (client.pstate) { + + case AWAITING_CONTROL: + // Regex only works on strings, so convert once to be more efficient. + // Long term answer is a hand rolled parser, not regex. + var buf = client.inbound.toString('binary', 0, MAX_CONTROL_LINE_SIZE); + if ((m = MSG.exec(buf)) !== null) { + client.payload = { + subj: m[1], + sid: parseInt(m[2], 10), + reply: m[4], + size: parseInt(m[5], 10) + }; + client.payload.psize = client.payload.size + CR_LF_LEN; + client.pstate = AWAITING_MSG_PAYLOAD; + } else if ((m = OK.exec(buf)) !== null) { + // Ignore for now.. + } else if ((m = ERR.exec(buf)) !== null) { + client.processErr(m[1]); + return; + } else if ((m = PONG.exec(buf)) !== null) { + var cb = client.pongs && client.pongs.shift(); + if (cb) { + cb(); + } // FIXME: Should we check for exceptions? + } else if ((m = PING.exec(buf)) !== null) { + client.sendCommand(PONG_RESPONSE); + } else if ((m = INFO.exec(buf)) !== null) { + client.info = JSON.parse(m[1]); + // Check on TLS mismatch. + if (client.checkTLSMismatch() === true) { + return; + } + + // Always try to read the connect_urls from info + if (client.info.connect_urls && client.info.connect_urls.length > 0) { + // don't add duplicates + var known = []; + client.servers.forEach(function(server) { + known.push(server.url.href); + }); + // add new ones + var toAdd = []; + client.info.connect_urls.forEach(function(server) { + var u = 'nats://' + server; + if (known.indexOf(u) === -1) { + toAdd.push(new Server(url.parse(u))); + } + }); + + if (toAdd.length > 0) { + if (client.options.noRandomize !== true) { + shuffle(toAdd); + } + toAdd.forEach(function(s) { + client.servers.push(s); + }); + } + } + + // Process first INFO + if (client.infoReceived === false) { + // Switch over to TLS as needed. + if (client.options.tls !== false && + client.stream.encrypted !== true) { + var tlsOpts = { + socket: client.stream + }; + if ('object' === typeof client.options.tls) { + for (var key in client.options.tls) { + tlsOpts[key] = client.options.tls[key]; + } + } + // if we have a stream, this is from an old connection, reap it + if (client.stream) { + client.stream.removeAllListeners(); + client.stream.end(); + } + client.stream = tls.connect(tlsOpts, function() { + client.flushPending(); + }); + client.setupHandlers(); + } + + // Send the connect message and subscriptions immediately + client.sendConnect(); + client.sendSubscriptions(); + + client.pongs.unshift(function() { + client.connectCB(); + }); + client.stream.write(PING_REQUEST); + + // Mark as received + client.infoReceived = true; + client.stripPendingSubs(); + client.flushPending(); + } + } else { + // FIXME, check line length for something weird. + // Nothing here yet, return + return; + } + break; + + case AWAITING_MSG_PAYLOAD: + + // If we do not have the complete message, hold onto the chunks + // and assemble when we have all we need. This optimizes for + // when we parse a large buffer down to a small number of bytes, + // then we receive a large chunk. This avoids a big copy with a + // simple concat above. + if (client.inbound.length < client.payload.psize) { + if (undefined === client.payload.chunks) { + client.payload.chunks = []; + } + client.payload.chunks.push(client.inbound); + client.payload.psize -= client.inbound.length; + client.inbound = null; + return; + } + + // If we are here we have the complete message. + // Check to see if we have existing chunks + if (client.payload.chunks) { + + client.payload.chunks.push(client.inbound.slice(0, client.payload.psize)); + // don't append trailing control characters + var mbuf = Buffer.concat(client.payload.chunks, client.payload.size); + + if (client.options.preserveBuffers) { + client.payload.msg = mbuf; + } else { + client.payload.msg = mbuf.toString(client.encoding); + } + + } else { + + if (client.options.preserveBuffers) { + client.payload.msg = client.inbound.slice(0, client.payload.size); + } else { + client.payload.msg = client.inbound.toString(client.encoding, 0, client.payload.size); + } + + } + + // Eat the size of the inbound that represents the message. + if (client.inbound.length === client.payload.psize) { + client.inbound = null; + } else { + client.inbound = client.inbound.slice(client.payload.psize); + } + + // process the message + client.processMsg(); + + // Reset + client.pstate = AWAITING_CONTROL; + client.payload = null; + + // Check to see if we have an option to yield for other events after yieldTime. + if (start !== undefined) { + if ((Date.now() - start) > client.options.yieldTime) { + client.stream.pause(); + setImmediate(client.processInbound.bind(this)); + return; + } + } + break; + } + + // This is applicable for a regex match to eat the bytes we used from a control line. + if (m && !this.closed) { + // Chop inbound + var psize = m[0].length; + if (psize >= client.inbound.length) { + client.inbound = null; + } else { + client.inbound = client.inbound.slice(psize); + } + } + m = null; } - m = null; - } }; /** @@ -964,45 +949,44 @@ Client.prototype.processInbound = function() { * * @api private */ - Client.prototype.processMsg = function() { - var sub = this.subs[this.payload.sid]; - if (sub !== undefined) { - sub.received += 1; - // Check for a timeout, and cancel if received >= expected - if (sub.timeout) { - if (sub.received >= sub.expected) { - clearTimeout(sub.timeout); - sub.timeout = null; - } - } - // Check for auto-unsubscribe - if (sub.max !== undefined) { - if (sub.received === sub.max) { - delete this.subs[this.payload.sid]; - this.emit('unsubscribe', this.payload.sid, sub.subject); - } else if (sub.received > sub.max) { - this.unsubscribe(this.payload.sid); - sub.callback = null; - } - } + var sub = this.subs[this.payload.sid]; + if (sub !== undefined) { + sub.received += 1; + // Check for a timeout, and cancel if received >= expected + if (sub.timeout) { + if (sub.received >= sub.expected) { + clearTimeout(sub.timeout); + sub.timeout = null; + } + } + // Check for auto-unsubscribe + if (sub.max !== undefined) { + if (sub.received === sub.max) { + delete this.subs[this.payload.sid]; + this.emit('unsubscribe', this.payload.sid, sub.subject); + } else if (sub.received > sub.max) { + this.unsubscribe(this.payload.sid); + sub.callback = null; + } + } - if (sub.callback) { - var msg = this.payload.msg; - if (this.options.json) { - try { - if (this.options.preserveBuffers) { - msg = JSON.parse(this.payload.msg.toString()); - } else { - msg = JSON.parse(this.payload.msg.toString(this.options.encoding)); - } - } catch (e) { - msg = e; + if (sub.callback) { + var msg = this.payload.msg; + if (this.options.json) { + try { + if (this.options.preserveBuffers) { + msg = JSON.parse(this.payload.msg.toString()); + } else { + msg = JSON.parse(this.payload.msg.toString(this.options.encoding)); + } + } catch (e) { + msg = e; + } + } + sub.callback(msg, this.payload.reply, this.payload.subj, this.payload.sid); } - } - sub.callback(msg, this.payload.reply, this.payload.subj, this.payload.sid); } - } }; /** @@ -1014,13 +998,13 @@ Client.prototype.processErr = function(s) { // current NATS clients, will raise an error and close on any errors // except stale connection and permission errors var m = s ? s.toLowerCase() : ''; - if(m.indexOf(STALE_CONNECTION_ERR) !== -1) { - this.scheduleReconnect(); - } else if(m.indexOf(PERMISSIONS_ERR) !== -1) { - this.emit('permission_error', new NatsError(s, NATS_PROTOCOL_ERR)); + if (m.indexOf(STALE_CONNECTION_ERR) !== -1) { + this.scheduleReconnect(); + } else if (m.indexOf(PERMISSIONS_ERR) !== -1) { + this.emit('permission_error', new NatsError(s, NATS_PROTOCOL_ERR)); } else { - this.emit('error', new NatsError(s, NATS_PROTOCOL_ERR)); - this.closeStream(); + this.emit('error', new NatsError(s, NATS_PROTOCOL_ERR)); + this.closeStream(); } }; @@ -1029,14 +1013,13 @@ Client.prototype.processErr = function(s) { * * @param {String} uri * @api public -*/ - + */ Client.prototype.addServer = function(uri) { - this.servers.push(new Server(url.parse(uri))); + this.servers.push(new Server(url.parse(uri))); - if (this.options.noRandomize !== true) { - shuffle(this.servers); - } + if (this.options.noRandomize !== true) { + shuffle(this.servers); + } }; /** @@ -1046,21 +1029,20 @@ Client.prototype.addServer = function(uri) { * @param {Function} opt_callback * @api public */ - Client.prototype.flush = function(opt_callback) { - if (this.closed) { - if (typeof opt_callback === 'function') { - opt_callback(new NatsError(CONN_CLOSED_MSG, CONN_CLOSED)); - return; - } else { - throw(new NatsError(CONN_CLOSED_MSG, CONN_CLOSED)); + if (this.closed) { + if (typeof opt_callback === 'function') { + opt_callback(new NatsError(CONN_CLOSED_MSG, CONN_CLOSED)); + return; + } else { + throw (new NatsError(CONN_CLOSED_MSG, CONN_CLOSED)); + } + } + if (this.pongs) { + this.pongs.push(opt_callback); + this.sendCommand(PING_REQUEST); + this.flushPending(); } - } - if (this.pongs) { - this.pongs.push(opt_callback); - this.sendCommand(PING_REQUEST); - this.flushPending(); - } }; /** @@ -1072,74 +1054,75 @@ Client.prototype.flush = function(opt_callback) { * @param {Function} opt_callback * @api public */ - Client.prototype.publish = function(subject, msg, opt_reply, opt_callback) { - // They only supplied a callback function. - if (typeof subject === 'function') { - opt_callback = subject; - subject = undefined; - } - if (!msg) { msg = EMPTY; } - if (!subject) { - if (opt_callback) { - opt_callback(new NatsError(BAD_SUBJECT_MSG, BAD_SUBJECT)); - } else { - throw(new NatsError(BAD_SUBJECT_MSG, BAD_SUBJECT)); + // They only supplied a callback function. + if (typeof subject === 'function') { + opt_callback = subject; + subject = undefined; } - } - if (typeof msg === 'function') { - if (opt_callback || opt_reply) { - opt_callback(new NatsError(BAD_MSG_MSG, BAD_MSG)); - return; + if (!msg) { + msg = EMPTY; } - opt_callback = msg; - msg = EMPTY; - opt_reply = undefined; - } - if (typeof opt_reply === 'function') { - if (opt_callback) { - opt_callback(new NatsError(BAD_REPLY_MSG, BAD_REPLY)); - return; + if (!subject) { + if (opt_callback) { + opt_callback(new NatsError(BAD_SUBJECT_MSG, BAD_SUBJECT)); + } else { + throw (new NatsError(BAD_SUBJECT_MSG, BAD_SUBJECT)); + } } - opt_callback = opt_reply; - opt_reply = undefined; - } - - // Hold PUB SUB [REPLY] - var psub; - if (opt_reply === undefined) { - psub = 'PUB ' + subject + SPC; - } else { - psub = 'PUB ' + subject + SPC + opt_reply + SPC; - } - - // Need to treat sending buffers different. - if (!Buffer.isBuffer(msg)) { - var str = msg; - if (this.options.json) { - if (typeof msg !== 'object') { - throw(new NatsError(BAD_JSON_MSG, BAD_JSON)); - } - try { - str = JSON.stringify(msg); - } catch (e) { - throw(new NatsError(BAD_JSON_MSG, BAD_JSON)); - } + if (typeof msg === 'function') { + if (opt_callback || opt_reply) { + opt_callback(new NatsError(BAD_MSG_MSG, BAD_MSG)); + return; + } + opt_callback = msg; + msg = EMPTY; + opt_reply = undefined; + } + if (typeof opt_reply === 'function') { + if (opt_callback) { + opt_callback(new NatsError(BAD_REPLY_MSG, BAD_REPLY)); + return; + } + opt_callback = opt_reply; + opt_reply = undefined; + } + + // Hold PUB SUB [REPLY] + var psub; + if (opt_reply === undefined) { + psub = 'PUB ' + subject + SPC; + } else { + psub = 'PUB ' + subject + SPC + opt_reply + SPC; + } + + // Need to treat sending buffers different. + if (!Buffer.isBuffer(msg)) { + var str = msg; + if (this.options.json) { + if (typeof msg !== 'object') { + throw (new NatsError(BAD_JSON_MSG, BAD_JSON)); + } + try { + str = JSON.stringify(msg); + } catch (e) { + throw (new NatsError(BAD_JSON_MSG, BAD_JSON)); + } + } + this.sendCommand(psub + Buffer.byteLength(str) + CR_LF + str + CR_LF); + } else { + var b = new Buffer(psub.length + msg.length + (2 * CR_LF_LEN) + msg.length.toString().length); + var len = b.write(psub + msg.length + CR_LF); + msg.copy(b, len); + b.write(CR_LF, len + msg.length); + this.sendCommand(b); + } + + if (opt_callback !== undefined) { + this.flush(opt_callback); + } else if (this.closed) { + throw (new NatsError(CONN_CLOSED_MSG, CONN_CLOSED)); } - this.sendCommand(psub + Buffer.byteLength(str) + CR_LF + str + CR_LF); - } else { - var b = new Buffer(psub.length + msg.length + (2 * CR_LF_LEN) + msg.length.toString().length); - var len = b.write(psub + msg.length + CR_LF); - msg.copy(b, len); - b.write(CR_LF, len + msg.length); - this.sendCommand(b); - } - - if (opt_callback !== undefined) { - this.flush(opt_callback); - } else if (this.closed) { - throw(new NatsError(CONN_CLOSED_MSG, CONN_CLOSED)); - } }; /** @@ -1152,38 +1135,41 @@ Client.prototype.publish = function(subject, msg, opt_reply, opt_callback) { * @return {Mixed} * @api public */ - Client.prototype.subscribe = function(subject, opts, callback) { - if (this.closed) { - throw(new NatsError(CONN_CLOSED_MSG, CONN_CLOSED)); - } - var qgroup, max; - if (typeof opts === 'function') { - callback = opts; - opts = undefined; - } else if (opts && typeof opts === 'object') { - // FIXME, check exists, error otherwise.. - qgroup = opts.queue; - max = opts.max; - } - this.ssid += 1; - this.subs[this.ssid] = { 'subject':subject, 'callback':callback, 'received':0 }; - - var proto; - if (typeof qgroup === 'string') { - this.subs[this.ssid].qgroup = qgroup; - proto = [SUB, subject, qgroup, this.ssid + CR_LF]; - } else { - proto = [SUB, subject, this.ssid + CR_LF]; - } - - this.sendCommand(proto.join(SPC)); - this.emit('subscribe', this.ssid, subject, opts); - - if (max) { - this.unsubscribe(this.ssid, max); - } - return this.ssid; + if (this.closed) { + throw (new NatsError(CONN_CLOSED_MSG, CONN_CLOSED)); + } + var qgroup, max; + if (typeof opts === 'function') { + callback = opts; + opts = undefined; + } else if (opts && typeof opts === 'object') { + // FIXME, check exists, error otherwise.. + qgroup = opts.queue; + max = opts.max; + } + this.ssid += 1; + this.subs[this.ssid] = { + 'subject': subject, + 'callback': callback, + 'received': 0 + }; + + var proto; + if (typeof qgroup === 'string') { + this.subs[this.ssid].qgroup = qgroup; + proto = [SUB, subject, qgroup, this.ssid + CR_LF]; + } else { + proto = [SUB, subject, this.ssid + CR_LF]; + } + + this.sendCommand(proto.join(SPC)); + this.emit('subscribe', this.ssid, subject, opts); + + if (max) { + this.unsubscribe(this.ssid, max); + } + return this.ssid; }; /** @@ -1195,32 +1181,33 @@ Client.prototype.subscribe = function(subject, opts, callback) { * @param {Number} opt_max * @api public */ - Client.prototype.unsubscribe = function(sid, opt_max) { - if (!sid || this.closed) { return; } - - var proto; - if (opt_max) { - proto = [UNSUB, sid, opt_max + CR_LF]; - } else { - proto = [UNSUB, sid + CR_LF]; - } - this.sendCommand(proto.join(SPC)); - - var sub = this.subs[sid]; - if (sub === undefined) { - return; - } - sub.max = opt_max; - if (sub.max === undefined || (sub.received >= sub.max)) { - // remove any timeouts that may be pending - if (sub.timeout) { - clearTimeout(sub.timeout); - sub.timeout = null; + if (!sid || this.closed) { + return; + } + + var proto; + if (opt_max) { + proto = [UNSUB, sid, opt_max + CR_LF]; + } else { + proto = [UNSUB, sid + CR_LF]; + } + this.sendCommand(proto.join(SPC)); + + var sub = this.subs[sid]; + if (sub === undefined) { + return; + } + sub.max = opt_max; + if (sub.max === undefined || (sub.received >= sub.max)) { + // remove any timeouts that may be pending + if (sub.timeout) { + clearTimeout(sub.timeout); + sub.timeout = null; + } + delete this.subs[sid]; + this.emit('unsubscribe', sid, sub.subject); } - delete this.subs[sid]; - this.emit('unsubscribe', sid, sub.subject); - } }; /** @@ -1233,16 +1220,20 @@ Client.prototype.unsubscribe = function(sid, opt_max) { * @api public */ Client.prototype.timeout = function(sid, timeout, expected, callback) { - if (!sid) { return; } - var sub = this.subs[sid]; - if (sub === null) { return; } - sub.expected = expected; - var that = this; - sub.timeout = setTimeout(function() { - callback(sid); - // if callback fails unsubscribe will leak - that.unsubscribe(sid); - }, timeout); + if (!sid) { + return; + } + var sub = this.subs[sid]; + if (sub === null) { + return; + } + sub.expected = expected; + var that = this; + sub.timeout = setTimeout(function() { + callback(sid); + // if callback fails unsubscribe will leak + that.unsubscribe(sid); + }, timeout); }; /** @@ -1260,21 +1251,21 @@ Client.prototype.timeout = function(sid, timeout, expected, callback) { * @api public */ Client.prototype.request = function(subject, opt_msg, opt_options, callback) { - if (typeof opt_msg === 'function') { - callback = opt_msg; - opt_msg = EMPTY; - opt_options = null; - } - if (typeof opt_options === 'function') { - callback = opt_options; - opt_options = null; - } - var inbox = createInbox(); - var s = this.subscribe(inbox, opt_options, function(msg, reply) { - callback(msg, reply); - }); - this.publish(subject, opt_msg, inbox); - return s; + if (typeof opt_msg === 'function') { + callback = opt_msg; + opt_msg = EMPTY; + opt_options = null; + } + if (typeof opt_options === 'function') { + callback = opt_options; + opt_options = null; + } + var inbox = createInbox(); + var s = this.subscribe(inbox, opt_options, function(msg, reply) { + callback(msg, reply); + }); + this.publish(subject, opt_msg, inbox); + return s; }; /** @@ -1296,13 +1287,13 @@ Client.prototype.request = function(subject, opt_msg, opt_options, callback) { * @api public */ Client.prototype.requestOne = function(subject, opt_msg, opt_options, timeout, callback) { - opt_options = opt_options || {}; - opt_options.max = 1; - var sid = this.request(subject, opt_msg, opt_options, callback); - this.timeout(sid, timeout, 1, function() { - callback(new NatsError(REQ_TIMEOUT_MSG_PREFIX + sid, REQ_TIMEOUT)); - }); - return sid; + opt_options = opt_options || {}; + opt_options.max = 1; + var sid = this.request(subject, opt_msg, opt_options, callback); + this.timeout(sid, timeout, 1, function() { + callback(new NatsError(REQ_TIMEOUT_MSG_PREFIX + sid, REQ_TIMEOUT)); + }); + return sid; }; /** @@ -1311,9 +1302,8 @@ Client.prototype.requestOne = function(subject, opt_msg, opt_options, timeout, c * @return {Number} * @api public */ - Client.prototype.numSubscriptions = function() { - return Object.keys(this.subs).length; + return Object.keys(this.subs).length; }; /** @@ -1321,14 +1311,15 @@ Client.prototype.numSubscriptions = function() { * * @api private */ - Client.prototype.reconnect = function() { - if (this.closed) { return; } - this.reconnects += 1; - this.createConnection(); - if (this.currentServer.didConnect === true) { - this.emit('reconnecting'); - } + if (this.closed) { + return; + } + this.reconnects += 1; + this.createConnection(); + if (this.currentServer.didConnect === true) { + this.emit('reconnecting'); + } }; /** @@ -1336,22 +1327,23 @@ Client.prototype.reconnect = function() { * * @api private */ - Client.prototype.scheduleReconnect = function() { - var client = this; - // Just return if no more servers - if (client.servers.length === 0) { - return; - } - // Don't set reconnecting state if we are just trying - // for the first time. - if (client.wasConnected === true) { - client.reconnecting = true; - } - // Only stall if we have connected before. - var wait = 0; - if (client.servers[0].didConnect === true) { - wait = this.options.reconnectTimeWait; - } - setTimeout(function() { client.reconnect(); }, wait); + var client = this; + // Just return if no more servers + if (client.servers.length === 0) { + return; + } + // Don't set reconnecting state if we are just trying + // for the first time. + if (client.wasConnected === true) { + client.reconnecting = true; + } + // Only stall if we have connected before. + var wait = 0; + if (client.servers[0].didConnect === true) { + wait = this.options.reconnectTimeWait; + } + setTimeout(function() { + client.reconnect(); + }, wait); }; diff --git a/package.json b/package.json index 0a1aa9da..ec125fd3 100644 --- a/package.json +++ b/package.json @@ -29,13 +29,14 @@ "contributors": [], "main": "./index.js", "scripts": { - "lint": "jshint --reporter node_modules/jshint-stylish lib test examples", "depcheck": "dependency-check . lib/*", "depcheck:unused": "dependency-check ./package.json --unused --no-dev lib/*", "test:unit": "mkdir -p reports/ && NODE_ENV=test multi='spec=- xunit=reports/mocha-xunit.xml' istanbul cover _mocha -- -R mocha-multi --timeout 10000 --slow 750 && istanbul check-coverage", "test": "npm run depcheck && npm run depcheck:unused && npm run lint && npm run test:unit", "coveralls": "npm run cover -- --report lcovonly && cat ./reports/coverage/lcov.info | coveralls", - "cover": "istanbul cover _mocha" + "cover": "istanbul cover _mocha", + "lint": "if-node-version >=4 eslint ./lib ./examples ./benchmark ./test", + "fmt": "js-beautify -n --config crockford.jscsrc -r lib/* test/*.js test/support/*.js examples/* benchmark/*.js" }, "engines": { "node": ">= 0.10.x" @@ -46,7 +47,10 @@ "devDependencies": { "coveralls": "^2.11.2", "dependency-check": "2.5.x", + "eslint": "^3.19.0", + "if-node-version": "^1.1.1", "istanbul": "0.4.x", + "js-beautify": "^1.6.12", "jshint": "2.9.x", "jshint-stylish": "2.2.x", "mocha": "2.5.x", diff --git a/test/.eslintrc b/test/.eslintrc new file mode 100644 index 00000000..81bf887a --- /dev/null +++ b/test/.eslintrc @@ -0,0 +1,19 @@ +{ + "env": { + "node": true + }, + "globals": { + "should" + }, + "rules": { + "no-unused-expressions": "off", + "handle-callback-err": "off", + "no-unused-vars": "off", + "no-invalid-this": "off", + "no-empty-function": "off", + "prefer-rest-params": "off", + "no-sync": "off", + "no-process-env": "off", + "no-console": "off" + } +} diff --git a/test/auth.js b/test/auth.js index 7819da3f..0c0eb85d 100644 --- a/test/auth.js +++ b/test/auth.js @@ -2,120 +2,131 @@ /* global describe: false, before: false, after: false, it: false */ 'use strict'; -var NATS = require ('../'), +var NATS = require('../'), nsc = require('./support/nats_server_control'), should = require('should'); describe('Authorization', function() { - var PORT = 1421; - var flags = ['--user', 'derek', '--pass', 'foobar']; - var authUrl = 'nats://derek:foobar@localhost:' + PORT; - var noAuthUrl = 'nats://localhost:' + PORT; - var server; - - // Start up our own nats-server - before(function(done) { - server = nsc.start_server(PORT, flags, done); - }); - - // Shutdown our server after we are done - after(function(){ - server.kill(); - }); - - it('should fail to connect with no credentials ', function(done) { - var nc = NATS.connect(PORT); - nc.on('error', function(err) { - should.exist(err); - should.exist(/Authorization/.exec(err)); - nc.close(); - done(); + var PORT = 1421; + var flags = ['--user', 'derek', '--pass', 'foobar']; + var authUrl = 'nats://derek:foobar@localhost:' + PORT; + var noAuthUrl = 'nats://localhost:' + PORT; + var server; + + // Start up our own nats-server + before(function(done) { + server = nsc.start_server(PORT, flags, done); }); - }); - - it('should connect with proper credentials in url', function(done) { - var nc = NATS.connect(authUrl); - nc.on('connect', function(/*nc*/) { - setTimeout(function() { - nc.close(); - done(); - }, 100); + + // Shutdown our server after we are done + after(function() { + server.kill(); }); - }); - it('should connect with proper credentials as options', function(done) { - var nc = NATS.connect({'url':noAuthUrl, 'user':'derek', 'pass':'foobar'}); - nc.on('connect', function(/*nc*/) { - setTimeout(function() { + it('should fail to connect with no credentials ', function(done) { + var nc = NATS.connect(PORT); + nc.on('error', function(err) { + should.exist(err); + should.exist(/Authorization/.exec(err)); nc.close(); done(); - }, 100); + }); + }); + + it('should connect with proper credentials in url', function(done) { + var nc = NATS.connect(authUrl); + nc.on('connect', function(nc) { + setTimeout(function() { + nc.close(); + done(); + }, 100); + }); + }); + + it('should connect with proper credentials as options', function(done) { + var nc = NATS.connect({ + 'url': noAuthUrl, + 'user': 'derek', + 'pass': 'foobar' + }); + nc.on('connect', function(nc) { + setTimeout(function() { + nc.close(); + done(); + }, 100); + }); }); - }); - it('should connect with proper credentials as server url', function(done) { - var nc = NATS.connect({'servers':[authUrl]}); - nc.on('connect', function(/*nc*/) { - setTimeout(done, 100); + it('should connect with proper credentials as server url', function(done) { + var nc = NATS.connect({ + 'servers': [authUrl] + }); + nc.on('connect', function(nc) { + setTimeout(done, 100); + }); }); - }); }); describe('Token Authorization', function() { - var PORT = 1421; - var flags = ['--auth', 'token1']; - var authUrl = 'nats://token1@localhost:' + PORT; - var noAuthUrl = 'nats://localhost:' + PORT; - var server; - - // Start up our own nats-server - before(function(done) { - server = nsc.start_server(PORT, flags, done); - }); - - // Shutdown our server after we are done - after(function(){ - server.kill(); - }); - - it('should fail to connect with no credentials ', function(done) { - var nc = NATS.connect(PORT); - nc.on('error', function(err) { - should.exist(err); - should.exist(/Authorization/.exec(err)); - nc.close(); - done(); + var PORT = 1421; + var flags = ['--auth', 'token1']; + var authUrl = 'nats://token1@localhost:' + PORT; + var noAuthUrl = 'nats://localhost:' + PORT; + var server; + + // Start up our own nats-server + before(function(done) { + server = nsc.start_server(PORT, flags, done); }); - }); - - it('should connect with proper credentials in url', function(done) { - var nc = NATS.connect(authUrl); - nc.on('connect', function(/*nc*/) { - setTimeout(function() { - nc.close(); - done(); - }, 100); + + // Shutdown our server after we are done + after(function() { + server.kill(); }); - }); - it('should connect with proper credentials as options', function(done) { - var nc = NATS.connect({'url':noAuthUrl, 'token':'token1'}); - nc.on('connect', function(/*nc*/) { - setTimeout(function() { + it('should fail to connect with no credentials ', function(done) { + var nc = NATS.connect(PORT); + nc.on('error', function(err) { + should.exist(err); + should.exist(/Authorization/.exec(err)); nc.close(); done(); - }, 100); + }); + }); + + it('should connect with proper credentials in url', function(done) { + var nc = NATS.connect(authUrl); + nc.on('connect', function(nc) { + setTimeout(function() { + nc.close(); + done(); + }, 100); + }); + }); + + it('should connect with proper credentials as options', function(done) { + var nc = NATS.connect({ + 'url': noAuthUrl, + 'token': 'token1' + }); + nc.on('connect', function(nc) { + setTimeout(function() { + nc.close(); + done(); + }, 100); + }); }); - }); - it('should connect with proper credentials as server url', function(done) { - var nc = NATS.connect({'servers':[authUrl]}); - nc.on('connect', function(/*nc*/) { - setTimeout(done, 100); + it('should connect with proper credentials as server url', function(done) { + var nc = NATS.connect({ + 'servers': [authUrl] + }); + nc.on('connect', function(nc) { + setTimeout(done, 100); + }); }); - }); }); diff --git a/test/autounsub.js b/test/autounsub.js index 5ecf63a4..c5cd9c78 100644 --- a/test/autounsub.js +++ b/test/autounsub.js @@ -2,183 +2,191 @@ /* global describe: false, before: false, after: false, it: false */ 'use strict'; -var NATS = require ('../'), +var NATS = require('../'), nsc = require('./support/nats_server_control'), should = require('should'); describe('Max responses and Auto-unsub', function() { - var PORT = 1422; - var server; + var PORT = 1422; + var server; - // Start up our own nats-server - before(function(done) { - server = nsc.start_server(PORT, done); - }); - - // Shutdown our server after we are done - after(function(){ - server.kill(); - }); - - it('should only received max responses requested', function(done) { - var nc = NATS.connect(PORT); - var WANT = 10; - var SEND = 20; - var received = 0; - - nc.subscribe('foo', {'max':WANT}, function() { - received += 1; - }); - for (var i=0; i', function() { + received += 1; + if (received === expected) { + nc.close(); + done(); + } + }); + nc.publish('foo.baz'); + nc.publish('foo.baz.foo'); + nc.publish('foo.bar.1'); + nc.publish('foo.bar.2'); + nc.publish('bar'); // miss + nc.publish('foo.bar.3'); }); - nc.publish('foo.baz'); // miss - nc.publish('foo.baz.foo'); // miss - nc.publish('foo'); - nc.publish('bar'); - nc.publish('foo.bar.3'); // miss - nc.publish('baz'); - }); - - it('should do partial wildcard subscriptions correctly', function(done) { - var nc = NATS.connect(PORT); - var expected = 3; - var received = 0; - nc.subscribe('foo.bar.*', function() { - received += 1; - if (received == expected) { - nc.close(); - done(); - } + + it('should pass exact subject to callback', function(done) { + var nc = NATS.connect(PORT); + var subject = 'foo.bar.baz'; + nc.subscribe('*.*.*', function(msg, reply, subj) { + should.exist(subj); + subj.should.equal(subject); + nc.close(); + done(); + }); + nc.publish(subject); }); - nc.publish('foo.baz'); // miss - nc.publish('foo.baz.foo'); // miss - nc.publish('foo.bar.1'); - nc.publish('foo.bar.2'); - nc.publish('bar'); - nc.publish('foo.bar.3'); - }); - - it('should do full wildcard subscriptions correctly', function(done) { - var nc = NATS.connect(PORT); - var expected = 5; - var received = 0; - nc.subscribe('foo.>', function() { - received += 1; - if (received == expected) { - nc.close(); - done(); - } + + it('should do callback after publish is flushed', function(done) { + var nc = NATS.connect(PORT); + nc.publish('foo', function() { + nc.close(); + done(); + }); }); - nc.publish('foo.baz'); - nc.publish('foo.baz.foo'); - nc.publish('foo.bar.1'); - nc.publish('foo.bar.2'); - nc.publish('bar'); // miss - nc.publish('foo.bar.3'); - }); - - it('should pass exact subject to callback', function(done) { - var nc = NATS.connect(PORT); - var subject = 'foo.bar.baz'; - nc.subscribe('*.*.*', function(msg, reply, subj) { - should.exist(subj); - subj.should.equal(subject); - nc.close(); - done(); + + it('should do callback after flush', function(done) { + var nc = NATS.connect(PORT); + nc.flush(function() { + nc.close(); + done(); + }); }); - nc.publish(subject); - }); - it('should do callback after publish is flushed', function(done) { - var nc = NATS.connect(PORT); - nc.publish('foo', function() { + it('should handle an unsubscribe after close of connection', function(done) { + var nc = NATS.connect(PORT); + var sid = nc.subscribe('foo'); nc.close(); + nc.unsubscribe(sid); done(); }); - }); - it('should do callback after flush', function(done) { - var nc = NATS.connect(PORT); - nc.flush(function() { - nc.close(); - done(); - }); - }); - - it('should handle an unsubscribe after close of connection', function(done) { - var nc = NATS.connect(PORT); - var sid = nc.subscribe('foo'); - nc.close(); - nc.unsubscribe(sid); - done(); - }); - - it('should not receive data after unsubscribe call', function(done) { - var nc = NATS.connect(PORT); - var received = 0; - var expected = 1; - - var sid = nc.subscribe('foo', function() { - nc.unsubscribe(sid); - received += 1; + it('should not receive data after unsubscribe call', function(done) { + var nc = NATS.connect(PORT); + var received = 0; + var expected = 1; + + var sid = nc.subscribe('foo', function() { + nc.unsubscribe(sid); + received += 1; + }); + + nc.publish('foo'); + nc.publish('foo'); + nc.publish('foo', function() { + received.should.equal(expected); + nc.close(); + done(); + }); }); - nc.publish('foo'); - nc.publish('foo'); - nc.publish('foo', function() { - received.should.equal(expected); - nc.close(); - done(); - }); - }); - - it('should pass sid properly to a message callback if requested', function(done) { - var nc = NATS.connect(PORT); - var expected = 5; - var received = 0; - var sid = nc.subscribe('foo', function(msg, reply, subj, lsid) { - sid.should.equal(lsid); - nc.close(); - done(); - }); - nc.publish('foo'); - }); - - it('should parse json messages', function(done) { - var config = { - port: PORT, - json: true, - }; - var nc = NATS.connect(config); - var jsonMsg = { - key: true - }; - nc.subscribe('foo1', function(msg) { - msg.should.have.property('key').and.be.a.Boolean(); - nc.close(); - done(); + it('should pass sid properly to a message callback if requested', function(done) { + var nc = NATS.connect(PORT); + var sid = nc.subscribe('foo', function(msg, reply, subj, lsid) { + sid.should.equal(lsid); + nc.close(); + done(); + }); + nc.publish('foo'); }); - nc.publish('foo1', jsonMsg); - }); - - it('should parse UTF8 json messages', function(done) { - var config = { - port: PORT, - json: true - }; - var nc = NATS.connect(config); - var utf8msg = { - key: 'CEDILA-Ç' - }; - nc.subscribe('foo2', function(msg) { - msg.should.have.property('key'); - msg.key.should.equal('CEDILA-Ç'); - nc.close(); - done(); + + it('should parse json messages', function(done) { + var config = { + port: PORT, + json: true, + }; + var nc = NATS.connect(config); + var jsonMsg = { + key: true + }; + nc.subscribe('foo1', function(msg) { + msg.should.have.property('key').and.be.a.Boolean(); + nc.close(); + done(); + }); + nc.publish('foo1', jsonMsg); }); - nc.publish('foo2', utf8msg); - }); - - it('should validate json messages before publishing', function(done) { - var config = { - port: PORT, - json: true - }; - var nc = NATS.connect(config); - var error; - - try { - nc.publish('foo3', 'not JSON'); - } catch (e) { - error = e; - } - if (!error) { - nc.close(); - return done('Should not accept string as message when JSON switch is turned on'); - } - - try { - nc.publish('foo3', 1); - } catch (e) { - error = e; - } - if (!error) { - nc.close(); - return done('Should not accept number as message when JSON switch is turned on'); - } - - try { - nc.publish('foo3', false); - } catch (e) { - error = e; - } - if (!error) { - nc.close(); - return done('Should not accept boolean as message when JSON switch is turned on'); - } - - try { - nc.publish('foo3', []); - } catch (e) { - error = e; - } - if (!error) { - nc.close(); - return done('Should not accept array as message when JSON switch is turned on'); - } - - nc.close(); - done(); - }); - - it('should do requestone-get-reply', function(done) { - var nc = NATS.connect(PORT); - var initMsg = 'Hello World'; - var replyMsg = 'Hello Back!'; - - nc.subscribe('foo', function(msg, reply) { - should.exist(msg); - msg.should.equal(initMsg); - should.exist(reply); - reply.should.match(/_INBOX\.*/); - nc.publish(reply, replyMsg); + + it('should parse UTF8 json messages', function(done) { + var config = { + port: PORT, + json: true + }; + var nc = NATS.connect(config); + var utf8msg = { + key: 'CEDILA-Ç' + }; + nc.subscribe('foo2', function(msg) { + msg.should.have.property('key'); + msg.key.should.equal('CEDILA-Ç'); + nc.close(); + done(); + }); + nc.publish('foo2', utf8msg); }); - var gotOne = false; - nc.requestOne('foo', initMsg, null, 1000, function(reply) { - should.exist(reply); - reply.should.equal(replyMsg); - if(! gotOne) { - gotOne = true; + it('should validate json messages before publishing', function(done) { + var config = { + port: PORT, + json: true + }; + var nc = NATS.connect(config); + var error; + + try { + nc.publish('foo3', 'not JSON'); + } catch (e) { + error = e; + } + if (!error) { + nc.close(); + return done('Should not accept string as message when JSON switch is turned on'); + } + + try { + nc.publish('foo3', 1); + } catch (e) { + error = e; + } + if (!error) { + nc.close(); + return done('Should not accept number as message when JSON switch is turned on'); + } + + try { + nc.publish('foo3', false); + } catch (e) { + error = e; + } + if (!error) { + nc.close(); + return done('Should not accept boolean as message when JSON switch is turned on'); + } + + try { + nc.publish('foo3', []); + } catch (e) { + error = e; + } + if (!error) { + nc.close(); + return done('Should not accept array as message when JSON switch is turned on'); + } + nc.close(); done(); - } }); - }); - - it('should do requestone-will-unsubscribe', function(done) { - this.timeout(3000); - var rsub = "x.y.z"; - var nc = NATS.connect(PORT); - var count = 0; - - nc.subscribe(rsub, function(msg, reply) { - reply.should.match(/_INBOX\.*/); - nc.publish(reply, "y"); - nc.publish(reply, "yy"); - nc.flush(); - setTimeout(function() { - nc.publish(reply, "z"); - nc.flush(); - nc.close(); - setTimeout(function() { - count.should.equal(1); - done(); - }, 1000); - }, 1500); + + it('should do requestone-get-reply', function(done) { + var nc = NATS.connect(PORT); + var initMsg = 'Hello World'; + var replyMsg = 'Hello Back!'; + + nc.subscribe('foo', function(msg, reply) { + should.exist(msg); + msg.should.equal(initMsg); + should.exist(reply); + reply.should.match(/_INBOX\.*/); + nc.publish(reply, replyMsg); + }); + + var gotOne = false; + nc.requestOne('foo', initMsg, null, 1000, function(reply) { + should.exist(reply); + reply.should.equal(replyMsg); + if (!gotOne) { + gotOne = true; + nc.close(); + done(); + } + }); }); - nc.requestOne(rsub, "", null, 1000, function(reply) { - reply.should.not.be.instanceof(NATS.NatsError); - should.exist(reply); - count++; + it('should do requestone-will-unsubscribe', function(done) { + // eslint-disable-next-line + this.timeout(3000); + var rsub = "x.y.z"; + var nc = NATS.connect(PORT); + var count = 0; + + nc.subscribe(rsub, function(msg, reply) { + reply.should.match(/_INBOX\.*/); + nc.publish(reply, "y"); + nc.publish(reply, "yy"); + nc.flush(); + setTimeout(function() { + nc.publish(reply, "z"); + nc.flush(); + nc.close(); + setTimeout(function() { + count.should.equal(1); + done(); + }, 1000); + }, 1500); + }); + + nc.requestOne(rsub, "", null, 1000, function(reply) { + reply.should.not.be.instanceof(NATS.NatsError); + should.exist(reply); + count++; + }); }); - }); - it('should do requestone-can-timeout', function(done) { - var nc = NATS.connect(PORT); - nc.requestOne('a.b.c', '', null, 1000, function(reply) { - should.exist(reply); - reply.should.be.instanceof(NATS.NatsError); - reply.should.have.property('code', NATS.REQ_TIMEOUT); - nc.close(); - done(); - }); - }); - - - it('should unsubscribe when request one timesout', function(done) { - this.timeout(3000); - var nc = NATS.connect(PORT); - - var replies = 0; - var responses = 0; - // set a subscriber to respond to the request - nc.subscribe('a.b.c', {max: 1}, function(msg, reply) { - setTimeout(function() { - nc.publish(reply, ''); - nc.flush(); - replies++; - }, 500); + it('should do requestone-can-timeout', function(done) { + var nc = NATS.connect(PORT); + nc.requestOne('a.b.c', '', null, 1000, function(reply) { + should.exist(reply); + reply.should.be.instanceof(NATS.NatsError); + reply.should.have.property('code', NATS.REQ_TIMEOUT); + nc.close(); + done(); + }); }); - // request one - we expect a timeout - nc.requestOne('a.b.c', '', null, 250, function(reply) { - reply.should.be.instanceof(NATS.NatsError); - reply.should.have.property('code', NATS.REQ_TIMEOUT); - if(! reply.hasOwnProperty('code')) { - responses++; - } - }); - // verify reply was sent, but we didn't get it - setTimeout(function() { - should(replies).equal(1); - should(responses).equal(0); - done(); - },1000); - }); + it('should unsubscribe when request one timesout', function(done) { + // eslint-disable-next-line + this.timeout(3000); + var nc = NATS.connect(PORT); + + var replies = 0; + var responses = 0; + // set a subscriber to respond to the request + nc.subscribe('a.b.c', { + max: 1 + }, function(msg, reply) { + setTimeout(function() { + nc.publish(reply, ''); + nc.flush(); + replies++; + }, 500); + }); + + // request one - we expect a timeout + nc.requestOne('a.b.c', '', null, 250, function(reply) { + reply.should.be.instanceof(NATS.NatsError); + reply.should.have.property('code', NATS.REQ_TIMEOUT); + if (!reply.hasOwnProperty('code')) { + responses++; + } + }); + + // verify reply was sent, but we didn't get it + setTimeout(function() { + should(replies).equal(1); + should(responses).equal(0); + done(); + }, 1000); + }); }); diff --git a/test/binary.js b/test/binary.js index a4be8628..14b39a68 100644 --- a/test/binary.js +++ b/test/binary.js @@ -2,148 +2,157 @@ /* global describe: false, before: false, after: false, it: false */ 'use strict'; -var NATS = require ('../'), +var NATS = require('../'), nsc = require('./support/nats_server_control'), crypto = require('crypto'), should = require('should'); describe('Binary', function() { - var PORT = 1432; - var server; - - // Start up our own nats-server - before(function(done) { - server = nsc.start_server(PORT, done); - }); - - // Shutdown our server - after(function() { - server.kill(); - }); - - - function binaryDataTests(done, nc) { - // try some invalid utf-8 byte sequences - var invalid2octet = new Buffer('\xc3\x28', 'binary'); - var invalidsequenceidentifier = new Buffer('\xa0\xa1', 'binary'); - var invalid3octet = new Buffer('\xe2\x28\xa1', 'binary'); - var invalid4octet = new Buffer('\xf0\x90\x28\xbc', 'binary'); - var bigBuffer = crypto.randomBytes(128*1024); - - // make sure embedded nulls don't cause truncation - var embeddednull = new Buffer('\x00\xf0\x00\x28\x00\x00\xf0\x9f\x92\xa9\x00', 'binary'); - - var count = 6; - var finished = function() { - if (--count <= 0) { - nc.close(); - done(); - } - }; - - nc.subscribe('invalid2octet', function(msg) { - msg.length.should.equal(2); - if(nc.options.preserveBuffers) { - should.ok(invalid2octet.equals(msg)); - } else { - msg.should.equal(invalid2octet.toString('binary')); - } - finished(); - }); + var PORT = 1432; + var server; - nc.subscribe('invalidsequenceidentifier', function(msg) { - msg.length.should.equal(2); - if(nc.options.preserveBuffers) { - should.ok(invalidsequenceidentifier.equals(msg)); - } else { - msg.should.equal(invalidsequenceidentifier.toString('binary')); - } - finished(); + // Start up our own nats-server + before(function(done) { + server = nsc.start_server(PORT, done); }); - nc.subscribe('invalid3octet', function(msg) { - msg.length.should.equal(3); - if(nc.options.preserveBuffers) { - should.ok(invalid3octet.equals(msg)); - } else { - msg.should.equal(invalid3octet.toString('binary')); - } - finished(); + // Shutdown our server + after(function() { + server.kill(); }); - nc.subscribe('invalid4octet', function(msg) { - msg.length.should.equal(4); - if(nc.options.preserveBuffers) { - should.ok(invalid4octet.equals(msg)); - } else { - msg.should.equal(invalid4octet.toString('binary')); - } - finished(); - }); - nc.subscribe('embeddednull', function(msg) { - msg.length.should.equal(11); - if(nc.options.preserveBuffers) { - should.ok(embeddednull.equals(msg)); - } else { - msg.should.equal(embeddednull.toString('binary')); - } - finished(); + function binaryDataTests(done, nc) { + // try some invalid utf-8 byte sequences + var invalid2octet = new Buffer('\xc3\x28', 'binary'); + var invalidsequenceidentifier = new Buffer('\xa0\xa1', 'binary'); + var invalid3octet = new Buffer('\xe2\x28\xa1', 'binary'); + var invalid4octet = new Buffer('\xf0\x90\x28\xbc', 'binary'); + var bigBuffer = crypto.randomBytes(128 * 1024); + + // make sure embedded nulls don't cause truncation + var embeddednull = new Buffer('\x00\xf0\x00\x28\x00\x00\xf0\x9f\x92\xa9\x00', 'binary'); + + var count = 6; + var finished = function() { + if (--count <= 0) { + nc.close(); + done(); + } + }; + + nc.subscribe('invalid2octet', function(msg) { + msg.length.should.equal(2); + if (nc.options.preserveBuffers) { + should.ok(invalid2octet.equals(msg)); + } else { + msg.should.equal(invalid2octet.toString('binary')); + } + finished(); + }); + + nc.subscribe('invalidsequenceidentifier', function(msg) { + msg.length.should.equal(2); + if (nc.options.preserveBuffers) { + should.ok(invalidsequenceidentifier.equals(msg)); + } else { + msg.should.equal(invalidsequenceidentifier.toString('binary')); + } + finished(); + }); + + nc.subscribe('invalid3octet', function(msg) { + msg.length.should.equal(3); + if (nc.options.preserveBuffers) { + should.ok(invalid3octet.equals(msg)); + } else { + msg.should.equal(invalid3octet.toString('binary')); + } + finished(); + }); + + nc.subscribe('invalid4octet', function(msg) { + msg.length.should.equal(4); + if (nc.options.preserveBuffers) { + should.ok(invalid4octet.equals(msg)); + } else { + msg.should.equal(invalid4octet.toString('binary')); + } + finished(); + }); + + nc.subscribe('embeddednull', function(msg) { + msg.length.should.equal(11); + if (nc.options.preserveBuffers) { + should.ok(embeddednull.equals(msg)); + } else { + msg.should.equal(embeddednull.toString('binary')); + } + finished(); + }); + + nc.subscribe('bigbuffer', function(msg) { + msg.length.should.equal(bigBuffer.length); + if (nc.options.preserveBuffers) { + should.ok(bigBuffer.equals(msg)); + } else { + msg.should.equal(bigBuffer.toString('binary')); + } + finished(); + }); + + + nc.publish('invalid2octet', invalid2octet); + nc.publish('invalidsequenceidentifier', invalidsequenceidentifier); + nc.publish('invalid3octet', invalid3octet); + nc.publish('invalid4octet', invalid4octet); + nc.publish('embeddednull', embeddednull); + nc.publish('bigbuffer', bigBuffer); + } + + it('should allow sending and receiving binary data', function(done) { + var nc = NATS.connect({ + 'url': 'nats://localhost:' + PORT, + 'encoding': 'binary' + }); + binaryDataTests(done, nc); }); - nc.subscribe('bigbuffer', function(msg) { - msg.length.should.equal(bigBuffer.length); - if(nc.options.preserveBuffers) { - should.ok(bigBuffer.equals(msg)); - } else { - msg.should.equal(bigBuffer.toString('binary')); - } - finished(); + it('should allow sending binary buffers', function(done) { + var nc = NATS.connect({ + 'url': 'nats://localhost:' + PORT, + 'preserveBuffers': true + }); + binaryDataTests(done, nc); }); + it('should not append control characters on chunk processing', function(done) { + var nc = NATS.connect({ + 'url': 'nats://localhost:' + PORT, + 'preserveBuffers': true + }); + var buffer = crypto.randomBytes(1024); - nc.publish('invalid2octet', invalid2octet); - nc.publish('invalidsequenceidentifier', invalidsequenceidentifier); - nc.publish('invalid3octet', invalid3octet); - nc.publish('invalid4octet', invalid4octet); - nc.publish('embeddednull', embeddednull); - nc.publish('bigbuffer', bigBuffer); - } - - it('should allow sending and receiving binary data', function(done) { - var nc = NATS.connect({'url': 'nats://localhost:' + PORT, 'encoding': 'binary'}); - binaryDataTests(done, nc); - }); - - it('should allow sending binary buffers', function(done) { - var nc = NATS.connect({'url': 'nats://localhost:' + PORT, 'preserveBuffers': true}); - binaryDataTests(done, nc); - }); - - it('should not append control characters on chunk processing', function(done) { - var nc = NATS.connect({ 'url': 'nats://localhost:' + PORT, 'preserveBuffers': true }); - var buffer = crypto.randomBytes(1024); - - var count = 0; - var finished = function () { - - if (++count == 100) { - nc.close(); - done(); - } - }; - - nc.subscribe('trailingData', function (msg) { - should.ok(msg.equals(buffer)); - finished(); - }); + var count = 0; + var finished = function() { - for (var i = 0; i <= 100; i++) { - - nc.publish('trailingData', buffer); - } + if (++count === 100) { + nc.close(); + done(); + } + }; + + nc.subscribe('trailingData', function(msg) { + should.ok(msg.equals(buffer)); + finished(); + }); + + for (var i = 0; i <= 100; i++) { - }); + nc.publish('trailingData', buffer); + } + + }); -}); \ No newline at end of file +}); diff --git a/test/buffer.js b/test/buffer.js index 8463e24a..a87b4512 100644 --- a/test/buffer.js +++ b/test/buffer.js @@ -6,22 +6,22 @@ var NATS = require('../'), nsc = require('./support/nats_server_control'), should = require('should'); -describe('Buffer', function () { +describe('Buffer', function() { var PORT = 1432; var server; // Start up our own nats-server - before(function (done) { + before(function(done) { server = nsc.start_server(PORT, done); }); // Shutdown our server - after(function () { + after(function() { server.kill(); }); - it('should allow sending and receiving raw buffers', function (done) { + it('should allow sending and receiving raw buffers', function(done) { var nc = NATS.connect({ 'url': 'nats://localhost:' + PORT, 'preserveBuffers': true @@ -29,7 +29,7 @@ describe('Buffer', function () { var validBuffer = new Buffer('foo-bar'); - nc.subscribe('validBuffer', function (msg) { + nc.subscribe('validBuffer', function(msg) { should(validBuffer.equals(msg)).equal(true); nc.close(); @@ -40,7 +40,7 @@ describe('Buffer', function () { }); - it('should allow parsing raw buffers to json', function (done) { + it('should allow parsing raw buffers to json', function(done) { var nc = NATS.connect({ 'url': 'nats://localhost:' + PORT, 'preserveBuffers': true, @@ -50,9 +50,11 @@ describe('Buffer', function () { var jsonString = '{ "foo-bar": true }'; var validBuffer = new Buffer(jsonString); - nc.subscribe('validBuffer', function (msg) { + nc.subscribe('validBuffer', function(msg) { - msg.should.eql({ "foo-bar": true }); + msg.should.eql({ + "foo-bar": true + }); nc.close(); done(); }); @@ -60,4 +62,4 @@ describe('Buffer', function () { nc.publish('validBuffer', validBuffer); }); -}); \ No newline at end of file +}); diff --git a/test/callbacks.js b/test/callbacks.js index 5ea6b4a6..a3dc74c3 100644 --- a/test/callbacks.js +++ b/test/callbacks.js @@ -2,41 +2,41 @@ /* global describe: false, before: false, after: false, it: false */ 'use strict'; -var NATS = require ('../'), +var NATS = require('../'), nsc = require('./support/nats_server_control'), should = require('should'); describe('Callbacks', function() { - var PORT = 1429; - var server; - - // Start up our own nats-server - before(function(done) { - server = nsc.start_server(PORT, done); - }); - - // Shutdown our server - after(function() { - server.kill(); - }); - - it('should properly do a publish callback after connection is closed', function(done) { - var nc = NATS.connect(PORT); - nc.close(); - nc.publish('foo', function(err) { - should.exist(err); - done(); + var PORT = 1429; + var server; + + // Start up our own nats-server + before(function(done) { + server = nsc.start_server(PORT, done); + }); + + // Shutdown our server + after(function() { + server.kill(); }); - }); - - it('should properly do a flush callback after connection is closed', function(done) { - var nc = NATS.connect(PORT); - nc.close(); - nc.flush(function(err) { - should.exist(err); - done(); + + it('should properly do a publish callback after connection is closed', function(done) { + var nc = NATS.connect(PORT); + nc.close(); + nc.publish('foo', function(err) { + should.exist(err); + done(); + }); + }); + + it('should properly do a flush callback after connection is closed', function(done) { + var nc = NATS.connect(PORT); + nc.close(); + nc.flush(function(err) { + should.exist(err); + done(); + }); }); - }); }); diff --git a/test/cluster.js b/test/cluster.js index f0006079..3664618e 100644 --- a/test/cluster.js +++ b/test/cluster.js @@ -3,153 +3,172 @@ /* jshint -W030 */ 'use strict'; -var NATS = require ('../'), +var NATS = require('../'), nsc = require('./support/nats_server_control'), should = require('should'), - url = require('url'); + url = require('url'); describe('Cluster', function() { - var WAIT = 20; - var ATTEMPTS = 4; + var WAIT = 20; + var ATTEMPTS = 4; - var PORT1 = 15621; - var PORT2 = 15622; + var PORT1 = 15621; + var PORT2 = 15622; - var s1Url = 'nats://localhost:' + PORT1; - var s2Url = 'nats://localhost:' + PORT2; + var s1Url = 'nats://localhost:' + PORT1; + var s2Url = 'nats://localhost:' + PORT2; - var s1; - var s2; + var s1; + var s2; - // Start up our own nats-server - before(function(done) { - s1 = nsc.start_server(PORT1, function() { - s2 = nsc.start_server(PORT2, function() { - done(); - }); - }); - }); - - // Shutdown our server - after(function() { - s1.kill(); - s2.kill(); - }); - - it('should accept servers options', function(done) { - var nc = NATS.connect({'servers':[s1Url, s2Url]}); - should.exists(nc); - nc.should.have.property('options'); - nc.options.should.have.property('servers'); - nc.should.have.property('servers'); - nc.servers.should.be.a.Array; - nc.should.have.property('url'); - nc.flush(function() { - nc.close(); - done(); + // Start up our own nats-server + before(function(done) { + s1 = nsc.start_server(PORT1, function() { + s2 = nsc.start_server(PORT2, function() { + done(); + }); + }); }); - }); - - it('should randomly connect to servers by default', function(done) { - var conns = []; - var s1Count = 0; - for (var i=0; i<100; i++) { - var nc = NATS.connect({'servers':[s1Url, s2Url]}); - conns.push(nc); - var nurl = url.format(nc.url); - if (nurl == s1Url) { - s1Count++; - } - } - for (i=0; i<100; i++) { - conns[i].close(); - } - s1Count.should.be.within(35, 65); - done(); - }); - - it('should connect to first valid server', function(done) { - var nc = NATS.connect({'servers':['nats://localhost:' + 21022, s1Url, s2Url]}); - nc.on('error', function(err) { - done(err); + + // Shutdown our server + after(function() { + s1.kill(); + s2.kill(); }); - nc.on('connect', function() { - nc.close(); - done(); + + it('should accept servers options', function(done) { + var nc = NATS.connect({ + 'servers': [s1Url, s2Url] + }); + should.exists(nc); + nc.should.have.property('options'); + nc.options.should.have.property('servers'); + nc.should.have.property('servers'); + nc.servers.should.be.a.Array; + nc.should.have.property('url'); + nc.flush(function() { + nc.close(); + done(); + }); }); - }); - it('should emit error if no servers are available', function(done) { - var nc = NATS.connect({'servers':['nats://localhost:' + 21022, 'nats://localhost:' + 21023]}); - nc.on('error', function(/*err*/) { - nc.close(); - done(); + it('should randomly connect to servers by default', function(done) { + var conns = []; + var s1Count = 0; + for (var i = 0; i < 100; i++) { + var nc = NATS.connect({ + 'servers': [s1Url, s2Url] + }); + conns.push(nc); + var nurl = url.format(nc.url); + if (nurl === s1Url) { + s1Count++; + } + } + for (i = 0; i < 100; i++) { + conns[i].close(); + } + s1Count.should.be.within(35, 65); + done(); }); - nc.on('reconnecting', function(/*err*/) { - // This is an error - done('Should not receive a reconnect event'); + + it('should connect to first valid server', function(done) { + var nc = NATS.connect({ + 'servers': ['nats://localhost:' + 21022, s1Url, s2Url] + }); + nc.on('error', function(err) { + done(err); + }); + nc.on('connect', function() { + nc.close(); + done(); + }); }); - }); - - it('should not randomly connect to servers if noRandomize is set', function(done) { - var conns = []; - var s1Count = 0; - for (var i=0; i<100; i++) { - var nc = NATS.connect({'noRandomize': true, 'servers':[s1Url, s2Url]}); - conns.push(nc); - var nurl = url.format(nc.url); - if (nurl == s1Url) { - s1Count++; - } - } - for (i=0; i<100; i++) { - conns[i].close(); - } - s1Count.should == 100; - done(); - }); - - it('should not randomly connect to servers if dontRandomize is set', function(done) { - var conns = []; - var s1Count = 0; - for (var i=0; i<100; i++) { - var nc = NATS.connect({'dontRandomize': true, 'servers':[s1Url, s2Url]}); - conns.push(nc); - var nurl = url.format(nc.url); - if (nurl == s1Url) { - s1Count++; - } - } - for (i=0; i<100; i++) { - conns[i].close(); - } - s1Count.should == 100; - done(); - }); - - it('should fail after maxReconnectAttempts when servers killed', function(done) { - var nc = NATS.connect({'noRandomize': true, 'servers':[s1Url, s2Url], 'reconnectTimeWait':WAIT, 'maxReconnectAttempts':ATTEMPTS}); - var startTime; - var numAttempts = 0; - nc.on('connect', function() { - s1.kill(); - startTime = new Date(); + + it('should emit error if no servers are available', function(done) { + var nc = NATS.connect({ + 'servers': ['nats://localhost:' + 21022, 'nats://localhost:' + 21023] + }); + nc.on('error', function(err) { + nc.close(); + done(); + }); + nc.on('reconnecting', function(err) { + // This is an error + done('Should not receive a reconnect event'); + }); }); - nc.on('reconnect', function() { - s2.kill(); + + it('should not randomly connect to servers if noRandomize is set', function(done) { + var conns = []; + var s1Count = 0; + for (var i = 0; i < 100; i++) { + var nc = NATS.connect({ + 'noRandomize': true, + 'servers': [s1Url, s2Url] + }); + conns.push(nc); + var nurl = url.format(nc.url); + if (nurl === s1Url) { + s1Count++; + } + } + for (i = 0; i < 100; i++) { + conns[i].close(); + } + s1Count.should.equal(100); + done(); }); - nc.on('reconnecting', function(/*client*/) { - var elapsed = new Date() - startTime; - elapsed.should.be.within(WAIT, 5*WAIT); - startTime = new Date(); - numAttempts += 1; + + it('should not randomly connect to servers if dontRandomize is set', function(done) { + var conns = []; + var s1Count = 0; + for (var i = 0; i < 100; i++) { + var nc = NATS.connect({ + 'dontRandomize': true, + 'servers': [s1Url, s2Url] + }); + conns.push(nc); + var nurl = url.format(nc.url); + if (nurl == s1Url) { + s1Count++; + } + } + for (i = 0; i < 100; i++) { + conns[i].close(); + } + s1Count.should == 100; + done(); }); - nc.on('close', function() { - numAttempts.should.equal(ATTEMPTS); - nc.close(); - done(); + + it('should fail after maxReconnectAttempts when servers killed', function(done) { + var nc = NATS.connect({ + 'noRandomize': true, + 'servers': [s1Url, s2Url], + 'reconnectTimeWait': WAIT, + 'maxReconnectAttempts': ATTEMPTS + }); + var startTime; + var numAttempts = 0; + nc.on('connect', function() { + s1.kill(); + startTime = new Date(); + }); + nc.on('reconnect', function() { + s2.kill(); + }); + nc.on('reconnecting', function(client) { + var elapsed = new Date() - startTime; + elapsed.should.be.within(WAIT, 5 * WAIT); + startTime = new Date(); + numAttempts += 1; + }); + nc.on('close', function() { + numAttempts.should.equal(ATTEMPTS); + nc.close(); + done(); + }); }); - }); }); diff --git a/test/connect.js b/test/connect.js index 3a9b661c..772bc44b 100644 --- a/test/connect.js +++ b/test/connect.js @@ -2,137 +2,154 @@ /* global describe: false, before: false, after: false, it: false */ 'use strict'; -var NATS = require ('../'), +var NATS = require('../'), nsc = require('./support/nats_server_control'), should = require('should'); describe('Basic Connectivity', function() { - var PORT = 1424; - var uri = 'nats://localhost:' + PORT; - var server; - - // Start up our own nats-server - before(function(done) { - server = nsc.start_server(PORT, done); - }); - - // Shutdown our server after we are done - after(function(){ - server.kill(); - }); - - - it('should perform basic connect with port', function(){ - var nc = NATS.connect(PORT); - should.exist(nc); - nc.close(); - }); - - it('should perform basic connect with uri', function(){ - var nc = NATS.connect(uri); - should.exist(nc); - nc.close(); - }); - - it('should perform basic connect with options arg', function(){ - var options = { 'uri' : uri }; - var nc = NATS.connect(options); - should.exist(nc); - nc.close(); - }); - - it('should emit a connect event', function(done){ - var nc = NATS.connect(PORT); - nc.on('connect', function(client) { - client.should.equal(nc); - nc.close(); - done(); + var PORT = 1424; + var uri = 'nats://localhost:' + PORT; + var server; + + // Start up our own nats-server + before(function(done) { + server = nsc.start_server(PORT, done); + }); + + // Shutdown our server after we are done + after(function() { + server.kill(); + }); + + + it('should perform basic connect with port', function() { + var nc = NATS.connect(PORT); + should.exist(nc); + nc.close(); + }); + + it('should perform basic connect with uri', function() { + var nc = NATS.connect(uri); + should.exist(nc); + nc.close(); + }); + + it('should perform basic connect with options arg', function() { + var options = { + 'uri': uri + }; + var nc = NATS.connect(options); + should.exist(nc); + nc.close(); }); - }); - it('should emit error if no server available', function(done){ - var nc = NATS.connect('nats://localhost:22222'); - nc.on('error', function() { - nc.close(); - done(); + it('should emit a connect event', function(done) { + var nc = NATS.connect(PORT); + nc.on('connect', function(client) { + client.should.equal(nc); + nc.close(); + done(); + }); }); - }); - - it('should emit connecting events and try repeatedly if configured and no server available', function(done){ - var nc = NATS.connect({'uri':'nats://localhost:22222', - 'waitOnFirstConnect': true, - 'reconnectTimeWait':100, - 'maxReconnectAttempts':20}); - var connectingEvents = 0; - nc.on('error', function() { - nc.close(); - done('should not have produced error'); + + it('should emit error if no server available', function(done) { + var nc = NATS.connect('nats://localhost:22222'); + nc.on('error', function() { + nc.close(); + done(); + }); }); - nc.on('reconnecting', function() { - connectingEvents++; + + it('should emit connecting events and try repeatedly if configured and no server available', function(done) { + var nc = NATS.connect({ + 'uri': 'nats://localhost:22222', + 'waitOnFirstConnect': true, + 'reconnectTimeWait': 100, + 'maxReconnectAttempts': 20 + }); + var connectingEvents = 0; + nc.on('error', function() { + nc.close(); + done('should not have produced error'); + }); + nc.on('reconnecting', function() { + connectingEvents++; + }); + setTimeout(function() { + connectingEvents.should.equal(5); + done(); + }, 550); }); - setTimeout(function(){ - connectingEvents.should.equal(5); - done(); - }, 550); - }); - - - it('should still receive publish when some servers are invalid', function(done){ - var natsServers = ['nats://localhost:22222', uri, 'nats://localhost:22223']; - var ua = NATS.connect({servers: natsServers}); - var ub = NATS.connect({servers: natsServers}); - var recvMsg = ''; - ua.subscribe('topic1', function(msg, reply, subject){ - recvMsg = msg; + + + it('should still receive publish when some servers are invalid', function(done) { + var natsServers = ['nats://localhost:22222', uri, 'nats://localhost:22223']; + var ua = NATS.connect({ + servers: natsServers + }); + var ub = NATS.connect({ + servers: natsServers + }); + var recvMsg = ''; + ua.subscribe('topic1', function(msg, reply, subject) { + recvMsg = msg; + }); + setTimeout(function() { + ub.publish('topic1', 'hello'); + }, 100 * 1); + setTimeout(function() { + recvMsg.should.equal('hello'); + ua.close(); + ub.close(); + done(); + }, 100 * 2); }); - setTimeout(function(){ - ub.publish('topic1', 'hello'); - }, 100 * 1); - setTimeout(function(){ - recvMsg.should.equal('hello'); - ua.close(); - ub.close(); - done(); - }, 100 * 2); - }); - - - it('should still receive publish when some servers[noRandomize] are invalid', function(done){ - var natsServers = ['nats://localhost:22222', uri, 'nats://localhost:22223']; - var ua = NATS.connect({servers: natsServers, noRandomize:true}); - var ub = NATS.connect({servers: natsServers, noRandomize:true}); - var recvMsg = ""; - ua.subscribe('topic1', function(msg, reply, subject){ - recvMsg = msg; + + + it('should still receive publish when some servers[noRandomize] are invalid', function(done) { + var natsServers = ['nats://localhost:22222', uri, 'nats://localhost:22223']; + var ua = NATS.connect({ + servers: natsServers, + noRandomize: true + }); + var ub = NATS.connect({ + servers: natsServers, + noRandomize: true + }); + var recvMsg = ""; + ua.subscribe('topic1', function(msg, reply, subject) { + recvMsg = msg; + }); + setTimeout(function() { + ub.publish('topic1', 'hello'); + }, 100 * 1); + setTimeout(function() { + recvMsg.should.equal('hello'); + ua.close(); + ub.close(); + done(); + }, 100 * 2); }); - setTimeout(function(){ - ub.publish('topic1', 'hello'); - }, 100 * 1); - setTimeout(function(){ - recvMsg.should.equal('hello'); - ua.close(); - ub.close(); - done(); - }, 100 * 2); - }); - - - it('should add a new cluster server', function(done){ - var servers = [uri,'nats://localhost:22223']; - var nc = NATS.connect({servers: new Array(servers[0])}); - var contains = 0; - - nc.on('connect', function(client) { - client.addServer(servers[1]); - client.servers.forEach(function(_server) { - if (servers.indexOf(_server.url.href) !== -1) - contains++; - }); - contains.should.equal(servers.length); - done(); + + + it('should add a new cluster server', function(done) { + var servers = [uri, 'nats://localhost:22223']; + var nc = NATS.connect({ + servers: new Array(servers[0]) + }); + var contains = 0; + + nc.on('connect', function(client) { + client.addServer(servers[1]); + client.servers.forEach(function(_server) { + if (servers.indexOf(_server.url.href) !== -1) { + contains++; + } + }); + contains.should.equal(servers.length); + done(); + }); }); - }); }); diff --git a/test/dsub.js b/test/dsub.js index 0418ba7b..9c1aff6b 100644 --- a/test/dsub.js +++ b/test/dsub.js @@ -2,47 +2,47 @@ /* global describe: false, before: false, after: false, it: false */ 'use strict'; -var NATS = require ('../'), +var NATS = require('../'), nsc = require('./support/nats_server_control'), should = require('should'); describe('Double SUBS', function() { - var PORT = 1922; - var flags = ['-DV']; - var server; - - // Start up our own nats-server - before(function(done) { - server = nsc.start_server(PORT, flags, done); - }); - - // Shutdown our server after we are done - after(function(){ - server.kill(); - }); - - it('should not send multiple subscriptions on startup', function(done) { - var subsSeen = 0; - var subRe = /(\[SUB foo \d\])+/g; - - // Capture log output from nats-server and check for double SUB protos. - server.stderr.on('data', function(data) { - var m; - while ((m = subRe.exec(data)) !== null) { - subsSeen ++; - } + var PORT = 1922; + var flags = ['-DV']; + var server; + + // Start up our own nats-server + before(function(done) { + server = nsc.start_server(PORT, flags, done); + }); + + // Shutdown our server after we are done + after(function() { + server.kill(); }); - var nc = NATS.connect(PORT); - nc.subscribe('foo'); - nc.on('connect', function(/*nc*/) { - setTimeout(function() { - nc.close(); - subsSeen.should.equal(1); - done(); - }, 100); + it('should not send multiple subscriptions on startup', function(done) { + var subsSeen = 0; + var subRe = /(\[SUB foo \d\])+/g; + + // Capture log output from nats-server and check for double SUB protos. + server.stderr.on('data', function(data) { + var m; + while ((m = subRe.exec(data)) !== null) { + subsSeen++; + } + }); + + var nc = NATS.connect(PORT); + nc.subscribe('foo'); + nc.on('connect', function(nc) { + setTimeout(function() { + nc.close(); + subsSeen.should.equal(1); + done(); + }, 100); + }); }); - }); }); diff --git a/test/dyncluster.js b/test/dyncluster.js index 3edc46ec..9b428adf 100644 --- a/test/dyncluster.js +++ b/test/dyncluster.js @@ -4,47 +4,50 @@ 'use strict'; var NATS = require('../'), -nsc = require('./support/nats_server_control'), -ncu = require('./support/nats_conf_utils'), -should = require('should'), -path = require('path'), -os = require('os'), -fs = require('fs'), -nuid = require('nuid'); + nsc = require('./support/nats_server_control'), + ncu = require('./support/nats_conf_utils'), + should = require('should'), + path = require('path'), + os = require('os'), + fs = require('fs'), + nuid = require('nuid'); -describe('Dynamic Cluster - Connect URLs', function () { +describe('Dynamic Cluster - Connect URLs', function() { this.timeout(10000); // this to enable per test cleanup var servers; // Shutdown our servers - afterEach(function () { + afterEach(function() { nsc.stop_cluster(servers); servers = []; }); - it('adding cluster performs update', function (done) { + it('adding cluster performs update', function(done) { var route_port = 54220; var port = 54221; // start a new cluster with single server - servers = nsc.start_cluster([port], route_port, function () { + servers = nsc.start_cluster([port], route_port, function() { should(servers.length).be.equal(1); // connect the client - var nc = NATS.connect({'port': port, 'reconnectTimeWait': 100}); - nc.on('connect', function () { + var nc = NATS.connect({ + 'port': port, + 'reconnectTimeWait': 100 + }); + nc.on('connect', function() { // start adding servers - process.nextTick(function () { - var others = nsc.add_member_with_delay([port + 1, port + 2], route_port, 250, function () { + process.nextTick(function() { + var others = nsc.add_member_with_delay([port + 1, port + 2], route_port, 250, function() { // verify that 2 servers were added should(others.length).be.equal(2); - others.forEach(function (o) { + others.forEach(function(o) { // add them so they can be reaped servers.push(o); }); // give some time for the server to send infos - setTimeout(function () { + setTimeout(function() { // we should know of 3 servers - the one we connected and the 2 we added should(nc.servers.length).be.equal(3); done(); @@ -55,7 +58,7 @@ describe('Dynamic Cluster - Connect URLs', function () { }); }); - it('added servers are shuffled at the end of the list', function (done) { + it('added servers are shuffled at the end of the list', function(done) { var route_port = 54320; var port = 54321; // start a cluster of one server @@ -64,16 +67,19 @@ describe('Dynamic Cluster - Connect URLs', function () { ports.push(port + i); } var map = {}; - servers = nsc.start_cluster(ports, route_port, function () { + servers = nsc.start_cluster(ports, route_port, function() { should(servers.length).be.equal(10); var connectCount = 0; function connectAndRecordPorts(check) { - var nc = NATS.connect({'port': port, 'reconnectTimeWait': 100}); - nc.on('connect', function () { + var nc = NATS.connect({ + 'port': port, + 'reconnectTimeWait': 100 + }); + nc.on('connect', function() { var have = []; - nc.servers.forEach(function (s) { + nc.servers.forEach(function(s) { have.push(s.url.port); }); @@ -102,7 +108,7 @@ describe('Dynamic Cluster - Connect URLs', function () { }); }); - it('added servers not shuffled when noRandomize is set', function (done) { + it('added servers not shuffled when noRandomize is set', function(done) { var route_port = 54320; var port = 54321; // start a cluster of one server @@ -111,16 +117,20 @@ describe('Dynamic Cluster - Connect URLs', function () { ports.push(port + i); } var map = {}; - servers = nsc.start_cluster(ports, route_port, function () { + servers = nsc.start_cluster(ports, route_port, function() { should(servers.length).be.equal(10); var connectCount = 0; function connectAndRecordPorts(check) { - var nc = NATS.connect({'port': port, 'reconnectTimeWait': 100, 'noRandomize': true}); - nc.on('connect', function () { + var nc = NATS.connect({ + 'port': port, + 'reconnectTimeWait': 100, + 'noRandomize': true + }); + nc.on('connect', function() { var have = []; - nc.servers.forEach(function (s) { + nc.servers.forEach(function(s) { have.push(s.url.port); }); @@ -150,11 +160,11 @@ describe('Dynamic Cluster - Connect URLs', function () { }); }); - it('error connecting raises error and closes', function (done) { + it('error connecting raises error and closes', function(done) { reconnectTest(55421, 55420, true, done); }); - it('error connecting raises error and closes - non tls', function (done) { + it('error connecting raises error and closes - non tls', function(done) { reconnectTest(55521, 55520, false, done); }); @@ -182,25 +192,25 @@ describe('Dynamic Cluster - Connect URLs', function () { // write two normal configs var normal = JSON.parse(JSON.stringify(config)); var normal_conf = path.resolve(os.tmpdir(), 'normalauth_' + nuid.next() + '.conf'); - ncu.writeFile(normal_conf, ncu.JsonToYaml(normal)); + ncu.writeFile(normal_conf, ncu.j(normal)); // one that has bad timeout var short = JSON.parse(JSON.stringify(normal)); - if(use_certs) { + if (use_certs) { short.tls.timeout = 0.0001; } short.authorization.timeout = 0.0001; var short_conf = path.resolve(os.tmpdir(), 'shortconf_' + nuid.next() + '.conf'); - ncu.writeFile(short_conf, ncu.JsonToYaml(short)); + ncu.writeFile(short_conf, ncu.j(short)); // start a new cluster with single server - servers = nsc.start_cluster([port], route_port, ['-c', normal_conf], function () { - process.nextTick(function () { - var others = nsc.add_member_with_delay([port + 1], route_port, 250, ['-c', short_conf], function () { + servers = nsc.start_cluster([port], route_port, ['-c', normal_conf], function() { + process.nextTick(function() { + var others = nsc.add_member_with_delay([port + 1], route_port, 250, ['-c', short_conf], function() { // add the second server servers.push(others[0]); - process.nextTick(function () { + process.nextTick(function() { startClient(); }); }); @@ -220,39 +230,39 @@ describe('Dynamic Cluster - Connect URLs', function () { rejectUnauthorized: false } }; - if(! use_certs) { + if (!use_certs) { delete opts.tls; } var nc = NATS.connect(opts); var connected = false; - nc.on('connect', function (c) { + nc.on('connect', function(c) { if (!connected) { // should(nc.servers.length).be.equal(2); // now we disconnect first server connected = true; - process.nextTick(function () { + process.nextTick(function() { servers[0].kill(); }); } }); var errors = []; - nc.on('error', function (e) { + nc.on('error', function(e) { // save the error errors.push(e); }); - nc.on('close', function () { + nc.on('close', function() { should.ok(connected); // for tls the error isn't always raised so we'll just trust // that we we tried connecting to the bad server - should.ok(errors.length === 1 || disconnects.indexOf((port+1)+'') !== -1); + should.ok(errors.length === 1 || disconnects.indexOf((port + 1) + '') !== -1); done(); }); var disconnects = []; nc.on('disconnect', function() { var p = nc.currentServer.url.port; - if(disconnects.indexOf(p) === -1) { + if (disconnects.indexOf(p) === -1) { disconnects.push(p); } }); diff --git a/test/errors.js b/test/errors.js index 6f9a7eb0..b48e9e98 100644 --- a/test/errors.js +++ b/test/errors.js @@ -2,94 +2,112 @@ /* global describe: false, before: false, after: false, it: false */ 'use strict'; -var NATS = require ('../'), +var NATS = require('../'), nsc = require('./support/nats_server_control'), should = require('should'); describe('Errors', function() { - var PORT = 1491; - var server; - - // Start up our own nats-server - before(function(done) { - server = nsc.start_server(PORT, done); - }); - - // Shutdown our server after we are done - after(function(){ - server.kill(); - }); - - it('should throw errors on connect', function(done) { - (function() { var nc = NATS.connect({'url':'nats://localhost:' + PORT, 'token':'token1', 'user':'foo'}); }).should.throw(Error); - done(); - }); - - it('should throw errors on publish', function(done) { - var nc = NATS.connect(PORT); - // No subject - (function() { nc.publish(); }).should.throw(Error); - // bad args - (function() { nc.publish('foo', function(){}, 'bar'); }).should.throw(Error); - (function() { nc.publish('foo', 'bar', function(){}, 'bar'); }).should.throw(Error); - // closed - nc.close(); - (function() { nc.publish('foo'); }).should.throw(Error); - done(); - }); - - it('should throw errors on flush', function(done) { - var nc = NATS.connect(PORT); - nc.close(); - (function() { nc.flush(); }).should.throw(Error); - done(); - }); - - it('should pass errors on publish with callbacks', function(done) { - var nc = NATS.connect(PORT); - var expectedErrors = 4; - var received = 0; - - var cb = function(err) { - should.exist(err); - if (++received == expectedErrors) { - done(); - } - }; - - // No subject - nc.publish(cb); - // bad args - nc.publish('foo', function(){}, 'bar', cb); - nc.publish('foo', 'bar', function(){}, cb); - - // closed will still throw since we remove event listeners. - nc.close(); - nc.publish('foo', cb); - }); - - it('should throw errors on subscribe', function(done) { - var nc = NATS.connect(PORT); - nc.close(); - // Closed - (function() { nc.subscribe('foo'); }).should.throw(Error); - done(); - }); - - it ('NatsErrors have code', function() { - var err = new NATS.NatsError("hello", "helloid"); - should.equal(err.message, 'hello'); - should.equal(err.code, 'helloid'); - }); - - it ('NatsErrors can chain an error', function() { - var srcErr = new Error('foo'); - var err = new NATS.NatsError("hello", "helloid", srcErr); - should.equal(err.message, 'hello'); - should.equal(err.code, 'helloid'); - should.equal(err.chainedError, srcErr); - should.equal(err.name, 'NatsError'); - }); + var PORT = 1491; + var server; + + // Start up our own nats-server + before(function(done) { + server = nsc.start_server(PORT, done); + }); + + // Shutdown our server after we are done + after(function() { + server.kill(); + }); + + it('should throw errors on connect', function(done) { + (function() { + var nc = NATS.connect({ + 'url': 'nats://localhost:' + PORT, + 'token': 'token1', + 'user': 'foo' + }); + }).should.throw(Error); + done(); + }); + + it('should throw errors on publish', function(done) { + var nc = NATS.connect(PORT); + // No subject + (function() { + nc.publish(); + }).should.throw(Error); + // bad args + (function() { + nc.publish('foo', function() {}, 'bar'); + }).should.throw(Error); + (function() { + nc.publish('foo', 'bar', function() {}, 'bar'); + }).should.throw(Error); + // closed + nc.close(); + (function() { + nc.publish('foo'); + }).should.throw(Error); + done(); + }); + + it('should throw errors on flush', function(done) { + var nc = NATS.connect(PORT); + nc.close(); + (function() { + nc.flush(); + }).should.throw(Error); + done(); + }); + + it('should pass errors on publish with callbacks', function(done) { + var nc = NATS.connect(PORT); + var expectedErrors = 4; + var received = 0; + + var cb = function(err) { + should.exist(err); + if (++received === expectedErrors) { + done(); + } + }; + + // No subject + nc.publish(cb); + // bad args + nc.publish('foo', function() {}, 'bar', cb); + nc.publish('foo', 'bar', function() {}, cb); + + // closed will still throw since we remove event listeners. + nc.close(); + nc.publish('foo', cb); + }); + + it('should throw errors on subscribe', function(done) { + var nc = NATS.connect(PORT); + nc.close(); + // Closed + (function() { + nc.subscribe('foo'); + }).should.throw(Error); + done(); + }); + + it('NatsErrors have code', function() { + var err = new NATS.NatsError("hello", "helloid"); + should.equal(err.message, 'hello'); + should.equal(err.code, 'helloid'); + }); + + it('NatsErrors can chain an error', function() { + var srcErr = new Error('foo'); + var err = new NATS.NatsError("hello", "helloid", srcErr); + should.equal(err.message, 'hello'); + should.equal(err.code, 'helloid'); + should.equal(err.chainedError, srcErr); + should.equal(err.name, 'NatsError'); + }); }); diff --git a/test/json.js b/test/json.js index c74e4b73..5cdbc842 100644 --- a/test/json.js +++ b/test/json.js @@ -3,63 +3,75 @@ 'use strict'; -var NATS = require ('../'), -nsc = require('./support/nats_server_control'), -should = require('should'); +var NATS = require('../'), + nsc = require('./support/nats_server_control'), + should = require('should'); describe('JSON payloads', function() { - var PORT = 1423; - var server; + var PORT = 1423; + var server; - // Start up our own nats-server - before(function (done) { - server = nsc.start_server(PORT, done); - }); + // Start up our own nats-server + before(function(done) { + server = nsc.start_server(PORT, done); + }); + + // Shutdown our server + after(function() { + server.kill(); + }); - // Shutdown our server - after(function () { - server.kill(); - }); + it('should pub/sub with json', function(done) { + var nc = NATS.connect({ + json: true, + port: PORT + }); + nc.subscribe('foo', function(msg, reply, subj, sid) { + should.ok(typeof msg !== 'string'); + should.exist(msg.field); + msg.field.should.be.equal('hello'); + should.exist(msg.body); + msg.body.should.be.equal('world'); + nc.unsubscribe(sid); + nc.close(); + done(); + }); - it('should pub/sub with json', function(done){ - var nc = NATS.connect({json: true, port: PORT}); - nc.subscribe('foo', function(msg, reply, subj, sid){ - should.ok(typeof msg !== 'string'); - should.exist(msg.field); - msg.field.should.be.equal('hello'); - should.exist(msg.body); - msg.body.should.be.equal('world'); - nc.unsubscribe(sid); - nc.close(); - done(); + nc.publish('foo', { + field: 'hello', + body: 'world' + }); }); - nc.publish('foo', {field:'hello', body:'world'}); - }); + it('should pub/sub fail not json', function(done) { + var nc = NATS.connect({ + json: true, + port: PORT + }); + try { + nc.publish('foo', 'hi'); + } catch (err) { + nc.close(); + err.message.should.be.equal('Message should be a JSON object'); + done(); + } + }); - it('should pub/sub fail not json', function(done){ - var nc = NATS.connect({json: true, port: PORT}); - try { - nc.publish('foo', 'hi'); - } catch(err) { - nc.close(); - err.message.should.be.equal('Message should be a JSON object'); - done(); - } - }); + it('should pub/sub array with json', function(done) { + var nc = NATS.connect({ + json: true, + port: PORT + }); + nc.subscribe('foo', function(msg, reply, subj, sid) { + should.ok(typeof msg !== 'string'); + msg.should.be.instanceof(Array).and.have.lengthOf(3); + nc.unsubscribe(sid); + nc.close(); + done(); + }); - it('should pub/sub array with json', function(done){ - var nc = NATS.connect({json: true, port: PORT}); - nc.subscribe('foo', function(msg, reply, subj, sid){ - should.ok(typeof msg !== 'string'); - msg.should.be.instanceof(Array).and.have.lengthOf(3); - nc.unsubscribe(sid); - nc.close(); - done(); + nc.publish('foo', ['one', 'two', 'three']); }); - - nc.publish('foo', ['one', 'two', 'three']); - }); -}); \ No newline at end of file +}); diff --git a/test/jsonyaml.js b/test/jsonyaml.js index 68dc2f36..be17a61a 100644 --- a/test/jsonyaml.js +++ b/test/jsonyaml.js @@ -9,8 +9,10 @@ var u = require('./support/nats_conf_utils'), describe('NATS Conf Utils', function() { it('test serializing simple', function() { - var x = {test: 'one'}; - var y = u.JsonToYaml(x); + var x = { + test: 'one' + }; + var y = u.j(x); var buf = y.split('\n'); buf.forEach(function(e, i) { @@ -22,8 +24,13 @@ describe('NATS Conf Utils', function() { }); it('test serializing nested', function() { - var x = {a: 'one', b: {a: 'two'}}; - var y = u.JsonToYaml(x); + var x = { + a: 'one', + b: { + a: 'two' + } + }; + var y = u.j(x); var buf = y.split('\n'); buf.forEach(function(e, i) { @@ -35,8 +42,11 @@ describe('NATS Conf Utils', function() { }); it('test serializing array', function() { - var x = {a: 'one', b: ['a', 'b', 'c']}; - var y = u.JsonToYaml(x); + var x = { + a: 'one', + b: ['a', 'b', 'c'] + }; + var y = u.j(x); var buf = y.split('\n'); buf.forEach(function(e, i) { @@ -48,8 +58,17 @@ describe('NATS Conf Utils', function() { }); it('test serializing array objs', function() { - var x = {a: 'one', b: [{a: 'a'}, {b: 'b'}, {c: 'c'}]}; - var y = u.JsonToYaml(x); + var x = { + a: 'one', + b: [{ + a: 'a' + }, { + b: 'b' + }, { + c: 'c' + }] + }; + var y = u.j(x); var buf = y.split('\n'); buf.forEach(function(e, i) { buf[i] = e.trim(); @@ -60,8 +79,18 @@ describe('NATS Conf Utils', function() { }); it('test serializing array arrays', function() { - var x = {a: 'one', b: [{a: 'a', b: ['b', 'c']}, {b: 'b'}, {c: 'c'}]}; - var y = u.JsonToYaml(x); + var x = { + a: 'one', + b: [{ + a: 'a', + b: ['b', 'c'] + }, { + b: 'b' + }, { + c: 'c' + }] + }; + var y = u.j(x); var buf = y.split('\n'); buf.forEach(function(e, i) { buf[i] = e.trim(); @@ -70,4 +99,4 @@ describe('NATS Conf Utils', function() { var z = buf.join(' '); should(z).be.equal("a: one b [ { a: a b [ b c ] } { b: b } { c: c } ]"); }); -}); \ No newline at end of file +}); diff --git a/test/perms.js b/test/perms.js index 67345843..e1520e08 100644 --- a/test/perms.js +++ b/test/perms.js @@ -3,14 +3,14 @@ /* jshint -W030 */ 'use strict'; -var NATS = require ('../'), -nsc = require('./support/nats_server_control'), -ncu = require('./support/nats_conf_utils'), -os = require('os'), -fs = require('fs'), -path = require('path'), -should = require('should'), -nuid = require('nuid'); +var NATS = require('../'), + nsc = require('./support/nats_server_control'), + ncu = require('./support/nats_conf_utils'), + os = require('os'), + fs = require('fs'), + path = require('path'), + should = require('should'), + nuid = require('nuid'); describe('Auth Basics', function() { @@ -19,7 +19,7 @@ describe('Auth Basics', function() { var server; // Start up our own nats-server - before(function (done) { + before(function(done) { var conf = { authorization: { ADMIN: { @@ -34,24 +34,35 @@ describe('Auth Basics', function() { subscribe: "foo", publish: "foo" }, - users: [ - {user: 'admin', password: 'admin', permission: '$ADMIN'}, - {user: 'foo', password: 'foo', permission: '$PUB'}, - {user: 'bar', password: 'bar', permission: '$SUB'} + users: [{ + user: 'admin', + password: 'admin', + permission: '$ADMIN' + }, + { + user: 'foo', + password: 'foo', + permission: '$PUB' + }, + { + user: 'bar', + password: 'bar', + permission: '$SUB' + } ] } }; - var cf = path.resolve(os.tmpdir(), 'conf-' + nuid.next() +'.conf'); - ncu.writeFile(cf, ncu.JsonToYaml(conf)); + var cf = path.resolve(os.tmpdir(), 'conf-' + nuid.next() + '.conf'); + ncu.writeFile(cf, ncu.j(conf)); server = nsc.start_server(PORT, ['-c', cf], done); }); // Shutdown our server - after(function () { + after(function() { nsc.stop_server(server); }); - it('bar cannot subscribe/pub foo', function (done) { + it('bar cannot subscribe/pub foo', function(done) { var nc = NATS.connect({ port: PORT, user: 'bar', @@ -61,7 +72,7 @@ describe('Auth Basics', function() { var perms = 0; nc.on('permission_error', function() { perms++; - if(perms === 2) { + if (perms === 2) { nc.close(); done(); } @@ -75,4 +86,4 @@ describe('Auth Basics', function() { nc.publish('foo', ''); }); }); -}); \ No newline at end of file +}); diff --git a/test/properties.js b/test/properties.js index 863d04a3..1916518c 100644 --- a/test/properties.js +++ b/test/properties.js @@ -3,91 +3,92 @@ /* jshint -W030 */ 'use strict'; -var NATS = require ('../'), +var NATS = require('../'), should = require('should'); describe('Base Properties', function() { - it('should have a version property', function() { - NATS.version.should.match(/[0-9]+\.[0-9]+\.[0-9]+/); - }); + it('should have a version property', function() { + NATS.version.should.match(/[0-9]+\.[0-9]+\.[0-9]+/); + }); - it ('should have the same version as package.json', function() { - var pkg = require('../package.json'); - NATS.version.should.equal(pkg.version); - }); + it('should have the same version as package.json', function() { + // eslint-disable-next-line + var pkg = require('../package.json'); + NATS.version.should.equal(pkg.version); + }); - it('should have a connect function', function() { - NATS.connect.should.be.a.Function; - }); + it('should have a connect function', function() { + NATS.connect.should.be.a.Function; + }); - it('should have a createInbox function', function() { - NATS.createInbox.should.be.a.Function; - }); + it('should have a createInbox function', function() { + NATS.createInbox.should.be.a.Function; + }); }); describe('Connection Properties', function() { - var nc = NATS.connect(); - nc.should.exist; - - it('should have a publish function', function() { - nc.publish.should.be.a.Function; - }); - - it('should have a subscribe function', function() { - nc.subscribe.should.be.a.Function; - }); - - it('should have an unsubscribe function', function() { - nc.unsubscribe.should.be.a.Function; - }); - - it('should have a request function', function() { - nc.request.should.be.a.Function; - }); - - it('should have an options hash with proper fields', function() { - nc.should.have.property('options'); - nc.options.should.have.property('url'); - nc.options.should.have.property('verbose'); - nc.options.should.have.property('pedantic'); - nc.options.should.have.property('reconnect'); - nc.options.should.have.property('maxReconnectAttempts'); - nc.options.should.have.property('reconnectTimeWait'); - }); - - it('should have an parsed url', function() { - nc.should.have.property('url'); - nc.url.should.be.an.Object; - nc.url.should.have.property('protocol'); - nc.url.should.have.property('host'); - nc.url.should.have.property('port'); - }); - - nc.close(); - - it('should allow options to be overridden', function() { - var options = { - 'url' : 'nats://localhost:22421', - 'verbose' : true, - 'pedantic' : true, - 'reconnect' : false, - 'maxReconnectAttempts' : 22, - 'reconnectTimeWait' : 11 - }; - - nc = NATS.connect(options); - nc.on('error', function() {}); // Eat error - - nc.options.url.should.equal('nats://localhost:22421'); - nc.options.verbose.should.equal(true); - nc.options.pedantic.should.equal(true); - nc.options.reconnect.should.equal(false); - nc.options.maxReconnectAttempts.should.equal(22); - nc.options.reconnectTimeWait.should.equal(11); + var nc = NATS.connect(); + nc.should.exist; + + it('should have a publish function', function() { + nc.publish.should.be.a.Function; + }); + + it('should have a subscribe function', function() { + nc.subscribe.should.be.a.Function; + }); + + it('should have an unsubscribe function', function() { + nc.unsubscribe.should.be.a.Function; + }); + + it('should have a request function', function() { + nc.request.should.be.a.Function; + }); + + it('should have an options hash with proper fields', function() { + nc.should.have.property('options'); + nc.options.should.have.property('url'); + nc.options.should.have.property('verbose'); + nc.options.should.have.property('pedantic'); + nc.options.should.have.property('reconnect'); + nc.options.should.have.property('maxReconnectAttempts'); + nc.options.should.have.property('reconnectTimeWait'); + }); + + it('should have an parsed url', function() { + nc.should.have.property('url'); + nc.url.should.be.an.Object; + nc.url.should.have.property('protocol'); + nc.url.should.have.property('host'); + nc.url.should.have.property('port'); + }); + nc.close(); - }); -}); \ No newline at end of file + it('should allow options to be overridden', function() { + var options = { + 'url': 'nats://localhost:22421', + 'verbose': true, + 'pedantic': true, + 'reconnect': false, + 'maxReconnectAttempts': 22, + 'reconnectTimeWait': 11 + }; + + nc = NATS.connect(options); + nc.on('error', function() {}); // Eat error + + nc.options.url.should.equal('nats://localhost:22421'); + nc.options.verbose.should.equal(true); + nc.options.pedantic.should.equal(true); + nc.options.reconnect.should.equal(false); + nc.options.maxReconnectAttempts.should.equal(22); + nc.options.reconnectTimeWait.should.equal(11); + nc.close(); + }); + +}); diff --git a/test/queues.js b/test/queues.js index fd90ded0..9def0520 100644 --- a/test/queues.js +++ b/test/queues.js @@ -2,129 +2,165 @@ /* global describe: false, before: false, after: false, it: false */ 'use strict'; -var NATS = require ('../'), +var NATS = require('../'), nsc = require('./support/nats_server_control'), should = require('should'); describe('Queues', function() { - var PORT = 1425; - var server; + var PORT = 1425; + var server; - // Start up our own nats-server - before(function(done) { - server = nsc.start_server(PORT, done); - }); - - // Shutdown our server - after(function() { - server.kill(); - }); - - it('should deliver a message to single member of a queue group', function(done) { - var nc = NATS.connect(PORT); - var received = 0; - nc.subscribe('foo', {'queue':'myqueue'}, function() { - received += 1; - }); - nc.publish('foo', function() { - should.exists(received); - received.should.equal(1); - nc.close(); - done(); + // Start up our own nats-server + before(function(done) { + server = nsc.start_server(PORT, done); }); - }); - - it('should deliver a message to only one member of a queue group', function(done) { - var nc = NATS.connect(PORT); - var received = 0; - var cb = function cb() { received += 1; }; - for (var i=0; i<5; i++) { - nc.subscribe('foo', {'queue':'myqueue'}, cb); - } - nc.publish('foo', function() { - received.should.equal(1); - nc.close(); - done(); + + // Shutdown our server + after(function() { + server.kill(); }); - }); - - it('should allow queue subscribers and normal subscribers to work together', function(done) { - var nc = NATS.connect(PORT); - var expected = 4; - var received = 0; - var recv = function() { - received += 1; - if (received == expected) { - nc.close(); - done(); - } - }; - - nc.subscribe('foo', {'queue':'myqueue'}, recv); - nc.subscribe('foo', recv); - nc.publish('foo'); - nc.publish('foo'); - nc.flush(); - }); - - it('should spread messages out equally (given random)', function(done) { - /* jshint loopfunc: true */ - var nc = NATS.connect(PORT); - var total = 5000; - var numSubscribers = 10; - var avg = total / numSubscribers; - var allowedVariance = total * 0.05; - var received = new Array(numSubscribers); - - for (var i=0; i', {'queue':'wcqueue'}, function() { received += 1; }); - nc.publish('foo.bar', function() { - received.should.equal(1); - nc.close(); - done(); + + it('should deliver a message to only one member of a queue group', function(done) { + var nc = NATS.connect(PORT); + var received = 0; + var cb = function() { + received += 1; + }; + for (var i = 0; i < 5; i++) { + nc.subscribe('foo', { + 'queue': 'myqueue' + }, cb); + } + nc.publish('foo', function() { + received.should.equal(1); + nc.close(); + done(); + }); }); - }); - it('should deliver to multiple queue groups', function(done) { - var nc = NATS.connect(PORT); - var received1 = 0; - var received2 = 0; - var num = 10; + it('should allow queue subscribers and normal subscribers to work together', function(done) { + var nc = NATS.connect(PORT); + var expected = 4; + var received = 0; + var recv = function() { + received += 1; + if (received == expected) { + nc.close(); + done(); + } + }; + + nc.subscribe('foo', { + 'queue': 'myqueue' + }, recv); + nc.subscribe('foo', recv); + nc.publish('foo'); + nc.publish('foo'); + nc.flush(); + }); - nc.subscribe('foo.bar', {'queue':'r1'}, function() { received1 += 1; }); - nc.subscribe('foo.bar', {'queue':'r2'}, function() { received2 += 1; }); + it('should spread messages out equally (given random)', function(done) { + /* jshint loopfunc: true */ + var nc = NATS.connect(PORT); + var total = 5000; + var numSubscribers = 10; + var avg = total / numSubscribers; + var allowedVariance = total * 0.05; + var received = new Array(numSubscribers); + + for (var i = 0; i < numSubscribers; i++) { + received[i] = 0; + nc.subscribe('foo.bar', { + 'queue': 'spreadtest' + }, (function(index) { + return function() { + received[index] += 1; + }; + }(i))); + } + + for (i = 0; i < total; i++) { + nc.publish('foo.bar', 'ok'); + } + + nc.flush(function() { + for (var i = 0; i < numSubscribers; i++) { + Math.abs(received[i] - avg).should.be.below(allowedVariance); + } + nc.close(); + done(); + }); + }); - for (var i=0; i', { + 'queue': 'wcqueue' + }, function() { + received += 1; + }); + nc.publish('foo.bar', function() { + received.should.equal(1); + nc.close(); + done(); + }); + }); - nc.flush(function() { - received1.should.equal(num); - received2.should.equal(num); - nc.close(); - done(); + it('should deliver to multiple queue groups', function(done) { + var nc = NATS.connect(PORT); + var received1 = 0; + var received2 = 0; + var num = 10; + + nc.subscribe('foo.bar', { + 'queue': 'r1' + }, function() { + received1 += 1; + }); + nc.subscribe('foo.bar', { + 'queue': 'r2' + }, function() { + received2 += 1; + }); + + for (var i = 0; i < num; i++) { + nc.publish('foo.bar'); + } + + nc.flush(function() { + received1.should.equal(num); + received2.should.equal(num); + nc.close(); + done(); + }); }); - }); }); diff --git a/test/reconnect.js b/test/reconnect.js index c328b5c1..53e03b2b 100644 --- a/test/reconnect.js +++ b/test/reconnect.js @@ -2,301 +2,343 @@ /* global describe: false, before: false, after: false, it: false */ 'use strict'; -var NATS = require ('../'), +var NATS = require('../'), nsc = require('./support/nats_server_control'), should = require('should'); describe('Reconnect functionality', function() { - var PORT = 1426; - var WAIT = 20; - var ATTEMPTS = 4; - var server; + var PORT = 1426; + var WAIT = 20; + var ATTEMPTS = 4; + var server; - // Start up our own nats-server - before(function(done) { - server = nsc.start_server(PORT, done); - }); - - // Shutdown our server after we are done - after(function() { - server.kill(); - }); - - it('should not emit a reconnecting event if suppressed', function(done) { - var nc = NATS.connect({'port':PORT, 'reconnect':false}); - should.exist(nc); - nc.on('connect', function() { - server.kill(); - }); - nc.on('reconnecting', function(/*client*/) { - done(new Error('Reconnecting improperly called')); + // Start up our own nats-server + before(function(done) { + server = nsc.start_server(PORT, done); }); - nc.on('close', function() { - nc.close(); - server = nsc.start_server(PORT, done); - }); - }); - it('should emit a disconnect and a reconnecting event after proper delay', function(done) { - var nc = NATS.connect({'port':PORT, 'reconnectTimeWait':WAIT}); - var startTime; - should.exist(nc); - nc.on('connect', function() { - server.kill(); - startTime = new Date(); - }); - nc.on('reconnecting', function(/*client*/) { - var elapsed = new Date() - startTime; - elapsed.should.be.within(WAIT, 5*WAIT); - nc.close(); - server = nsc.start_server(PORT, done); + // Shutdown our server after we are done + after(function() { + server.kill(); }); - nc.on('disconnect', function() { - var elapsed = new Date() - startTime; - elapsed.should.be.within(0, 5*WAIT); - }); - }); - it('should emit multiple reconnecting events and fail after maxReconnectAttempts', function(done) { - var nc = NATS.connect({'port':PORT, 'reconnectTimeWait':WAIT, 'maxReconnectAttempts':ATTEMPTS}); - var startTime; - var numAttempts = 0; - nc.on('connect', function() { - server.kill(); - startTime = new Date(); + it('should not emit a reconnecting event if suppressed', function(done) { + var nc = NATS.connect({ + 'port': PORT, + 'reconnect': false + }); + should.exist(nc); + nc.on('connect', function() { + server.kill(); + }); + nc.on('reconnecting', function(client) { + done(new Error('Reconnecting improperly called')); + }); + nc.on('close', function() { + nc.close(); + server = nsc.start_server(PORT, done); + }); }); - nc.on('reconnecting', function(/*client*/) { - var elapsed = new Date() - startTime; - elapsed.should.be.within(WAIT, 5*WAIT); - startTime = new Date(); - numAttempts += 1; + + it('should emit a disconnect and a reconnecting event after proper delay', function(done) { + var nc = NATS.connect({ + 'port': PORT, + 'reconnectTimeWait': WAIT + }); + var startTime; + should.exist(nc); + nc.on('connect', function() { + server.kill(); + startTime = new Date(); + }); + nc.on('reconnecting', function(client) { + var elapsed = new Date() - startTime; + elapsed.should.be.within(WAIT, 5 * WAIT); + nc.close(); + server = nsc.start_server(PORT, done); + }); + nc.on('disconnect', function() { + var elapsed = new Date() - startTime; + elapsed.should.be.within(0, 5 * WAIT); + }); }); - nc.on('close', function() { - numAttempts.should.equal(ATTEMPTS); - nc.close(); - server = nsc.start_server(PORT, done); + + it('should emit multiple reconnecting events and fail after maxReconnectAttempts', function(done) { + var nc = NATS.connect({ + 'port': PORT, + 'reconnectTimeWait': WAIT, + 'maxReconnectAttempts': ATTEMPTS + }); + var startTime; + var numAttempts = 0; + nc.on('connect', function() { + server.kill(); + startTime = new Date(); + }); + nc.on('reconnecting', function(client) { + var elapsed = new Date() - startTime; + elapsed.should.be.within(WAIT, 5 * WAIT); + startTime = new Date(); + numAttempts += 1; + }); + nc.on('close', function() { + numAttempts.should.equal(ATTEMPTS); + nc.close(); + server = nsc.start_server(PORT, done); + }); }); - }); - it('should emit reconnecting events indefinitely if maxReconnectAttempts is set to -1', function(done) { + it('should emit reconnecting events indefinitely if maxReconnectAttempts is set to -1', function(done) { - var nc = NATS.connect({'port':PORT, 'reconnectTimeWait':WAIT, 'maxReconnectAttempts':-1}); - var numAttempts = 0; + var nc = NATS.connect({ + 'port': PORT, + 'reconnectTimeWait': WAIT, + 'maxReconnectAttempts': -1 + }); + var numAttempts = 0; - // stop trying after an arbitrary amount of elapsed time - var timeout = setTimeout(function() { - // restart server and make sure next flush works ok - if (server === null) { - server = nsc.start_server(PORT); - } - }, 1000); + // stop trying after an arbitrary amount of elapsed time + var timeout = setTimeout(function() { + // restart server and make sure next flush works ok + if (server === null) { + server = nsc.start_server(PORT); + } + }, 1000); - nc.on('connect', function() { - server.kill(); - server = null; - }); - nc.on('reconnecting', function(/*client*/) { - numAttempts += 1; - // attempt indefinitely to reconnect - nc.reconnects.should.equal(numAttempts); - nc.connected.should.equal(false); - nc.wasConnected.should.equal(true); - nc.reconnecting.should.equal(true); - // if maxReconnectAttempts is set to -1, the number of reconnects will always be greater - nc.reconnects.should.be.above(nc.options.maxReconnectAttempts); - }); - nc.on('reconnect', function() { - nc.flush(function() { - nc.close(); - done(); - }); + nc.on('connect', function() { + server.kill(); + server = null; + }); + nc.on('reconnecting', function(client) { + numAttempts += 1; + // attempt indefinitely to reconnect + nc.reconnects.should.equal(numAttempts); + nc.connected.should.equal(false); + nc.wasConnected.should.equal(true); + nc.reconnecting.should.equal(true); + // if maxReconnectAttempts is set to -1, the number of reconnects will always be greater + nc.reconnects.should.be.above(nc.options.maxReconnectAttempts); + }); + nc.on('reconnect', function() { + nc.flush(function() { + nc.close(); + done(); + }); + }); }); - }); - it('should succesfully reconnect to new server', function(done) { - var nc = NATS.connect({'port':PORT, 'reconnectTimeWait':100}); - // Kill server after first successful contact - nc.flush(function() { - server.kill(); - server = null; - }); - nc.on('reconnecting', function(/*client*/) { - // restart server and make sure next flush works ok - if (server === null) { - server = nsc.start_server(PORT); - } - }); - nc.on('reconnect', function() { - nc.flush(function() { - nc.close(); - done(); - }); + it('should succesfully reconnect to new server', function(done) { + var nc = NATS.connect({ + 'port': PORT, + 'reconnectTimeWait': 100 + }); + // Kill server after first successful contact + nc.flush(function() { + server.kill(); + server = null; + }); + nc.on('reconnecting', function(client) { + // restart server and make sure next flush works ok + if (server === null) { + server = nsc.start_server(PORT); + } + }); + nc.on('reconnect', function() { + nc.flush(function() { + nc.close(); + done(); + }); + }); }); - }); - it('should succesfully reconnect to new server with subscriptions', function(done) { - var nc = NATS.connect({'port':PORT, 'reconnectTimeWait':100}); - // Kill server after first successful contact - nc.flush(function() { - server.kill(); - server = null; - }); - nc.subscribe('foo', function() { - nc.close(); - done(); - }); - nc.on('reconnecting', function(/*client*/) { - // restart server and make sure next flush works ok - if (server === null) { - server = nsc.start_server(PORT); - } - }); - nc.on('reconnect', function() { - nc.publish('foo'); + it('should succesfully reconnect to new server with subscriptions', function(done) { + var nc = NATS.connect({ + 'port': PORT, + 'reconnectTimeWait': 100 + }); + // Kill server after first successful contact + nc.flush(function() { + server.kill(); + server = null; + }); + nc.subscribe('foo', function() { + nc.close(); + done(); + }); + nc.on('reconnecting', function(client) { + // restart server and make sure next flush works ok + if (server === null) { + server = nsc.start_server(PORT); + } + }); + nc.on('reconnect', function() { + nc.publish('foo'); + }); }); - }); - it('should succesfully reconnect to new server with queue subscriptions correctly', function(done) { - var nc = NATS.connect({'port':PORT, 'reconnectTimeWait':100}); - // Kill server after first successful contact - nc.flush(function() { - server.kill(); - server = null; - }); - var received = 0; - // Multiple subscribers - var cb = function cb() { received += 1; }; - for (var i=0; i<5; i++) { - nc.subscribe('foo', {'queue':'myReconnectQueue'}, cb); - } - nc.on('reconnecting', function(/*client*/) { - // restart server and make sure next flush works ok - if (server === null) { - server = nsc.start_server(PORT); - } - }); - nc.on('reconnect', function() { - nc.publish('foo', function() { - received.should.equal(1); - nc.close(); - done(); - }); + it('should succesfully reconnect to new server with queue subscriptions correctly', function(done) { + var nc = NATS.connect({ + 'port': PORT, + 'reconnectTimeWait': 100 + }); + // Kill server after first successful contact + nc.flush(function() { + server.kill(); + server = null; + }); + var received = 0; + // Multiple subscribers + var cb = function() { + received += 1; + }; + for (var i = 0; i < 5; i++) { + nc.subscribe('foo', { + 'queue': 'myReconnectQueue' + }, cb); + } + nc.on('reconnecting', function(client) { + // restart server and make sure next flush works ok + if (server === null) { + server = nsc.start_server(PORT); + } + }); + nc.on('reconnect', function() { + nc.publish('foo', function() { + received.should.equal(1); + nc.close(); + done(); + }); + }); }); - }); - it('should properly resync with inbound buffer non-nil', function(done) { - var nc = NATS.connect({'port':PORT, 'reconnectTimeWait':100}); + it('should properly resync with inbound buffer non-nil', function(done) { + var nc = NATS.connect({ + 'port': PORT, + 'reconnectTimeWait': 100 + }); - // Send lots of data to ourselves - nc.on('connect', function() { - var sid = nc.subscribe('foo', function() { - // Kill server on first message, inbound should still be full. - server.kill(); - nc.unsubscribe(sid); - server = nsc.start_server(PORT); - }); - var b = new Buffer(4096).toString(); - for (var i=0; i<1000; i++) { - nc.publish('foo', b); - } - }); + // Send lots of data to ourselves + nc.on('connect', function() { + var sid = nc.subscribe('foo', function() { + // Kill server on first message, inbound should still be full. + server.kill(); + nc.unsubscribe(sid); + server = nsc.start_server(PORT); + }); + var b = new Buffer(4096).toString(); + for (var i = 0; i < 1000; i++) { + nc.publish('foo', b); + } + }); - nc.on('reconnect', function() { - nc.flush(function() { - nc.close(); - done(); - }); + nc.on('reconnect', function() { + nc.flush(function() { + nc.close(); + done(); + }); + }); }); - }); - it('should not crash when sending a publish with a callback after connection loss', function(done) { - var nc = NATS.connect({'port':PORT, 'reconnectTimeWait':WAIT}); - var startTime; - should.exist(nc); - nc.on('connect', function() { - server.kill(); - startTime = new Date(); - }); - nc.on('disconnect', function() { - nc.publish('foo', 'bar', 'reply', function() { - // fails to get here, but should not crash - }); - server = nsc.start_server(PORT); - }); - nc.on('reconnect', function() { - nc.flush(function() { - nc.close(); - done(); - }); + it('should not crash when sending a publish with a callback after connection loss', function(done) { + var nc = NATS.connect({ + 'port': PORT, + 'reconnectTimeWait': WAIT + }); + var startTime; + should.exist(nc); + nc.on('connect', function() { + server.kill(); + startTime = new Date(); + }); + nc.on('disconnect', function() { + nc.publish('foo', 'bar', 'reply', function() { + // fails to get here, but should not crash + }); + server = nsc.start_server(PORT); + }); + nc.on('reconnect', function() { + nc.flush(function() { + nc.close(); + done(); + }); + }); }); - }); - it('should execute callbacks if published during reconnect', function(done) { - var nc = NATS.connect({'port':PORT, 'reconnectTimeWait':100}); - nc.on('reconnecting', function(/*client*/) { - // restart server - if (server === null) { - nc.publish('foo', function() { - nc.close(); - done(); - }); - server = nsc.start_server(PORT); - } - }); - nc.on('connect', function() { - var s = server; - server = null; - s.kill(); + it('should execute callbacks if published during reconnect', function(done) { + var nc = NATS.connect({ + 'port': PORT, + 'reconnectTimeWait': 100 + }); + nc.on('reconnecting', function(client) { + // restart server + if (server === null) { + nc.publish('foo', function() { + nc.close(); + done(); + }); + server = nsc.start_server(PORT); + } + }); + nc.on('connect', function() { + var s = server; + server = null; + s.kill(); + }); }); - }); - it('should not lose messages if published during reconnect', function(done) { - // This checks two things if the client publishes while reconnecting: - // 1) the message is published when the client reconnects - // 2) the client's subscriptions are synced before the message is published - var nc = NATS.connect({'port':PORT, 'reconnectTimeWait':100}); - nc.subscribe('foo', function() { - nc.close(); - done(); - }); - nc.on('reconnecting', function(/*client*/) { - // restart server - if (server === null) { - nc.publish('foo'); - server = nsc.start_server(PORT); - } - }); - nc.on('connect', function() { - var s = server; - server = null; - s.kill(); + it('should not lose messages if published during reconnect', function(done) { + // This checks two things if the client publishes while reconnecting: + // 1) the message is published when the client reconnects + // 2) the client's subscriptions are synced before the message is published + var nc = NATS.connect({ + 'port': PORT, + 'reconnectTimeWait': 100 + }); + nc.subscribe('foo', function() { + nc.close(); + done(); + }); + nc.on('reconnecting', function(client) { + // restart server + if (server === null) { + nc.publish('foo'); + server = nsc.start_server(PORT); + } + }); + nc.on('connect', function() { + var s = server; + server = null; + s.kill(); + }); }); - }); - it('should emit reconnect before flush callbacks are called', function(done) { - var nc = NATS.connect({'port':PORT, 'reconnectTimeWait':100}); - var reconnected = false; - nc.on('reconnecting', function() { - // restart server - if (server === null) { - nc.flush(function() { - nc.close(); - if (!reconnected) { - done(new Error('Flush callback called before reconnect emitted')); - } - done(); - }); - server = nsc.start_server(PORT); - } - }); - nc.on('reconnect', function() { - reconnected = true; - }); - nc.on('connect', function() { - var s = server; - server = null; - s.kill(); + it('should emit reconnect before flush callbacks are called', function(done) { + var nc = NATS.connect({ + 'port': PORT, + 'reconnectTimeWait': 100 + }); + var reconnected = false; + nc.on('reconnecting', function() { + // restart server + if (server === null) { + nc.flush(function() { + nc.close(); + if (!reconnected) { + done(new Error('Flush callback called before reconnect emitted')); + } + done(); + }); + server = nsc.start_server(PORT); + } + }); + nc.on('reconnect', function() { + reconnected = true; + }); + nc.on('connect', function() { + var s = server; + server = null; + s.kill(); + }); }); - }); }); diff --git a/test/split.js b/test/split.js index 35ac8764..2514eea6 100644 --- a/test/split.js +++ b/test/split.js @@ -2,68 +2,68 @@ /* global describe: false, before: false, after: false, it: false */ 'use strict'; -var NATS = require ('../'), +var NATS = require('../'), nsc = require('./support/nats_server_control'), should = require('should'); describe('Split Messages', function() { - var PORT = 1427; - var server; + var PORT = 1427; + var server; - // Start up our own nats-server - before(function(done) { - server = nsc.start_server(PORT, done); - }); + // Start up our own nats-server + before(function(done) { + server = nsc.start_server(PORT, done); + }); + + // Shutdown our server + after(function() { + server.kill(); + }); - // Shutdown our server - after(function() { - server.kill(); - }); + it('should properly handle large # of messages from split buffers', function(done) { + var nc = NATS.connect(PORT); - it('should properly handle large # of messages from split buffers', function(done) { - var nc = NATS.connect(PORT); + var data = 'Hello World!'; + var received = 0; + var expected = 10000; - var data = 'Hello World!'; - var received = 0; - var expected = 10000; + nc.subscribe('foo', function(msg) { + should.exists(msg); + msg.should.equal(data); + msg.length.should.equal(data.length); + received += 1; + if (received == expected) { + nc.close(); + done(); + } + }); - nc.subscribe('foo', function(msg) { - should.exists(msg); - msg.should.equal(data); - msg.length.should.equal(data.length); - received += 1; - if (received == expected) { - nc.close(); - done(); - } + for (var i = 0; i < expected; i++) { + nc.publish('foo', data); + } }); - for (var i = 0; i < expected; i++) { - nc.publish('foo', data); - } - }); + it('should properly handle large # of utf8 messages from split buffers', function(done) { + var nc = NATS.connect(PORT); - it('should properly handle large # of utf8 messages from split buffers', function(done) { - var nc = NATS.connect(PORT); + // Use utf8 string to make sure encoding works too. + var data = '½ + ¼ = ¾'; + var received = 0; + var expected = 10000; - // Use utf8 string to make sure encoding works too. - var data = '½ + ¼ = ¾'; - var received = 0; - var expected = 10000; + nc.subscribe('foo', function(msg) { + msg.should.equal(data); + msg.length.should.equal(data.length); + received += 1; + if (received == expected) { + done(); + } + }); - nc.subscribe('foo', function(msg) { - msg.should.equal(data); - msg.length.should.equal(data.length); - received += 1; - if (received == expected) { - done(); - } + for (var i = 0; i < expected; i++) { + nc.publish('foo', data); + } }); - for (var i = 0; i < expected; i++) { - nc.publish('foo', data); - } - }); - }); diff --git a/test/subevents.js b/test/subevents.js index 7ebcc217..999cb205 100644 --- a/test/subevents.js +++ b/test/subevents.js @@ -2,103 +2,107 @@ /* global describe: false, before: false, after: false, it: false */ 'use strict'; -var NATS = require ('../'), +var NATS = require('../'), nsc = require('./support/nats_server_control'), should = require('should'); describe('Subscription Events', function() { - var PORT = 9422; - var server; + var PORT = 9422; + var server; - // Start up our own nats-server - before(function(done) { - server = nsc.start_server(PORT, done); - }); + // Start up our own nats-server + before(function(done) { + server = nsc.start_server(PORT, done); + }); - // Shutdown our server after we are done - after(function(){ - server.kill(); - }); + // Shutdown our server after we are done + after(function() { + server.kill(); + }); - it('should generate subscribe events', function(done) { - var nc = NATS.connect(PORT); - var subj = 'sub.event'; - nc.on('subscribe', function(sid, subject) { - should.exist(sid); - should.exist(subject); - subject.should.equal(subj); - nc.close(); - done(); + it('should generate subscribe events', function(done) { + var nc = NATS.connect(PORT); + var subj = 'sub.event'; + nc.on('subscribe', function(sid, subject) { + should.exist(sid); + should.exist(subject); + subject.should.equal(subj); + nc.close(); + done(); + }); + nc.subscribe(subj); }); - nc.subscribe(subj); - }); - it('should generate subscribe events with opts', function(done) { - var nc = NATS.connect(PORT); - var subj = 'sub.event'; - var queuegroup = 'bar'; - nc.on('subscribe', function(sid, subject, opts) { - should.exist(sid); - should.exist(subject); - subject.should.equal(subj); - should.exist(opts); - should.exist(opts.queue); - opts.queue.should.equal(queuegroup); - nc.close(); - done(); + it('should generate subscribe events with opts', function(done) { + var nc = NATS.connect(PORT); + var subj = 'sub.event'; + var queuegroup = 'bar'; + nc.on('subscribe', function(sid, subject, opts) { + should.exist(sid); + should.exist(subject); + subject.should.equal(subj); + should.exist(opts); + should.exist(opts.queue); + opts.queue.should.equal(queuegroup); + nc.close(); + done(); + }); + nc.subscribe(subj, { + queue: queuegroup + }); }); - nc.subscribe(subj, {queue:queuegroup}); - }); - it('should generate unsubscribe events', function(done) { - var nc = NATS.connect(PORT); - var subj = 'sub.event'; - nc.on('unsubscribe', function(sid, subject) { - should.exist(sid); - should.exist(subject); - subject.should.equal(subj); - nc.close(); - done(); + it('should generate unsubscribe events', function(done) { + var nc = NATS.connect(PORT); + var subj = 'sub.event'; + nc.on('unsubscribe', function(sid, subject) { + should.exist(sid); + should.exist(subject); + subject.should.equal(subj); + nc.close(); + done(); + }); + var sid = nc.subscribe(subj); + nc.unsubscribe(sid); }); - var sid = nc.subscribe(subj); - nc.unsubscribe(sid); - }); - it('should generate unsubscribe events on auto-unsub', function(done) { - var nc = NATS.connect(PORT); - var subj = 'autounsub.event'; - nc.on('unsubscribe', function(sid, subject) { - should.exist(sid); - should.exist(subject); - subject.should.equal(subj); - nc.close(); - done(); + it('should generate unsubscribe events on auto-unsub', function(done) { + var nc = NATS.connect(PORT); + var subj = 'autounsub.event'; + nc.on('unsubscribe', function(sid, subject) { + should.exist(sid); + should.exist(subject); + subject.should.equal(subj); + nc.close(); + done(); + }); + nc.subscribe(subj, { + max: 1 + }); + nc.publish(subj); }); - nc.subscribe(subj, {max:1}); - nc.publish(subj); - }); - it('should generate only unsubscribe events on auto-unsub', function(done) { - var nc = NATS.connect(PORT); - var subj = 'autounsub.event'; - var eventsReceived = 0; - var want = 5; + it('should generate only unsubscribe events on auto-unsub', function(done) { + var nc = NATS.connect(PORT); + var subj = 'autounsub.event'; + var eventsReceived = 0; + var want = 5; - nc.on('unsubscribe', function(sid, subject) { - eventsReceived++; - }); - var sid = nc.subscribe(subj); - nc.unsubscribe(sid, want); - for (var i=0; i maxWait) { - finish(new Error('Can\'t connect to server on port: ' + port)); - } + var start = new Date(); + var wait = 0; + var maxWait = 5 * 1000; // 5 secs + var delta = 250; + var socket; + var timer; - // Try to connect to the correct port. - socket = net.createConnection(port); - - // Success - socket.on('connect', function() { - if (server.pid === null) { - // We connected but not to our server.. - finish(new Error('Server already running on port: ' + port)); - } else { - finish(); - } - }); + var resetSocket = function() { + if (socket !== undefined) { + socket.removeAllListeners(); + socket.destroy(); + socket = undefined; + } + }; - // Wait for next try.. - socket.on('error', function(error) { - finish(new Error("Problem connecting to server on port: " + port + " (" + error + ")")); - }); + var finish = function(err) { + resetSocket(); + if (timer !== undefined) { + clearInterval(timer); + timer = undefined; + } + if (done) { + done(err); + } + }; - }, delta); + // Test for when socket is bound. + timer = setInterval(function() { + resetSocket(); - // Other way to catch another server running. - server.on('exit', function(code, signal) { - if (code === 1) { - finish(new Error('Server exited with bad code, already running? (' + code + ' / ' + signal + ')')); - } - }); + wait = new Date() - start; + if (wait > maxWait) { + finish(new Error('Can\'t connect to server on port: ' + port)); + } - // Server does not exist.. - server.stderr.on('data', function(data) { - if (/^execvp\(\)/.test(data)) { - clearInterval(timer); - finish(new Error('Can\'t find the ' + SERVER)); - } - }); + // Try to connect to the correct port. + socket = net.createConnection(port); + + // Success + socket.on('connect', function() { + if (server.pid === null) { + // We connected but not to our server.. + finish(new Error('Server already running on port: ' + port)); + } else { + finish(); + } + }); + + // Wait for next try.. + socket.on('error', function(error) { + finish(new Error("Problem connecting to server on port: " + port + " (" + error + ")")); + }); + + }, delta); + + // Other way to catch another server running. + server.on('exit', function(code, signal) { + if (code === 1) { + finish(new Error('Server exited with bad code, already running? (' + code + ' / ' + signal + ')')); + } + }); + + // Server does not exist.. + server.stderr.on('data', function(data) { + if (/^execvp\(\)/.test(data)) { + clearInterval(timer); + finish(new Error('Can\'t find the ' + SERVER)); + } + }); - return server; + return server; } exports.start_server = start_server; function stop_server(server) { - if (server !== undefined) { - server.kill(); - } + if (server !== undefined) { + server.kill(); + } } exports.stop_server = stop_server; @@ -113,75 +113,74 @@ exports.stop_server = stop_server; // starts a number of servers in a cluster at the specified ports. // must call with at least one port. function start_cluster(ports, route_port, opt_flags, done) { - if (typeof opt_flags == 'function') { - done = opt_flags; - opt_flags = null; - } - var servers = []; - var started = 0; - var server = add_member(ports[0], route_port, route_port, opt_flags, function() { - started++; - servers.push(server); - if(started === ports.length) { - done(); + if (typeof opt_flags == 'function') { + done = opt_flags; + opt_flags = null; } - }); - - var others = ports.slice(1); - others.forEach(function(p){ - var s = add_member(p, route_port, p+1000, opt_flags, function() { + var servers = []; + var started = 0; + var server = add_member(ports[0], route_port, route_port, opt_flags, function() { started++; - servers.push(s); - if(started === ports.length) { - done(); - } + servers.push(server); + if (started === ports.length) { + done(); + } + }); + + var others = ports.slice(1); + others.forEach(function(p) { + var s = add_member(p, route_port, p + 1000, opt_flags, function() { + started++; + servers.push(s); + if (started === ports.length) { + done(); + } + }); }); - }); - return servers; + return servers; } // adds more cluster members, if more than one server is added additional // servers are added after the specified delay. function add_member_with_delay(ports, route_port, delay, opt_flags, done) { - if (typeof opt_flags == 'function') { - done = opt_flags; - opt_flags = null; - } - var servers = []; - ports.forEach(function(p, i) { - setTimeout(function() { - var s = add_member(p, route_port, p+1000, opt_flags, function() { - servers.push(s); - if(servers.length === ports.length) { - done(); - } - }); - }, i*delay); - }); + if (typeof opt_flags == 'function') { + done = opt_flags; + opt_flags = null; + } + var servers = []; + ports.forEach(function(p, i) { + setTimeout(function() { + var s = add_member(p, route_port, p + 1000, opt_flags, function() { + servers.push(s); + if (servers.length === ports.length) { + done(); + } + }); + }, i * delay); + }); - return servers; + return servers; } exports.add_member_with_delay = add_member_with_delay; function add_member(port, route_port, cluster_port, opt_flags, done) { - if (typeof opt_flags == 'function') { - done = opt_flags; - opt_flags = null; - } - opt_flags = opt_flags || []; - var opts = JSON.parse(JSON.stringify(opt_flags)); - opts.push('--routes', 'nats://localhost:' + route_port); - opts.push('--cluster', 'nats://localhost:' + cluster_port); - - return start_server(port, opts, done); + if (typeof opt_flags == 'function') { + done = opt_flags; + opt_flags = null; + } + opt_flags = opt_flags || []; + var opts = JSON.parse(JSON.stringify(opt_flags)); + opts.push('--routes', 'nats://localhost:' + route_port); + opts.push('--cluster', 'nats://localhost:' + cluster_port); + + return start_server(port, opts, done); } exports.start_cluster = start_cluster; exports.add_member = add_member; exports.stop_cluster = function(servers) { - servers.forEach(function(s) { - stop_server(s); - }); + servers.forEach(function(s) { + stop_server(s); + }); }; - diff --git a/test/support/sleep.js b/test/support/sleep.js index babf8dcc..7178c1fa 100644 --- a/test/support/sleep.js +++ b/test/support/sleep.js @@ -3,7 +3,9 @@ 'use strict'; exports.sleep = function(ms) { - var start = new Date().getTime(), expire = start + ms; - while (new Date().getTime() < expire) { } - return; + var start = new Date().getTime(), + expire = start + ms; + while (new Date().getTime() < expire) { + // spinning... + } }; diff --git a/test/timeouts.js b/test/timeouts.js index 65c40cd3..d71a2b3f 100644 --- a/test/timeouts.js +++ b/test/timeouts.js @@ -2,7 +2,7 @@ /* global describe: false, before: false, after: false, it: false */ 'use strict'; -var NATS = require ('../'), +var NATS = require('../'), nsc = require('./support/nats_server_control'), should = require('should'); @@ -10,88 +10,88 @@ var PORT = 1428; describe('Timeout and max received events for subscriptions', function() { - var server; + var server; - // Start up our own nats-server - before(function(done) { - server = nsc.start_server(PORT, done); - }); + // Start up our own nats-server + before(function(done) { + server = nsc.start_server(PORT, done); + }); - // Shutdown our server after we are done - after(function(){ - server.kill(); - }); + // Shutdown our server after we are done + after(function() { + server.kill(); + }); - it('should perform simple timeouts on subscriptions', function(done) { - var nc = NATS.connect(PORT); - nc.on('connect', function() { - var startTime = new Date(); - var sid = nc.subscribe('foo'); - nc.timeout(sid, 50, 1, function() { - var elapsed = new Date() - startTime; - should.exists(elapsed); - elapsed.should.be.within(45, 75); - nc.close(); - done(); - }); + it('should perform simple timeouts on subscriptions', function(done) { + var nc = NATS.connect(PORT); + nc.on('connect', function() { + var startTime = new Date(); + var sid = nc.subscribe('foo'); + nc.timeout(sid, 50, 1, function() { + var elapsed = new Date() - startTime; + should.exists(elapsed); + elapsed.should.be.within(45, 75); + nc.close(); + done(); + }); + }); }); - }); - it('should not timeout if exepected has been received', function(done) { - var nc = NATS.connect(PORT); - nc.on('connect', function() { - var sid = nc.subscribe('foo'); - nc.timeout(sid, 50, 1, function() { - done(new Error('Timeout improperly called')); - }); - nc.publish('foo', function() { - nc.close(); - done(); - }); + it('should not timeout if exepected has been received', function(done) { + var nc = NATS.connect(PORT); + nc.on('connect', function() { + var sid = nc.subscribe('foo'); + nc.timeout(sid, 50, 1, function() { + done(new Error('Timeout improperly called')); + }); + nc.publish('foo', function() { + nc.close(); + done(); + }); + }); }); - }); - it('should not timeout if unsubscribe is called', function(done) { - var nc = NATS.connect(PORT); - nc.on('connect', function() { - var count = 0; - var sid = nc.subscribe('bar', function(m) { - count++; - if(count === 1) { - nc.unsubscribe(sid); - } - }); - nc.timeout(sid, 1000, 2, function() { - done(new Error('Timeout improperly called')); - }); - nc.publish('bar', ''); - nc.flush(); - setTimeout(function() { - // terminate the test - done(); - }, 1500); + it('should not timeout if unsubscribe is called', function(done) { + var nc = NATS.connect(PORT); + nc.on('connect', function() { + var count = 0; + var sid = nc.subscribe('bar', function(m) { + count++; + if (count === 1) { + nc.unsubscribe(sid); + } + }); + nc.timeout(sid, 1000, 2, function() { + done(new Error('Timeout improperly called')); + }); + nc.publish('bar', ''); + nc.flush(); + setTimeout(function() { + // terminate the test + done(); + }, 1500); + }); }); - }); - it('timeout should unsubscribe', function(done) { - var nc = NATS.connect(PORT); - nc.on('connect', function() { - var count = 0; - var sid = nc.subscribe('bar', function(m) { - count++; - }); - nc.timeout(sid, 250, 2, function() { - process.nextTick(function () { - nc.publish('bar', ''); - nc.flush(); + it('timeout should unsubscribe', function(done) { + var nc = NATS.connect(PORT); + nc.on('connect', function() { + var count = 0; + var sid = nc.subscribe('bar', function(m) { + count++; + }); + nc.timeout(sid, 250, 2, function() { + process.nextTick(function() { + nc.publish('bar', ''); + nc.flush(); + }); + }); + setTimeout(function() { + nc.close(); + should(count).equal(0); + done(); + }, 1000); }); - }); - setTimeout(function() { - nc.close(); - should(count).equal(0); - done(); - }, 1000); }); - }); }); diff --git a/test/tls.js b/test/tls.js index cda14304..adb3d821 100644 --- a/test/tls.js +++ b/test/tls.js @@ -2,127 +2,147 @@ /* global describe: false, before: false, after: false, it: false */ 'use strict'; -var NATS = require ('../'), +var NATS = require('../'), nsc = require('./support/nats_server_control'), should = require('should'), fs = require('fs'); describe('TLS', function() { - var PORT = 1442; - var TLSPORT = 1443; - var TLSVERIFYPORT = 1444; - var flags = []; - - var server; - var tlsServer; - var tlsVerifyServer; - - // Start up our own nats-server for each test - // We will start a plain, a no client cert, and a client cert required. - before(function(done) { - server = nsc.start_server(PORT, function() { - var flags = ['--tls', '--tlscert', './test/certs/server-cert.pem', - '--tlskey', './test/certs/server-key.pem']; - tlsServer = nsc.start_server(TLSPORT, flags, function() { - var flags = ['--tlsverify', '--tlscert', './test/certs/server-cert.pem', - '--tlskey', './test/certs/server-key.pem', - '--tlscacert', './test/certs/ca.pem']; - tlsVerifyServer = nsc.start_server(TLSVERIFYPORT, flags, done); - }); + var PORT = 1442; + var TLSPORT = 1443; + var TLSVERIFYPORT = 1444; + var flags = []; + + var server; + var tlsServer; + var tlsVerifyServer; + + // Start up our own nats-server for each test + // We will start a plain, a no client cert, and a client cert required. + before(function(done) { + server = nsc.start_server(PORT, function() { + var flags = ['--tls', '--tlscert', './test/certs/server-cert.pem', + '--tlskey', './test/certs/server-key.pem' + ]; + tlsServer = nsc.start_server(TLSPORT, flags, function() { + var flags = ['--tlsverify', '--tlscert', './test/certs/server-cert.pem', + '--tlskey', './test/certs/server-key.pem', + '--tlscacert', './test/certs/ca.pem' + ]; + tlsVerifyServer = nsc.start_server(TLSVERIFYPORT, flags, done); + }); + }); }); - }); - - - // Shutdown our server after each test. - after(function() { - server.kill(); - tlsServer.kill(); - tlsVerifyServer.kill(); - }); - - it('should error if server does not support TLS', function(done) { - var nc = NATS.connect({port: PORT, tls: true}); - nc.on('error', function(err) { - should.exist(err); - should.exist(/Server does not support a secure/.exec(err)); - nc.close(); - done(); + + + // Shutdown our server after each test. + after(function() { + server.kill(); + tlsServer.kill(); + tlsVerifyServer.kill(); }); - }); - - it('should error if server requires TLS', function(done) { - var nc = NATS.connect(TLSPORT); - nc.on('error', function(err) { - should.exist(err); - should.exist(/Server requires a secure/.exec(err)); - nc.close(); - done(); + + it('should error if server does not support TLS', function(done) { + var nc = NATS.connect({ + port: PORT, + tls: true + }); + nc.on('error', function(err) { + should.exist(err); + should.exist(/Server does not support a secure/.exec(err)); + nc.close(); + done(); + }); }); - }); - - it('should reject without proper CA', function(done) { - var nc = NATS.connect({port: TLSPORT, tls: true}); - nc.on('error', function(err) { - should.exist(err); - should.exist(/unable to verify the first certificate/.exec(err)); - nc.close(); - done(); + + it('should error if server requires TLS', function(done) { + var nc = NATS.connect(TLSPORT); + nc.on('error', function(err) { + should.exist(err); + should.exist(/Server requires a secure/.exec(err)); + nc.close(); + done(); + }); }); - }); - - it('should connect if authorized is overridden', function(done) { - var tlsOptions = { - rejectUnauthorized: false, - }; - var nc = NATS.connect({port: TLSPORT, tls: tlsOptions}); - should.exist(nc); - nc.on('connect', function(client) { - client.should.equal(nc); - nc.stream.authorized.should.equal(false); - nc.close(); - done(); + + it('should reject without proper CA', function(done) { + var nc = NATS.connect({ + port: TLSPORT, + tls: true + }); + nc.on('error', function(err) { + should.exist(err); + should.exist(/unable to verify the first certificate/.exec(err)); + nc.close(); + done(); + }); }); - }); - - it('should connect with proper ca and be authorized', function(done) { - var tlsOptions = { - ca: [ fs.readFileSync('./test/certs/ca.pem') ] - }; - var nc = NATS.connect({port: TLSPORT, tls: tlsOptions}); - should.exist(nc); - nc.on('connect', function(client) { - client.should.equal(nc); - nc.stream.authorized.should.equal(true); - nc.close(); - done(); + + it('should connect if authorized is overridden', function(done) { + var tlsOptions = { + rejectUnauthorized: false, + }; + var nc = NATS.connect({ + port: TLSPORT, + tls: tlsOptions + }); + should.exist(nc); + nc.on('connect', function(client) { + client.should.equal(nc); + nc.stream.authorized.should.equal(false); + nc.close(); + done(); + }); }); - }); - - it('should reject without proper cert if required by server', function(done) { - var nc = NATS.connect({port: TLSVERIFYPORT, tls: true}); - nc.on('error', function(err) { - should.exist(err); - should.exist(/Server requires a client certificate/.exec(err)); - nc.close(); - done(); + + it('should connect with proper ca and be authorized', function(done) { + var tlsOptions = { + ca: [fs.readFileSync('./test/certs/ca.pem')] + }; + var nc = NATS.connect({ + port: TLSPORT, + tls: tlsOptions + }); + should.exist(nc); + nc.on('connect', function(client) { + client.should.equal(nc); + nc.stream.authorized.should.equal(true); + nc.close(); + done(); + }); + }); + + it('should reject without proper cert if required by server', function(done) { + var nc = NATS.connect({ + port: TLSVERIFYPORT, + tls: true + }); + nc.on('error', function(err) { + should.exist(err); + should.exist(/Server requires a client certificate/.exec(err)); + nc.close(); + done(); + }); }); - }); - - - it('should be authrorized with proper cert', function(done) { - var tlsOptions = { - key: fs.readFileSync('./test/certs/client-key.pem'), - cert: fs.readFileSync('./test/certs/client-cert.pem'), - ca: [ fs.readFileSync('./test/certs/ca.pem') ] - }; - var nc = NATS.connect({port: TLSPORT, tls: tlsOptions}); - nc.on('connect', function(client) { - client.should.equal(nc); - nc.stream.authorized.should.equal(true); - nc.close(); - done(); + + + it('should be authrorized with proper cert', function(done) { + var tlsOptions = { + key: fs.readFileSync('./test/certs/client-key.pem'), + cert: fs.readFileSync('./test/certs/client-cert.pem'), + ca: [fs.readFileSync('./test/certs/ca.pem')] + }; + var nc = NATS.connect({ + port: TLSPORT, + tls: tlsOptions + }); + nc.on('connect', function(client) { + client.should.equal(nc); + nc.stream.authorized.should.equal(true); + nc.close(); + done(); + }); }); - }); }); diff --git a/test/utf8.js b/test/utf8.js index 70b3da99..48368a5f 100644 --- a/test/utf8.js +++ b/test/utf8.js @@ -2,76 +2,82 @@ /* global describe: false, before: false, after: false, it: false */ 'use strict'; -var NATS = require ('../'), +var NATS = require('../'), nsc = require('./support/nats_server_control'), should = require('should'); describe('UTF8', function() { - var PORT = 1430; - var server; + var PORT = 1430; + var server; - // Start up our own nats-server - before(function(done) { - server = nsc.start_server(PORT, done); - }); + // Start up our own nats-server + before(function(done) { + server = nsc.start_server(PORT, done); + }); + + // Shutdown our server + after(function() { + server.kill(); + }); - // Shutdown our server - after(function() { - server.kill(); - }); + it('should do publish and subscribe with UTF8 payloads by default', function(done) { + var nc = NATS.connect(PORT); + // ½ + ¼ = ¾: 9 characters, 12 bytes + var data = '\u00bd + \u00bc = \u00be'; + data.length.should.equal(9); + Buffer.byteLength(data).should.equal(12); - it('should do publish and subscribe with UTF8 payloads by default', function(done) { - var nc = NATS.connect(PORT); - // ½ + ¼ = ¾: 9 characters, 12 bytes - var data = '\u00bd + \u00bc = \u00be'; - data.length.should.equal(9); - Buffer.byteLength(data).should.equal(12); + nc.subscribe('utf8', function(msg) { + should.exists(msg); + msg.should.equal(data); + nc.close(); + done(); + }); - nc.subscribe('utf8', function(msg) { - should.exists(msg); - msg.should.equal(data); - nc.close(); - done(); + nc.publish('utf8', data); }); - nc.publish('utf8', data); - }); + it('should allow encoding override with the encoding option', function(done) { + var nc = NATS.connect({ + 'url': 'nats://localhost:' + PORT, + 'encoding': 'ascii' + }); + // ½ + ¼ = ¾: 9 characters, 12 bytes + var utf8_data = '\u00bd + \u00bc = \u00be'; + var plain_data = 'Hello World'; - it('should allow encoding override with the encoding option', function(done) { - var nc = NATS.connect({'url': 'nats://localhost:' + PORT, 'encoding': 'ascii'}); - // ½ + ¼ = ¾: 9 characters, 12 bytes - var utf8_data = '\u00bd + \u00bc = \u00be'; - var plain_data = 'Hello World'; + nc.subscribe('utf8', function(msg) { + // Should be all 12 bytes.. + msg.length.should.equal(12); + // Should not be a proper utf8 string. + msg.should.not.equal(utf8_data); + }); - nc.subscribe('utf8', function(msg) { - // Should be all 12 bytes.. - msg.length.should.equal(12); - // Should not be a proper utf8 string. - msg.should.not.equal(utf8_data); - }); + nc.subscribe('plain', function(msg) { + msg.should.equal(plain_data); + nc.close(); + done(); + }); - nc.subscribe('plain', function(msg) { - msg.should.equal(plain_data); - nc.close(); - done(); + nc.publish('utf8', utf8_data); + nc.publish('plain', plain_data); }); - nc.publish('utf8', utf8_data); - nc.publish('plain', plain_data); - }); - - it('should not allow unsupported encodings', function(done) { - try { - NATS.connect({'url': 'nats://localhost:' + PORT, 'encoding': 'foobar'}); - done('No error thrown, wanted Invalid Encoding Exception'); - } catch(err) { - if (err.toString().indexOf('Invalid Encoding') < 0) { - done('Bad Error, wanted Invalid Encoding'); - } else { - done(); - } - } - }); + it('should not allow unsupported encodings', function(done) { + try { + NATS.connect({ + 'url': 'nats://localhost:' + PORT, + 'encoding': 'foobar' + }); + done('No error thrown, wanted Invalid Encoding Exception'); + } catch (err) { + if (err.toString().indexOf('Invalid Encoding') < 0) { + done('Bad Error, wanted Invalid Encoding'); + } else { + done(); + } + } + }); }); diff --git a/test/yield.js b/test/yield.js index a5396a00..84885d54 100644 --- a/test/yield.js +++ b/test/yield.js @@ -2,44 +2,47 @@ /* global describe: false, before: false, after: false, it: false */ 'use strict'; -var NATS = require ('../'), +var NATS = require('../'), nsc = require('./support/nats_server_control'), sleep = require('./support/sleep'), should = require('should'); describe('Yield', function() { - var PORT = 1469; - var server; - - // Start up our own nats-server - before(function(done) { - server = nsc.start_server(PORT, done); - }); - - // Shutdown our server - after(function() { - server.kill(); - }); - - it('should yield to other events', function(done) { - var nc = NATS.connect({port: PORT, yieldTime: 5}); - - var start = Date.now(); - - var timer = setInterval(function() { - var delta = Date.now() - start; - nc.close(); - clearTimeout(timer); - delta.should.within(10, 25); - done(); - }, 10); - - nc.subscribe('foo', function() { - sleep.sleep(1); + var PORT = 1469; + var server; + + // Start up our own nats-server + before(function(done) { + server = nsc.start_server(PORT, done); + }); + + // Shutdown our server + after(function() { + server.kill(); }); - for (var i = 0; i < 256; i++) { - nc.publish('foo', 'hello world'); - } - }); + it('should yield to other events', function(done) { + var nc = NATS.connect({ + port: PORT, + yieldTime: 5 + }); + + var start = Date.now(); + + var timer = setInterval(function() { + var delta = Date.now() - start; + nc.close(); + clearTimeout(timer); + delta.should.within(10, 25); + done(); + }, 10); + + nc.subscribe('foo', function() { + sleep.sleep(1); + }); + + for (var i = 0; i < 256; i++) { + nc.publish('foo', 'hello world'); + } + }); });