diff --git a/services/document-updater/test/acceptance/coffee/ApplyingUpdatesToADocTests.js b/services/document-updater/test/acceptance/coffee/ApplyingUpdatesToADocTests.js index 489f8d98eb..b5259dc7d5 100644 --- a/services/document-updater/test/acceptance/coffee/ApplyingUpdatesToADocTests.js +++ b/services/document-updater/test/acceptance/coffee/ApplyingUpdatesToADocTests.js @@ -1,394 +1,499 @@ -sinon = require "sinon" -chai = require("chai") -chai.should() -expect = chai.expect -async = require "async" -Settings = require('settings-sharelatex') -rclient_history = require("redis-sharelatex").createClient(Settings.redis.history) # note: this is track changes, not project-history -rclient_project_history = require("redis-sharelatex").createClient(Settings.redis.project_history) -rclient_du = require("redis-sharelatex").createClient(Settings.redis.documentupdater) -Keys = Settings.redis.documentupdater.key_schema -HistoryKeys = Settings.redis.history.key_schema -ProjectHistoryKeys = Settings.redis.project_history.key_schema +/* + * 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 sinon = require("sinon"); +const chai = require("chai"); +chai.should(); +const { + expect +} = chai; +const async = require("async"); +const Settings = require('settings-sharelatex'); +const rclient_history = require("redis-sharelatex").createClient(Settings.redis.history); // note: this is track changes, not project-history +const rclient_project_history = require("redis-sharelatex").createClient(Settings.redis.project_history); +const rclient_du = require("redis-sharelatex").createClient(Settings.redis.documentupdater); +const Keys = Settings.redis.documentupdater.key_schema; +const HistoryKeys = Settings.redis.history.key_schema; +const ProjectHistoryKeys = Settings.redis.project_history.key_schema; -MockTrackChangesApi = require "./helpers/MockTrackChangesApi" -MockWebApi = require "./helpers/MockWebApi" -DocUpdaterClient = require "./helpers/DocUpdaterClient" -DocUpdaterApp = require "./helpers/DocUpdaterApp" +const MockTrackChangesApi = require("./helpers/MockTrackChangesApi"); +const MockWebApi = require("./helpers/MockWebApi"); +const DocUpdaterClient = require("./helpers/DocUpdaterClient"); +const DocUpdaterApp = require("./helpers/DocUpdaterApp"); -describe "Applying updates to a doc", -> - before (done) -> - @lines = ["one", "two", "three"] - @version = 42 - @update = - doc: @doc_id +describe("Applying updates to a doc", function() { + before(function(done) { + this.lines = ["one", "two", "three"]; + this.version = 42; + this.update = { + doc: this.doc_id, op: [{ - i: "one and a half\n" + i: "one and a half\n", p: 4 - }] - v: @version - @result = ["one", "one and a half", "two", "three"] - DocUpdaterApp.ensureRunning(done) + }], + v: this.version + }; + this.result = ["one", "one and a half", "two", "three"]; + return DocUpdaterApp.ensureRunning(done); + }); - describe "when the document is not loaded", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - sinon.spy MockWebApi, "getDocument" - @startTime = Date.now() - MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} - DocUpdaterClient.sendUpdate @project_id, @doc_id, @update, (error) -> - throw error if error? - setTimeout done, 200 - return null + describe("when the document is not loaded", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); + sinon.spy(MockWebApi, "getDocument"); + this.startTime = Date.now(); + MockWebApi.insertDoc(this.project_id, this.doc_id, {lines: this.lines, version: this.version}); + DocUpdaterClient.sendUpdate(this.project_id, this.doc_id, this.update, function(error) { + if (error != null) { throw error; } + return setTimeout(done, 200); + }); + return null; + }); - after -> - MockWebApi.getDocument.restore() + after(() => MockWebApi.getDocument.restore()); - it "should load the document from the web API", -> - MockWebApi.getDocument - .calledWith(@project_id, @doc_id) - .should.equal true + it("should load the document from the web API", function() { + return MockWebApi.getDocument + .calledWith(this.project_id, this.doc_id) + .should.equal(true); + }); - it "should update the doc", (done) -> - DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, doc) => - doc.lines.should.deep.equal @result - done() - return null + it("should update the doc", function(done) { + DocUpdaterClient.getDoc(this.project_id, this.doc_id, (error, res, doc) => { + doc.lines.should.deep.equal(this.result); + return done(); + }); + return null; + }); - it "should push the applied updates to the track changes api", (done) -> - rclient_history.lrange HistoryKeys.uncompressedHistoryOps({@doc_id}), 0, -1, (error, updates) => - throw error if error? - JSON.parse(updates[0]).op.should.deep.equal @update.op - rclient_history.sismember HistoryKeys.docsWithHistoryOps({@project_id}), @doc_id, (error, result) => - throw error if error? - result.should.equal 1 - done() - return null + it("should push the applied updates to the track changes api", function(done) { + rclient_history.lrange(HistoryKeys.uncompressedHistoryOps({doc_id: this.doc_id}), 0, -1, (error, updates) => { + if (error != null) { throw error; } + JSON.parse(updates[0]).op.should.deep.equal(this.update.op); + return rclient_history.sismember(HistoryKeys.docsWithHistoryOps({project_id: this.project_id}), this.doc_id, (error, result) => { + if (error != null) { throw error; } + result.should.equal(1); + return done(); + }); + }); + return null; + }); - it "should push the applied updates to the project history changes api", (done) -> - rclient_project_history.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) => - throw error if error? - JSON.parse(updates[0]).op.should.deep.equal @update.op - done() - return null + it("should push the applied updates to the project history changes api", function(done) { + rclient_project_history.lrange(ProjectHistoryKeys.projectHistoryOps({project_id: this.project_id}), 0, -1, (error, updates) => { + if (error != null) { throw error; } + JSON.parse(updates[0]).op.should.deep.equal(this.update.op); + return done(); + }); + return null; + }); - it "should set the first op timestamp", (done) -> - rclient_project_history.get ProjectHistoryKeys.projectHistoryFirstOpTimestamp({@project_id}), (error, result) => - throw error if error? - result.should.be.within(@startTime, Date.now()) - @firstOpTimestamp = result - done() - return null + it("should set the first op timestamp", function(done) { + rclient_project_history.get(ProjectHistoryKeys.projectHistoryFirstOpTimestamp({project_id: this.project_id}), (error, result) => { + if (error != null) { throw error; } + result.should.be.within(this.startTime, Date.now()); + this.firstOpTimestamp = result; + return done(); + }); + return null; + }); - describe "when sending another update", -> - before (done) -> - @timeout = 10000 - @second_update = Object.create(@update) - @second_update.v = @version + 1 - DocUpdaterClient.sendUpdate @project_id, @doc_id, @second_update, (error) -> - throw error if error? - setTimeout done, 200 - return null + return describe("when sending another update", function() { + before(function(done) { + this.timeout = 10000; + this.second_update = Object.create(this.update); + this.second_update.v = this.version + 1; + DocUpdaterClient.sendUpdate(this.project_id, this.doc_id, this.second_update, function(error) { + if (error != null) { throw error; } + return setTimeout(done, 200); + }); + return null; + }); - it "should not change the first op timestamp", (done) -> - rclient_project_history.get ProjectHistoryKeys.projectHistoryFirstOpTimestamp({@project_id}), (error, result) => - throw error if error? - result.should.equal @firstOpTimestamp - done() - return null + return it("should not change the first op timestamp", function(done) { + rclient_project_history.get(ProjectHistoryKeys.projectHistoryFirstOpTimestamp({project_id: this.project_id}), (error, result) => { + if (error != null) { throw error; } + result.should.equal(this.firstOpTimestamp); + return done(); + }); + return null; + }); + }); + }); - describe "when the document is loaded", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] + describe("when the document is loaded", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); - MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} - DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) => - throw error if error? - sinon.spy MockWebApi, "getDocument" - DocUpdaterClient.sendUpdate @project_id, @doc_id, @update, (error) -> - throw error if error? - setTimeout done, 200 - return null + MockWebApi.insertDoc(this.project_id, this.doc_id, {lines: this.lines, version: this.version}); + DocUpdaterClient.preloadDoc(this.project_id, this.doc_id, error => { + if (error != null) { throw error; } + sinon.spy(MockWebApi, "getDocument"); + return DocUpdaterClient.sendUpdate(this.project_id, this.doc_id, this.update, function(error) { + if (error != null) { throw error; } + return setTimeout(done, 200); + }); + }); + return null; + }); - after -> - MockWebApi.getDocument.restore() + after(() => MockWebApi.getDocument.restore()); - it "should not need to call the web api", -> - MockWebApi.getDocument.called.should.equal false + it("should not need to call the web api", () => MockWebApi.getDocument.called.should.equal(false)); - it "should update the doc", (done) -> - DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, doc) => - doc.lines.should.deep.equal @result - done() - return null + it("should update the doc", function(done) { + DocUpdaterClient.getDoc(this.project_id, this.doc_id, (error, res, doc) => { + doc.lines.should.deep.equal(this.result); + return done(); + }); + return null; + }); - it "should push the applied updates to the track changes api", (done) -> - rclient_history.lrange HistoryKeys.uncompressedHistoryOps({@doc_id}), 0, -1, (error, updates) => - JSON.parse(updates[0]).op.should.deep.equal @update.op - rclient_history.sismember HistoryKeys.docsWithHistoryOps({@project_id}), @doc_id, (error, result) => - result.should.equal 1 - done() - return null + it("should push the applied updates to the track changes api", function(done) { + rclient_history.lrange(HistoryKeys.uncompressedHistoryOps({doc_id: this.doc_id}), 0, -1, (error, updates) => { + JSON.parse(updates[0]).op.should.deep.equal(this.update.op); + return rclient_history.sismember(HistoryKeys.docsWithHistoryOps({project_id: this.project_id}), this.doc_id, (error, result) => { + result.should.equal(1); + return done(); + }); + }); + return null; + }); - it "should push the applied updates to the project history changes api", (done) -> - rclient_project_history.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) => - JSON.parse(updates[0]).op.should.deep.equal @update.op - done() - return null + return it("should push the applied updates to the project history changes api", function(done) { + rclient_project_history.lrange(ProjectHistoryKeys.projectHistoryOps({project_id: this.project_id}), 0, -1, (error, updates) => { + JSON.parse(updates[0]).op.should.deep.equal(this.update.op); + return done(); + }); + return null; + }); + }); - describe "when the document is loaded and is using project-history only", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] + describe("when the document is loaded and is using project-history only", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); - MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version, projectHistoryType: 'project-history'} - DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) => - throw error if error? - sinon.spy MockWebApi, "getDocument" - DocUpdaterClient.sendUpdate @project_id, @doc_id, @update, (error) -> - throw error if error? - setTimeout done, 200 - return null + MockWebApi.insertDoc(this.project_id, this.doc_id, {lines: this.lines, version: this.version, projectHistoryType: 'project-history'}); + DocUpdaterClient.preloadDoc(this.project_id, this.doc_id, error => { + if (error != null) { throw error; } + sinon.spy(MockWebApi, "getDocument"); + return DocUpdaterClient.sendUpdate(this.project_id, this.doc_id, this.update, function(error) { + if (error != null) { throw error; } + return setTimeout(done, 200); + }); + }); + return null; + }); - after -> - MockWebApi.getDocument.restore() + after(() => MockWebApi.getDocument.restore()); - it "should update the doc", (done) -> - DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, doc) => - doc.lines.should.deep.equal @result - done() - return null + it("should update the doc", function(done) { + DocUpdaterClient.getDoc(this.project_id, this.doc_id, (error, res, doc) => { + doc.lines.should.deep.equal(this.result); + return done(); + }); + return null; + }); - it "should not push any applied updates to the track changes api", (done) -> - rclient_history.lrange HistoryKeys.uncompressedHistoryOps({@doc_id}), 0, -1, (error, updates) => - updates.length.should.equal 0 - done() - return null + it("should not push any applied updates to the track changes api", function(done) { + rclient_history.lrange(HistoryKeys.uncompressedHistoryOps({doc_id: this.doc_id}), 0, -1, (error, updates) => { + updates.length.should.equal(0); + return done(); + }); + return null; + }); - it "should push the applied updates to the project history changes api", (done) -> - rclient_project_history.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) => - JSON.parse(updates[0]).op.should.deep.equal @update.op - done() - return null + return it("should push the applied updates to the project history changes api", function(done) { + rclient_project_history.lrange(ProjectHistoryKeys.projectHistoryOps({project_id: this.project_id}), 0, -1, (error, updates) => { + JSON.parse(updates[0]).op.should.deep.equal(this.update.op); + return done(); + }); + return null; + }); + }); - describe "when the document has been deleted", -> - describe "when the ops come in a single linear order", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - lines = ["", "", ""] - MockWebApi.insertDoc @project_id, @doc_id, {lines: lines, version: 0} - @updates = [ - { doc_id: @doc_id, v: 0, op: [i: "h", p: 0 ] } - { doc_id: @doc_id, v: 1, op: [i: "e", p: 1 ] } - { doc_id: @doc_id, v: 2, op: [i: "l", p: 2 ] } - { doc_id: @doc_id, v: 3, op: [i: "l", p: 3 ] } - { doc_id: @doc_id, v: 4, op: [i: "o", p: 4 ] } - { doc_id: @doc_id, v: 5, op: [i: " ", p: 5 ] } - { doc_id: @doc_id, v: 6, op: [i: "w", p: 6 ] } - { doc_id: @doc_id, v: 7, op: [i: "o", p: 7 ] } - { doc_id: @doc_id, v: 8, op: [i: "r", p: 8 ] } - { doc_id: @doc_id, v: 9, op: [i: "l", p: 9 ] } - { doc_id: @doc_id, v: 10, op: [i: "d", p: 10] } - ] - @my_result = ["hello world", "", ""] - done() + describe("when the document has been deleted", function() { + describe("when the ops come in a single linear order", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); + const lines = ["", "", ""]; + MockWebApi.insertDoc(this.project_id, this.doc_id, {lines, version: 0}); + this.updates = [ + { doc_id: this.doc_id, v: 0, op: [{i: "h", p: 0} ] }, + { doc_id: this.doc_id, v: 1, op: [{i: "e", p: 1} ] }, + { doc_id: this.doc_id, v: 2, op: [{i: "l", p: 2} ] }, + { doc_id: this.doc_id, v: 3, op: [{i: "l", p: 3} ] }, + { doc_id: this.doc_id, v: 4, op: [{i: "o", p: 4} ] }, + { doc_id: this.doc_id, v: 5, op: [{i: " ", p: 5} ] }, + { doc_id: this.doc_id, v: 6, op: [{i: "w", p: 6} ] }, + { doc_id: this.doc_id, v: 7, op: [{i: "o", p: 7} ] }, + { doc_id: this.doc_id, v: 8, op: [{i: "r", p: 8} ] }, + { doc_id: this.doc_id, v: 9, op: [{i: "l", p: 9} ] }, + { doc_id: this.doc_id, v: 10, op: [{i: "d", p: 10}] } + ]; + this.my_result = ["hello world", "", ""]; + return done(); + }); - it "should be able to continue applying updates when the project has been deleted", (done) -> - actions = [] - for update in @updates.slice(0,6) - do (update) => - actions.push (callback) => DocUpdaterClient.sendUpdate @project_id, @doc_id, update, callback - actions.push (callback) => DocUpdaterClient.deleteDoc @project_id, @doc_id, callback - for update in @updates.slice(6) - do (update) => - actions.push (callback) => DocUpdaterClient.sendUpdate @project_id, @doc_id, update, callback + it("should be able to continue applying updates when the project has been deleted", function(done) { + let update; + const actions = []; + for (update of Array.from(this.updates.slice(0,6))) { + (update => { + return actions.push(callback => DocUpdaterClient.sendUpdate(this.project_id, this.doc_id, update, callback)); + })(update); + } + actions.push(callback => DocUpdaterClient.deleteDoc(this.project_id, this.doc_id, callback)); + for (update of Array.from(this.updates.slice(6))) { + (update => { + return actions.push(callback => DocUpdaterClient.sendUpdate(this.project_id, this.doc_id, update, callback)); + })(update); + } - async.series actions, (error) => - throw error if error? - DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, doc) => - doc.lines.should.deep.equal @my_result - done() - return null + async.series(actions, error => { + if (error != null) { throw error; } + return DocUpdaterClient.getDoc(this.project_id, this.doc_id, (error, res, doc) => { + doc.lines.should.deep.equal(this.my_result); + return done(); + }); + }); + return null; + }); - it "should push the applied updates to the track changes api", (done) -> - rclient_history.lrange HistoryKeys.uncompressedHistoryOps({@doc_id}), 0, -1, (error, updates) => - updates = (JSON.parse(u) for u in updates) - for appliedUpdate, i in @updates - appliedUpdate.op.should.deep.equal updates[i].op + it("should push the applied updates to the track changes api", function(done) { + rclient_history.lrange(HistoryKeys.uncompressedHistoryOps({doc_id: this.doc_id}), 0, -1, (error, updates) => { + updates = (Array.from(updates).map((u) => JSON.parse(u))); + for (let i = 0; i < this.updates.length; i++) { + const appliedUpdate = this.updates[i]; + appliedUpdate.op.should.deep.equal(updates[i].op); + } - rclient_history.sismember HistoryKeys.docsWithHistoryOps({@project_id}), @doc_id, (error, result) => - result.should.equal 1 - done() - return null + return rclient_history.sismember(HistoryKeys.docsWithHistoryOps({project_id: this.project_id}), this.doc_id, (error, result) => { + result.should.equal(1); + return done(); + }); + }); + return null; + }); - it "should store the doc ops in the correct order", (done) -> - rclient_du.lrange Keys.docOps({doc_id: @doc_id}), 0, -1, (error, updates) => - updates = (JSON.parse(u) for u in updates) - for appliedUpdate, i in @updates - appliedUpdate.op.should.deep.equal updates[i].op - done() - return null + return it("should store the doc ops in the correct order", function(done) { + rclient_du.lrange(Keys.docOps({doc_id: this.doc_id}), 0, -1, (error, updates) => { + updates = (Array.from(updates).map((u) => JSON.parse(u))); + for (let i = 0; i < this.updates.length; i++) { + const appliedUpdate = this.updates[i]; + appliedUpdate.op.should.deep.equal(updates[i].op); + } + return done(); + }); + return null; + }); + }); - describe "when older ops come in after the delete", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - lines = ["", "", ""] - MockWebApi.insertDoc @project_id, @doc_id, {lines: lines, version: 0} - @updates = [ - { doc_id: @doc_id, v: 0, op: [i: "h", p: 0 ] } - { doc_id: @doc_id, v: 1, op: [i: "e", p: 1 ] } - { doc_id: @doc_id, v: 2, op: [i: "l", p: 2 ] } - { doc_id: @doc_id, v: 3, op: [i: "l", p: 3 ] } - { doc_id: @doc_id, v: 4, op: [i: "o", p: 4 ] } - { doc_id: @doc_id, v: 0, op: [i: "world", p: 1 ] } - ] - @my_result = ["hello", "world", ""] - done() + return describe("when older ops come in after the delete", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); + const lines = ["", "", ""]; + MockWebApi.insertDoc(this.project_id, this.doc_id, {lines, version: 0}); + this.updates = [ + { doc_id: this.doc_id, v: 0, op: [{i: "h", p: 0} ] }, + { doc_id: this.doc_id, v: 1, op: [{i: "e", p: 1} ] }, + { doc_id: this.doc_id, v: 2, op: [{i: "l", p: 2} ] }, + { doc_id: this.doc_id, v: 3, op: [{i: "l", p: 3} ] }, + { doc_id: this.doc_id, v: 4, op: [{i: "o", p: 4} ] }, + { doc_id: this.doc_id, v: 0, op: [{i: "world", p: 1} ] } + ]; + this.my_result = ["hello", "world", ""]; + return done(); + }); - it "should be able to continue applying updates when the project has been deleted", (done) -> - actions = [] - for update in @updates.slice(0,5) - do (update) => - actions.push (callback) => DocUpdaterClient.sendUpdate @project_id, @doc_id, update, callback - actions.push (callback) => DocUpdaterClient.deleteDoc @project_id, @doc_id, callback - for update in @updates.slice(5) - do (update) => - actions.push (callback) => DocUpdaterClient.sendUpdate @project_id, @doc_id, update, callback + return it("should be able to continue applying updates when the project has been deleted", function(done) { + let update; + const actions = []; + for (update of Array.from(this.updates.slice(0,5))) { + (update => { + return actions.push(callback => DocUpdaterClient.sendUpdate(this.project_id, this.doc_id, update, callback)); + })(update); + } + actions.push(callback => DocUpdaterClient.deleteDoc(this.project_id, this.doc_id, callback)); + for (update of Array.from(this.updates.slice(5))) { + (update => { + return actions.push(callback => DocUpdaterClient.sendUpdate(this.project_id, this.doc_id, update, callback)); + })(update); + } - async.series actions, (error) => - throw error if error? - DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, doc) => - doc.lines.should.deep.equal @my_result - done() - return null + async.series(actions, error => { + if (error != null) { throw error; } + return DocUpdaterClient.getDoc(this.project_id, this.doc_id, (error, res, doc) => { + doc.lines.should.deep.equal(this.my_result); + return done(); + }); + }); + return null; + }); + }); + }); - describe "with a broken update", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - @broken_update = { doc_id: @doc_id, v: @version, op: [d: "not the correct content", p: 0 ] } - MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} + describe("with a broken update", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); + this.broken_update = { doc_id: this.doc_id, v: this.version, op: [{d: "not the correct content", p: 0} ] }; + MockWebApi.insertDoc(this.project_id, this.doc_id, {lines: this.lines, version: this.version}); - DocUpdaterClient.subscribeToAppliedOps @messageCallback = sinon.stub() + DocUpdaterClient.subscribeToAppliedOps(this.messageCallback = sinon.stub()); - DocUpdaterClient.sendUpdate @project_id, @doc_id, @broken_update, (error) -> - throw error if error? - setTimeout done, 200 - return null + DocUpdaterClient.sendUpdate(this.project_id, this.doc_id, this.broken_update, function(error) { + if (error != null) { throw error; } + return setTimeout(done, 200); + }); + return null; + }); - it "should not update the doc", (done) -> - DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, doc) => - doc.lines.should.deep.equal @lines - done() - return null + it("should not update the doc", function(done) { + DocUpdaterClient.getDoc(this.project_id, this.doc_id, (error, res, doc) => { + doc.lines.should.deep.equal(this.lines); + return done(); + }); + return null; + }); - it "should send a message with an error", -> - @messageCallback.called.should.equal true - [channel, message] = @messageCallback.args[0] - channel.should.equal "applied-ops" - JSON.parse(message).should.deep.include { - project_id: @project_id, - doc_id: @doc_id, + return it("should send a message with an error", function() { + this.messageCallback.called.should.equal(true); + const [channel, message] = Array.from(this.messageCallback.args[0]); + channel.should.equal("applied-ops"); + return JSON.parse(message).should.deep.include({ + project_id: this.project_id, + doc_id: this.doc_id, error:'Delete component does not match' + }); + }); +}); + + describe("with enough updates to flush to the track changes api", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); + const updates = []; + for (let v = 0; v <= 199; v++) { // Should flush after 100 ops + updates.push({ + doc_id: this.doc_id, + op: [{i: v.toString(), p: 0}], + v + }); } - describe "with enough updates to flush to the track changes api", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - updates = [] - for v in [0..199] # Should flush after 100 ops - updates.push - doc_id: @doc_id, - op: [i: v.toString(), p: 0] - v: v + sinon.spy(MockTrackChangesApi, "flushDoc"); - sinon.spy MockTrackChangesApi, "flushDoc" + MockWebApi.insertDoc(this.project_id, this.doc_id, {lines: this.lines, version: 0}); - MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: 0} - - # Send updates in chunks to causes multiple flushes - actions = [] - for i in [0..19] - do (i) => - actions.push (cb) => - DocUpdaterClient.sendUpdates @project_id, @doc_id, updates.slice(i*10, (i+1)*10), cb - async.series actions, (error) => - throw error if error? - setTimeout done, 2000 - return null - - after -> - MockTrackChangesApi.flushDoc.restore() - - it "should flush the doc twice", -> - MockTrackChangesApi.flushDoc.calledTwice.should.equal true - - describe "when there is no version in Mongo", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - MockWebApi.insertDoc @project_id, @doc_id, { - lines: @lines + // Send updates in chunks to causes multiple flushes + const actions = []; + for (let i = 0; i <= 19; i++) { + (i => { + return actions.push(cb => { + return DocUpdaterClient.sendUpdates(this.project_id, this.doc_id, updates.slice(i*10, (i+1)*10), cb); + }); + })(i); } + async.series(actions, error => { + if (error != null) { throw error; } + return setTimeout(done, 2000); + }); + return null; + }); - update = - doc: @doc_id - op: @update.op + after(() => MockTrackChangesApi.flushDoc.restore()); + + return it("should flush the doc twice", () => MockTrackChangesApi.flushDoc.calledTwice.should.equal(true)); + }); + + describe("when there is no version in Mongo", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); + MockWebApi.insertDoc(this.project_id, this.doc_id, { + lines: this.lines + }); + + const update = { + doc: this.doc_id, + op: this.update.op, v: 0 - DocUpdaterClient.sendUpdate @project_id, @doc_id, update, (error) -> - throw error if error? - setTimeout done, 200 - return null + }; + DocUpdaterClient.sendUpdate(this.project_id, this.doc_id, update, function(error) { + if (error != null) { throw error; } + return setTimeout(done, 200); + }); + return null; + }); - it "should update the doc (using version = 0)", (done) -> - DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, doc) => - doc.lines.should.deep.equal @result - done() - return null + return it("should update the doc (using version = 0)", function(done) { + DocUpdaterClient.getDoc(this.project_id, this.doc_id, (error, res, doc) => { + doc.lines.should.deep.equal(this.result); + return done(); + }); + return null; + }); + }); - describe "when the sending duplicate ops", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} + return describe("when the sending duplicate ops", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); + MockWebApi.insertDoc(this.project_id, this.doc_id, {lines: this.lines, version: this.version}); - DocUpdaterClient.subscribeToAppliedOps @messageCallback = sinon.stub() + DocUpdaterClient.subscribeToAppliedOps(this.messageCallback = sinon.stub()); - # One user delete 'one', the next turns it into 'once'. The second becomes a NOP. - DocUpdaterClient.sendUpdate @project_id, @doc_id, { - doc: @doc_id + // One user delete 'one', the next turns it into 'once'. The second becomes a NOP. + DocUpdaterClient.sendUpdate(this.project_id, this.doc_id, { + doc: this.doc_id, op: [{ - i: "one and a half\n" + i: "one and a half\n", p: 4 - }] - v: @version - meta: + }], + v: this.version, + meta: { source: "ikHceq3yfAdQYzBo4-xZ" - }, (error) => - throw error if error? - setTimeout () => - DocUpdaterClient.sendUpdate @project_id, @doc_id, { - doc: @doc_id + } + }, error => { + if (error != null) { throw error; } + return setTimeout(() => { + return DocUpdaterClient.sendUpdate(this.project_id, this.doc_id, { + doc: this.doc_id, op: [{ - i: "one and a half\n" + i: "one and a half\n", p: 4 - }] - v: @version - dupIfSource: ["ikHceq3yfAdQYzBo4-xZ"] - meta: + }], + v: this.version, + dupIfSource: ["ikHceq3yfAdQYzBo4-xZ"], + meta: { source: "ikHceq3yfAdQYzBo4-xZ" - }, (error) => - throw error if error? - setTimeout done, 200 - , 200 - return null + } + }, error => { + if (error != null) { throw error; } + return setTimeout(done, 200); + }); + } + , 200); + }); + return null; + }); - it "should update the doc", (done) -> - DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, doc) => - doc.lines.should.deep.equal @result - done() - return null + it("should update the doc", function(done) { + DocUpdaterClient.getDoc(this.project_id, this.doc_id, (error, res, doc) => { + doc.lines.should.deep.equal(this.result); + return done(); + }); + return null; + }); - it "should return a message about duplicate ops", -> - @messageCallback.calledTwice.should.equal true - @messageCallback.args[0][0].should.equal "applied-ops" - expect(JSON.parse(@messageCallback.args[0][1]).op.dup).to.be.undefined - @messageCallback.args[1][0].should.equal "applied-ops" - expect(JSON.parse(@messageCallback.args[1][1]).op.dup).to.equal true + return it("should return a message about duplicate ops", function() { + this.messageCallback.calledTwice.should.equal(true); + this.messageCallback.args[0][0].should.equal("applied-ops"); + expect(JSON.parse(this.messageCallback.args[0][1]).op.dup).to.be.undefined; + this.messageCallback.args[1][0].should.equal("applied-ops"); + return expect(JSON.parse(this.messageCallback.args[1][1]).op.dup).to.equal(true); + }); + }); +}); diff --git a/services/document-updater/test/acceptance/coffee/ApplyingUpdatesToProjectStructureTests.js b/services/document-updater/test/acceptance/coffee/ApplyingUpdatesToProjectStructureTests.js index e18aa2e6a1..3875cf28d1 100644 --- a/services/document-updater/test/acceptance/coffee/ApplyingUpdatesToProjectStructureTests.js +++ b/services/document-updater/test/acceptance/coffee/ApplyingUpdatesToProjectStructureTests.js @@ -1,300 +1,363 @@ -sinon = require "sinon" -chai = require("chai") -chai.should() -Settings = require('settings-sharelatex') -rclient_project_history = require("redis-sharelatex").createClient(Settings.redis.project_history) -ProjectHistoryKeys = Settings.redis.project_history.key_schema +/* + * 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 sinon = require("sinon"); +const chai = require("chai"); +chai.should(); +const Settings = require('settings-sharelatex'); +const rclient_project_history = require("redis-sharelatex").createClient(Settings.redis.project_history); +const ProjectHistoryKeys = Settings.redis.project_history.key_schema; -MockProjectHistoryApi = require "./helpers/MockProjectHistoryApi" -MockWebApi = require "./helpers/MockWebApi" -DocUpdaterClient = require "./helpers/DocUpdaterClient" -DocUpdaterApp = require "./helpers/DocUpdaterApp" +const MockProjectHistoryApi = require("./helpers/MockProjectHistoryApi"); +const MockWebApi = require("./helpers/MockWebApi"); +const DocUpdaterClient = require("./helpers/DocUpdaterClient"); +const DocUpdaterApp = require("./helpers/DocUpdaterApp"); -describe "Applying updates to a project's structure", -> - before -> - @user_id = 'user-id-123' - @version = 1234 +describe("Applying updates to a project's structure", function() { + before(function() { + this.user_id = 'user-id-123'; + return this.version = 1234; + }); - describe "renaming a file", -> - before (done) -> - @project_id = DocUpdaterClient.randomId() - @fileUpdate = - id: DocUpdaterClient.randomId() - pathname: '/file-path' + describe("renaming a file", function() { + before(function(done) { + this.project_id = DocUpdaterClient.randomId(); + this.fileUpdate = { + id: DocUpdaterClient.randomId(), + pathname: '/file-path', newPathname: '/new-file-path' - @fileUpdates = [ @fileUpdate ] - DocUpdaterApp.ensureRunning (error) => - throw error if error? - DocUpdaterClient.sendProjectUpdate @project_id, @user_id, [], @fileUpdates, @version, (error) -> - throw error if error? - setTimeout done, 200 + }; + this.fileUpdates = [ this.fileUpdate ]; + return DocUpdaterApp.ensureRunning(error => { + if (error != null) { throw error; } + return DocUpdaterClient.sendProjectUpdate(this.project_id, this.user_id, [], this.fileUpdates, this.version, function(error) { + if (error != null) { throw error; } + return setTimeout(done, 200); + }); + }); + }); - it "should push the applied file renames to the project history api", (done) -> - rclient_project_history.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) => - throw error if error? + return it("should push the applied file renames to the project history api", function(done) { + rclient_project_history.lrange(ProjectHistoryKeys.projectHistoryOps({project_id: this.project_id}), 0, -1, (error, updates) => { + if (error != null) { throw error; } - update = JSON.parse(updates[0]) - update.file.should.equal @fileUpdate.id - update.pathname.should.equal '/file-path' - update.new_pathname.should.equal '/new-file-path' - update.meta.user_id.should.equal @user_id - update.meta.ts.should.be.a('string') - update.version.should.equal "#{@version}.0" + const update = JSON.parse(updates[0]); + update.file.should.equal(this.fileUpdate.id); + update.pathname.should.equal('/file-path'); + update.new_pathname.should.equal('/new-file-path'); + update.meta.user_id.should.equal(this.user_id); + update.meta.ts.should.be.a('string'); + update.version.should.equal(`${this.version}.0`); - done() - return null + return done(); + }); + return null; + }); + }); - describe "renaming a document", -> - before -> - @docUpdate = - id: DocUpdaterClient.randomId() - pathname: '/doc-path' + describe("renaming a document", function() { + before(function() { + this.docUpdate = { + id: DocUpdaterClient.randomId(), + pathname: '/doc-path', newPathname: '/new-doc-path' - @docUpdates = [ @docUpdate ] + }; + return this.docUpdates = [ this.docUpdate ];}); - describe "when the document is not loaded", -> - before (done) -> - @project_id = DocUpdaterClient.randomId() - DocUpdaterClient.sendProjectUpdate @project_id, @user_id, @docUpdates, [], @version, (error) -> - throw error if error? - setTimeout done, 200 - return null + describe("when the document is not loaded", function() { + before(function(done) { + this.project_id = DocUpdaterClient.randomId(); + DocUpdaterClient.sendProjectUpdate(this.project_id, this.user_id, this.docUpdates, [], this.version, function(error) { + if (error != null) { throw error; } + return setTimeout(done, 200); + }); + return null; + }); - it "should push the applied doc renames to the project history api", (done) -> - rclient_project_history.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) => - throw error if error? + return it("should push the applied doc renames to the project history api", function(done) { + rclient_project_history.lrange(ProjectHistoryKeys.projectHistoryOps({project_id: this.project_id}), 0, -1, (error, updates) => { + if (error != null) { throw error; } - update = JSON.parse(updates[0]) - update.doc.should.equal @docUpdate.id - update.pathname.should.equal '/doc-path' - update.new_pathname.should.equal '/new-doc-path' - update.meta.user_id.should.equal @user_id - update.meta.ts.should.be.a('string') - update.version.should.equal "#{@version}.0" + const update = JSON.parse(updates[0]); + update.doc.should.equal(this.docUpdate.id); + update.pathname.should.equal('/doc-path'); + update.new_pathname.should.equal('/new-doc-path'); + update.meta.user_id.should.equal(this.user_id); + update.meta.ts.should.be.a('string'); + update.version.should.equal(`${this.version}.0`); - done() - return null + return done(); + }); + return null; + }); + }); - describe "when the document is loaded", -> - before (done) -> - @project_id = DocUpdaterClient.randomId() - MockWebApi.insertDoc @project_id, @docUpdate.id, {} - DocUpdaterClient.preloadDoc @project_id, @docUpdate.id, (error) => - throw error if error? - sinon.spy MockWebApi, "getDocument" - DocUpdaterClient.sendProjectUpdate @project_id, @user_id, @docUpdates, [], @version, (error) -> - throw error if error? - setTimeout done, 200 - return null + return describe("when the document is loaded", function() { + before(function(done) { + this.project_id = DocUpdaterClient.randomId(); + MockWebApi.insertDoc(this.project_id, this.docUpdate.id, {}); + DocUpdaterClient.preloadDoc(this.project_id, this.docUpdate.id, error => { + if (error != null) { throw error; } + sinon.spy(MockWebApi, "getDocument"); + return DocUpdaterClient.sendProjectUpdate(this.project_id, this.user_id, this.docUpdates, [], this.version, function(error) { + if (error != null) { throw error; } + return setTimeout(done, 200); + }); + }); + return null; + }); - after -> - MockWebApi.getDocument.restore() + after(() => MockWebApi.getDocument.restore()); - it "should update the doc", (done) -> - DocUpdaterClient.getDoc @project_id, @docUpdate.id, (error, res, doc) => - doc.pathname.should.equal @docUpdate.newPathname - done() - return null + it("should update the doc", function(done) { + DocUpdaterClient.getDoc(this.project_id, this.docUpdate.id, (error, res, doc) => { + doc.pathname.should.equal(this.docUpdate.newPathname); + return done(); + }); + return null; + }); - it "should push the applied doc renames to the project history api", (done) -> - rclient_project_history.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) => - throw error if error? + return it("should push the applied doc renames to the project history api", function(done) { + rclient_project_history.lrange(ProjectHistoryKeys.projectHistoryOps({project_id: this.project_id}), 0, -1, (error, updates) => { + if (error != null) { throw error; } - update = JSON.parse(updates[0]) - update.doc.should.equal @docUpdate.id - update.pathname.should.equal '/doc-path' - update.new_pathname.should.equal '/new-doc-path' - update.meta.user_id.should.equal @user_id - update.meta.ts.should.be.a('string') - update.version.should.equal "#{@version}.0" + const update = JSON.parse(updates[0]); + update.doc.should.equal(this.docUpdate.id); + update.pathname.should.equal('/doc-path'); + update.new_pathname.should.equal('/new-doc-path'); + update.meta.user_id.should.equal(this.user_id); + update.meta.ts.should.be.a('string'); + update.version.should.equal(`${this.version}.0`); - done() - return null + return done(); + }); + return null; + }); + }); + }); - describe "renaming multiple documents and files", -> - before -> - @docUpdate0 = - id: DocUpdaterClient.randomId() - pathname: '/doc-path0' + describe("renaming multiple documents and files", function() { + before(function() { + this.docUpdate0 = { + id: DocUpdaterClient.randomId(), + pathname: '/doc-path0', newPathname: '/new-doc-path0' - @docUpdate1 = - id: DocUpdaterClient.randomId() - pathname: '/doc-path1' + }; + this.docUpdate1 = { + id: DocUpdaterClient.randomId(), + pathname: '/doc-path1', newPathname: '/new-doc-path1' - @docUpdates = [ @docUpdate0, @docUpdate1 ] - @fileUpdate0 = - id: DocUpdaterClient.randomId() - pathname: '/file-path0' + }; + this.docUpdates = [ this.docUpdate0, this.docUpdate1 ]; + this.fileUpdate0 = { + id: DocUpdaterClient.randomId(), + pathname: '/file-path0', newPathname: '/new-file-path0' - @fileUpdate1 = - id: DocUpdaterClient.randomId() - pathname: '/file-path1' + }; + this.fileUpdate1 = { + id: DocUpdaterClient.randomId(), + pathname: '/file-path1', newPathname: '/new-file-path1' - @fileUpdates = [ @fileUpdate0, @fileUpdate1 ] + }; + return this.fileUpdates = [ this.fileUpdate0, this.fileUpdate1 ];}); - describe "when the documents are not loaded", -> - before (done) -> - @project_id = DocUpdaterClient.randomId() - DocUpdaterClient.sendProjectUpdate @project_id, @user_id, @docUpdates, @fileUpdates, @version, (error) -> - throw error if error? - setTimeout done, 200 - return null + return describe("when the documents are not loaded", function() { + before(function(done) { + this.project_id = DocUpdaterClient.randomId(); + DocUpdaterClient.sendProjectUpdate(this.project_id, this.user_id, this.docUpdates, this.fileUpdates, this.version, function(error) { + if (error != null) { throw error; } + return setTimeout(done, 200); + }); + return null; + }); - it "should push the applied doc renames to the project history api", (done) -> - rclient_project_history.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) => - throw error if error? + return it("should push the applied doc renames to the project history api", function(done) { + rclient_project_history.lrange(ProjectHistoryKeys.projectHistoryOps({project_id: this.project_id}), 0, -1, (error, updates) => { + if (error != null) { throw error; } - update = JSON.parse(updates[0]) - update.doc.should.equal @docUpdate0.id - update.pathname.should.equal '/doc-path0' - update.new_pathname.should.equal '/new-doc-path0' - update.meta.user_id.should.equal @user_id - update.meta.ts.should.be.a('string') - update.version.should.equal "#{@version}.0" + let update = JSON.parse(updates[0]); + update.doc.should.equal(this.docUpdate0.id); + update.pathname.should.equal('/doc-path0'); + update.new_pathname.should.equal('/new-doc-path0'); + update.meta.user_id.should.equal(this.user_id); + update.meta.ts.should.be.a('string'); + update.version.should.equal(`${this.version}.0`); - update = JSON.parse(updates[1]) - update.doc.should.equal @docUpdate1.id - update.pathname.should.equal '/doc-path1' - update.new_pathname.should.equal '/new-doc-path1' - update.meta.user_id.should.equal @user_id - update.meta.ts.should.be.a('string') - update.version.should.equal "#{@version}.1" + update = JSON.parse(updates[1]); + update.doc.should.equal(this.docUpdate1.id); + update.pathname.should.equal('/doc-path1'); + update.new_pathname.should.equal('/new-doc-path1'); + update.meta.user_id.should.equal(this.user_id); + update.meta.ts.should.be.a('string'); + update.version.should.equal(`${this.version}.1`); - update = JSON.parse(updates[2]) - update.file.should.equal @fileUpdate0.id - update.pathname.should.equal '/file-path0' - update.new_pathname.should.equal '/new-file-path0' - update.meta.user_id.should.equal @user_id - update.meta.ts.should.be.a('string') - update.version.should.equal "#{@version}.2" + update = JSON.parse(updates[2]); + update.file.should.equal(this.fileUpdate0.id); + update.pathname.should.equal('/file-path0'); + update.new_pathname.should.equal('/new-file-path0'); + update.meta.user_id.should.equal(this.user_id); + update.meta.ts.should.be.a('string'); + update.version.should.equal(`${this.version}.2`); - update = JSON.parse(updates[3]) - update.file.should.equal @fileUpdate1.id - update.pathname.should.equal '/file-path1' - update.new_pathname.should.equal '/new-file-path1' - update.meta.user_id.should.equal @user_id - update.meta.ts.should.be.a('string') - update.version.should.equal "#{@version}.3" + update = JSON.parse(updates[3]); + update.file.should.equal(this.fileUpdate1.id); + update.pathname.should.equal('/file-path1'); + update.new_pathname.should.equal('/new-file-path1'); + update.meta.user_id.should.equal(this.user_id); + update.meta.ts.should.be.a('string'); + update.version.should.equal(`${this.version}.3`); - done() - return null + return done(); + }); + return null; + }); + }); + }); - describe "adding a file", -> - before (done) -> - @project_id = DocUpdaterClient.randomId() - @fileUpdate = - id: DocUpdaterClient.randomId() - pathname: '/file-path' + describe("adding a file", function() { + before(function(done) { + this.project_id = DocUpdaterClient.randomId(); + this.fileUpdate = { + id: DocUpdaterClient.randomId(), + pathname: '/file-path', url: 'filestore.example.com' - @fileUpdates = [ @fileUpdate ] - DocUpdaterClient.sendProjectUpdate @project_id, @user_id, [], @fileUpdates, @version, (error) -> - throw error if error? - setTimeout done, 200 - return null + }; + this.fileUpdates = [ this.fileUpdate ]; + DocUpdaterClient.sendProjectUpdate(this.project_id, this.user_id, [], this.fileUpdates, this.version, function(error) { + if (error != null) { throw error; } + return setTimeout(done, 200); + }); + return null; + }); - it "should push the file addition to the project history api", (done) -> - rclient_project_history.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) => - throw error if error? + return it("should push the file addition to the project history api", function(done) { + rclient_project_history.lrange(ProjectHistoryKeys.projectHistoryOps({project_id: this.project_id}), 0, -1, (error, updates) => { + if (error != null) { throw error; } - update = JSON.parse(updates[0]) - update.file.should.equal @fileUpdate.id - update.pathname.should.equal '/file-path' - update.url.should.equal 'filestore.example.com' - update.meta.user_id.should.equal @user_id - update.meta.ts.should.be.a('string') - update.version.should.equal "#{@version}.0" + const update = JSON.parse(updates[0]); + update.file.should.equal(this.fileUpdate.id); + update.pathname.should.equal('/file-path'); + update.url.should.equal('filestore.example.com'); + update.meta.user_id.should.equal(this.user_id); + update.meta.ts.should.be.a('string'); + update.version.should.equal(`${this.version}.0`); - done() - return null + return done(); + }); + return null; + }); + }); - describe "adding a doc", -> - before (done) -> - @project_id = DocUpdaterClient.randomId() - @docUpdate = - id: DocUpdaterClient.randomId() - pathname: '/file-path' + describe("adding a doc", function() { + before(function(done) { + this.project_id = DocUpdaterClient.randomId(); + this.docUpdate = { + id: DocUpdaterClient.randomId(), + pathname: '/file-path', docLines: 'a\nb' - @docUpdates = [ @docUpdate ] - DocUpdaterClient.sendProjectUpdate @project_id, @user_id, @docUpdates, [], @version, (error) -> - throw error if error? - setTimeout done, 200 - return null + }; + this.docUpdates = [ this.docUpdate ]; + DocUpdaterClient.sendProjectUpdate(this.project_id, this.user_id, this.docUpdates, [], this.version, function(error) { + if (error != null) { throw error; } + return setTimeout(done, 200); + }); + return null; + }); - it "should push the doc addition to the project history api", (done) -> - rclient_project_history.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) => - throw error if error? + return it("should push the doc addition to the project history api", function(done) { + rclient_project_history.lrange(ProjectHistoryKeys.projectHistoryOps({project_id: this.project_id}), 0, -1, (error, updates) => { + if (error != null) { throw error; } - update = JSON.parse(updates[0]) - update.doc.should.equal @docUpdate.id - update.pathname.should.equal '/file-path' - update.docLines.should.equal 'a\nb' - update.meta.user_id.should.equal @user_id - update.meta.ts.should.be.a('string') - update.version.should.equal "#{@version}.0" + const update = JSON.parse(updates[0]); + update.doc.should.equal(this.docUpdate.id); + update.pathname.should.equal('/file-path'); + update.docLines.should.equal('a\nb'); + update.meta.user_id.should.equal(this.user_id); + update.meta.ts.should.be.a('string'); + update.version.should.equal(`${this.version}.0`); - done() - return null + return done(); + }); + return null; + }); + }); - describe "with enough updates to flush to the history service", -> - before (done) -> - @project_id = DocUpdaterClient.randomId() - @user_id = DocUpdaterClient.randomId() - @version0 = 12345 - @version1 = @version0 + 1 - updates = [] - for v in [0..599] # Should flush after 500 ops - updates.push + describe("with enough updates to flush to the history service", function() { + before(function(done) { + this.project_id = DocUpdaterClient.randomId(); + this.user_id = DocUpdaterClient.randomId(); + this.version0 = 12345; + this.version1 = this.version0 + 1; + const updates = []; + for (let v = 0; v <= 599; v++) { // Should flush after 500 ops + updates.push({ id: DocUpdaterClient.randomId(), - pathname: '/file-' + v + pathname: '/file-' + v, docLines: 'a\nb' + }); + } - sinon.spy MockProjectHistoryApi, "flushProject" + sinon.spy(MockProjectHistoryApi, "flushProject"); - # Send updates in chunks to causes multiple flushes - projectId = @project_id - userId = @project_id - DocUpdaterClient.sendProjectUpdate projectId, userId, updates.slice(0, 250), [], @version0, (error) -> - throw error if error? - DocUpdaterClient.sendProjectUpdate projectId, userId, updates.slice(250), [], @version1, (error) -> - throw error if error? - setTimeout done, 2000 - return null + // Send updates in chunks to causes multiple flushes + const projectId = this.project_id; + const userId = this.project_id; + DocUpdaterClient.sendProjectUpdate(projectId, userId, updates.slice(0, 250), [], this.version0, function(error) { + if (error != null) { throw error; } + return DocUpdaterClient.sendProjectUpdate(projectId, userId, updates.slice(250), [], this.version1, function(error) { + if (error != null) { throw error; } + return setTimeout(done, 2000); + }); + }); + return null; + }); - after -> - MockProjectHistoryApi.flushProject.restore() + after(() => MockProjectHistoryApi.flushProject.restore()); - it "should flush project history", -> - MockProjectHistoryApi.flushProject.calledWith(@project_id).should.equal true + return it("should flush project history", function() { + return MockProjectHistoryApi.flushProject.calledWith(this.project_id).should.equal(true); + }); + }); - describe "with too few updates to flush to the history service", -> - before (done) -> - @project_id = DocUpdaterClient.randomId() - @user_id = DocUpdaterClient.randomId() - @version0 = 12345 - @version1 = @version0 + 1 + return describe("with too few updates to flush to the history service", function() { + before(function(done) { + this.project_id = DocUpdaterClient.randomId(); + this.user_id = DocUpdaterClient.randomId(); + this.version0 = 12345; + this.version1 = this.version0 + 1; - updates = [] - for v in [0..42] # Should flush after 500 ops - updates.push + const updates = []; + for (let v = 0; v <= 42; v++) { // Should flush after 500 ops + updates.push({ id: DocUpdaterClient.randomId(), - pathname: '/file-' + v + pathname: '/file-' + v, docLines: 'a\nb' + }); + } - sinon.spy MockProjectHistoryApi, "flushProject" + sinon.spy(MockProjectHistoryApi, "flushProject"); - # Send updates in chunks - projectId = @project_id - userId = @project_id - DocUpdaterClient.sendProjectUpdate projectId, userId, updates.slice(0, 10), [], @version0, (error) -> - throw error if error? - DocUpdaterClient.sendProjectUpdate projectId, userId, updates.slice(10), [], @version1, (error) -> - throw error if error? - setTimeout done, 2000 - return null + // Send updates in chunks + const projectId = this.project_id; + const userId = this.project_id; + DocUpdaterClient.sendProjectUpdate(projectId, userId, updates.slice(0, 10), [], this.version0, function(error) { + if (error != null) { throw error; } + return DocUpdaterClient.sendProjectUpdate(projectId, userId, updates.slice(10), [], this.version1, function(error) { + if (error != null) { throw error; } + return setTimeout(done, 2000); + }); + }); + return null; + }); - after -> - MockProjectHistoryApi.flushProject.restore() + after(() => MockProjectHistoryApi.flushProject.restore()); - it "should not flush project history", -> - MockProjectHistoryApi.flushProject.calledWith(@project_id).should.equal false + return it("should not flush project history", function() { + return MockProjectHistoryApi.flushProject.calledWith(this.project_id).should.equal(false); + }); + }); +}); diff --git a/services/document-updater/test/acceptance/coffee/DeletingADocumentTests.js b/services/document-updater/test/acceptance/coffee/DeletingADocumentTests.js index c2c4462d31..527ec2edd2 100644 --- a/services/document-updater/test/acceptance/coffee/DeletingADocumentTests.js +++ b/services/document-updater/test/acceptance/coffee/DeletingADocumentTests.js @@ -1,109 +1,141 @@ -sinon = require "sinon" -chai = require("chai") -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 sinon = require("sinon"); +const chai = require("chai"); +chai.should(); -MockTrackChangesApi = require "./helpers/MockTrackChangesApi" -MockProjectHistoryApi = require "./helpers/MockProjectHistoryApi" -MockWebApi = require "./helpers/MockWebApi" -DocUpdaterClient = require "./helpers/DocUpdaterClient" -DocUpdaterApp = require "./helpers/DocUpdaterApp" +const MockTrackChangesApi = require("./helpers/MockTrackChangesApi"); +const MockProjectHistoryApi = require("./helpers/MockProjectHistoryApi"); +const MockWebApi = require("./helpers/MockWebApi"); +const DocUpdaterClient = require("./helpers/DocUpdaterClient"); +const DocUpdaterApp = require("./helpers/DocUpdaterApp"); -describe "Deleting a document", -> - before (done) -> - @lines = ["one", "two", "three"] - @version = 42 - @update = - doc: @doc_id +describe("Deleting a document", function() { + before(function(done) { + this.lines = ["one", "two", "three"]; + this.version = 42; + this.update = { + doc: this.doc_id, op: [{ - i: "one and a half\n" + i: "one and a half\n", p: 4 - }] - v: @version - @result = ["one", "one and a half", "two", "three"] + }], + v: this.version + }; + this.result = ["one", "one and a half", "two", "three"]; - sinon.spy MockTrackChangesApi, "flushDoc" - sinon.spy MockProjectHistoryApi, "flushProject" - DocUpdaterApp.ensureRunning(done) + sinon.spy(MockTrackChangesApi, "flushDoc"); + sinon.spy(MockProjectHistoryApi, "flushProject"); + return DocUpdaterApp.ensureRunning(done); + }); - after -> - MockTrackChangesApi.flushDoc.restore() - MockProjectHistoryApi.flushProject.restore() + after(function() { + MockTrackChangesApi.flushDoc.restore(); + return MockProjectHistoryApi.flushProject.restore(); + }); - describe "when the updated doc exists in the doc updater", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - sinon.spy MockWebApi, "setDocument" - sinon.spy MockWebApi, "getDocument" + describe("when the updated doc exists in the doc updater", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); + sinon.spy(MockWebApi, "setDocument"); + sinon.spy(MockWebApi, "getDocument"); - MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} - DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) => - throw error if error? - DocUpdaterClient.sendUpdate @project_id, @doc_id, @update, (error) => - throw error if error? - setTimeout () => - DocUpdaterClient.deleteDoc @project_id, @doc_id, (error, res, body) => - @statusCode = res.statusCode - setTimeout done, 200 - , 200 + MockWebApi.insertDoc(this.project_id, this.doc_id, {lines: this.lines, version: this.version}); + return DocUpdaterClient.preloadDoc(this.project_id, this.doc_id, error => { + if (error != null) { throw error; } + return DocUpdaterClient.sendUpdate(this.project_id, this.doc_id, this.update, error => { + if (error != null) { throw error; } + return setTimeout(() => { + return DocUpdaterClient.deleteDoc(this.project_id, this.doc_id, (error, res, body) => { + this.statusCode = res.statusCode; + return setTimeout(done, 200); + }); + } + , 200); + }); + }); + }); - after -> - MockWebApi.setDocument.restore() - MockWebApi.getDocument.restore() + after(function() { + MockWebApi.setDocument.restore(); + return MockWebApi.getDocument.restore(); + }); - it "should return a 204 status code", -> - @statusCode.should.equal 204 + it("should return a 204 status code", function() { + return this.statusCode.should.equal(204); + }); - it "should send the updated document and version to the web api", -> - MockWebApi.setDocument - .calledWith(@project_id, @doc_id, @result, @version + 1) - .should.equal true + it("should send the updated document and version to the web api", function() { + return MockWebApi.setDocument + .calledWith(this.project_id, this.doc_id, this.result, this.version + 1) + .should.equal(true); + }); - it "should need to reload the doc if read again", (done) -> - MockWebApi.getDocument.called.should.equal.false - DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, doc) => + it("should need to reload the doc if read again", function(done) { + MockWebApi.getDocument.called.should.equal.false; + return DocUpdaterClient.getDoc(this.project_id, this.doc_id, (error, res, doc) => { MockWebApi.getDocument - .calledWith(@project_id, @doc_id) - .should.equal true - done() + .calledWith(this.project_id, this.doc_id) + .should.equal(true); + return done(); + }); + }); - it "should flush track changes", -> - MockTrackChangesApi.flushDoc.calledWith(@doc_id).should.equal true + it("should flush track changes", function() { + return MockTrackChangesApi.flushDoc.calledWith(this.doc_id).should.equal(true); + }); - it "should flush project history", -> - MockProjectHistoryApi.flushProject.calledWith(@project_id).should.equal true + return it("should flush project history", function() { + return MockProjectHistoryApi.flushProject.calledWith(this.project_id).should.equal(true); + }); + }); - describe "when the doc is not in the doc updater", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - MockWebApi.insertDoc @project_id, @doc_id, { - lines: @lines - } - sinon.spy MockWebApi, "setDocument" - sinon.spy MockWebApi, "getDocument" - DocUpdaterClient.deleteDoc @project_id, @doc_id, (error, res, body) => - @statusCode = res.statusCode - setTimeout done, 200 + return describe("when the doc is not in the doc updater", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); + MockWebApi.insertDoc(this.project_id, this.doc_id, { + lines: this.lines + }); + sinon.spy(MockWebApi, "setDocument"); + sinon.spy(MockWebApi, "getDocument"); + return DocUpdaterClient.deleteDoc(this.project_id, this.doc_id, (error, res, body) => { + this.statusCode = res.statusCode; + return setTimeout(done, 200); + }); + }); - after -> - MockWebApi.setDocument.restore() - MockWebApi.getDocument.restore() + after(function() { + MockWebApi.setDocument.restore(); + return MockWebApi.getDocument.restore(); + }); - it "should return a 204 status code", -> - @statusCode.should.equal 204 + it("should return a 204 status code", function() { + return this.statusCode.should.equal(204); + }); - it "should not need to send the updated document to the web api", -> - MockWebApi.setDocument.called.should.equal false + it("should not need to send the updated document to the web api", () => MockWebApi.setDocument.called.should.equal(false)); - it "should need to reload the doc if read again", (done) -> - MockWebApi.getDocument.called.should.equal.false - DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, doc) => + it("should need to reload the doc if read again", function(done) { + MockWebApi.getDocument.called.should.equal.false; + return DocUpdaterClient.getDoc(this.project_id, this.doc_id, (error, res, doc) => { MockWebApi.getDocument - .calledWith(@project_id, @doc_id) - .should.equal true - done() + .calledWith(this.project_id, this.doc_id) + .should.equal(true); + return done(); + }); + }); - it "should flush track changes", -> - MockTrackChangesApi.flushDoc.calledWith(@doc_id).should.equal true + it("should flush track changes", function() { + return MockTrackChangesApi.flushDoc.calledWith(this.doc_id).should.equal(true); + }); - it "should flush project history", -> - MockProjectHistoryApi.flushProject.calledWith(@project_id).should.equal true + return it("should flush project history", function() { + return MockProjectHistoryApi.flushProject.calledWith(this.project_id).should.equal(true); + }); + }); +}); diff --git a/services/document-updater/test/acceptance/coffee/DeletingAProjectTests.js b/services/document-updater/test/acceptance/coffee/DeletingAProjectTests.js index cddc008bc0..b60d04bd40 100644 --- a/services/document-updater/test/acceptance/coffee/DeletingAProjectTests.js +++ b/services/document-updater/test/acceptance/coffee/DeletingAProjectTests.js @@ -1,174 +1,217 @@ -sinon = require "sinon" -chai = require("chai") -chai.should() -async = require "async" +/* + * 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 sinon = require("sinon"); +const chai = require("chai"); +chai.should(); +const async = require("async"); -MockTrackChangesApi = require "./helpers/MockTrackChangesApi" -MockProjectHistoryApi = require "./helpers/MockProjectHistoryApi" -MockWebApi = require "./helpers/MockWebApi" -DocUpdaterClient = require "./helpers/DocUpdaterClient" -DocUpdaterApp = require "./helpers/DocUpdaterApp" +const MockTrackChangesApi = require("./helpers/MockTrackChangesApi"); +const MockProjectHistoryApi = require("./helpers/MockProjectHistoryApi"); +const MockWebApi = require("./helpers/MockWebApi"); +const DocUpdaterClient = require("./helpers/DocUpdaterClient"); +const DocUpdaterApp = require("./helpers/DocUpdaterApp"); -describe "Deleting a project", -> - before (done) -> - @project_id = DocUpdaterClient.randomId() - @docs = [{ - id: doc_id0 = DocUpdaterClient.randomId() - lines: ["one", "two", "three"] - update: - doc: doc_id0 +describe("Deleting a project", function() { + before(function(done) { + let doc_id0, doc_id1; + this.project_id = DocUpdaterClient.randomId(); + this.docs = [{ + id: (doc_id0 = DocUpdaterClient.randomId()), + lines: ["one", "two", "three"], + update: { + doc: doc_id0, op: [{ - i: "one and a half\n" + i: "one and a half\n", p: 4 - }] + }], v: 0 + }, updatedLines: ["one", "one and a half", "two", "three"] }, { - id: doc_id1 = DocUpdaterClient.randomId() - lines: ["four", "five", "six"] - update: - doc: doc_id1 + id: (doc_id1 = DocUpdaterClient.randomId()), + lines: ["four", "five", "six"], + update: { + doc: doc_id1, op: [{ - i: "four and a half\n" + i: "four and a half\n", p: 5 - }] + }], v: 0 + }, updatedLines: ["four", "four and a half", "five", "six"] - }] - for doc in @docs - MockWebApi.insertDoc @project_id, doc.id, { - lines: doc.lines + }]; + for (let doc of Array.from(this.docs)) { + MockWebApi.insertDoc(this.project_id, doc.id, { + lines: doc.lines, version: doc.update.v - } + }); + } - DocUpdaterApp.ensureRunning(done) + return DocUpdaterApp.ensureRunning(done); + }); - describe "with documents which have been updated", -> - before (done) -> - sinon.spy MockWebApi, "setDocument" - sinon.spy MockTrackChangesApi, "flushDoc" - sinon.spy MockProjectHistoryApi, "flushProject" + describe("with documents which have been updated", function() { + before(function(done) { + sinon.spy(MockWebApi, "setDocument"); + sinon.spy(MockTrackChangesApi, "flushDoc"); + sinon.spy(MockProjectHistoryApi, "flushProject"); - async.series @docs.map((doc) => - (callback) => - DocUpdaterClient.preloadDoc @project_id, doc.id, (error) => - return callback(error) if error? - DocUpdaterClient.sendUpdate @project_id, doc.id, doc.update, (error) => - callback(error) - ), (error) => - throw error if error? - setTimeout () => - DocUpdaterClient.deleteProject @project_id, (error, res, body) => - @statusCode = res.statusCode - done() - , 200 + return async.series(this.docs.map(doc => { + return callback => { + return DocUpdaterClient.preloadDoc(this.project_id, doc.id, error => { + if (error != null) { return callback(error); } + return DocUpdaterClient.sendUpdate(this.project_id, doc.id, doc.update, error => { + return callback(error); + }); + }); + }; + }), error => { + if (error != null) { throw error; } + return setTimeout(() => { + return DocUpdaterClient.deleteProject(this.project_id, (error, res, body) => { + this.statusCode = res.statusCode; + return done(); + }); + } + , 200); + }); + }); - after -> - MockWebApi.setDocument.restore() - MockTrackChangesApi.flushDoc.restore() - MockProjectHistoryApi.flushProject.restore() + after(function() { + MockWebApi.setDocument.restore(); + MockTrackChangesApi.flushDoc.restore(); + return MockProjectHistoryApi.flushProject.restore(); + }); - it "should return a 204 status code", -> - @statusCode.should.equal 204 + it("should return a 204 status code", function() { + return this.statusCode.should.equal(204); + }); - it "should send each document to the web api", -> - for doc in @docs + it("should send each document to the web api", function() { + return Array.from(this.docs).map((doc) => MockWebApi.setDocument - .calledWith(@project_id, doc.id, doc.updatedLines) - .should.equal true + .calledWith(this.project_id, doc.id, doc.updatedLines) + .should.equal(true)); + }); - it "should need to reload the docs if read again", (done) -> - sinon.spy MockWebApi, "getDocument" - async.series @docs.map((doc) => - (callback) => - MockWebApi.getDocument.calledWith(@project_id, doc.id).should.equal false - DocUpdaterClient.getDoc @project_id, doc.id, (error, res, returnedDoc) => - MockWebApi.getDocument.calledWith(@project_id, doc.id).should.equal true - callback() - ), () -> - MockWebApi.getDocument.restore() - done() + it("should need to reload the docs if read again", function(done) { + sinon.spy(MockWebApi, "getDocument"); + return async.series(this.docs.map(doc => { + return callback => { + MockWebApi.getDocument.calledWith(this.project_id, doc.id).should.equal(false); + return DocUpdaterClient.getDoc(this.project_id, doc.id, (error, res, returnedDoc) => { + MockWebApi.getDocument.calledWith(this.project_id, doc.id).should.equal(true); + return callback(); + }); + }; + }), function() { + MockWebApi.getDocument.restore(); + return done(); + }); + }); - it "should flush each doc in track changes", -> - for doc in @docs - MockTrackChangesApi.flushDoc.calledWith(doc.id).should.equal true + it("should flush each doc in track changes", function() { + return Array.from(this.docs).map((doc) => + MockTrackChangesApi.flushDoc.calledWith(doc.id).should.equal(true)); + }); - it "should flush each doc in project history", -> - MockProjectHistoryApi.flushProject.calledWith(@project_id).should.equal true + return it("should flush each doc in project history", function() { + return MockProjectHistoryApi.flushProject.calledWith(this.project_id).should.equal(true); + }); + }); - describe "with the background=true parameter from realtime and no request to flush the queue", -> - before (done) -> - sinon.spy MockWebApi, "setDocument" - sinon.spy MockTrackChangesApi, "flushDoc" - sinon.spy MockProjectHistoryApi, "flushProject" + describe("with the background=true parameter from realtime and no request to flush the queue", function() { + before(function(done) { + sinon.spy(MockWebApi, "setDocument"); + sinon.spy(MockTrackChangesApi, "flushDoc"); + sinon.spy(MockProjectHistoryApi, "flushProject"); - async.series @docs.map((doc) => - (callback) => - DocUpdaterClient.preloadDoc @project_id, doc.id, callback - ), (error) => - throw error if error? - setTimeout () => - DocUpdaterClient.deleteProjectOnShutdown @project_id, (error, res, body) => - @statusCode = res.statusCode - done() - , 200 + return async.series(this.docs.map(doc => { + return callback => { + return DocUpdaterClient.preloadDoc(this.project_id, doc.id, callback); + }; + }), error => { + if (error != null) { throw error; } + return setTimeout(() => { + return DocUpdaterClient.deleteProjectOnShutdown(this.project_id, (error, res, body) => { + this.statusCode = res.statusCode; + return done(); + }); + } + , 200); + }); + }); - after -> - MockWebApi.setDocument.restore() - MockTrackChangesApi.flushDoc.restore() - MockProjectHistoryApi.flushProject.restore() + after(function() { + MockWebApi.setDocument.restore(); + MockTrackChangesApi.flushDoc.restore(); + return MockProjectHistoryApi.flushProject.restore(); + }); - it "should return a 204 status code", -> - @statusCode.should.equal 204 + it("should return a 204 status code", function() { + return this.statusCode.should.equal(204); + }); - it "should not send any documents to the web api", -> - MockWebApi.setDocument.called.should.equal false + it("should not send any documents to the web api", () => MockWebApi.setDocument.called.should.equal(false)); - it "should not flush any docs in track changes", -> - MockTrackChangesApi.flushDoc.called.should.equal false + it("should not flush any docs in track changes", () => MockTrackChangesApi.flushDoc.called.should.equal(false)); - it "should not flush to project history", -> - MockProjectHistoryApi.flushProject.called.should.equal false + return it("should not flush to project history", () => MockProjectHistoryApi.flushProject.called.should.equal(false)); + }); - describe "with the background=true parameter from realtime and a request to flush the queue", -> - before (done) -> - sinon.spy MockWebApi, "setDocument" - sinon.spy MockTrackChangesApi, "flushDoc" - sinon.spy MockProjectHistoryApi, "flushProject" + return describe("with the background=true parameter from realtime and a request to flush the queue", function() { + before(function(done) { + sinon.spy(MockWebApi, "setDocument"); + sinon.spy(MockTrackChangesApi, "flushDoc"); + sinon.spy(MockProjectHistoryApi, "flushProject"); - async.series @docs.map((doc) => - (callback) => - DocUpdaterClient.preloadDoc @project_id, doc.id, callback - ), (error) => - throw error if error? - setTimeout () => - DocUpdaterClient.deleteProjectOnShutdown @project_id, (error, res, body) => - @statusCode = res.statusCode - # after deleting the project and putting it in the queue, flush the queue - setTimeout () -> - DocUpdaterClient.flushOldProjects done - , 2000 - , 200 + return async.series(this.docs.map(doc => { + return callback => { + return DocUpdaterClient.preloadDoc(this.project_id, doc.id, callback); + }; + }), error => { + if (error != null) { throw error; } + return setTimeout(() => { + return DocUpdaterClient.deleteProjectOnShutdown(this.project_id, (error, res, body) => { + this.statusCode = res.statusCode; + // after deleting the project and putting it in the queue, flush the queue + return setTimeout(() => DocUpdaterClient.flushOldProjects(done) + , 2000); + }); + } + , 200); + }); + }); - after -> - MockWebApi.setDocument.restore() - MockTrackChangesApi.flushDoc.restore() - MockProjectHistoryApi.flushProject.restore() + after(function() { + MockWebApi.setDocument.restore(); + MockTrackChangesApi.flushDoc.restore(); + return MockProjectHistoryApi.flushProject.restore(); + }); - it "should return a 204 status code", -> - @statusCode.should.equal 204 + it("should return a 204 status code", function() { + return this.statusCode.should.equal(204); + }); - it "should send each document to the web api", -> - for doc in @docs + it("should send each document to the web api", function() { + return Array.from(this.docs).map((doc) => MockWebApi.setDocument - .calledWith(@project_id, doc.id, doc.updatedLines) - .should.equal true + .calledWith(this.project_id, doc.id, doc.updatedLines) + .should.equal(true)); + }); - it "should flush each doc in track changes", -> - for doc in @docs - MockTrackChangesApi.flushDoc.calledWith(doc.id).should.equal true + it("should flush each doc in track changes", function() { + return Array.from(this.docs).map((doc) => + MockTrackChangesApi.flushDoc.calledWith(doc.id).should.equal(true)); + }); - it "should flush to project history", -> - MockProjectHistoryApi.flushProject.called.should.equal true + return it("should flush to project history", () => MockProjectHistoryApi.flushProject.called.should.equal(true)); + }); +}); diff --git a/services/document-updater/test/acceptance/coffee/FlushingAProjectTests.js b/services/document-updater/test/acceptance/coffee/FlushingAProjectTests.js index c32b6b4001..e70798ee27 100644 --- a/services/document-updater/test/acceptance/coffee/FlushingAProjectTests.js +++ b/services/document-updater/test/acceptance/coffee/FlushingAProjectTests.js @@ -1,80 +1,105 @@ -sinon = require "sinon" -chai = require("chai") -chai.should() -async = require "async" +/* + * 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 sinon = require("sinon"); +const chai = require("chai"); +chai.should(); +const async = require("async"); -MockWebApi = require "./helpers/MockWebApi" -DocUpdaterClient = require "./helpers/DocUpdaterClient" -DocUpdaterApp = require "./helpers/DocUpdaterApp" +const MockWebApi = require("./helpers/MockWebApi"); +const DocUpdaterClient = require("./helpers/DocUpdaterClient"); +const DocUpdaterApp = require("./helpers/DocUpdaterApp"); -describe "Flushing a project", -> - before (done) -> - @project_id = DocUpdaterClient.randomId() - @docs = [{ - id: doc_id0 = DocUpdaterClient.randomId() - lines: ["one", "two", "three"] - update: - doc: doc_id0 +describe("Flushing a project", function() { + before(function(done) { + let doc_id0, doc_id1; + this.project_id = DocUpdaterClient.randomId(); + this.docs = [{ + id: (doc_id0 = DocUpdaterClient.randomId()), + lines: ["one", "two", "three"], + update: { + doc: doc_id0, op: [{ - i: "one and a half\n" + i: "one and a half\n", p: 4 - }] + }], v: 0 + }, updatedLines: ["one", "one and a half", "two", "three"] }, { - id: doc_id1 = DocUpdaterClient.randomId() - lines: ["four", "five", "six"] - update: - doc: doc_id1 + id: (doc_id1 = DocUpdaterClient.randomId()), + lines: ["four", "five", "six"], + update: { + doc: doc_id1, op: [{ - i: "four and a half\n" + i: "four and a half\n", p: 5 - }] + }], v: 0 + }, updatedLines: ["four", "four and a half", "five", "six"] - }] - for doc in @docs - MockWebApi.insertDoc @project_id, doc.id, { - lines: doc.lines + }]; + for (let doc of Array.from(this.docs)) { + MockWebApi.insertDoc(this.project_id, doc.id, { + lines: doc.lines, version: doc.update.v - } - DocUpdaterApp.ensureRunning(done) + }); + } + return DocUpdaterApp.ensureRunning(done); + }); - describe "with documents which have been updated", -> - before (done) -> - sinon.spy MockWebApi, "setDocument" + return describe("with documents which have been updated", function() { + before(function(done) { + sinon.spy(MockWebApi, "setDocument"); - async.series @docs.map((doc) => - (callback) => - DocUpdaterClient.preloadDoc @project_id, doc.id, (error) => - return callback(error) if error? - DocUpdaterClient.sendUpdate @project_id, doc.id, doc.update, (error) => - callback(error) - ), (error) => - throw error if error? - setTimeout () => - DocUpdaterClient.flushProject @project_id, (error, res, body) => - @statusCode = res.statusCode - done() - , 200 + return async.series(this.docs.map(doc => { + return callback => { + return DocUpdaterClient.preloadDoc(this.project_id, doc.id, error => { + if (error != null) { return callback(error); } + return DocUpdaterClient.sendUpdate(this.project_id, doc.id, doc.update, error => { + return callback(error); + }); + }); + }; + }), error => { + if (error != null) { throw error; } + return setTimeout(() => { + return DocUpdaterClient.flushProject(this.project_id, (error, res, body) => { + this.statusCode = res.statusCode; + return done(); + }); + } + , 200); + }); + }); - after -> - MockWebApi.setDocument.restore() + after(() => MockWebApi.setDocument.restore()); - it "should return a 204 status code", -> - @statusCode.should.equal 204 + it("should return a 204 status code", function() { + return this.statusCode.should.equal(204); + }); - it "should send each document to the web api", -> - for doc in @docs + it("should send each document to the web api", function() { + return Array.from(this.docs).map((doc) => MockWebApi.setDocument - .calledWith(@project_id, doc.id, doc.updatedLines) - .should.equal true + .calledWith(this.project_id, doc.id, doc.updatedLines) + .should.equal(true)); + }); - it "should update the lines in the doc updater", (done) -> - async.series @docs.map((doc) => - (callback) => - DocUpdaterClient.getDoc @project_id, doc.id, (error, res, returnedDoc) => - returnedDoc.lines.should.deep.equal doc.updatedLines - callback() - ), done + return it("should update the lines in the doc updater", function(done) { + return async.series(this.docs.map(doc => { + return callback => { + return DocUpdaterClient.getDoc(this.project_id, doc.id, (error, res, returnedDoc) => { + returnedDoc.lines.should.deep.equal(doc.updatedLines); + return callback(); + }); + }; + }), done); + }); + }); +}); diff --git a/services/document-updater/test/acceptance/coffee/FlushingDocsTests.js b/services/document-updater/test/acceptance/coffee/FlushingDocsTests.js index 4f19f13c2f..761a388d3e 100644 --- a/services/document-updater/test/acceptance/coffee/FlushingDocsTests.js +++ b/services/document-updater/test/acceptance/coffee/FlushingDocsTests.js @@ -1,90 +1,112 @@ -sinon = require "sinon" -chai = require("chai") -chai.should() -expect = chai.expect -async = require "async" +/* + * 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 sinon = require("sinon"); +const chai = require("chai"); +chai.should(); +const { + expect +} = chai; +const async = require("async"); -MockWebApi = require "./helpers/MockWebApi" -DocUpdaterClient = require "./helpers/DocUpdaterClient" -DocUpdaterApp = require "./helpers/DocUpdaterApp" +const MockWebApi = require("./helpers/MockWebApi"); +const DocUpdaterClient = require("./helpers/DocUpdaterClient"); +const DocUpdaterApp = require("./helpers/DocUpdaterApp"); -describe "Flushing a doc to Mongo", -> - before (done) -> - @lines = ["one", "two", "three"] - @version = 42 - @update = - doc: @doc_id - meta: { user_id: 'last-author-fake-id' } +describe("Flushing a doc to Mongo", function() { + before(function(done) { + this.lines = ["one", "two", "three"]; + this.version = 42; + this.update = { + doc: this.doc_id, + meta: { user_id: 'last-author-fake-id' }, op: [{ - i: "one and a half\n" + i: "one and a half\n", p: 4 - }] - v: @version - @result = ["one", "one and a half", "two", "three"] - DocUpdaterApp.ensureRunning(done) + }], + v: this.version + }; + this.result = ["one", "one and a half", "two", "three"]; + return DocUpdaterApp.ensureRunning(done); + }); - describe "when the updated doc exists in the doc updater", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - sinon.spy MockWebApi, "setDocument" + describe("when the updated doc exists in the doc updater", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); + sinon.spy(MockWebApi, "setDocument"); - MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} - DocUpdaterClient.sendUpdates @project_id, @doc_id, [@update], (error) => - throw error if error? - setTimeout () => - DocUpdaterClient.flushDoc @project_id, @doc_id, done - , 200 + MockWebApi.insertDoc(this.project_id, this.doc_id, {lines: this.lines, version: this.version}); + return DocUpdaterClient.sendUpdates(this.project_id, this.doc_id, [this.update], error => { + if (error != null) { throw error; } + return setTimeout(() => { + return DocUpdaterClient.flushDoc(this.project_id, this.doc_id, done); + } + , 200); + }); + }); - after -> - MockWebApi.setDocument.restore() + after(() => MockWebApi.setDocument.restore()); - it "should flush the updated doc lines and version to the web api", -> - MockWebApi.setDocument - .calledWith(@project_id, @doc_id, @result, @version + 1) - .should.equal true + it("should flush the updated doc lines and version to the web api", function() { + return MockWebApi.setDocument + .calledWith(this.project_id, this.doc_id, this.result, this.version + 1) + .should.equal(true); + }); - it "should flush the last update author and time to the web api", -> - lastUpdatedAt = MockWebApi.setDocument.lastCall.args[5] - parseInt(lastUpdatedAt).should.be.closeTo((new Date()).getTime(), 30000) + return it("should flush the last update author and time to the web api", function() { + const lastUpdatedAt = MockWebApi.setDocument.lastCall.args[5]; + parseInt(lastUpdatedAt).should.be.closeTo((new Date()).getTime(), 30000); - lastUpdatedBy = MockWebApi.setDocument.lastCall.args[6] - lastUpdatedBy.should.equal 'last-author-fake-id' + const lastUpdatedBy = MockWebApi.setDocument.lastCall.args[6]; + return lastUpdatedBy.should.equal('last-author-fake-id'); + }); + }); - describe "when the doc does not exist in the doc updater", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - MockWebApi.insertDoc @project_id, @doc_id, { - lines: @lines - } - sinon.spy MockWebApi, "setDocument" - DocUpdaterClient.flushDoc @project_id, @doc_id, done + describe("when the doc does not exist in the doc updater", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); + MockWebApi.insertDoc(this.project_id, this.doc_id, { + lines: this.lines + }); + sinon.spy(MockWebApi, "setDocument"); + return DocUpdaterClient.flushDoc(this.project_id, this.doc_id, done); + }); - after -> - MockWebApi.setDocument.restore() + after(() => MockWebApi.setDocument.restore()); - it "should not flush the doc to the web api", -> - MockWebApi.setDocument.called.should.equal false + return it("should not flush the doc to the web api", () => MockWebApi.setDocument.called.should.equal(false)); + }); - describe "when the web api http request takes a long time on first request", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - MockWebApi.insertDoc @project_id, @doc_id, { - lines: @lines - version: @version - } - t = 30000 - sinon.stub MockWebApi, "setDocument", (project_id, doc_id, lines, version, ranges, lastUpdatedAt, lastUpdatedBy, callback = (error) ->) -> - setTimeout callback, t - t = 0 - DocUpdaterClient.preloadDoc @project_id, @doc_id, done + return describe("when the web api http request takes a long time on first request", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); + MockWebApi.insertDoc(this.project_id, this.doc_id, { + lines: this.lines, + version: this.version + }); + let t = 30000; + sinon.stub(MockWebApi, "setDocument", function(project_id, doc_id, lines, version, ranges, lastUpdatedAt, lastUpdatedBy, callback) { + if (callback == null) { callback = function(error) {}; } + setTimeout(callback, t); + return t = 0; + }); + return DocUpdaterClient.preloadDoc(this.project_id, this.doc_id, done); + }); - after -> - MockWebApi.setDocument.restore() + after(() => MockWebApi.setDocument.restore()); - it "should still work", (done) -> - start = Date.now() - DocUpdaterClient.flushDoc @project_id, @doc_id, (error, res, doc) => - res.statusCode.should.equal 204 - delta = Date.now() - start - expect(delta).to.be.below 20000 - done() + return it("should still work", function(done) { + const start = Date.now(); + return DocUpdaterClient.flushDoc(this.project_id, this.doc_id, (error, res, doc) => { + res.statusCode.should.equal(204); + const delta = Date.now() - start; + expect(delta).to.be.below(20000); + return done(); + }); + }); + }); +}); diff --git a/services/document-updater/test/acceptance/coffee/GettingADocumentTests.js b/services/document-updater/test/acceptance/coffee/GettingADocumentTests.js index f3aa6ef875..273ee1c3f0 100644 --- a/services/document-updater/test/acceptance/coffee/GettingADocumentTests.js +++ b/services/document-updater/test/acceptance/coffee/GettingADocumentTests.js @@ -1,138 +1,188 @@ -sinon = require "sinon" -chai = require("chai") -chai.should() -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 sinon = require("sinon"); +const chai = require("chai"); +chai.should(); +const { + expect +} = chai; -MockWebApi = require "./helpers/MockWebApi" -DocUpdaterClient = require "./helpers/DocUpdaterClient" -DocUpdaterApp = require "./helpers/DocUpdaterApp" +const MockWebApi = require("./helpers/MockWebApi"); +const DocUpdaterClient = require("./helpers/DocUpdaterClient"); +const DocUpdaterApp = require("./helpers/DocUpdaterApp"); -describe "Getting a document", -> - before (done) -> - @lines = ["one", "two", "three"] - @version = 42 - DocUpdaterApp.ensureRunning(done) +describe("Getting a document", function() { + before(function(done) { + this.lines = ["one", "two", "three"]; + this.version = 42; + return DocUpdaterApp.ensureRunning(done); + }); - describe "when the document is not loaded", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - sinon.spy MockWebApi, "getDocument" + describe("when the document is not loaded", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); + sinon.spy(MockWebApi, "getDocument"); - MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} + MockWebApi.insertDoc(this.project_id, this.doc_id, {lines: this.lines, version: this.version}); - DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, @returnedDoc) => done() + return DocUpdaterClient.getDoc(this.project_id, this.doc_id, (error, res, returnedDoc) => { this.returnedDoc = returnedDoc; return done(); }); + }); - after -> - MockWebApi.getDocument.restore() + after(() => MockWebApi.getDocument.restore()); - it "should load the document from the web API", -> - MockWebApi.getDocument - .calledWith(@project_id, @doc_id) - .should.equal true + it("should load the document from the web API", function() { + return MockWebApi.getDocument + .calledWith(this.project_id, this.doc_id) + .should.equal(true); + }); - it "should return the document lines", -> - @returnedDoc.lines.should.deep.equal @lines + it("should return the document lines", function() { + return this.returnedDoc.lines.should.deep.equal(this.lines); + }); - it "should return the document at its current version", -> - @returnedDoc.version.should.equal @version + return it("should return the document at its current version", function() { + return this.returnedDoc.version.should.equal(this.version); + }); + }); - describe "when the document is already loaded", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] + describe("when the document is already loaded", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); - MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} - DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) => - throw error if error? - sinon.spy MockWebApi, "getDocument" - DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, @returnedDoc) => done() + MockWebApi.insertDoc(this.project_id, this.doc_id, {lines: this.lines, version: this.version}); + return DocUpdaterClient.preloadDoc(this.project_id, this.doc_id, error => { + if (error != null) { throw error; } + sinon.spy(MockWebApi, "getDocument"); + return DocUpdaterClient.getDoc(this.project_id, this.doc_id, (error, res, returnedDoc) => { this.returnedDoc = returnedDoc; return done(); }); + }); + }); - after -> - MockWebApi.getDocument.restore() + after(() => MockWebApi.getDocument.restore()); - it "should not load the document from the web API", -> - MockWebApi.getDocument.called.should.equal false + it("should not load the document from the web API", () => MockWebApi.getDocument.called.should.equal(false)); - it "should return the document lines", -> - @returnedDoc.lines.should.deep.equal @lines + return it("should return the document lines", function() { + return this.returnedDoc.lines.should.deep.equal(this.lines); + }); + }); - describe "when the request asks for some recent ops", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - MockWebApi.insertDoc @project_id, @doc_id, { - lines: @lines = ["one", "two", "three"] - } + describe("when the request asks for some recent ops", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); + MockWebApi.insertDoc(this.project_id, this.doc_id, { + lines: (this.lines = ["one", "two", "three"]) + }); - @updates = for v in [0..199] - doc_id: @doc_id, - op: [i: v.toString(), p: 0] - v: v + this.updates = __range__(0, 199, true).map((v) => ({ + doc_id: this.doc_id, + op: [{i: v.toString(), p: 0}], + v + })); - DocUpdaterClient.sendUpdates @project_id, @doc_id, @updates, (error) => - throw error if error? - sinon.spy MockWebApi, "getDocument" - done() + return DocUpdaterClient.sendUpdates(this.project_id, this.doc_id, this.updates, error => { + if (error != null) { throw error; } + sinon.spy(MockWebApi, "getDocument"); + return done(); + }); + }); - after -> - MockWebApi.getDocument.restore() + after(() => MockWebApi.getDocument.restore()); - describe "when the ops are loaded", -> - before (done) -> - DocUpdaterClient.getDocAndRecentOps @project_id, @doc_id, 190, (error, res, @returnedDoc) => done() + describe("when the ops are loaded", function() { + before(function(done) { + return DocUpdaterClient.getDocAndRecentOps(this.project_id, this.doc_id, 190, (error, res, returnedDoc) => { this.returnedDoc = returnedDoc; return done(); }); + }); - it "should return the recent ops", -> - @returnedDoc.ops.length.should.equal 10 - for update, i in @updates.slice(190, -1) - @returnedDoc.ops[i].op.should.deep.equal update.op + return it("should return the recent ops", function() { + this.returnedDoc.ops.length.should.equal(10); + return Array.from(this.updates.slice(190, -1)).map((update, i) => + this.returnedDoc.ops[i].op.should.deep.equal(update.op)); + }); + }); - describe "when the ops are not all loaded", -> - before (done) -> - # We only track 100 ops - DocUpdaterClient.getDocAndRecentOps @project_id, @doc_id, 10, (error, @res, @returnedDoc) => done() + return describe("when the ops are not all loaded", function() { + before(function(done) { + // We only track 100 ops + return DocUpdaterClient.getDocAndRecentOps(this.project_id, this.doc_id, 10, (error, res, returnedDoc) => { this.res = res; this.returnedDoc = returnedDoc; return done(); }); + }); - it "should return UnprocessableEntity", -> - @res.statusCode.should.equal 422 + return it("should return UnprocessableEntity", function() { + return this.res.statusCode.should.equal(422); + }); + }); + }); - describe "when the document does not exist", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, doc) => - @statusCode = res.statusCode - done() + describe("when the document does not exist", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); + return DocUpdaterClient.getDoc(this.project_id, this.doc_id, (error, res, doc) => { + this.statusCode = res.statusCode; + return done(); + }); + }); - it "should return 404", -> - @statusCode.should.equal 404 + return it("should return 404", function() { + return this.statusCode.should.equal(404); + }); + }); - describe "when the web api returns an error", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - sinon.stub MockWebApi, "getDocument", (project_id, doc_id, callback = (error, doc) ->) -> - callback new Error("oops") - DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, doc) => - @statusCode = res.statusCode - done() + describe("when the web api returns an error", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); + sinon.stub(MockWebApi, "getDocument", function(project_id, doc_id, callback) { + if (callback == null) { callback = function(error, doc) {}; } + return callback(new Error("oops")); + }); + return DocUpdaterClient.getDoc(this.project_id, this.doc_id, (error, res, doc) => { + this.statusCode = res.statusCode; + return done(); + }); + }); - after -> - MockWebApi.getDocument.restore() + after(() => MockWebApi.getDocument.restore()); - it "should return 500", -> - @statusCode.should.equal 500 + return it("should return 500", function() { + return this.statusCode.should.equal(500); + }); + }); - describe "when the web api http request takes a long time", -> - before (done) -> - @timeout = 10000 - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - sinon.stub MockWebApi, "getDocument", (project_id, doc_id, callback = (error, doc) ->) -> - setTimeout callback, 30000 - done() + return describe("when the web api http request takes a long time", function() { + before(function(done) { + this.timeout = 10000; + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); + sinon.stub(MockWebApi, "getDocument", function(project_id, doc_id, callback) { + if (callback == null) { callback = function(error, doc) {}; } + return setTimeout(callback, 30000); + }); + return done(); + }); - after -> - MockWebApi.getDocument.restore() + after(() => MockWebApi.getDocument.restore()); - it "should return quickly(ish)", (done) -> - start = Date.now() - DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, doc) => - res.statusCode.should.equal 500 - delta = Date.now() - start - expect(delta).to.be.below 20000 - done() + return it("should return quickly(ish)", function(done) { + const start = Date.now(); + return DocUpdaterClient.getDoc(this.project_id, this.doc_id, (error, res, doc) => { + res.statusCode.should.equal(500); + const delta = Date.now() - start; + expect(delta).to.be.below(20000); + return done(); + }); + }); + }); +}); + +function __range__(left, right, inclusive) { + let range = []; + let ascending = left < right; + let end = !inclusive ? right : ascending ? right + 1 : right - 1; + for (let i = left; ascending ? i < end : i > end; ascending ? i++ : i--) { + range.push(i); + } + return range; +} \ No newline at end of file diff --git a/services/document-updater/test/acceptance/coffee/GettingProjectDocsTests.js b/services/document-updater/test/acceptance/coffee/GettingProjectDocsTests.js index 3483d170fa..e974070468 100644 --- a/services/document-updater/test/acceptance/coffee/GettingProjectDocsTests.js +++ b/services/document-updater/test/acceptance/coffee/GettingProjectDocsTests.js @@ -1,69 +1,109 @@ -sinon = require "sinon" -chai = require("chai") -chai.should() -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 sinon = require("sinon"); +const chai = require("chai"); +chai.should(); +const { + expect +} = chai; -MockWebApi = require "./helpers/MockWebApi" -DocUpdaterClient = require "./helpers/DocUpdaterClient" -DocUpdaterApp = require "./helpers/DocUpdaterApp" +const MockWebApi = require("./helpers/MockWebApi"); +const DocUpdaterClient = require("./helpers/DocUpdaterClient"); +const DocUpdaterApp = require("./helpers/DocUpdaterApp"); -describe "Getting documents for project", -> - before (done) -> - @lines = ["one", "two", "three"] - @version = 42 - DocUpdaterApp.ensureRunning(done) +describe("Getting documents for project", function() { + before(function(done) { + this.lines = ["one", "two", "three"]; + this.version = 42; + return DocUpdaterApp.ensureRunning(done); + }); - describe "when project state hash does not match", -> - before (done) -> - @projectStateHash = DocUpdaterClient.randomId() - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] + describe("when project state hash does not match", function() { + before(function(done) { + this.projectStateHash = DocUpdaterClient.randomId(); + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); - MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} - DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) => - throw error if error? - DocUpdaterClient.getProjectDocs @project_id, @projectStateHash, (error, @res, @returnedDocs) => - done() + MockWebApi.insertDoc(this.project_id, this.doc_id, {lines: this.lines, version: this.version}); + return DocUpdaterClient.preloadDoc(this.project_id, this.doc_id, error => { + if (error != null) { throw error; } + return DocUpdaterClient.getProjectDocs(this.project_id, this.projectStateHash, (error, res, returnedDocs) => { + this.res = res; + this.returnedDocs = returnedDocs; + return done(); + }); + }); + }); - it "should return a 409 Conflict response", -> - @res.statusCode.should.equal 409 + return it("should return a 409 Conflict response", function() { + return this.res.statusCode.should.equal(409); + }); + }); - describe "when project state hash matches", -> - before (done) -> - @projectStateHash = DocUpdaterClient.randomId() - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] + describe("when project state hash matches", function() { + before(function(done) { + this.projectStateHash = DocUpdaterClient.randomId(); + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); - MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} - DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) => - throw error if error? - DocUpdaterClient.getProjectDocs @project_id, @projectStateHash, (error, @res0, @returnedDocs0) => - # set the hash - DocUpdaterClient.getProjectDocs @project_id, @projectStateHash, (error, @res, @returnedDocs) => - # the hash should now match - done() + MockWebApi.insertDoc(this.project_id, this.doc_id, {lines: this.lines, version: this.version}); + return DocUpdaterClient.preloadDoc(this.project_id, this.doc_id, error => { + if (error != null) { throw error; } + return DocUpdaterClient.getProjectDocs(this.project_id, this.projectStateHash, (error, res0, returnedDocs0) => { + // set the hash + this.res0 = res0; + this.returnedDocs0 = returnedDocs0; + return DocUpdaterClient.getProjectDocs(this.project_id, this.projectStateHash, (error, res, returnedDocs) => { + // the hash should now match + this.res = res; + this.returnedDocs = returnedDocs; + return done(); + }); + }); + }); + }); - it "should return a 200 response", -> - @res.statusCode.should.equal 200 + it("should return a 200 response", function() { + return this.res.statusCode.should.equal(200); + }); - it "should return the documents", -> - @returnedDocs.should.deep.equal [ {_id: @doc_id, lines: @lines, v: @version} ] + return it("should return the documents", function() { + return this.returnedDocs.should.deep.equal([ {_id: this.doc_id, lines: this.lines, v: this.version} ]); + }); +}); - describe "when the doc has been removed", -> - before (done) -> - @projectStateHash = DocUpdaterClient.randomId() - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] + return describe("when the doc has been removed", function() { + before(function(done) { + this.projectStateHash = DocUpdaterClient.randomId(); + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); - MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} - DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) => - throw error if error? - DocUpdaterClient.getProjectDocs @project_id, @projectStateHash, (error, @res0, @returnedDocs0) => - # set the hash - DocUpdaterClient.deleteDoc @project_id, @doc_id, (error, res, body) => - # delete the doc - DocUpdaterClient.getProjectDocs @project_id, @projectStateHash, (error, @res, @returnedDocs) => - # the hash would match, but the doc has been deleted - done() + MockWebApi.insertDoc(this.project_id, this.doc_id, {lines: this.lines, version: this.version}); + return DocUpdaterClient.preloadDoc(this.project_id, this.doc_id, error => { + if (error != null) { throw error; } + return DocUpdaterClient.getProjectDocs(this.project_id, this.projectStateHash, (error, res0, returnedDocs0) => { + // set the hash + this.res0 = res0; + this.returnedDocs0 = returnedDocs0; + return DocUpdaterClient.deleteDoc(this.project_id, this.doc_id, (error, res, body) => { + // delete the doc + return DocUpdaterClient.getProjectDocs(this.project_id, this.projectStateHash, (error, res1, returnedDocs) => { + // the hash would match, but the doc has been deleted + this.res = res1; + this.returnedDocs = returnedDocs; + return done(); + }); + }); + }); + }); + }); - it "should return a 409 Conflict response", -> - @res.statusCode.should.equal 409 + return it("should return a 409 Conflict response", function() { + return this.res.statusCode.should.equal(409); + }); + }); +}); diff --git a/services/document-updater/test/acceptance/coffee/RangesTests.js b/services/document-updater/test/acceptance/coffee/RangesTests.js index 52946f4823..e7ba085b04 100644 --- a/services/document-updater/test/acceptance/coffee/RangesTests.js +++ b/services/document-updater/test/acceptance/coffee/RangesTests.js @@ -1,372 +1,467 @@ -sinon = require "sinon" -chai = require("chai") -chai.should() -expect = chai.expect -async = require "async" +/* + * 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 sinon = require("sinon"); +const chai = require("chai"); +chai.should(); +const { + expect +} = chai; +const async = require("async"); -{db, ObjectId} = require "../../../app/js/mongojs" -MockWebApi = require "./helpers/MockWebApi" -DocUpdaterClient = require "./helpers/DocUpdaterClient" -DocUpdaterApp = require "./helpers/DocUpdaterApp" +const {db, ObjectId} = require("../../../app/js/mongojs"); +const MockWebApi = require("./helpers/MockWebApi"); +const DocUpdaterClient = require("./helpers/DocUpdaterClient"); +const DocUpdaterApp = require("./helpers/DocUpdaterApp"); -describe "Ranges", -> - before (done) -> - DocUpdaterApp.ensureRunning done +describe("Ranges", function() { + before(done => DocUpdaterApp.ensureRunning(done)); - describe "tracking changes from ops", -> - before (done) -> - @project_id = DocUpdaterClient.randomId() - @user_id = DocUpdaterClient.randomId() - @id_seed = "587357bd35e64f6157" - @doc = { - id: DocUpdaterClient.randomId() + describe("tracking changes from ops", function() { + before(function(done) { + this.project_id = DocUpdaterClient.randomId(); + this.user_id = DocUpdaterClient.randomId(); + this.id_seed = "587357bd35e64f6157"; + this.doc = { + id: DocUpdaterClient.randomId(), lines: ["aaa"] - } - @updates = [{ - doc: @doc.id - op: [{ i: "123", p: 1 }] - v: 0 - meta: { user_id: @user_id } + }; + this.updates = [{ + doc: this.doc.id, + op: [{ i: "123", p: 1 }], + v: 0, + meta: { user_id: this.user_id } }, { - doc: @doc.id - op: [{ i: "456", p: 5 }] - v: 1 - meta: { user_id: @user_id, tc: @id_seed } + doc: this.doc.id, + op: [{ i: "456", p: 5 }], + v: 1, + meta: { user_id: this.user_id, tc: this.id_seed } }, { - doc: @doc.id - op: [{ d: "12", p: 1 }] - v: 2 - meta: { user_id: @user_id } - }] - MockWebApi.insertDoc @project_id, @doc.id, { - lines: @doc.lines + doc: this.doc.id, + op: [{ d: "12", p: 1 }], + v: 2, + meta: { user_id: this.user_id } + }]; + MockWebApi.insertDoc(this.project_id, this.doc.id, { + lines: this.doc.lines, version: 0 + }); + const jobs = []; + for (let update of Array.from(this.updates)) { + (update => { + return jobs.push(callback => DocUpdaterClient.sendUpdate(this.project_id, this.doc.id, update, callback)); + })(update); } - jobs = [] - for update in @updates - do (update) => - jobs.push (callback) => DocUpdaterClient.sendUpdate @project_id, @doc.id, update, callback - DocUpdaterApp.ensureRunning (error) => - throw error if error? - DocUpdaterClient.preloadDoc @project_id, @doc.id, (error) => - throw error if error? - async.series jobs, (error) -> - throw error if error? - done() + return DocUpdaterApp.ensureRunning(error => { + if (error != null) { throw error; } + return DocUpdaterClient.preloadDoc(this.project_id, this.doc.id, error => { + if (error != null) { throw error; } + return async.series(jobs, function(error) { + if (error != null) { throw error; } + return done(); + }); + }); + }); + }); - it "should update the ranges", (done) -> - DocUpdaterClient.getDoc @project_id, @doc.id, (error, res, data) => - throw error if error? - ranges = data.ranges - change = ranges.changes[0] - change.op.should.deep.equal { i: "456", p: 3 } - change.id.should.equal @id_seed + "000001" - change.metadata.user_id.should.equal @user_id - done() + it("should update the ranges", function(done) { + return DocUpdaterClient.getDoc(this.project_id, this.doc.id, (error, res, data) => { + if (error != null) { throw error; } + const { + ranges + } = data; + const change = ranges.changes[0]; + change.op.should.deep.equal({ i: "456", p: 3 }); + change.id.should.equal(this.id_seed + "000001"); + change.metadata.user_id.should.equal(this.user_id); + return done(); + }); + }); - describe "Adding comments", -> - describe "standalone", -> - before (done) -> - @project_id = DocUpdaterClient.randomId() - @user_id = DocUpdaterClient.randomId() - @doc = { - id: DocUpdaterClient.randomId() + return describe("Adding comments", function() { + describe("standalone", function() { + before(function(done) { + this.project_id = DocUpdaterClient.randomId(); + this.user_id = DocUpdaterClient.randomId(); + this.doc = { + id: DocUpdaterClient.randomId(), lines: ["foo bar baz"] - } - @updates = [{ - doc: @doc.id - op: [{ c: "bar", p: 4, t: @tid = DocUpdaterClient.randomId() }] + }; + this.updates = [{ + doc: this.doc.id, + op: [{ c: "bar", p: 4, t: (this.tid = DocUpdaterClient.randomId()) }], v: 0 - }] - MockWebApi.insertDoc @project_id, @doc.id, { - lines: @doc.lines + }]; + MockWebApi.insertDoc(this.project_id, this.doc.id, { + lines: this.doc.lines, version: 0 + }); + const jobs = []; + for (let update of Array.from(this.updates)) { + (update => { + return jobs.push(callback => DocUpdaterClient.sendUpdate(this.project_id, this.doc.id, update, callback)); + })(update); } - jobs = [] - for update in @updates - do (update) => - jobs.push (callback) => DocUpdaterClient.sendUpdate @project_id, @doc.id, update, callback - DocUpdaterClient.preloadDoc @project_id, @doc.id, (error) => - throw error if error? - async.series jobs, (error) -> - throw error if error? - setTimeout done, 200 + return DocUpdaterClient.preloadDoc(this.project_id, this.doc.id, error => { + if (error != null) { throw error; } + return async.series(jobs, function(error) { + if (error != null) { throw error; } + return setTimeout(done, 200); + }); + }); + }); - it "should update the ranges", (done) -> - DocUpdaterClient.getDoc @project_id, @doc.id, (error, res, data) => - throw error if error? - ranges = data.ranges - comment = ranges.comments[0] - comment.op.should.deep.equal { c: "bar", p: 4, t: @tid } - comment.id.should.equal @tid - done() + return it("should update the ranges", function(done) { + return DocUpdaterClient.getDoc(this.project_id, this.doc.id, (error, res, data) => { + if (error != null) { throw error; } + const { + ranges + } = data; + const comment = ranges.comments[0]; + comment.op.should.deep.equal({ c: "bar", p: 4, t: this.tid }); + comment.id.should.equal(this.tid); + return done(); + }); + }); + }); - describe "with conflicting ops needing OT", -> - before (done) -> - @project_id = DocUpdaterClient.randomId() - @user_id = DocUpdaterClient.randomId() - @doc = { - id: DocUpdaterClient.randomId() + return describe("with conflicting ops needing OT", function() { + before(function(done) { + this.project_id = DocUpdaterClient.randomId(); + this.user_id = DocUpdaterClient.randomId(); + this.doc = { + id: DocUpdaterClient.randomId(), lines: ["foo bar baz"] - } - @updates = [{ - doc: @doc.id - op: [{ i: "ABC", p: 3 }] - v: 0 - meta: { user_id: @user_id } + }; + this.updates = [{ + doc: this.doc.id, + op: [{ i: "ABC", p: 3 }], + v: 0, + meta: { user_id: this.user_id } }, { - doc: @doc.id - op: [{ c: "bar", p: 4, t: @tid = DocUpdaterClient.randomId() }] + doc: this.doc.id, + op: [{ c: "bar", p: 4, t: (this.tid = DocUpdaterClient.randomId()) }], v: 0 - }] - MockWebApi.insertDoc @project_id, @doc.id, { - lines: @doc.lines + }]; + MockWebApi.insertDoc(this.project_id, this.doc.id, { + lines: this.doc.lines, version: 0 + }); + const jobs = []; + for (let update of Array.from(this.updates)) { + (update => { + return jobs.push(callback => DocUpdaterClient.sendUpdate(this.project_id, this.doc.id, update, callback)); + })(update); } - jobs = [] - for update in @updates - do (update) => - jobs.push (callback) => DocUpdaterClient.sendUpdate @project_id, @doc.id, update, callback - DocUpdaterClient.preloadDoc @project_id, @doc.id, (error) => - throw error if error? - async.series jobs, (error) -> - throw error if error? - setTimeout done, 200 + return DocUpdaterClient.preloadDoc(this.project_id, this.doc.id, error => { + if (error != null) { throw error; } + return async.series(jobs, function(error) { + if (error != null) { throw error; } + return setTimeout(done, 200); + }); + }); + }); - it "should update the comments with the OT shifted comment", (done) -> - DocUpdaterClient.getDoc @project_id, @doc.id, (error, res, data) => - throw error if error? - ranges = data.ranges - comment = ranges.comments[0] - comment.op.should.deep.equal { c: "bar", p: 7, t: @tid } - done() + return it("should update the comments with the OT shifted comment", function(done) { + return DocUpdaterClient.getDoc(this.project_id, this.doc.id, (error, res, data) => { + if (error != null) { throw error; } + const { + ranges + } = data; + const comment = ranges.comments[0]; + comment.op.should.deep.equal({ c: "bar", p: 7, t: this.tid }); + return done(); + }); + }); + }); + }); + }); - describe "Loading ranges from persistence layer", -> - before (done) -> - @project_id = DocUpdaterClient.randomId() - @user_id = DocUpdaterClient.randomId() - @id_seed = "587357bd35e64f6157" - @doc = { - id: DocUpdaterClient.randomId() + describe("Loading ranges from persistence layer", function() { + before(function(done) { + this.project_id = DocUpdaterClient.randomId(); + this.user_id = DocUpdaterClient.randomId(); + this.id_seed = "587357bd35e64f6157"; + this.doc = { + id: DocUpdaterClient.randomId(), lines: ["a123aa"] - } - @update = { - doc: @doc.id - op: [{ i: "456", p: 5 }] - v: 0 - meta: { user_id: @user_id, tc: @id_seed } - } - MockWebApi.insertDoc @project_id, @doc.id, { - lines: @doc.lines - version: 0 + }; + this.update = { + doc: this.doc.id, + op: [{ i: "456", p: 5 }], + v: 0, + meta: { user_id: this.user_id, tc: this.id_seed } + }; + MockWebApi.insertDoc(this.project_id, this.doc.id, { + lines: this.doc.lines, + version: 0, ranges: { changes: [{ - op: { i: "123", p: 1 } - metadata: - user_id: @user_id + op: { i: "123", p: 1 }, + metadata: { + user_id: this.user_id, ts: new Date() + } }] } - } - DocUpdaterClient.preloadDoc @project_id, @doc.id, (error) => - throw error if error? - DocUpdaterClient.sendUpdate @project_id, @doc.id, @update, (error) -> - throw error if error? - setTimeout done, 200 + }); + return DocUpdaterClient.preloadDoc(this.project_id, this.doc.id, error => { + if (error != null) { throw error; } + return DocUpdaterClient.sendUpdate(this.project_id, this.doc.id, this.update, function(error) { + if (error != null) { throw error; } + return setTimeout(done, 200); + }); + }); + }); - it "should have preloaded the existing ranges", (done) -> - DocUpdaterClient.getDoc @project_id, @doc.id, (error, res, data) => - throw error if error? - {changes} = data.ranges - changes[0].op.should.deep.equal { i: "123", p: 1 } - changes[1].op.should.deep.equal { i: "456", p: 5 } - done() + it("should have preloaded the existing ranges", function(done) { + return DocUpdaterClient.getDoc(this.project_id, this.doc.id, (error, res, data) => { + if (error != null) { throw error; } + const {changes} = data.ranges; + changes[0].op.should.deep.equal({ i: "123", p: 1 }); + changes[1].op.should.deep.equal({ i: "456", p: 5 }); + return done(); + }); + }); - it "should flush the ranges to the persistence layer again", (done) -> - DocUpdaterClient.flushDoc @project_id, @doc.id, (error) => - throw error if error? - MockWebApi.getDocument @project_id, @doc.id, (error, doc) => - {changes} = doc.ranges - changes[0].op.should.deep.equal { i: "123", p: 1 } - changes[1].op.should.deep.equal { i: "456", p: 5 } - done() + return it("should flush the ranges to the persistence layer again", function(done) { + return DocUpdaterClient.flushDoc(this.project_id, this.doc.id, error => { + if (error != null) { throw error; } + return MockWebApi.getDocument(this.project_id, this.doc.id, (error, doc) => { + const {changes} = doc.ranges; + changes[0].op.should.deep.equal({ i: "123", p: 1 }); + changes[1].op.should.deep.equal({ i: "456", p: 5 }); + return done(); + }); + }); + }); + }); - describe "accepting a change", -> - before (done) -> - @project_id = DocUpdaterClient.randomId() - @user_id = DocUpdaterClient.randomId() - @id_seed = "587357bd35e64f6157" - @doc = { - id: DocUpdaterClient.randomId() + describe("accepting a change", function() { + before(function(done) { + this.project_id = DocUpdaterClient.randomId(); + this.user_id = DocUpdaterClient.randomId(); + this.id_seed = "587357bd35e64f6157"; + this.doc = { + id: DocUpdaterClient.randomId(), lines: ["aaa"] - } - @update = { - doc: @doc.id - op: [{ i: "456", p: 1 }] - v: 0 - meta: { user_id: @user_id, tc: @id_seed } - } - MockWebApi.insertDoc @project_id, @doc.id, { - lines: @doc.lines + }; + this.update = { + doc: this.doc.id, + op: [{ i: "456", p: 1 }], + v: 0, + meta: { user_id: this.user_id, tc: this.id_seed } + }; + MockWebApi.insertDoc(this.project_id, this.doc.id, { + lines: this.doc.lines, version: 0 - } - DocUpdaterClient.preloadDoc @project_id, @doc.id, (error) => - throw error if error? - DocUpdaterClient.sendUpdate @project_id, @doc.id, @update, (error) => - throw error if error? - setTimeout () => - DocUpdaterClient.getDoc @project_id, @doc.id, (error, res, data) => - throw error if error? - ranges = data.ranges - change = ranges.changes[0] - change.op.should.deep.equal { i: "456", p: 1 } - change.id.should.equal @id_seed + "000001" - change.metadata.user_id.should.equal @user_id - done() - , 200 + }); + return DocUpdaterClient.preloadDoc(this.project_id, this.doc.id, error => { + if (error != null) { throw error; } + return DocUpdaterClient.sendUpdate(this.project_id, this.doc.id, this.update, error => { + if (error != null) { throw error; } + return setTimeout(() => { + return DocUpdaterClient.getDoc(this.project_id, this.doc.id, (error, res, data) => { + if (error != null) { throw error; } + const { + ranges + } = data; + const change = ranges.changes[0]; + change.op.should.deep.equal({ i: "456", p: 1 }); + change.id.should.equal(this.id_seed + "000001"); + change.metadata.user_id.should.equal(this.user_id); + return done(); + }); + } + , 200); + }); + }); + }); - it "should remove the change after accepting", (done) -> - DocUpdaterClient.acceptChange @project_id, @doc.id, @id_seed + "000001", (error) => - throw error if error? - DocUpdaterClient.getDoc @project_id, @doc.id, (error, res, data) => - throw error if error? - expect(data.ranges.changes).to.be.undefined - done() + return it("should remove the change after accepting", function(done) { + return DocUpdaterClient.acceptChange(this.project_id, this.doc.id, this.id_seed + "000001", error => { + if (error != null) { throw error; } + return DocUpdaterClient.getDoc(this.project_id, this.doc.id, (error, res, data) => { + if (error != null) { throw error; } + expect(data.ranges.changes).to.be.undefined; + return done(); + }); + }); + }); + }); - describe "deleting a comment range", -> - before (done) -> - @project_id = DocUpdaterClient.randomId() - @user_id = DocUpdaterClient.randomId() - @doc = { - id: DocUpdaterClient.randomId() + describe("deleting a comment range", function() { + before(function(done) { + this.project_id = DocUpdaterClient.randomId(); + this.user_id = DocUpdaterClient.randomId(); + this.doc = { + id: DocUpdaterClient.randomId(), lines: ["foo bar"] - } - @update = { - doc: @doc.id - op: [{ c: "bar", p: 4, t: @tid = DocUpdaterClient.randomId() }] + }; + this.update = { + doc: this.doc.id, + op: [{ c: "bar", p: 4, t: (this.tid = DocUpdaterClient.randomId()) }], v: 0 - } - MockWebApi.insertDoc @project_id, @doc.id, { - lines: @doc.lines + }; + MockWebApi.insertDoc(this.project_id, this.doc.id, { + lines: this.doc.lines, version: 0 - } - DocUpdaterClient.preloadDoc @project_id, @doc.id, (error) => - throw error if error? - DocUpdaterClient.sendUpdate @project_id, @doc.id, @update, (error) => - throw error if error? - setTimeout () => - DocUpdaterClient.getDoc @project_id, @doc.id, (error, res, data) => - throw error if error? - ranges = data.ranges - change = ranges.comments[0] - change.op.should.deep.equal { c: "bar", p: 4, t: @tid } - change.id.should.equal @tid - done() - , 200 + }); + return DocUpdaterClient.preloadDoc(this.project_id, this.doc.id, error => { + if (error != null) { throw error; } + return DocUpdaterClient.sendUpdate(this.project_id, this.doc.id, this.update, error => { + if (error != null) { throw error; } + return setTimeout(() => { + return DocUpdaterClient.getDoc(this.project_id, this.doc.id, (error, res, data) => { + if (error != null) { throw error; } + const { + ranges + } = data; + const change = ranges.comments[0]; + change.op.should.deep.equal({ c: "bar", p: 4, t: this.tid }); + change.id.should.equal(this.tid); + return done(); + }); + } + , 200); + }); + }); + }); - it "should remove the comment range", (done) -> - DocUpdaterClient.removeComment @project_id, @doc.id, @tid, (error, res) => - throw error if error? - expect(res.statusCode).to.equal 204 - DocUpdaterClient.getDoc @project_id, @doc.id, (error, res, data) => - throw error if error? - expect(data.ranges.comments).to.be.undefined - done() + return it("should remove the comment range", function(done) { + return DocUpdaterClient.removeComment(this.project_id, this.doc.id, this.tid, (error, res) => { + if (error != null) { throw error; } + expect(res.statusCode).to.equal(204); + return DocUpdaterClient.getDoc(this.project_id, this.doc.id, (error, res, data) => { + if (error != null) { throw error; } + expect(data.ranges.comments).to.be.undefined; + return done(); + }); + }); + }); + }); - describe "tripping range size limit", -> - before (done) -> - @project_id = DocUpdaterClient.randomId() - @user_id = DocUpdaterClient.randomId() - @id_seed = DocUpdaterClient.randomId() - @doc = { - id: DocUpdaterClient.randomId() + describe("tripping range size limit", function() { + before(function(done) { + this.project_id = DocUpdaterClient.randomId(); + this.user_id = DocUpdaterClient.randomId(); + this.id_seed = DocUpdaterClient.randomId(); + this.doc = { + id: DocUpdaterClient.randomId(), lines: ["aaa"] - } - @i = new Array(3 * 1024 * 1024).join("a") - @updates = [{ - doc: @doc.id - op: [{ i: @i, p: 1 }] - v: 0 - meta: { user_id: @user_id, tc: @id_seed } - }] - MockWebApi.insertDoc @project_id, @doc.id, { - lines: @doc.lines + }; + this.i = new Array(3 * 1024 * 1024).join("a"); + this.updates = [{ + doc: this.doc.id, + op: [{ i: this.i, p: 1 }], + v: 0, + meta: { user_id: this.user_id, tc: this.id_seed } + }]; + MockWebApi.insertDoc(this.project_id, this.doc.id, { + lines: this.doc.lines, version: 0 + }); + const jobs = []; + for (let update of Array.from(this.updates)) { + (update => { + return jobs.push(callback => DocUpdaterClient.sendUpdate(this.project_id, this.doc.id, update, callback)); + })(update); } - jobs = [] - for update in @updates - do (update) => - jobs.push (callback) => DocUpdaterClient.sendUpdate @project_id, @doc.id, update, callback - DocUpdaterClient.preloadDoc @project_id, @doc.id, (error) => - throw error if error? - async.series jobs, (error) -> - throw error if error? - setTimeout done, 200 + return DocUpdaterClient.preloadDoc(this.project_id, this.doc.id, error => { + if (error != null) { throw error; } + return async.series(jobs, function(error) { + if (error != null) { throw error; } + return setTimeout(done, 200); + }); + }); + }); - it "should not update the ranges", (done) -> - DocUpdaterClient.getDoc @project_id, @doc.id, (error, res, data) => - throw error if error? - ranges = data.ranges - expect(ranges.changes).to.be.undefined - done() + return it("should not update the ranges", function(done) { + return DocUpdaterClient.getDoc(this.project_id, this.doc.id, (error, res, data) => { + if (error != null) { throw error; } + const { + ranges + } = data; + expect(ranges.changes).to.be.undefined; + return done(); + }); + }); + }); - describe "deleting text surrounding a comment", -> - before (done) -> - @project_id = DocUpdaterClient.randomId() - @user_id = DocUpdaterClient.randomId() - @doc_id = DocUpdaterClient.randomId() - MockWebApi.insertDoc @project_id, @doc_id, { - lines: ["foo bar baz"] - version: 0 + return describe("deleting text surrounding a comment", function() { + before(function(done) { + this.project_id = DocUpdaterClient.randomId(); + this.user_id = DocUpdaterClient.randomId(); + this.doc_id = DocUpdaterClient.randomId(); + MockWebApi.insertDoc(this.project_id, this.doc_id, { + lines: ["foo bar baz"], + version: 0, ranges: { comments: [{ - op: { c: "a", p: 5, tid: @tid = DocUpdaterClient.randomId() } - metadata: - user_id: @user_id + op: { c: "a", p: 5, tid: (this.tid = DocUpdaterClient.randomId()) }, + metadata: { + user_id: this.user_id, ts: new Date() + } }] } - } - @updates = [{ - doc: @doc_id - op: [{ d: "foo ", p: 0 }] - v: 0 - meta: { user_id: @user_id } + }); + this.updates = [{ + doc: this.doc_id, + op: [{ d: "foo ", p: 0 }], + v: 0, + meta: { user_id: this.user_id } }, { - doc: @doc_id - op: [{ d: "bar ", p: 0 }] - v: 1 - meta: { user_id: @user_id } - }] - jobs = [] - for update in @updates - do (update) => - jobs.push (callback) => DocUpdaterClient.sendUpdate @project_id, @doc_id, update, callback - DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) => - throw error if error? - async.series jobs, (error) -> - throw error if error? - setTimeout () => - DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, data) => - throw error if error? - done() - , 200 + doc: this.doc_id, + op: [{ d: "bar ", p: 0 }], + v: 1, + meta: { user_id: this.user_id } + }]; + const jobs = []; + for (let update of Array.from(this.updates)) { + (update => { + return jobs.push(callback => DocUpdaterClient.sendUpdate(this.project_id, this.doc_id, update, callback)); + })(update); + } + return DocUpdaterClient.preloadDoc(this.project_id, this.doc_id, error => { + if (error != null) { throw error; } + return async.series(jobs, function(error) { + if (error != null) { throw error; } + return setTimeout(() => { + return DocUpdaterClient.getDoc(this.project_id, this.doc_id, (error, res, data) => { + if (error != null) { throw error; } + return done(); + }); + } + , 200); + }); + }); + }); - it "should write a snapshot from before the destructive change", (done) -> - DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, data) => - return done(error) if error? - db.docSnapshots.find { - project_id: ObjectId(@project_id), - doc_id: ObjectId(@doc_id) - }, (error, docSnapshots) => - return done(error) if error? - expect(docSnapshots.length).to.equal 1 - expect(docSnapshots[0].version).to.equal 1 - expect(docSnapshots[0].lines).to.deep.equal ["bar baz"] - expect(docSnapshots[0].ranges.comments[0].op).to.deep.equal { + return it("should write a snapshot from before the destructive change", function(done) { + return DocUpdaterClient.getDoc(this.project_id, this.doc_id, (error, res, data) => { + if (error != null) { return done(error); } + return db.docSnapshots.find({ + project_id: ObjectId(this.project_id), + doc_id: ObjectId(this.doc_id) + }, (error, docSnapshots) => { + if (error != null) { return done(error); } + expect(docSnapshots.length).to.equal(1); + expect(docSnapshots[0].version).to.equal(1); + expect(docSnapshots[0].lines).to.deep.equal(["bar baz"]); + expect(docSnapshots[0].ranges.comments[0].op).to.deep.equal({ c: "a", p: 1, - tid: @tid - } - done() + tid: this.tid + }); + return done(); + }); + }); + }); + }); +}); diff --git a/services/document-updater/test/acceptance/coffee/SettingADocumentTests.js b/services/document-updater/test/acceptance/coffee/SettingADocumentTests.js index 5ea43a39cc..1255a0a938 100644 --- a/services/document-updater/test/acceptance/coffee/SettingADocumentTests.js +++ b/services/document-updater/test/acceptance/coffee/SettingADocumentTests.js @@ -1,248 +1,320 @@ -sinon = require "sinon" -chai = require("chai") -chai.should() -expect = require("chai").expect -Settings = require('settings-sharelatex') -rclient_du = require("redis-sharelatex").createClient(Settings.redis.documentupdater) -Keys = Settings.redis.documentupdater.key_schema +/* + * 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 sinon = require("sinon"); +const chai = require("chai"); +chai.should(); +const { + expect +} = require("chai"); +const Settings = require('settings-sharelatex'); +const rclient_du = require("redis-sharelatex").createClient(Settings.redis.documentupdater); +const Keys = Settings.redis.documentupdater.key_schema; -MockTrackChangesApi = require "./helpers/MockTrackChangesApi" -MockProjectHistoryApi = require "./helpers/MockProjectHistoryApi" -MockWebApi = require "./helpers/MockWebApi" -DocUpdaterClient = require "./helpers/DocUpdaterClient" -DocUpdaterApp = require "./helpers/DocUpdaterApp" +const MockTrackChangesApi = require("./helpers/MockTrackChangesApi"); +const MockProjectHistoryApi = require("./helpers/MockProjectHistoryApi"); +const MockWebApi = require("./helpers/MockWebApi"); +const DocUpdaterClient = require("./helpers/DocUpdaterClient"); +const DocUpdaterApp = require("./helpers/DocUpdaterApp"); -describe "Setting a document", -> - before (done) -> - @lines = ["one", "two", "three"] - @version = 42 - @update = - doc: @doc_id +describe("Setting a document", function() { + before(function(done) { + this.lines = ["one", "two", "three"]; + this.version = 42; + this.update = { + doc: this.doc_id, op: [{ - i: "one and a half\n" + i: "one and a half\n", p: 4 - }] - v: @version - @result = ["one", "one and a half", "two", "three"] - @newLines = ["these", "are", "the", "new", "lines"] - @source = "dropbox" - @user_id = "user-id-123" + }], + v: this.version + }; + this.result = ["one", "one and a half", "two", "three"]; + this.newLines = ["these", "are", "the", "new", "lines"]; + this.source = "dropbox"; + this.user_id = "user-id-123"; - sinon.spy MockTrackChangesApi, "flushDoc" - sinon.spy MockProjectHistoryApi, "flushProject" - sinon.spy MockWebApi, "setDocument" - DocUpdaterApp.ensureRunning(done) + sinon.spy(MockTrackChangesApi, "flushDoc"); + sinon.spy(MockProjectHistoryApi, "flushProject"); + sinon.spy(MockWebApi, "setDocument"); + return DocUpdaterApp.ensureRunning(done); + }); - after -> - MockTrackChangesApi.flushDoc.restore() - MockProjectHistoryApi.flushProject.restore() - MockWebApi.setDocument.restore() + after(function() { + MockTrackChangesApi.flushDoc.restore(); + MockProjectHistoryApi.flushProject.restore(); + return MockWebApi.setDocument.restore(); + }); - describe "when the updated doc exists in the doc updater", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - MockWebApi.insertDoc @project_id, @doc_id, lines: @lines, version: @version - DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) => - throw error if error? - DocUpdaterClient.sendUpdate @project_id, @doc_id, @update, (error) => - throw error if error? - setTimeout () => - DocUpdaterClient.setDocLines @project_id, @doc_id, @newLines, @source, @user_id, false, (error, res, body) => - @statusCode = res.statusCode - done() - , 200 - return null + describe("when the updated doc exists in the doc updater", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); + MockWebApi.insertDoc(this.project_id, this.doc_id, {lines: this.lines, version: this.version}); + DocUpdaterClient.preloadDoc(this.project_id, this.doc_id, error => { + if (error != null) { throw error; } + return DocUpdaterClient.sendUpdate(this.project_id, this.doc_id, this.update, error => { + if (error != null) { throw error; } + return setTimeout(() => { + return DocUpdaterClient.setDocLines(this.project_id, this.doc_id, this.newLines, this.source, this.user_id, false, (error, res, body) => { + this.statusCode = res.statusCode; + return done(); + }); + } + , 200); + }); + }); + return null; + }); - after -> - MockTrackChangesApi.flushDoc.reset() - MockProjectHistoryApi.flushProject.reset() - MockWebApi.setDocument.reset() + after(function() { + MockTrackChangesApi.flushDoc.reset(); + MockProjectHistoryApi.flushProject.reset(); + return MockWebApi.setDocument.reset(); + }); - it "should return a 204 status code", -> - @statusCode.should.equal 204 + it("should return a 204 status code", function() { + return this.statusCode.should.equal(204); + }); - it "should send the updated doc lines and version to the web api", -> - MockWebApi.setDocument - .calledWith(@project_id, @doc_id, @newLines) - .should.equal true + it("should send the updated doc lines and version to the web api", function() { + return MockWebApi.setDocument + .calledWith(this.project_id, this.doc_id, this.newLines) + .should.equal(true); + }); - it "should update the lines in the doc updater", (done) -> - DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, doc) => - doc.lines.should.deep.equal @newLines - done() - return null + it("should update the lines in the doc updater", function(done) { + DocUpdaterClient.getDoc(this.project_id, this.doc_id, (error, res, doc) => { + doc.lines.should.deep.equal(this.newLines); + return done(); + }); + return null; + }); - it "should bump the version in the doc updater", (done) -> - DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, doc) => - doc.version.should.equal @version + 2 - done() - return null + it("should bump the version in the doc updater", function(done) { + DocUpdaterClient.getDoc(this.project_id, this.doc_id, (error, res, doc) => { + doc.version.should.equal(this.version + 2); + return done(); + }); + return null; + }); - it "should leave the document in redis", (done) -> - rclient_du.get Keys.docLines({doc_id: @doc_id}), (error, lines) => - throw error if error? - expect(JSON.parse(lines)).to.deep.equal @newLines - done() - return null + return it("should leave the document in redis", function(done) { + rclient_du.get(Keys.docLines({doc_id: this.doc_id}), (error, lines) => { + if (error != null) { throw error; } + expect(JSON.parse(lines)).to.deep.equal(this.newLines); + return done(); + }); + return null; + }); + }); - describe "when the updated doc does not exist in the doc updater", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} - DocUpdaterClient.setDocLines @project_id, @doc_id, @newLines, @source, @user_id, false, (error, res, body) => - @statusCode = res.statusCode - setTimeout done, 200 - return null + describe("when the updated doc does not exist in the doc updater", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); + MockWebApi.insertDoc(this.project_id, this.doc_id, {lines: this.lines, version: this.version}); + DocUpdaterClient.setDocLines(this.project_id, this.doc_id, this.newLines, this.source, this.user_id, false, (error, res, body) => { + this.statusCode = res.statusCode; + return setTimeout(done, 200); + }); + return null; + }); - after -> - MockTrackChangesApi.flushDoc.reset() - MockProjectHistoryApi.flushProject.reset() - MockWebApi.setDocument.reset() + after(function() { + MockTrackChangesApi.flushDoc.reset(); + MockProjectHistoryApi.flushProject.reset(); + return MockWebApi.setDocument.reset(); + }); - it "should return a 204 status code", -> - @statusCode.should.equal 204 + it("should return a 204 status code", function() { + return this.statusCode.should.equal(204); + }); - it "should send the updated doc lines to the web api", -> - MockWebApi.setDocument - .calledWith(@project_id, @doc_id, @newLines) - .should.equal true + it("should send the updated doc lines to the web api", function() { + return MockWebApi.setDocument + .calledWith(this.project_id, this.doc_id, this.newLines) + .should.equal(true); + }); - it "should flush track changes", -> - MockTrackChangesApi.flushDoc.calledWith(@doc_id).should.equal true + it("should flush track changes", function() { + return MockTrackChangesApi.flushDoc.calledWith(this.doc_id).should.equal(true); + }); - it "should flush project history", -> - MockProjectHistoryApi.flushProject.calledWith(@project_id).should.equal true + it("should flush project history", function() { + return MockProjectHistoryApi.flushProject.calledWith(this.project_id).should.equal(true); + }); - it "should remove the document from redis", (done) -> - rclient_du.get Keys.docLines({doc_id: @doc_id}), (error, lines) => - throw error if error? - expect(lines).to.not.exist - done() - return null + return it("should remove the document from redis", function(done) { + rclient_du.get(Keys.docLines({doc_id: this.doc_id}), (error, lines) => { + if (error != null) { throw error; } + expect(lines).to.not.exist; + return done(); + }); + return null; + }); + }); - describe "when the updated doc is too large for the body parser", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} - @newLines = [] - while JSON.stringify(@newLines).length < Settings.max_doc_length + 64 * 1024 - @newLines.push("(a long line of text)".repeat(10000)) - DocUpdaterClient.setDocLines @project_id, @doc_id, @newLines, @source, @user_id, false, (error, res, body) => - @statusCode = res.statusCode - setTimeout done, 200 - return null + describe("when the updated doc is too large for the body parser", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); + MockWebApi.insertDoc(this.project_id, this.doc_id, {lines: this.lines, version: this.version}); + this.newLines = []; + while (JSON.stringify(this.newLines).length < (Settings.max_doc_length + (64 * 1024))) { + this.newLines.push("(a long line of text)".repeat(10000)); + } + DocUpdaterClient.setDocLines(this.project_id, this.doc_id, this.newLines, this.source, this.user_id, false, (error, res, body) => { + this.statusCode = res.statusCode; + return setTimeout(done, 200); + }); + return null; + }); - after -> - MockTrackChangesApi.flushDoc.reset() - MockProjectHistoryApi.flushProject.reset() - MockWebApi.setDocument.reset() + after(function() { + MockTrackChangesApi.flushDoc.reset(); + MockProjectHistoryApi.flushProject.reset(); + return MockWebApi.setDocument.reset(); + }); - it "should return a 413 status code", -> - @statusCode.should.equal 413 + it("should return a 413 status code", function() { + return this.statusCode.should.equal(413); + }); - it "should not send the updated doc lines to the web api", -> - MockWebApi.setDocument.called.should.equal false + it("should not send the updated doc lines to the web api", () => MockWebApi.setDocument.called.should.equal(false)); - it "should not flush track changes", -> - MockTrackChangesApi.flushDoc.called.should.equal false + it("should not flush track changes", () => MockTrackChangesApi.flushDoc.called.should.equal(false)); - it "should not flush project history", -> - MockProjectHistoryApi.flushProject.called.should.equal false + return it("should not flush project history", () => MockProjectHistoryApi.flushProject.called.should.equal(false)); + }); - describe "when the updated doc is large but under the bodyParser and HTTPController size limit", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} + describe("when the updated doc is large but under the bodyParser and HTTPController size limit", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); + MockWebApi.insertDoc(this.project_id, this.doc_id, {lines: this.lines, version: this.version}); - @newLines = [] - while JSON.stringify(@newLines).length < 2 * 1024 * 1024 # limit in HTTPController - @newLines.push("(a long line of text)".repeat(10000)) - @newLines.pop() # remove the line which took it over the limit - DocUpdaterClient.setDocLines @project_id, @doc_id, @newLines, @source, @user_id, false, (error, res, body) => - @statusCode = res.statusCode - setTimeout done, 200 - return null + this.newLines = []; + while (JSON.stringify(this.newLines).length < (2 * 1024 * 1024)) { // limit in HTTPController + this.newLines.push("(a long line of text)".repeat(10000)); + } + this.newLines.pop(); // remove the line which took it over the limit + DocUpdaterClient.setDocLines(this.project_id, this.doc_id, this.newLines, this.source, this.user_id, false, (error, res, body) => { + this.statusCode = res.statusCode; + return setTimeout(done, 200); + }); + return null; + }); - after -> - MockTrackChangesApi.flushDoc.reset() - MockProjectHistoryApi.flushProject.reset() - MockWebApi.setDocument.reset() + after(function() { + MockTrackChangesApi.flushDoc.reset(); + MockProjectHistoryApi.flushProject.reset(); + return MockWebApi.setDocument.reset(); + }); - it "should return a 204 status code", -> - @statusCode.should.equal 204 + it("should return a 204 status code", function() { + return this.statusCode.should.equal(204); + }); - it "should send the updated doc lines to the web api", -> - MockWebApi.setDocument - .calledWith(@project_id, @doc_id, @newLines) - .should.equal true + return it("should send the updated doc lines to the web api", function() { + return MockWebApi.setDocument + .calledWith(this.project_id, this.doc_id, this.newLines) + .should.equal(true); + }); + }); - describe "with track changes", -> - before -> - @lines = ["one", "one and a half", "two", "three"] - @id_seed = "587357bd35e64f6157" - @update = - doc: @doc_id + return describe("with track changes", function() { + before(function() { + this.lines = ["one", "one and a half", "two", "three"]; + this.id_seed = "587357bd35e64f6157"; + return this.update = { + doc: this.doc_id, op: [{ - d: "one and a half\n" + d: "one and a half\n", p: 4 - }] - meta: - tc: @id_seed - user_id: @user_id - v: @version + }], + meta: { + tc: this.id_seed, + user_id: this.user_id + }, + v: this.version + }; + }); - describe "with the undo flag", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} - DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) => - throw error if error? - DocUpdaterClient.sendUpdate @project_id, @doc_id, @update, (error) => - throw error if error? - # Go back to old lines, with undo flag - DocUpdaterClient.setDocLines @project_id, @doc_id, @lines, @source, @user_id, true, (error, res, body) => - @statusCode = res.statusCode - setTimeout done, 200 - return null + describe("with the undo flag", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); + MockWebApi.insertDoc(this.project_id, this.doc_id, {lines: this.lines, version: this.version}); + DocUpdaterClient.preloadDoc(this.project_id, this.doc_id, error => { + if (error != null) { throw error; } + return DocUpdaterClient.sendUpdate(this.project_id, this.doc_id, this.update, error => { + if (error != null) { throw error; } + // Go back to old lines, with undo flag + return DocUpdaterClient.setDocLines(this.project_id, this.doc_id, this.lines, this.source, this.user_id, true, (error, res, body) => { + this.statusCode = res.statusCode; + return setTimeout(done, 200); + }); + }); + }); + return null; + }); - after -> - MockTrackChangesApi.flushDoc.reset() - MockProjectHistoryApi.flushProject.reset() - MockWebApi.setDocument.reset() + after(function() { + MockTrackChangesApi.flushDoc.reset(); + MockProjectHistoryApi.flushProject.reset(); + return MockWebApi.setDocument.reset(); + }); - it "should undo the tracked changes", (done) -> - DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, data) => - throw error if error? - ranges = data.ranges - expect(ranges.changes).to.be.undefined - done() - return null + return it("should undo the tracked changes", function(done) { + DocUpdaterClient.getDoc(this.project_id, this.doc_id, (error, res, data) => { + if (error != null) { throw error; } + const { + ranges + } = data; + expect(ranges.changes).to.be.undefined; + return done(); + }); + return null; + }); + }); - describe "without the undo flag", -> - before (done) -> - [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} - DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) => - throw error if error? - DocUpdaterClient.sendUpdate @project_id, @doc_id, @update, (error) => - throw error if error? - # Go back to old lines, without undo flag - DocUpdaterClient.setDocLines @project_id, @doc_id, @lines, @source, @user_id, false, (error, res, body) => - @statusCode = res.statusCode - setTimeout done, 200 - return null + return describe("without the undo flag", function() { + before(function(done) { + [this.project_id, this.doc_id] = Array.from([DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]); + MockWebApi.insertDoc(this.project_id, this.doc_id, {lines: this.lines, version: this.version}); + DocUpdaterClient.preloadDoc(this.project_id, this.doc_id, error => { + if (error != null) { throw error; } + return DocUpdaterClient.sendUpdate(this.project_id, this.doc_id, this.update, error => { + if (error != null) { throw error; } + // Go back to old lines, without undo flag + return DocUpdaterClient.setDocLines(this.project_id, this.doc_id, this.lines, this.source, this.user_id, false, (error, res, body) => { + this.statusCode = res.statusCode; + return setTimeout(done, 200); + }); + }); + }); + return null; + }); - after -> - MockTrackChangesApi.flushDoc.reset() - MockProjectHistoryApi.flushProject.reset() - MockWebApi.setDocument.reset() + after(function() { + MockTrackChangesApi.flushDoc.reset(); + MockProjectHistoryApi.flushProject.reset(); + return MockWebApi.setDocument.reset(); + }); - it "should not undo the tracked changes", (done) -> - DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, data) => - throw error if error? - ranges = data.ranges - expect(ranges.changes.length).to.equal 1 - done() - return null + return it("should not undo the tracked changes", function(done) { + DocUpdaterClient.getDoc(this.project_id, this.doc_id, (error, res, data) => { + if (error != null) { throw error; } + const { + ranges + } = data; + expect(ranges.changes.length).to.equal(1); + return done(); + }); + return null; + }); + }); + }); +}); diff --git a/services/document-updater/test/acceptance/coffee/helpers/DocUpdaterApp.js b/services/document-updater/test/acceptance/coffee/helpers/DocUpdaterApp.js index 0f77199e73..985458819a 100644 --- a/services/document-updater/test/acceptance/coffee/helpers/DocUpdaterApp.js +++ b/services/document-updater/test/acceptance/coffee/helpers/DocUpdaterApp.js @@ -1,20 +1,38 @@ -app = require('../../../../app') -require("logger-sharelatex").logger.level("fatal") +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * 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'); +require("logger-sharelatex").logger.level("fatal"); -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 3003, "localhost", (error) => - throw error if error? - @running = true - for callback in @callbacks - callback() +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(3003, "localhost", error => { + if (error != null) { throw error; } + this.running = true; + return (() => { + const result = []; + for (callback of Array.from(this.callbacks)) { + result.push(callback()); + } + return result; + })(); + }); + } + } +}; diff --git a/services/document-updater/test/acceptance/coffee/helpers/DocUpdaterClient.js b/services/document-updater/test/acceptance/coffee/helpers/DocUpdaterClient.js index b78f2aa7dd..09fad8c8f7 100644 --- a/services/document-updater/test/acceptance/coffee/helpers/DocUpdaterClient.js +++ b/services/document-updater/test/acceptance/coffee/helpers/DocUpdaterClient.js @@ -1,111 +1,171 @@ -Settings = require('settings-sharelatex') -rclient = require("redis-sharelatex").createClient(Settings.redis.documentupdater) -keys = Settings.redis.documentupdater.key_schema -request = require("request").defaults(jar: false) -async = require "async" +/* + * 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 + */ +let DocUpdaterClient; +const Settings = require('settings-sharelatex'); +const rclient = require("redis-sharelatex").createClient(Settings.redis.documentupdater); +const keys = Settings.redis.documentupdater.key_schema; +const request = require("request").defaults({jar: false}); +const async = require("async"); -rclient_sub = require("redis-sharelatex").createClient(Settings.redis.pubsub) -rclient_sub.subscribe "applied-ops" -rclient_sub.setMaxListeners(0) +const rclient_sub = require("redis-sharelatex").createClient(Settings.redis.pubsub); +rclient_sub.subscribe("applied-ops"); +rclient_sub.setMaxListeners(0); -module.exports = DocUpdaterClient = - randomId: () -> - chars = for i in [1..24] - Math.random().toString(16)[2] - return chars.join("") +module.exports = (DocUpdaterClient = { + randomId() { + const chars = __range__(1, 24, true).map((i) => + Math.random().toString(16)[2]); + return chars.join(""); + }, - subscribeToAppliedOps: (callback = (message) ->) -> - rclient_sub.on "message", callback + subscribeToAppliedOps(callback) { + if (callback == null) { callback = function(message) {}; } + return rclient_sub.on("message", callback); + }, - sendUpdate: (project_id, doc_id, update, callback = (error) ->) -> - rclient.rpush keys.pendingUpdates({doc_id}), JSON.stringify(update), (error)-> - return callback(error) if error? - doc_key = "#{project_id}:#{doc_id}" - rclient.sadd "DocsWithPendingUpdates", doc_key, (error) -> - return callback(error) if error? - rclient.rpush "pending-updates-list", doc_key, callback + sendUpdate(project_id, doc_id, update, callback) { + if (callback == null) { callback = function(error) {}; } + return rclient.rpush(keys.pendingUpdates({doc_id}), JSON.stringify(update), function(error){ + if (error != null) { return callback(error); } + const doc_key = `${project_id}:${doc_id}`; + return rclient.sadd("DocsWithPendingUpdates", doc_key, function(error) { + if (error != null) { return callback(error); } + return rclient.rpush("pending-updates-list", doc_key, callback); + }); + }); + }, - sendUpdates: (project_id, doc_id, updates, callback = (error) ->) -> - DocUpdaterClient.preloadDoc project_id, doc_id, (error) -> - return callback(error) if error? - jobs = [] - for update in updates - do (update) -> - jobs.push (callback) -> - DocUpdaterClient.sendUpdate project_id, doc_id, update, callback - async.series jobs, (err) -> - DocUpdaterClient.waitForPendingUpdates project_id, doc_id, callback + sendUpdates(project_id, doc_id, updates, callback) { + if (callback == null) { callback = function(error) {}; } + return DocUpdaterClient.preloadDoc(project_id, doc_id, function(error) { + if (error != null) { return callback(error); } + const jobs = []; + for (let update of Array.from(updates)) { + ((update => jobs.push(callback => DocUpdaterClient.sendUpdate(project_id, doc_id, update, callback))))(update); + } + return async.series(jobs, err => DocUpdaterClient.waitForPendingUpdates(project_id, doc_id, callback)); + }); + }, - waitForPendingUpdates: (project_id, doc_id, callback) -> - async.retry {times: 30, interval: 100}, (cb) -> - rclient.llen keys.pendingUpdates({doc_id}), (err, length) -> - if length > 0 - cb(new Error("updates still pending")) - else - cb() - , callback + waitForPendingUpdates(project_id, doc_id, callback) { + return async.retry({times: 30, interval: 100}, cb => rclient.llen(keys.pendingUpdates({doc_id}), function(err, length) { + if (length > 0) { + return cb(new Error("updates still pending")); + } else { + return cb(); + } + }) + , callback); + }, - getDoc: (project_id, doc_id, callback = (error, res, body) ->) -> - request.get "http://localhost:3003/project/#{project_id}/doc/#{doc_id}", (error, res, body) -> - if body? and res.statusCode >= 200 and res.statusCode < 300 - body = JSON.parse(body) - callback error, res, body + getDoc(project_id, doc_id, callback) { + if (callback == null) { callback = function(error, res, body) {}; } + return request.get(`http://localhost:3003/project/${project_id}/doc/${doc_id}`, function(error, res, body) { + if ((body != null) && (res.statusCode >= 200) && (res.statusCode < 300)) { + body = JSON.parse(body); + } + return callback(error, res, body); + }); + }, - getDocAndRecentOps: (project_id, doc_id, fromVersion, callback = (error, res, body) ->) -> - request.get "http://localhost:3003/project/#{project_id}/doc/#{doc_id}?fromVersion=#{fromVersion}", (error, res, body) -> - if body? and res.statusCode >= 200 and res.statusCode < 300 - body = JSON.parse(body) - callback error, res, body + getDocAndRecentOps(project_id, doc_id, fromVersion, callback) { + if (callback == null) { callback = function(error, res, body) {}; } + return request.get(`http://localhost:3003/project/${project_id}/doc/${doc_id}?fromVersion=${fromVersion}`, function(error, res, body) { + if ((body != null) && (res.statusCode >= 200) && (res.statusCode < 300)) { + body = JSON.parse(body); + } + return callback(error, res, body); + }); + }, - preloadDoc: (project_id, doc_id, callback = (error) ->) -> - DocUpdaterClient.getDoc project_id, doc_id, callback + preloadDoc(project_id, doc_id, callback) { + if (callback == null) { callback = function(error) {}; } + return DocUpdaterClient.getDoc(project_id, doc_id, callback); + }, - flushDoc: (project_id, doc_id, callback = (error) ->) -> - request.post "http://localhost:3003/project/#{project_id}/doc/#{doc_id}/flush", (error, res, body) -> - callback error, res, body + flushDoc(project_id, doc_id, callback) { + if (callback == null) { callback = function(error) {}; } + return request.post(`http://localhost:3003/project/${project_id}/doc/${doc_id}/flush`, (error, res, body) => callback(error, res, body)); + }, - setDocLines: (project_id, doc_id, lines, source, user_id, undoing, callback = (error) ->) -> - request.post { - url: "http://localhost:3003/project/#{project_id}/doc/#{doc_id}" - json: - lines: lines - source: source - user_id: user_id - undoing: undoing - }, (error, res, body) -> - callback error, res, body + setDocLines(project_id, doc_id, lines, source, user_id, undoing, callback) { + if (callback == null) { callback = function(error) {}; } + return request.post({ + url: `http://localhost:3003/project/${project_id}/doc/${doc_id}`, + json: { + lines, + source, + user_id, + undoing + } + }, (error, res, body) => callback(error, res, body)); + }, - deleteDoc: (project_id, doc_id, callback = (error) ->) -> - request.del "http://localhost:3003/project/#{project_id}/doc/#{doc_id}", (error, res, body) -> - callback error, res, body + deleteDoc(project_id, doc_id, callback) { + if (callback == null) { callback = function(error) {}; } + return request.del(`http://localhost:3003/project/${project_id}/doc/${doc_id}`, (error, res, body) => callback(error, res, body)); + }, - flushProject: (project_id, callback = () ->) -> - request.post "http://localhost:3003/project/#{project_id}/flush", callback + flushProject(project_id, callback) { + if (callback == null) { callback = function() {}; } + return request.post(`http://localhost:3003/project/${project_id}/flush`, callback); + }, - deleteProject: (project_id, callback = () ->) -> - request.del "http://localhost:3003/project/#{project_id}", callback + deleteProject(project_id, callback) { + if (callback == null) { callback = function() {}; } + return request.del(`http://localhost:3003/project/${project_id}`, callback); + }, - deleteProjectOnShutdown: (project_id, callback = () ->) -> - request.del "http://localhost:3003/project/#{project_id}?background=true&shutdown=true", callback + deleteProjectOnShutdown(project_id, callback) { + if (callback == null) { callback = function() {}; } + return request.del(`http://localhost:3003/project/${project_id}?background=true&shutdown=true`, callback); + }, - flushOldProjects: (callback = () ->) -> - request.get "http://localhost:3003/flush_queued_projects?min_delete_age=1", callback + flushOldProjects(callback) { + if (callback == null) { callback = function() {}; } + return request.get("http://localhost:3003/flush_queued_projects?min_delete_age=1", callback); + }, - acceptChange: (project_id, doc_id, change_id, callback = () ->) -> - request.post "http://localhost:3003/project/#{project_id}/doc/#{doc_id}/change/#{change_id}/accept", callback + acceptChange(project_id, doc_id, change_id, callback) { + if (callback == null) { callback = function() {}; } + return request.post(`http://localhost:3003/project/${project_id}/doc/${doc_id}/change/${change_id}/accept`, callback); + }, - removeComment: (project_id, doc_id, comment, callback = () ->) -> - request.del "http://localhost:3003/project/#{project_id}/doc/#{doc_id}/comment/#{comment}", callback + removeComment(project_id, doc_id, comment, callback) { + if (callback == null) { callback = function() {}; } + return request.del(`http://localhost:3003/project/${project_id}/doc/${doc_id}/comment/${comment}`, callback); + }, - getProjectDocs: (project_id, projectStateHash, callback = () ->) -> - request.get "http://localhost:3003/project/#{project_id}/doc?state=#{projectStateHash}", (error, res, body) -> - if body? and res.statusCode >= 200 and res.statusCode < 300 - body = JSON.parse(body) - callback error, res, body + getProjectDocs(project_id, projectStateHash, callback) { + if (callback == null) { callback = function() {}; } + return request.get(`http://localhost:3003/project/${project_id}/doc?state=${projectStateHash}`, function(error, res, body) { + if ((body != null) && (res.statusCode >= 200) && (res.statusCode < 300)) { + body = JSON.parse(body); + } + return callback(error, res, body); + }); + }, - sendProjectUpdate: (project_id, userId, docUpdates, fileUpdates, version, callback = (error) ->) -> - request.post { - url: "http://localhost:3003/project/#{project_id}" + sendProjectUpdate(project_id, userId, docUpdates, fileUpdates, version, callback) { + if (callback == null) { callback = function(error) {}; } + return request.post({ + url: `http://localhost:3003/project/${project_id}`, json: { userId, docUpdates, fileUpdates, version } - }, (error, res, body) -> - callback error, res, body + }, (error, res, body) => callback(error, res, body)); + } +}); + +function __range__(left, right, inclusive) { + let range = []; + let ascending = left < right; + let end = !inclusive ? right : ascending ? right + 1 : right - 1; + for (let i = left; ascending ? i < end : i > end; ascending ? i++ : i--) { + range.push(i); + } + return range; +} \ No newline at end of file diff --git a/services/document-updater/test/acceptance/coffee/helpers/MockProjectHistoryApi.js b/services/document-updater/test/acceptance/coffee/helpers/MockProjectHistoryApi.js index eb635225da..ba084fd108 100644 --- a/services/document-updater/test/acceptance/coffee/helpers/MockProjectHistoryApi.js +++ b/services/document-updater/test/acceptance/coffee/helpers/MockProjectHistoryApi.js @@ -1,19 +1,34 @@ -express = require("express") -app = 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 MockProjectHistoryApi; +const express = require("express"); +const app = express(); -module.exports = MockProjectHistoryApi = - flushProject: (doc_id, callback = (error) ->) -> - callback() +module.exports = (MockProjectHistoryApi = { + flushProject(doc_id, callback) { + if (callback == null) { callback = function(error) {}; } + return callback(); + }, - run: () -> - app.post "/project/:project_id/flush", (req, res, next) => - @flushProject req.params.project_id, (error) -> - if error? - res.sendStatus 500 - else - res.sendStatus 204 + run() { + app.post("/project/:project_id/flush", (req, res, next) => { + return this.flushProject(req.params.project_id, function(error) { + if (error != null) { + return res.sendStatus(500); + } else { + return res.sendStatus(204); + } + }); + }); - app.listen 3054, (error) -> - throw error if error? + return app.listen(3054, function(error) { + if (error != null) { throw error; } + }); + } +}); -MockProjectHistoryApi.run() +MockProjectHistoryApi.run(); diff --git a/services/document-updater/test/acceptance/coffee/helpers/MockTrackChangesApi.js b/services/document-updater/test/acceptance/coffee/helpers/MockTrackChangesApi.js index 924937fe39..bd217d5545 100644 --- a/services/document-updater/test/acceptance/coffee/helpers/MockTrackChangesApi.js +++ b/services/document-updater/test/acceptance/coffee/helpers/MockTrackChangesApi.js @@ -1,23 +1,38 @@ -express = require("express") -app = 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 MockTrackChangesApi; +const express = require("express"); +const app = express(); -module.exports = MockTrackChangesApi = - flushDoc: (doc_id, callback = (error) ->) -> - callback() +module.exports = (MockTrackChangesApi = { + flushDoc(doc_id, callback) { + if (callback == null) { callback = function(error) {}; } + return callback(); + }, - run: () -> - app.post "/project/:project_id/doc/:doc_id/flush", (req, res, next) => - @flushDoc req.params.doc_id, (error) -> - if error? - res.sendStatus 500 - else - res.sendStatus 204 + run() { + app.post("/project/:project_id/doc/:doc_id/flush", (req, res, next) => { + return this.flushDoc(req.params.doc_id, function(error) { + if (error != null) { + return res.sendStatus(500); + } else { + return res.sendStatus(204); + } + }); + }); - app.listen 3015, (error) -> - throw error if error? - .on "error", (error) -> - console.error "error starting MockTrackChangesApi:", error.message - process.exit(1) + return app.listen(3015, function(error) { + if (error != null) { throw error; } + }).on("error", function(error) { + console.error("error starting MockTrackChangesApi:", error.message); + return process.exit(1); + }); + } +}); -MockTrackChangesApi.run() +MockTrackChangesApi.run(); diff --git a/services/document-updater/test/acceptance/coffee/helpers/MockWebApi.js b/services/document-updater/test/acceptance/coffee/helpers/MockWebApi.js index 19b518f7c6..5069c20cb6 100644 --- a/services/document-updater/test/acceptance/coffee/helpers/MockWebApi.js +++ b/services/document-updater/test/acceptance/coffee/helpers/MockWebApi.js @@ -1,54 +1,75 @@ -express = require("express") -bodyParser = require("body-parser") -app = express() -MAX_REQUEST_SIZE = 2*(2*1024*1024 + 64*1024) +/* + * 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 MockWebApi; +const express = require("express"); +const bodyParser = require("body-parser"); +const app = express(); +const MAX_REQUEST_SIZE = 2*((2*1024*1024) + (64*1024)); -module.exports = MockWebApi = - docs: {} +module.exports = (MockWebApi = { + docs: {}, - clearDocs: () -> @docs = {} + clearDocs() { return this.docs = {}; }, - insertDoc: (project_id, doc_id, doc) -> - doc.version ?= 0 - doc.lines ?= [] - doc.pathname = '/a/b/c.tex' - @docs["#{project_id}:#{doc_id}"] = doc + insertDoc(project_id, doc_id, doc) { + if (doc.version == null) { doc.version = 0; } + if (doc.lines == null) { doc.lines = []; } + doc.pathname = '/a/b/c.tex'; + return this.docs[`${project_id}:${doc_id}`] = doc; + }, - setDocument: (project_id, doc_id, lines, version, ranges, lastUpdatedAt, lastUpdatedBy, callback = (error) ->) -> - doc = @docs["#{project_id}:#{doc_id}"] ||= {} - doc.lines = lines - doc.version = version - doc.ranges = ranges - doc.pathname = '/a/b/c.tex' - doc.lastUpdatedAt = lastUpdatedAt - doc.lastUpdatedBy = lastUpdatedBy - callback null + setDocument(project_id, doc_id, lines, version, ranges, lastUpdatedAt, lastUpdatedBy, callback) { + if (callback == null) { callback = function(error) {}; } + const doc = this.docs[`${project_id}:${doc_id}`] || (this.docs[`${project_id}:${doc_id}`] = {}); + doc.lines = lines; + doc.version = version; + doc.ranges = ranges; + doc.pathname = '/a/b/c.tex'; + doc.lastUpdatedAt = lastUpdatedAt; + doc.lastUpdatedBy = lastUpdatedBy; + return callback(null); + }, - getDocument: (project_id, doc_id, callback = (error, doc) ->) -> - callback null, @docs["#{project_id}:#{doc_id}"] + getDocument(project_id, doc_id, callback) { + if (callback == null) { callback = function(error, doc) {}; } + return callback(null, this.docs[`${project_id}:${doc_id}`]); + }, - run: () -> - app.get "/project/:project_id/doc/:doc_id", (req, res, next) => - @getDocument req.params.project_id, req.params.doc_id, (error, doc) -> - if error? - res.sendStatus 500 - else if doc? - res.send JSON.stringify doc - else - res.sendStatus 404 + run() { + app.get("/project/:project_id/doc/:doc_id", (req, res, next) => { + return this.getDocument(req.params.project_id, req.params.doc_id, function(error, doc) { + if (error != null) { + return res.sendStatus(500); + } else if (doc != null) { + return res.send(JSON.stringify(doc)); + } else { + return res.sendStatus(404); + } + }); + }); - app.post "/project/:project_id/doc/:doc_id", bodyParser.json({limit: MAX_REQUEST_SIZE}), (req, res, next) => - MockWebApi.setDocument req.params.project_id, req.params.doc_id, req.body.lines, req.body.version, req.body.ranges, req.body.lastUpdatedAt, req.body.lastUpdatedBy, (error) -> - if error? - res.sendStatus 500 - else - res.sendStatus 204 + app.post("/project/:project_id/doc/:doc_id", bodyParser.json({limit: MAX_REQUEST_SIZE}), (req, res, next) => { + return MockWebApi.setDocument(req.params.project_id, req.params.doc_id, req.body.lines, req.body.version, req.body.ranges, req.body.lastUpdatedAt, req.body.lastUpdatedBy, function(error) { + if (error != null) { + return res.sendStatus(500); + } else { + return res.sendStatus(204); + } + }); + }); - app.listen 3000, (error) -> - throw error if error? - .on "error", (error) -> - console.error "error starting MockWebApi:", error.message - process.exit(1) + return app.listen(3000, function(error) { + if (error != null) { throw error; } + }).on("error", function(error) { + console.error("error starting MockWebApi:", error.message); + return process.exit(1); + }); + } +}); -MockWebApi.run() +MockWebApi.run();