diff --git a/src/socket.io/modules.js b/src/socket.io/modules.js index a3a9ff4fe3..172d91e60f 100644 --- a/src/socket.io/modules.js +++ b/src/socket.io/modules.js @@ -12,16 +12,16 @@ var utils = require('../utils'); var server = require('./'); var user = require('../user'); -var SocketModules = { - chats: {}, - sounds: {}, - settings: {}, -}; +var SocketModules = module.exports; + +SocketModules.chats = {}; +SocketModules.sounds = {}; +SocketModules.settings = {}; /* Chat */ SocketModules.chats.getRaw = function (socket, data, callback) { - if (!data || !data.hasOwnProperty('mid')) { + if (!data || !data.hasOwnProperty('mid') || !data.hasOwnProperty('roomId')) { return callback(new Error('[[error:invalid-data]]')); } async.waterfall([ @@ -57,13 +57,14 @@ SocketModules.chats.newRoom = function (socket, data, callback) { return callback(new Error('[[error:too-many-messages]]')); } - Messaging.canMessageUser(socket.uid, data.touid, function (err) { - if (err) { - return callback(err); - } - - Messaging.newRoom(socket.uid, [data.touid], callback); - }); + async.waterfall([ + function (next) { + Messaging.canMessageUser(socket.uid, data.touid, next); + }, + function (next) { + Messaging.newRoom(socket.uid, [data.touid], next); + }, + ], callback); }; SocketModules.chats.send = function (socket, data, callback) { @@ -223,17 +224,21 @@ SocketModules.chats.leave = function (socket, roomid, callback) { SocketModules.chats.edit = function (socket, data, callback) { - if (!data || !data.roomId) { + if (!data || !data.roomId || !data.message) { return callback(new Error('[[error:invalid-data]]')); } - Messaging.canEdit(data.mid, socket.uid, function (err, allowed) { - if (err || !allowed) { - return callback(err || new Error('[[error:cant-edit-chat-message]]')); - } - - Messaging.editMessage(socket.uid, data.mid, data.roomId, data.message, callback); - }); + async.waterfall([ + function (next) { + Messaging.canEdit(data.mid, socket.uid, next); + }, + function (allowed, next) { + if (!allowed) { + return next(new Error('[[error:cant-edit-chat-message]]')); + } + Messaging.editMessage(socket.uid, data.mid, data.roomId, data.message, next); + }, + ], callback); }; SocketModules.chats.delete = function (socket, data, callback) { @@ -241,13 +246,18 @@ SocketModules.chats.delete = function (socket, data, callback) { return callback(new Error('[[error:invalid-data]]')); } - Messaging.canEdit(data.messageId, socket.uid, function (err, allowed) { - if (err || !allowed) { - return callback(err || new Error('[[error:cant-delete-chat-message]]')); - } + async.waterfall([ + function (next) { + Messaging.canEdit(data.messageId, socket.uid, next); + }, + function (allowed, next) { + if (!allowed) { + return next(new Error('[[error:cant-delete-chat-message]]')); + } - Messaging.deleteMessage(data.messageId, data.roomId, callback); - }); + Messaging.deleteMessage(data.messageId, data.roomId, next); + }, + ], callback); }; SocketModules.chats.canMessage = function (socket, roomId, callback) { @@ -255,37 +265,38 @@ SocketModules.chats.canMessage = function (socket, roomId, callback) { }; SocketModules.chats.markRead = function (socket, roomId, callback) { - if (!socket.uid) { + if (!socket.uid || !roomId) { return callback(new Error('[[error:invalid-data]]')); } - async.parallel({ - uidsInRoom: async.apply(Messaging.getUidsInRoom, roomId, 0, -1), - markRead: async.apply(Messaging.markRead, socket.uid, roomId), - }, function (err, results) { - if (err) { - return callback(err); - } - - Messaging.pushUnreadCount(socket.uid); - server.in('uid_' + socket.uid).emit('event:chats.markedAsRead', { roomId: roomId }); - - if (results.uidsInRoom.indexOf(socket.uid.toString()) === -1) { - return callback(); - } - - // Mark notification read - var nids = results.uidsInRoom.filter(function (uid) { - return parseInt(uid, 10) !== socket.uid; - }).map(function (uid) { - return 'chat_' + uid + '_' + roomId; - }); - - notifications.markReadMultiple(nids, socket.uid, function () { - user.notifications.pushCount(socket.uid); - }); - - callback(); - }); + async.waterfall([ + function (next) { + async.parallel({ + uidsInRoom: async.apply(Messaging.getUidsInRoom, roomId, 0, -1), + markRead: async.apply(Messaging.markRead, socket.uid, roomId), + }, next); + }, + function (results, next) { + Messaging.pushUnreadCount(socket.uid); + server.in('uid_' + socket.uid).emit('event:chats.markedAsRead', { roomId: roomId }); + + if (results.uidsInRoom.indexOf(socket.uid.toString()) === -1) { + return callback(); + } + + // Mark notification read + var nids = results.uidsInRoom.filter(function (uid) { + return parseInt(uid, 10) !== socket.uid; + }).map(function (uid) { + return 'chat_' + uid + '_' + roomId; + }); + + notifications.markReadMultiple(nids, socket.uid, function () { + user.notifications.pushCount(socket.uid); + }); + + next(); + }, + ], callback); }; SocketModules.chats.markAllRead = function (socket, data, callback) { @@ -301,8 +312,8 @@ SocketModules.chats.markAllRead = function (socket, data, callback) { }; SocketModules.chats.renameRoom = function (socket, data, callback) { - if (!data) { - return callback(new Error('[[error:invalid-name]]')); + if (!data || !data.roomId || !data.newName) { + return callback(new Error('[[error:invalid-data]]')); } async.waterfall([ @@ -333,13 +344,13 @@ SocketModules.chats.getRecentChats = function (socket, data, callback) { SocketModules.chats.hasPrivateChat = function (socket, uid, callback) { if (!socket.uid || !uid) { - return callback(null, new Error('[[error:invalid-data]]')); + return callback(new Error('[[error:invalid-data]]')); } Messaging.hasPrivateChat(socket.uid, uid, callback); }; SocketModules.chats.getMessages = function (socket, data, callback) { - if (!socket.uid || !data.uid || !data.roomId) { + if (!socket.uid || !data || !data.uid || !data.roomId) { return callback(new Error('[[error:invalid-data]]')); } @@ -358,5 +369,3 @@ SocketModules.chats.getMessages = function (socket, data, callback) { SocketModules.sounds.getUserSoundMap = function getUserSoundMap(socket, data, callback) { meta.sounds.getUserSoundMap(socket.uid, callback); }; - -module.exports = SocketModules; diff --git a/test/messaging.js b/test/messaging.js index 436fd78a87..a009d5ad21 100644 --- a/test/messaging.js +++ b/test/messaging.js @@ -11,7 +11,7 @@ var User = require('../src/user'); var Groups = require('../src/groups'); var Messaging = require('../src/messaging'); var helpers = require('./helpers'); - +var socketModules = require('../src/socket.io/modules'); describe('Messaging Library', function () { var fooUid; @@ -55,7 +55,10 @@ describe('Messaging Library', function () { assert.ifError(err); Messaging.canMessageUser(herpUid, bazUid, function (err) { assert.strictEqual(err.message, '[[error:chat-restricted]]'); - done(); + socketModules.chats.addUserToRoom({ uid: herpUid }, { roomId: 1, username: 'baz' }, function (err) { + assert.equal(err.message, '[[error:chat-restricted]]'); + done(); + }); }); }); }); @@ -78,23 +81,93 @@ describe('Messaging Library', function () { }); describe('rooms', function () { - var socketModules = require('../src/socket.io/modules'); + it('should fail to create a new chat room with invalid data', function (done) { + socketModules.chats.newRoom({ uid: fooUid }, null, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + done(); + }); + }); + + it('should return rate limit error on second try', function (done) { + var socketMock = { uid: fooUid }; + socketModules.chats.newRoom(socketMock, { touid: bazUid }, function (err) { + assert.ifError(err); + socketModules.chats.newRoom(socketMock, { touid: bazUid }, function (err) { + assert.equal(err.message, '[[error:too-many-messages]]'); + done(); + }); + }); + }); + it('should create a new chat room', function (done) { socketModules.chats.newRoom({ uid: fooUid }, { touid: bazUid }, function (err, _roomId) { roomId = _roomId; assert.ifError(err); assert(roomId); - done(); + socketModules.chats.canMessage({ uid: fooUid }, _roomId, function (err) { + assert.ifError(err); + done(); + }); + }); + }); + + it('should fail to add user to room with invalid data', function (done) { + socketModules.chats.addUserToRoom({ uid: fooUid }, null, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + socketModules.chats.addUserToRoom({ uid: fooUid }, { roomId: null }, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + socketModules.chats.addUserToRoom({ uid: fooUid }, { roomId: roomId, username: null }, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + done(); + }); + }); }); }); it('should add a user to room', function (done) { socketModules.chats.addUserToRoom({ uid: fooUid }, { roomId: roomId, username: 'herp' }, function (err) { assert.ifError(err); + Messaging.isUserInRoom(herpUid, roomId, function (err, isInRoom) { + assert.ifError(err); + assert(isInRoom); + done(); + }); + }); + }); + + it('should fail to add users to room if max is reached', function (done) { + meta.config.maximumUsersInChatRoom = 2; + socketModules.chats.addUserToRoom({ uid: fooUid }, { roomId: roomId, username: 'test' }, function (err) { + assert.equal(err.message, '[[error:cant-add-more-users-to-chat-room]]'); + meta.config.maximumUsersInChatRoom = 0; + done(); + }); + }); + + it('should fail to add users to room if user does not exist', function (done) { + socketModules.chats.addUserToRoom({ uid: fooUid }, { roomId: roomId, username: 'doesnotexist' }, function (err) { + assert.equal(err.message, '[[error:no-user]]'); + done(); + }); + }); + + it('should fail to add self to room', function (done) { + socketModules.chats.addUserToRoom({ uid: fooUid }, { roomId: roomId, username: 'foo' }, function (err) { + assert.equal(err.message, '[[error:cant-add-self-to-chat-room]]'); done(); }); }); + it('should fail to leave room with invalid data', function (done) { + socketModules.chats.leave({ uid: null }, roomId, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + socketModules.chats.leave({ uid: fooUid }, null, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + done(); + }); + }); + }); + it('should leave the chat room', function (done) { socketModules.chats.leave({ uid: bazUid }, roomId, function (err) { assert.ifError(err); @@ -106,6 +179,60 @@ describe('Messaging Library', function () { }); }); + it('should fail to remove user from room', function (done) { + socketModules.chats.removeUserFromRoom({ uid: fooUid }, null, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + socketModules.chats.removeUserFromRoom({ uid: fooUid }, {}, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + done(); + }); + }); + }); + + it('should fail to remove user from room if user does not exist', function (done) { + socketModules.chats.removeUserFromRoom({ uid: fooUid }, { roomId: roomId, username: 'doesnotexist' }, function (err) { + assert.equal(err.message, '[[error:no-user]]'); + done(); + }); + }); + + it('should remove user from room', function (done) { + socketModules.chats.newRoom({ uid: fooUid }, { touid: herpUid }, function (err, roomId) { + assert.ifError(err); + Messaging.isUserInRoom(herpUid, roomId, function (err, isInRoom) { + assert.ifError(err); + assert(isInRoom); + socketModules.chats.removeUserFromRoom({ uid: fooUid }, { roomId: roomId, username: 'herp' }, function (err) { + assert.equal(err.message, '[[error:cant-remove-last-user]]'); + socketModules.chats.addUserToRoom({ uid: fooUid }, { roomId: roomId, username: 'baz' }, function (err) { + assert.ifError(err); + socketModules.chats.removeUserFromRoom({ uid: fooUid }, { roomId: roomId, username: 'herp' }, function (err) { + assert.ifError(err); + Messaging.isUserInRoom(herpUid, roomId, function (err, isInRoom) { + assert.ifError(err); + assert(!isInRoom); + done(); + }); + }); + }); + }); + }); + }); + }); + + it('should fail to send a message to room with invalid data', function (done) { + socketModules.chats.send({ uid: fooUid }, null, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + socketModules.chats.send({ uid: fooUid }, { roomId: null }, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + socketModules.chats.send({ uid: null }, { roomId: 1 }, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + done(); + }); + }); + }); + }); + it('should send a message to a room', function (done) { socketModules.chats.send({ uid: fooUid }, { roomId: roomId, message: 'first chat message' }, function (err, messageData) { assert.ifError(err); @@ -116,11 +243,39 @@ describe('Messaging Library', function () { socketModules.chats.getRaw({ uid: fooUid }, { roomId: roomId, mid: messageData.mid }, function (err, raw) { assert.ifError(err); assert.equal(raw, 'first chat message'); + setTimeout(done, 300); + }); + }); + }); + + it('should fail to send second message due to rate limit', function (done) { + var socketMock = { uid: fooUid }; + socketModules.chats.send(socketMock, { roomId: roomId, message: 'first chat message' }, function (err) { + assert.ifError(err); + socketModules.chats.send(socketMock, { roomId: roomId, message: 'first chat message' }, function (err) { + assert.equal(err.message, '[[error:too-many-messages]]'); + done(); + }); + }); + }); + + it('should return invalid-data error', function (done) { + socketModules.chats.getRaw({ uid: fooUid }, null, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + socketModules.chats.getRaw({ uid: fooUid }, { }, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); done(); }); }); }); + it('should return not in room error', function (done) { + socketModules.chats.getRaw({ uid: 0 }, { roomId: roomId, mid: 1 }, function (err) { + assert.equal(err.message, '[[error:not-allowed]]'); + done(); + }); + }); + it('should notify offline users of message', function (done) { Messaging.notificationSendDelay = 100; @@ -143,6 +298,22 @@ describe('Messaging Library', function () { }); }); + it('should fail to get messages from room with invalid data', function (done) { + socketModules.chats.getMessages({ uid: null }, null, function (err, messages) { + assert.equal(err.message, '[[error:invalid-data]]'); + socketModules.chats.getMessages({ uid: fooUid }, null, function (err, messages) { + assert.equal(err.message, '[[error:invalid-data]]'); + socketModules.chats.getMessages({ uid: fooUid }, { uid: null }, function (err, messages) { + assert.equal(err.message, '[[error:invalid-data]]'); + socketModules.chats.getMessages({ uid: fooUid }, { uid: 1, roomId: null }, function (err, messages) { + assert.equal(err.message, '[[error:invalid-data]]'); + done(); + }); + }); + }); + }); + }); + it('should get messages from room', function (done) { socketModules.chats.getMessages({ uid: fooUid }, { uid: fooUid, @@ -157,6 +328,23 @@ describe('Messaging Library', function () { }); }); + it('should fail to mark read with invalid data', function (done) { + socketModules.chats.markRead({ uid: null }, roomId, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + socketModules.chats.markRead({ uid: fooUid }, null, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + done(); + }); + }); + }); + + it('should not error if user is not in room', function (done) { + socketModules.chats.markRead({ uid: herpUid }, roomId, function (err) { + assert.ifError(err); + done(); + }); + }); + it('should mark room read', function (done) { socketModules.chats.markRead({ uid: fooUid }, roomId, function (err) { assert.ifError(err); @@ -171,10 +359,39 @@ describe('Messaging Library', function () { }); }); + it('should fail to rename room with invalid data', function (done) { + socketModules.chats.renameRoom({ uid: fooUid }, null, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + socketModules.chats.renameRoom({ uid: fooUid }, { roomId: null }, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + socketModules.chats.renameRoom({ uid: fooUid }, { roomId: roomId, newName: null }, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + done(); + }); + }); + }); + }); + it('should rename room', function (done) { socketModules.chats.renameRoom({ uid: fooUid }, { roomId: roomId, newName: 'new room name' }, function (err) { assert.ifError(err); + done(); + }); + }); + + it('should fail to load room with invalid-data', function (done) { + socketModules.chats.loadRoom({ uid: fooUid }, null, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + socketModules.chats.loadRoom({ uid: fooUid }, { roomId: null }, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + done(); + }); + }); + }); + it('should fail to load room if user is not in', function (done) { + socketModules.chats.loadRoom({ uid: 0 }, { roomId: roomId }, function (err) { + assert.equal(err.message, '[[error:not-allowed]]'); done(); }); }); @@ -198,6 +415,45 @@ describe('Messaging Library', function () { }); }); }); + + it('should fail to load recent chats with invalid data', function (done) { + socketModules.chats.getRecentChats({ uid: fooUid }, null, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + socketModules.chats.getRecentChats({ uid: fooUid }, { after: null }, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + socketModules.chats.getRecentChats({ uid: fooUid }, { after: 0, uid: null }, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + done(); + }); + }); + }); + }); + + it('should load recent chats of user', function (done) { + socketModules.chats.getRecentChats({ uid: fooUid }, { after: 0, uid: fooUid }, function (err, data) { + assert.ifError(err); + assert(Array.isArray(data.rooms)); + done(); + }); + }); + + it('should fail to check if user has private chat with invalid data', function (done) { + socketModules.chats.hasPrivateChat({ uid: null }, null, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + socketModules.chats.hasPrivateChat({ uid: fooUid }, null, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + done(); + }); + }); + }); + + it('should check if user has private chat with another uid', function (done) { + socketModules.chats.hasPrivateChat({ uid: fooUid }, herpUid, function (err, roomId) { + assert.ifError(err); + assert(roomId); + done(); + }); + }); }); describe('edit/delete', function () { @@ -211,6 +467,26 @@ describe('Messaging Library', function () { }); }); + it('should fail to edit message with invalid data', function (done) { + socketModules.chats.edit({ uid: fooUid }, null, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + socketModules.chats.edit({ uid: fooUid }, { roomId: null }, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + socketModules.chats.edit({ uid: fooUid }, { roomId: 1, message: null }, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + done(); + }); + }); + }); + }); + + it('should fail to edit message if not own message', function (done) { + socketModules.chats.edit({ uid: herpUid }, { mid: 5, roomId: roomId, message: 'message edited' }, function (err) { + assert.equal(err.message, '[[error:cant-edit-chat-message]]'); + done(); + }); + }); + it('should edit message', function (done) { socketModules.chats.edit({ uid: fooUid }, { mid: mid, roomId: roomId, message: 'message edited' }, function (err) { assert.ifError(err); @@ -222,6 +498,20 @@ describe('Messaging Library', function () { }); }); + it('should fail to delete message with invalid data', function (done) { + socketModules.chats.delete({ uid: fooUid }, null, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + socketModules.chats.delete({ uid: fooUid }, { roomId: null }, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + socketModules.chats.delete({ uid: fooUid }, { roomId: 1, messageId: null }, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + done(); + }); + }); + }); + }); + + it('should delete message', function (done) { socketModules.chats.delete({ uid: fooUid }, { messageId: mid, roomId: roomId }, function (err) { assert.ifError(err); diff --git a/test/meta.js b/test/meta.js index 8b32e90070..a92f6c74f6 100644 --- a/test/meta.js +++ b/test/meta.js @@ -262,6 +262,21 @@ describe('meta', function () { }); + describe('sounds', function () { + var socketModules = require('../src/socket.io/modules'); + + it('should getUserMap', function (done) { + socketModules.sounds.getUserSoundMap({ uid: 1 }, null, function (err, data) { + assert.ifError(err); + assert(data.hasOwnProperty('chat-incoming')); + assert(data.hasOwnProperty('chat-outgoing')); + assert(data.hasOwnProperty('notification')); + done(); + }); + }); + }); + + after(function (done) { db.emptydb(done); }); diff --git a/test/mocks/databasemock.js b/test/mocks/databasemock.js index 5b186e7f35..bd7831ac82 100644 --- a/test/mocks/databasemock.js +++ b/test/mocks/databasemock.js @@ -5,181 +5,178 @@ * ATTENTION: testing db is flushed before every use! */ -(function (module) { - var async = require('async'); - var winston = require('winston'); - var path = require('path'); - var nconf = require('nconf'); - var url = require('url'); - var errorText; - - - nconf.file({ file: path.join(__dirname, '../../config.json') }); - nconf.defaults({ - base_dir: path.join(__dirname, '../..'), - themes_path: path.join(__dirname, '../../node_modules'), - upload_path: 'public/uploads', - views_dir: path.join(__dirname, '../../build/public/templates'), - relative_path: '', - }); - - if (!nconf.get('isCluster')) { - nconf.set('isPrimary', 'true'); - nconf.set('isCluster', 'false'); - } - - var dbType = nconf.get('database'); - var testDbConfig = nconf.get('test_database'); - var productionDbConfig = nconf.get(dbType); - - if (!testDbConfig) { - errorText = 'test_database is not defined'; - winston.info( - '\n===========================================================\n' + - 'Please, add parameters for test database in config.json\n' + - 'For example (redis):\n' + - '"test_database": {\n' + - ' "host": "127.0.0.1",\n' + - ' "port": "6379",\n' + - ' "password": "",\n' + - ' "database": "1"\n' + - '}\n' + - ' or (mongo):\n' + - '"test_database": {\n' + - ' "host": "127.0.0.1",\n' + - ' "port": "27017",\n' + - ' "password": "",\n' + - ' "database": "1\n' + - '}\n' + - ' or (mongo) in a replicaset\n' + - '"test_database": {\n' + - ' "host": "127.0.0.1,127.0.0.1,127.0.0.1",\n' + - ' "port": "27017,27018,27019",\n' + - ' "username": "",\n' + - ' "password": "",\n' + - ' "database": "nodebb_test"\n' + - '}\n' + - '===========================================================' - ); - winston.error(errorText); - throw new Error(errorText); - } - - if (testDbConfig.database === productionDbConfig.database && - testDbConfig.host === productionDbConfig.host && - testDbConfig.port === productionDbConfig.port) { - errorText = 'test_database has the same config as production db'; - winston.error(errorText); - throw new Error(errorText); - } - - nconf.set(dbType, testDbConfig); - - winston.info('database config'); - winston.info(dbType); - winston.info(testDbConfig); - - var db = require('../../src/database'); - - after(function (done) { - db.close(done); - }); - - before(function (done) { - this.timeout(30000); - var meta; - async.waterfall([ - function (next) { - db.init(next); - }, - function (next) { - db.emptydb(next); - }, - function (next) { - db.createIndices(next); - }, - function (next) { - winston.info('test_database flushed'); - meta = require('../../src/meta'); - setupDefaultConfigs(meta, next); - }, - function (next) { - meta.configs.init(next); - }, - function (next) { - db.initSessionStore(next); - }, - function (next) { - meta.dependencies.check(next); - }, - function (next) { - meta.config.postDelay = 0; - meta.config.initialPostDelay = 0; - meta.config.newbiePostDelay = 0; - - enableDefaultPlugins(next); - }, - function (next) { - meta.themes.set({ - type: 'local', - id: 'nodebb-theme-persona', - }, next); - }, - function (next) { - // nconf defaults, if not set in config - if (!nconf.get('sessionKey')) { - nconf.set('sessionKey', 'express.sid'); - } - // Parse out the relative_url and other goodies from the configured URL - var urlObject = url.parse(nconf.get('url')); - var relativePath = urlObject.pathname !== '/' ? urlObject.pathname : ''; - nconf.set('base_url', urlObject.protocol + '//' + urlObject.host); - nconf.set('secure', urlObject.protocol === 'https:'); - nconf.set('use_port', !!urlObject.port); - nconf.set('relative_path', relativePath); - nconf.set('port', urlObject.port || nconf.get('port') || nconf.get('PORT') || (nconf.get('PORT_ENV_VAR') ? nconf.get(nconf.get('PORT_ENV_VAR')) : false) || 4567); - nconf.set('upload_path', path.join(nconf.get('base_dir'), nconf.get('upload_path'))); - - nconf.set('core_templates_path', path.join(__dirname, '../../src/views')); - nconf.set('base_templates_path', path.join(nconf.get('themes_path'), 'nodebb-theme-persona/templates')); - nconf.set('theme_templates_path', meta.config['theme:templates'] ? path.join(nconf.get('themes_path'), meta.config['theme:id'], meta.config['theme:templates']) : nconf.get('base_templates_path')); - nconf.set('theme_config', path.join(nconf.get('themes_path'), 'nodebb-theme-persona', 'theme.json')); - nconf.set('bcrypt_rounds', 1); - - next(); - }, - function (next) { - var webserver = require('../../src/webserver'); - var sockets = require('../../src/socket.io'); - sockets.init(webserver.server); - - require('../../src/notifications').startJobs(); - require('../../src/user').startJobs(); - - webserver.listen(next); - }, - ], done); - }); - - function setupDefaultConfigs(meta, next) { - winston.info('Populating database with default configs, if not already set...\n'); - - var defaults = require(path.join(nconf.get('base_dir'), 'install/data/defaults.json')); - - meta.configs.setOnEmpty(defaults, next); - } - - function enableDefaultPlugins(callback) { - winston.info('Enabling default plugins\n'); - - var defaultEnabled = [ - 'nodebb-plugin-dbsearch', - ]; - - winston.info('[install/enableDefaultPlugins] activating default plugins', defaultEnabled); - - db.sortedSetAdd('plugins:active', [0], defaultEnabled, callback); - } - - module.exports = db; -}(module)); +var async = require('async'); +var winston = require('winston'); +var path = require('path'); +var nconf = require('nconf'); +var url = require('url'); +var errorText; + + +nconf.file({ file: path.join(__dirname, '../../config.json') }); +nconf.defaults({ + base_dir: path.join(__dirname, '../..'), + themes_path: path.join(__dirname, '../../node_modules'), + upload_path: 'public/uploads', + views_dir: path.join(__dirname, '../../build/public/templates'), + relative_path: '', +}); + +if (!nconf.get('isCluster')) { + nconf.set('isPrimary', 'true'); + nconf.set('isCluster', 'false'); +} + +var dbType = nconf.get('database'); +var testDbConfig = nconf.get('test_database'); +var productionDbConfig = nconf.get(dbType); + +if (!testDbConfig) { + errorText = 'test_database is not defined'; + winston.info( + '\n===========================================================\n' + + 'Please, add parameters for test database in config.json\n' + + 'For example (redis):\n' + + '"test_database": {\n' + + ' "host": "127.0.0.1",\n' + + ' "port": "6379",\n' + + ' "password": "",\n' + + ' "database": "1"\n' + + '}\n' + + ' or (mongo):\n' + + '"test_database": {\n' + + ' "host": "127.0.0.1",\n' + + ' "port": "27017",\n' + + ' "password": "",\n' + + ' "database": "1\n' + + '}\n' + + ' or (mongo) in a replicaset\n' + + '"test_database": {\n' + + ' "host": "127.0.0.1,127.0.0.1,127.0.0.1",\n' + + ' "port": "27017,27018,27019",\n' + + ' "username": "",\n' + + ' "password": "",\n' + + ' "database": "nodebb_test"\n' + + '}\n' + + '===========================================================' + ); + winston.error(errorText); + throw new Error(errorText); +} + +if (testDbConfig.database === productionDbConfig.database && + testDbConfig.host === productionDbConfig.host && + testDbConfig.port === productionDbConfig.port) { + errorText = 'test_database has the same config as production db'; + winston.error(errorText); + throw new Error(errorText); +} + +nconf.set(dbType, testDbConfig); + +winston.info('database config'); +winston.info(dbType); +winston.info(testDbConfig); + +var db = require('../../src/database'); +module.exports = db; + +after(function (done) { + db.close(done); +}); + +before(function (done) { + this.timeout(30000); + var meta; + async.waterfall([ + function (next) { + db.init(next); + }, + function (next) { + db.emptydb(next); + }, + function (next) { + db.createIndices(next); + }, + function (next) { + winston.info('test_database flushed'); + meta = require('../../src/meta'); + setupDefaultConfigs(meta, next); + }, + function (next) { + meta.configs.init(next); + }, + function (next) { + db.initSessionStore(next); + }, + function (next) { + meta.dependencies.check(next); + }, + function (next) { + meta.config.postDelay = 0; + meta.config.initialPostDelay = 0; + meta.config.newbiePostDelay = 0; + + enableDefaultPlugins(next); + }, + function (next) { + meta.themes.set({ + type: 'local', + id: 'nodebb-theme-persona', + }, next); + }, + function (next) { + // nconf defaults, if not set in config + if (!nconf.get('sessionKey')) { + nconf.set('sessionKey', 'express.sid'); + } + // Parse out the relative_url and other goodies from the configured URL + var urlObject = url.parse(nconf.get('url')); + var relativePath = urlObject.pathname !== '/' ? urlObject.pathname : ''; + nconf.set('base_url', urlObject.protocol + '//' + urlObject.host); + nconf.set('secure', urlObject.protocol === 'https:'); + nconf.set('use_port', !!urlObject.port); + nconf.set('relative_path', relativePath); + nconf.set('port', urlObject.port || nconf.get('port') || nconf.get('PORT') || (nconf.get('PORT_ENV_VAR') ? nconf.get(nconf.get('PORT_ENV_VAR')) : false) || 4567); + nconf.set('upload_path', path.join(nconf.get('base_dir'), nconf.get('upload_path'))); + + nconf.set('core_templates_path', path.join(__dirname, '../../src/views')); + nconf.set('base_templates_path', path.join(nconf.get('themes_path'), 'nodebb-theme-persona/templates')); + nconf.set('theme_templates_path', meta.config['theme:templates'] ? path.join(nconf.get('themes_path'), meta.config['theme:id'], meta.config['theme:templates']) : nconf.get('base_templates_path')); + nconf.set('theme_config', path.join(nconf.get('themes_path'), 'nodebb-theme-persona', 'theme.json')); + nconf.set('bcrypt_rounds', 1); + + next(); + }, + function (next) { + var webserver = require('../../src/webserver'); + var sockets = require('../../src/socket.io'); + sockets.init(webserver.server); + + require('../../src/notifications').startJobs(); + require('../../src/user').startJobs(); + + webserver.listen(next); + }, + ], done); +}); + +function setupDefaultConfigs(meta, next) { + winston.info('Populating database with default configs, if not already set...\n'); + + var defaults = require(path.join(nconf.get('base_dir'), 'install/data/defaults.json')); + + meta.configs.setOnEmpty(defaults, next); +} + +function enableDefaultPlugins(callback) { + winston.info('Enabling default plugins\n'); + + var defaultEnabled = [ + 'nodebb-plugin-dbsearch', + ]; + + winston.info('[install/enableDefaultPlugins] activating default plugins', defaultEnabled); + + db.sortedSetAdd('plugins:active', [0], defaultEnabled, callback); +}