diff --git a/services/document-updater/Gruntfile.coffee b/services/document-updater/Gruntfile.coffee index 042fe32ce2..2e0e12dd66 100644 --- a/services/document-updater/Gruntfile.coffee +++ b/services/document-updater/Gruntfile.coffee @@ -1,13 +1,4 @@ module.exports = (grunt) -> - grunt.loadNpmTasks 'grunt-contrib-coffee' - grunt.loadNpmTasks 'grunt-contrib-clean' - grunt.loadNpmTasks 'grunt-mocha-test' - grunt.loadNpmTasks 'grunt-available-tasks' - grunt.loadNpmTasks 'grunt-execute' - grunt.loadNpmTasks 'grunt-bunyan' - grunt.loadNpmTasks 'grunt-forever' - grunt.loadNpmTasks 'grunt-shell' - grunt.initConfig forever: app: @@ -107,6 +98,15 @@ module.exports = (grunt) -> "help" ] + grunt.loadNpmTasks 'grunt-contrib-coffee' + grunt.loadNpmTasks 'grunt-contrib-clean' + grunt.loadNpmTasks 'grunt-mocha-test' + grunt.loadNpmTasks 'grunt-available-tasks' + grunt.loadNpmTasks 'grunt-execute' + grunt.loadNpmTasks 'grunt-bunyan' + grunt.loadNpmTasks 'grunt-forever' + grunt.loadNpmTasks 'grunt-shell' + grunt.registerTask 'help', 'Display this help list', 'availabletasks' grunt.registerTask 'compile:server', 'Compile the server side coffee script', ['clean:app', 'coffee:app', 'coffee:app_dir'] diff --git a/services/document-updater/app.coffee b/services/document-updater/app.coffee index df26b81a2f..f9099660c8 100644 --- a/services/document-updater/app.coffee +++ b/services/document-updater/app.coffee @@ -8,7 +8,6 @@ DispatchManager = require('./app/js/DispatchManager') Keys = require('./app/js/RedisKeyBuilder') Errors = require "./app/js/Errors" HttpController = require "./app/js/HttpController" -MongoHealthCheck = require('./app/js/MongoHealthCheck') redis = require("redis-sharelatex") rclient = redis.createClient(Settings.redis.web) @@ -60,13 +59,6 @@ app.get '/status', (req, res)-> else res.send('document updater is alive') -app.get '/health_check/mongo', (req, res, next) -> - MongoHealthCheck.isAlive (error) -> - if error? - res.send 500, error.message - else - res.send 200 - redisCheck = require("redis-sharelatex").activeHealthCheckRedis(Settings.redis.web) app.get "/health_check/redis", (req, res, next)-> if redisCheck.isAlive() diff --git a/services/document-updater/app/coffee/MongoHealthCheck.coffee b/services/document-updater/app/coffee/MongoHealthCheck.coffee deleted file mode 100644 index 3872c051c4..0000000000 --- a/services/document-updater/app/coffee/MongoHealthCheck.coffee +++ /dev/null @@ -1,26 +0,0 @@ -Settings = require "settings-sharelatex" -PersistenceManager = require "./PersistenceManager" - -module.exports = MongoHealthCheck = - isAlive: (_callback = (error) ->) -> - # We've seen very occasionally the doc-updater losing its connection to Mongo. - # E.g. https://sharelatex.hackpad.com/29th-Aug-2015-0650-0740-fHlw8RL8zuN - # It seems that the mongo callbacks never returned. - # Mongo is only called in the persistence manager, so we do a read-only - # test call, check that it's working, and returns in a reasonable time. - callback = (args...) -> - _callback(args...) - _callback = () -> - - doc_id = Settings.smokeTest?.doc_id - if !doc_id? - return callback(new Error("No test doc_id configured")) - - PersistenceManager.getDocVersionInMongo doc_id, (error, version) -> - return callback(error) if error? - callback(null) - - timeout = Settings.smokeTest?.timeout or 10000 - setTimeout () -> - callback(new Error("Mongo did not return in #{timeout}ms")) - , timeout \ No newline at end of file diff --git a/services/document-updater/app/coffee/PersistenceManager.coffee b/services/document-updater/app/coffee/PersistenceManager.coffee index 8d5578b4cf..fff037f6fc 100644 --- a/services/document-updater/app/coffee/PersistenceManager.coffee +++ b/services/document-updater/app/coffee/PersistenceManager.coffee @@ -2,7 +2,6 @@ request = require "request" Settings = require "settings-sharelatex" Errors = require "./Errors" Metrics = require "./Metrics" -{db, ObjectId} = require("./mongojs") logger = require "logger-sharelatex" # We have to be quick with HTTP calls because we're holding a lock that @@ -11,21 +10,7 @@ logger = require "logger-sharelatex" MAX_HTTP_REQUEST_LENGTH = 5000 # 5 seconds module.exports = PersistenceManager = - getDoc: (project_id, doc_id, callback = (error, lines, version) ->) -> - PersistenceManager.getDocFromWeb project_id, doc_id, (error, lines, track_changes, track_changes_entries) -> - return callback(error) if error? - PersistenceManager.getDocVersionInMongo doc_id, (error, version) -> - return callback(error) if error? - callback null, lines, version, track_changes, track_changes_entries - - setDoc: (project_id, doc_id, lines, version, track_changes, track_changes_entries, callback = (error) ->) -> - PersistenceManager.setDocInWeb project_id, doc_id, lines, track_changes, track_changes_entries, (error) -> - return callback(error) if error? - PersistenceManager.setDocVersionInMongo doc_id, version, (error) -> - return callback(error) if error? - callback() - - getDocFromWeb: (project_id, doc_id, _callback = (error, lines) ->) -> + getDoc: (project_id, doc_id, _callback = (error, lines, version, track_changes, track_changes_entries) ->) -> timer = new Metrics.Timer("persistenceManager.getDoc") callback = (args...) -> timer.done() @@ -50,13 +35,17 @@ module.exports = PersistenceManager = body = JSON.parse body catch e return callback(e) + if !body.lines? + return callback(new Error("web API response had no doc lines")) + if !body.version? or not body.version instanceof Number + return callback(new Error("web API response had no valid doc version")) return callback null, body.lines, body.track_changes, body.track_changes_entries else if res.statusCode == 404 return callback(new Errors.NotFoundError("doc not not found: #{url}")) else return callback(new Error("error accessing web API: #{url} #{res.statusCode}")) - setDocInWeb: (project_id, doc_id, lines, track_changes, track_changes_entries, _callback = (error) ->) -> + setDoc: (project_id, doc_id, lines, version, track_changes, track_changes_entries, _callback = (error) ->) -> timer = new Metrics.Timer("persistenceManager.setDoc") callback = (args...) -> timer.done() @@ -70,6 +59,7 @@ module.exports = PersistenceManager = lines: lines track_changes: track_changes track_changes_entries: track_changes_entries + version: version headers: "content-type": "application/json" auth: @@ -86,27 +76,4 @@ module.exports = PersistenceManager = return callback(new Errors.NotFoundError("doc not not found: #{url}")) else return callback(new Error("error accessing web API: #{url} #{res.statusCode}")) - - getDocVersionInMongo: (doc_id, callback = (error, version) ->) -> - db.docOps.find { - doc_id: ObjectId(doc_id) - }, { - version: 1 - }, (error, docs) -> - return callback(error) if error? - if docs.length < 1 or !docs[0].version? - return callback null, 0 - else - return callback null, docs[0].version - setDocVersionInMongo: (doc_id, version, callback = (error) ->) -> - db.docOps.update { - doc_id: ObjectId(doc_id) - }, { - $set: version: version - }, { - upsert: true - }, callback - - - diff --git a/services/document-updater/app/coffee/mongojs.coffee b/services/document-updater/app/coffee/mongojs.coffee deleted file mode 100644 index cf9f5fec86..0000000000 --- a/services/document-updater/app/coffee/mongojs.coffee +++ /dev/null @@ -1,6 +0,0 @@ -Settings = require "settings-sharelatex" -mongojs = require "mongojs" -db = mongojs.connect(Settings.mongo.url, ["docOps"]) -module.exports = - db: db - ObjectId: mongojs.ObjectId diff --git a/services/document-updater/package.json b/services/document-updater/package.json index 85958950d8..eaa8c726ec 100644 --- a/services/document-updater/package.json +++ b/services/document-updater/package.json @@ -11,10 +11,9 @@ "coffee-script": "1.4.0", "express": "3.3.4", "ioredis": "^2.2.0", - "logger-sharelatex": "git+https://github.com/sharelatex/logger-sharelatex.git#v1.0.0", + "logger-sharelatex": "git+https://github.com/sharelatex/logger-sharelatex.git#v1.5.1", "lynx": "0.0.11", "metrics-sharelatex": "git+https://github.com/sharelatex/metrics-sharelatex.git#v1.5.0", - "mongojs": "0.9.11", "redis-sharelatex": "0.0.9", "request": "2.25.0", "sandboxed-module": "~0.2.0", @@ -33,7 +32,7 @@ "grunt-contrib-clean": "~0.5.0", "grunt-contrib-coffee": "~0.10.0", "grunt-execute": "~0.1.5", - "grunt-forever": "0.4.1", + "grunt-forever": "^0.4.7", "grunt-mocha-test": "~0.9.0", "grunt-shell": "^1.3.0" } diff --git a/services/document-updater/test/acceptance/coffee/ApplyingUpdatesToADocTests.coffee b/services/document-updater/test/acceptance/coffee/ApplyingUpdatesToADocTests.coffee index 89f1acbcfe..4166f8499e 100644 --- a/services/document-updater/test/acceptance/coffee/ApplyingUpdatesToADocTests.coffee +++ b/services/document-updater/test/acceptance/coffee/ApplyingUpdatesToADocTests.coffee @@ -3,8 +3,8 @@ chai = require("chai") chai.should() expect = chai.expect async = require "async" -rclient = require("redis").createClient() -{db, ObjectId} = require "../../../app/js/mongojs" +Settings = require('settings-sharelatex') +rclient = require("redis-sharelatex").createClient(Settings.redis.web) MockTrackChangesApi = require "./helpers/MockTrackChangesApi" MockWebApi = require "./helpers/MockWebApi" @@ -28,15 +28,10 @@ describe "Applying updates to a doc", -> [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] sinon.spy MockWebApi, "getDocument" - MockWebApi.insertDoc @project_id, @doc_id, lines: @lines - db.docOps.insert { - doc_id: ObjectId(@doc_id) - version: @version - }, (error) => + MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} + DocUpdaterClient.sendUpdate @project_id, @doc_id, @update, (error) -> throw error if error? - DocUpdaterClient.sendUpdate @project_id, @doc_id, @update, (error) -> - throw error if error? - setTimeout done, 200 + setTimeout done, 200 after -> MockWebApi.getDocument.restore() @@ -65,15 +60,13 @@ describe "Applying updates to a doc", -> before (done) -> [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - MockWebApi.insertDoc @project_id, @doc_id, lines: @lines - db.docOps.insert doc_id: ObjectId(@doc_id), version: @version, (error) => + MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} + DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) => throw error if error? - DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) => + sinon.spy MockWebApi, "getDocument" + DocUpdaterClient.sendUpdate @project_id, @doc_id, @update, (error) -> throw error if error? - sinon.spy MockWebApi, "getDocument" - DocUpdaterClient.sendUpdate @project_id, @doc_id, @update, (error) -> - throw error if error? - setTimeout done, 200 + setTimeout done, 200 after -> MockWebApi.getDocument.restore() @@ -98,24 +91,22 @@ describe "Applying updates to a doc", -> before (done) -> [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] lines = ["", "", ""] - MockWebApi.insertDoc @project_id, @doc_id, lines: lines - db.docOps.insert doc_id: ObjectId(@doc_id), version: 0, (error) => - throw error if error? - @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() + 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() it "should be able to continue applying updates when the project has been deleted", (done) -> actions = [] @@ -154,21 +145,17 @@ describe "Applying updates to a doc", -> before (done) -> [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] lines = ["", "", ""] - MockWebApi.insertDoc @project_id, @doc_id, lines: lines - db.docOps.insert doc_id: ObjectId(@doc_id), version: 0, (error) => - throw error if error? - - @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() + 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() it "should be able to continue applying updates when the project has been deleted", (done) -> actions = [] @@ -189,12 +176,10 @@ describe "Applying updates to a doc", -> describe "with a broken update", -> before (done) -> [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - MockWebApi.insertDoc @project_id, @doc_id, lines: @lines - db.docOps.insert doc_id: ObjectId(@doc_id), version: @version, (error) => + MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} + DocUpdaterClient.sendUpdate @project_id, @doc_id, @undefined, (error) -> throw error if error? - DocUpdaterClient.sendUpdate @project_id, @doc_id, @undefined, (error) -> - throw error if error? - setTimeout done, 200 + setTimeout done, 200 it "should not update the doc", (done) -> DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, doc) => @@ -213,19 +198,17 @@ describe "Applying updates to a doc", -> sinon.spy MockTrackChangesApi, "flushDoc" - MockWebApi.insertDoc @project_id, @doc_id, lines: @lines - db.docOps.insert doc_id: ObjectId(@doc_id), version: 0, (error) => + MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: 0} + + # Send updates in chunks to causes multiple flushes + actions = [] + for i in [0..9] + 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? - - # Send updates in chunks to causes multiple flushes - actions = [] - for i in [0..9] - 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 + setTimeout done, 2000 after -> MockTrackChangesApi.flushDoc.restore() @@ -256,41 +239,37 @@ describe "Applying updates to a doc", -> describe "when the sending duplicate ops", -> before (done) -> [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - MockWebApi.insertDoc @project_id, @doc_id, lines: @lines - db.docOps.insert { - doc_id: ObjectId(@doc_id) - version: @version + MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} + + DocUpdaterClient.subscribeToAppliedOps @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 + op: [{ + i: "one and a half\n" + p: 4 + }] + v: @version + meta: + source: "ikHceq3yfAdQYzBo4-xZ" }, (error) => throw error if error? - # One user delete 'one', the next turns it into 'once'. The second becomes a NOP. - DocUpdaterClient.sendUpdate @project_id, @doc_id, { - doc: @doc_id - op: [{ - i: "one and a half\n" - p: 4 - }] - v: @version - meta: - source: "ikHceq3yfAdQYzBo4-xZ" - }, (error) => - throw error if error? - setTimeout () => - DocUpdaterClient.sendUpdate @project_id, @doc_id, { - doc: @doc_id - op: [{ - i: "one and a half\n" - p: 4 - }] - v: @version - dupIfSource: ["ikHceq3yfAdQYzBo4-xZ"] - meta: - source: "ikHceq3yfAdQYzBo4-xZ" - }, (error) => - throw error if error? - setTimeout done, 200 - , 200 - - DocUpdaterClient.subscribeToAppliedOps @messageCallback = sinon.stub() + setTimeout () => + DocUpdaterClient.sendUpdate @project_id, @doc_id, { + doc: @doc_id + op: [{ + i: "one and a half\n" + p: 4 + }] + v: @version + dupIfSource: ["ikHceq3yfAdQYzBo4-xZ"] + meta: + source: "ikHceq3yfAdQYzBo4-xZ" + }, (error) => + throw error if error? + setTimeout done, 200 + , 200 it "should update the doc", (done) -> DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, doc) => diff --git a/services/document-updater/test/acceptance/coffee/DeletingADocumentTests.coffee b/services/document-updater/test/acceptance/coffee/DeletingADocumentTests.coffee index e08b7fc12f..291b627a3e 100644 --- a/services/document-updater/test/acceptance/coffee/DeletingADocumentTests.coffee +++ b/services/document-updater/test/acceptance/coffee/DeletingADocumentTests.coffee @@ -1,7 +1,6 @@ sinon = require "sinon" chai = require("chai") chai.should() -{db, ObjectId} = require "../../../app/js/mongojs" MockTrackChangesApi = require "./helpers/MockTrackChangesApi" MockWebApi = require "./helpers/MockWebApi" @@ -28,47 +27,32 @@ describe "Deleting a document", -> describe "when the updated doc exists in the doc updater", -> before (done) -> [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - sinon.spy MockWebApi, "setDocumentLines" + sinon.spy MockWebApi, "setDocument" sinon.spy MockWebApi, "getDocument" - MockWebApi.insertDoc @project_id, @doc_id, lines: @lines - db.docOps.insert { - doc_id: ObjectId(@doc_id) - version: @version - }, (error) => + MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} + DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) => throw error if error? - DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) => + DocUpdaterClient.sendUpdate @project_id, @doc_id, @update, (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 + setTimeout () => + DocUpdaterClient.deleteDoc @project_id, @doc_id, (error, res, body) => + @statusCode = res.statusCode + setTimeout done, 200 + , 200 after -> - MockWebApi.setDocumentLines.restore() + MockWebApi.setDocument.restore() MockWebApi.getDocument.restore() it "should return a 204 status code", -> @statusCode.should.equal 204 - it "should send the updated document to the web api", -> - MockWebApi.setDocumentLines - .calledWith(@project_id, @doc_id, @result) + 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 write the version to mongo", (done) -> - db.docOps.find { - doc_id: ObjectId(@doc_id) - }, { - version: 1 - }, (error, docs) => - doc = docs[0] - doc.version.should.equal @version + 1 - done() - 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) => @@ -86,21 +70,21 @@ describe "Deleting a document", -> MockWebApi.insertDoc @project_id, @doc_id, { lines: @lines } - sinon.spy MockWebApi, "setDocumentLines" + sinon.spy MockWebApi, "setDocument" sinon.spy MockWebApi, "getDocument" DocUpdaterClient.deleteDoc @project_id, @doc_id, (error, res, body) => @statusCode = res.statusCode setTimeout done, 200 after -> - MockWebApi.setDocumentLines.restore() + MockWebApi.setDocument.restore() MockWebApi.getDocument.restore() it "should return a 204 status code", -> @statusCode.should.equal 204 it "should not need to send the updated document to the web api", -> - MockWebApi.setDocumentLines.called.should.equal false + MockWebApi.setDocument.called.should.equal false it "should need to reload the doc if read again", (done) -> MockWebApi.getDocument.called.should.equal.false diff --git a/services/document-updater/test/acceptance/coffee/DeletingAProjectTests.coffee b/services/document-updater/test/acceptance/coffee/DeletingAProjectTests.coffee index 2f7a47ff8b..27d241d97d 100644 --- a/services/document-updater/test/acceptance/coffee/DeletingAProjectTests.coffee +++ b/services/document-updater/test/acceptance/coffee/DeletingAProjectTests.coffee @@ -46,7 +46,7 @@ describe "Deleting a project", -> describe "with documents which have been updated", -> before (done) -> - sinon.spy MockWebApi, "setDocumentLines" + sinon.spy MockWebApi, "setDocument" async.series @docs.map((doc) => (callback) => DocUpdaterClient.preloadDoc @project_id, doc.id, (error) => @@ -62,14 +62,14 @@ describe "Deleting a project", -> , 200 after -> - MockWebApi.setDocumentLines.restore() + MockWebApi.setDocument.restore() it "should return a 204 status code", -> @statusCode.should.equal 204 it "should send each document to the web api", -> for doc in @docs - MockWebApi.setDocumentLines + MockWebApi.setDocument .calledWith(@project_id, doc.id, doc.updatedLines) .should.equal true diff --git a/services/document-updater/test/acceptance/coffee/FlushingAProjectTests.coffee b/services/document-updater/test/acceptance/coffee/FlushingAProjectTests.coffee index 61837fa2b6..f6f7818990 100644 --- a/services/document-updater/test/acceptance/coffee/FlushingAProjectTests.coffee +++ b/services/document-updater/test/acceptance/coffee/FlushingAProjectTests.coffee @@ -40,7 +40,7 @@ describe "Flushing a project", -> describe "with documents which have been updated", -> before (done) -> - sinon.spy MockWebApi, "setDocumentLines" + sinon.spy MockWebApi, "setDocument" async.series @docs.map((doc) => (callback) => @@ -57,14 +57,14 @@ describe "Flushing a project", -> , 200 after -> - MockWebApi.setDocumentLines.restore() + MockWebApi.setDocument.restore() it "should return a 204 status code", -> @statusCode.should.equal 204 it "should send each document to the web api", -> for doc in @docs - MockWebApi.setDocumentLines + MockWebApi.setDocument .calledWith(@project_id, doc.id, doc.updatedLines) .should.equal true diff --git a/services/document-updater/test/acceptance/coffee/FlushingDocsTests.coffee b/services/document-updater/test/acceptance/coffee/FlushingDocsTests.coffee index 8fe89de7be..47dddcd19a 100644 --- a/services/document-updater/test/acceptance/coffee/FlushingDocsTests.coffee +++ b/services/document-updater/test/acceptance/coffee/FlushingDocsTests.coffee @@ -3,7 +3,6 @@ chai = require("chai") chai.should() expect = chai.expect async = require "async" -{db, ObjectId} = require "../../../app/js/mongojs" MockWebApi = require "./helpers/MockWebApi" DocUpdaterClient = require "./helpers/DocUpdaterClient" @@ -24,53 +23,37 @@ describe "Flushing a doc to Mongo", -> describe "when the updated doc exists in the doc updater", -> before (done) -> [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - sinon.spy MockWebApi, "setDocumentLines" + sinon.spy MockWebApi, "setDocument" - MockWebApi.insertDoc @project_id, @doc_id, lines: @lines - db.docOps.insert { - doc_id: ObjectId(@doc_id) - version: @version - }, (error) => + MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} + DocUpdaterClient.sendUpdates @project_id, @doc_id, [@update], (error) => throw error if error? - DocUpdaterClient.sendUpdates @project_id, @doc_id, [@update], (error) => - throw error if error? - setTimeout () => - DocUpdaterClient.flushDoc @project_id, @doc_id, done - , 200 + setTimeout () => + DocUpdaterClient.flushDoc @project_id, @doc_id, done + , 200 after -> - MockWebApi.setDocumentLines.restore() + MockWebApi.setDocument.restore() - it "should flush the updated doc lines to the web api", -> - MockWebApi.setDocumentLines - .calledWith(@project_id, @doc_id, @result) + 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 store the updated doc version into mongo", (done) -> - db.docOps.find { - doc_id: ObjectId(@doc_id) - }, { - version: 1 - }, (error, docs) => - doc = docs[0] - doc.version.should.equal @version + 1 - done() - - 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, "setDocumentLines" + sinon.spy MockWebApi, "setDocument" DocUpdaterClient.flushDoc @project_id, @doc_id, done after -> - MockWebApi.setDocumentLines.restore() + MockWebApi.setDocument.restore() it "should not flush the doc to the web api", -> - MockWebApi.setDocumentLines.called.should.equal false + MockWebApi.setDocument.called.should.equal false describe "when the web api http request takes a long time", -> before (done) -> @@ -78,19 +61,14 @@ describe "Flushing a doc to Mongo", -> @timeout = 10000 MockWebApi.insertDoc @project_id, @doc_id, { lines: @lines - } - sinon.stub MockWebApi, "setDocumentLines", (project_id, doc_id, lines, callback = (error) ->) -> - setTimeout callback, 30000 - - db.docOps.insert { - doc_id: ObjectId(@doc_id) version: @version - }, (error) => - throw error if error? - DocUpdaterClient.preloadDoc @project_id, @doc_id, done + } + sinon.stub MockWebApi, "setDocument", (project_id, doc_id, lines, version, callback = (error) ->) -> + setTimeout callback, 30000 + DocUpdaterClient.preloadDoc @project_id, @doc_id, done after -> - MockWebApi.setDocumentLines.restore() + MockWebApi.setDocument.restore() it "should return quickly(ish)", (done) -> start = Date.now() diff --git a/services/document-updater/test/acceptance/coffee/GettingADocumentTests.coffee b/services/document-updater/test/acceptance/coffee/GettingADocumentTests.coffee index 0823b8483a..67bbd6ea80 100644 --- a/services/document-updater/test/acceptance/coffee/GettingADocumentTests.coffee +++ b/services/document-updater/test/acceptance/coffee/GettingADocumentTests.coffee @@ -2,7 +2,6 @@ sinon = require "sinon" chai = require("chai") chai.should() expect = chai.expect -{db, ObjectId} = require "../../../app/js/mongojs" MockWebApi = require "./helpers/MockWebApi" DocUpdaterClient = require "./helpers/DocUpdaterClient" @@ -18,13 +17,9 @@ describe "Getting a document", -> [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] sinon.spy MockWebApi, "getDocument" - MockWebApi.insertDoc @project_id, @doc_id, lines: @lines - db.docOps.insert { - doc_id: ObjectId(@doc_id) - version: @version - }, (error) => - throw error if error? - DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, @returnedDoc) => done() + MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} + + DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, @returnedDoc) => done() after -> MockWebApi.getDocument.restore() @@ -44,16 +39,11 @@ describe "Getting a document", -> before (done) -> [@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()] - MockWebApi.insertDoc @project_id, @doc_id, lines: @lines - db.docOps.insert { - doc_id: ObjectId(@doc_id) - version: @version - }, (error) => + MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} + DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) => throw error if error? - 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() + sinon.spy MockWebApi, "getDocument" + DocUpdaterClient.getDoc @project_id, @doc_id, (error, res, @returnedDoc) => done() after -> MockWebApi.getDocument.restore() diff --git a/services/document-updater/test/acceptance/coffee/SettingADocumentTests.coffee b/services/document-updater/test/acceptance/coffee/SettingADocumentTests.coffee index 0d05e30982..3232c6e219 100644 --- a/services/document-updater/test/acceptance/coffee/SettingADocumentTests.coffee +++ b/services/document-updater/test/acceptance/coffee/SettingADocumentTests.coffee @@ -2,8 +2,8 @@ sinon = require "sinon" chai = require("chai") chai.should() expect = require("chai").expect -{db, ObjectId} = require "../../../app/js/mongojs" -rclient = require("redis").createClient() +Settings = require('settings-sharelatex') +rclient = require("redis-sharelatex").createClient(Settings.redis.web) MockTrackChangesApi = require "./helpers/MockTrackChangesApi" MockWebApi = require "./helpers/MockWebApi" @@ -26,36 +26,31 @@ describe "Setting a document", -> @user_id = "user-id-123" sinon.spy MockTrackChangesApi, "flushDoc" - sinon.spy MockWebApi, "setDocumentLines" + sinon.spy MockWebApi, "setDocument" after -> - MockWebApi.setDocumentLines.restore() + MockWebApi.setDocument.restore() MockTrackChangesApi.flushDoc.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 - db.docOps.insert { - doc_id: ObjectId(@doc_id) - version: @version - }, (error) => + MockWebApi.insertDoc @project_id, @doc_id, lines: @lines, version: @version + DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) => throw error if error? - DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) => + DocUpdaterClient.sendUpdate @project_id, @doc_id, @update, (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, (error, res, body) => - @statusCode = res.statusCode - done() - , 200 + setTimeout () => + DocUpdaterClient.setDocLines @project_id, @doc_id, @newLines, @source, @user_id, (error, res, body) => + @statusCode = res.statusCode + done() + , 200 it "should return a 204 status code", -> @statusCode.should.equal 204 - it "should send the updated doc lines to the web api", -> - MockWebApi.setDocumentLines + it "should send the updated doc lines and version to the web api", -> + MockWebApi.setDocument .calledWith(@project_id, @doc_id, @newLines) .should.equal true @@ -78,21 +73,16 @@ describe "Setting a document", -> 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 - db.docOps.insert { - doc_id: ObjectId(@doc_id) - version: @version - }, (error) => - throw error if error? - DocUpdaterClient.setDocLines @project_id, @doc_id, @newLines, @source, @user_id, (error, res, body) => - @statusCode = res.statusCode - setTimeout done, 200 + MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version} + DocUpdaterClient.setDocLines @project_id, @doc_id, @newLines, @source, @user_id, (error, res, body) => + @statusCode = res.statusCode + setTimeout done, 200 it "should return a 204 status code", -> @statusCode.should.equal 204 it "should send the updated doc lines to the web api", -> - MockWebApi.setDocumentLines + MockWebApi.setDocument .calledWith(@project_id, @doc_id, @newLines) .should.equal true diff --git a/services/document-updater/test/acceptance/coffee/helpers/MockWebApi.coffee b/services/document-updater/test/acceptance/coffee/helpers/MockWebApi.coffee index 7bab5b9b9f..e77a18c0ea 100644 --- a/services/document-updater/test/acceptance/coffee/helpers/MockWebApi.coffee +++ b/services/document-updater/test/acceptance/coffee/helpers/MockWebApi.coffee @@ -7,11 +7,14 @@ module.exports = MockWebApi = clearDocs: () -> @docs = {} insertDoc: (project_id, doc_id, doc) -> + doc.version ?= 0 + doc.lines ?= [] @docs["#{project_id}:#{doc_id}"] = doc - setDocumentLines: (project_id, doc_id, lines, callback = (error) ->) -> - @docs["#{project_id}:#{doc_id}"] ||= {} - @docs["#{project_id}:#{doc_id}"].lines = lines + setDocument: (project_id, doc_id, lines, version, callback = (error) ->) -> + doc = @docs["#{project_id}:#{doc_id}"] ||= {} + doc.lines = lines + doc.version = version callback null getDocument: (project_id, doc_id, callback = (error, doc) ->) -> @@ -28,7 +31,7 @@ module.exports = MockWebApi = res.send 404 app.post "/project/:project_id/doc/:doc_id", express.bodyParser(), (req, res, next) => - MockWebApi.setDocumentLines req.params.project_id, req.params.doc_id, req.body.lines, (error) -> + MockWebApi.setDocument req.params.project_id, req.params.doc_id, req.body.lines, req.body.version, (error) -> if error? res.send 500 else diff --git a/services/document-updater/test/acceptance/scripts/full-test.sh b/services/document-updater/test/acceptance/scripts/full-test.sh old mode 100644 new mode 100755 index 32fa62133c..af8ad4103d --- a/services/document-updater/test/acceptance/scripts/full-test.sh +++ b/services/document-updater/test/acceptance/scripts/full-test.sh @@ -1,20 +1,22 @@ #! /usr/bin/env bash +npm rebuild + echo ">> Starting server..." -grunt execute:app >> /dev/null & -_pid="$!" +grunt --no-color forever:app:start -echo ">> Server started with pid: $_pid" +echo ">> Server started" -sleep 20 +sleep 5 echo ">> Running acceptance tests..." -grunt mochaTest:acceptance +grunt --no-color test:acceptance _test_exit_code=$? -echo ">> Killing server (pid: $_pid)" -kill -1 "$_pid" +echo ">> Killing server" + +grunt --no-color forever:app:stop echo ">> Done" diff --git a/services/document-updater/test/unit/coffee/MongoHealthCheckTests/MongoHealthCheckTests.coffee b/services/document-updater/test/unit/coffee/MongoHealthCheckTests/MongoHealthCheckTests.coffee deleted file mode 100644 index b8da766a4c..0000000000 --- a/services/document-updater/test/unit/coffee/MongoHealthCheckTests/MongoHealthCheckTests.coffee +++ /dev/null @@ -1,52 +0,0 @@ -SandboxedModule = require('sandboxed-module') -sinon = require('sinon') -require('chai').should() -modulePath = require('path').join __dirname, '../../../../app/js/MongoHealthCheck' - -describe "MongoHealthCheck", -> - beforeEach -> - @MongoHealthCheck = SandboxedModule.require modulePath, requires: - "settings-sharelatex": @Settings = {} - "./PersistenceManager": @PersistenceManager = {} - @doc_id = "mock-doc-id" - @callback = sinon.stub() - - describe "isAlive", -> - describe "with no configured doc_id", -> - beforeEach -> - @MongoHealthCheck.isAlive @callback - - it "should call the call the callback with an error", -> - @callback.calledOnce.should.equal true - error = @callback.args[0][0] - error.message.should.equal "No test doc_id configured" - - describe "when mongo returns within the timeout", -> - beforeEach -> - @Settings.smokeTest = - doc_id: @doc_id - @PersistenceManager.getDocVersionInMongo = sinon.stub().callsArg(1) - @MongoHealthCheck.isAlive @callback - - it "should call PersistenceManager.getDocVersionInMongo", -> - @PersistenceManager.getDocVersionInMongo - .calledWith(@doc_id) - .should.equal true - - it "should call the call the callback without an error", -> - @callback.calledOnce.should.equal true - @callback.calledWith(null).should.equal true - - describe "when mongo does not return within the timeout", -> - beforeEach (done) -> - @Settings.smokeTest = - doc_id: @doc_id - timeout: 50 - @PersistenceManager.getDocVersionInMongo = (doc_id, callback) -> - setTimeout callback, 100 - @MongoHealthCheck.isAlive (@error) => - done() - - it "should call the call the callback with an error", -> - @error.message.should.equal "Mongo did not return in 50ms" - \ No newline at end of file diff --git a/services/document-updater/test/unit/coffee/PersistenceManager/getDocFromWebTests.coffee b/services/document-updater/test/unit/coffee/PersistenceManager/getDocFromWebTests.coffee deleted file mode 100644 index e782c0065b..0000000000 --- a/services/document-updater/test/unit/coffee/PersistenceManager/getDocFromWebTests.coffee +++ /dev/null @@ -1,87 +0,0 @@ -sinon = require('sinon') -chai = require('chai') -should = chai.should() -modulePath = "../../../../app/js/PersistenceManager.js" -SandboxedModule = require('sandboxed-module') -Errors = require "../../../../app/js/Errors" - -describe "PersistenceManager.getDocFromWeb", -> - beforeEach -> - @PersistenceManager = SandboxedModule.require modulePath, requires: - "request": @request = sinon.stub() - "settings-sharelatex": @Settings = {} - "./Metrics": @Metrics = - Timer: class Timer - done: sinon.stub() - "logger-sharelatex": @logger = {log: sinon.stub(), err: sinon.stub()} - @project_id = "project-id-123" - @doc_id = "doc-id-123" - @lines = ["one", "two", "three"] - @callback = sinon.stub() - @Settings.apis = - web: - url: @url = "www.example.com" - user: @user = "sharelatex" - pass: @pass = "password" - - describe "with a successful response from the web api", -> - beforeEach -> - @request.callsArgWith(1, null, {statusCode: 200}, JSON.stringify(lines: @lines)) - @PersistenceManager.getDocFromWeb(@project_id, @doc_id, @callback) - - it "should call the web api", -> - @request - .calledWith({ - url: "#{@url}/project/#{@project_id}/doc/#{@doc_id}" - method: "GET" - headers: - "accept": "application/json" - auth: - user: @user - pass: @pass - sendImmediately: true - jar: false - timeout: 5000 - }) - .should.equal true - - it "should call the callback with the doc lines", -> - @callback.calledWith(null, @lines).should.equal true - - it "should time the execution", -> - @Metrics.Timer::done.called.should.equal true - - describe "when request returns an error", -> - beforeEach -> - @request.callsArgWith(1, @error = new Error("oops"), null, null) - @PersistenceManager.getDocFromWeb(@project_id, @doc_id, @callback) - - it "should return the error", -> - @callback.calledWith(@error).should.equal true - - it "should time the execution", -> - @Metrics.Timer::done.called.should.equal true - - describe "when the request returns 404", -> - beforeEach -> - @request.callsArgWith(1, null, {statusCode: 404}, "") - @PersistenceManager.getDocFromWeb(@project_id, @doc_id, @callback) - - it "should return a NotFoundError", -> - @callback.calledWith(new Errors.NotFoundError("not found")).should.equal true - - it "should time the execution", -> - @Metrics.Timer::done.called.should.equal true - - describe "when the request returns an error status code", -> - beforeEach -> - @request.callsArgWith(1, null, {statusCode: 500}, "") - @PersistenceManager.getDocFromWeb(@project_id, @doc_id, @callback) - - it "should return an error", -> - @callback.calledWith(new Error("web api error")).should.equal true - - it "should time the execution", -> - @Metrics.Timer::done.called.should.equal true - - diff --git a/services/document-updater/test/unit/coffee/PersistenceManager/getDocTests.coffee b/services/document-updater/test/unit/coffee/PersistenceManager/getDocTests.coffee index ae3e476ec4..d4f44afa46 100644 --- a/services/document-updater/test/unit/coffee/PersistenceManager/getDocTests.coffee +++ b/services/document-updater/test/unit/coffee/PersistenceManager/getDocTests.coffee @@ -3,7 +3,7 @@ chai = require('chai') should = chai.should() modulePath = "../../../../app/js/PersistenceManager.js" SandboxedModule = require('sandboxed-module') -{ObjectId} = require("mongojs") +Errors = require "../../../../app/js/Errors" describe "PersistenceManager.getDoc", -> beforeEach -> @@ -13,34 +13,92 @@ describe "PersistenceManager.getDoc", -> "./Metrics": @Metrics = Timer: class Timer done: sinon.stub() - "logger-sharelatex": @logger = {warn: sinon.stub()} - "./mongojs": - db: @db = { docOps: {} } - ObjectId: ObjectId - - @project_id = ObjectId().toString() - @doc_id = ObjectId().toString() - @callback = sinon.stub() - @lines = ["mock", "doc", "lines"] + "logger-sharelatex": @logger = {log: sinon.stub(), err: sinon.stub()} + @project_id = "project-id-123" + @doc_id = "doc-id-123" + @lines = ["one", "two", "three"] @version = 42 + @callback = sinon.stub() + @Settings.apis = + web: + url: @url = "www.example.com" + user: @user = "sharelatex" + pass: @pass = "password" - describe "successfully", -> + describe "with a successful response from the web api", -> beforeEach -> - @PersistenceManager.getDocFromWeb = sinon.stub().callsArgWith(2, null, @lines) - @PersistenceManager.getDocVersionInMongo = sinon.stub().callsArgWith(1, null, @version) - @PersistenceManager.getDoc @project_id, @doc_id, @callback + @request.callsArgWith(1, null, {statusCode: 200}, JSON.stringify(lines: @lines, version: @version)) + @PersistenceManager.getDoc(@project_id, @doc_id, @callback) - it "should look up the doc in the web api", -> - @PersistenceManager.getDocFromWeb - .calledWith(@project_id, @doc_id) + it "should call the web api", -> + @request + .calledWith({ + url: "#{@url}/project/#{@project_id}/doc/#{@doc_id}" + method: "GET" + headers: + "accept": "application/json" + auth: + user: @user + pass: @pass + sendImmediately: true + jar: false + timeout: 5000 + }) .should.equal true - it "should look up the version in Mongo", -> - @PersistenceManager.getDocVersionInMongo - .calledWith(@doc_id) - .should.equal true - - it "should call the callback with the lines and version", -> + it "should call the callback with the doc lines and version", -> @callback.calledWith(null, @lines, @version).should.equal true + it "should time the execution", -> + @Metrics.Timer::done.called.should.equal true + describe "when request returns an error", -> + beforeEach -> + @request.callsArgWith(1, @error = new Error("oops"), null, null) + @PersistenceManager.getDoc(@project_id, @doc_id, @callback) + + it "should return the error", -> + @callback.calledWith(@error).should.equal true + + it "should time the execution", -> + @Metrics.Timer::done.called.should.equal true + + describe "when the request returns 404", -> + beforeEach -> + @request.callsArgWith(1, null, {statusCode: 404}, "") + @PersistenceManager.getDoc(@project_id, @doc_id, @callback) + + it "should return a NotFoundError", -> + @callback.calledWith(new Errors.NotFoundError("not found")).should.equal true + + it "should time the execution", -> + @Metrics.Timer::done.called.should.equal true + + describe "when the request returns an error status code", -> + beforeEach -> + @request.callsArgWith(1, null, {statusCode: 500}, "") + @PersistenceManager.getDoc(@project_id, @doc_id, @callback) + + it "should return an error", -> + @callback.calledWith(new Error("web api error")).should.equal true + + it "should time the execution", -> + @Metrics.Timer::done.called.should.equal true + + describe "when request returns an doc without lines", -> + beforeEach -> + @request.callsArgWith(1, null, {statusCode: 200}, JSON.stringify(version: @version)) + @PersistenceManager.getDoc(@project_id, @doc_id, @callback) + + it "should return and error", -> + @callback.calledWith(new Error("web API response had no doc lines")).should.equal true + + describe "when request returns an doc without a version", -> + beforeEach -> + @request.callsArgWith(1, null, {statusCode: 200}, JSON.stringify(lines: @lines)) + @PersistenceManager.getDoc(@project_id, @doc_id, @callback) + + it "should return and error", -> + @callback.calledWith(new Error("web API response had no valid doc version")).should.equal true + + diff --git a/services/document-updater/test/unit/coffee/PersistenceManager/getDocVersionInMongoTests.coffee b/services/document-updater/test/unit/coffee/PersistenceManager/getDocVersionInMongoTests.coffee deleted file mode 100644 index 2ab89f6795..0000000000 --- a/services/document-updater/test/unit/coffee/PersistenceManager/getDocVersionInMongoTests.coffee +++ /dev/null @@ -1,47 +0,0 @@ -sinon = require('sinon') -chai = require('chai') -should = chai.should() -modulePath = "../../../../app/js/PersistenceManager.js" -SandboxedModule = require('sandboxed-module') -Errors = require "../../../../app/js/Errors" -{ObjectId} = require("mongojs") - -describe "PersistenceManager.getDocVersionInMongo", -> - beforeEach -> - @PersistenceManager = SandboxedModule.require modulePath, requires: - "request": @request = sinon.stub() - "settings-sharelatex": @Settings = {} - "./Metrics": @Metrics = - Timer: class Timer - done: sinon.stub() - "./mongojs": - db: @db = { docOps: {} } - ObjectId: ObjectId - "logger-sharelatex": @logger = {log: sinon.stub(), err: sinon.stub()} - - @doc_id = ObjectId().toString() - @callback = sinon.stub() - - describe "getDocVersionInMongo", -> - describe "when the doc exists", -> - beforeEach -> - @doc = - version: @version = 42 - @db.docOps.find = sinon.stub().callsArgWith(2, null, [@doc]) - @PersistenceManager.getDocVersionInMongo @doc_id, @callback - - it "should look for the doc in the database", -> - @db.docOps.find - .calledWith({ doc_id: ObjectId(@doc_id) }, {version: 1}) - .should.equal true - - it "should call the callback with the version", -> - @callback.calledWith(null, @version).should.equal true - - describe "when the doc doesn't exist", -> - beforeEach -> - @db.docOps.find = sinon.stub().callsArgWith(2, null, []) - @PersistenceManager.getDocVersionInMongo @doc_id, @callback - - it "should call the callback with 0", -> - @callback.calledWith(null, 0).should.equal true \ No newline at end of file diff --git a/services/document-updater/test/unit/coffee/PersistenceManager/setDocInWebTests.coffee b/services/document-updater/test/unit/coffee/PersistenceManager/setDocInWebTests.coffee deleted file mode 100644 index b70c7dbe1b..0000000000 --- a/services/document-updater/test/unit/coffee/PersistenceManager/setDocInWebTests.coffee +++ /dev/null @@ -1,88 +0,0 @@ -sinon = require('sinon') -chai = require('chai') -should = chai.should() -modulePath = "../../../../app/js/PersistenceManager.js" -SandboxedModule = require('sandboxed-module') -Errors = require "../../../../app/js/Errors" - -describe "PersistenceManager.setDocInWeb", -> - beforeEach -> - @PersistenceManager = SandboxedModule.require modulePath, requires: - "request": @request = sinon.stub() - "settings-sharelatex": @Settings = {} - "./Metrics": @Metrics = - Timer: class Timer - done: sinon.stub() - "logger-sharelatex": @logger = {log: sinon.stub(), err: sinon.stub()} - @project_id = "project-id-123" - @doc_id = "doc-id-123" - @lines = ["one", "two", "three"] - @callback = sinon.stub() - @Settings.apis = - web: - url: @url = "www.example.com" - user: @user = "sharelatex" - pass: @pass = "password" - - describe "with a successful response from the web api", -> - beforeEach -> - @request.callsArgWith(1, null, {statusCode: 200}, JSON.stringify(lines: @lines, version: @version)) - @PersistenceManager.setDocInWeb(@project_id, @doc_id, @lines, @callback) - - it "should call the web api", -> - @request - .calledWith({ - url: "#{@url}/project/#{@project_id}/doc/#{@doc_id}" - body: JSON.stringify - lines: @lines - method: "POST" - headers: - "content-type": "application/json" - auth: - user: @user - pass: @pass - sendImmediately: true - jar: false - timeout: 5000 - }) - .should.equal true - - it "should call the callback without error", -> - @callback.calledWith(null).should.equal true - - it "should time the execution", -> - @Metrics.Timer::done.called.should.equal true - - describe "when request returns an error", -> - beforeEach -> - @request.callsArgWith(1, @error = new Error("oops"), null, null) - @PersistenceManager.setDocInWeb(@project_id, @doc_id, @lines, @callback) - - it "should return the error", -> - @callback.calledWith(@error).should.equal true - - it "should time the execution", -> - @Metrics.Timer::done.called.should.equal true - - describe "when the request returns 404", -> - beforeEach -> - @request.callsArgWith(1, null, {statusCode: 404}, "") - @PersistenceManager.setDocInWeb(@project_id, @doc_id, @lines, @callback) - - it "should return a NotFoundError", -> - @callback.calledWith(new Errors.NotFoundError("not found")).should.equal true - - it "should time the execution", -> - @Metrics.Timer::done.called.should.equal true - - describe "when the request returns an error status code", -> - beforeEach -> - @request.callsArgWith(1, null, {statusCode: 500}, "") - @PersistenceManager.setDocInWeb(@project_id, @doc_id, @lines, @callback) - - it "should return an error", -> - @callback.calledWith(new Error("web api error")).should.equal true - - it "should time the execution", -> - @Metrics.Timer::done.called.should.equal true - diff --git a/services/document-updater/test/unit/coffee/PersistenceManager/setDocTests.coffee b/services/document-updater/test/unit/coffee/PersistenceManager/setDocTests.coffee index 80c0a5e18f..98f252a35d 100644 --- a/services/document-updater/test/unit/coffee/PersistenceManager/setDocTests.coffee +++ b/services/document-updater/test/unit/coffee/PersistenceManager/setDocTests.coffee @@ -3,6 +3,7 @@ chai = require('chai') should = chai.should() modulePath = "../../../../app/js/PersistenceManager.js" SandboxedModule = require('sandboxed-module') +Errors = require "../../../../app/js/Errors" describe "PersistenceManager.setDoc", -> beforeEach -> @@ -12,27 +13,78 @@ describe "PersistenceManager.setDoc", -> "./Metrics": @Metrics = Timer: class Timer done: sinon.stub() - "logger-sharelatex": @logger = {warn: sinon.stub()} - - @project_id = "mock-project-id" - @doc_id = "mock-doc-id" + "logger-sharelatex": @logger = {log: sinon.stub(), err: sinon.stub()} + @project_id = "project-id-123" + @doc_id = "doc-id-123" + @lines = ["one", "two", "three"] + @version = 42 @callback = sinon.stub() - @lines = ["mock", "doc", "lines"] + @Settings.apis = + web: + url: @url = "www.example.com" + user: @user = "sharelatex" + pass: @pass = "password" - @PersistenceManager.setDocInWeb = sinon.stub().callsArg(3) - @PersistenceManager.setDocVersionInMongo = sinon.stub().callsArg(2) + describe "with a successful response from the web api", -> + beforeEach -> + @request.callsArgWith(1, null, {statusCode: 200}, JSON.stringify(lines: @lines, version: @version)) + @PersistenceManager.setDoc(@project_id, @doc_id, @lines, @version, @callback) - @PersistenceManager.setDoc @project_id, @doc_id, @lines, @version, @callback + it "should call the web api", -> + @request + .calledWith({ + url: "#{@url}/project/#{@project_id}/doc/#{@doc_id}" + body: JSON.stringify + lines: @lines + version: @version + method: "POST" + headers: + "content-type": "application/json" + auth: + user: @user + pass: @pass + sendImmediately: true + jar: false + timeout: 5000 + }) + .should.equal true - it "should set the doc in the web api", -> - @PersistenceManager.setDocInWeb - .calledWith(@project_id, @doc_id, @lines) - .should.equal true + it "should call the callback without error", -> + @callback.calledWith(null).should.equal true - it "should set the doc version in mongo", -> - @PersistenceManager.setDocVersionInMongo - .calledWith(@doc_id, @version) - .should.equal true + it "should time the execution", -> + @Metrics.Timer::done.called.should.equal true + + describe "when request returns an error", -> + beforeEach -> + @request.callsArgWith(1, @error = new Error("oops"), null, null) + @PersistenceManager.setDoc(@project_id, @doc_id, @lines, @version, @callback) + + it "should return the error", -> + @callback.calledWith(@error).should.equal true + + it "should time the execution", -> + @Metrics.Timer::done.called.should.equal true + + describe "when the request returns 404", -> + beforeEach -> + @request.callsArgWith(1, null, {statusCode: 404}, "") + @PersistenceManager.setDoc(@project_id, @doc_id, @lines, @version, @callback) + + it "should return a NotFoundError", -> + @callback.calledWith(new Errors.NotFoundError("not found")).should.equal true + + it "should time the execution", -> + @Metrics.Timer::done.called.should.equal true + + describe "when the request returns an error status code", -> + beforeEach -> + @request.callsArgWith(1, null, {statusCode: 500}, "") + @PersistenceManager.setDoc(@project_id, @doc_id, @lines, @version, @callback) + + it "should return an error", -> + @callback.calledWith(new Error("web api error")).should.equal true + + it "should time the execution", -> + @Metrics.Timer::done.called.should.equal true - it "should call the callback", -> - @callback.called.should.equal true diff --git a/services/document-updater/test/unit/coffee/PersistenceManager/setDocVersionInMongo.coffee b/services/document-updater/test/unit/coffee/PersistenceManager/setDocVersionInMongo.coffee deleted file mode 100644 index d642aba0d8..0000000000 --- a/services/document-updater/test/unit/coffee/PersistenceManager/setDocVersionInMongo.coffee +++ /dev/null @@ -1,44 +0,0 @@ -sinon = require('sinon') -chai = require('chai') -should = chai.should() -modulePath = "../../../../app/js/PersistenceManager.js" -SandboxedModule = require('sandboxed-module') -Errors = require "../../../../app/js/Errors" -{ObjectId} = require("mongojs") - -describe "PersistenceManager.getDocVersionInMongo", -> - beforeEach -> - @PersistenceManager = SandboxedModule.require modulePath, requires: - "request": @request = sinon.stub() - "settings-sharelatex": @Settings = {} - "./Metrics": @Metrics = - Timer: class Timer - done: sinon.stub() - "./mongojs": - db: @db = { docOps: {} } - ObjectId: ObjectId - "logger-sharelatex": @logger = {log: sinon.stub(), err: sinon.stub()} - - @doc_id = ObjectId().toString() - @callback = sinon.stub() - - describe "setDocVersionInMongo", -> - beforeEach -> - @version = 42 - @db.docOps.update = sinon.stub().callsArg(3) - @PersistenceManager.setDocVersionInMongo @doc_id, @version, @callback - - it "should update the doc version", -> - @db.docOps.update - .calledWith({ - doc_id: ObjectId(@doc_id) - }, { - $set: - version: @version - }, { - upsert: true - }) - .should.equal true - - it "should call the callback", -> - @callback.called.should.equal true