2020-06-23 13:30:03 -04:00
|
|
|
/* eslint-disable
|
|
|
|
camelcase,
|
|
|
|
handle-callback-err,
|
|
|
|
no-return-assign,
|
|
|
|
no-unused-vars,
|
|
|
|
*/
|
|
|
|
// TODO: This file was created by bulk-decaffeinate.
|
|
|
|
// Fix any style issues and re-enable lint.
|
2020-06-23 13:29:59 -04:00
|
|
|
/*
|
|
|
|
* decaffeinate suggestions:
|
|
|
|
* DS102: Remove unnecessary code created because of implicit returns
|
|
|
|
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
|
|
|
*/
|
|
|
|
|
|
|
|
const should = require('chai').should();
|
|
|
|
const SandboxedModule = require('sandboxed-module');
|
|
|
|
const assert = require('assert');
|
|
|
|
const path = require('path');
|
|
|
|
const sinon = require('sinon');
|
|
|
|
const modulePath = path.join(__dirname, "../../../app/js/ConnectedUsersManager");
|
|
|
|
const {
|
|
|
|
expect
|
|
|
|
} = require("chai");
|
|
|
|
const tk = require("timekeeper");
|
|
|
|
|
|
|
|
|
|
|
|
describe("ConnectedUsersManager", function() {
|
|
|
|
|
|
|
|
beforeEach(function() {
|
|
|
|
|
|
|
|
this.settings = {
|
|
|
|
redis: {
|
|
|
|
realtime: {
|
|
|
|
key_schema: {
|
|
|
|
clientsInProject({project_id}) { return `clients_in_project:${project_id}`; },
|
|
|
|
connectedUser({project_id, client_id}){ return `connected_user:${project_id}:${client_id}`; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
this.rClient = {
|
|
|
|
auth() {},
|
|
|
|
setex:sinon.stub(),
|
|
|
|
sadd:sinon.stub(),
|
|
|
|
get: sinon.stub(),
|
|
|
|
srem:sinon.stub(),
|
|
|
|
del:sinon.stub(),
|
|
|
|
smembers:sinon.stub(),
|
|
|
|
expire:sinon.stub(),
|
|
|
|
hset:sinon.stub(),
|
|
|
|
hgetall:sinon.stub(),
|
|
|
|
exec:sinon.stub(),
|
|
|
|
multi: () => { return this.rClient; }
|
|
|
|
};
|
|
|
|
tk.freeze(new Date());
|
|
|
|
|
|
|
|
this.ConnectedUsersManager = SandboxedModule.require(modulePath, { requires: {
|
|
|
|
"settings-sharelatex":this.settings,
|
|
|
|
"logger-sharelatex": { log() {}
|
|
|
|
},
|
|
|
|
"redis-sharelatex": { createClient:() => {
|
|
|
|
return this.rClient;
|
|
|
|
}
|
2014-11-13 07:27:46 -05:00
|
|
|
}
|
2020-06-23 13:29:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
this.client_id = "32132132";
|
|
|
|
this.project_id = "dskjh2u21321";
|
|
|
|
this.user = {
|
|
|
|
_id: "user-id-123",
|
|
|
|
first_name: "Joe",
|
|
|
|
last_name: "Bloggs",
|
|
|
|
email: "joe@example.com"
|
|
|
|
};
|
|
|
|
return this.cursorData = { row: 12, column: 9, doc_id: '53c3b8c85fee64000023dc6e' };});
|
|
|
|
|
2020-06-23 13:30:03 -04:00
|
|
|
afterEach(function() { return tk.reset(); });
|
2020-06-23 13:29:59 -04:00
|
|
|
|
|
|
|
describe("updateUserPosition", function() {
|
|
|
|
beforeEach(function() {
|
|
|
|
return this.rClient.exec.callsArgWith(0);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should set a key with the date and give it a ttl", function(done){
|
|
|
|
return this.ConnectedUsersManager.updateUserPosition(this.project_id, this.client_id, this.user, null, err=> {
|
|
|
|
this.rClient.hset.calledWith(`connected_user:${this.project_id}:${this.client_id}`, "last_updated_at", Date.now()).should.equal(true);
|
|
|
|
return done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should set a key with the user_id", function(done){
|
|
|
|
return this.ConnectedUsersManager.updateUserPosition(this.project_id, this.client_id, this.user, null, err=> {
|
|
|
|
this.rClient.hset.calledWith(`connected_user:${this.project_id}:${this.client_id}`, "user_id", this.user._id).should.equal(true);
|
|
|
|
return done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should set a key with the first_name", function(done){
|
|
|
|
return this.ConnectedUsersManager.updateUserPosition(this.project_id, this.client_id, this.user, null, err=> {
|
|
|
|
this.rClient.hset.calledWith(`connected_user:${this.project_id}:${this.client_id}`, "first_name", this.user.first_name).should.equal(true);
|
|
|
|
return done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should set a key with the last_name", function(done){
|
|
|
|
return this.ConnectedUsersManager.updateUserPosition(this.project_id, this.client_id, this.user, null, err=> {
|
|
|
|
this.rClient.hset.calledWith(`connected_user:${this.project_id}:${this.client_id}`, "last_name", this.user.last_name).should.equal(true);
|
|
|
|
return done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should set a key with the email", function(done){
|
|
|
|
return this.ConnectedUsersManager.updateUserPosition(this.project_id, this.client_id, this.user, null, err=> {
|
|
|
|
this.rClient.hset.calledWith(`connected_user:${this.project_id}:${this.client_id}`, "email", this.user.email).should.equal(true);
|
|
|
|
return done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should push the client_id on to the project list", function(done){
|
|
|
|
return this.ConnectedUsersManager.updateUserPosition(this.project_id, this.client_id, this.user, null, err=> {
|
|
|
|
this.rClient.sadd.calledWith(`clients_in_project:${this.project_id}`, this.client_id).should.equal(true);
|
|
|
|
return done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should add a ttl to the project set so it stays clean", function(done){
|
|
|
|
return this.ConnectedUsersManager.updateUserPosition(this.project_id, this.client_id, this.user, null, err=> {
|
|
|
|
this.rClient.expire.calledWith(`clients_in_project:${this.project_id}`, 24 * 4 * 60 * 60).should.equal(true);
|
|
|
|
return done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should add a ttl to the connected user so it stays clean", function(done) {
|
|
|
|
return this.ConnectedUsersManager.updateUserPosition(this.project_id, this.client_id, this.user, null, err=> {
|
|
|
|
this.rClient.expire.calledWith(`connected_user:${this.project_id}:${this.client_id}`, 60 * 15).should.equal(true);
|
|
|
|
return done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
return it("should set the cursor position when provided", function(done){
|
|
|
|
return this.ConnectedUsersManager.updateUserPosition(this.project_id, this.client_id, this.user, this.cursorData, err=> {
|
|
|
|
this.rClient.hset.calledWith(`connected_user:${this.project_id}:${this.client_id}`, "cursorData", JSON.stringify(this.cursorData)).should.equal(true);
|
|
|
|
return done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe("markUserAsDisconnected", function() {
|
|
|
|
beforeEach(function() {
|
|
|
|
return this.rClient.exec.callsArgWith(0);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should remove the user from the set", function(done){
|
|
|
|
return this.ConnectedUsersManager.markUserAsDisconnected(this.project_id, this.client_id, err=> {
|
|
|
|
this.rClient.srem.calledWith(`clients_in_project:${this.project_id}`, this.client_id).should.equal(true);
|
|
|
|
return done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should delete the connected_user string", function(done){
|
|
|
|
return this.ConnectedUsersManager.markUserAsDisconnected(this.project_id, this.client_id, err=> {
|
|
|
|
this.rClient.del.calledWith(`connected_user:${this.project_id}:${this.client_id}`).should.equal(true);
|
|
|
|
return done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
return it("should add a ttl to the connected user set so it stays clean", function(done){
|
|
|
|
return this.ConnectedUsersManager.markUserAsDisconnected(this.project_id, this.client_id, err=> {
|
|
|
|
this.rClient.expire.calledWith(`clients_in_project:${this.project_id}`, 24 * 4 * 60 * 60).should.equal(true);
|
|
|
|
return done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe("_getConnectedUser", function() {
|
|
|
|
|
|
|
|
it("should return a connected user if there is a user object", function(done){
|
|
|
|
const cursorData = JSON.stringify({cursorData:{row:1}});
|
|
|
|
this.rClient.hgetall.callsArgWith(1, null, {connected_at:new Date(), user_id: this.user._id, last_updated_at: `${Date.now()}`, cursorData});
|
|
|
|
return this.ConnectedUsersManager._getConnectedUser(this.project_id, this.client_id, (err, result)=> {
|
|
|
|
result.connected.should.equal(true);
|
|
|
|
result.client_id.should.equal(this.client_id);
|
|
|
|
return done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should return a not connected user if there is no object", function(done){
|
|
|
|
this.rClient.hgetall.callsArgWith(1, null, null);
|
|
|
|
return this.ConnectedUsersManager._getConnectedUser(this.project_id, this.client_id, (err, result)=> {
|
|
|
|
result.connected.should.equal(false);
|
|
|
|
result.client_id.should.equal(this.client_id);
|
|
|
|
return done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
return it("should return a not connected user if there is an empty object", function(done){
|
|
|
|
this.rClient.hgetall.callsArgWith(1, null, {});
|
|
|
|
return this.ConnectedUsersManager._getConnectedUser(this.project_id, this.client_id, (err, result)=> {
|
|
|
|
result.connected.should.equal(false);
|
|
|
|
result.client_id.should.equal(this.client_id);
|
|
|
|
return done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
return describe("getConnectedUsers", function() {
|
|
|
|
|
|
|
|
beforeEach(function() {
|
|
|
|
this.users = ["1234", "5678", "9123", "8234"];
|
|
|
|
this.rClient.smembers.callsArgWith(1, null, this.users);
|
|
|
|
this.ConnectedUsersManager._getConnectedUser = sinon.stub();
|
|
|
|
this.ConnectedUsersManager._getConnectedUser.withArgs(this.project_id, this.users[0]).callsArgWith(2, null, {connected:true, client_age: 2, client_id:this.users[0]});
|
|
|
|
this.ConnectedUsersManager._getConnectedUser.withArgs(this.project_id, this.users[1]).callsArgWith(2, null, {connected:false, client_age: 1, client_id:this.users[1]});
|
|
|
|
this.ConnectedUsersManager._getConnectedUser.withArgs(this.project_id, this.users[2]).callsArgWith(2, null, {connected:true, client_age: 3, client_id:this.users[2]});
|
|
|
|
return this.ConnectedUsersManager._getConnectedUser.withArgs(this.project_id, this.users[3]).callsArgWith(2, null, {connected:true, client_age: 11, client_id:this.users[3]});
|
|
|
|
}); // connected but old
|
|
|
|
|
|
|
|
return it("should only return the users in the list which are still in redis and recently updated", function(done){
|
|
|
|
return this.ConnectedUsersManager.getConnectedUsers(this.project_id, (err, users)=> {
|
|
|
|
users.length.should.equal(2);
|
|
|
|
users[0].should.deep.equal({client_id:this.users[0], client_age: 2, connected:true});
|
|
|
|
users[1].should.deep.equal({client_id:this.users[2], client_age: 3, connected:true});
|
|
|
|
return done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2014-11-13 07:27:46 -05:00
|
|
|
|