mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-29 16:23:39 -05:00
Merge pull request #3 from sharelatex/ja-track-changes
Clean up dead code and add acceptance tests
This commit is contained in:
commit
ce506f0675
22 changed files with 190 additions and 974 deletions
1
services/chat/.gitignore
vendored
1
services/chat/.gitignore
vendored
|
@ -3,6 +3,7 @@
|
|||
app.js
|
||||
app/js/
|
||||
test/unit/js/
|
||||
test/acceptance/js/
|
||||
public/build/
|
||||
|
||||
node_modules/
|
||||
|
|
|
@ -2,6 +2,11 @@ module.exports = (grunt) ->
|
|||
|
||||
# Project configuration.
|
||||
grunt.initConfig
|
||||
forever:
|
||||
app:
|
||||
options:
|
||||
index: "app.js"
|
||||
|
||||
execute:
|
||||
app:
|
||||
src: "app.js"
|
||||
|
@ -30,7 +35,7 @@ module.exports = (grunt) ->
|
|||
dest: './',
|
||||
ext: '.js'
|
||||
|
||||
server_tests:
|
||||
unit_tests:
|
||||
expand: true,
|
||||
flatten: false,
|
||||
cwd: 'test/unit/coffee',
|
||||
|
@ -38,10 +43,18 @@ module.exports = (grunt) ->
|
|||
dest: 'test/unit/js/',
|
||||
ext: '.js'
|
||||
|
||||
acceptance_tests:
|
||||
expand: true,
|
||||
flatten: false,
|
||||
cwd: 'test/acceptance/coffee',
|
||||
src: ['**/*.coffee'],
|
||||
dest: 'test/acceptance/js/',
|
||||
ext: '.js'
|
||||
|
||||
watch:
|
||||
server_coffee:
|
||||
files: ['app/**/*.coffee', 'test/unit/**/*.coffee']
|
||||
tasks: ['compile:server', 'compile:server_tests', 'mochaTest']
|
||||
tasks: ['compile:server', 'compile:unit_tests', 'mochaTest']
|
||||
|
||||
client_coffee:
|
||||
files: ['public/**/*.coffee']
|
||||
|
@ -101,7 +114,12 @@ module.exports = (grunt) ->
|
|||
options:
|
||||
reporter: process.env.MOCHA_RUNNER || "spec"
|
||||
grep: grunt.option("grep")
|
||||
src: ['test/**/*.js']
|
||||
src: ['test/unit/**/*.js']
|
||||
acceptance:
|
||||
options:
|
||||
reporter: process.env.MOCHA_RUNNER || "spec"
|
||||
grep: grunt.option("grep")
|
||||
src: ['test/acceptance/**/*.js']
|
||||
|
||||
plato:
|
||||
your_task:
|
||||
|
@ -121,6 +139,7 @@ module.exports = (grunt) ->
|
|||
grunt.loadNpmTasks 'grunt-plato'
|
||||
grunt.loadNpmTasks 'grunt-execute'
|
||||
grunt.loadNpmTasks 'grunt-bunyan'
|
||||
grunt.loadNpmTasks 'grunt-forever'
|
||||
|
||||
|
||||
grunt.registerTask 'compile', ['clean', 'copy', 'coffee', 'less', 'jade', 'requirejs']
|
||||
|
@ -128,4 +147,5 @@ module.exports = (grunt) ->
|
|||
grunt.registerTask 'default', ['compile', 'bunyan', 'execute']
|
||||
grunt.registerTask 'compileAndCompress', ['compile', 'uglify']
|
||||
grunt.registerTask 'test:unit', ['compile', 'mochaTest:unit']
|
||||
grunt.registerTask 'test:acceptance', ['compile:acceptance_tests', 'mochaTest:acceptance']
|
||||
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
async = require "async"
|
||||
logger = require "logger-sharelatex"
|
||||
WebApiManager = require("../WebApi/WebApiManager")
|
||||
UserFormatter = require("../Users/UserFormatter")
|
||||
|
||||
module.exports = AuthenticationController =
|
||||
authClient: (client, data, callback = (error) ->) ->
|
||||
logger.log auth_token: data.auth_token, "authenticating user"
|
||||
WebApiManager.getUserDetailsFromAuthToken data.auth_token, (error, user) =>
|
||||
if error?
|
||||
logger.error data: data, client_id: client.id, err: error, "error authenticating user"
|
||||
return callback("something went wrong")
|
||||
logger.log user: user, auth_token: data.auth_token, "authenticated user"
|
||||
user = UserFormatter.formatUserForClientSide user
|
||||
jobs = []
|
||||
for key, value of user
|
||||
do (key, value) ->
|
||||
jobs.push (callback) -> client.set key, value, callback
|
||||
jobs.push (callback) -> client.set "auth_token", data.auth_token, callback
|
||||
async.series jobs, (error, results) =>
|
||||
callback(error, user)
|
||||
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
WebApiManager = require "../WebApi/WebApiManager"
|
||||
SocketManager = require "../Sockets/SocketManager"
|
||||
|
||||
module.exports = AuthorizationManager =
|
||||
canClientJoinProjectRoom: (client, project_id, callback = (error, authorized) ->) ->
|
||||
client.get "auth_token", (error, auth_token) ->
|
||||
return callback(error) if error?
|
||||
WebApiManager.getProjectCollaborators project_id, auth_token, (error, collaborators) ->
|
||||
return callback(error) if error?
|
||||
client.get "id", (error, user_id) ->
|
||||
return callback(error) if error?
|
||||
authorized = false
|
||||
for collaborator in collaborators
|
||||
if collaborator.id == user_id
|
||||
authorized = true
|
||||
break
|
||||
callback null, authorized
|
||||
|
||||
canClientSendMessageToRoom: (client, room_id, callback = (error, authorized) ->) ->
|
||||
SocketManager.isClientInRoom(client, room_id, callback)
|
||||
|
||||
canClientReadMessagesInRoom: (client, room_id, callback = (error, authorized) ->) ->
|
||||
SocketManager.isClientInRoom(client, room_id, callback)
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
logger = require "logger-sharelatex"
|
||||
metrics = require "metrics-sharelatex"
|
||||
MessageManager = require "./MessageManager"
|
||||
MessageFormatter = require "./MessageFormatter"
|
||||
SocketManager = require "../Sockets/SocketManager"
|
||||
AuthorizationManager = require "../Authorization/AuthorizationManager"
|
||||
|
||||
|
||||
module.exports = MessageController =
|
||||
DEFAULT_MESSAGE_LIMIT: 50
|
||||
|
||||
sendMessage: (client, data, callback = (error) ->) ->
|
||||
content = data?.message?.content
|
||||
room_id = data?.room?.id
|
||||
return callback("malformed message") if not (content? and room_id?)
|
||||
|
||||
client.get "id", (error, user_id) ->
|
||||
logger.log user_id: user_id, room_id: room_id, "sending message"
|
||||
AuthorizationManager.canClientSendMessageToRoom client, room_id, (error, authorized) ->
|
||||
if error?
|
||||
logger.err err:error, user_id:user_id, "something went wrong checking if canClientSendMessageToRoom"
|
||||
return callback("something went wrong")
|
||||
if authorized
|
||||
SocketManager.getClientAttributes client, ["id"], (error, values) ->
|
||||
if error?
|
||||
logger.err err:error, user_id:user_id, "something went wrong getClientAttributes"
|
||||
return callback("something went wrong")
|
||||
newMessageOpts =
|
||||
content: content
|
||||
room_id: room_id
|
||||
user_id: values[0]
|
||||
timestamp: Date.now()
|
||||
MessageManager.createMessage newMessageOpts, (error, message) ->
|
||||
if error?
|
||||
logger.err err:error, user_id:user_id, "something went wrong createMessage"
|
||||
return callback("something went wrong")
|
||||
MessageManager.populateMessagesWithUsers [message], (error, messages) ->
|
||||
if error?
|
||||
logger.err err:error, user_id:user_id, "something went wrong populateMessagesWithUsers"
|
||||
return callback("something went wrong")
|
||||
message = MessageFormatter.formatMessageForClientSide(messages[0])
|
||||
message.room =
|
||||
id: room_id
|
||||
SocketManager.emitToRoom data.room.id, "messageReceived", message:message
|
||||
metrics.inc "editor.instant-message"
|
||||
logger.log user_id: user_id, room_id: room_id, "sent message"
|
||||
callback()
|
||||
else
|
||||
logger.log user_id: user_id, room_id: room_id, "unauthorized attempt to send message"
|
||||
callback("unknown room")
|
||||
|
||||
getMessages: (client, data, callback = (error, messages) ->) ->
|
||||
room_id = data?.room?.id
|
||||
return callback("malformed message") if not room_id?
|
||||
|
||||
client.get "id", (error, user_id) ->
|
||||
logger.log user_id: user_id, room_id: room_id, "getting messages"
|
||||
AuthorizationManager.canClientReadMessagesInRoom client, room_id, (error, authorized) ->
|
||||
if error?
|
||||
logger.err err:error, user_id:user_id, "something went canClientReadMessagesInRoom"
|
||||
return callback("something went wrong")
|
||||
if authorized
|
||||
query = room_id: room_id
|
||||
if data.before?
|
||||
query.timestamp = $lt: data.before
|
||||
options =
|
||||
order_by: "timestamp"
|
||||
sort_order: -1
|
||||
limit: data.limit || MessageController.DEFAULT_MESSAGE_LIMIT
|
||||
MessageManager.getMessages query, options, (error, messages) ->
|
||||
if error?
|
||||
logger.err err:error, user_id:user_id, "something went getMessages"
|
||||
return callback("something went wrong")
|
||||
MessageManager.populateMessagesWithUsers messages, (error, messages) ->
|
||||
if error?
|
||||
logger.err err:error, user_id:user_id, "something went populateMessagesWithUsers"
|
||||
return callback("something went wrong")
|
||||
messages = MessageFormatter.formatMessagesForClientSide messages
|
||||
logger.log user_id: user_id, room_id: room_id, "got messages"
|
||||
callback null, messages
|
||||
else
|
||||
logger.log user_id: user_id, room_id: room_id, "unauthorized attempt to get messages"
|
||||
callback("unknown room")
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
async = require "async"
|
||||
logger = require "logger-sharelatex"
|
||||
AuthorizationManager = require "../Authorization/AuthorizationManager"
|
||||
RoomManager = require "../Rooms/RoomManager"
|
||||
SocketManager = require "../Sockets/SocketManager"
|
||||
|
||||
module.exports = RoomController =
|
||||
joinRoom: (client, data, callback = (error) ->) ->
|
||||
if !data.room?.project_id?
|
||||
return callback("unknown room")
|
||||
project_id = data.room.project_id
|
||||
|
||||
client.get "id", (error, id) ->
|
||||
logger.log user_id: id, project_id: project_id, "joining room"
|
||||
AuthorizationManager.canClientJoinProjectRoom client, project_id, (error, authorized) ->
|
||||
return callback("something went wrong") if error?
|
||||
if authorized
|
||||
RoomManager.findOrCreateRoom project_id: project_id, (error, room) ->
|
||||
return callback("something went wrong") if error?
|
||||
room_id = room._id.toString()
|
||||
RoomController._addClientToRoom client, room_id, (error) ->
|
||||
return callback("something went wrong") if error?
|
||||
RoomController._getClientsInRoom room_id, (error, clients) ->
|
||||
return callback("something went wrong") if error?
|
||||
logger.log user_id: id, project_id: project_id, room_id: room_id, "joined room"
|
||||
roomDetails =
|
||||
room:
|
||||
id: room_id
|
||||
connectedUsers: clients
|
||||
callback null, roomDetails
|
||||
else
|
||||
logger.log user_id: id, project_id: project_id, "unauthorized attempt to join room"
|
||||
callback("unknown room")
|
||||
|
||||
leaveAllRooms: (client, callback = (error) ->) ->
|
||||
client.get "id", (error, id) ->
|
||||
logger.log user_id: id, "leaving all rooms"
|
||||
SocketManager.getRoomIdsClientHasJoined client, (error, room_ids) ->
|
||||
return callback("something went wrong") if error?
|
||||
jobs = []
|
||||
for room_id in room_ids
|
||||
do (room_id) ->
|
||||
jobs.push (callback) ->
|
||||
RoomController.leaveRoom client, room_id, callback
|
||||
async.series jobs, (error)-> callback(error)
|
||||
|
||||
leaveRoom: (client, room_id, callback = (error) ->) ->
|
||||
client.get "id", (error, id) ->
|
||||
logger.log user_id: id, room_id: room_id, "leaving room"
|
||||
RoomController._getClientAttributes client, (error, attributes) ->
|
||||
return callback("something went wrong") if error?
|
||||
SocketManager.removeClientFromRoom client, room_id, (error) ->
|
||||
return callback("something went wrong") if error?
|
||||
leftRoomUpdate =
|
||||
room:
|
||||
id: room_id
|
||||
user: attributes
|
||||
SocketManager.emitToRoom room_id, "userLeft", leftRoomUpdate
|
||||
logger.log user_id: id, room_id: room_id, "left room"
|
||||
callback()
|
||||
|
||||
_addClientToRoom: (client, room_id, callback = (error) ->) ->
|
||||
RoomController._getClientAttributes client, (error, attributes) ->
|
||||
return callback(error) if error?
|
||||
update =
|
||||
room:
|
||||
id: room_id
|
||||
user: attributes
|
||||
SocketManager.emitToRoom room_id, "userJoined", update
|
||||
SocketManager.addClientToRoom client, room_id, callback
|
||||
|
||||
_getClientsInRoom: (room_id, callback = (error, clients) ->) ->
|
||||
SocketManager.getClientsInRoom room_id, (error, clients) ->
|
||||
return callback(error) if error?
|
||||
formattedClients = []
|
||||
jobs = []
|
||||
|
||||
for client in clients
|
||||
do (client) ->
|
||||
jobs.push (callback) ->
|
||||
RoomController._getClientAttributes client, (error, attributes) ->
|
||||
return callback(error) if error?
|
||||
formattedClients.push attributes
|
||||
callback()
|
||||
|
||||
async.series jobs, (error) ->
|
||||
return callback(error) if error?
|
||||
callback null, formattedClients
|
||||
|
||||
_getClientAttributes: (client, callback = (error, attributes) ->) ->
|
||||
SocketManager.getClientAttributes client, ["id", "first_name", "last_name", "email", "gravatar_url"], (error, attributes) ->
|
||||
return callback(error) if error?
|
||||
[id, first_name, last_name, email, gravatar_url] = attributes
|
||||
clientAttributes =
|
||||
id : id
|
||||
first_name : first_name
|
||||
last_name : last_name
|
||||
email : email
|
||||
gravatar_url : gravatar_url
|
||||
callback null, clientAttributes
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
settings = require 'settings-sharelatex'
|
||||
rclientPub = require("redis").createClient(settings.redis.web.port, settings.redis.web.host)
|
||||
rclientPub.auth(settings.redis.web.password)
|
||||
rclientSub = require("redis").createClient(settings.redis.web.port, settings.redis.web.host)
|
||||
rclientSub.auth(settings.redis.web.password)
|
||||
|
||||
module.exports = RealTimeEventManager =
|
||||
|
||||
rclientPub:rclientPub
|
||||
rclientSub:rclientSub
|
||||
|
||||
emitToRoom: (room_id, message, payload...) ->
|
||||
RealTimeEventManager.rclientPub.publish "chat-events", JSON.stringify
|
||||
room_id: room_id
|
||||
message: message
|
||||
payload: payload
|
||||
|
||||
listenForChatEvents: () ->
|
||||
@rclientSub.subscribe "chat-events"
|
||||
@rclientSub.on "message", @_processEditorEvent.bind(@)
|
||||
|
||||
_processEditorEvent: (channel, message) ->
|
||||
io = require('../../server').io
|
||||
message = JSON.parse(message)
|
||||
io.sockets.in(message.room_id).emit(message.message, message.payload...)
|
|
@ -1,40 +0,0 @@
|
|||
async = require "async"
|
||||
RealTimeEventManager = require("./RealTimeEventManager")
|
||||
|
||||
module.exports = SocketManager =
|
||||
addClientToRoom: (client, room_id, callback = (error) ->) ->
|
||||
client.join(room_id)
|
||||
callback()
|
||||
|
||||
removeClientFromRoom: (client, room_id, callback = (error) ->) ->
|
||||
client.leave(room_id)
|
||||
callback()
|
||||
|
||||
getClientAttributes: (client, attributes, callback = (error, values) ->) ->
|
||||
jobs = []
|
||||
for attribute in attributes
|
||||
do (attribute) ->
|
||||
jobs.push (cb) -> client.get attribute, cb
|
||||
async.series jobs, callback
|
||||
|
||||
emitToRoom: RealTimeEventManager.emitToRoom
|
||||
|
||||
isClientInRoom: (targetClient, room_id, callback = (error, inRoom) ->) ->
|
||||
io = require("../../server").io
|
||||
for client in io.sockets.clients(room_id)
|
||||
if client.id == targetClient.id
|
||||
return callback null, true
|
||||
callback null, false
|
||||
|
||||
getClientsInRoom: (room_id, callback = (error, clients) ->) ->
|
||||
io = require("../../server").io
|
||||
callback null, io.sockets.clients(room_id)
|
||||
|
||||
getRoomIdsClientHasJoined: (client, callback = (error, room_ids) ->) ->
|
||||
io = require("../../server").io
|
||||
room_ids = []
|
||||
for room_id, value of io.sockets.manager.roomClients[client.id]
|
||||
if room_id[0] == "/"
|
||||
room_ids.push room_id.slice(1)
|
||||
callback null, room_ids
|
||||
|
|
@ -2,6 +2,7 @@ crypto = require "crypto"
|
|||
|
||||
module.exports = UserFormatter =
|
||||
formatUserForClientSide: (user) ->
|
||||
return null if !user?
|
||||
if user._id?
|
||||
user.id = user._id.toString()
|
||||
delete user._id
|
||||
|
|
|
@ -16,14 +16,16 @@ module.exports = WebApiManager =
|
|||
options.method = method
|
||||
request options, (error, response, body) ->
|
||||
return callback(error) if error?
|
||||
try
|
||||
result = JSON.parse(body)
|
||||
catch e
|
||||
return callback(e)
|
||||
return callback null, result
|
||||
|
||||
getUserDetailsFromAuthToken: (auth_token, callback = (error, details) ->) ->
|
||||
@apiRequest "/user/personal_info?auth_token=#{auth_token}", "get", callback
|
||||
if 200 <= response.statusCode < 300
|
||||
try
|
||||
result = JSON.parse(body)
|
||||
catch e
|
||||
return callback(e)
|
||||
return callback null, result
|
||||
else
|
||||
error = new Error("web api returned non-success code: #{response.statusCode}")
|
||||
error.statusCode = response.statusCode
|
||||
return callback error
|
||||
|
||||
getUserDetails: (user_id, callback = (error, details) ->) ->
|
||||
@apiRequest "/user/#{user_id}/personal_info", "get", {
|
||||
|
@ -31,7 +33,11 @@ module.exports = WebApiManager =
|
|||
user: Settings.apis.web.user
|
||||
pass: Settings.apis.web.pass
|
||||
sendImmediately: true
|
||||
}, callback
|
||||
|
||||
getProjectCollaborators: (project_id, auth_token, callback = (error, collaborators) ->) ->
|
||||
@apiRequest "/project/#{project_id}/collaborators?auth_token=#{auth_token}", "get", callback
|
||||
}, (error, data) ->
|
||||
if error?
|
||||
if error.statusCode == 404
|
||||
return callback null, null
|
||||
else
|
||||
return callback error
|
||||
else
|
||||
return callback null, data
|
||||
|
|
|
@ -1,31 +1,12 @@
|
|||
AuthenticationController = require("./Features/Authentication/AuthenticationController")
|
||||
MessageController = require("./Features/Messages/MessageController")
|
||||
RoomController = require("./Features/Rooms/RoomController")
|
||||
MessageHttpController = require('./Features/Messages/MessageHttpController')
|
||||
|
||||
module.exports = Router =
|
||||
route: (app, io) ->
|
||||
|
||||
route: (app) ->
|
||||
app.get "/room/:project_id/messages", MessageHttpController.getMessages
|
||||
app.post "/room/:project_id/messages", MessageHttpController.sendMessage
|
||||
|
||||
app.get "/status", (req, res, next) ->
|
||||
res.send("chat is alive")
|
||||
|
||||
io.sockets.on "connection", (client) ->
|
||||
client.on "disconnect", () ->
|
||||
RoomController.leaveAllRooms(client)
|
||||
|
||||
client.on "auth", (data, callback = (error) ->) ->
|
||||
AuthenticationController.authClient(client, data, callback)
|
||||
|
||||
client.on "joinRoom", (data, callback = (error) ->) ->
|
||||
RoomController.joinRoom(client, data, callback)
|
||||
|
||||
client.on "sendMessage", (data, callback = (error) ->) ->
|
||||
MessageController.sendMessage(client, data, callback)
|
||||
|
||||
client.on "getMessages", (data, callback = (error) ->) ->
|
||||
MessageController.getMessages(client, data, callback)
|
||||
|
||||
|
||||
|
|
|
@ -6,16 +6,13 @@ Path = require("path")
|
|||
express = require("express")
|
||||
app = express()
|
||||
server = require("http").createServer(app)
|
||||
io = require("socket.io").listen(server)
|
||||
io.set("resource", "/chat/socket.io")
|
||||
io.set("log level", 1)
|
||||
Router = require "./router"
|
||||
|
||||
metrics.mongodb.monitor(Path.resolve(__dirname + "/../../node_modules/mongojs/node_modules/mongodb"), logger)
|
||||
|
||||
app.use express.bodyParser()
|
||||
app.use metrics.http.monitor(logger)
|
||||
Router.route(app, io)
|
||||
Router.route(app)
|
||||
|
||||
if (app.get 'env') == 'development'
|
||||
console.log "Development Enviroment"
|
||||
|
@ -39,13 +36,9 @@ app.use (req, res, next) ->
|
|||
|
||||
app.use(express.static(__dirname + "/../../public/build"))
|
||||
|
||||
|
||||
|
||||
module.exports = {
|
||||
server: server
|
||||
io: io
|
||||
app: app
|
||||
}
|
||||
|
||||
require("./Features/Sockets/RealTimeEventManager").listenForChatEvents()
|
||||
|
||||
|
|
|
@ -8,15 +8,14 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"async": "0.2.9",
|
||||
"coffee-script": "~1.7.1",
|
||||
"express": "3.3.1",
|
||||
"request": "2.21.0",
|
||||
"socket.io": "0.9.14",
|
||||
"settings-sharelatex": "git+https://github.com/sharelatex/settings-sharelatex.git#v1.0.0",
|
||||
"logger-sharelatex": "git+https://github.com/sharelatex/logger-sharelatex.git#master",
|
||||
"metrics-sharelatex": "git+https://github.com/sharelatex/metrics-sharelatex.git#v1.0.0",
|
||||
"mongojs": "0.18.2",
|
||||
"redis": "~0.10.1",
|
||||
"coffee-script": "~1.7.1"
|
||||
"request": "^2.79.0",
|
||||
"settings-sharelatex": "git+https://github.com/sharelatex/settings-sharelatex.git#v1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bunyan": "^1.0.0",
|
||||
|
@ -32,12 +31,13 @@
|
|||
"grunt-contrib-requirejs": "~0.4.1",
|
||||
"grunt-contrib-uglify": "~0.2.7",
|
||||
"grunt-contrib-watch": "~0.5.3",
|
||||
"grunt-requirejs": "~0.4.0",
|
||||
"grunt-mocha-test": "~0.8.0",
|
||||
"grunt-execute": "^0.2.2",
|
||||
"grunt-forever": "^0.4.7",
|
||||
"grunt-mocha-test": "~0.8.0",
|
||||
"grunt-nodemon": "~0.1.2",
|
||||
"grunt-notify": "~0.2.16",
|
||||
"grunt-plato": "~0.2.1",
|
||||
"grunt-requirejs": "~0.4.0",
|
||||
"sandboxed-module": "",
|
||||
"sinon": "",
|
||||
"timekeeper": ""
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
{ObjectId} = require "../../../app/js/mongojs"
|
||||
expect = require("chai").expect
|
||||
async = require "async"
|
||||
crypto = require "crypto"
|
||||
|
||||
MockWebApi = require "./helpers/MockWebApi"
|
||||
ChatClient = require "./helpers/ChatClient"
|
||||
|
||||
describe "Getting messages", ->
|
||||
before ->
|
||||
@user_id1 = ObjectId().toString()
|
||||
@user_id2 = ObjectId().toString()
|
||||
@content1 = "foo bar"
|
||||
@content2 = "hello world"
|
||||
MockWebApi.addUser @user_id1, @user1 = {
|
||||
id: @user_id1
|
||||
first_name: "Jane"
|
||||
last_name: "Smith"
|
||||
email: "jane@example.com"
|
||||
}
|
||||
MockWebApi.addUser @user_id2, @user2 = {
|
||||
id: @user_id2
|
||||
first_name: "John"
|
||||
last_name: "Doe"
|
||||
email: "john@example.com"
|
||||
}
|
||||
|
||||
describe "normally", ->
|
||||
before (done) ->
|
||||
@project_id = ObjectId().toString()
|
||||
async.series [
|
||||
(cb) => ChatClient.sendMessage @project_id, @user_id1, @content1, cb
|
||||
(cb) => ChatClient.sendMessage @project_id, @user_id2, @content2, cb
|
||||
], done
|
||||
|
||||
it "should contain the messages and populated users when getting the messages", (done) ->
|
||||
ChatClient.getMessages @project_id, (error, response, messages) =>
|
||||
expect(messages.length).to.equal 2
|
||||
messages.reverse()
|
||||
expect(messages[0].content).to.equal @content1
|
||||
expect(messages[0].user).to.deep.equal {
|
||||
id: @user_id1
|
||||
first_name: "Jane"
|
||||
last_name: "Smith"
|
||||
email: "jane@example.com"
|
||||
gravatar_url: "//www.gravatar.com/avatar/#{crypto.createHash("md5").update("jane@example.com").digest("hex")}"
|
||||
}
|
||||
expect(messages[1].content).to.equal @content2
|
||||
expect(messages[1].user).to.deep.equal {
|
||||
id: @user_id2
|
||||
first_name: "John"
|
||||
last_name: "Doe"
|
||||
email: "john@example.com"
|
||||
gravatar_url: "//www.gravatar.com/avatar/#{crypto.createHash("md5").update("john@example.com").digest("hex")}"
|
||||
}
|
||||
done()
|
||||
|
||||
describe "when a user doesn't exit", ->
|
||||
before (done) ->
|
||||
@project_id = ObjectId().toString()
|
||||
@user_id3 = ObjectId().toString()
|
||||
async.series [
|
||||
(cb) => ChatClient.sendMessage @project_id, @user_id3, @content1, cb
|
||||
(cb) => ChatClient.sendMessage @project_id, @user_id2, @content2, cb
|
||||
], done
|
||||
|
||||
it "should just return null for the user", (done) ->
|
||||
ChatClient.getMessages @project_id, (error, response, messages) =>
|
||||
expect(messages.length).to.equal 2
|
||||
messages.reverse()
|
||||
expect(messages[0].content).to.equal @content1
|
||||
expect(messages[0].user).to.equal null
|
||||
done()
|
|
@ -0,0 +1,23 @@
|
|||
{ObjectId} = require "../../../app/js/mongojs"
|
||||
expect = require("chai").expect
|
||||
|
||||
MockWebApi = require "./helpers/MockWebApi"
|
||||
ChatClient = require "./helpers/ChatClient"
|
||||
|
||||
describe "Sending a message", ->
|
||||
before (done) ->
|
||||
@project_id = ObjectId().toString()
|
||||
@user_id = ObjectId().toString()
|
||||
@content = "foo bar"
|
||||
ChatClient.sendMessage @project_id, @user_id, @content, (error, response, body) ->
|
||||
expect(error).to.be.null
|
||||
expect(response.statusCode).to.equal 201
|
||||
done()
|
||||
|
||||
it "should then list the message in project messages", (done) ->
|
||||
ChatClient.getMessages @project_id, (error, response, messages) =>
|
||||
expect(error).to.be.null
|
||||
expect(response.statusCode).to.equal 200
|
||||
expect(messages.length).to.equal 1
|
||||
expect(messages[0].content).to.equal @content
|
||||
done()
|
|
@ -0,0 +1,16 @@
|
|||
request = require("request").defaults({baseUrl: "http://localhost:3010"})
|
||||
|
||||
module.exports =
|
||||
sendMessage: (project_id, user_id, content, callback) ->
|
||||
request.post {
|
||||
url: "/room/#{project_id}/messages"
|
||||
json:
|
||||
user_id: user_id
|
||||
content: content
|
||||
}, callback
|
||||
|
||||
getMessages: (project_id, callback) ->
|
||||
request.get {
|
||||
url: "/room/#{project_id}/messages",
|
||||
json: true
|
||||
}, callback
|
|
@ -0,0 +1,27 @@
|
|||
express = require("express")
|
||||
app = express()
|
||||
|
||||
module.exports = MockWebApi =
|
||||
users: {}
|
||||
|
||||
addUser: (user_id, user) ->
|
||||
@users[user_id] = user
|
||||
|
||||
getUser: (user_id, callback = (error, user) ->) ->
|
||||
return callback null, @users[user_id]
|
||||
|
||||
run: () ->
|
||||
app.get "/user/:user_id/personal_info", (req, res, next) =>
|
||||
@getUser req.params.user_id, (error, user) ->
|
||||
if error?
|
||||
res.send 500
|
||||
else if user?
|
||||
res.send JSON.stringify user
|
||||
else
|
||||
res.send 404
|
||||
|
||||
app.listen 3000, (error) ->
|
||||
throw error if error?
|
||||
|
||||
MockWebApi.run()
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
sinon = require('sinon')
|
||||
chai = require('chai')
|
||||
should = chai.should()
|
||||
expect = chai.expect
|
||||
modulePath = "../../../../app/js/Features/Authentication/AuthenticationController.js"
|
||||
SandboxedModule = require('sandboxed-module')
|
||||
|
||||
describe "AuthenticationController", ->
|
||||
beforeEach ->
|
||||
@AuthenticationController = SandboxedModule.require modulePath, requires:
|
||||
"../WebApi/WebApiManager": @WebApiManager = {}
|
||||
"../Users/UserFormatter": @UserFormatter = {}
|
||||
"logger-sharelatex": @logger = { log: sinon.stub() }
|
||||
@callback = sinon.stub()
|
||||
|
||||
describe "authClient", ->
|
||||
beforeEach ->
|
||||
@auth_token = "super-secret-auth-token"
|
||||
@client =
|
||||
params: {}
|
||||
set: (key, value, callback) ->
|
||||
@params[key] = value
|
||||
callback()
|
||||
@user =
|
||||
id: "user-id-123"
|
||||
email: "doug@sharelatex.com"
|
||||
first_name: "Douglas"
|
||||
last_name: "Adams"
|
||||
@WebApiManager.getUserDetailsFromAuthToken = sinon.stub().callsArgWith(1, null, @user)
|
||||
@UserFormatter.formatUserForClientSide = sinon.stub().returns({
|
||||
id: @user.id
|
||||
first_name: @user.first_name
|
||||
last_name: @user.last_name
|
||||
email: @user.email
|
||||
gravatar_url: "//gravatar/url"
|
||||
})
|
||||
@AuthenticationController.authClient(@client, auth_token: @auth_token, @callback)
|
||||
|
||||
it "should get the user's data from the web api", ->
|
||||
@WebApiManager.getUserDetailsFromAuthToken
|
||||
.calledWith(@auth_token)
|
||||
.should.equal true
|
||||
|
||||
it "should set the user's data and auth_token on the client object", ->
|
||||
@client.params.should.deep.equal {
|
||||
id: @user.id
|
||||
first_name: @user.first_name
|
||||
last_name: @user.last_name
|
||||
email: @user.email
|
||||
gravatar_url: "//gravatar/url"
|
||||
auth_token: @auth_token
|
||||
}
|
||||
|
||||
it "should call the callback with the user details (including the gravatar URL, but not the auth_token)", ->
|
||||
@callback
|
||||
.calledWith(null, {
|
||||
id: @user.id
|
||||
email: @user.email
|
||||
first_name: @user.first_name
|
||||
last_name: @user.last_name
|
||||
gravatar_url: "//gravatar/url"
|
||||
}).should.equal true
|
||||
|
||||
it "should log the request", ->
|
||||
@logger.log
|
||||
.calledWith(auth_token: @auth_token, "authenticating user")
|
||||
.should.equal true
|
||||
@logger.log
|
||||
.calledWith(user: @user, auth_token: @auth_token, "authenticated user")
|
||||
.should.equal true
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
sinon = require('sinon')
|
||||
chai = require('chai')
|
||||
should = chai.should()
|
||||
expect = chai.expect
|
||||
modulePath = "../../../../app/js/Features/Authorization/AuthorizationManager.js"
|
||||
SandboxedModule = require('sandboxed-module')
|
||||
events = require "events"
|
||||
|
||||
describe "AuthorizationManager", ->
|
||||
beforeEach ->
|
||||
@SocketManager = {}
|
||||
@AuthorizationManager = SandboxedModule.require modulePath, requires:
|
||||
"../WebApi/WebApiManager": @WebApiManager = {}
|
||||
"../Sockets/SocketManager": @SocketManager
|
||||
@callback = sinon.stub()
|
||||
@user_id = "user-id-123"
|
||||
@project_id = "project-id-456"
|
||||
@auth_token = "auth-token-789"
|
||||
@client =
|
||||
params: {}
|
||||
get: (key, callback = (error, value) ->) ->
|
||||
callback null, @params[key]
|
||||
|
||||
describe "canClientJoinProjectRoom", ->
|
||||
beforeEach ->
|
||||
@client.params.auth_token = @auth_token
|
||||
@client.params.id = @user_id
|
||||
|
||||
describe "when the client is a collaborator", ->
|
||||
beforeEach ->
|
||||
@collaborators = [
|
||||
id: @user_id
|
||||
]
|
||||
@WebApiManager.getProjectCollaborators = sinon.stub().callsArgWith(2, null, @collaborators)
|
||||
@AuthorizationManager.canClientJoinProjectRoom(@client, @project_id, @callback)
|
||||
|
||||
it "should get the list of collaborators from the web api", ->
|
||||
@WebApiManager.getProjectCollaborators
|
||||
.calledWith(@project_id, @auth_token)
|
||||
.should.equal true
|
||||
|
||||
it "should return true", ->
|
||||
@callback.calledWith(null, true).should.equal true
|
||||
|
||||
describe "when the client is not a collaborator", ->
|
||||
beforeEach ->
|
||||
@collaborators = [
|
||||
id: "not the user id"
|
||||
]
|
||||
@WebApiManager.getProjectCollaborators = sinon.stub().callsArgWith(2, null, @collaborators)
|
||||
@AuthorizationManager.canClientJoinProjectRoom(@client, @project_id, @callback)
|
||||
|
||||
it "should return false", ->
|
||||
@callback.calledWith(null, false).should.equal true
|
||||
|
|
@ -1,187 +0,0 @@
|
|||
sinon = require('sinon')
|
||||
chai = require('chai')
|
||||
should = chai.should()
|
||||
expect = chai.expect
|
||||
modulePath = "../../../../app/js/Features/Messages/MessageController.js"
|
||||
SandboxedModule = require('sandboxed-module')
|
||||
events = require "events"
|
||||
tk = require "timekeeper"
|
||||
ObjectId = require("mongojs").ObjectId
|
||||
|
||||
describe "MessageController", ->
|
||||
beforeEach ->
|
||||
tk.freeze(new Date())
|
||||
@MessageController = SandboxedModule.require modulePath, requires:
|
||||
"./MessageManager": @MessageManager = {}
|
||||
"./MessageFormatter": @MessageFormatter = {}
|
||||
"../Sockets/SocketManager": @SocketManager = {}
|
||||
"../Authorization/AuthorizationManager": @AuthorizationManager = {}
|
||||
"logger-sharelatex": @logger = { log: sinon.stub() }
|
||||
"metrics-sharelatex": @metrics = {inc: sinon.stub()}
|
||||
@callback = sinon.stub()
|
||||
@client =
|
||||
params:
|
||||
id: @user_id = "user-id-123"
|
||||
first_name: @first_name = "Douglas"
|
||||
last_name: @last_name = "Adams"
|
||||
email: @email = "doug@sharelatex.com"
|
||||
gravatar_url: @gravatar_url = "//gravatar/url"
|
||||
get: (key, callback = (error, value) ->) -> callback null, @params[key]
|
||||
|
||||
afterEach ->
|
||||
tk.reset()
|
||||
|
||||
describe "sendMessage", ->
|
||||
beforeEach ->
|
||||
@MessageManager.createMessage = sinon.stub().callsArg(1)
|
||||
@SocketManager.emitToRoom = sinon.stub()
|
||||
@singlePopulatedMessage = {data:"here"}
|
||||
@formattedMessage = {formatted:true}
|
||||
@MessageFormatter.formatMessageForClientSide = sinon.stub().returns(@formattedMessage)
|
||||
@MessageManager.populateMessagesWithUsers = sinon.stub().callsArgWith(1, null, [@singlePopulatedMessage])
|
||||
@SocketManager.getClientAttributes = (client, attributes, callback) ->
|
||||
values = (client.params[key] for key in attributes)
|
||||
callback null, values
|
||||
|
||||
describe "when the client is authorized to send a message to the room", ->
|
||||
beforeEach ->
|
||||
@AuthorizationManager.canClientSendMessageToRoom = sinon.stub().callsArgWith(2, null, true)
|
||||
@MessageController.sendMessage(@client, {
|
||||
message:
|
||||
content: @content = "Hello world"
|
||||
room:
|
||||
id: @room_id = "room-id-123"
|
||||
}, @callback)
|
||||
|
||||
it "should check that the client can send a message to the room", ->
|
||||
@AuthorizationManager.canClientSendMessageToRoom
|
||||
.calledWith(@client, @room_id)
|
||||
.should.equal true
|
||||
|
||||
it "should insert the message into the database", ->
|
||||
@MessageManager.createMessage
|
||||
.calledWith({
|
||||
content: @content
|
||||
user_id: @user_id
|
||||
room_id: @room_id
|
||||
timestamp: Date.now()
|
||||
})
|
||||
.should.equal true
|
||||
|
||||
|
||||
it "should format the message for the client", ->
|
||||
@MessageFormatter.formatMessageForClientSide.calledWith(@singlePopulatedMessage).should.equal true
|
||||
|
||||
it "should send the formatted message out to the other clients in the room", ->
|
||||
@SocketManager.emitToRoom.calledWith(@room_id, "messageReceived", message:@formattedMessage).should.equal true
|
||||
|
||||
it "should record the message as a metric", ->
|
||||
@metrics.inc
|
||||
.calledWith("editor.instant-message")
|
||||
.should.equal true
|
||||
|
||||
it "should call the callback", ->
|
||||
@callback.called.should.equal true
|
||||
|
||||
describe "when the client is not authorized", ->
|
||||
beforeEach ->
|
||||
@AuthorizationManager.canClientSendMessageToRoom = sinon.stub().callsArgWith(2, null, false)
|
||||
@MessageController.sendMessage(@client, {
|
||||
message:
|
||||
content: @content = "Hello world"
|
||||
room:
|
||||
id: @room_id = "room-id-123"
|
||||
}, @callback)
|
||||
|
||||
it "should not insert the message into the database", ->
|
||||
@MessageManager.createMessage.called.should.equal false
|
||||
|
||||
it "should not send the message out to the other clients in the room", ->
|
||||
@SocketManager.emitToRoom.called.should.equal false
|
||||
|
||||
it "should call the callback with an error that doesn't give anything away", ->
|
||||
@callback.calledWith("unknown room").should.equal true
|
||||
|
||||
describe "getMessage", ->
|
||||
beforeEach ->
|
||||
@room_id = "room-id-123"
|
||||
@timestamp = Date.now()
|
||||
@limit = 42
|
||||
|
||||
describe "when the client is authorized", ->
|
||||
beforeEach ->
|
||||
@messages = "messages without users stub"
|
||||
@messagesWithUsers = "messages with users stub"
|
||||
@formattedMessages = "formatted messages stub"
|
||||
@MessageManager.getMessages = sinon.stub().callsArgWith(2, null, @messages)
|
||||
@MessageManager.populateMessagesWithUsers = sinon.stub().callsArgWith(1, null, @messagesWithUsers)
|
||||
@AuthorizationManager.canClientReadMessagesInRoom = sinon.stub().callsArgWith(2, null, true)
|
||||
@MessageFormatter.formatMessagesForClientSide = sinon.stub().returns @formattedMessages
|
||||
|
||||
describe "with a timestamp and limit", ->
|
||||
beforeEach ->
|
||||
@MessageController.getMessages(@client, {
|
||||
room:
|
||||
id: @room_id,
|
||||
before: @timestamp,
|
||||
limit: @limit
|
||||
}, @callback)
|
||||
|
||||
it "should get the requested messages", ->
|
||||
@MessageManager.getMessages
|
||||
.calledWith({
|
||||
timestamp: $lt: @timestamp
|
||||
room_id: @room_id
|
||||
}, {
|
||||
limit: @limit
|
||||
order_by: "timestamp"
|
||||
sort_order: -1
|
||||
})
|
||||
.should.equal true
|
||||
|
||||
it "should populate the messages with the users", ->
|
||||
@MessageManager.populateMessagesWithUsers
|
||||
.calledWith(@messages)
|
||||
.should.equal true
|
||||
|
||||
it "should return the formatted messages", ->
|
||||
@MessageFormatter.formatMessagesForClientSide
|
||||
.calledWith(@messagesWithUsers)
|
||||
.should.equal true
|
||||
|
||||
it "should call the callback with the formatted messages", ->
|
||||
@callback
|
||||
.calledWith(null, @formattedMessages)
|
||||
.should.equal true
|
||||
|
||||
describe "without a timestamp or limit", ->
|
||||
beforeEach ->
|
||||
@MessageController.getMessages(@client, {
|
||||
room:
|
||||
id: @room_id,
|
||||
}, @callback)
|
||||
|
||||
it "should get a default number of messages from the beginning", ->
|
||||
@MessageManager.getMessages
|
||||
.calledWith({
|
||||
room_id: @room_id
|
||||
}, {
|
||||
limit: @MessageController.DEFAULT_MESSAGE_LIMIT
|
||||
order_by: "timestamp"
|
||||
sort_order: -1
|
||||
})
|
||||
.should.equal true
|
||||
|
||||
describe "when the client is not authorized", ->
|
||||
beforeEach ->
|
||||
@AuthorizationManager.canClientReadMessagesInRoom = sinon.stub().callsArgWith(2, null, false)
|
||||
@MessageController.getMessages(@client, {
|
||||
room:
|
||||
id: @room_id,
|
||||
before: @timestamp,
|
||||
limit: @limit
|
||||
}, @callback)
|
||||
|
||||
it "should call the callback with an error", ->
|
||||
@callback.calledWith("unknown room").should.equal true
|
||||
|
|
@ -1,240 +0,0 @@
|
|||
sinon = require('sinon')
|
||||
chai = require('chai')
|
||||
should = chai.should()
|
||||
expect = chai.expect
|
||||
modulePath = "../../../../app/js/Features/Rooms/RoomController.js"
|
||||
SandboxedModule = require('sandboxed-module')
|
||||
events = require "events"
|
||||
ObjectId = require("mongojs").ObjectId
|
||||
|
||||
class MockClient
|
||||
params: {}
|
||||
get: (key, callback = (error, value) ->) ->
|
||||
callback null, @params[key]
|
||||
|
||||
describe "RoomController", ->
|
||||
beforeEach ->
|
||||
@SocketManager =
|
||||
getClientAttributes: sinon.stub()
|
||||
|
||||
|
||||
@RoomController = SandboxedModule.require modulePath, requires:
|
||||
"../Authorization/AuthorizationManager": @AuthorizationManager = {}
|
||||
"../Sockets/SocketManager": @SocketManager
|
||||
"../Rooms/RoomManager": @RoomManager = {}
|
||||
"logger-sharelatex": @logger = { log: sinon.stub() }
|
||||
|
||||
|
||||
@project_id = ObjectId().toString()
|
||||
@room_id = ObjectId().toString()
|
||||
@room =
|
||||
_id: ObjectId(@room_id)
|
||||
project_id: ObjectId(@project_id)
|
||||
@callback = sinon.stub()
|
||||
@client =
|
||||
params: {}
|
||||
get: (key, callback = (error, value) ->) -> callback null, @params[key]
|
||||
|
||||
describe "joinRoom", ->
|
||||
describe "when the client is authorized", ->
|
||||
beforeEach ->
|
||||
@AuthorizationManager.canClientJoinProjectRoom = sinon.stub().callsArgWith(2, null, true)
|
||||
@RoomManager.findOrCreateRoom = sinon.stub().callsArgWith(1, null, @room)
|
||||
@RoomController._addClientToRoom = sinon.stub().callsArg(2)
|
||||
@RoomController._getClientsInRoom = sinon.stub().callsArgWith(1, null, @clients = ["client1", "client2"])
|
||||
@RoomController.joinRoom @client, { room: project_id: @project_id }, @callback
|
||||
|
||||
it "should check that the client can join the room", ->
|
||||
@AuthorizationManager.canClientJoinProjectRoom
|
||||
.calledWith(@client, @project_id)
|
||||
.should.equal true
|
||||
|
||||
it "should ensure that the room exists", ->
|
||||
@RoomManager.findOrCreateRoom
|
||||
.calledWith({ project_id: @project_id })
|
||||
.should.equal true
|
||||
|
||||
it "should put the client into the room", ->
|
||||
@RoomController._addClientToRoom
|
||||
.calledWith(@client, @room_id)
|
||||
.should.equal true
|
||||
|
||||
it "should get the clients already in the room", ->
|
||||
@RoomController._getClientsInRoom
|
||||
.calledWith(@room_id)
|
||||
.should.equal true
|
||||
|
||||
it "should call the callback with the room id", ->
|
||||
@callback.calledWith(null, {
|
||||
room:
|
||||
id: @room_id
|
||||
connectedUsers: @clients
|
||||
}).should.equal true
|
||||
|
||||
describe "when the client is not authorized", ->
|
||||
beforeEach ->
|
||||
@AuthorizationManager.canClientJoinProjectRoom = sinon.stub().callsArgWith(2, null, false)
|
||||
@RoomController._addClientToRoom = sinon.stub().callsArg(2)
|
||||
@RoomController.joinRoom @client, { room: project_id: @project_id }, @callback
|
||||
|
||||
it "should not put the client into the room", ->
|
||||
@RoomController._addClientToRoom.called.should.equal false
|
||||
|
||||
it "should call the callback with an error that gives nothing away", ->
|
||||
@callback.calledWith("unknown room").should.equal true
|
||||
|
||||
describe "leaveAllRooms", ->
|
||||
|
||||
beforeEach ->
|
||||
@client = new MockClient()
|
||||
@client.params =
|
||||
id: "client-1-id"
|
||||
first_name: "Douglas"
|
||||
last_name: "Adams"
|
||||
email: "doug@sharelatex.com"
|
||||
gravatar_url: "//gravatar/url/1"
|
||||
@room_ids = ["room-id-1", "room-id-2"]
|
||||
@SocketManager.getRoomIdsClientHasJoined = sinon.stub().callsArgWith(1, null, @room_ids)
|
||||
@RoomController.leaveRoom = sinon.stub().callsArg(2)
|
||||
@RoomController.leaveAllRooms @client, @callback
|
||||
|
||||
it "should get the rooms the client has joined", ->
|
||||
@SocketManager.getRoomIdsClientHasJoined
|
||||
.calledWith(@client)
|
||||
.should.equal true
|
||||
|
||||
it "should leave each room", ->
|
||||
for room_id in @room_ids
|
||||
@RoomController.leaveRoom
|
||||
.calledWith(@client, room_id)
|
||||
.should.equal true
|
||||
|
||||
it "should call the callback", ->
|
||||
@callback.called.should.equal true
|
||||
|
||||
describe "leaveRoom", ->
|
||||
beforeEach ->
|
||||
@client = new MockClient()
|
||||
@client.params =
|
||||
id: "client-1-id"
|
||||
first_name: "Douglas"
|
||||
last_name: "Adams"
|
||||
email: "doug@sharelatex.com"
|
||||
gravatar_url: "//gravatar/url/1"
|
||||
@RoomController._getClientAttributes = sinon.stub().callsArgWith(1, null, @client.params)
|
||||
|
||||
@SocketManager.removeClientFromRoom = sinon.stub().callsArg(2)
|
||||
@SocketManager.emitToRoom = sinon.stub()
|
||||
@RoomController.leaveRoom @client, @room_id, @callback
|
||||
|
||||
it "should leave the room", ->
|
||||
@SocketManager.removeClientFromRoom
|
||||
.calledWith(@client, @room_id)
|
||||
.should.equal true
|
||||
|
||||
it "should tell the other clients in the room that we have left", ->
|
||||
@SocketManager.emitToRoom
|
||||
.calledWith(@room_id, "userLeft", {
|
||||
room:
|
||||
id: @room_id
|
||||
user:
|
||||
id : @client.params["id"]
|
||||
first_name : @client.params["first_name"]
|
||||
last_name : @client.params["last_name"]
|
||||
email : @client.params["email"]
|
||||
gravatar_url : @client.params["gravatar_url"]
|
||||
})
|
||||
.should.equal true
|
||||
|
||||
it "should call the callback", ->
|
||||
@callback.called.should.equal true
|
||||
|
||||
describe "_getClientsInRoom", ->
|
||||
beforeEach ->
|
||||
@client1 = new MockClient()
|
||||
@client1.params =
|
||||
id: "client-1-id"
|
||||
first_name: "Douglas"
|
||||
last_name: "Adams"
|
||||
email: "doug@sharelatex.com"
|
||||
gravatar_url: "//gravatar/url/1"
|
||||
@client2 = new MockClient()
|
||||
@client2.params =
|
||||
id: "client-2-id"
|
||||
first_name: "James"
|
||||
last_name: "Allen"
|
||||
email: "james@sharelatex.com"
|
||||
gravatar_url: "//gravatar/url/2"
|
||||
@clients = [ @client1, @client2 ]
|
||||
callCount = 0
|
||||
|
||||
@RoomController._getClientAttributes = (ignore, cb)=>
|
||||
if callCount == 0
|
||||
callCount++
|
||||
cb(null, @client1.params)
|
||||
else
|
||||
cb null, @client2.params
|
||||
|
||||
|
||||
@SocketManager.getClientsInRoom = sinon.stub().callsArgWith(1, null, @clients)
|
||||
@RoomController._getClientsInRoom(@room_id, @callback)
|
||||
|
||||
it "should get the socket.io clients in the room", ->
|
||||
@SocketManager.getClientsInRoom
|
||||
.calledWith(@room_id)
|
||||
.should.equal true
|
||||
|
||||
it "should return a formatted array of clients", ->
|
||||
@callback
|
||||
.calledWith(null, [{
|
||||
id : @client1.params["id"]
|
||||
first_name : @client1.params["first_name"]
|
||||
last_name : @client1.params["last_name"]
|
||||
email : @client1.params["email"]
|
||||
gravatar_url : @client1.params["gravatar_url"]
|
||||
}, {
|
||||
id : @client2.params["id"]
|
||||
first_name : @client2.params["first_name"]
|
||||
last_name : @client2.params["last_name"]
|
||||
email : @client2.params["email"]
|
||||
gravatar_url : @client2.params["gravatar_url"]
|
||||
}])
|
||||
.should.equal true
|
||||
|
||||
describe "_addClientToRoom", ->
|
||||
beforeEach ->
|
||||
@client = new MockClient()
|
||||
@client.params =
|
||||
id: "client-1-id"
|
||||
first_name: "Douglas"
|
||||
last_name: "Adams"
|
||||
email: "doug@sharelatex.com"
|
||||
gravatar_url: "//gravatar/url/1"
|
||||
@RoomController._getClientAttributes = sinon.stub().callsArgWith(1, null, @client.params)
|
||||
@SocketManager.addClientToRoom = sinon.stub().callsArg(2)
|
||||
@SocketManager.emitToRoom = sinon.stub()
|
||||
@RoomController._addClientToRoom(@client, @room_id, @callback)
|
||||
|
||||
it "should add the client to the room", ->
|
||||
@SocketManager.addClientToRoom
|
||||
.calledWith(@client, @room_id)
|
||||
.should.equal true
|
||||
|
||||
it "should tell the room that the client has been added", ->
|
||||
@SocketManager.emitToRoom
|
||||
.calledWith(@room_id, "userJoined", {
|
||||
room:
|
||||
id: @room_id
|
||||
user:
|
||||
id : @client.params["id"]
|
||||
first_name : @client.params["first_name"]
|
||||
last_name : @client.params["last_name"]
|
||||
email : @client.params["email"]
|
||||
gravatar_url : @client.params["gravatar_url"]
|
||||
})
|
||||
.should.equal true
|
||||
|
||||
it "should call the callback", ->
|
||||
@callback.called.should.equal true
|
||||
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
SandboxedModule = require('sandboxed-module')
|
||||
sinon = require('sinon')
|
||||
require('chai').should()
|
||||
modulePath = "../../../../app/js/Features/Sockets/RealTimeEventManager.js"
|
||||
|
||||
describe "RealTimeEventManager", ->
|
||||
|
||||
beforeEach ->
|
||||
@settings =
|
||||
redis:
|
||||
web:
|
||||
host: "host here"
|
||||
port: "port here"
|
||||
password: "password here"
|
||||
@RealTimeEventManager = SandboxedModule.require modulePath, requires:
|
||||
"redis":
|
||||
createClient: () ->
|
||||
auth:->
|
||||
"../../server" : io: @io = {}
|
||||
"settings-sharelatex":@settings
|
||||
@RealTimeEventManager.rclientPub = publish: sinon.stub()
|
||||
@RealTimeEventManager.rclientSub =
|
||||
subscribe: sinon.stub()
|
||||
on: sinon.stub()
|
||||
|
||||
@room_id = "room-id-here"
|
||||
@message = "message-to-chat-here"
|
||||
@payload = ["argument one", 42]
|
||||
|
||||
describe "emitToRoom", ->
|
||||
beforeEach ->
|
||||
@RealTimeEventManager.emitToRoom(@room_id, @message, @payload...)
|
||||
|
||||
it "should publish the message to redis", ->
|
||||
@RealTimeEventManager.rclientPub.publish
|
||||
.calledWith("chat-events", JSON.stringify(
|
||||
room_id: @room_id,
|
||||
message: @message
|
||||
payload: @payload
|
||||
))
|
||||
.should.equal true
|
||||
|
||||
describe "listenForChatEvents", ->
|
||||
beforeEach ->
|
||||
@RealTimeEventManager._processEditorEvent = sinon.stub()
|
||||
@RealTimeEventManager.listenForChatEvents()
|
||||
|
||||
it "should subscribe to the chat-events channel", ->
|
||||
@RealTimeEventManager.rclientSub.subscribe
|
||||
.calledWith("chat-events")
|
||||
.should.equal true
|
||||
|
||||
it "should process the events with _processEditorEvent", ->
|
||||
@RealTimeEventManager.rclientSub.on
|
||||
.calledWith("message", sinon.match.func)
|
||||
.should.equal true
|
||||
|
||||
describe "_processEditorEvent", ->
|
||||
describe "with a designated room", ->
|
||||
beforeEach ->
|
||||
@io.sockets =
|
||||
in: sinon.stub().returns(emit: @emit = sinon.stub())
|
||||
data = JSON.stringify
|
||||
room_id: @room_id
|
||||
message: @message
|
||||
payload: @payload
|
||||
@RealTimeEventManager._processEditorEvent("chat-events", data)
|
||||
|
||||
it "should send the message to all clients in the room", ->
|
||||
@io.sockets.in
|
||||
.calledWith(@room_id)
|
||||
.should.equal true
|
||||
@emit.calledWith(@message, @payload...).should.equal true
|
||||
|
||||
|
Loading…
Reference in a new issue