├── .gitignore ├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── example ├── publish.js └── subscribe.js ├── index.js ├── lib ├── channel.js ├── connection.js └── index.js ├── package.json └── test ├── channel.js ├── connection.js ├── fixtures └── data.json └── helpers.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | - "0.11" 5 | - "0.12" 6 | - "5" 7 | - "4" 8 | script: "npm test" 9 | services: 10 | - mongodb 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2012-2014 Scott Nelson 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | ./node_modules/.bin/mocha --reporter list --timeout 10000 3 | 4 | .PHONY: test -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## mubsub 2 | 3 | Mubsub is a pub/sub implementation for Node.js and MongoDB. It utilizes Mongo's capped collections and tailable cursors to notify subscribers of inserted documents that match a given query. 4 | 5 | [![NPM](https://img.shields.io/npm/v/mubsub.svg?style=flat)](http://npm.im/mubsub) 6 | [![Build Status](https://img.shields.io/travis/scttnlsn/mubsub.svg?style=flat)](https://travis-ci.org/scttnlsn/mubsub) 7 | 8 | ## Example 9 | 10 | ```javascript 11 | var mubsub = require('mubsub'); 12 | 13 | var client = mubsub('mongodb://localhost:27017/mubsub_example'); 14 | var channel = client.channel('test'); 15 | 16 | client.on('error', console.error); 17 | channel.on('error', console.error); 18 | 19 | channel.subscribe('bar', function (message) { 20 | console.log(message.foo); // => 'bar' 21 | }); 22 | 23 | channel.subscribe('baz', function (message) { 24 | console.log(message); // => 'baz' 25 | }); 26 | 27 | channel.publish('bar', { foo: 'bar' }); 28 | channel.publish('baz', 'baz'); 29 | 30 | ``` 31 | 32 | ## Usage 33 | 34 | ### Create a client 35 | 36 | You can pass a Db instance or a URI string. For more information about the URI format visit [http://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html](http://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html) 37 | 38 | ```javascript 39 | var mubsub = require('mubsub'); 40 | 41 | // Using a URI 42 | var client = mubsub('mongodb://localhost:27017/mubsub_example', [options]); 43 | 44 | // Passing a MongoDB driver `Db` instance directly. 45 | var client = mubsub(new Db(...)); 46 | ``` 47 | 48 | ### Channels 49 | 50 | A channel maps one-to-one with a capped collection (Mubsub will create these if they do not already exist in the database). Optionally specify the byte size of the collection and/or the max number of documents in the collection when creating a channel. 51 | 52 | **WARNING**: You should not create lots of channels because Mubsub will poll from the cursor position. 53 | 54 | ```javascript 55 | var channel = client.channel('foo', { size: 100000, max: 500 }); 56 | ``` 57 | 58 | Options: 59 | 60 | - `size` max size of the collection in bytes, default is 5mb 61 | - `max` max amount of documents in the collection 62 | - `retryInterval` time in ms to wait if no docs are found, default is 200ms 63 | - `recreate` recreate the tailable cursor when an error occurs, default is true 64 | 65 | 66 | **WARNING**: Don't remove collections with running publishers. It's possible for `mongod` to recreate the collection on the next insert (before Mubsub has the chance to do so). If this happens the collection will be recreated as a normal, uncapped collection. 67 | 68 | ### Subscribe 69 | 70 | ```javascript 71 | var subscription = channel.subscribe([event], callback); 72 | ``` 73 | 74 | Subscriptions register a callback to be called whenever a document matching the specified event is inserted (published) into the collection (channel). You can omit the event to match all inserted documents. To later unsubscribe a particular callback, call `unsubscribe` on the returned subscription object: 75 | 76 | ```javascript 77 | subscription.unsubscribe(); 78 | ``` 79 | ### Publish 80 | 81 | ```javascript 82 | channel.publish(event, obj, [callback]); 83 | ``` 84 | 85 | Publishing a document simply inserts the document into the channel's capped collection. A callback is optional. 86 | 87 | ### Listen to events 88 | 89 | The following events will be emitted: 90 | 91 | ```javascript 92 | // The given event was published 93 | channel.on('myevent', console.log); 94 | 95 | // Any event was published 96 | channel.on('message', console.log); 97 | 98 | // Document was inserted 99 | channel.on('document', console.log); 100 | 101 | // Mubsub is ready to receive new documents 102 | channel.on('ready', console.log); 103 | 104 | // Connection error 105 | client.on('error', console.log); 106 | 107 | // Channel error 108 | channel.on('error', console.log); 109 | ``` 110 | 111 | ### Close 112 | 113 | ```javascript 114 | client.close(); 115 | ``` 116 | 117 | Closes the MongoDB connection. 118 | 119 | ## Install 120 | 121 | npm install mubsub 122 | 123 | ## Tests 124 | 125 | make test 126 | 127 | You can optionally specify the MongoDB URI to be used for tests: 128 | 129 | MONGODB_URI=mongodb://localhost:27017/mubsub_tests make test 130 | 131 | ## Projects using mubsub 132 | 133 | - [simpleio](https://github.com/kof/simpleio) Simple long polling based communication. 134 | -------------------------------------------------------------------------------- /example/publish.js: -------------------------------------------------------------------------------- 1 | var mubsub = require('../lib/index'); 2 | 3 | var client = mubsub(process.env.MONGODB_URI || 'mongodb://localhost:27017/mubsub_example'); 4 | var channel = client.channel('example'); 5 | 6 | channel.on('error', console.error); 7 | client.on('error', console.error) 8 | 9 | setInterval(function () { 10 | channel.publish('foo', { foo: 'bar', time: Date.now() }, function (err) { 11 | if (err) throw err; 12 | }); 13 | }, 2000); 14 | -------------------------------------------------------------------------------- /example/subscribe.js: -------------------------------------------------------------------------------- 1 | var mubsub = require('../lib/index'); 2 | 3 | var client = mubsub(process.env.MONGODB_URI || 'mongodb://localhost:27017/mubsub_example'); 4 | var channel = client.channel('example'); 5 | 6 | channel.on('error', console.error); 7 | client.on('error', console.error); 8 | 9 | channel.subscribe('foo', function (message) { 10 | console.log(message); 11 | }); 12 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib'); 2 | -------------------------------------------------------------------------------- /lib/channel.js: -------------------------------------------------------------------------------- 1 | var EventEmitter = require('events').EventEmitter; 2 | var util = require('util'); 3 | 4 | var noop = function () {}; 5 | 6 | /** 7 | * Channel constructor. 8 | * 9 | * @param {Connection} connection 10 | * @param {String} [name] optional channel/collection name, default is 'mubsub' 11 | * @param {Object} [options] optional options 12 | * - `size` max size of the collection in bytes, default is 5mb 13 | * - `max` max amount of documents in the collection 14 | * - `retryInterval` time in ms to wait if no docs found, default is 200ms 15 | * - `recreate` recreate the tailable cursor on error, default is true 16 | * @api public 17 | */ 18 | function Channel(connection, name, options) { 19 | options || (options = {}); 20 | options.capped = true; 21 | // In mongo v <= 2.2 index for _id is not done by default 22 | options.autoIndexId = true; 23 | options.size || (options.size = 1024 * 1024 * 5); 24 | options.strict = false; 25 | 26 | this.options = options; 27 | this.connection = connection; 28 | this.closed = false; 29 | this.listening = null; 30 | this.name = name || 'mubsub'; 31 | 32 | this.create().listen(); 33 | this.setMaxListeners(0); 34 | } 35 | 36 | module.exports = Channel; 37 | util.inherits(Channel, EventEmitter); 38 | 39 | /** 40 | * Close the channel. 41 | * 42 | * @return {Channel} this 43 | * @api public 44 | */ 45 | Channel.prototype.close = function () { 46 | this.closed = true; 47 | 48 | return this; 49 | }; 50 | 51 | /** 52 | * Publish an event. 53 | * 54 | * @param {String} event 55 | * @param {Object} [message] 56 | * @param {Function} [callback] 57 | * @return {Channel} this 58 | * @api public 59 | */ 60 | Channel.prototype.publish = function (event, message, callback) { 61 | var options = callback ? { safe: true } : {}; 62 | callback || (callback = noop); 63 | 64 | this.ready(function (collection) { 65 | collection.insert({ event: event, message: message }, options, function (err, docs) { 66 | if (err) return callback(err); 67 | callback(null, docs.ops[0]); 68 | }); 69 | }); 70 | 71 | return this; 72 | }; 73 | 74 | /** 75 | * Subscribe an event. 76 | * 77 | * @param {String} [event] if no event passed - all events are subscribed. 78 | * @param {Function} callback 79 | * @return {Object} unsubscribe function 80 | * @api public 81 | */ 82 | Channel.prototype.subscribe = function (event, callback) { 83 | var self = this; 84 | 85 | if (typeof event == 'function') { 86 | callback = event; 87 | event = 'message'; 88 | } 89 | 90 | this.on(event, callback); 91 | 92 | return { 93 | unsubscribe: function () { 94 | self.removeListener(event, callback); 95 | } 96 | }; 97 | }; 98 | 99 | /** 100 | * Create a channel collection. 101 | * 102 | * @return {Channel} this 103 | * @api private 104 | */ 105 | Channel.prototype.create = function () { 106 | var self = this; 107 | 108 | function create() { 109 | self.connection.db.createCollection( 110 | self.name, 111 | self.options, 112 | function (err, collection) { 113 | if (err && err.message === 'collection already exists') { 114 | return self.create(); 115 | } else if (err) { 116 | return self.emit('error', err); 117 | } 118 | 119 | self.emit('collection', self.collection = collection); 120 | } 121 | ); 122 | } 123 | 124 | this.connection.db ? create() : this.connection.once('connect', create); 125 | 126 | return this; 127 | }; 128 | 129 | /** 130 | * Create a listener which will emit events for subscribers. 131 | * It will listen to any document with event property. 132 | * 133 | * @param {Object} [latest] latest document to start listening from 134 | * @return {Channel} this 135 | * @api private 136 | */ 137 | Channel.prototype.listen = function (latest) { 138 | var self = this; 139 | 140 | this.latest(latest, this.handle(true, function (latest, collection) { 141 | var cursor = collection 142 | .find( 143 | { _id: { $gt: latest._id }}, 144 | { 145 | tailable: true, 146 | awaitData: true, 147 | timeout: false, 148 | sortValue: {$natural: -1}, 149 | numberOfRetries: Number.MAX_VALUE, 150 | tailableRetryInterval: self.options.retryInterval 151 | } 152 | ); 153 | 154 | var next = self.handle(function (doc) { 155 | // There is no document only if the cursor is closed by accident. 156 | // F.e. if collection was dropped or connection died. 157 | if (!doc) { 158 | return setTimeout(function () { 159 | self.emit('error', new Error('Mubsub: broken cursor.')); 160 | if (self.options.recreate) { 161 | self.create().listen(latest); 162 | } 163 | }, 1000); 164 | } 165 | 166 | latest = doc; 167 | 168 | if (doc.event) { 169 | self.emit(doc.event, doc.message); 170 | self.emit('message', doc.message); 171 | } 172 | self.emit('document', doc); 173 | process.nextTick(more); 174 | }); 175 | 176 | var more = function () { 177 | cursor.nextObject(next); 178 | }; 179 | 180 | more(); 181 | self.listening = collection; 182 | self.emit('ready', collection); 183 | })); 184 | 185 | return this; 186 | }; 187 | 188 | /** 189 | * Get the latest document from the collection. Insert a dummy object in case 190 | * the collection is empty, because otherwise we don't get a tailable cursor 191 | * and need to poll in a loop. 192 | * 193 | * @param {Object} [latest] latest known document 194 | * @param {Function} callback 195 | * @return {Channel} this 196 | * @api private 197 | */ 198 | Channel.prototype.latest = function (latest, callback) { 199 | function onCollection(collection) { 200 | collection 201 | .find(latest ? { _id: latest._id } : null, {timeout: false}) 202 | .sort({$natural: -1}) 203 | .limit(1) 204 | .nextObject(function (err, doc) { 205 | if (err || doc) return callback(err, doc, collection); 206 | 207 | collection.insert({ 'dummy': true }, { safe: true }, function (err, docs) { 208 | if (err) return cb(err); 209 | callback(err, docs.ops[0], collection); 210 | }); 211 | }); 212 | } 213 | 214 | this.collection ? onCollection(this.collection) : this.once('collection', onCollection); 215 | 216 | return this; 217 | }; 218 | 219 | /** 220 | * Return a function which will handle errors and consider channel and connection 221 | * state. 222 | * 223 | * @param {Boolean} [exit] if error happens and exit is true, callback will not be called 224 | * @param {Function} callback 225 | * @return {Function} 226 | * @api private 227 | */ 228 | Channel.prototype.handle = function (exit, callback) { 229 | var self = this; 230 | 231 | if (typeof exit === 'function') { 232 | callback = exit; 233 | exit = null; 234 | } 235 | 236 | return function () { 237 | if (self.closed || self.connection.destroyed) return; 238 | 239 | var args = [].slice.call(arguments); 240 | var err = args.shift(); 241 | 242 | if (err) self.emit('error', err); 243 | if (err && exit) return; 244 | 245 | callback.apply(self, args); 246 | }; 247 | }; 248 | 249 | /** 250 | * Call back if collection is ready for publishing. 251 | * 252 | * @param {Function} callback 253 | * @return {Channel} this 254 | * @api private 255 | */ 256 | Channel.prototype.ready = function (callback) { 257 | if (this.listening) { 258 | callback(this.listening); 259 | } else { 260 | this.once('ready', callback); 261 | } 262 | 263 | return this; 264 | }; 265 | -------------------------------------------------------------------------------- /lib/connection.js: -------------------------------------------------------------------------------- 1 | var EventEmitter = require('events').EventEmitter; 2 | var util = require('util'); 3 | var MongoClient = require('mongodb').MongoClient; 4 | var Channel = require('./channel'); 5 | 6 | /** 7 | * Connection constructor. 8 | * 9 | * @param {String|Db} uri string or Db instance 10 | * @param {Object} mongo driver options 11 | * @api public 12 | */ 13 | function Connection(uri, options) { 14 | var self = this; 15 | 16 | options || (options = {}); 17 | options.autoReconnect != null || (options.autoReconnect = true); 18 | 19 | // It's a Db instance. 20 | if (uri.collection) { 21 | this.db = uri; 22 | } else { 23 | MongoClient.connect(uri, options, function (err, db) { 24 | if (err) return self.emit('error', err); 25 | self.db = db; 26 | self.emit('connect', db); 27 | db.on('error', function (err) { 28 | self.emit('error', err); 29 | }); 30 | }); 31 | } 32 | 33 | this.destroyed = false; 34 | this.channels = {}; 35 | } 36 | 37 | module.exports = Connection; 38 | util.inherits(Connection, EventEmitter); 39 | 40 | /** 41 | * Current connection state. 42 | * 43 | * @type {String} 44 | * @api public 45 | */ 46 | Object.defineProperty(Connection.prototype, 'state', { 47 | enumerable: true, 48 | 49 | get: function () { 50 | var state; 51 | 52 | // Using 'destroyed' to be compatible with the driver. 53 | if (this.destroyed) { 54 | state = 'destroyed'; 55 | } 56 | else if (this.db) { 57 | state = this.db.serverConfig.isConnected() 58 | ? 'connected' : 'disconnected'; 59 | } else { 60 | state = 'connecting'; 61 | } 62 | 63 | return state; 64 | } 65 | }); 66 | 67 | /** 68 | * Creates or returns a channel with the passed name. 69 | * 70 | * @see Channel 71 | * @return {Channel} 72 | * @api public 73 | */ 74 | Connection.prototype.channel = function (name, options) { 75 | if (typeof name === 'object') { 76 | options = name; 77 | name = 'mubsub'; 78 | } 79 | 80 | if (!this.channels[name] || this.channels[name].closed) { 81 | this.channels[name] = new Channel(this, name, options); 82 | } 83 | 84 | return this.channels[name]; 85 | }; 86 | 87 | /** 88 | * Close connection. 89 | * 90 | * @param {Function} [callback] 91 | * @return {Connection} this 92 | * @api public 93 | */ 94 | Connection.prototype.close = function (callback) { 95 | this.destroyed = true; 96 | this.db.close(callback); 97 | 98 | return this; 99 | }; 100 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | var Connection = require('./connection'); 2 | var Channel = require('./channel'); 3 | var mongodb = require('mongodb'); 4 | 5 | /** 6 | * Create connection. 7 | * 8 | * @see Connection 9 | * @return {Connection} 10 | * @api public 11 | */ 12 | module.exports = exports = function (uri, options) { 13 | return new Connection(uri, options); 14 | }; 15 | 16 | /** 17 | * Mubsub version. 18 | * 19 | * @api public 20 | */ 21 | exports.version = require('../package').version; 22 | 23 | /** 24 | * Expose Connection constructor. 25 | * 26 | * @api public 27 | */ 28 | exports.Connection = Connection; 29 | 30 | /** 31 | * Expose Channel constructor. 32 | * 33 | * @api public 34 | */ 35 | exports.Channel = Channel; 36 | 37 | /** 38 | * Expose mongodb module. 39 | * 40 | * @api public 41 | */ 42 | exports.mongodb = mongodb; 43 | 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mubsub", 3 | "version": "1.4.0", 4 | "description": "Pub/sub for Node.js and MongoDB", 5 | "homepage": "http://github.com/scttnlsn/mubsub", 6 | "author": "Scott Nelson ", 7 | "license": "MIT", 8 | "main": "./lib/index", 9 | "keywords": [ 10 | "mongodb", 11 | "pubsub", 12 | "pub", 13 | "sub", 14 | "capped collection" 15 | ], 16 | "contributors": [ 17 | { 18 | "name": "Oleg Slobodskoi", 19 | "email": "oleg008@gmail.com" 20 | } 21 | ], 22 | "repository": { 23 | "type": "git", 24 | "url": "git://github.com/scttnlsn/mubsub.git" 25 | }, 26 | "dependencies": { 27 | "mongodb": "^2.0.35" 28 | }, 29 | "devDependencies": { 30 | "mocha": "^2.2.5" 31 | }, 32 | "scripts": { 33 | "test": "mocha test --timeout 10000", 34 | "publish": "git push origin && git push origin --tags", 35 | "release:patch": "npm version patch && npm publish", 36 | "release:minor": "npm version minor && npm publish", 37 | "release:major": "npm version major && npm publish" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test/channel.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var mubsub = require('../lib/index'); 3 | var data = require('./fixtures/data'); 4 | var helpers = require('./helpers'); 5 | 6 | describe('Channel', function () { 7 | beforeEach(function () { 8 | this.client = mubsub(helpers.uri); 9 | this.channel = this.client.channel('channel'); 10 | }); 11 | 12 | it('unsubscribes properly', function (done) { 13 | var subscription = this.channel.subscribe('a', function (data) { 14 | assert.equal(data, 'a'); 15 | subscription.unsubscribe(); 16 | done(); 17 | }); 18 | 19 | this.channel.publish('a', 'a'); 20 | this.channel.publish('a', 'a'); 21 | this.channel.publish('a', 'a'); 22 | }); 23 | 24 | it('unsubscribes if channel is closed', function (done) { 25 | var self = this; 26 | 27 | var subscription = this.channel.subscribe('a', function (data) { 28 | assert.equal(data, 'a'); 29 | self.channel.close(); 30 | done(); 31 | }); 32 | 33 | this.channel.publish('a', 'a'); 34 | this.channel.publish('a', 'a'); 35 | this.channel.publish('a', 'a'); 36 | }); 37 | 38 | it('unsubscribes if client is closed', function (done) { 39 | var self = this; 40 | 41 | var subscription = this.channel.subscribe('a', function (data) { 42 | assert.equal(data, 'a'); 43 | self.client.close(); 44 | done(); 45 | }); 46 | 47 | this.channel.publish('a', 'a'); 48 | this.channel.publish('a', 'a'); 49 | this.channel.publish('a', 'a'); 50 | }); 51 | 52 | it('should not emit old events to a second client', function (done) { 53 | var self = this; 54 | var channel0 = this.client.channel('channel1'); 55 | 56 | var subscription0 = channel0.subscribe('b', function (data) { 57 | subscription0.unsubscribe(); 58 | assert.equal(data, 'b'); 59 | 60 | // Client 0 have now published and received one event 61 | // Client 1 should not receive that event but should get the second event 62 | var client1 = mubsub(helpers.uri); 63 | var channel1 = client1.channel('channel1'); 64 | 65 | var subscription1 = channel1.subscribe('b', function (data) { 66 | subscription1.unsubscribe(); 67 | assert.equal(data, 'a'); 68 | done(); 69 | }); 70 | 71 | channel1.publish('b', 'a'); 72 | }); 73 | 74 | channel0.publish('b', 'b'); 75 | }); 76 | 77 | it('race condition should not occur', function (done) { 78 | var client0 = this.client; 79 | var client1 = mubsub(helpers.uri); 80 | 81 | client1.once('connect', function () { 82 | var channel0 = client0.channel('channel2'); 83 | var channel1 = client1.channel('channel2'); 84 | 85 | Promise.all([ 86 | new Promise(function (resolve, reject) { 87 | client0.channels.channel2.once('error', reject); 88 | client0.channels.channel2.once('collection', resolve); 89 | }), 90 | new Promise(function (resolve, reject) { 91 | client1.channels.channel2.once('error', reject); 92 | client1.channels.channel2.once('collection', resolve); 93 | }) 94 | ]).then(function () { 95 | done(); 96 | }, done); 97 | }); 98 | }); 99 | 100 | it('can subscribe and publish different events', function (done) { 101 | var todo = 3; 102 | var subscriptions = []; 103 | 104 | function complete() { 105 | todo--; 106 | 107 | if (!todo) { 108 | subscriptions.forEach(function (subscriptions) { 109 | subscriptions.unsubscribe(); 110 | }); 111 | 112 | done(); 113 | } 114 | } 115 | 116 | subscriptions.push(this.channel.subscribe('a', function (data) { 117 | assert.equal(data, 'a'); 118 | complete(); 119 | })); 120 | 121 | subscriptions.push(this.channel.subscribe('b', function (data) { 122 | assert.deepEqual(data, {b: 1}); 123 | complete(); 124 | })); 125 | 126 | subscriptions.push(this.channel.subscribe('c', function (data) { 127 | assert.deepEqual(data, ['c']); 128 | complete(); 129 | })); 130 | 131 | this.channel.publish('a', 'a'); 132 | this.channel.publish('b', { b: 1 }); 133 | this.channel.publish('c', ['c']); 134 | }); 135 | 136 | it('gets lots of subscribed data fast enough', function (done) { 137 | var channel = this.client.channel('channel.bench', { size: 1024 * 1024 * 100 }); 138 | 139 | var n = 5000; 140 | var count = 0; 141 | 142 | var subscription = channel.subscribe('a', function (_data) { 143 | assert.deepEqual(_data, data); 144 | 145 | if (++count == n) { 146 | subscription.unsubscribe(); 147 | done(); 148 | } 149 | }); 150 | 151 | for (var i = 0; i < n; i++) { 152 | channel.publish('a', data); 153 | } 154 | }); 155 | }); 156 | -------------------------------------------------------------------------------- /test/connection.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var mubsub = require('../lib/index'); 3 | var helpers = require('./helpers'); 4 | 5 | describe('Connection', function () { 6 | it('emits "error" event', function (done) { 7 | mubsub('mongodb://localhost:6666/mubsub_tests').on('error', function () { 8 | done(); 9 | }); 10 | }); 11 | 12 | it('emits "connect" event', function (done) { 13 | this.client = mubsub(helpers.uri); 14 | 15 | this.client.on('connect', function (db) { 16 | done(); 17 | }); 18 | }); 19 | 20 | 21 | it('states are correct', function (done) { 22 | var self = this; 23 | 24 | this.client = mubsub(helpers.uri); 25 | 26 | this.client.on('connect', function () { 27 | assert.equal(self.client.state, 'connected'); 28 | 29 | self.client.close(); 30 | assert.equal(self.client.state, 'destroyed'); 31 | 32 | done(); 33 | }); 34 | 35 | assert.equal(self.client.state, 'connecting'); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /test/fixtures/data.json: -------------------------------------------------------------------------------- 1 | {"a": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"} 2 | -------------------------------------------------------------------------------- /test/helpers.js: -------------------------------------------------------------------------------- 1 | var mubsub = require('../lib/index'); 2 | 3 | exports.uri = process.env.MONGODB_URI || 'mongodb://localhost:27017/mubsub_tests'; 4 | 5 | exports.clear = function (done) { 6 | var self = this; 7 | 8 | mubsub(exports.uri).on('connect', function (db) { 9 | if (self.client) self.client.close(); 10 | db.dropDatabase(done); 11 | }); 12 | }; 13 | 14 | before(function (done) { 15 | exports.clear.call(this, done); 16 | }); 17 | 18 | after(function (done) { 19 | exports.clear.call(this, done); 20 | }); 21 | --------------------------------------------------------------------------------