diff --git a/src/database/mongo.js b/src/database/mongo.js index fc37c7ae74..507a9c9a86 100644 --- a/src/database/mongo.js +++ b/src/database/mongo.js @@ -161,8 +161,11 @@ mongoModule.createIndices = function (callback) { mongoModule.checkCompatibility = function (callback) { var mongoPkg = require('mongodb/package.json'); + mongoModule.checkCompatibilityVersion(mongoPkg.version, callback); +}; - if (semver.lt(mongoPkg.version, '2.0.0')) { +mongoModule.checkCompatibilityVersion = function (version, callback) { + if (semver.lt(version, '2.0.0')) { return callback(new Error('The `mongodb` package is out-of-date, please run `./nodebb setup` again.')); } @@ -173,66 +176,75 @@ mongoModule.info = function (db, callback) { if (!db) { return callback(); } - async.parallel({ - serverStatus: function (next) { - db.command({ serverStatus: 1 }, next); - }, - stats: function (next) { - db.command({ dbStats: 1 }, next); + async.waterfall([ + function (next) { + async.parallel({ + serverStatus: function (next) { + db.command({ serverStatus: 1 }, next); + }, + stats: function (next) { + db.command({ dbStats: 1 }, next); + }, + listCollections: function (next) { + getCollectionStats(db, next); + }, + }, next); }, - listCollections: function (next) { - db.listCollections().toArray(function (err, items) { - if (err) { - return next(err); - } - async.map(items, function (collection, next) { - db.collection(collection.name).stats(next); - }, next); + function (results, next) { + var stats = results.stats; + var scale = 1024 * 1024 * 1024; + + results.listCollections = results.listCollections.map(function (collectionInfo) { + return { + name: collectionInfo.ns, + count: collectionInfo.count, + size: collectionInfo.size, + avgObjSize: collectionInfo.avgObjSize, + storageSize: collectionInfo.storageSize, + totalIndexSize: collectionInfo.totalIndexSize, + indexSizes: collectionInfo.indexSizes, + }; }); - }, - }, function (err, results) { - if (err) { - return callback(err); - } - var stats = results.stats; - var scale = 1024 * 1024 * 1024; - - results.listCollections = results.listCollections.map(function (collectionInfo) { - return { - name: collectionInfo.ns, - count: collectionInfo.count, - size: collectionInfo.size, - avgObjSize: collectionInfo.avgObjSize, - storageSize: collectionInfo.storageSize, - totalIndexSize: collectionInfo.totalIndexSize, - indexSizes: collectionInfo.indexSizes, - }; - }); - stats.mem = results.serverStatus.mem; - stats.mem = results.serverStatus.mem; - stats.mem.resident = (stats.mem.resident / 1024).toFixed(2); - stats.mem.virtual = (stats.mem.virtual / 1024).toFixed(2); - stats.mem.mapped = (stats.mem.mapped / 1024).toFixed(2); - stats.collectionData = results.listCollections; - stats.network = results.serverStatus.network; - stats.raw = JSON.stringify(stats, null, 4); - - stats.avgObjSize = stats.avgObjSize.toFixed(2); - stats.dataSize = (stats.dataSize / scale).toFixed(2); - stats.storageSize = (stats.storageSize / scale).toFixed(2); - stats.fileSize = stats.fileSize ? (stats.fileSize / scale).toFixed(2) : 0; - stats.indexSize = (stats.indexSize / scale).toFixed(2); - stats.storageEngine = results.serverStatus.storageEngine ? results.serverStatus.storageEngine.name : 'mmapv1'; - stats.host = results.serverStatus.host; - stats.version = results.serverStatus.version; - stats.uptime = results.serverStatus.uptime; - stats.mongo = true; - - callback(null, stats); - }); + stats.mem = results.serverStatus.mem; + stats.mem = results.serverStatus.mem; + stats.mem.resident = (stats.mem.resident / 1024).toFixed(2); + stats.mem.virtual = (stats.mem.virtual / 1024).toFixed(2); + stats.mem.mapped = (stats.mem.mapped / 1024).toFixed(2); + stats.collectionData = results.listCollections; + stats.network = results.serverStatus.network; + stats.raw = JSON.stringify(stats, null, 4); + + stats.avgObjSize = stats.avgObjSize.toFixed(2); + stats.dataSize = (stats.dataSize / scale).toFixed(2); + stats.storageSize = (stats.storageSize / scale).toFixed(2); + stats.fileSize = stats.fileSize ? (stats.fileSize / scale).toFixed(2) : 0; + stats.indexSize = (stats.indexSize / scale).toFixed(2); + stats.storageEngine = results.serverStatus.storageEngine ? results.serverStatus.storageEngine.name : 'mmapv1'; + stats.host = results.serverStatus.host; + stats.version = results.serverStatus.version; + stats.uptime = results.serverStatus.uptime; + stats.mongo = true; + + next(null, stats); + }, + ], callback); }; -mongoModule.close = function () { - db.close(); +function getCollectionStats(db, callback) { + async.waterfall([ + function (next) { + db.listCollections().toArray(next); + }, + function (items, next) { + async.map(items, function (collection, next) { + db.collection(collection.name).stats(next); + }, next); + }, + ], callback); +} + +mongoModule.close = function (callback) { + callback = callback || function () {}; + db.close(callback); }; diff --git a/src/database/redis.js b/src/database/redis.js index 9ebc154705..d0d80d0038 100644 --- a/src/database/redis.js +++ b/src/database/redis.js @@ -1,6 +1,7 @@ 'use strict'; var _ = require('underscore'); +var async = require('async'); var winston = require('winston'); var nconf = require('nconf'); var semver = require('semver'); @@ -71,10 +72,6 @@ redisModule.connect = function (options) { var redis_socket_or_host = nconf.get('redis:host'); var cxn; - if (!redis) { - redis = require('redis'); - } - options = options || {}; if (nconf.get('redis:password')) { @@ -101,10 +98,10 @@ redisModule.connect = function (options) { } var dbIdx = parseInt(nconf.get('redis:database'), 10); - if (dbIdx) { - cxn.select(dbIdx, function (error) { - if (error) { - winston.error('NodeBB could not connect to your Redis database. Redis returned the following error: ' + error.message); + if (dbIdx >= 0) { + cxn.select(dbIdx, function (err) { + if (err) { + winston.error('NodeBB could not connect to your Redis database. Redis returned the following error: ' + err.message); process.exit(); } }); @@ -118,46 +115,52 @@ redisModule.createIndices = function (callback) { }; redisModule.checkCompatibility = function (callback) { - redisModule.info(redisModule.client, function (err, info) { - if (err) { - return callback(err); - } - - if (semver.lt(info.redis_version, '2.8.9')) { - return callback(new Error('Your Redis version is not new enough to support NodeBB, please upgrade Redis to v2.8.9 or higher.')); - } + async.waterfall([ + function (next) { + redisModule.info(redisModule.client, next); + }, + function (info, next) { + redisModule.checkCompatibilityVersion(info.redis_version, next); + }, + ], callback); +}; - callback(); - }); +redisModule.checkCompatibilityVersion = function (version, callback) { + if (semver.lt(version, '2.8.9')) { + return callback(new Error('Your Redis version is not new enough to support NodeBB, please upgrade Redis to v2.8.9 or higher.')); + } + callback(); }; -redisModule.close = function () { - redisClient.quit(); +redisModule.close = function (callback) { + callback = callback || function () {}; + redisClient.quit(callback); }; redisModule.info = function (cxn, callback) { if (!cxn) { return callback(); } - cxn.info(function (err, data) { - if (err) { - return callback(err); - } - - var lines = data.toString().split('\r\n').sort(); - var redisData = {}; - lines.forEach(function (line) { - var parts = line.split(':'); - if (parts[1]) { - redisData[parts[0]] = parts[1]; - } - }); - redisData.used_memory_human = (redisData.used_memory / (1024 * 1024 * 1024)).toFixed(2); - redisData.raw = JSON.stringify(redisData, null, 4); - redisData.redis = true; - - callback(null, redisData); - }); + async.waterfall([ + function (next) { + cxn.info(next); + }, + function (data, next) { + var lines = data.toString().split('\r\n').sort(); + var redisData = {}; + lines.forEach(function (line) { + var parts = line.split(':'); + if (parts[1]) { + redisData[parts[0]] = parts[1]; + } + }); + redisData.used_memory_human = (redisData.used_memory / (1024 * 1024 * 1024)).toFixed(2); + redisData.raw = JSON.stringify(redisData, null, 4); + redisData.redis = true; + + next(null, redisData); + }, + ], callback); }; redisModule.helpers = redisModule.helpers || {}; diff --git a/test/database.js b/test/database.js index f55bf78edb..327d8095cf 100644 --- a/test/database.js +++ b/test/database.js @@ -2,6 +2,7 @@ var assert = require('assert'); +var nconf = require('nconf'); var db = require('./mocks/databasemock'); @@ -12,14 +13,46 @@ describe('Test database', function () { }); }); - it('should return info about database', function (done) { - db.info(db.client, function (err, info) { - assert.ifError(err); - assert(info); - done(); + describe('info', function () { + it('should return info about database', function (done) { + db.info(db.client, function (err, info) { + assert.ifError(err); + assert(info); + done(); + }); + }); + + it('should not error and return null if client is falsy', function (done) { + db.info(null, function (err, info) { + assert.ifError(err); + assert.equal(info, null); + done(); + }); + }); + }); + + describe('checkCompatibility', function () { + it('should not throw', function (done) { + db.checkCompatibility(done); + }); + + it('should return error with a too low version', function (done) { + var dbName = nconf.get('database'); + if (dbName === 'redis') { + db.checkCompatibilityVersion('2.4.0', function (err) { + assert.equal(err.message, 'Your Redis version is not new enough to support NodeBB, please upgrade Redis to v2.8.9 or higher.'); + done(); + }); + } else if (dbName === 'mongo') { + db.checkCompatibilityVersion('1.8.0', function (err) { + assert.equal(err.message, 'The `mongodb` package is out-of-date, please run `./nodebb setup` again.'); + done(); + }); + } }); }); + require('./database/keys'); require('./database/list'); require('./database/sets'); diff --git a/test/database/list.js b/test/database/list.js index 8475ad2f52..1f5d72c6c3 100644 --- a/test/database/list.js +++ b/test/database/list.js @@ -9,11 +9,18 @@ describe('List methods', function () { describe('listAppend()', function () { it('should append to a list', function (done) { db.listAppend('testList1', 5, function (err) { - assert.equal(err, null); + assert.ifError(err); assert.equal(arguments.length, 1); done(); }); }); + + it('should not add anyhing if key is falsy', function (done) { + db.listAppend(null, 3, function (err) { + assert.ifError(err); + done(); + }); + }); }); describe('listPrepend()', function () { @@ -38,6 +45,13 @@ describe('List methods', function () { done(); }); }); + + it('should not add anyhing if key is falsy', function (done) { + db.listPrepend(null, 3, function (err) { + assert.ifError(err); + done(); + }); + }); }); describe('getListRange()', function () { @@ -83,6 +97,14 @@ describe('List methods', function () { done(); }); }); + + it('should not get anyhing if key is falsy', function (done) { + db.getListRange(null, 0, -1, function (err, data) { + assert.ifError(err); + assert.equal(data, undefined); + done(); + }); + }); }); describe('listRemoveLast()', function () { @@ -105,6 +127,13 @@ describe('List methods', function () { done(); }); }); + + it('should not remove anyhing if key is falsy', function (done) { + db.listRemoveLast(null, function (err) { + assert.ifError(err); + done(); + }); + }); }); describe('listRemoveAll()', function () { @@ -132,6 +161,13 @@ describe('List methods', function () { }); }); }); + + it('should not remove anyhing if key is falsy', function (done) { + db.listRemoveAll(null, 3, function (err) { + assert.ifError(err); + done(); + }); + }); }); describe('listTrim()', function () { @@ -156,6 +192,13 @@ describe('List methods', function () { }); }); }); + + it('should not add anyhing if key is falsy', function (done) { + db.listTrim(null, 0, 3, function (err) { + assert.ifError(err); + done(); + }); + }); }); diff --git a/test/mocks/databasemock.js b/test/mocks/databasemock.js index 4432f944f1..5b186e7f35 100644 --- a/test/mocks/databasemock.js +++ b/test/mocks/databasemock.js @@ -81,6 +81,10 @@ var db = require('../../src/database'); + after(function (done) { + db.close(done); + }); + before(function (done) { this.timeout(30000); var meta; @@ -91,6 +95,9 @@ function (next) { db.emptydb(next); }, + function (next) { + db.createIndices(next); + }, function (next) { winston.info('test_database flushed'); meta = require('../../src/meta');