diff --git a/services/real-time/test/acceptance/coffee/ApplyUpdateTests.js b/services/real-time/test/acceptance/coffee/ApplyUpdateTests.js index f2437f2641..41d1a5e100 100644 --- a/services/real-time/test/acceptance/coffee/ApplyUpdateTests.js +++ b/services/real-time/test/acceptance/coffee/ApplyUpdateTests.js @@ -1,222 +1,317 @@ -async = require "async" -chai = require("chai") -expect = chai.expect -chai.should() +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS201: Simplify complex destructure assignments + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const async = require("async"); +const chai = require("chai"); +const { + expect +} = chai; +chai.should(); -RealTimeClient = require "./helpers/RealTimeClient" -FixturesManager = require "./helpers/FixturesManager" +const RealTimeClient = require("./helpers/RealTimeClient"); +const FixturesManager = require("./helpers/FixturesManager"); -settings = require "settings-sharelatex" -redis = require "redis-sharelatex" -rclient = redis.createClient(settings.redis.documentupdater) +const settings = require("settings-sharelatex"); +const redis = require("redis-sharelatex"); +const rclient = redis.createClient(settings.redis.documentupdater); -redisSettings = settings.redis +const redisSettings = settings.redis; -describe "applyOtUpdate", -> - before -> - @update = { +describe("applyOtUpdate", function() { + before(function() { + return this.update = { op: [{i: "foo", p: 42}] - } - describe "when authorized", -> - before (done) -> - async.series [ - (cb) => - FixturesManager.setUpProject { + };}); + describe("when authorized", function() { + before(function(done) { + return async.series([ + cb => { + return FixturesManager.setUpProject({ privilegeLevel: "readAndWrite" - }, (e, {@project_id, @user_id}) => - cb(e) + }, (e, {project_id, user_id}) => { + this.project_id = project_id; + this.user_id = user_id; + return cb(e); + }); + }, - (cb) => - FixturesManager.setUpDoc @project_id, {@lines, @version, @ops}, (e, {@doc_id}) => - cb(e) + cb => { + return FixturesManager.setUpDoc(this.project_id, {lines: this.lines, version: this.version, ops: this.ops}, (e, {doc_id}) => { + this.doc_id = doc_id; + return cb(e); + }); + }, - (cb) => - @client = RealTimeClient.connect() - @client.on "connectionAccepted", cb + cb => { + this.client = RealTimeClient.connect(); + return this.client.on("connectionAccepted", cb); + }, - (cb) => - @client.emit "joinProject", project_id: @project_id, cb + cb => { + return this.client.emit("joinProject", {project_id: this.project_id}, cb); + }, - (cb) => - @client.emit "joinDoc", @doc_id, cb + cb => { + return this.client.emit("joinDoc", this.doc_id, cb); + }, - (cb) => - @client.emit "applyOtUpdate", @doc_id, @update, cb - ], done - - it "should push the doc into the pending updates list", (done) -> - rclient.lrange "pending-updates-list", 0, -1, (error, [doc_id]) => - doc_id.should.equal "#{@project_id}:#{@doc_id}" - done() - return null - - it "should push the update into redis", (done) -> - rclient.lrange redisSettings.documentupdater.key_schema.pendingUpdates({@doc_id}), 0, -1, (error, [update]) => - update = JSON.parse(update) - update.op.should.deep.equal @update.op - update.meta.should.deep.equal { - source: @client.publicId - user_id: @user_id + cb => { + return this.client.emit("applyOtUpdate", this.doc_id, this.update, cb); } - done() - return null - - after (done) -> - async.series [ - (cb) => rclient.del "pending-updates-list", cb - (cb) => rclient.del "DocsWithPendingUpdates", "#{@project_id}:#{@doc_id}", cb - (cb) => rclient.del redisSettings.documentupdater.key_schema.pendingUpdates(@doc_id), cb - ], done + ], done); + }); - describe "when authorized with a huge edit update", -> - before (done) -> - @update = { + it("should push the doc into the pending updates list", function(done) { + rclient.lrange("pending-updates-list", 0, -1, (error, ...rest) => { + const [doc_id] = Array.from(rest[0]); + doc_id.should.equal(`${this.project_id}:${this.doc_id}`); + return done(); + }); + return null; + }); + + it("should push the update into redis", function(done) { + rclient.lrange(redisSettings.documentupdater.key_schema.pendingUpdates({doc_id: this.doc_id}), 0, -1, (error, ...rest) => { + let [update] = Array.from(rest[0]); + update = JSON.parse(update); + update.op.should.deep.equal(this.update.op); + update.meta.should.deep.equal({ + source: this.client.publicId, + user_id: this.user_id + }); + return done(); + }); + return null; + }); + + return after(function(done) { + return async.series([ + cb => rclient.del("pending-updates-list", cb), + cb => rclient.del("DocsWithPendingUpdates", `${this.project_id}:${this.doc_id}`, cb), + cb => rclient.del(redisSettings.documentupdater.key_schema.pendingUpdates(this.doc_id), cb) + ], done); + }); + }); + + describe("when authorized with a huge edit update", function() { + before(function(done) { + this.update = { op: { p: 12, - t: "update is too large".repeat(1024 * 400) # >7MB + t: "update is too large".repeat(1024 * 400) // >7MB } - } - async.series [ - (cb) => - FixturesManager.setUpProject { + }; + return async.series([ + cb => { + return FixturesManager.setUpProject({ privilegeLevel: "readAndWrite" - }, (e, {@project_id, @user_id}) => - cb(e) + }, (e, {project_id, user_id}) => { + this.project_id = project_id; + this.user_id = user_id; + return cb(e); + }); + }, - (cb) => - FixturesManager.setUpDoc @project_id, {@lines, @version, @ops}, (e, {@doc_id}) => - cb(e) + cb => { + return FixturesManager.setUpDoc(this.project_id, {lines: this.lines, version: this.version, ops: this.ops}, (e, {doc_id}) => { + this.doc_id = doc_id; + return cb(e); + }); + }, - (cb) => - @client = RealTimeClient.connect() - @client.on "connectionAccepted", cb - @client.on "otUpdateError", (@otUpdateError) => - - (cb) => - @client.emit "joinProject", project_id: @project_id, cb - - (cb) => - @client.emit "joinDoc", @doc_id, cb - - (cb) => - @client.emit "applyOtUpdate", @doc_id, @update, (@error) => - cb() - ], done - - it "should not return an error", -> - expect(@error).to.not.exist - - it "should send an otUpdateError to the client", (done) -> - setTimeout () => - expect(@otUpdateError).to.exist - done() - , 300 - - it "should disconnect the client", (done) -> - setTimeout () => - @client.socket.connected.should.equal false - done() - , 300 - - it "should not put the update in redis", (done) -> - rclient.llen redisSettings.documentupdater.key_schema.pendingUpdates({@doc_id}), (error, len) => - len.should.equal 0 - done() - return null - - describe "when authorized to read-only with an edit update", -> - before (done) -> - async.series [ - (cb) => - FixturesManager.setUpProject { - privilegeLevel: "readOnly" - }, (e, {@project_id, @user_id}) => - cb(e) - - (cb) => - FixturesManager.setUpDoc @project_id, {@lines, @version, @ops}, (e, {@doc_id}) => - cb(e) - - (cb) => - @client = RealTimeClient.connect() - @client.on "connectionAccepted", cb + cb => { + this.client = RealTimeClient.connect(); + this.client.on("connectionAccepted", cb); + return this.client.on("otUpdateError", otUpdateError => { + this.otUpdateError = otUpdateError; - (cb) => - @client.emit "joinProject", project_id: @project_id, cb - - (cb) => - @client.emit "joinDoc", @doc_id, cb - - (cb) => - @client.emit "applyOtUpdate", @doc_id, @update, (@error) => - cb() - ], done - - it "should return an error", -> - expect(@error).to.exist - - it "should disconnect the client", (done) -> - setTimeout () => - @client.socket.connected.should.equal false - done() - , 300 - - it "should not put the update in redis", (done) -> - rclient.llen redisSettings.documentupdater.key_schema.pendingUpdates({@doc_id}), (error, len) => - len.should.equal 0 - done() - return null - - describe "when authorized to read-only with a comment update", -> - before (done) -> - @comment_update = { - op: [{c: "foo", p: 42}] - } - async.series [ - (cb) => - FixturesManager.setUpProject { - privilegeLevel: "readOnly" - }, (e, {@project_id, @user_id}) => - cb(e) - - (cb) => - FixturesManager.setUpDoc @project_id, {@lines, @version, @ops}, (e, {@doc_id}) => - cb(e) + }); + }, - (cb) => - @client = RealTimeClient.connect() - @client.on "connectionAccepted", cb - - (cb) => - @client.emit "joinProject", project_id: @project_id, cb - - (cb) => - @client.emit "joinDoc", @doc_id, cb - - (cb) => - @client.emit "applyOtUpdate", @doc_id, @comment_update, cb - ], done - - it "should push the doc into the pending updates list", (done) -> - rclient.lrange "pending-updates-list", 0, -1, (error, [doc_id]) => - doc_id.should.equal "#{@project_id}:#{@doc_id}" - done() - return null + cb => { + return this.client.emit("joinProject", {project_id: this.project_id}, cb); + }, - it "should push the update into redis", (done) -> - rclient.lrange redisSettings.documentupdater.key_schema.pendingUpdates({@doc_id}), 0, -1, (error, [update]) => - update = JSON.parse(update) - update.op.should.deep.equal @comment_update.op - update.meta.should.deep.equal { - source: @client.publicId - user_id: @user_id + cb => { + return this.client.emit("joinDoc", this.doc_id, cb); + }, + + cb => { + return this.client.emit("applyOtUpdate", this.doc_id, this.update, error => { + this.error = error; + return cb(); + }); } - done() - return null + ], done); + }); - after (done) -> - async.series [ - (cb) => rclient.del "pending-updates-list", cb - (cb) => rclient.del "DocsWithPendingUpdates", "#{@project_id}:#{@doc_id}", cb - (cb) => rclient.del redisSettings.documentupdater.key_schema.pendingUpdates({@doc_id}), cb - ], done + it("should not return an error", function() { + return expect(this.error).to.not.exist; + }); + + it("should send an otUpdateError to the client", function(done) { + return setTimeout(() => { + expect(this.otUpdateError).to.exist; + return done(); + } + , 300); + }); + + it("should disconnect the client", function(done) { + return setTimeout(() => { + this.client.socket.connected.should.equal(false); + return done(); + } + , 300); + }); + + return it("should not put the update in redis", function(done) { + rclient.llen(redisSettings.documentupdater.key_schema.pendingUpdates({doc_id: this.doc_id}), (error, len) => { + len.should.equal(0); + return done(); + }); + return null; + }); + }); + + describe("when authorized to read-only with an edit update", function() { + before(function(done) { + return async.series([ + cb => { + return FixturesManager.setUpProject({ + privilegeLevel: "readOnly" + }, (e, {project_id, user_id}) => { + this.project_id = project_id; + this.user_id = user_id; + return cb(e); + }); + }, + + cb => { + return FixturesManager.setUpDoc(this.project_id, {lines: this.lines, version: this.version, ops: this.ops}, (e, {doc_id}) => { + this.doc_id = doc_id; + return cb(e); + }); + }, + + cb => { + this.client = RealTimeClient.connect(); + return this.client.on("connectionAccepted", cb); + }, + + cb => { + return this.client.emit("joinProject", {project_id: this.project_id}, cb); + }, + + cb => { + return this.client.emit("joinDoc", this.doc_id, cb); + }, + + cb => { + return this.client.emit("applyOtUpdate", this.doc_id, this.update, error => { + this.error = error; + return cb(); + }); + } + ], done); + }); + + it("should return an error", function() { + return expect(this.error).to.exist; + }); + + it("should disconnect the client", function(done) { + return setTimeout(() => { + this.client.socket.connected.should.equal(false); + return done(); + } + , 300); + }); + + return it("should not put the update in redis", function(done) { + rclient.llen(redisSettings.documentupdater.key_schema.pendingUpdates({doc_id: this.doc_id}), (error, len) => { + len.should.equal(0); + return done(); + }); + return null; + }); + }); + + return describe("when authorized to read-only with a comment update", function() { + before(function(done) { + this.comment_update = { + op: [{c: "foo", p: 42}] + }; + return async.series([ + cb => { + return FixturesManager.setUpProject({ + privilegeLevel: "readOnly" + }, (e, {project_id, user_id}) => { + this.project_id = project_id; + this.user_id = user_id; + return cb(e); + }); + }, + + cb => { + return FixturesManager.setUpDoc(this.project_id, {lines: this.lines, version: this.version, ops: this.ops}, (e, {doc_id}) => { + this.doc_id = doc_id; + return cb(e); + }); + }, + + cb => { + this.client = RealTimeClient.connect(); + return this.client.on("connectionAccepted", cb); + }, + + cb => { + return this.client.emit("joinProject", {project_id: this.project_id}, cb); + }, + + cb => { + return this.client.emit("joinDoc", this.doc_id, cb); + }, + + cb => { + return this.client.emit("applyOtUpdate", this.doc_id, this.comment_update, cb); + } + ], done); + }); + + it("should push the doc into the pending updates list", function(done) { + rclient.lrange("pending-updates-list", 0, -1, (error, ...rest) => { + const [doc_id] = Array.from(rest[0]); + doc_id.should.equal(`${this.project_id}:${this.doc_id}`); + return done(); + }); + return null; + }); + + it("should push the update into redis", function(done) { + rclient.lrange(redisSettings.documentupdater.key_schema.pendingUpdates({doc_id: this.doc_id}), 0, -1, (error, ...rest) => { + let [update] = Array.from(rest[0]); + update = JSON.parse(update); + update.op.should.deep.equal(this.comment_update.op); + update.meta.should.deep.equal({ + source: this.client.publicId, + user_id: this.user_id + }); + return done(); + }); + return null; + }); + + return after(function(done) { + return async.series([ + cb => rclient.del("pending-updates-list", cb), + cb => rclient.del("DocsWithPendingUpdates", `${this.project_id}:${this.doc_id}`, cb), + cb => rclient.del(redisSettings.documentupdater.key_schema.pendingUpdates({doc_id: this.doc_id}), cb) + ], done); + }); + }); +}); diff --git a/services/real-time/test/acceptance/coffee/ClientTrackingTests.js b/services/real-time/test/acceptance/coffee/ClientTrackingTests.js index e76eca7d8e..8406aebcbe 100644 --- a/services/real-time/test/acceptance/coffee/ClientTrackingTests.js +++ b/services/real-time/test/acceptance/coffee/ClientTrackingTests.js @@ -1,146 +1,191 @@ -chai = require("chai") -expect = chai.expect -chai.should() +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const chai = require("chai"); +const { + expect +} = chai; +chai.should(); -RealTimeClient = require "./helpers/RealTimeClient" -MockWebServer = require "./helpers/MockWebServer" -FixturesManager = require "./helpers/FixturesManager" +const RealTimeClient = require("./helpers/RealTimeClient"); +const MockWebServer = require("./helpers/MockWebServer"); +const FixturesManager = require("./helpers/FixturesManager"); -async = require "async" +const async = require("async"); -describe "clientTracking", -> - describe "when a client updates its cursor location", -> - before (done) -> - async.series [ - (cb) => - FixturesManager.setUpProject { - privilegeLevel: "owner" +describe("clientTracking", function() { + describe("when a client updates its cursor location", function() { + before(function(done) { + return async.series([ + cb => { + return FixturesManager.setUpProject({ + privilegeLevel: "owner", project: { name: "Test Project" } - }, (error, {@user_id, @project_id}) => cb() + }, (error, {user_id, project_id}) => { this.user_id = user_id; this.project_id = project_id; return cb(); }); + }, - (cb) => - FixturesManager.setUpDoc @project_id, {@lines, @version, @ops}, (e, {@doc_id}) => - cb(e) + cb => { + return FixturesManager.setUpDoc(this.project_id, {lines: this.lines, version: this.version, ops: this.ops}, (e, {doc_id}) => { + this.doc_id = doc_id; + return cb(e); + }); + }, - (cb) => - @clientA = RealTimeClient.connect() - @clientA.on "connectionAccepted", cb + cb => { + this.clientA = RealTimeClient.connect(); + return this.clientA.on("connectionAccepted", cb); + }, - (cb) => - @clientB = RealTimeClient.connect() - @clientB.on "connectionAccepted", cb + cb => { + this.clientB = RealTimeClient.connect(); + return this.clientB.on("connectionAccepted", cb); + }, - (cb) => - @clientA.emit "joinProject", { - project_id: @project_id - }, cb + cb => { + return this.clientA.emit("joinProject", { + project_id: this.project_id + }, cb); + }, - (cb) => - @clientA.emit "joinDoc", @doc_id, cb + cb => { + return this.clientA.emit("joinDoc", this.doc_id, cb); + }, - (cb) => - @clientB.emit "joinProject", { - project_id: @project_id - }, cb + cb => { + return this.clientB.emit("joinProject", { + project_id: this.project_id + }, cb); + }, - (cb) => - @updates = [] - @clientB.on "clientTracking.clientUpdated", (data) => - @updates.push data + cb => { + this.updates = []; + this.clientB.on("clientTracking.clientUpdated", data => { + return this.updates.push(data); + }); - @clientA.emit "clientTracking.updatePosition", { - row: @row = 42 - column: @column = 36 - doc_id: @doc_id - }, (error) -> - throw error if error? - setTimeout cb, 300 # Give the message a chance to reach client B. - ], done + return this.clientA.emit("clientTracking.updatePosition", { + row: (this.row = 42), + column: (this.column = 36), + doc_id: this.doc_id + }, function(error) { + if (error != null) { throw error; } + return setTimeout(cb, 300); + }); + } // Give the message a chance to reach client B. + ], done); + }); - it "should tell other clients about the update", -> - @updates.should.deep.equal [ + it("should tell other clients about the update", function() { + return this.updates.should.deep.equal([ { - row: @row - column: @column - doc_id: @doc_id - id: @clientA.publicId - user_id: @user_id + row: this.row, + column: this.column, + doc_id: this.doc_id, + id: this.clientA.publicId, + user_id: this.user_id, name: "Joe Bloggs" } - ] + ]); + }); - it "should record the update in getConnectedUsers", (done) -> - @clientB.emit "clientTracking.getConnectedUsers", (error, users) => - for user in users - if user.client_id == @clientA.publicId + return it("should record the update in getConnectedUsers", function(done) { + return this.clientB.emit("clientTracking.getConnectedUsers", (error, users) => { + for (let user of Array.from(users)) { + if (user.client_id === this.clientA.publicId) { expect(user.cursorData).to.deep.equal({ - row: @row - column: @column - doc_id: @doc_id - }) - return done() - throw new Error("user was never found") + row: this.row, + column: this.column, + doc_id: this.doc_id + }); + return done(); + } + } + throw new Error("user was never found"); + }); + }); + }); - describe "when an anonymous client updates its cursor location", -> - before (done) -> - async.series [ - (cb) => - FixturesManager.setUpProject { - privilegeLevel: "owner" - project: { name: "Test Project" } + return describe("when an anonymous client updates its cursor location", function() { + before(function(done) { + return async.series([ + cb => { + return FixturesManager.setUpProject({ + privilegeLevel: "owner", + project: { name: "Test Project" }, publicAccess: "readAndWrite" - }, (error, {@user_id, @project_id}) => cb() + }, (error, {user_id, project_id}) => { this.user_id = user_id; this.project_id = project_id; return cb(); }); + }, - (cb) => - FixturesManager.setUpDoc @project_id, {@lines, @version, @ops}, (e, {@doc_id}) => - cb(e) + cb => { + return FixturesManager.setUpDoc(this.project_id, {lines: this.lines, version: this.version, ops: this.ops}, (e, {doc_id}) => { + this.doc_id = doc_id; + return cb(e); + }); + }, - (cb) => - @clientA = RealTimeClient.connect() - @clientA.on "connectionAccepted", cb + cb => { + this.clientA = RealTimeClient.connect(); + return this.clientA.on("connectionAccepted", cb); + }, - (cb) => - @clientA.emit "joinProject", { - project_id: @project_id - }, cb + cb => { + return this.clientA.emit("joinProject", { + project_id: this.project_id + }, cb); + }, - (cb) => - RealTimeClient.setSession({}, cb) + cb => { + return RealTimeClient.setSession({}, cb); + }, - (cb) => - @anonymous = RealTimeClient.connect() - @anonymous.on "connectionAccepted", cb + cb => { + this.anonymous = RealTimeClient.connect(); + return this.anonymous.on("connectionAccepted", cb); + }, - (cb) => - @anonymous.emit "joinProject", { - project_id: @project_id - }, cb + cb => { + return this.anonymous.emit("joinProject", { + project_id: this.project_id + }, cb); + }, - (cb) => - @anonymous.emit "joinDoc", @doc_id, cb + cb => { + return this.anonymous.emit("joinDoc", this.doc_id, cb); + }, - (cb) => - @updates = [] - @clientA.on "clientTracking.clientUpdated", (data) => - @updates.push data + cb => { + this.updates = []; + this.clientA.on("clientTracking.clientUpdated", data => { + return this.updates.push(data); + }); - @anonymous.emit "clientTracking.updatePosition", { - row: @row = 42 - column: @column = 36 - doc_id: @doc_id - }, (error) -> - throw error if error? - setTimeout cb, 300 # Give the message a chance to reach client B. - ], done + return this.anonymous.emit("clientTracking.updatePosition", { + row: (this.row = 42), + column: (this.column = 36), + doc_id: this.doc_id + }, function(error) { + if (error != null) { throw error; } + return setTimeout(cb, 300); + }); + } // Give the message a chance to reach client B. + ], done); + }); - it "should tell other clients about the update", -> - @updates.should.deep.equal [ + return it("should tell other clients about the update", function() { + return this.updates.should.deep.equal([ { - row: @row - column: @column - doc_id: @doc_id - id: @anonymous.publicId - user_id: "anonymous-user" + row: this.row, + column: this.column, + doc_id: this.doc_id, + id: this.anonymous.publicId, + user_id: "anonymous-user", name: "" } - ] + ]); + }); +}); +}); diff --git a/services/real-time/test/acceptance/coffee/DrainManagerTests.js b/services/real-time/test/acceptance/coffee/DrainManagerTests.js index ca967408d8..91bf8836ec 100644 --- a/services/real-time/test/acceptance/coffee/DrainManagerTests.js +++ b/services/real-time/test/acceptance/coffee/DrainManagerTests.js @@ -1,81 +1,100 @@ -RealTimeClient = require "./helpers/RealTimeClient" -FixturesManager = require "./helpers/FixturesManager" +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const RealTimeClient = require("./helpers/RealTimeClient"); +const FixturesManager = require("./helpers/FixturesManager"); -expect = require("chai").expect +const { + expect +} = require("chai"); -async = require "async" -request = require "request" +const async = require("async"); +const request = require("request"); -Settings = require "settings-sharelatex" +const Settings = require("settings-sharelatex"); -drain = (rate, callback) -> - request.post { - url: "http://localhost:3026/drain?rate=#{rate}" +const drain = function(rate, callback) { + request.post({ + url: `http://localhost:3026/drain?rate=${rate}`, auth: { user: Settings.internal.realTime.user, pass: Settings.internal.realTime.pass } - }, (error, response, data) -> - callback error, data - return null + }, (error, response, data) => callback(error, data)); + return null; +}; -describe "DrainManagerTests", -> - before (done) -> - FixturesManager.setUpProject { - privilegeLevel: "owner" +describe("DrainManagerTests", function() { + before(function(done) { + FixturesManager.setUpProject({ + privilegeLevel: "owner", project: { name: "Test Project" } - }, (e, {@project_id, @user_id}) => done() - return null + }, (e, {project_id, user_id}) => { this.project_id = project_id; this.user_id = user_id; return done(); }); + return null; + }); - before (done) -> - # cleanup to speedup reconnecting - @timeout(10000) - RealTimeClient.disconnectAllClients done + before(function(done) { + // cleanup to speedup reconnecting + this.timeout(10000); + return RealTimeClient.disconnectAllClients(done); + }); - # trigger and check cleanup - it "should have disconnected all previous clients", (done) -> - RealTimeClient.getConnectedClients (error, data) -> - return done(error) if error - expect(data.length).to.equal(0) - done() + // trigger and check cleanup + it("should have disconnected all previous clients", done => RealTimeClient.getConnectedClients(function(error, data) { + if (error) { return done(error); } + expect(data.length).to.equal(0); + return done(); + })); - describe "with two clients in the project", -> - beforeEach (done) -> - async.series [ - (cb) => - @clientA = RealTimeClient.connect() - @clientA.on "connectionAccepted", cb + return describe("with two clients in the project", function() { + beforeEach(function(done) { + return async.series([ + cb => { + this.clientA = RealTimeClient.connect(); + return this.clientA.on("connectionAccepted", cb); + }, - (cb) => - @clientB = RealTimeClient.connect() - @clientB.on "connectionAccepted", cb + cb => { + this.clientB = RealTimeClient.connect(); + return this.clientB.on("connectionAccepted", cb); + }, - (cb) => - @clientA.emit "joinProject", project_id: @project_id, cb + cb => { + return this.clientA.emit("joinProject", {project_id: this.project_id}, cb); + }, - (cb) => - @clientB.emit "joinProject", project_id: @project_id, cb - ], done + cb => { + return this.clientB.emit("joinProject", {project_id: this.project_id}, cb); + } + ], done); + }); - describe "starting to drain", () -> - beforeEach (done) -> - async.parallel [ - (cb) => - @clientA.on "reconnectGracefully", cb - (cb) => - @clientB.on "reconnectGracefully", cb + return describe("starting to drain", function() { + beforeEach(function(done) { + return async.parallel([ + cb => { + return this.clientA.on("reconnectGracefully", cb); + }, + cb => { + return this.clientB.on("reconnectGracefully", cb); + }, - (cb) -> drain(2, cb) - ], done + cb => drain(2, cb) + ], done); + }); - afterEach (done) -> - drain(0, done) # reset drain + afterEach(done => drain(0, done)); // reset drain - it "should not timeout", -> - expect(true).to.equal(true) + it("should not timeout", () => expect(true).to.equal(true)); - it "should not have disconnected", -> - expect(@clientA.socket.connected).to.equal true - expect(@clientB.socket.connected).to.equal true + return it("should not have disconnected", function() { + expect(this.clientA.socket.connected).to.equal(true); + return expect(this.clientB.socket.connected).to.equal(true); + }); + }); + }); +}); diff --git a/services/real-time/test/acceptance/coffee/EarlyDisconnect.js b/services/real-time/test/acceptance/coffee/EarlyDisconnect.js index d90c36b430..875f33ee33 100644 --- a/services/real-time/test/acceptance/coffee/EarlyDisconnect.js +++ b/services/real-time/test/acceptance/coffee/EarlyDisconnect.js @@ -1,160 +1,209 @@ -async = require "async" -{expect} = require("chai") +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const async = require("async"); +const {expect} = require("chai"); -RealTimeClient = require "./helpers/RealTimeClient" -MockDocUpdaterServer = require "./helpers/MockDocUpdaterServer" -MockWebServer = require "./helpers/MockWebServer" -FixturesManager = require "./helpers/FixturesManager" +const RealTimeClient = require("./helpers/RealTimeClient"); +const MockDocUpdaterServer = require("./helpers/MockDocUpdaterServer"); +const MockWebServer = require("./helpers/MockWebServer"); +const FixturesManager = require("./helpers/FixturesManager"); -settings = require "settings-sharelatex" -redis = require "redis-sharelatex" -rclient = redis.createClient(settings.redis.pubsub) -rclientRT = redis.createClient(settings.redis.realtime) -KeysRT = settings.redis.realtime.key_schema +const settings = require("settings-sharelatex"); +const redis = require("redis-sharelatex"); +const rclient = redis.createClient(settings.redis.pubsub); +const rclientRT = redis.createClient(settings.redis.realtime); +const KeysRT = settings.redis.realtime.key_schema; -describe "EarlyDisconnect", -> - before (done) -> - MockDocUpdaterServer.run done +describe("EarlyDisconnect", function() { + before(done => MockDocUpdaterServer.run(done)); - describe "when the client disconnects before joinProject completes", -> - before () -> - # slow down web-api requests to force the race condition - @actualWebAPIjoinProject = joinProject = MockWebServer.joinProject - MockWebServer.joinProject = (project_id, user_id, cb) -> - setTimeout () -> - joinProject(project_id, user_id, cb) - , 300 + describe("when the client disconnects before joinProject completes", function() { + before(function() { + // slow down web-api requests to force the race condition + let joinProject; + this.actualWebAPIjoinProject = (joinProject = MockWebServer.joinProject); + return MockWebServer.joinProject = (project_id, user_id, cb) => setTimeout(() => joinProject(project_id, user_id, cb) + , 300); + }); - after () -> - MockWebServer.joinProject = @actualWebAPIjoinProject + after(function() { + return MockWebServer.joinProject = this.actualWebAPIjoinProject; + }); - beforeEach (done) -> - async.series [ - (cb) => - FixturesManager.setUpProject { - privilegeLevel: "owner" + beforeEach(function(done) { + return async.series([ + cb => { + return FixturesManager.setUpProject({ + privilegeLevel: "owner", project: { name: "Test Project" } - }, (e, {@project_id, @user_id}) => cb() + }, (e, {project_id, user_id}) => { this.project_id = project_id; this.user_id = user_id; return cb(); }); + }, - (cb) => - @clientA = RealTimeClient.connect() - @clientA.on "connectionAccepted", cb + cb => { + this.clientA = RealTimeClient.connect(); + return this.clientA.on("connectionAccepted", cb); + }, - (cb) => - @clientA.emit "joinProject", project_id: @project_id, (() ->) - # disconnect before joinProject completes - @clientA.on "disconnect", () -> cb() - @clientA.disconnect() + cb => { + this.clientA.emit("joinProject", {project_id: this.project_id}, (function() {})); + // disconnect before joinProject completes + this.clientA.on("disconnect", () => cb()); + return this.clientA.disconnect(); + }, - (cb) => - # wait for joinDoc and subscribe - setTimeout cb, 500 - ], done + cb => { + // wait for joinDoc and subscribe + return setTimeout(cb, 500); + } + ], done); + }); - # we can force the race condition, there is no need to repeat too often - for attempt in Array.from(length: 5).map((_, i) -> i+1) - it "should not subscribe to the pub/sub channel anymore (race #{attempt})", (done) -> - rclient.pubsub 'CHANNELS', (err, resp) => - return done(err) if err - expect(resp).to.not.include "editor-events:#{@project_id}" - done() - return null + // we can force the race condition, there is no need to repeat too often + return Array.from(Array.from({length: 5}).map((_, i) => i+1)).map((attempt) => + it(`should not subscribe to the pub/sub channel anymore (race ${attempt})`, function(done) { + rclient.pubsub('CHANNELS', (err, resp) => { + if (err) { return done(err); } + expect(resp).to.not.include(`editor-events:${this.project_id}`); + return done(); + }); + return null; + })); + }); - describe "when the client disconnects before joinDoc completes", -> - beforeEach (done) -> - async.series [ - (cb) => - FixturesManager.setUpProject { - privilegeLevel: "owner" + describe("when the client disconnects before joinDoc completes", function() { + beforeEach(function(done) { + return async.series([ + cb => { + return FixturesManager.setUpProject({ + privilegeLevel: "owner", project: { name: "Test Project" } - }, (e, {@project_id, @user_id}) => cb() + }, (e, {project_id, user_id}) => { this.project_id = project_id; this.user_id = user_id; return cb(); }); + }, - (cb) => - @clientA = RealTimeClient.connect() - @clientA.on "connectionAccepted", cb + cb => { + this.clientA = RealTimeClient.connect(); + return this.clientA.on("connectionAccepted", cb); + }, - (cb) => - @clientA.emit "joinProject", project_id: @project_id, (error, @project, @privilegeLevel, @protocolVersion) => - cb(error) + cb => { + return this.clientA.emit("joinProject", {project_id: this.project_id}, (error, project, privilegeLevel, protocolVersion) => { + this.project = project; + this.privilegeLevel = privilegeLevel; + this.protocolVersion = protocolVersion; + return cb(error); + }); + }, - (cb) => - FixturesManager.setUpDoc @project_id, {@lines, @version, @ops}, (e, {@doc_id}) => - cb(e) + cb => { + return FixturesManager.setUpDoc(this.project_id, {lines: this.lines, version: this.version, ops: this.ops}, (e, {doc_id}) => { + this.doc_id = doc_id; + return cb(e); + }); + }, - (cb) => - @clientA.emit "joinDoc", @doc_id, (() ->) - # disconnect before joinDoc completes - @clientA.on "disconnect", () -> cb() - @clientA.disconnect() + cb => { + this.clientA.emit("joinDoc", this.doc_id, (function() {})); + // disconnect before joinDoc completes + this.clientA.on("disconnect", () => cb()); + return this.clientA.disconnect(); + }, - (cb) => - # wait for subscribe and unsubscribe - setTimeout cb, 100 - ], done + cb => { + // wait for subscribe and unsubscribe + return setTimeout(cb, 100); + } + ], done); + }); - # we can not force the race condition, so we have to try many times - for attempt in Array.from(length: 20).map((_, i) -> i+1) - it "should not subscribe to the pub/sub channels anymore (race #{attempt})", (done) -> - rclient.pubsub 'CHANNELS', (err, resp) => - return done(err) if err - expect(resp).to.not.include "editor-events:#{@project_id}" + // we can not force the race condition, so we have to try many times + return Array.from(Array.from({length: 20}).map((_, i) => i+1)).map((attempt) => + it(`should not subscribe to the pub/sub channels anymore (race ${attempt})`, function(done) { + rclient.pubsub('CHANNELS', (err, resp) => { + if (err) { return done(err); } + expect(resp).to.not.include(`editor-events:${this.project_id}`); - rclient.pubsub 'CHANNELS', (err, resp) => - return done(err) if err - expect(resp).to.not.include "applied-ops:#{@doc_id}" - done() - return null + return rclient.pubsub('CHANNELS', (err, resp) => { + if (err) { return done(err); } + expect(resp).to.not.include(`applied-ops:${this.doc_id}`); + return done(); + }); + }); + return null; + })); + }); - describe "when the client disconnects before clientTracking.updatePosition starts", -> - beforeEach (done) -> - async.series [ - (cb) => - FixturesManager.setUpProject { - privilegeLevel: "owner" + return describe("when the client disconnects before clientTracking.updatePosition starts", function() { + beforeEach(function(done) { + return async.series([ + cb => { + return FixturesManager.setUpProject({ + privilegeLevel: "owner", project: { name: "Test Project" } - }, (e, {@project_id, @user_id}) => cb() + }, (e, {project_id, user_id}) => { this.project_id = project_id; this.user_id = user_id; return cb(); }); + }, - (cb) => - @clientA = RealTimeClient.connect() - @clientA.on "connectionAccepted", cb + cb => { + this.clientA = RealTimeClient.connect(); + return this.clientA.on("connectionAccepted", cb); + }, - (cb) => - @clientA.emit "joinProject", project_id: @project_id, (error, @project, @privilegeLevel, @protocolVersion) => - cb(error) + cb => { + return this.clientA.emit("joinProject", {project_id: this.project_id}, (error, project, privilegeLevel, protocolVersion) => { + this.project = project; + this.privilegeLevel = privilegeLevel; + this.protocolVersion = protocolVersion; + return cb(error); + }); + }, - (cb) => - FixturesManager.setUpDoc @project_id, {@lines, @version, @ops}, (e, {@doc_id}) => - cb(e) + cb => { + return FixturesManager.setUpDoc(this.project_id, {lines: this.lines, version: this.version, ops: this.ops}, (e, {doc_id}) => { + this.doc_id = doc_id; + return cb(e); + }); + }, - (cb) => - @clientA.emit "joinDoc", @doc_id, cb + cb => { + return this.clientA.emit("joinDoc", this.doc_id, cb); + }, - (cb) => - @clientA.emit "clientTracking.updatePosition", { - row: 42 - column: 36 - doc_id: @doc_id - }, (() ->) - # disconnect before updateClientPosition completes - @clientA.on "disconnect", () -> cb() - @clientA.disconnect() + cb => { + this.clientA.emit("clientTracking.updatePosition", { + row: 42, + column: 36, + doc_id: this.doc_id + }, (function() {})); + // disconnect before updateClientPosition completes + this.clientA.on("disconnect", () => cb()); + return this.clientA.disconnect(); + }, - (cb) => - # wait for updateClientPosition - setTimeout cb, 100 - ], done + cb => { + // wait for updateClientPosition + return setTimeout(cb, 100); + } + ], done); + }); - # we can not force the race condition, so we have to try many times - for attempt in Array.from(length: 20).map((_, i) -> i+1) - it "should not show the client as connected (race #{attempt})", (done) -> - rclientRT.smembers KeysRT.clientsInProject({project_id: @project_id}), (err, results) -> - return done(err) if err - expect(results).to.deep.equal([]) - done() - return null + // we can not force the race condition, so we have to try many times + return Array.from(Array.from({length: 20}).map((_, i) => i+1)).map((attempt) => + it(`should not show the client as connected (race ${attempt})`, function(done) { + rclientRT.smembers(KeysRT.clientsInProject({project_id: this.project_id}), function(err, results) { + if (err) { return done(err); } + expect(results).to.deep.equal([]); + return done(); + }); + return null; + })); + }); +}); diff --git a/services/real-time/test/acceptance/coffee/HttpControllerTests.js b/services/real-time/test/acceptance/coffee/HttpControllerTests.js index 524ea7e5de..701b1f7d23 100644 --- a/services/real-time/test/acceptance/coffee/HttpControllerTests.js +++ b/services/real-time/test/acceptance/coffee/HttpControllerTests.js @@ -1,68 +1,91 @@ -async = require('async') -expect = require('chai').expect -request = require('request').defaults({ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const async = require('async'); +const { + expect +} = require('chai'); +const request = require('request').defaults({ baseUrl: 'http://localhost:3026' -}) +}); -RealTimeClient = require "./helpers/RealTimeClient" -FixturesManager = require "./helpers/FixturesManager" +const RealTimeClient = require("./helpers/RealTimeClient"); +const FixturesManager = require("./helpers/FixturesManager"); -describe 'HttpControllerTests', -> - describe 'without a user', -> - it 'should return 404 for the client view', (done) -> - client_id = 'not-existing' - request.get { - url: "/clients/#{client_id}" - json: true - }, (error, response, data) -> - return done(error) if error - expect(response.statusCode).to.equal(404) - done() +describe('HttpControllerTests', function() { + describe('without a user', () => it('should return 404 for the client view', function(done) { + const client_id = 'not-existing'; + return request.get({ + url: `/clients/${client_id}`, + json: true + }, function(error, response, data) { + if (error) { return done(error); } + expect(response.statusCode).to.equal(404); + return done(); + }); + })); - describe 'with a user and after joining a project', -> - before (done) -> - async.series [ - (cb) => - FixturesManager.setUpProject { + return describe('with a user and after joining a project', function() { + before(function(done) { + return async.series([ + cb => { + return FixturesManager.setUpProject({ privilegeLevel: "owner" - }, (error, {@project_id, @user_id}) => - cb(error) + }, (error, {project_id, user_id}) => { + this.project_id = project_id; + this.user_id = user_id; + return cb(error); + }); + }, - (cb) => - FixturesManager.setUpDoc @project_id, {}, (error, {@doc_id}) => - cb(error) + cb => { + return FixturesManager.setUpDoc(this.project_id, {}, (error, {doc_id}) => { + this.doc_id = doc_id; + return cb(error); + }); + }, - (cb) => - @client = RealTimeClient.connect() - @client.on "connectionAccepted", cb + cb => { + this.client = RealTimeClient.connect(); + return this.client.on("connectionAccepted", cb); + }, - (cb) => - @client.emit "joinProject", {@project_id}, cb + cb => { + return this.client.emit("joinProject", {project_id: this.project_id}, cb); + }, - (cb) => - @client.emit "joinDoc", @doc_id, cb - ], done + cb => { + return this.client.emit("joinDoc", this.doc_id, cb); + } + ], done); + }); - it 'should send a client view', (done) -> - request.get { - url: "/clients/#{@client.socket.sessionid}" + return it('should send a client view', function(done) { + return request.get({ + url: `/clients/${this.client.socket.sessionid}`, json: true - }, (error, response, data) => - return done(error) if error - expect(response.statusCode).to.equal(200) - expect(data.connected_time).to.exist - delete data.connected_time - # .email is not set in the session - delete data.email + }, (error, response, data) => { + if (error) { return done(error); } + expect(response.statusCode).to.equal(200); + expect(data.connected_time).to.exist; + delete data.connected_time; + // .email is not set in the session + delete data.email; expect(data).to.deep.equal({ - client_id: @client.socket.sessionid, + client_id: this.client.socket.sessionid, first_name: 'Joe', last_name: 'Bloggs', - project_id: @project_id, - user_id: @user_id, + project_id: this.project_id, + user_id: this.user_id, rooms: [ - @project_id, - @doc_id, + this.project_id, + this.doc_id, ] - }) - done() + }); + return done(); + }); + }); + }); +}); diff --git a/services/real-time/test/acceptance/coffee/JoinDocTests.js b/services/real-time/test/acceptance/coffee/JoinDocTests.js index 6c204b6079..0026a6e858 100644 --- a/services/real-time/test/acceptance/coffee/JoinDocTests.js +++ b/services/real-time/test/acceptance/coffee/JoinDocTests.js @@ -1,246 +1,351 @@ -chai = require("chai") -expect = chai.expect -chai.should() +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const chai = require("chai"); +const { + expect +} = chai; +chai.should(); -RealTimeClient = require "./helpers/RealTimeClient" -MockDocUpdaterServer = require "./helpers/MockDocUpdaterServer" -FixturesManager = require "./helpers/FixturesManager" +const RealTimeClient = require("./helpers/RealTimeClient"); +const MockDocUpdaterServer = require("./helpers/MockDocUpdaterServer"); +const FixturesManager = require("./helpers/FixturesManager"); -async = require "async" +const async = require("async"); -describe "joinDoc", -> - before -> - @lines = ["test", "doc", "lines"] - @version = 42 - @ops = ["mock", "doc", "ops"] - @ranges = {"mock": "ranges"} +describe("joinDoc", function() { + before(function() { + this.lines = ["test", "doc", "lines"]; + this.version = 42; + this.ops = ["mock", "doc", "ops"]; + return this.ranges = {"mock": "ranges"};}); - describe "when authorised readAndWrite", -> - before (done) -> - async.series [ - (cb) => - FixturesManager.setUpProject { + describe("when authorised readAndWrite", function() { + before(function(done) { + return async.series([ + cb => { + return FixturesManager.setUpProject({ privilegeLevel: "readAndWrite" - }, (e, {@project_id, @user_id}) => - cb(e) + }, (e, {project_id, user_id}) => { + this.project_id = project_id; + this.user_id = user_id; + return cb(e); + }); + }, - (cb) => - FixturesManager.setUpDoc @project_id, {@lines, @version, @ops, @ranges}, (e, {@doc_id}) => - cb(e) + cb => { + return FixturesManager.setUpDoc(this.project_id, {lines: this.lines, version: this.version, ops: this.ops, ranges: this.ranges}, (e, {doc_id}) => { + this.doc_id = doc_id; + return cb(e); + }); + }, - (cb) => - @client = RealTimeClient.connect() - @client.on "connectionAccepted", cb + cb => { + this.client = RealTimeClient.connect(); + return this.client.on("connectionAccepted", cb); + }, - (cb) => - @client.emit "joinProject", project_id: @project_id, cb + cb => { + return this.client.emit("joinProject", {project_id: this.project_id}, cb); + }, - (cb) => - @client.emit "joinDoc", @doc_id, (error, @returnedArgs...) => cb(error) - ], done + cb => { + return this.client.emit("joinDoc", this.doc_id, (error, ...rest) => { [...this.returnedArgs] = Array.from(rest); return cb(error); }); + } + ], done); + }); - it "should get the doc from the doc updater", -> - MockDocUpdaterServer.getDocument - .calledWith(@project_id, @doc_id, -1) - .should.equal true + it("should get the doc from the doc updater", function() { + return MockDocUpdaterServer.getDocument + .calledWith(this.project_id, this.doc_id, -1) + .should.equal(true); + }); - it "should return the doc lines, version, ranges and ops", -> - @returnedArgs.should.deep.equal [@lines, @version, @ops, @ranges] + it("should return the doc lines, version, ranges and ops", function() { + return this.returnedArgs.should.deep.equal([this.lines, this.version, this.ops, this.ranges]); + }); - it "should have joined the doc room", (done) -> - RealTimeClient.getConnectedClient @client.socket.sessionid, (error, client) => - expect(@doc_id in client.rooms).to.equal true - done() + return it("should have joined the doc room", function(done) { + return RealTimeClient.getConnectedClient(this.client.socket.sessionid, (error, client) => { + expect(Array.from(client.rooms).includes(this.doc_id)).to.equal(true); + return done(); + }); + }); + }); - describe "when authorised readOnly", -> - before (done) -> - async.series [ - (cb) => - FixturesManager.setUpProject { + describe("when authorised readOnly", function() { + before(function(done) { + return async.series([ + cb => { + return FixturesManager.setUpProject({ privilegeLevel: "readOnly" - }, (e, {@project_id, @user_id}) => - cb(e) + }, (e, {project_id, user_id}) => { + this.project_id = project_id; + this.user_id = user_id; + return cb(e); + }); + }, - (cb) => - FixturesManager.setUpDoc @project_id, {@lines, @version, @ops, @ranges}, (e, {@doc_id}) => - cb(e) + cb => { + return FixturesManager.setUpDoc(this.project_id, {lines: this.lines, version: this.version, ops: this.ops, ranges: this.ranges}, (e, {doc_id}) => { + this.doc_id = doc_id; + return cb(e); + }); + }, - (cb) => - @client = RealTimeClient.connect() - @client.on "connectionAccepted", cb + cb => { + this.client = RealTimeClient.connect(); + return this.client.on("connectionAccepted", cb); + }, - (cb) => - @client.emit "joinProject", project_id: @project_id, cb + cb => { + return this.client.emit("joinProject", {project_id: this.project_id}, cb); + }, - (cb) => - @client.emit "joinDoc", @doc_id, (error, @returnedArgs...) => cb(error) - ], done + cb => { + return this.client.emit("joinDoc", this.doc_id, (error, ...rest) => { [...this.returnedArgs] = Array.from(rest); return cb(error); }); + } + ], done); + }); - it "should get the doc from the doc updater", -> - MockDocUpdaterServer.getDocument - .calledWith(@project_id, @doc_id, -1) - .should.equal true + it("should get the doc from the doc updater", function() { + return MockDocUpdaterServer.getDocument + .calledWith(this.project_id, this.doc_id, -1) + .should.equal(true); + }); - it "should return the doc lines, version, ranges and ops", -> - @returnedArgs.should.deep.equal [@lines, @version, @ops, @ranges] + it("should return the doc lines, version, ranges and ops", function() { + return this.returnedArgs.should.deep.equal([this.lines, this.version, this.ops, this.ranges]); + }); - it "should have joined the doc room", (done) -> - RealTimeClient.getConnectedClient @client.socket.sessionid, (error, client) => - expect(@doc_id in client.rooms).to.equal true - done() + return it("should have joined the doc room", function(done) { + return RealTimeClient.getConnectedClient(this.client.socket.sessionid, (error, client) => { + expect(Array.from(client.rooms).includes(this.doc_id)).to.equal(true); + return done(); + }); + }); + }); - describe "when authorised as owner", -> - before (done) -> - async.series [ - (cb) => - FixturesManager.setUpProject { + describe("when authorised as owner", function() { + before(function(done) { + return async.series([ + cb => { + return FixturesManager.setUpProject({ privilegeLevel: "owner" - }, (e, {@project_id, @user_id}) => - cb(e) + }, (e, {project_id, user_id}) => { + this.project_id = project_id; + this.user_id = user_id; + return cb(e); + }); + }, - (cb) => - FixturesManager.setUpDoc @project_id, {@lines, @version, @ops, @ranges}, (e, {@doc_id}) => - cb(e) + cb => { + return FixturesManager.setUpDoc(this.project_id, {lines: this.lines, version: this.version, ops: this.ops, ranges: this.ranges}, (e, {doc_id}) => { + this.doc_id = doc_id; + return cb(e); + }); + }, - (cb) => - @client = RealTimeClient.connect() - @client.on "connectionAccepted", cb + cb => { + this.client = RealTimeClient.connect(); + return this.client.on("connectionAccepted", cb); + }, - (cb) => - @client.emit "joinProject", project_id: @project_id, cb + cb => { + return this.client.emit("joinProject", {project_id: this.project_id}, cb); + }, - (cb) => - @client.emit "joinDoc", @doc_id, (error, @returnedArgs...) => cb(error) - ], done + cb => { + return this.client.emit("joinDoc", this.doc_id, (error, ...rest) => { [...this.returnedArgs] = Array.from(rest); return cb(error); }); + } + ], done); + }); - it "should get the doc from the doc updater", -> - MockDocUpdaterServer.getDocument - .calledWith(@project_id, @doc_id, -1) - .should.equal true + it("should get the doc from the doc updater", function() { + return MockDocUpdaterServer.getDocument + .calledWith(this.project_id, this.doc_id, -1) + .should.equal(true); + }); - it "should return the doc lines, version, ranges and ops", -> - @returnedArgs.should.deep.equal [@lines, @version, @ops, @ranges] + it("should return the doc lines, version, ranges and ops", function() { + return this.returnedArgs.should.deep.equal([this.lines, this.version, this.ops, this.ranges]); + }); - it "should have joined the doc room", (done) -> - RealTimeClient.getConnectedClient @client.socket.sessionid, (error, client) => - expect(@doc_id in client.rooms).to.equal true - done() + return it("should have joined the doc room", function(done) { + return RealTimeClient.getConnectedClient(this.client.socket.sessionid, (error, client) => { + expect(Array.from(client.rooms).includes(this.doc_id)).to.equal(true); + return done(); + }); + }); + }); - # It is impossible to write an acceptance test to test joining an unauthorized - # project, since joinProject already catches that. If you can join a project, - # then you can join a doc in that project. + // It is impossible to write an acceptance test to test joining an unauthorized + // project, since joinProject already catches that. If you can join a project, + // then you can join a doc in that project. - describe "with a fromVersion", -> - before (done) -> - @fromVersion = 36 - async.series [ - (cb) => - FixturesManager.setUpProject { + describe("with a fromVersion", function() { + before(function(done) { + this.fromVersion = 36; + return async.series([ + cb => { + return FixturesManager.setUpProject({ privilegeLevel: "readAndWrite" - }, (e, {@project_id, @user_id}) => - cb(e) + }, (e, {project_id, user_id}) => { + this.project_id = project_id; + this.user_id = user_id; + return cb(e); + }); + }, - (cb) => - FixturesManager.setUpDoc @project_id, {@lines, @version, @ops, @ranges}, (e, {@doc_id}) => - cb(e) + cb => { + return FixturesManager.setUpDoc(this.project_id, {lines: this.lines, version: this.version, ops: this.ops, ranges: this.ranges}, (e, {doc_id}) => { + this.doc_id = doc_id; + return cb(e); + }); + }, - (cb) => - @client = RealTimeClient.connect() - @client.on "connectionAccepted", cb + cb => { + this.client = RealTimeClient.connect(); + return this.client.on("connectionAccepted", cb); + }, - (cb) => - @client.emit "joinProject", project_id: @project_id, cb + cb => { + return this.client.emit("joinProject", {project_id: this.project_id}, cb); + }, - (cb) => - @client.emit "joinDoc", @doc_id, @fromVersion, (error, @returnedArgs...) => cb(error) - ], done + cb => { + return this.client.emit("joinDoc", this.doc_id, this.fromVersion, (error, ...rest) => { [...this.returnedArgs] = Array.from(rest); return cb(error); }); + } + ], done); + }); - it "should get the doc from the doc updater with the fromVersion", -> - MockDocUpdaterServer.getDocument - .calledWith(@project_id, @doc_id, @fromVersion) - .should.equal true + it("should get the doc from the doc updater with the fromVersion", function() { + return MockDocUpdaterServer.getDocument + .calledWith(this.project_id, this.doc_id, this.fromVersion) + .should.equal(true); + }); - it "should return the doc lines, version, ranges and ops", -> - @returnedArgs.should.deep.equal [@lines, @version, @ops, @ranges] + it("should return the doc lines, version, ranges and ops", function() { + return this.returnedArgs.should.deep.equal([this.lines, this.version, this.ops, this.ranges]); + }); - it "should have joined the doc room", (done) -> - RealTimeClient.getConnectedClient @client.socket.sessionid, (error, client) => - expect(@doc_id in client.rooms).to.equal true - done() + return it("should have joined the doc room", function(done) { + return RealTimeClient.getConnectedClient(this.client.socket.sessionid, (error, client) => { + expect(Array.from(client.rooms).includes(this.doc_id)).to.equal(true); + return done(); + }); + }); + }); - describe "with options", -> - before (done) -> - @options = { encodeRanges: true } - async.series [ - (cb) => - FixturesManager.setUpProject { + describe("with options", function() { + before(function(done) { + this.options = { encodeRanges: true }; + return async.series([ + cb => { + return FixturesManager.setUpProject({ privilegeLevel: "readAndWrite" - }, (e, {@project_id, @user_id}) => - cb(e) + }, (e, {project_id, user_id}) => { + this.project_id = project_id; + this.user_id = user_id; + return cb(e); + }); + }, - (cb) => - FixturesManager.setUpDoc @project_id, {@lines, @version, @ops, @ranges}, (e, {@doc_id}) => - cb(e) + cb => { + return FixturesManager.setUpDoc(this.project_id, {lines: this.lines, version: this.version, ops: this.ops, ranges: this.ranges}, (e, {doc_id}) => { + this.doc_id = doc_id; + return cb(e); + }); + }, - (cb) => - @client = RealTimeClient.connect() - @client.on "connectionAccepted", cb + cb => { + this.client = RealTimeClient.connect(); + return this.client.on("connectionAccepted", cb); + }, - (cb) => - @client.emit "joinProject", project_id: @project_id, cb + cb => { + return this.client.emit("joinProject", {project_id: this.project_id}, cb); + }, - (cb) => - @client.emit "joinDoc", @doc_id, @options, (error, @returnedArgs...) => cb(error) - ], done + cb => { + return this.client.emit("joinDoc", this.doc_id, this.options, (error, ...rest) => { [...this.returnedArgs] = Array.from(rest); return cb(error); }); + } + ], done); + }); - it "should get the doc from the doc updater with the default fromVersion", -> - MockDocUpdaterServer.getDocument - .calledWith(@project_id, @doc_id, -1) - .should.equal true + it("should get the doc from the doc updater with the default fromVersion", function() { + return MockDocUpdaterServer.getDocument + .calledWith(this.project_id, this.doc_id, -1) + .should.equal(true); + }); - it "should return the doc lines, version, ranges and ops", -> - @returnedArgs.should.deep.equal [@lines, @version, @ops, @ranges] + it("should return the doc lines, version, ranges and ops", function() { + return this.returnedArgs.should.deep.equal([this.lines, this.version, this.ops, this.ranges]); + }); - it "should have joined the doc room", (done) -> - RealTimeClient.getConnectedClient @client.socket.sessionid, (error, client) => - expect(@doc_id in client.rooms).to.equal true - done() + return it("should have joined the doc room", function(done) { + return RealTimeClient.getConnectedClient(this.client.socket.sessionid, (error, client) => { + expect(Array.from(client.rooms).includes(this.doc_id)).to.equal(true); + return done(); + }); + }); + }); - describe "with fromVersion and options", -> - before (done) -> - @fromVersion = 36 - @options = { encodeRanges: true } - async.series [ - (cb) => - FixturesManager.setUpProject { + return describe("with fromVersion and options", function() { + before(function(done) { + this.fromVersion = 36; + this.options = { encodeRanges: true }; + return async.series([ + cb => { + return FixturesManager.setUpProject({ privilegeLevel: "readAndWrite" - }, (e, {@project_id, @user_id}) => - cb(e) + }, (e, {project_id, user_id}) => { + this.project_id = project_id; + this.user_id = user_id; + return cb(e); + }); + }, - (cb) => - FixturesManager.setUpDoc @project_id, {@lines, @version, @ops, @ranges}, (e, {@doc_id}) => - cb(e) + cb => { + return FixturesManager.setUpDoc(this.project_id, {lines: this.lines, version: this.version, ops: this.ops, ranges: this.ranges}, (e, {doc_id}) => { + this.doc_id = doc_id; + return cb(e); + }); + }, - (cb) => - @client = RealTimeClient.connect() - @client.on "connectionAccepted", cb + cb => { + this.client = RealTimeClient.connect(); + return this.client.on("connectionAccepted", cb); + }, - (cb) => - @client.emit "joinProject", project_id: @project_id, cb + cb => { + return this.client.emit("joinProject", {project_id: this.project_id}, cb); + }, - (cb) => - @client.emit "joinDoc", @doc_id, @fromVersion, @options, (error, @returnedArgs...) => cb(error) - ], done + cb => { + return this.client.emit("joinDoc", this.doc_id, this.fromVersion, this.options, (error, ...rest) => { [...this.returnedArgs] = Array.from(rest); return cb(error); }); + } + ], done); + }); - it "should get the doc from the doc updater with the fromVersion", -> - MockDocUpdaterServer.getDocument - .calledWith(@project_id, @doc_id, @fromVersion) - .should.equal true + it("should get the doc from the doc updater with the fromVersion", function() { + return MockDocUpdaterServer.getDocument + .calledWith(this.project_id, this.doc_id, this.fromVersion) + .should.equal(true); + }); - it "should return the doc lines, version, ranges and ops", -> - @returnedArgs.should.deep.equal [@lines, @version, @ops, @ranges] + it("should return the doc lines, version, ranges and ops", function() { + return this.returnedArgs.should.deep.equal([this.lines, this.version, this.ops, this.ranges]); + }); - it "should have joined the doc room", (done) -> - RealTimeClient.getConnectedClient @client.socket.sessionid, (error, client) => - expect(@doc_id in client.rooms).to.equal true - done() + return it("should have joined the doc room", function(done) { + return RealTimeClient.getConnectedClient(this.client.socket.sessionid, (error, client) => { + expect(Array.from(client.rooms).includes(this.doc_id)).to.equal(true); + return done(); + }); + }); + }); +}); diff --git a/services/real-time/test/acceptance/coffee/JoinProjectTests.js b/services/real-time/test/acceptance/coffee/JoinProjectTests.js index 11082cdb6c..3f962e2c12 100644 --- a/services/real-time/test/acceptance/coffee/JoinProjectTests.js +++ b/services/real-time/test/acceptance/coffee/JoinProjectTests.js @@ -1,108 +1,162 @@ -chai = require("chai") -expect = chai.expect -chai.should() +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const chai = require("chai"); +const { + expect +} = chai; +chai.should(); -RealTimeClient = require "./helpers/RealTimeClient" -MockWebServer = require "./helpers/MockWebServer" -FixturesManager = require "./helpers/FixturesManager" +const RealTimeClient = require("./helpers/RealTimeClient"); +const MockWebServer = require("./helpers/MockWebServer"); +const FixturesManager = require("./helpers/FixturesManager"); -async = require "async" +const async = require("async"); -describe "joinProject", -> - describe "when authorized", -> - before (done) -> - async.series [ - (cb) => - FixturesManager.setUpProject { - privilegeLevel: "owner" +describe("joinProject", function() { + describe("when authorized", function() { + before(function(done) { + return async.series([ + cb => { + return FixturesManager.setUpProject({ + privilegeLevel: "owner", project: { name: "Test Project" } - }, (e, {@project_id, @user_id}) => - cb(e) + }, (e, {project_id, user_id}) => { + this.project_id = project_id; + this.user_id = user_id; + return cb(e); + }); + }, - (cb) => - @client = RealTimeClient.connect() - @client.on "connectionAccepted", cb + cb => { + this.client = RealTimeClient.connect(); + return this.client.on("connectionAccepted", cb); + }, - (cb) => - @client.emit "joinProject", project_id: @project_id, (error, @project, @privilegeLevel, @protocolVersion) => - cb(error) - ], done + cb => { + return this.client.emit("joinProject", {project_id: this.project_id}, (error, project, privilegeLevel, protocolVersion) => { + this.project = project; + this.privilegeLevel = privilegeLevel; + this.protocolVersion = protocolVersion; + return cb(error); + }); + } + ], done); + }); - it "should get the project from web", -> - MockWebServer.joinProject - .calledWith(@project_id, @user_id) - .should.equal true + it("should get the project from web", function() { + return MockWebServer.joinProject + .calledWith(this.project_id, this.user_id) + .should.equal(true); + }); - it "should return the project", -> - @project.should.deep.equal { + it("should return the project", function() { + return this.project.should.deep.equal({ name: "Test Project" - } + }); + }); - it "should return the privilege level", -> - @privilegeLevel.should.equal "owner" + it("should return the privilege level", function() { + return this.privilegeLevel.should.equal("owner"); + }); - it "should return the protocolVersion", -> - @protocolVersion.should.equal 2 + it("should return the protocolVersion", function() { + return this.protocolVersion.should.equal(2); + }); - it "should have joined the project room", (done) -> - RealTimeClient.getConnectedClient @client.socket.sessionid, (error, client) => - expect(@project_id in client.rooms).to.equal true - done() + it("should have joined the project room", function(done) { + return RealTimeClient.getConnectedClient(this.client.socket.sessionid, (error, client) => { + expect(Array.from(client.rooms).includes(this.project_id)).to.equal(true); + return done(); + }); + }); - it "should have marked the user as connected", (done) -> - @client.emit "clientTracking.getConnectedUsers", (error, users) => - connected = false - for user in users - if user.client_id == @client.publicId and user.user_id == @user_id - connected = true - break - expect(connected).to.equal true - done() + return it("should have marked the user as connected", function(done) { + return this.client.emit("clientTracking.getConnectedUsers", (error, users) => { + let connected = false; + for (let user of Array.from(users)) { + if ((user.client_id === this.client.publicId) && (user.user_id === this.user_id)) { + connected = true; + break; + } + } + expect(connected).to.equal(true); + return done(); + }); + }); + }); - describe "when not authorized", -> - before (done) -> - async.series [ - (cb) => - FixturesManager.setUpProject { - privilegeLevel: null + describe("when not authorized", function() { + before(function(done) { + return async.series([ + cb => { + return FixturesManager.setUpProject({ + privilegeLevel: null, project: { name: "Test Project" } - }, (e, {@project_id, @user_id}) => - cb(e) + }, (e, {project_id, user_id}) => { + this.project_id = project_id; + this.user_id = user_id; + return cb(e); + }); + }, - (cb) => - @client = RealTimeClient.connect() - @client.on "connectionAccepted", cb + cb => { + this.client = RealTimeClient.connect(); + return this.client.on("connectionAccepted", cb); + }, - (cb) => - @client.emit "joinProject", project_id: @project_id, (@error, @project, @privilegeLevel, @protocolVersion) => - cb() - ], done + cb => { + return this.client.emit("joinProject", {project_id: this.project_id}, (error, project, privilegeLevel, protocolVersion) => { + this.error = error; + this.project = project; + this.privilegeLevel = privilegeLevel; + this.protocolVersion = protocolVersion; + return cb(); + }); + } + ], done); + }); - it "should return an error", -> - @error.message.should.equal "not authorized" + it("should return an error", function() { + return this.error.message.should.equal("not authorized"); + }); - it "should not have joined the project room", (done) -> - RealTimeClient.getConnectedClient @client.socket.sessionid, (error, client) => - expect(@project_id in client.rooms).to.equal false - done() + return it("should not have joined the project room", function(done) { + return RealTimeClient.getConnectedClient(this.client.socket.sessionid, (error, client) => { + expect(Array.from(client.rooms).includes(this.project_id)).to.equal(false); + return done(); + }); + }); + }); - describe "when over rate limit", -> - before (done) -> - async.series [ - (cb) => - @client = RealTimeClient.connect() - @client.on "connectionAccepted", cb + return describe("when over rate limit", function() { + before(function(done) { + return async.series([ + cb => { + this.client = RealTimeClient.connect(); + return this.client.on("connectionAccepted", cb); + }, - (cb) => - @client.emit "joinProject", project_id: 'rate-limited', (@error) => - cb() - ], done + cb => { + return this.client.emit("joinProject", {project_id: 'rate-limited'}, error => { + this.error = error; + return cb(); + }); + } + ], done); + }); - it "should return a TooManyRequests error code", -> - @error.message.should.equal "rate-limit hit when joining project" - @error.code.should.equal "TooManyRequests" + return it("should return a TooManyRequests error code", function() { + this.error.message.should.equal("rate-limit hit when joining project"); + return this.error.code.should.equal("TooManyRequests"); + }); + }); +}); diff --git a/services/real-time/test/acceptance/coffee/LeaveDocTests.js b/services/real-time/test/acceptance/coffee/LeaveDocTests.js index e35e9093d3..5e589356f9 100644 --- a/services/real-time/test/acceptance/coffee/LeaveDocTests.js +++ b/services/real-time/test/acceptance/coffee/LeaveDocTests.js @@ -1,86 +1,121 @@ -chai = require("chai") -expect = chai.expect -chai.should() -sinon = require("sinon") +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const chai = require("chai"); +const { + expect +} = chai; +chai.should(); +const sinon = require("sinon"); -RealTimeClient = require "./helpers/RealTimeClient" -MockDocUpdaterServer = require "./helpers/MockDocUpdaterServer" -FixturesManager = require "./helpers/FixturesManager" -logger = require("logger-sharelatex") +const RealTimeClient = require("./helpers/RealTimeClient"); +const MockDocUpdaterServer = require("./helpers/MockDocUpdaterServer"); +const FixturesManager = require("./helpers/FixturesManager"); +const logger = require("logger-sharelatex"); -async = require "async" +const async = require("async"); -describe "leaveDoc", -> - before -> - @lines = ["test", "doc", "lines"] - @version = 42 - @ops = ["mock", "doc", "ops"] - sinon.spy(logger, "error") - sinon.spy(logger, "warn") - sinon.spy(logger, "log") - @other_doc_id = FixturesManager.getRandomId() +describe("leaveDoc", function() { + before(function() { + this.lines = ["test", "doc", "lines"]; + this.version = 42; + this.ops = ["mock", "doc", "ops"]; + sinon.spy(logger, "error"); + sinon.spy(logger, "warn"); + sinon.spy(logger, "log"); + return this.other_doc_id = FixturesManager.getRandomId(); + }); - after -> - logger.error.restore() # remove the spy - logger.warn.restore() - logger.log.restore() + after(function() { + logger.error.restore(); // remove the spy + logger.warn.restore(); + return logger.log.restore(); + }); - describe "when joined to a doc", -> - beforeEach (done) -> - async.series [ - (cb) => - FixturesManager.setUpProject { + return describe("when joined to a doc", function() { + beforeEach(function(done) { + return async.series([ + cb => { + return FixturesManager.setUpProject({ privilegeLevel: "readAndWrite" - }, (e, {@project_id, @user_id}) => - cb(e) + }, (e, {project_id, user_id}) => { + this.project_id = project_id; + this.user_id = user_id; + return cb(e); + }); + }, - (cb) => - FixturesManager.setUpDoc @project_id, {@lines, @version, @ops}, (e, {@doc_id}) => - cb(e) + cb => { + return FixturesManager.setUpDoc(this.project_id, {lines: this.lines, version: this.version, ops: this.ops}, (e, {doc_id}) => { + this.doc_id = doc_id; + return cb(e); + }); + }, - (cb) => - @client = RealTimeClient.connect() - @client.on "connectionAccepted", cb + cb => { + this.client = RealTimeClient.connect(); + return this.client.on("connectionAccepted", cb); + }, - (cb) => - @client.emit "joinProject", project_id: @project_id, cb + cb => { + return this.client.emit("joinProject", {project_id: this.project_id}, cb); + }, - (cb) => - @client.emit "joinDoc", @doc_id, (error, @returnedArgs...) => cb(error) - ], done + cb => { + return this.client.emit("joinDoc", this.doc_id, (error, ...rest) => { [...this.returnedArgs] = Array.from(rest); return cb(error); }); + } + ], done); + }); - describe "then leaving the doc", -> - beforeEach (done) -> - @client.emit "leaveDoc", @doc_id, (error) -> - throw error if error? - done() + describe("then leaving the doc", function() { + beforeEach(function(done) { + return this.client.emit("leaveDoc", this.doc_id, function(error) { + if (error != null) { throw error; } + return done(); + }); + }); - it "should have left the doc room", (done) -> - RealTimeClient.getConnectedClient @client.socket.sessionid, (error, client) => - expect(@doc_id in client.rooms).to.equal false - done() + return it("should have left the doc room", function(done) { + return RealTimeClient.getConnectedClient(this.client.socket.sessionid, (error, client) => { + expect(Array.from(client.rooms).includes(this.doc_id)).to.equal(false); + return done(); + }); + }); + }); - describe "when sending a leaveDoc request before the previous joinDoc request has completed", -> - beforeEach (done) -> - @client.emit "leaveDoc", @doc_id, () -> - @client.emit "joinDoc", @doc_id, () -> - @client.emit "leaveDoc", @doc_id, (error) -> - throw error if error? - done() + describe("when sending a leaveDoc request before the previous joinDoc request has completed", function() { + beforeEach(function(done) { + this.client.emit("leaveDoc", this.doc_id, function() {}); + this.client.emit("joinDoc", this.doc_id, function() {}); + return this.client.emit("leaveDoc", this.doc_id, function(error) { + if (error != null) { throw error; } + return done(); + }); + }); - it "should not trigger an error", -> - sinon.assert.neverCalledWith(logger.error, sinon.match.any, "not subscribed - shouldn't happen") + it("should not trigger an error", () => sinon.assert.neverCalledWith(logger.error, sinon.match.any, "not subscribed - shouldn't happen")); - it "should have left the doc room", (done) -> - RealTimeClient.getConnectedClient @client.socket.sessionid, (error, client) => - expect(@doc_id in client.rooms).to.equal false - done() + return it("should have left the doc room", function(done) { + return RealTimeClient.getConnectedClient(this.client.socket.sessionid, (error, client) => { + expect(Array.from(client.rooms).includes(this.doc_id)).to.equal(false); + return done(); + }); + }); + }); - describe "when sending a leaveDoc for a room the client has not joined ", -> - beforeEach (done) -> - @client.emit "leaveDoc", @other_doc_id, (error) -> - throw error if error? - done() + return describe("when sending a leaveDoc for a room the client has not joined ", function() { + beforeEach(function(done) { + return this.client.emit("leaveDoc", this.other_doc_id, function(error) { + if (error != null) { throw error; } + return done(); + }); + }); - it "should trigger a low level message only", -> - sinon.assert.calledWith(logger.log, sinon.match.any, "ignoring request from client to leave room it is not in") + return it("should trigger a low level message only", () => sinon.assert.calledWith(logger.log, sinon.match.any, "ignoring request from client to leave room it is not in")); + }); + }); +}); diff --git a/services/real-time/test/acceptance/coffee/LeaveProjectTests.js b/services/real-time/test/acceptance/coffee/LeaveProjectTests.js index 91ec1a1159..11e4ed2471 100644 --- a/services/real-time/test/acceptance/coffee/LeaveProjectTests.js +++ b/services/real-time/test/acceptance/coffee/LeaveProjectTests.js @@ -1,147 +1,206 @@ -RealTimeClient = require "./helpers/RealTimeClient" -MockDocUpdaterServer = require "./helpers/MockDocUpdaterServer" -FixturesManager = require "./helpers/FixturesManager" +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const RealTimeClient = require("./helpers/RealTimeClient"); +const MockDocUpdaterServer = require("./helpers/MockDocUpdaterServer"); +const FixturesManager = require("./helpers/FixturesManager"); -async = require "async" +const async = require("async"); -settings = require "settings-sharelatex" -redis = require "redis-sharelatex" -rclient = redis.createClient(settings.redis.pubsub) +const settings = require("settings-sharelatex"); +const redis = require("redis-sharelatex"); +const rclient = redis.createClient(settings.redis.pubsub); -describe "leaveProject", -> - before (done) -> - MockDocUpdaterServer.run done +describe("leaveProject", function() { + before(done => MockDocUpdaterServer.run(done)); - describe "with other clients in the project", -> - before (done) -> - async.series [ - (cb) => - FixturesManager.setUpProject { - privilegeLevel: "owner" + describe("with other clients in the project", function() { + before(function(done) { + return async.series([ + cb => { + return FixturesManager.setUpProject({ + privilegeLevel: "owner", project: { name: "Test Project" } - }, (e, {@project_id, @user_id}) => cb() + }, (e, {project_id, user_id}) => { this.project_id = project_id; this.user_id = user_id; return cb(); }); + }, - (cb) => - @clientA = RealTimeClient.connect() - @clientA.on "connectionAccepted", cb + cb => { + this.clientA = RealTimeClient.connect(); + return this.clientA.on("connectionAccepted", cb); + }, - (cb) => - @clientB = RealTimeClient.connect() - @clientB.on "connectionAccepted", cb + cb => { + this.clientB = RealTimeClient.connect(); + this.clientB.on("connectionAccepted", cb); - @clientBDisconnectMessages = [] - @clientB.on "clientTracking.clientDisconnected", (data) => - @clientBDisconnectMessages.push data + this.clientBDisconnectMessages = []; + return this.clientB.on("clientTracking.clientDisconnected", data => { + return this.clientBDisconnectMessages.push(data); + }); + }, - (cb) => - @clientA.emit "joinProject", project_id: @project_id, (error, @project, @privilegeLevel, @protocolVersion) => - cb(error) + cb => { + return this.clientA.emit("joinProject", {project_id: this.project_id}, (error, project, privilegeLevel, protocolVersion) => { + this.project = project; + this.privilegeLevel = privilegeLevel; + this.protocolVersion = protocolVersion; + return cb(error); + }); + }, - (cb) => - @clientB.emit "joinProject", project_id: @project_id, (error, @project, @privilegeLevel, @protocolVersion) => - cb(error) + cb => { + return this.clientB.emit("joinProject", {project_id: this.project_id}, (error, project, privilegeLevel, protocolVersion) => { + this.project = project; + this.privilegeLevel = privilegeLevel; + this.protocolVersion = protocolVersion; + return cb(error); + }); + }, - (cb) => - FixturesManager.setUpDoc @project_id, {@lines, @version, @ops}, (e, {@doc_id}) => - cb(e) + cb => { + return FixturesManager.setUpDoc(this.project_id, {lines: this.lines, version: this.version, ops: this.ops}, (e, {doc_id}) => { + this.doc_id = doc_id; + return cb(e); + }); + }, - (cb) => - @clientA.emit "joinDoc", @doc_id, cb - (cb) => - @clientB.emit "joinDoc", @doc_id, cb + cb => { + return this.clientA.emit("joinDoc", this.doc_id, cb); + }, + cb => { + return this.clientB.emit("joinDoc", this.doc_id, cb); + }, - (cb) => - # leaveProject is called when the client disconnects - @clientA.on "disconnect", () -> cb() - @clientA.disconnect() + cb => { + // leaveProject is called when the client disconnects + this.clientA.on("disconnect", () => cb()); + return this.clientA.disconnect(); + }, - (cb) => - # The API waits a little while before flushing changes - setTimeout done, 1000 + cb => { + // The API waits a little while before flushing changes + return setTimeout(done, 1000); + } - ], done + ], done); + }); - it "should emit a disconnect message to the room", -> - @clientBDisconnectMessages.should.deep.equal [@clientA.publicId] + it("should emit a disconnect message to the room", function() { + return this.clientBDisconnectMessages.should.deep.equal([this.clientA.publicId]); + }); - it "should no longer list the client in connected users", (done) -> - @clientB.emit "clientTracking.getConnectedUsers", (error, users) => - for user in users - if user.client_id == @clientA.publicId - throw "Expected clientA to not be listed in connected users" - return done() + it("should no longer list the client in connected users", function(done) { + return this.clientB.emit("clientTracking.getConnectedUsers", (error, users) => { + for (let user of Array.from(users)) { + if (user.client_id === this.clientA.publicId) { + throw "Expected clientA to not be listed in connected users"; + } + } + return done(); + }); + }); - it "should not flush the project to the document updater", -> - MockDocUpdaterServer.deleteProject - .calledWith(@project_id) - .should.equal false + it("should not flush the project to the document updater", function() { + return MockDocUpdaterServer.deleteProject + .calledWith(this.project_id) + .should.equal(false); + }); - it "should remain subscribed to the editor-events channels", (done) -> - rclient.pubsub 'CHANNELS', (err, resp) => - return done(err) if err - resp.should.include "editor-events:#{@project_id}" - done() - return null + it("should remain subscribed to the editor-events channels", function(done) { + rclient.pubsub('CHANNELS', (err, resp) => { + if (err) { return done(err); } + resp.should.include(`editor-events:${this.project_id}`); + return done(); + }); + return null; + }); - it "should remain subscribed to the applied-ops channels", (done) -> - rclient.pubsub 'CHANNELS', (err, resp) => - return done(err) if err - resp.should.include "applied-ops:#{@doc_id}" - done() - return null + return it("should remain subscribed to the applied-ops channels", function(done) { + rclient.pubsub('CHANNELS', (err, resp) => { + if (err) { return done(err); } + resp.should.include(`applied-ops:${this.doc_id}`); + return done(); + }); + return null; + }); + }); - describe "with no other clients in the project", -> - before (done) -> - async.series [ - (cb) => - FixturesManager.setUpProject { - privilegeLevel: "owner" + return describe("with no other clients in the project", function() { + before(function(done) { + return async.series([ + cb => { + return FixturesManager.setUpProject({ + privilegeLevel: "owner", project: { name: "Test Project" } - }, (e, {@project_id, @user_id}) => cb() + }, (e, {project_id, user_id}) => { this.project_id = project_id; this.user_id = user_id; return cb(); }); + }, - (cb) => - @clientA = RealTimeClient.connect() - @clientA.on "connect", cb + cb => { + this.clientA = RealTimeClient.connect(); + return this.clientA.on("connect", cb); + }, - (cb) => - @clientA.emit "joinProject", project_id: @project_id, (error, @project, @privilegeLevel, @protocolVersion) => - cb(error) + cb => { + return this.clientA.emit("joinProject", {project_id: this.project_id}, (error, project, privilegeLevel, protocolVersion) => { + this.project = project; + this.privilegeLevel = privilegeLevel; + this.protocolVersion = protocolVersion; + return cb(error); + }); + }, - (cb) => - FixturesManager.setUpDoc @project_id, {@lines, @version, @ops}, (e, {@doc_id}) => - cb(e) - (cb) => - @clientA.emit "joinDoc", @doc_id, cb + cb => { + return FixturesManager.setUpDoc(this.project_id, {lines: this.lines, version: this.version, ops: this.ops}, (e, {doc_id}) => { + this.doc_id = doc_id; + return cb(e); + }); + }, + cb => { + return this.clientA.emit("joinDoc", this.doc_id, cb); + }, - (cb) => - # leaveProject is called when the client disconnects - @clientA.on "disconnect", () -> cb() - @clientA.disconnect() + cb => { + // leaveProject is called when the client disconnects + this.clientA.on("disconnect", () => cb()); + return this.clientA.disconnect(); + }, - (cb) => - # The API waits a little while before flushing changes - setTimeout done, 1000 - ], done + cb => { + // The API waits a little while before flushing changes + return setTimeout(done, 1000); + } + ], done); + }); - it "should flush the project to the document updater", -> - MockDocUpdaterServer.deleteProject - .calledWith(@project_id) - .should.equal true + it("should flush the project to the document updater", function() { + return MockDocUpdaterServer.deleteProject + .calledWith(this.project_id) + .should.equal(true); + }); - it "should not subscribe to the editor-events channels anymore", (done) -> - rclient.pubsub 'CHANNELS', (err, resp) => - return done(err) if err - resp.should.not.include "editor-events:#{@project_id}" - done() - return null + it("should not subscribe to the editor-events channels anymore", function(done) { + rclient.pubsub('CHANNELS', (err, resp) => { + if (err) { return done(err); } + resp.should.not.include(`editor-events:${this.project_id}`); + return done(); + }); + return null; + }); - it "should not subscribe to the applied-ops channels anymore", (done) -> - rclient.pubsub 'CHANNELS', (err, resp) => - return done(err) if err - resp.should.not.include "applied-ops:#{@doc_id}" - done() - return null + return it("should not subscribe to the applied-ops channels anymore", function(done) { + rclient.pubsub('CHANNELS', (err, resp) => { + if (err) { return done(err); } + resp.should.not.include(`applied-ops:${this.doc_id}`); + return done(); + }); + return null; + }); + }); +}); diff --git a/services/real-time/test/acceptance/coffee/PubSubRace.js b/services/real-time/test/acceptance/coffee/PubSubRace.js index d5e6653fac..3c5a6f0669 100644 --- a/services/real-time/test/acceptance/coffee/PubSubRace.js +++ b/services/real-time/test/acceptance/coffee/PubSubRace.js @@ -1,205 +1,277 @@ -RealTimeClient = require "./helpers/RealTimeClient" -MockDocUpdaterServer = require "./helpers/MockDocUpdaterServer" -FixturesManager = require "./helpers/FixturesManager" +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const RealTimeClient = require("./helpers/RealTimeClient"); +const MockDocUpdaterServer = require("./helpers/MockDocUpdaterServer"); +const FixturesManager = require("./helpers/FixturesManager"); -async = require "async" +const async = require("async"); -settings = require "settings-sharelatex" -redis = require "redis-sharelatex" -rclient = redis.createClient(settings.redis.pubsub) +const settings = require("settings-sharelatex"); +const redis = require("redis-sharelatex"); +const rclient = redis.createClient(settings.redis.pubsub); -describe "PubSubRace", -> - before (done) -> - MockDocUpdaterServer.run done +describe("PubSubRace", function() { + before(done => MockDocUpdaterServer.run(done)); - describe "when the client leaves a doc before joinDoc completes", -> - before (done) -> - async.series [ - (cb) => - FixturesManager.setUpProject { - privilegeLevel: "owner" + describe("when the client leaves a doc before joinDoc completes", function() { + before(function(done) { + return async.series([ + cb => { + return FixturesManager.setUpProject({ + privilegeLevel: "owner", project: { name: "Test Project" } - }, (e, {@project_id, @user_id}) => cb() + }, (e, {project_id, user_id}) => { this.project_id = project_id; this.user_id = user_id; return cb(); }); + }, - (cb) => - @clientA = RealTimeClient.connect() - @clientA.on "connect", cb + cb => { + this.clientA = RealTimeClient.connect(); + return this.clientA.on("connect", cb); + }, - (cb) => - @clientA.emit "joinProject", project_id: @project_id, (error, @project, @privilegeLevel, @protocolVersion) => - cb(error) + cb => { + return this.clientA.emit("joinProject", {project_id: this.project_id}, (error, project, privilegeLevel, protocolVersion) => { + this.project = project; + this.privilegeLevel = privilegeLevel; + this.protocolVersion = protocolVersion; + return cb(error); + }); + }, - (cb) => - FixturesManager.setUpDoc @project_id, {@lines, @version, @ops}, (e, {@doc_id}) => - cb(e) + cb => { + return FixturesManager.setUpDoc(this.project_id, {lines: this.lines, version: this.version, ops: this.ops}, (e, {doc_id}) => { + this.doc_id = doc_id; + return cb(e); + }); + }, - (cb) => - @clientA.emit "joinDoc", @doc_id, () -> - # leave before joinDoc completes - @clientA.emit "leaveDoc", @doc_id, cb + cb => { + this.clientA.emit("joinDoc", this.doc_id, function() {}); + // leave before joinDoc completes + return this.clientA.emit("leaveDoc", this.doc_id, cb); + }, - (cb) => - # wait for subscribe and unsubscribe - setTimeout cb, 100 - ], done + cb => { + // wait for subscribe and unsubscribe + return setTimeout(cb, 100); + } + ], done); + }); - it "should not subscribe to the applied-ops channels anymore", (done) -> - rclient.pubsub 'CHANNELS', (err, resp) => - return done(err) if err - resp.should.not.include "applied-ops:#{@doc_id}" - done() - return null + return it("should not subscribe to the applied-ops channels anymore", function(done) { + rclient.pubsub('CHANNELS', (err, resp) => { + if (err) { return done(err); } + resp.should.not.include(`applied-ops:${this.doc_id}`); + return done(); + }); + return null; + }); + }); - describe "when the client emits joinDoc and leaveDoc requests frequently and leaves eventually", -> - before (done) -> - async.series [ - (cb) => - FixturesManager.setUpProject { - privilegeLevel: "owner" + describe("when the client emits joinDoc and leaveDoc requests frequently and leaves eventually", function() { + before(function(done) { + return async.series([ + cb => { + return FixturesManager.setUpProject({ + privilegeLevel: "owner", project: { name: "Test Project" } - }, (e, {@project_id, @user_id}) => cb() + }, (e, {project_id, user_id}) => { this.project_id = project_id; this.user_id = user_id; return cb(); }); + }, - (cb) => - @clientA = RealTimeClient.connect() - @clientA.on "connect", cb + cb => { + this.clientA = RealTimeClient.connect(); + return this.clientA.on("connect", cb); + }, - (cb) => - @clientA.emit "joinProject", project_id: @project_id, (error, @project, @privilegeLevel, @protocolVersion) => - cb(error) + cb => { + return this.clientA.emit("joinProject", {project_id: this.project_id}, (error, project, privilegeLevel, protocolVersion) => { + this.project = project; + this.privilegeLevel = privilegeLevel; + this.protocolVersion = protocolVersion; + return cb(error); + }); + }, - (cb) => - FixturesManager.setUpDoc @project_id, {@lines, @version, @ops}, (e, {@doc_id}) => - cb(e) + cb => { + return FixturesManager.setUpDoc(this.project_id, {lines: this.lines, version: this.version, ops: this.ops}, (e, {doc_id}) => { + this.doc_id = doc_id; + return cb(e); + }); + }, - (cb) => - @clientA.emit "joinDoc", @doc_id, () -> - @clientA.emit "leaveDoc", @doc_id, () -> - @clientA.emit "joinDoc", @doc_id, () -> - @clientA.emit "leaveDoc", @doc_id, () -> - @clientA.emit "joinDoc", @doc_id, () -> - @clientA.emit "leaveDoc", @doc_id, () -> - @clientA.emit "joinDoc", @doc_id, () -> - @clientA.emit "leaveDoc", @doc_id, () -> - @clientA.emit "joinDoc", @doc_id, () -> - @clientA.emit "leaveDoc", @doc_id, cb + cb => { + this.clientA.emit("joinDoc", this.doc_id, function() {}); + this.clientA.emit("leaveDoc", this.doc_id, function() {}); + this.clientA.emit("joinDoc", this.doc_id, function() {}); + this.clientA.emit("leaveDoc", this.doc_id, function() {}); + this.clientA.emit("joinDoc", this.doc_id, function() {}); + this.clientA.emit("leaveDoc", this.doc_id, function() {}); + this.clientA.emit("joinDoc", this.doc_id, function() {}); + this.clientA.emit("leaveDoc", this.doc_id, function() {}); + this.clientA.emit("joinDoc", this.doc_id, function() {}); + return this.clientA.emit("leaveDoc", this.doc_id, cb); + }, - (cb) => - # wait for subscribe and unsubscribe - setTimeout cb, 100 - ], done + cb => { + // wait for subscribe and unsubscribe + return setTimeout(cb, 100); + } + ], done); + }); - it "should not subscribe to the applied-ops channels anymore", (done) -> - rclient.pubsub 'CHANNELS', (err, resp) => - return done(err) if err - resp.should.not.include "applied-ops:#{@doc_id}" - done() - return null + return it("should not subscribe to the applied-ops channels anymore", function(done) { + rclient.pubsub('CHANNELS', (err, resp) => { + if (err) { return done(err); } + resp.should.not.include(`applied-ops:${this.doc_id}`); + return done(); + }); + return null; + }); + }); - describe "when the client emits joinDoc and leaveDoc requests frequently and remains in the doc", -> - before (done) -> - async.series [ - (cb) => - FixturesManager.setUpProject { - privilegeLevel: "owner" + describe("when the client emits joinDoc and leaveDoc requests frequently and remains in the doc", function() { + before(function(done) { + return async.series([ + cb => { + return FixturesManager.setUpProject({ + privilegeLevel: "owner", project: { name: "Test Project" } - }, (e, {@project_id, @user_id}) => cb() + }, (e, {project_id, user_id}) => { this.project_id = project_id; this.user_id = user_id; return cb(); }); + }, - (cb) => - @clientA = RealTimeClient.connect() - @clientA.on "connect", cb + cb => { + this.clientA = RealTimeClient.connect(); + return this.clientA.on("connect", cb); + }, - (cb) => - @clientA.emit "joinProject", project_id: @project_id, (error, @project, @privilegeLevel, @protocolVersion) => - cb(error) + cb => { + return this.clientA.emit("joinProject", {project_id: this.project_id}, (error, project, privilegeLevel, protocolVersion) => { + this.project = project; + this.privilegeLevel = privilegeLevel; + this.protocolVersion = protocolVersion; + return cb(error); + }); + }, - (cb) => - FixturesManager.setUpDoc @project_id, {@lines, @version, @ops}, (e, {@doc_id}) => - cb(e) + cb => { + return FixturesManager.setUpDoc(this.project_id, {lines: this.lines, version: this.version, ops: this.ops}, (e, {doc_id}) => { + this.doc_id = doc_id; + return cb(e); + }); + }, - (cb) => - @clientA.emit "joinDoc", @doc_id, () -> - @clientA.emit "leaveDoc", @doc_id, () -> - @clientA.emit "joinDoc", @doc_id, () -> - @clientA.emit "leaveDoc", @doc_id, () -> - @clientA.emit "joinDoc", @doc_id, () -> - @clientA.emit "leaveDoc", @doc_id, () -> - @clientA.emit "joinDoc", @doc_id, () -> - @clientA.emit "leaveDoc", @doc_id, () -> - @clientA.emit "joinDoc", @doc_id, cb + cb => { + this.clientA.emit("joinDoc", this.doc_id, function() {}); + this.clientA.emit("leaveDoc", this.doc_id, function() {}); + this.clientA.emit("joinDoc", this.doc_id, function() {}); + this.clientA.emit("leaveDoc", this.doc_id, function() {}); + this.clientA.emit("joinDoc", this.doc_id, function() {}); + this.clientA.emit("leaveDoc", this.doc_id, function() {}); + this.clientA.emit("joinDoc", this.doc_id, function() {}); + this.clientA.emit("leaveDoc", this.doc_id, function() {}); + return this.clientA.emit("joinDoc", this.doc_id, cb); + }, - (cb) => - # wait for subscribe and unsubscribe - setTimeout cb, 100 - ], done + cb => { + // wait for subscribe and unsubscribe + return setTimeout(cb, 100); + } + ], done); + }); - it "should subscribe to the applied-ops channels", (done) -> - rclient.pubsub 'CHANNELS', (err, resp) => - return done(err) if err - resp.should.include "applied-ops:#{@doc_id}" - done() - return null + return it("should subscribe to the applied-ops channels", function(done) { + rclient.pubsub('CHANNELS', (err, resp) => { + if (err) { return done(err); } + resp.should.include(`applied-ops:${this.doc_id}`); + return done(); + }); + return null; + }); + }); - describe "when the client disconnects before joinDoc completes", -> - before (done) -> - async.series [ - (cb) => - FixturesManager.setUpProject { - privilegeLevel: "owner" + return describe("when the client disconnects before joinDoc completes", function() { + before(function(done) { + return async.series([ + cb => { + return FixturesManager.setUpProject({ + privilegeLevel: "owner", project: { name: "Test Project" } - }, (e, {@project_id, @user_id}) => cb() + }, (e, {project_id, user_id}) => { this.project_id = project_id; this.user_id = user_id; return cb(); }); + }, - (cb) => - @clientA = RealTimeClient.connect() - @clientA.on "connect", cb + cb => { + this.clientA = RealTimeClient.connect(); + return this.clientA.on("connect", cb); + }, - (cb) => - @clientA.emit "joinProject", project_id: @project_id, (error, @project, @privilegeLevel, @protocolVersion) => - cb(error) + cb => { + return this.clientA.emit("joinProject", {project_id: this.project_id}, (error, project, privilegeLevel, protocolVersion) => { + this.project = project; + this.privilegeLevel = privilegeLevel; + this.protocolVersion = protocolVersion; + return cb(error); + }); + }, - (cb) => - FixturesManager.setUpDoc @project_id, {@lines, @version, @ops}, (e, {@doc_id}) => - cb(e) + cb => { + return FixturesManager.setUpDoc(this.project_id, {lines: this.lines, version: this.version, ops: this.ops}, (e, {doc_id}) => { + this.doc_id = doc_id; + return cb(e); + }); + }, - (cb) => - joinDocCompleted = false - @clientA.emit "joinDoc", @doc_id, () -> - joinDocCompleted = true - # leave before joinDoc completes - setTimeout () => - if joinDocCompleted - return cb(new Error('joinDocCompleted -- lower timeout')) - @clientA.on "disconnect", () -> cb() - @clientA.disconnect() - # socket.io processes joinDoc and disconnect with different delays: - # - joinDoc goes through two process.nextTick - # - disconnect goes through one process.nextTick - # We have to inject the disconnect event into a different event loop - # cycle. - , 3 + cb => { + let joinDocCompleted = false; + this.clientA.emit("joinDoc", this.doc_id, () => joinDocCompleted = true); + // leave before joinDoc completes + return setTimeout(() => { + if (joinDocCompleted) { + return cb(new Error('joinDocCompleted -- lower timeout')); + } + this.clientA.on("disconnect", () => cb()); + return this.clientA.disconnect(); + } + // socket.io processes joinDoc and disconnect with different delays: + // - joinDoc goes through two process.nextTick + // - disconnect goes through one process.nextTick + // We have to inject the disconnect event into a different event loop + // cycle. + , 3); + }, - (cb) => - # wait for subscribe and unsubscribe - setTimeout cb, 100 - ], done + cb => { + // wait for subscribe and unsubscribe + return setTimeout(cb, 100); + } + ], done); + }); - it "should not subscribe to the editor-events channels anymore", (done) -> - rclient.pubsub 'CHANNELS', (err, resp) => - return done(err) if err - resp.should.not.include "editor-events:#{@project_id}" - done() - return null + it("should not subscribe to the editor-events channels anymore", function(done) { + rclient.pubsub('CHANNELS', (err, resp) => { + if (err) { return done(err); } + resp.should.not.include(`editor-events:${this.project_id}`); + return done(); + }); + return null; + }); - it "should not subscribe to the applied-ops channels anymore", (done) -> - rclient.pubsub 'CHANNELS', (err, resp) => - return done(err) if err - resp.should.not.include "applied-ops:#{@doc_id}" - done() - return null + return it("should not subscribe to the applied-ops channels anymore", function(done) { + rclient.pubsub('CHANNELS', (err, resp) => { + if (err) { return done(err); } + resp.should.not.include(`applied-ops:${this.doc_id}`); + return done(); + }); + return null; + }); + }); +}); diff --git a/services/real-time/test/acceptance/coffee/ReceiveUpdateTests.js b/services/real-time/test/acceptance/coffee/ReceiveUpdateTests.js index da9ee0ca36..960ddb145e 100644 --- a/services/real-time/test/acceptance/coffee/ReceiveUpdateTests.js +++ b/services/real-time/test/acceptance/coffee/ReceiveUpdateTests.js @@ -1,208 +1,274 @@ -chai = require("chai") -expect = chai.expect -chai.should() +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const chai = require("chai"); +const { + expect +} = chai; +chai.should(); -RealTimeClient = require "./helpers/RealTimeClient" -MockWebServer = require "./helpers/MockWebServer" -FixturesManager = require "./helpers/FixturesManager" +const RealTimeClient = require("./helpers/RealTimeClient"); +const MockWebServer = require("./helpers/MockWebServer"); +const FixturesManager = require("./helpers/FixturesManager"); -async = require "async" +const async = require("async"); -settings = require "settings-sharelatex" -redis = require "redis-sharelatex" -rclient = redis.createClient(settings.redis.pubsub) +const settings = require("settings-sharelatex"); +const redis = require("redis-sharelatex"); +const rclient = redis.createClient(settings.redis.pubsub); -describe "receiveUpdate", -> - beforeEach (done) -> - @lines = ["test", "doc", "lines"] - @version = 42 - @ops = ["mock", "doc", "ops"] +describe("receiveUpdate", function() { + beforeEach(function(done) { + this.lines = ["test", "doc", "lines"]; + this.version = 42; + this.ops = ["mock", "doc", "ops"]; - async.series [ - (cb) => - FixturesManager.setUpProject { - privilegeLevel: "owner" + return async.series([ + cb => { + return FixturesManager.setUpProject({ + privilegeLevel: "owner", project: { name: "Test Project" } - }, (error, {@user_id, @project_id}) => cb() + }, (error, {user_id, project_id}) => { this.user_id = user_id; this.project_id = project_id; return cb(); }); + }, - (cb) => - FixturesManager.setUpDoc @project_id, {@lines, @version, @ops}, (e, {@doc_id}) => - cb(e) + cb => { + return FixturesManager.setUpDoc(this.project_id, {lines: this.lines, version: this.version, ops: this.ops}, (e, {doc_id}) => { + this.doc_id = doc_id; + return cb(e); + }); + }, - (cb) => - @clientA = RealTimeClient.connect() - @clientA.on "connectionAccepted", cb + cb => { + this.clientA = RealTimeClient.connect(); + return this.clientA.on("connectionAccepted", cb); + }, - (cb) => - @clientB = RealTimeClient.connect() - @clientB.on "connectionAccepted", cb + cb => { + this.clientB = RealTimeClient.connect(); + return this.clientB.on("connectionAccepted", cb); + }, - (cb) => - @clientA.emit "joinProject", { - project_id: @project_id - }, cb + cb => { + return this.clientA.emit("joinProject", { + project_id: this.project_id + }, cb); + }, - (cb) => - @clientA.emit "joinDoc", @doc_id, cb + cb => { + return this.clientA.emit("joinDoc", this.doc_id, cb); + }, - (cb) => - @clientB.emit "joinProject", { - project_id: @project_id - }, cb + cb => { + return this.clientB.emit("joinProject", { + project_id: this.project_id + }, cb); + }, - (cb) => - @clientB.emit "joinDoc", @doc_id, cb + cb => { + return this.clientB.emit("joinDoc", this.doc_id, cb); + }, - (cb) => - FixturesManager.setUpProject { - privilegeLevel: "owner" + cb => { + return FixturesManager.setUpProject({ + privilegeLevel: "owner", project: {name: "Test Project"} - }, (error, {user_id: @user_id_second, project_id: @project_id_second}) => cb() + }, (error, {user_id: user_id_second, project_id: project_id_second}) => { this.user_id_second = user_id_second; this.project_id_second = project_id_second; return cb(); }); + }, - (cb) => - FixturesManager.setUpDoc @project_id_second, {@lines, @version, @ops}, (e, {doc_id: @doc_id_second}) => - cb(e) + cb => { + return FixturesManager.setUpDoc(this.project_id_second, {lines: this.lines, version: this.version, ops: this.ops}, (e, {doc_id: doc_id_second}) => { + this.doc_id_second = doc_id_second; + return cb(e); + }); + }, - (cb) => - @clientC = RealTimeClient.connect() - @clientC.on "connectionAccepted", cb + cb => { + this.clientC = RealTimeClient.connect(); + return this.clientC.on("connectionAccepted", cb); + }, - (cb) => - @clientC.emit "joinProject", { - project_id: @project_id_second - }, cb - (cb) => - @clientC.emit "joinDoc", @doc_id_second, cb + cb => { + return this.clientC.emit("joinProject", { + project_id: this.project_id_second + }, cb); + }, + cb => { + return this.clientC.emit("joinDoc", this.doc_id_second, cb); + }, - (cb) => - @clientAUpdates = [] - @clientA.on "otUpdateApplied", (update) => @clientAUpdates.push(update) - @clientBUpdates = [] - @clientB.on "otUpdateApplied", (update) => @clientBUpdates.push(update) - @clientCUpdates = [] - @clientC.on "otUpdateApplied", (update) => @clientCUpdates.push(update) + cb => { + this.clientAUpdates = []; + this.clientA.on("otUpdateApplied", update => this.clientAUpdates.push(update)); + this.clientBUpdates = []; + this.clientB.on("otUpdateApplied", update => this.clientBUpdates.push(update)); + this.clientCUpdates = []; + this.clientC.on("otUpdateApplied", update => this.clientCUpdates.push(update)); - @clientAErrors = [] - @clientA.on "otUpdateError", (error) => @clientAErrors.push(error) - @clientBErrors = [] - @clientB.on "otUpdateError", (error) => @clientBErrors.push(error) - @clientCErrors = [] - @clientC.on "otUpdateError", (error) => @clientCErrors.push(error) - cb() - ], done - - afterEach () -> - @clientA?.disconnect() - @clientB?.disconnect() - @clientC?.disconnect() - - describe "with an update from clientA", -> - beforeEach (done) -> - @update = { - doc_id: @doc_id - op: - meta: - source: @clientA.publicId - v: @version - doc: @doc_id - op: [{i: "foo", p: 50}] + this.clientAErrors = []; + this.clientA.on("otUpdateError", error => this.clientAErrors.push(error)); + this.clientBErrors = []; + this.clientB.on("otUpdateError", error => this.clientBErrors.push(error)); + this.clientCErrors = []; + this.clientC.on("otUpdateError", error => this.clientCErrors.push(error)); + return cb(); } - rclient.publish "applied-ops", JSON.stringify(@update) - setTimeout done, 200 # Give clients time to get message - - it "should send the full op to clientB", -> - @clientBUpdates.should.deep.equal [@update.op] - - it "should send an ack to clientA", -> - @clientAUpdates.should.deep.equal [{ - v: @version, doc: @doc_id - }] + ], done); + }); - it "should send nothing to clientC", -> - @clientCUpdates.should.deep.equal [] + afterEach(function() { + if (this.clientA != null) { + this.clientA.disconnect(); + } + if (this.clientB != null) { + this.clientB.disconnect(); + } + return (this.clientC != null ? this.clientC.disconnect() : undefined); + }); - describe "with an update from clientC", -> - beforeEach (done) -> - @update = { - doc_id: @doc_id_second - op: - meta: - source: @clientC.publicId - v: @version - doc: @doc_id_second - op: [{i: "update from clientC", p: 50}] - } - rclient.publish "applied-ops", JSON.stringify(@update) - setTimeout done, 200 # Give clients time to get message - - it "should send nothing to clientA", -> - @clientAUpdates.should.deep.equal [] - - it "should send nothing to clientB", -> - @clientBUpdates.should.deep.equal [] - - it "should send an ack to clientC", -> - @clientCUpdates.should.deep.equal [{ - v: @version, doc: @doc_id_second - }] - - describe "with an update from a remote client for project 1", -> - beforeEach (done) -> - @update = { - doc_id: @doc_id - op: - meta: - source: 'this-is-a-remote-client-id' - v: @version - doc: @doc_id + describe("with an update from clientA", function() { + beforeEach(function(done) { + this.update = { + doc_id: this.doc_id, + op: { + meta: { + source: this.clientA.publicId + }, + v: this.version, + doc: this.doc_id, op: [{i: "foo", p: 50}] - } - rclient.publish "applied-ops", JSON.stringify(@update) - setTimeout done, 200 # Give clients time to get message - - it "should send the full op to clientA", -> - @clientAUpdates.should.deep.equal [@update.op] + } + }; + rclient.publish("applied-ops", JSON.stringify(this.update)); + return setTimeout(done, 200); + }); // Give clients time to get message - it "should send the full op to clientB", -> - @clientBUpdates.should.deep.equal [@update.op] + it("should send the full op to clientB", function() { + return this.clientBUpdates.should.deep.equal([this.update.op]); + }); + + it("should send an ack to clientA", function() { + return this.clientAUpdates.should.deep.equal([{ + v: this.version, doc: this.doc_id + }]); + }); - it "should send nothing to clientC", -> - @clientCUpdates.should.deep.equal [] + return it("should send nothing to clientC", function() { + return this.clientCUpdates.should.deep.equal([]); + }); +}); - describe "with an error for the first project", -> - beforeEach (done) -> - rclient.publish "applied-ops", JSON.stringify({doc_id: @doc_id, error: @error = "something went wrong"}) - setTimeout done, 200 # Give clients time to get message + describe("with an update from clientC", function() { + beforeEach(function(done) { + this.update = { + doc_id: this.doc_id_second, + op: { + meta: { + source: this.clientC.publicId + }, + v: this.version, + doc: this.doc_id_second, + op: [{i: "update from clientC", p: 50}] + } + }; + rclient.publish("applied-ops", JSON.stringify(this.update)); + return setTimeout(done, 200); + }); // Give clients time to get message - it "should send the error to the clients in the first project", -> - @clientAErrors.should.deep.equal [@error] - @clientBErrors.should.deep.equal [@error] + it("should send nothing to clientA", function() { + return this.clientAUpdates.should.deep.equal([]); + }); - it "should not send any errors to the client in the second project", -> - @clientCErrors.should.deep.equal [] + it("should send nothing to clientB", function() { + return this.clientBUpdates.should.deep.equal([]); + }); - it "should disconnect the clients of the first project", -> - @clientA.socket.connected.should.equal false - @clientB.socket.connected.should.equal false + return it("should send an ack to clientC", function() { + return this.clientCUpdates.should.deep.equal([{ + v: this.version, doc: this.doc_id_second + }]); + }); +}); - it "should not disconnect the client in the second project", -> - @clientC.socket.connected.should.equal true + describe("with an update from a remote client for project 1", function() { + beforeEach(function(done) { + this.update = { + doc_id: this.doc_id, + op: { + meta: { + source: 'this-is-a-remote-client-id' + }, + v: this.version, + doc: this.doc_id, + op: [{i: "foo", p: 50}] + } + }; + rclient.publish("applied-ops", JSON.stringify(this.update)); + return setTimeout(done, 200); + }); // Give clients time to get message - describe "with an error for the second project", -> - beforeEach (done) -> - rclient.publish "applied-ops", JSON.stringify({doc_id: @doc_id_second, error: @error = "something went wrong"}) - setTimeout done, 200 # Give clients time to get message + it("should send the full op to clientA", function() { + return this.clientAUpdates.should.deep.equal([this.update.op]); + }); + + it("should send the full op to clientB", function() { + return this.clientBUpdates.should.deep.equal([this.update.op]); + }); - it "should not send any errors to the clients in the first project", -> - @clientAErrors.should.deep.equal [] - @clientBErrors.should.deep.equal [] + return it("should send nothing to clientC", function() { + return this.clientCUpdates.should.deep.equal([]); + }); +}); - it "should send the error to the client in the second project", -> - @clientCErrors.should.deep.equal [@error] + describe("with an error for the first project", function() { + beforeEach(function(done) { + rclient.publish("applied-ops", JSON.stringify({doc_id: this.doc_id, error: (this.error = "something went wrong")})); + return setTimeout(done, 200); + }); // Give clients time to get message - it "should not disconnect the clients of the first project", -> - @clientA.socket.connected.should.equal true - @clientB.socket.connected.should.equal true + it("should send the error to the clients in the first project", function() { + this.clientAErrors.should.deep.equal([this.error]); + return this.clientBErrors.should.deep.equal([this.error]); + }); - it "should disconnect the client in the second project", -> - @clientC.socket.connected.should.equal false + it("should not send any errors to the client in the second project", function() { + return this.clientCErrors.should.deep.equal([]); + }); + + it("should disconnect the clients of the first project", function() { + this.clientA.socket.connected.should.equal(false); + return this.clientB.socket.connected.should.equal(false); + }); + + return it("should not disconnect the client in the second project", function() { + return this.clientC.socket.connected.should.equal(true); + }); + }); + + return describe("with an error for the second project", function() { + beforeEach(function(done) { + rclient.publish("applied-ops", JSON.stringify({doc_id: this.doc_id_second, error: (this.error = "something went wrong")})); + return setTimeout(done, 200); + }); // Give clients time to get message + + it("should not send any errors to the clients in the first project", function() { + this.clientAErrors.should.deep.equal([]); + return this.clientBErrors.should.deep.equal([]); + }); + + it("should send the error to the client in the second project", function() { + return this.clientCErrors.should.deep.equal([this.error]); + }); + + it("should not disconnect the clients of the first project", function() { + this.clientA.socket.connected.should.equal(true); + return this.clientB.socket.connected.should.equal(true); + }); + + return it("should disconnect the client in the second project", function() { + return this.clientC.socket.connected.should.equal(false); + }); + }); +}); diff --git a/services/real-time/test/acceptance/coffee/RouterTests.js b/services/real-time/test/acceptance/coffee/RouterTests.js index c3952a2887..6254eb5208 100644 --- a/services/real-time/test/acceptance/coffee/RouterTests.js +++ b/services/real-time/test/acceptance/coffee/RouterTests.js @@ -1,76 +1,101 @@ -async = require "async" -{expect} = require("chai") +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const async = require("async"); +const {expect} = require("chai"); -RealTimeClient = require "./helpers/RealTimeClient" -FixturesManager = require "./helpers/FixturesManager" +const RealTimeClient = require("./helpers/RealTimeClient"); +const FixturesManager = require("./helpers/FixturesManager"); -describe "Router", -> - describe "joinProject", -> - describe "when there is no callback provided", -> - after () -> - process.removeListener('unhandledRejection', @onUnhandled) +describe("Router", () => describe("joinProject", function() { + describe("when there is no callback provided", function() { + after(function() { + return process.removeListener('unhandledRejection', this.onUnhandled); + }); - before (done) -> - @onUnhandled = (error) -> - done(error) - process.on('unhandledRejection', @onUnhandled) - async.series [ - (cb) => - FixturesManager.setUpProject { - privilegeLevel: "owner" - project: { - name: "Test Project" - } - }, (e, {@project_id, @user_id}) => - cb(e) + before(function(done) { + this.onUnhandled = error => done(error); + process.on('unhandledRejection', this.onUnhandled); + return async.series([ + cb => { + return FixturesManager.setUpProject({ + privilegeLevel: "owner", + project: { + name: "Test Project" + } + }, (e, {project_id, user_id}) => { + this.project_id = project_id; + this.user_id = user_id; + return cb(e); + }); + }, - (cb) => - @client = RealTimeClient.connect() - @client.on "connectionAccepted", cb + cb => { + this.client = RealTimeClient.connect(); + return this.client.on("connectionAccepted", cb); + }, - (cb) => - @client = RealTimeClient.connect() - @client.on "connectionAccepted", cb + cb => { + this.client = RealTimeClient.connect(); + return this.client.on("connectionAccepted", cb); + }, - (cb) => - @client.emit "joinProject", project_id: @project_id - setTimeout(cb, 100) - ], done + cb => { + this.client.emit("joinProject", {project_id: this.project_id}); + return setTimeout(cb, 100); + } + ], done); + }); - it "should keep on going", -> - expect('still running').to.exist + return it("should keep on going", () => expect('still running').to.exist); + }); - describe "when there are too many arguments", -> - after () -> - process.removeListener('unhandledRejection', @onUnhandled) + return describe("when there are too many arguments", function() { + after(function() { + return process.removeListener('unhandledRejection', this.onUnhandled); + }); - before (done) -> - @onUnhandled = (error) -> - done(error) - process.on('unhandledRejection', @onUnhandled) - async.series [ - (cb) => - FixturesManager.setUpProject { - privilegeLevel: "owner" - project: { - name: "Test Project" - } - }, (e, {@project_id, @user_id}) => - cb(e) + before(function(done) { + this.onUnhandled = error => done(error); + process.on('unhandledRejection', this.onUnhandled); + return async.series([ + cb => { + return FixturesManager.setUpProject({ + privilegeLevel: "owner", + project: { + name: "Test Project" + } + }, (e, {project_id, user_id}) => { + this.project_id = project_id; + this.user_id = user_id; + return cb(e); + }); + }, - (cb) => - @client = RealTimeClient.connect() - @client.on "connectionAccepted", cb + cb => { + this.client = RealTimeClient.connect(); + return this.client.on("connectionAccepted", cb); + }, - (cb) => - @client = RealTimeClient.connect() - @client.on "connectionAccepted", cb + cb => { + this.client = RealTimeClient.connect(); + return this.client.on("connectionAccepted", cb); + }, - (cb) => - @client.emit "joinProject", 1, 2, 3, 4, 5, (@error) => - cb() - ], done + cb => { + return this.client.emit("joinProject", 1, 2, 3, 4, 5, error => { + this.error = error; + return cb(); + }); + } + ], done); + }); - it "should return an error message", -> - expect(@error.message).to.equal('unexpected arguments') + return it("should return an error message", function() { + return expect(this.error.message).to.equal('unexpected arguments'); + }); + }); +})); diff --git a/services/real-time/test/acceptance/coffee/SessionSocketsTests.js b/services/real-time/test/acceptance/coffee/SessionSocketsTests.js index 3009da682f..912e0912e5 100644 --- a/services/real-time/test/acceptance/coffee/SessionSocketsTests.js +++ b/services/real-time/test/acceptance/coffee/SessionSocketsTests.js @@ -1,67 +1,90 @@ -RealTimeClient = require("./helpers/RealTimeClient") -Settings = require("settings-sharelatex") -{expect} = require('chai') +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const RealTimeClient = require("./helpers/RealTimeClient"); +const Settings = require("settings-sharelatex"); +const {expect} = require('chai'); -describe 'SessionSockets', -> - before -> - @checkSocket = (fn) -> - client = RealTimeClient.connect() - client.on 'connectionAccepted', fn - client.on 'connectionRejected', fn - return null +describe('SessionSockets', function() { + before(function() { + return this.checkSocket = function(fn) { + const client = RealTimeClient.connect(); + client.on('connectionAccepted', fn); + client.on('connectionRejected', fn); + return null; + }; + }); - describe 'without cookies', -> - before -> - RealTimeClient.cookie = null + describe('without cookies', function() { + before(() => RealTimeClient.cookie = null); - it 'should return a lookup error', (done) -> - @checkSocket (error) -> - expect(error).to.exist - expect(error.message).to.equal('invalid session') - done() + return it('should return a lookup error', function(done) { + return this.checkSocket(function(error) { + expect(error).to.exist; + expect(error.message).to.equal('invalid session'); + return done(); + }); + }); + }); - describe 'with a different cookie', -> - before -> - RealTimeClient.cookie = "some.key=someValue" + describe('with a different cookie', function() { + before(() => RealTimeClient.cookie = "some.key=someValue"); - it 'should return a lookup error', (done) -> - @checkSocket (error) -> - expect(error).to.exist - expect(error.message).to.equal('invalid session') - done() + return it('should return a lookup error', function(done) { + return this.checkSocket(function(error) { + expect(error).to.exist; + expect(error.message).to.equal('invalid session'); + return done(); + }); + }); + }); - describe 'with an invalid cookie', -> - before (done) -> - RealTimeClient.setSession {}, (error) -> - return done(error) if error - RealTimeClient.cookie = "#{Settings.cookieName}=#{ + describe('with an invalid cookie', function() { + before(function(done) { + RealTimeClient.setSession({}, function(error) { + if (error) { return done(error); } + RealTimeClient.cookie = `${Settings.cookieName}=${ RealTimeClient.cookie.slice(17, 49) - }" - done() - return null + }`; + return done(); + }); + return null; + }); - it 'should return a lookup error', (done) -> - @checkSocket (error) -> - expect(error).to.exist - expect(error.message).to.equal('invalid session') - done() + return it('should return a lookup error', function(done) { + return this.checkSocket(function(error) { + expect(error).to.exist; + expect(error.message).to.equal('invalid session'); + return done(); + }); + }); + }); - describe 'with a valid cookie and no matching session', -> - before -> - RealTimeClient.cookie = "#{Settings.cookieName}=unknownId" + describe('with a valid cookie and no matching session', function() { + before(() => RealTimeClient.cookie = `${Settings.cookieName}=unknownId`); - it 'should return a lookup error', (done) -> - @checkSocket (error) -> - expect(error).to.exist - expect(error.message).to.equal('invalid session') - done() + return it('should return a lookup error', function(done) { + return this.checkSocket(function(error) { + expect(error).to.exist; + expect(error.message).to.equal('invalid session'); + return done(); + }); + }); + }); - describe 'with a valid cookie and a matching session', -> - before (done) -> - RealTimeClient.setSession({}, done) - return null + return describe('with a valid cookie and a matching session', function() { + before(function(done) { + RealTimeClient.setSession({}, done); + return null; + }); - it 'should not return an error', (done) -> - @checkSocket (error) -> - expect(error).to.not.exist - done() + return it('should not return an error', function(done) { + return this.checkSocket(function(error) { + expect(error).to.not.exist; + return done(); + }); + }); + }); +}); diff --git a/services/real-time/test/acceptance/coffee/SessionTests.js b/services/real-time/test/acceptance/coffee/SessionTests.js index 23c4e78ce9..b8da531875 100644 --- a/services/real-time/test/acceptance/coffee/SessionTests.js +++ b/services/real-time/test/acceptance/coffee/SessionTests.js @@ -1,35 +1,51 @@ -chai = require("chai") -expect = chai.expect +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const chai = require("chai"); +const { + expect +} = chai; -RealTimeClient = require "./helpers/RealTimeClient" +const RealTimeClient = require("./helpers/RealTimeClient"); -describe "Session", -> - describe "with an established session", -> - before (done) -> - @user_id = "mock-user-id" - RealTimeClient.setSession { - user: { _id: @user_id } - }, (error) => - throw error if error? - @client = RealTimeClient.connect() - return done() - return null +describe("Session", () => describe("with an established session", function() { + before(function(done) { + this.user_id = "mock-user-id"; + RealTimeClient.setSession({ + user: { _id: this.user_id } + }, error => { + if (error != null) { throw error; } + this.client = RealTimeClient.connect(); + return done(); + }); + return null; + }); - it "should not get disconnected", (done) -> - disconnected = false - @client.on "disconnect", () -> - disconnected = true - setTimeout () => - expect(disconnected).to.equal false - done() - , 500 - - it "should appear in the list of connected clients", (done) -> - RealTimeClient.getConnectedClients (error, clients) => - included = false - for client in clients - if client.client_id == @client.socket.sessionid - included = true - break - expect(included).to.equal true - done() + it("should not get disconnected", function(done) { + let disconnected = false; + this.client.on("disconnect", () => disconnected = true); + return setTimeout(() => { + expect(disconnected).to.equal(false); + return done(); + } + , 500); + }); + + return it("should appear in the list of connected clients", function(done) { + return RealTimeClient.getConnectedClients((error, clients) => { + let included = false; + for (let client of Array.from(clients)) { + if (client.client_id === this.client.socket.sessionid) { + included = true; + break; + } + } + expect(included).to.equal(true); + return done(); + }); + }); +})); diff --git a/services/real-time/test/acceptance/coffee/helpers/FixturesManager.js b/services/real-time/test/acceptance/coffee/helpers/FixturesManager.js index 0889b45c2a..bdae3e01e1 100644 --- a/services/real-time/test/acceptance/coffee/helpers/FixturesManager.js +++ b/services/real-time/test/acceptance/coffee/helpers/FixturesManager.js @@ -1,48 +1,67 @@ -RealTimeClient = require "./RealTimeClient" -MockWebServer = require "./MockWebServer" -MockDocUpdaterServer = require "./MockDocUpdaterServer" +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let FixturesManager; +const RealTimeClient = require("./RealTimeClient"); +const MockWebServer = require("./MockWebServer"); +const MockDocUpdaterServer = require("./MockDocUpdaterServer"); -module.exports = FixturesManager = - setUpProject: (options = {}, callback = (error, data) ->) -> - options.user_id ||= FixturesManager.getRandomId() - options.project_id ||= FixturesManager.getRandomId() - options.project ||= { name: "Test Project" } - {project_id, user_id, privilegeLevel, project, publicAccess} = options +module.exports = (FixturesManager = { + setUpProject(options, callback) { + if (options == null) { options = {}; } + if (callback == null) { callback = function(error, data) {}; } + if (!options.user_id) { options.user_id = FixturesManager.getRandomId(); } + if (!options.project_id) { options.project_id = FixturesManager.getRandomId(); } + if (!options.project) { options.project = { name: "Test Project" }; } + const {project_id, user_id, privilegeLevel, project, publicAccess} = options; - privileges = {} - privileges[user_id] = privilegeLevel - if publicAccess - privileges["anonymous-user"] = publicAccess + const privileges = {}; + privileges[user_id] = privilegeLevel; + if (publicAccess) { + privileges["anonymous-user"] = publicAccess; + } - MockWebServer.createMockProject(project_id, privileges, project) - MockWebServer.run (error) => - throw error if error? - RealTimeClient.setSession { + MockWebServer.createMockProject(project_id, privileges, project); + return MockWebServer.run(error => { + if (error != null) { throw error; } + return RealTimeClient.setSession({ user: { - _id: user_id - first_name: "Joe" + _id: user_id, + first_name: "Joe", last_name: "Bloggs" } - }, (error) => - throw error if error? - callback null, {project_id, user_id, privilegeLevel, project} + }, error => { + if (error != null) { throw error; } + return callback(null, {project_id, user_id, privilegeLevel, project}); + }); + }); + }, - setUpDoc: (project_id, options = {}, callback = (error, data) ->) -> - options.doc_id ||= FixturesManager.getRandomId() - options.lines ||= ["doc", "lines"] - options.version ||= 42 - options.ops ||= ["mock", "ops"] - {doc_id, lines, version, ops, ranges} = options + setUpDoc(project_id, options, callback) { + if (options == null) { options = {}; } + if (callback == null) { callback = function(error, data) {}; } + if (!options.doc_id) { options.doc_id = FixturesManager.getRandomId(); } + if (!options.lines) { options.lines = ["doc", "lines"]; } + if (!options.version) { options.version = 42; } + if (!options.ops) { options.ops = ["mock", "ops"]; } + const {doc_id, lines, version, ops, ranges} = options; - MockDocUpdaterServer.createMockDoc project_id, doc_id, {lines, version, ops, ranges} - MockDocUpdaterServer.run (error) => - throw error if error? - callback null, {project_id, doc_id, lines, version, ops} + MockDocUpdaterServer.createMockDoc(project_id, doc_id, {lines, version, ops, ranges}); + return MockDocUpdaterServer.run(error => { + if (error != null) { throw error; } + return callback(null, {project_id, doc_id, lines, version, ops}); + }); + }, - getRandomId: () -> + getRandomId() { return require("crypto") .createHash("sha1") .update(Math.random().toString()) .digest("hex") - .slice(0,24) + .slice(0,24); + } +}); \ No newline at end of file diff --git a/services/real-time/test/acceptance/coffee/helpers/MockDocUpdaterServer.js b/services/real-time/test/acceptance/coffee/helpers/MockDocUpdaterServer.js index ac5bfc7093..675c07a0ed 100644 --- a/services/real-time/test/acceptance/coffee/helpers/MockDocUpdaterServer.js +++ b/services/real-time/test/acceptance/coffee/helpers/MockDocUpdaterServer.js @@ -1,46 +1,65 @@ -sinon = require "sinon" -express = require "express" +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let MockDocUpdaterServer; +const sinon = require("sinon"); +const express = require("express"); -module.exports = MockDocUpdaterServer = - docs: {} +module.exports = (MockDocUpdaterServer = { + docs: {}, - createMockDoc: (project_id, doc_id, data) -> - MockDocUpdaterServer.docs["#{project_id}:#{doc_id}"] = data + createMockDoc(project_id, doc_id, data) { + return MockDocUpdaterServer.docs[`${project_id}:${doc_id}`] = data; + }, - getDocument: (project_id, doc_id, fromVersion, callback = (error, data) ->) -> - callback( - null, MockDocUpdaterServer.docs["#{project_id}:#{doc_id}"] - ) + getDocument(project_id, doc_id, fromVersion, callback) { + if (callback == null) { callback = function(error, data) {}; } + return callback( + null, MockDocUpdaterServer.docs[`${project_id}:${doc_id}`] + ); + }, - deleteProject: sinon.stub().callsArg(1) + deleteProject: sinon.stub().callsArg(1), - getDocumentRequest: (req, res, next) -> - {project_id, doc_id} = req.params - {fromVersion} = req.query - fromVersion = parseInt(fromVersion, 10) - MockDocUpdaterServer.getDocument project_id, doc_id, fromVersion, (error, data) -> - return next(error) if error? - res.json data + getDocumentRequest(req, res, next) { + const {project_id, doc_id} = req.params; + let {fromVersion} = req.query; + fromVersion = parseInt(fromVersion, 10); + return MockDocUpdaterServer.getDocument(project_id, doc_id, fromVersion, function(error, data) { + if (error != null) { return next(error); } + return res.json(data); + }); + }, - deleteProjectRequest: (req, res, next) -> - {project_id} = req.params - MockDocUpdaterServer.deleteProject project_id, (error) -> - return next(error) if error? - res.sendStatus 204 + deleteProjectRequest(req, res, next) { + const {project_id} = req.params; + return MockDocUpdaterServer.deleteProject(project_id, function(error) { + if (error != null) { return next(error); } + return res.sendStatus(204); + }); + }, - running: false - run: (callback = (error) ->) -> - if MockDocUpdaterServer.running - return callback() - app = express() - app.get "/project/:project_id/doc/:doc_id", MockDocUpdaterServer.getDocumentRequest - app.delete "/project/:project_id", MockDocUpdaterServer.deleteProjectRequest - app.listen 3003, (error) -> - MockDocUpdaterServer.running = true - callback(error) - .on "error", (error) -> - console.error "error starting MockDocUpdaterServer:", error.message - process.exit(1) + running: false, + run(callback) { + if (callback == null) { callback = function(error) {}; } + if (MockDocUpdaterServer.running) { + return callback(); + } + const app = express(); + app.get("/project/:project_id/doc/:doc_id", MockDocUpdaterServer.getDocumentRequest); + app.delete("/project/:project_id", MockDocUpdaterServer.deleteProjectRequest); + return app.listen(3003, function(error) { + MockDocUpdaterServer.running = true; + return callback(error); + }).on("error", function(error) { + console.error("error starting MockDocUpdaterServer:", error.message); + return process.exit(1); + }); + } +}); -sinon.spy MockDocUpdaterServer, "getDocument" +sinon.spy(MockDocUpdaterServer, "getDocument"); diff --git a/services/real-time/test/acceptance/coffee/helpers/MockWebServer.js b/services/real-time/test/acceptance/coffee/helpers/MockWebServer.js index 7c479c59bb..3fb8db33e7 100644 --- a/services/real-time/test/acceptance/coffee/helpers/MockWebServer.js +++ b/services/real-time/test/acceptance/coffee/helpers/MockWebServer.js @@ -1,46 +1,64 @@ -sinon = require "sinon" -express = require "express" +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let MockWebServer; +const sinon = require("sinon"); +const express = require("express"); -module.exports = MockWebServer = - projects: {} - privileges: {} +module.exports = (MockWebServer = { + projects: {}, + privileges: {}, - createMockProject: (project_id, privileges, project) -> - MockWebServer.privileges[project_id] = privileges - MockWebServer.projects[project_id] = project + createMockProject(project_id, privileges, project) { + MockWebServer.privileges[project_id] = privileges; + return MockWebServer.projects[project_id] = project; + }, - joinProject: (project_id, user_id, callback = (error, project, privilegeLevel) ->) -> - callback( + joinProject(project_id, user_id, callback) { + if (callback == null) { callback = function(error, project, privilegeLevel) {}; } + return callback( null, MockWebServer.projects[project_id], MockWebServer.privileges[project_id][user_id] - ) + ); + }, - joinProjectRequest: (req, res, next) -> - {project_id} = req.params - {user_id} = req.query - if project_id == 'rate-limited' - res.status(429).send() - else - MockWebServer.joinProject project_id, user_id, (error, project, privilegeLevel) -> - return next(error) if error? - res.json { - project: project - privilegeLevel: privilegeLevel - } + joinProjectRequest(req, res, next) { + const {project_id} = req.params; + const {user_id} = req.query; + if (project_id === 'rate-limited') { + return res.status(429).send(); + } else { + return MockWebServer.joinProject(project_id, user_id, function(error, project, privilegeLevel) { + if (error != null) { return next(error); } + return res.json({ + project, + privilegeLevel + }); + }); + } + }, - running: false - run: (callback = (error) ->) -> - if MockWebServer.running - return callback() - app = express() - app.post "/project/:project_id/join", MockWebServer.joinProjectRequest - app.listen 3000, (error) -> - MockWebServer.running = true - callback(error) - .on "error", (error) -> - console.error "error starting MockWebServer:", error.message - process.exit(1) + running: false, + run(callback) { + if (callback == null) { callback = function(error) {}; } + if (MockWebServer.running) { + return callback(); + } + const app = express(); + app.post("/project/:project_id/join", MockWebServer.joinProjectRequest); + return app.listen(3000, function(error) { + MockWebServer.running = true; + return callback(error); + }).on("error", function(error) { + console.error("error starting MockWebServer:", error.message); + return process.exit(1); + }); + } +}); -sinon.spy MockWebServer, "joinProject" +sinon.spy(MockWebServer, "joinProject"); diff --git a/services/real-time/test/acceptance/coffee/helpers/RealTimeClient.js b/services/real-time/test/acceptance/coffee/helpers/RealTimeClient.js index 7d54e23b3c..5fc8466a2a 100644 --- a/services/real-time/test/acceptance/coffee/helpers/RealTimeClient.js +++ b/services/real-time/test/acceptance/coffee/helpers/RealTimeClient.js @@ -1,75 +1,94 @@ -XMLHttpRequest = require("../../libs/XMLHttpRequest").XMLHttpRequest -io = require("socket.io-client") -async = require("async") +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let Client; +const { + XMLHttpRequest +} = require("../../libs/XMLHttpRequest"); +const io = require("socket.io-client"); +const async = require("async"); -request = require "request" -Settings = require "settings-sharelatex" -redis = require "redis-sharelatex" -rclient = redis.createClient(Settings.redis.websessions) +const request = require("request"); +const Settings = require("settings-sharelatex"); +const redis = require("redis-sharelatex"); +const rclient = redis.createClient(Settings.redis.websessions); -uid = require('uid-safe').sync -signature = require("cookie-signature") +const uid = require('uid-safe').sync; +const signature = require("cookie-signature"); -io.util.request = () -> - xhr = new XMLHttpRequest() - _open = xhr.open - xhr.open = () => - _open.apply(xhr, arguments) - if Client.cookie? - xhr.setRequestHeader("Cookie", Client.cookie) - return xhr +io.util.request = function() { + const xhr = new XMLHttpRequest(); + const _open = xhr.open; + xhr.open = function() { + _open.apply(xhr, arguments); + if (Client.cookie != null) { + return xhr.setRequestHeader("Cookie", Client.cookie); + } + }.bind(this); + return xhr; +}; -module.exports = Client = - cookie: null +module.exports = (Client = { + cookie: null, - setSession: (session, callback = (error) ->) -> - sessionId = uid(24) - session.cookie = {} - rclient.set "sess:" + sessionId, JSON.stringify(session), (error) -> - return callback(error) if error? - secret = Settings.security.sessionSecret - cookieKey = 's:' + signature.sign(sessionId, secret) - Client.cookie = "#{Settings.cookieName}=#{cookieKey}" - callback() + setSession(session, callback) { + if (callback == null) { callback = function(error) {}; } + const sessionId = uid(24); + session.cookie = {}; + return rclient.set("sess:" + sessionId, JSON.stringify(session), function(error) { + if (error != null) { return callback(error); } + const secret = Settings.security.sessionSecret; + const cookieKey = 's:' + signature.sign(sessionId, secret); + Client.cookie = `${Settings.cookieName}=${cookieKey}`; + return callback(); + }); + }, - unsetSession: (callback = (error) ->) -> - Client.cookie = null - callback() + unsetSession(callback) { + if (callback == null) { callback = function(error) {}; } + Client.cookie = null; + return callback(); + }, - connect: (cookie) -> - client = io.connect("http://localhost:3026", 'force new connection': true) - client.on 'connectionAccepted', (_, publicId) -> - client.publicId = publicId - return client + connect(cookie) { + const client = io.connect("http://localhost:3026", {'force new connection': true}); + client.on('connectionAccepted', (_, publicId) => client.publicId = publicId); + return client; + }, - getConnectedClients: (callback = (error, clients) ->) -> - request.get { - url: "http://localhost:3026/clients" + getConnectedClients(callback) { + if (callback == null) { callback = function(error, clients) {}; } + return request.get({ + url: "http://localhost:3026/clients", json: true - }, (error, response, data) -> - callback error, data + }, (error, response, data) => callback(error, data)); + }, - getConnectedClient: (client_id, callback = (error, clients) ->) -> - request.get { - url: "http://localhost:3026/clients/#{client_id}" + getConnectedClient(client_id, callback) { + if (callback == null) { callback = function(error, clients) {}; } + return request.get({ + url: `http://localhost:3026/clients/${client_id}`, json: true - }, (error, response, data) -> - callback error, data + }, (error, response, data) => callback(error, data)); + }, - disconnectClient: (client_id, callback) -> - request.post { - url: "http://localhost:3026/client/#{client_id}/disconnect" + disconnectClient(client_id, callback) { + request.post({ + url: `http://localhost:3026/client/${client_id}/disconnect`, auth: { user: Settings.internal.realTime.user, pass: Settings.internal.realTime.pass } - }, (error, response, data) -> - callback error, data - return null + }, (error, response, data) => callback(error, data)); + return null; + }, - disconnectAllClients: (callback) -> - Client.getConnectedClients (error, clients) -> - async.each clients, (clientView, cb) -> - Client.disconnectClient clientView.client_id, cb - , callback + disconnectAllClients(callback) { + return Client.getConnectedClients((error, clients) => async.each(clients, (clientView, cb) => Client.disconnectClient(clientView.client_id, cb) + , callback)); + } +}); diff --git a/services/real-time/test/acceptance/coffee/helpers/RealtimeServer.js b/services/real-time/test/acceptance/coffee/helpers/RealtimeServer.js index 3a721c18ed..7c97b003ef 100644 --- a/services/real-time/test/acceptance/coffee/helpers/RealtimeServer.js +++ b/services/real-time/test/acceptance/coffee/helpers/RealtimeServer.js @@ -1,23 +1,46 @@ -app = require('../../../../app') -logger = require("logger-sharelatex") -Settings = require("settings-sharelatex") +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS103: Rewrite code to no longer use __guard__ + * DS205: Consider reworking code to avoid use of IIFEs + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const app = require('../../../../app'); +const logger = require("logger-sharelatex"); +const Settings = require("settings-sharelatex"); -module.exports = - running: false - initing: false - callbacks: [] - ensureRunning: (callback = (error) ->) -> - if @running - return callback() - else if @initing - @callbacks.push callback - else - @initing = true - @callbacks.push callback - app.listen Settings.internal?.realtime?.port, "localhost", (error) => - throw error if error? - @running = true - logger.log("clsi running in dev mode") +module.exports = { + running: false, + initing: false, + callbacks: [], + ensureRunning(callback) { + if (callback == null) { callback = function(error) {}; } + if (this.running) { + return callback(); + } else if (this.initing) { + return this.callbacks.push(callback); + } else { + this.initing = true; + this.callbacks.push(callback); + return app.listen(__guard__(Settings.internal != null ? Settings.internal.realtime : undefined, x => x.port), "localhost", error => { + if (error != null) { throw error; } + this.running = true; + logger.log("clsi running in dev mode"); - for callback in @callbacks - callback() + return (() => { + const result = []; + for (callback of Array.from(this.callbacks)) { + result.push(callback()); + } + return result; + })(); + }); + } + } +}; + +function __guard__(value, transform) { + return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; +} \ No newline at end of file