mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Revert "Revert "Track the isRestrictedUser
flag on clients""
This reverts commit 651e392a7c644403f199e1b03e7494b61ce71d0c.
This commit is contained in:
parent
ddb7c4270f
commit
403caa65e8
6 changed files with 210 additions and 91 deletions
|
@ -4,7 +4,7 @@ logger = require "logger-sharelatex"
|
||||||
{ CodedError } = require "./Errors"
|
{ CodedError } = require "./Errors"
|
||||||
|
|
||||||
module.exports = WebApiManager =
|
module.exports = WebApiManager =
|
||||||
joinProject: (project_id, user, callback = (error, project, privilegeLevel) ->) ->
|
joinProject: (project_id, user, callback = (error, project, privilegeLevel, isRestrictedUser) ->) ->
|
||||||
user_id = user._id
|
user_id = user._id
|
||||||
logger.log {project_id, user_id}, "sending join project request to web"
|
logger.log {project_id, user_id}, "sending join project request to web"
|
||||||
url = "#{settings.apis.web.url}/project/#{project_id}/join"
|
url = "#{settings.apis.web.url}/project/#{project_id}/join"
|
||||||
|
@ -24,7 +24,11 @@ module.exports = WebApiManager =
|
||||||
}, (error, response, data) ->
|
}, (error, response, data) ->
|
||||||
return callback(error) if error?
|
return callback(error) if error?
|
||||||
if 200 <= response.statusCode < 300
|
if 200 <= response.statusCode < 300
|
||||||
callback null, data?.project, data?.privilegeLevel
|
if !data? || !data?.project?
|
||||||
|
err = new Error('no data returned from joinProject request')
|
||||||
|
logger.error {err, project_id, user_id}, "error accessing web api"
|
||||||
|
return callback(err)
|
||||||
|
callback null, data.project, data.privilegeLevel, data.isRestrictedUser
|
||||||
else if response.statusCode == 429
|
else if response.statusCode == 429
|
||||||
logger.log(project_id, user_id, "rate-limit hit when joining project")
|
logger.log(project_id, user_id, "rate-limit hit when joining project")
|
||||||
callback(new CodedError("rate-limit hit when joining project", "TooManyRequests"))
|
callback(new CodedError("rate-limit hit when joining project", "TooManyRequests"))
|
||||||
|
|
|
@ -13,12 +13,12 @@ module.exports = WebsocketController =
|
||||||
# it will force a full refresh of the page. Useful for non-backwards
|
# it will force a full refresh of the page. Useful for non-backwards
|
||||||
# compatible protocol changes. Use only in extreme need.
|
# compatible protocol changes. Use only in extreme need.
|
||||||
PROTOCOL_VERSION: 2
|
PROTOCOL_VERSION: 2
|
||||||
|
|
||||||
joinProject: (client, user, project_id, callback = (error, project, privilegeLevel, protocolVersion) ->) ->
|
joinProject: (client, user, project_id, callback = (error, project, privilegeLevel, protocolVersion) ->) ->
|
||||||
user_id = user?._id
|
user_id = user?._id
|
||||||
logger.log {user_id, project_id, client_id: client.id}, "user joining project"
|
logger.log {user_id, project_id, client_id: client.id}, "user joining project"
|
||||||
metrics.inc "editor.join-project"
|
metrics.inc "editor.join-project"
|
||||||
WebApiManager.joinProject project_id, user, (error, project, privilegeLevel) ->
|
WebApiManager.joinProject project_id, user, (error, project, privilegeLevel, isRestrictedUser) ->
|
||||||
return callback(error) if error?
|
return callback(error) if error?
|
||||||
|
|
||||||
if !privilegeLevel or privilegeLevel == ""
|
if !privilegeLevel or privilegeLevel == ""
|
||||||
|
@ -26,7 +26,6 @@ module.exports = WebsocketController =
|
||||||
logger.warn {err, project_id, user_id, client_id: client.id}, "user is not authorized to join project"
|
logger.warn {err, project_id, user_id, client_id: client.id}, "user is not authorized to join project"
|
||||||
return callback(err)
|
return callback(err)
|
||||||
|
|
||||||
|
|
||||||
client.set("privilege_level", privilegeLevel)
|
client.set("privilege_level", privilegeLevel)
|
||||||
client.set("user_id", user_id)
|
client.set("user_id", user_id)
|
||||||
client.set("project_id", project_id)
|
client.set("project_id", project_id)
|
||||||
|
@ -37,18 +36,19 @@ module.exports = WebsocketController =
|
||||||
client.set("connected_time", new Date())
|
client.set("connected_time", new Date())
|
||||||
client.set("signup_date", user?.signUpDate)
|
client.set("signup_date", user?.signUpDate)
|
||||||
client.set("login_count", user?.loginCount)
|
client.set("login_count", user?.loginCount)
|
||||||
|
client.set("is_restricted_user", !!(isRestrictedUser))
|
||||||
|
|
||||||
RoomManager.joinProject client, project_id, (err) ->
|
RoomManager.joinProject client, project_id, (err) ->
|
||||||
logger.log {user_id, project_id, client_id: client.id}, "user joined project"
|
logger.log {user_id, project_id, client_id: client.id}, "user joined project"
|
||||||
callback null, project, privilegeLevel, WebsocketController.PROTOCOL_VERSION
|
callback null, project, privilegeLevel, WebsocketController.PROTOCOL_VERSION
|
||||||
|
|
||||||
# No need to block for setting the user as connected in the cursor tracking
|
# No need to block for setting the user as connected in the cursor tracking
|
||||||
ConnectedUsersManager.updateUserPosition project_id, client.id, user, null, () ->
|
ConnectedUsersManager.updateUserPosition project_id, client.id, user, null, () ->
|
||||||
|
|
||||||
# We want to flush a project if there are no more (local) connected clients
|
# We want to flush a project if there are no more (local) connected clients
|
||||||
# but we need to wait for the triggering client to disconnect. How long we wait
|
# but we need to wait for the triggering client to disconnect. How long we wait
|
||||||
# is determined by FLUSH_IF_EMPTY_DELAY.
|
# is determined by FLUSH_IF_EMPTY_DELAY.
|
||||||
FLUSH_IF_EMPTY_DELAY: 500 #ms
|
FLUSH_IF_EMPTY_DELAY: 500 #ms
|
||||||
leaveProject: (io, client, callback = (error) ->) ->
|
leaveProject: (io, client, callback = (error) ->) ->
|
||||||
metrics.inc "editor.leave-project"
|
metrics.inc "editor.leave-project"
|
||||||
Utils.getClientAttributes client, ["project_id", "user_id"], (error, {project_id, user_id}) ->
|
Utils.getClientAttributes client, ["project_id", "user_id"], (error, {project_id, user_id}) ->
|
||||||
|
@ -56,7 +56,7 @@ module.exports = WebsocketController =
|
||||||
|
|
||||||
logger.log {project_id, user_id, client_id: client.id}, "client leaving project"
|
logger.log {project_id, user_id, client_id: client.id}, "client leaving project"
|
||||||
WebsocketLoadBalancer.emitToRoom project_id, "clientTracking.clientDisconnected", client.id
|
WebsocketLoadBalancer.emitToRoom project_id, "clientTracking.clientDisconnected", client.id
|
||||||
|
|
||||||
# bail out if the client had not managed to authenticate or join
|
# bail out if the client had not managed to authenticate or join
|
||||||
# the project. Prevents downstream errors in docupdater from
|
# the project. Prevents downstream errors in docupdater from
|
||||||
# flushProjectToMongoAndDelete with null project_id.
|
# flushProjectToMongoAndDelete with null project_id.
|
||||||
|
@ -66,12 +66,12 @@ module.exports = WebsocketController =
|
||||||
if not project_id?
|
if not project_id?
|
||||||
logger.log {user_id: user_id, client_id: client.id}, "client leaving, not in project"
|
logger.log {user_id: user_id, client_id: client.id}, "client leaving, not in project"
|
||||||
return callback()
|
return callback()
|
||||||
|
|
||||||
# We can do this in the background
|
# We can do this in the background
|
||||||
ConnectedUsersManager.markUserAsDisconnected project_id, client.id, (err) ->
|
ConnectedUsersManager.markUserAsDisconnected project_id, client.id, (err) ->
|
||||||
if err?
|
if err?
|
||||||
logger.error {err, project_id, user_id, client_id: client.id}, "error marking client as disconnected"
|
logger.error {err, project_id, user_id, client_id: client.id}, "error marking client as disconnected"
|
||||||
|
|
||||||
RoomManager.leaveProjectAndDocs(client)
|
RoomManager.leaveProjectAndDocs(client)
|
||||||
setTimeout () ->
|
setTimeout () ->
|
||||||
remainingClients = io.sockets.clients(project_id)
|
remainingClients = io.sockets.clients(project_id)
|
||||||
|
@ -82,14 +82,14 @@ module.exports = WebsocketController =
|
||||||
logger.error {err, project_id, user_id, client_id: client.id}, "error flushing to doc updater after leaving project"
|
logger.error {err, project_id, user_id, client_id: client.id}, "error flushing to doc updater after leaving project"
|
||||||
callback()
|
callback()
|
||||||
, WebsocketController.FLUSH_IF_EMPTY_DELAY
|
, WebsocketController.FLUSH_IF_EMPTY_DELAY
|
||||||
|
|
||||||
joinDoc: (client, doc_id, fromVersion = -1, options, callback = (error, doclines, version, ops, ranges) ->) ->
|
joinDoc: (client, doc_id, fromVersion = -1, options, callback = (error, doclines, version, ops, ranges) ->) ->
|
||||||
metrics.inc "editor.join-doc"
|
metrics.inc "editor.join-doc"
|
||||||
Utils.getClientAttributes client, ["project_id", "user_id"], (error, {project_id, user_id}) ->
|
Utils.getClientAttributes client, ["project_id", "user_id"], (error, {project_id, user_id}) ->
|
||||||
return callback(error) if error?
|
return callback(error) if error?
|
||||||
return callback(new Error("no project_id found on client")) if !project_id?
|
return callback(new Error("no project_id found on client")) if !project_id?
|
||||||
logger.log {user_id, project_id, doc_id, fromVersion, client_id: client.id}, "client joining doc"
|
logger.log {user_id, project_id, doc_id, fromVersion, client_id: client.id}, "client joining doc"
|
||||||
|
|
||||||
AuthorizationManager.assertClientCanViewProject client, (error) ->
|
AuthorizationManager.assertClientCanViewProject client, (error) ->
|
||||||
return callback(error) if error?
|
return callback(error) if error?
|
||||||
# ensure the per-doc applied-ops channel is subscribed before sending the
|
# ensure the per-doc applied-ops channel is subscribed before sending the
|
||||||
|
@ -124,7 +124,7 @@ module.exports = WebsocketController =
|
||||||
AuthorizationManager.addAccessToDoc client, doc_id
|
AuthorizationManager.addAccessToDoc client, doc_id
|
||||||
logger.log {user_id, project_id, doc_id, fromVersion, client_id: client.id}, "client joined doc"
|
logger.log {user_id, project_id, doc_id, fromVersion, client_id: client.id}, "client joined doc"
|
||||||
callback null, escapedLines, version, ops, ranges
|
callback null, escapedLines, version, ops, ranges
|
||||||
|
|
||||||
leaveDoc: (client, doc_id, callback = (error) ->) ->
|
leaveDoc: (client, doc_id, callback = (error) ->) ->
|
||||||
metrics.inc "editor.leave-doc"
|
metrics.inc "editor.leave-doc"
|
||||||
Utils.getClientAttributes client, ["project_id", "user_id"], (error, {project_id, user_id}) ->
|
Utils.getClientAttributes client, ["project_id", "user_id"], (error, {project_id, user_id}) ->
|
||||||
|
@ -178,8 +178,11 @@ module.exports = WebsocketController =
|
||||||
CLIENT_REFRESH_DELAY: 1000
|
CLIENT_REFRESH_DELAY: 1000
|
||||||
getConnectedUsers: (client, callback = (error, users) ->) ->
|
getConnectedUsers: (client, callback = (error, users) ->) ->
|
||||||
metrics.inc "editor.get-connected-users"
|
metrics.inc "editor.get-connected-users"
|
||||||
Utils.getClientAttributes client, ["project_id", "user_id"], (error, {project_id, user_id}) ->
|
Utils.getClientAttributes client, ["project_id", "user_id", "is_restricted_user"], (error, clientAttributes) ->
|
||||||
return callback(error) if error?
|
return callback(error) if error?
|
||||||
|
{project_id, user_id, is_restricted_user} = clientAttributes
|
||||||
|
if is_restricted_user
|
||||||
|
return callback(null, [])
|
||||||
return callback(new Error("no project_id found on client")) if !project_id?
|
return callback(new Error("no project_id found on client")) if !project_id?
|
||||||
logger.log {user_id, project_id, client_id: client.id}, "getting connected users"
|
logger.log {user_id, project_id, client_id: client.id}, "getting connected users"
|
||||||
AuthorizationManager.assertClientCanViewProject client, (error) ->
|
AuthorizationManager.assertClientCanViewProject client, (error) ->
|
||||||
|
@ -227,9 +230,9 @@ module.exports = WebsocketController =
|
||||||
return callback(error)
|
return callback(error)
|
||||||
else
|
else
|
||||||
return callback(null)
|
return callback(null)
|
||||||
|
|
||||||
_isCommentUpdate: (update) ->
|
_isCommentUpdate: (update) ->
|
||||||
for op in update.op
|
for op in update.op
|
||||||
if !op.c?
|
if !op.c?
|
||||||
return false
|
return false
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -7,6 +7,19 @@ HealthCheckManager = require "./HealthCheckManager"
|
||||||
RoomManager = require "./RoomManager"
|
RoomManager = require "./RoomManager"
|
||||||
ChannelManager = require "./ChannelManager"
|
ChannelManager = require "./ChannelManager"
|
||||||
ConnectedUsersManager = require "./ConnectedUsersManager"
|
ConnectedUsersManager = require "./ConnectedUsersManager"
|
||||||
|
Utils = require './Utils'
|
||||||
|
Async = require 'async'
|
||||||
|
|
||||||
|
RESTRICTED_USER_MESSAGE_TYPE_PASS_LIST = [
|
||||||
|
'connectionAccepted',
|
||||||
|
'otUpdateApplied',
|
||||||
|
'otUpdateError',
|
||||||
|
'joinDoc',
|
||||||
|
'reciveNewDoc',
|
||||||
|
'reciveNewFile',
|
||||||
|
'reciveNewFolder',
|
||||||
|
'removeEntity'
|
||||||
|
]
|
||||||
|
|
||||||
module.exports = WebsocketLoadBalancer =
|
module.exports = WebsocketLoadBalancer =
|
||||||
rclientPubList: RedisClientManager.createClientList(Settings.redis.pubsub)
|
rclientPubList: RedisClientManager.createClientList(Settings.redis.pubsub)
|
||||||
|
@ -58,7 +71,7 @@ module.exports = WebsocketLoadBalancer =
|
||||||
else if message.message is 'clientTracking.refresh' && message.room_id?
|
else if message.message is 'clientTracking.refresh' && message.room_id?
|
||||||
clientList = io.sockets.clients(message.room_id)
|
clientList = io.sockets.clients(message.room_id)
|
||||||
logger.log {channel:channel, message: message.message, room_id: message.room_id, message_id: message._id, socketIoClients: (client.id for client in clientList)}, "refreshing client list"
|
logger.log {channel:channel, message: message.message, room_id: message.room_id, message_id: message._id, socketIoClients: (client.id for client in clientList)}, "refreshing client list"
|
||||||
for client in clientList
|
for client in clientList
|
||||||
ConnectedUsersManager.refreshClient(message.room_id, client.id)
|
ConnectedUsersManager.refreshClient(message.room_id, client.id)
|
||||||
else if message.room_id?
|
else if message.room_id?
|
||||||
if message._id? && Settings.checkEventOrder
|
if message._id? && Settings.checkEventOrder
|
||||||
|
@ -69,12 +82,28 @@ module.exports = WebsocketLoadBalancer =
|
||||||
clientList = io.sockets.clients(message.room_id)
|
clientList = io.sockets.clients(message.room_id)
|
||||||
# avoid unnecessary work if no clients are connected
|
# avoid unnecessary work if no clients are connected
|
||||||
return if clientList.length is 0
|
return if clientList.length is 0
|
||||||
logger.log {channel:channel, message: message.message, room_id: message.room_id, message_id: message._id, socketIoClients: (client.id for client in clientList)}, "distributing event to clients"
|
logger.log {
|
||||||
|
channel: channel,
|
||||||
|
message: message.message,
|
||||||
|
room_id: message.room_id,
|
||||||
|
message_id: message._id,
|
||||||
|
socketIoClients: (client.id for client in clientList)
|
||||||
|
}, "distributing event to clients"
|
||||||
seen = {}
|
seen = {}
|
||||||
for client in clientList when not seen[client.id]
|
# Send the messages to clients async, don't wait for them all to finish
|
||||||
seen[client.id] = true
|
Async.eachLimit clientList
|
||||||
client.emit(message.message, message.payload...)
|
, 2
|
||||||
|
, (client, cb) ->
|
||||||
|
Utils.getClientAttributes client, ['is_restricted_user'], (err, {is_restricted_user}) ->
|
||||||
|
return cb(err) if err?
|
||||||
|
if !seen[client.id]
|
||||||
|
seen[client.id] = true
|
||||||
|
if !(is_restricted_user && message.message not in RESTRICTED_USER_MESSAGE_TYPE_PASS_LIST)
|
||||||
|
client.emit(message.message, message.payload...)
|
||||||
|
cb()
|
||||||
|
, (err) ->
|
||||||
|
if err?
|
||||||
|
logger.err {err, message}, "Error sending message to clients"
|
||||||
else if message.health_check?
|
else if message.health_check?
|
||||||
logger.debug {message}, "got health check message in editor events channel"
|
logger.debug {message}, "got health check message in editor events channel"
|
||||||
HealthCheckManager.check channel, message.key
|
HealthCheckManager.check channel, message.key
|
||||||
|
|
||||||
|
|
|
@ -20,17 +20,18 @@ describe 'WebApiManager', ->
|
||||||
user: "username"
|
user: "username"
|
||||||
pass: "password"
|
pass: "password"
|
||||||
"logger-sharelatex": @logger = { log: sinon.stub(), error: sinon.stub() }
|
"logger-sharelatex": @logger = { log: sinon.stub(), error: sinon.stub() }
|
||||||
|
|
||||||
describe "joinProject", ->
|
describe "joinProject", ->
|
||||||
describe "successfully", ->
|
describe "successfully", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@response = {
|
@response = {
|
||||||
project: { name: "Test project" }
|
project: { name: "Test project" }
|
||||||
privilegeLevel: "owner"
|
privilegeLevel: "owner",
|
||||||
|
isRestrictedUser: true
|
||||||
}
|
}
|
||||||
@request.post = sinon.stub().callsArgWith(1, null, {statusCode: 200}, @response)
|
@request.post = sinon.stub().callsArgWith(1, null, {statusCode: 200}, @response)
|
||||||
@WebApiManager.joinProject @project_id, @user, @callback
|
@WebApiManager.joinProject @project_id, @user, @callback
|
||||||
|
|
||||||
it "should send a request to web to join the project", ->
|
it "should send a request to web to join the project", ->
|
||||||
@request.post
|
@request.post
|
||||||
.calledWith({
|
.calledWith({
|
||||||
|
@ -46,22 +47,32 @@ describe 'WebApiManager', ->
|
||||||
headers: {}
|
headers: {}
|
||||||
})
|
})
|
||||||
.should.equal true
|
.should.equal true
|
||||||
|
|
||||||
it "should return the project and privilegeLevel", ->
|
it "should return the project, privilegeLevel, and restricted flag", ->
|
||||||
@callback
|
@callback
|
||||||
.calledWith(null, @response.project, @response.privilegeLevel)
|
.calledWith(null, @response.project, @response.privilegeLevel, @response.isRestrictedUser)
|
||||||
.should.equal true
|
.should.equal true
|
||||||
|
|
||||||
describe "with an error from web", ->
|
describe "with an error from web", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@request.post = sinon.stub().callsArgWith(1, null, {statusCode: 500}, null)
|
@request.post = sinon.stub().callsArgWith(1, null, {statusCode: 500}, null)
|
||||||
@WebApiManager.joinProject @project_id, @user_id, @callback
|
@WebApiManager.joinProject @project_id, @user_id, @callback
|
||||||
|
|
||||||
it "should call the callback with an error", ->
|
it "should call the callback with an error", ->
|
||||||
@callback
|
@callback
|
||||||
.calledWith(new Error("non-success code from web: 500"))
|
.calledWith(new Error("non-success code from web: 500"))
|
||||||
.should.equal true
|
.should.equal true
|
||||||
|
|
||||||
|
describe "with no data from web", ->
|
||||||
|
beforeEach ->
|
||||||
|
@request.post = sinon.stub().callsArgWith(1, null, {statusCode: 200}, null)
|
||||||
|
@WebApiManager.joinProject @project_id, @user_id, @callback
|
||||||
|
|
||||||
|
it "should call the callback with an error", ->
|
||||||
|
@callback
|
||||||
|
.calledWith(new Error("no data returned from joinProject request"))
|
||||||
|
.should.equal true
|
||||||
|
|
||||||
describe "when the project is over its rate limit", ->
|
describe "when the project is over its rate limit", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@request.post = sinon.stub().callsArgWith(1, null, {statusCode: 429}, null)
|
@request.post = sinon.stub().callsArgWith(1, null, {statusCode: 429}, null)
|
||||||
|
|
|
@ -37,10 +37,10 @@ describe 'WebsocketController', ->
|
||||||
inc: sinon.stub()
|
inc: sinon.stub()
|
||||||
set: sinon.stub()
|
set: sinon.stub()
|
||||||
"./RoomManager": @RoomManager = {}
|
"./RoomManager": @RoomManager = {}
|
||||||
|
|
||||||
afterEach ->
|
afterEach ->
|
||||||
tk.reset()
|
tk.reset()
|
||||||
|
|
||||||
describe "joinProject", ->
|
describe "joinProject", ->
|
||||||
describe "when authorised", ->
|
describe "when authorised", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
|
@ -53,61 +53,65 @@ describe 'WebsocketController', ->
|
||||||
}
|
}
|
||||||
@privilegeLevel = "owner"
|
@privilegeLevel = "owner"
|
||||||
@ConnectedUsersManager.updateUserPosition = sinon.stub().callsArg(4)
|
@ConnectedUsersManager.updateUserPosition = sinon.stub().callsArg(4)
|
||||||
@WebApiManager.joinProject = sinon.stub().callsArgWith(2, null, @project, @privilegeLevel)
|
@isRestrictedUser = true
|
||||||
|
@WebApiManager.joinProject = sinon.stub().callsArgWith(2, null, @project, @privilegeLevel, @isRestrictedUser)
|
||||||
@RoomManager.joinProject = sinon.stub().callsArg(2)
|
@RoomManager.joinProject = sinon.stub().callsArg(2)
|
||||||
@WebsocketController.joinProject @client, @user, @project_id, @callback
|
@WebsocketController.joinProject @client, @user, @project_id, @callback
|
||||||
|
|
||||||
it "should load the project from web", ->
|
it "should load the project from web", ->
|
||||||
@WebApiManager.joinProject
|
@WebApiManager.joinProject
|
||||||
.calledWith(@project_id, @user)
|
.calledWith(@project_id, @user)
|
||||||
.should.equal true
|
.should.equal true
|
||||||
|
|
||||||
it "should join the project room", ->
|
it "should join the project room", ->
|
||||||
@RoomManager.joinProject.calledWith(@client, @project_id).should.equal true
|
@RoomManager.joinProject.calledWith(@client, @project_id).should.equal true
|
||||||
|
|
||||||
it "should set the privilege level on the client", ->
|
it "should set the privilege level on the client", ->
|
||||||
@client.set.calledWith("privilege_level", @privilegeLevel).should.equal true
|
@client.set.calledWith("privilege_level", @privilegeLevel).should.equal true
|
||||||
|
|
||||||
it "should set the user's id on the client", ->
|
it "should set the user's id on the client", ->
|
||||||
@client.set.calledWith("user_id", @user._id).should.equal true
|
@client.set.calledWith("user_id", @user._id).should.equal true
|
||||||
|
|
||||||
it "should set the user's email on the client", ->
|
it "should set the user's email on the client", ->
|
||||||
@client.set.calledWith("email", @user.email).should.equal true
|
@client.set.calledWith("email", @user.email).should.equal true
|
||||||
|
|
||||||
it "should set the user's first_name on the client", ->
|
it "should set the user's first_name on the client", ->
|
||||||
@client.set.calledWith("first_name", @user.first_name).should.equal true
|
@client.set.calledWith("first_name", @user.first_name).should.equal true
|
||||||
|
|
||||||
it "should set the user's last_name on the client", ->
|
it "should set the user's last_name on the client", ->
|
||||||
@client.set.calledWith("last_name", @user.last_name).should.equal true
|
@client.set.calledWith("last_name", @user.last_name).should.equal true
|
||||||
|
|
||||||
it "should set the user's sign up date on the client", ->
|
it "should set the user's sign up date on the client", ->
|
||||||
@client.set.calledWith("signup_date", @user.signUpDate).should.equal true
|
@client.set.calledWith("signup_date", @user.signUpDate).should.equal true
|
||||||
|
|
||||||
it "should set the user's login_count on the client", ->
|
it "should set the user's login_count on the client", ->
|
||||||
@client.set.calledWith("login_count", @user.loginCount).should.equal true
|
@client.set.calledWith("login_count", @user.loginCount).should.equal true
|
||||||
|
|
||||||
it "should set the connected time on the client", ->
|
it "should set the connected time on the client", ->
|
||||||
@client.set.calledWith("connected_time", new Date()).should.equal true
|
@client.set.calledWith("connected_time", new Date()).should.equal true
|
||||||
|
|
||||||
it "should set the project_id on the client", ->
|
it "should set the project_id on the client", ->
|
||||||
@client.set.calledWith("project_id", @project_id).should.equal true
|
@client.set.calledWith("project_id", @project_id).should.equal true
|
||||||
|
|
||||||
it "should set the project owner id on the client", ->
|
it "should set the project owner id on the client", ->
|
||||||
@client.set.calledWith("owner_id", @owner_id).should.equal true
|
@client.set.calledWith("owner_id", @owner_id).should.equal true
|
||||||
|
|
||||||
|
it "should set the is_restricted_user flag on the client", ->
|
||||||
|
@client.set.calledWith("is_restricted_user", @isRestrictedUser).should.equal true
|
||||||
|
|
||||||
it "should call the callback with the project, privilegeLevel and protocolVersion", ->
|
it "should call the callback with the project, privilegeLevel and protocolVersion", ->
|
||||||
@callback
|
@callback
|
||||||
.calledWith(null, @project, @privilegeLevel, @WebsocketController.PROTOCOL_VERSION)
|
.calledWith(null, @project, @privilegeLevel, @WebsocketController.PROTOCOL_VERSION)
|
||||||
.should.equal true
|
.should.equal true
|
||||||
|
|
||||||
it "should mark the user as connected in ConnectedUsersManager", ->
|
it "should mark the user as connected in ConnectedUsersManager", ->
|
||||||
@ConnectedUsersManager.updateUserPosition
|
@ConnectedUsersManager.updateUserPosition
|
||||||
.calledWith(@project_id, @client.id, @user, null)
|
.calledWith(@project_id, @client.id, @user, null)
|
||||||
.should.equal true
|
.should.equal true
|
||||||
|
|
||||||
it "should increment the join-project metric", ->
|
it "should increment the join-project metric", ->
|
||||||
@metrics.inc.calledWith("editor.join-project").should.equal true
|
@metrics.inc.calledWith("editor.join-project").should.equal true
|
||||||
|
|
||||||
describe "when not authorized", ->
|
describe "when not authorized", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@WebApiManager.joinProject = sinon.stub().callsArgWith(2, null, null, null)
|
@WebApiManager.joinProject = sinon.stub().callsArgWith(2, null, null, null)
|
||||||
|
@ -138,30 +142,30 @@ describe 'WebsocketController', ->
|
||||||
@client.params.user_id = @user_id
|
@client.params.user_id = @user_id
|
||||||
@WebsocketController.FLUSH_IF_EMPTY_DELAY = 0
|
@WebsocketController.FLUSH_IF_EMPTY_DELAY = 0
|
||||||
tk.reset() # Allow setTimeout to work.
|
tk.reset() # Allow setTimeout to work.
|
||||||
|
|
||||||
describe "when the project is empty", ->
|
describe "when the project is empty", ->
|
||||||
beforeEach (done) ->
|
beforeEach (done) ->
|
||||||
@clientsInRoom = []
|
@clientsInRoom = []
|
||||||
@WebsocketController.leaveProject @io, @client, done
|
@WebsocketController.leaveProject @io, @client, done
|
||||||
|
|
||||||
it "should end clientTracking.clientDisconnected to the project room", ->
|
it "should end clientTracking.clientDisconnected to the project room", ->
|
||||||
@WebsocketLoadBalancer.emitToRoom
|
@WebsocketLoadBalancer.emitToRoom
|
||||||
.calledWith(@project_id, "clientTracking.clientDisconnected", @client.id)
|
.calledWith(@project_id, "clientTracking.clientDisconnected", @client.id)
|
||||||
.should.equal true
|
.should.equal true
|
||||||
|
|
||||||
it "should mark the user as disconnected", ->
|
it "should mark the user as disconnected", ->
|
||||||
@ConnectedUsersManager.markUserAsDisconnected
|
@ConnectedUsersManager.markUserAsDisconnected
|
||||||
.calledWith(@project_id, @client.id)
|
.calledWith(@project_id, @client.id)
|
||||||
.should.equal true
|
.should.equal true
|
||||||
|
|
||||||
it "should flush the project in the document updater", ->
|
it "should flush the project in the document updater", ->
|
||||||
@DocumentUpdaterManager.flushProjectToMongoAndDelete
|
@DocumentUpdaterManager.flushProjectToMongoAndDelete
|
||||||
.calledWith(@project_id)
|
.calledWith(@project_id)
|
||||||
.should.equal true
|
.should.equal true
|
||||||
|
|
||||||
it "should increment the leave-project metric", ->
|
it "should increment the leave-project metric", ->
|
||||||
@metrics.inc.calledWith("editor.leave-project").should.equal true
|
@metrics.inc.calledWith("editor.leave-project").should.equal true
|
||||||
|
|
||||||
it "should track the disconnection in RoomManager", ->
|
it "should track the disconnection in RoomManager", ->
|
||||||
@RoomManager.leaveProjectAndDocs
|
@RoomManager.leaveProjectAndDocs
|
||||||
.calledWith(@client)
|
.calledWith(@client)
|
||||||
|
@ -171,7 +175,7 @@ describe 'WebsocketController', ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@clientsInRoom = ["mock-remaining-client"]
|
@clientsInRoom = ["mock-remaining-client"]
|
||||||
@WebsocketController.leaveProject @io, @client
|
@WebsocketController.leaveProject @io, @client
|
||||||
|
|
||||||
it "should not flush the project in the document updater", ->
|
it "should not flush the project in the document updater", ->
|
||||||
@DocumentUpdaterManager.flushProjectToMongoAndDelete
|
@DocumentUpdaterManager.flushProjectToMongoAndDelete
|
||||||
.called.should.equal false
|
.called.should.equal false
|
||||||
|
@ -232,7 +236,7 @@ describe 'WebsocketController', ->
|
||||||
@ops = ["mock", "ops"]
|
@ops = ["mock", "ops"]
|
||||||
@ranges = { "mock": "ranges" }
|
@ranges = { "mock": "ranges" }
|
||||||
@options = {}
|
@options = {}
|
||||||
|
|
||||||
@client.params.project_id = @project_id
|
@client.params.project_id = @project_id
|
||||||
@AuthorizationManager.addAccessToDoc = sinon.stub()
|
@AuthorizationManager.addAccessToDoc = sinon.stub()
|
||||||
@AuthorizationManager.assertClientCanViewProject = sinon.stub().callsArgWith(1, null)
|
@AuthorizationManager.assertClientCanViewProject = sinon.stub().callsArgWith(1, null)
|
||||||
|
@ -275,7 +279,7 @@ describe 'WebsocketController', ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@fromVersion = 40
|
@fromVersion = 40
|
||||||
@WebsocketController.joinDoc @client, @doc_id, @fromVersion, @options, @callback
|
@WebsocketController.joinDoc @client, @doc_id, @fromVersion, @options, @callback
|
||||||
|
|
||||||
it "should get the document from the DocumentUpdaterManager with fromVersion", ->
|
it "should get the document from the DocumentUpdaterManager with fromVersion", ->
|
||||||
@DocumentUpdaterManager.getDocument
|
@DocumentUpdaterManager.getDocument
|
||||||
.calledWith(@project_id, @doc_id, @fromVersion)
|
.calledWith(@project_id, @doc_id, @fromVersion)
|
||||||
|
@ -285,7 +289,7 @@ describe 'WebsocketController', ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@doc_lines.push ["räksmörgås"]
|
@doc_lines.push ["räksmörgås"]
|
||||||
@WebsocketController.joinDoc @client, @doc_id, -1, @options, @callback
|
@WebsocketController.joinDoc @client, @doc_id, -1, @options, @callback
|
||||||
|
|
||||||
it "should call the callback with the escaped lines", ->
|
it "should call the callback with the escaped lines", ->
|
||||||
escaped_lines = @callback.args[0][1]
|
escaped_lines = @callback.args[0][1]
|
||||||
escaped_word = escaped_lines.pop()
|
escaped_word = escaped_lines.pop()
|
||||||
|
@ -327,44 +331,44 @@ describe 'WebsocketController', ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@AuthorizationManager.assertClientCanViewProject = sinon.stub().callsArgWith(1, @err = new Error("not authorized"))
|
@AuthorizationManager.assertClientCanViewProject = sinon.stub().callsArgWith(1, @err = new Error("not authorized"))
|
||||||
@WebsocketController.joinDoc @client, @doc_id, -1, @options, @callback
|
@WebsocketController.joinDoc @client, @doc_id, -1, @options, @callback
|
||||||
|
|
||||||
it "should call the callback with an error", ->
|
it "should call the callback with an error", ->
|
||||||
@callback.calledWith(@err).should.equal true
|
@callback.calledWith(@err).should.equal true
|
||||||
|
|
||||||
it "should not call the DocumentUpdaterManager", ->
|
it "should not call the DocumentUpdaterManager", ->
|
||||||
@DocumentUpdaterManager.getDocument.called.should.equal false
|
@DocumentUpdaterManager.getDocument.called.should.equal false
|
||||||
|
|
||||||
describe "leaveDoc", ->
|
describe "leaveDoc", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@doc_id = "doc-id-123"
|
@doc_id = "doc-id-123"
|
||||||
@client.params.project_id = @project_id
|
@client.params.project_id = @project_id
|
||||||
@RoomManager.leaveDoc = sinon.stub()
|
@RoomManager.leaveDoc = sinon.stub()
|
||||||
@WebsocketController.leaveDoc @client, @doc_id, @callback
|
@WebsocketController.leaveDoc @client, @doc_id, @callback
|
||||||
|
|
||||||
it "should remove the client from the doc_id room", ->
|
it "should remove the client from the doc_id room", ->
|
||||||
@RoomManager.leaveDoc
|
@RoomManager.leaveDoc
|
||||||
.calledWith(@client, @doc_id).should.equal true
|
.calledWith(@client, @doc_id).should.equal true
|
||||||
|
|
||||||
it "should call the callback", ->
|
it "should call the callback", ->
|
||||||
@callback.called.should.equal true
|
@callback.called.should.equal true
|
||||||
|
|
||||||
it "should increment the leave-doc metric", ->
|
it "should increment the leave-doc metric", ->
|
||||||
@metrics.inc.calledWith("editor.leave-doc").should.equal true
|
@metrics.inc.calledWith("editor.leave-doc").should.equal true
|
||||||
|
|
||||||
describe "getConnectedUsers", ->
|
describe "getConnectedUsers", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@client.params.project_id = @project_id
|
@client.params.project_id = @project_id
|
||||||
@users = ["mock", "users"]
|
@users = ["mock", "users"]
|
||||||
@WebsocketLoadBalancer.emitToRoom = sinon.stub()
|
@WebsocketLoadBalancer.emitToRoom = sinon.stub()
|
||||||
@ConnectedUsersManager.getConnectedUsers = sinon.stub().callsArgWith(1, null, @users)
|
@ConnectedUsersManager.getConnectedUsers = sinon.stub().callsArgWith(1, null, @users)
|
||||||
|
|
||||||
describe "when authorized", ->
|
describe "when authorized", ->
|
||||||
beforeEach (done) ->
|
beforeEach (done) ->
|
||||||
@AuthorizationManager.assertClientCanViewProject = sinon.stub().callsArgWith(1, null)
|
@AuthorizationManager.assertClientCanViewProject = sinon.stub().callsArgWith(1, null)
|
||||||
@WebsocketController.getConnectedUsers @client, (args...) =>
|
@WebsocketController.getConnectedUsers @client, (args...) =>
|
||||||
@callback(args...)
|
@callback(args...)
|
||||||
done()
|
done()
|
||||||
|
|
||||||
it "should check that the client is authorized to view the project", ->
|
it "should check that the client is authorized to view the project", ->
|
||||||
@AuthorizationManager.assertClientCanViewProject
|
@AuthorizationManager.assertClientCanViewProject
|
||||||
.calledWith(@client)
|
.calledWith(@client)
|
||||||
|
@ -379,26 +383,40 @@ describe 'WebsocketController', ->
|
||||||
@ConnectedUsersManager.getConnectedUsers
|
@ConnectedUsersManager.getConnectedUsers
|
||||||
.calledWith(@project_id)
|
.calledWith(@project_id)
|
||||||
.should.equal true
|
.should.equal true
|
||||||
|
|
||||||
it "should return the users", ->
|
it "should return the users", ->
|
||||||
@callback.calledWith(null, @users).should.equal true
|
@callback.calledWith(null, @users).should.equal true
|
||||||
|
|
||||||
it "should increment the get-connected-users metric", ->
|
it "should increment the get-connected-users metric", ->
|
||||||
@metrics.inc.calledWith("editor.get-connected-users").should.equal true
|
@metrics.inc.calledWith("editor.get-connected-users").should.equal true
|
||||||
|
|
||||||
describe "when not authorized", ->
|
describe "when not authorized", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@AuthorizationManager.assertClientCanViewProject = sinon.stub().callsArgWith(1, @err = new Error("not authorized"))
|
@AuthorizationManager.assertClientCanViewProject = sinon.stub().callsArgWith(1, @err = new Error("not authorized"))
|
||||||
@WebsocketController.getConnectedUsers @client, @callback
|
@WebsocketController.getConnectedUsers @client, @callback
|
||||||
|
|
||||||
it "should not get the connected users for the project", ->
|
it "should not get the connected users for the project", ->
|
||||||
@ConnectedUsersManager.getConnectedUsers
|
@ConnectedUsersManager.getConnectedUsers
|
||||||
.called
|
.called
|
||||||
.should.equal false
|
.should.equal false
|
||||||
|
|
||||||
it "should return an error", ->
|
it "should return an error", ->
|
||||||
@callback.calledWith(@err).should.equal true
|
@callback.calledWith(@err).should.equal true
|
||||||
|
|
||||||
|
describe "when restricted user", ->
|
||||||
|
beforeEach ->
|
||||||
|
@client.params.is_restricted_user = true
|
||||||
|
@AuthorizationManager.assertClientCanViewProject = sinon.stub().callsArgWith(1, null)
|
||||||
|
@WebsocketController.getConnectedUsers @client, @callback
|
||||||
|
|
||||||
|
it "should return an empty array of users", ->
|
||||||
|
@callback.calledWith(null, []).should.equal true
|
||||||
|
|
||||||
|
it "should not get the connected users for the project", ->
|
||||||
|
@ConnectedUsersManager.getConnectedUsers
|
||||||
|
.called
|
||||||
|
.should.equal false
|
||||||
|
|
||||||
describe "updateClientPosition", ->
|
describe "updateClientPosition", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@WebsocketLoadBalancer.emitToRoom = sinon.stub()
|
@WebsocketLoadBalancer.emitToRoom = sinon.stub()
|
||||||
|
@ -422,7 +440,7 @@ describe 'WebsocketController', ->
|
||||||
@client.get = (param, callback) => callback null, @clientParams[param]
|
@client.get = (param, callback) => callback null, @clientParams[param]
|
||||||
@WebsocketController.updateClientPosition @client, @update
|
@WebsocketController.updateClientPosition @client, @update
|
||||||
|
|
||||||
@populatedCursorData =
|
@populatedCursorData =
|
||||||
doc_id: @doc_id,
|
doc_id: @doc_id,
|
||||||
id: @client.id
|
id: @client.id
|
||||||
name: "#{@first_name} #{@last_name}"
|
name: "#{@first_name} #{@last_name}"
|
||||||
|
@ -462,7 +480,7 @@ describe 'WebsocketController', ->
|
||||||
@client.get = (param, callback) => callback null, @clientParams[param]
|
@client.get = (param, callback) => callback null, @clientParams[param]
|
||||||
@WebsocketController.updateClientPosition @client, @update
|
@WebsocketController.updateClientPosition @client, @update
|
||||||
|
|
||||||
@populatedCursorData =
|
@populatedCursorData =
|
||||||
doc_id: @doc_id,
|
doc_id: @doc_id,
|
||||||
id: @client.id
|
id: @client.id
|
||||||
name: "#{@first_name}"
|
name: "#{@first_name}"
|
||||||
|
@ -502,7 +520,7 @@ describe 'WebsocketController', ->
|
||||||
@client.get = (param, callback) => callback null, @clientParams[param]
|
@client.get = (param, callback) => callback null, @clientParams[param]
|
||||||
@WebsocketController.updateClientPosition @client, @update
|
@WebsocketController.updateClientPosition @client, @update
|
||||||
|
|
||||||
@populatedCursorData =
|
@populatedCursorData =
|
||||||
doc_id: @doc_id,
|
doc_id: @doc_id,
|
||||||
id: @client.id
|
id: @client.id
|
||||||
name: "#{@last_name}"
|
name: "#{@last_name}"
|
||||||
|
@ -603,7 +621,7 @@ describe 'WebsocketController', ->
|
||||||
|
|
||||||
it "should call the callback", ->
|
it "should call the callback", ->
|
||||||
@callback.called.should.equal true
|
@callback.called.should.equal true
|
||||||
|
|
||||||
it "should increment the doc updates", ->
|
it "should increment the doc updates", ->
|
||||||
@metrics.inc.calledWith("editor.doc-update").should.equal true
|
@metrics.inc.calledWith("editor.doc-update").should.equal true
|
||||||
|
|
||||||
|
@ -621,7 +639,7 @@ describe 'WebsocketController', ->
|
||||||
|
|
||||||
it "should call the callback with the error", ->
|
it "should call the callback with the error", ->
|
||||||
@callback.calledWith(@error).should.equal true
|
@callback.calledWith(@error).should.equal true
|
||||||
|
|
||||||
describe "when not authorized", ->
|
describe "when not authorized", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@client.disconnect = sinon.stub()
|
@client.disconnect = sinon.stub()
|
||||||
|
@ -645,7 +663,7 @@ describe 'WebsocketController', ->
|
||||||
@comment_update = { op: [{c: "bar", p: 132}] }
|
@comment_update = { op: [{c: "bar", p: 132}] }
|
||||||
@AuthorizationManager.assertClientCanEditProjectAndDoc = sinon.stub()
|
@AuthorizationManager.assertClientCanEditProjectAndDoc = sinon.stub()
|
||||||
@AuthorizationManager.assertClientCanViewProjectAndDoc = sinon.stub()
|
@AuthorizationManager.assertClientCanViewProjectAndDoc = sinon.stub()
|
||||||
|
|
||||||
describe "with a read-write client", ->
|
describe "with a read-write client", ->
|
||||||
it "should return successfully", (done) ->
|
it "should return successfully", (done) ->
|
||||||
@AuthorizationManager.assertClientCanEditProjectAndDoc.yields(null)
|
@AuthorizationManager.assertClientCanEditProjectAndDoc.yields(null)
|
||||||
|
@ -660,7 +678,7 @@ describe 'WebsocketController', ->
|
||||||
@WebsocketController._assertClientCanApplyUpdate @client, @doc_id, @edit_update, (error) ->
|
@WebsocketController._assertClientCanApplyUpdate @client, @doc_id, @edit_update, (error) ->
|
||||||
expect(error.message).to.equal "not authorized"
|
expect(error.message).to.equal "not authorized"
|
||||||
done()
|
done()
|
||||||
|
|
||||||
describe "with a read-only client and a comment op", ->
|
describe "with a read-only client and a comment op", ->
|
||||||
it "should return successfully", (done) ->
|
it "should return successfully", (done) ->
|
||||||
@AuthorizationManager.assertClientCanEditProjectAndDoc.yields(new Error("not authorized"))
|
@AuthorizationManager.assertClientCanEditProjectAndDoc.yields(new Error("not authorized"))
|
||||||
|
@ -668,7 +686,7 @@ describe 'WebsocketController', ->
|
||||||
@WebsocketController._assertClientCanApplyUpdate @client, @doc_id, @comment_update, (error) ->
|
@WebsocketController._assertClientCanApplyUpdate @client, @doc_id, @comment_update, (error) ->
|
||||||
expect(error).to.be.null
|
expect(error).to.be.null
|
||||||
done()
|
done()
|
||||||
|
|
||||||
describe "with a totally unauthorized client", ->
|
describe "with a totally unauthorized client", ->
|
||||||
it "should return an error", (done) ->
|
it "should return an error", (done) ->
|
||||||
@AuthorizationManager.assertClientCanEditProjectAndDoc.yields(new Error("not authorized"))
|
@AuthorizationManager.assertClientCanEditProjectAndDoc.yields(new Error("not authorized"))
|
||||||
|
|
|
@ -8,7 +8,7 @@ describe "WebsocketLoadBalancer", ->
|
||||||
@rclient = {}
|
@rclient = {}
|
||||||
@RoomEvents = {on: sinon.stub()}
|
@RoomEvents = {on: sinon.stub()}
|
||||||
@WebsocketLoadBalancer = SandboxedModule.require modulePath, requires:
|
@WebsocketLoadBalancer = SandboxedModule.require modulePath, requires:
|
||||||
"./RedisClientManager":
|
"./RedisClientManager":
|
||||||
createClientList: () => []
|
createClientList: () => []
|
||||||
"logger-sharelatex": @logger = { log: sinon.stub(), error: sinon.stub() }
|
"logger-sharelatex": @logger = { log: sinon.stub(), error: sinon.stub() }
|
||||||
"./SafeJsonParse": @SafeJsonParse =
|
"./SafeJsonParse": @SafeJsonParse =
|
||||||
|
@ -18,6 +18,12 @@ describe "WebsocketLoadBalancer", ->
|
||||||
"./RoomManager" : @RoomManager = {eventSource: sinon.stub().returns @RoomEvents}
|
"./RoomManager" : @RoomManager = {eventSource: sinon.stub().returns @RoomEvents}
|
||||||
"./ChannelManager": @ChannelManager = {publish: sinon.stub()}
|
"./ChannelManager": @ChannelManager = {publish: sinon.stub()}
|
||||||
"./ConnectedUsersManager": @ConnectedUsersManager = {refreshClient: sinon.stub()}
|
"./ConnectedUsersManager": @ConnectedUsersManager = {refreshClient: sinon.stub()}
|
||||||
|
"./Utils": @Utils = {
|
||||||
|
getClientAttributes: sinon.spy(
|
||||||
|
(client, _attrs, callback) ->
|
||||||
|
callback(null, {is_restricted_user: !!client.__isRestricted})
|
||||||
|
)
|
||||||
|
}
|
||||||
@io = {}
|
@io = {}
|
||||||
@WebsocketLoadBalancer.rclientPubList = [{publish: sinon.stub()}]
|
@WebsocketLoadBalancer.rclientPubList = [{publish: sinon.stub()}]
|
||||||
@WebsocketLoadBalancer.rclientSubList = [{
|
@WebsocketLoadBalancer.rclientSubList = [{
|
||||||
|
@ -26,7 +32,7 @@ describe "WebsocketLoadBalancer", ->
|
||||||
}]
|
}]
|
||||||
|
|
||||||
@room_id = "room-id"
|
@room_id = "room-id"
|
||||||
@message = "message-to-editor"
|
@message = "otUpdateApplied"
|
||||||
@payload = ["argument one", 42]
|
@payload = ["argument one", 42]
|
||||||
|
|
||||||
describe "emitToRoom", ->
|
describe "emitToRoom", ->
|
||||||
|
@ -51,7 +57,7 @@ describe "WebsocketLoadBalancer", ->
|
||||||
@WebsocketLoadBalancer.emitToRoom
|
@WebsocketLoadBalancer.emitToRoom
|
||||||
.calledWith("all", @message, @payload...)
|
.calledWith("all", @message, @payload...)
|
||||||
.should.equal true
|
.should.equal true
|
||||||
|
|
||||||
describe "listenForEditorEvents", ->
|
describe "listenForEditorEvents", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@WebsocketLoadBalancer._processEditorEvent = sinon.stub()
|
@WebsocketLoadBalancer._processEditorEvent = sinon.stub()
|
||||||
|
@ -70,9 +76,10 @@ describe "WebsocketLoadBalancer", ->
|
||||||
describe "_processEditorEvent", ->
|
describe "_processEditorEvent", ->
|
||||||
describe "with bad JSON", ->
|
describe "with bad JSON", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
|
@isRestrictedUser = false
|
||||||
@SafeJsonParse.parse = sinon.stub().callsArgWith 1, new Error("oops")
|
@SafeJsonParse.parse = sinon.stub().callsArgWith 1, new Error("oops")
|
||||||
@WebsocketLoadBalancer._processEditorEvent(@io, "editor-events", "blah")
|
@WebsocketLoadBalancer._processEditorEvent(@io, "editor-events", "blah")
|
||||||
|
|
||||||
it "should log an error", ->
|
it "should log an error", ->
|
||||||
@logger.error.called.should.equal true
|
@logger.error.called.should.equal true
|
||||||
|
|
||||||
|
@ -98,6 +105,54 @@ describe "WebsocketLoadBalancer", ->
|
||||||
@emit2.calledWith(@message, @payload...).should.equal true
|
@emit2.calledWith(@message, @payload...).should.equal true
|
||||||
@emit3.called.should.equal false # duplicate client should be ignored
|
@emit3.called.should.equal false # duplicate client should be ignored
|
||||||
|
|
||||||
|
describe "with a designated room, and restricted clients, not restricted message", ->
|
||||||
|
beforeEach ->
|
||||||
|
@io.sockets =
|
||||||
|
clients: sinon.stub().returns([
|
||||||
|
{id: 'client-id-1', emit: @emit1 = sinon.stub()}
|
||||||
|
{id: 'client-id-2', emit: @emit2 = sinon.stub()}
|
||||||
|
{id: 'client-id-1', emit: @emit3 = sinon.stub()} # duplicate client
|
||||||
|
{id: 'client-id-4', emit: @emit4 = sinon.stub(), __isRestricted: true}
|
||||||
|
])
|
||||||
|
data = JSON.stringify
|
||||||
|
room_id: @room_id
|
||||||
|
message: @message
|
||||||
|
payload: @payload
|
||||||
|
@WebsocketLoadBalancer._processEditorEvent(@io, "editor-events", data)
|
||||||
|
|
||||||
|
it "should send the message to all (unique) clients in the room", ->
|
||||||
|
@io.sockets.clients
|
||||||
|
.calledWith(@room_id)
|
||||||
|
.should.equal true
|
||||||
|
@emit1.calledWith(@message, @payload...).should.equal true
|
||||||
|
@emit2.calledWith(@message, @payload...).should.equal true
|
||||||
|
@emit3.called.should.equal false # duplicate client should be ignored
|
||||||
|
@emit4.called.should.equal true # restricted client, but should be called
|
||||||
|
|
||||||
|
describe "with a designated room, and restricted clients, restricted message", ->
|
||||||
|
beforeEach ->
|
||||||
|
@io.sockets =
|
||||||
|
clients: sinon.stub().returns([
|
||||||
|
{id: 'client-id-1', emit: @emit1 = sinon.stub()}
|
||||||
|
{id: 'client-id-2', emit: @emit2 = sinon.stub()}
|
||||||
|
{id: 'client-id-1', emit: @emit3 = sinon.stub()} # duplicate client
|
||||||
|
{id: 'client-id-4', emit: @emit4 = sinon.stub(), __isRestricted: true}
|
||||||
|
])
|
||||||
|
data = JSON.stringify
|
||||||
|
room_id: @room_id
|
||||||
|
message: @restrictedMessage = 'new-comment'
|
||||||
|
payload: @payload
|
||||||
|
@WebsocketLoadBalancer._processEditorEvent(@io, "editor-events", data)
|
||||||
|
|
||||||
|
it "should send the message to all (unique) clients in the room, who are not restricted", ->
|
||||||
|
@io.sockets.clients
|
||||||
|
.calledWith(@room_id)
|
||||||
|
.should.equal true
|
||||||
|
@emit1.calledWith(@restrictedMessage, @payload...).should.equal true
|
||||||
|
@emit2.calledWith(@restrictedMessage, @payload...).should.equal true
|
||||||
|
@emit3.called.should.equal false # duplicate client should be ignored
|
||||||
|
@emit4.called.should.equal false # restricted client, should not be called
|
||||||
|
|
||||||
describe "when emitting to all", ->
|
describe "when emitting to all", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@io.sockets =
|
@io.sockets =
|
||||||
|
@ -110,4 +165,3 @@ describe "WebsocketLoadBalancer", ->
|
||||||
|
|
||||||
it "should send the message to all clients", ->
|
it "should send the message to all clients", ->
|
||||||
@emit.calledWith(@message, @payload...).should.equal true
|
@emit.calledWith(@message, @payload...).should.equal true
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue