mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-14 20:40:17 -05:00
Tell track changes api to flush doc when flushing doc to mongo
This commit is contained in:
parent
dfd3ec993b
commit
f3192da87f
12 changed files with 141 additions and 14 deletions
|
@ -45,16 +45,16 @@ module.exports = (grunt) ->
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
app: ["app/js"]
|
app: ["app/js"]
|
||||||
acceptance_tests: ["test/unit/js"]
|
acceptance_tests: ["test/acceptance/js"]
|
||||||
|
|
||||||
mochaTest:
|
mochaTest:
|
||||||
unit:
|
unit:
|
||||||
src: ['test/unit/js/**/*.js']
|
src: ["test/unit/js/#{grunt.option('feature') or '**'}/*.js"]
|
||||||
options:
|
options:
|
||||||
reporter: grunt.option('reporter') or 'spec'
|
reporter: grunt.option('reporter') or 'spec'
|
||||||
grep: grunt.option("grep")
|
grep: grunt.option("grep")
|
||||||
acceptance:
|
acceptance:
|
||||||
src: ['test/acceptance/js/**/*.js']
|
src: ["test/acceptance/js/#{grunt.option('feature') or '*'}.js"]
|
||||||
options:
|
options:
|
||||||
reporter: grunt.option('reporter') or 'spec'
|
reporter: grunt.option('reporter') or 'spec'
|
||||||
grep: grunt.option("grep")
|
grep: grunt.option("grep")
|
||||||
|
|
|
@ -21,15 +21,6 @@ app.configure ->
|
||||||
app.use express.bodyParser()
|
app.use express.bodyParser()
|
||||||
app.use app.router
|
app.use app.router
|
||||||
|
|
||||||
app.configure 'development', ()->
|
|
||||||
console.log "Development Enviroment"
|
|
||||||
app.use express.errorHandler({ dumpExceptions: true, showStack: true })
|
|
||||||
|
|
||||||
app.configure 'production', ()->
|
|
||||||
console.log "Production Enviroment"
|
|
||||||
app.use express.logger()
|
|
||||||
app.use express.errorHandler()
|
|
||||||
|
|
||||||
rclient.subscribe("pending-updates")
|
rclient.subscribe("pending-updates")
|
||||||
rclient.on "message", (channel, doc_key)->
|
rclient.on "message", (channel, doc_key)->
|
||||||
[project_id, doc_id] = Keys.splitProjectIdAndDocId(doc_key)
|
[project_id, doc_id] = Keys.splitProjectIdAndDocId(doc_key)
|
||||||
|
|
|
@ -2,6 +2,7 @@ RedisManager = require "./RedisManager"
|
||||||
PersistenceManager = require "./PersistenceManager"
|
PersistenceManager = require "./PersistenceManager"
|
||||||
DocOpsManager = require "./DocOpsManager"
|
DocOpsManager = require "./DocOpsManager"
|
||||||
DiffCodec = require "./DiffCodec"
|
DiffCodec = require "./DiffCodec"
|
||||||
|
TrackChangesManager = require "./TrackChangesManager"
|
||||||
logger = require "logger-sharelatex"
|
logger = require "logger-sharelatex"
|
||||||
Metrics = require "./Metrics"
|
Metrics = require "./Metrics"
|
||||||
|
|
||||||
|
@ -81,6 +82,10 @@ module.exports = DocumentManager =
|
||||||
timer.done()
|
timer.done()
|
||||||
_callback(args...)
|
_callback(args...)
|
||||||
|
|
||||||
|
TrackChangesManager.flushDocChanges doc_id, (error) ->
|
||||||
|
if error?
|
||||||
|
logger.error err: error, project_id: project_id, doc_id: doc_id, "error flushing doc to track changes api"
|
||||||
|
|
||||||
RedisManager.getDoc doc_id, (error, lines, version) ->
|
RedisManager.getDoc doc_id, (error, lines, version) ->
|
||||||
return callback(error) if error?
|
return callback(error) if error?
|
||||||
if !lines? or !version?
|
if !lines? or !version?
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
settings = require "settings-sharelatex"
|
||||||
|
request = require "request"
|
||||||
|
logger = require "logger-sharelatex"
|
||||||
|
|
||||||
|
module.exports =
|
||||||
|
flushDocChanges: (doc_id, callback = (error) ->) ->
|
||||||
|
if !settings.apis?.trackchanges?
|
||||||
|
logger.warn doc_id: doc_id, "track changes API is not configured, so not flushing"
|
||||||
|
return callback()
|
||||||
|
|
||||||
|
url = "#{settings.apis.trackchanges.url}/doc/#{doc_id}/flush"
|
||||||
|
logger.log doc_id: doc_id, url: url, "flushing doc in track changes api"
|
||||||
|
request.post url, (error, res, body)->
|
||||||
|
if error?
|
||||||
|
return callback(error)
|
||||||
|
else if res.statusCode >= 200 and res.statusCode < 300
|
||||||
|
return callback(null)
|
||||||
|
else
|
||||||
|
error = new Error("track changes api returned a failure status code: #{res.statusCode}")
|
||||||
|
return callback(error)
|
|
@ -12,6 +12,8 @@ module.exports =
|
||||||
url: "http://localhost:3000"
|
url: "http://localhost:3000"
|
||||||
user: "sharelatex"
|
user: "sharelatex"
|
||||||
pass: "password"
|
pass: "password"
|
||||||
|
trackchanges:
|
||||||
|
url: "http://localhost:3014"
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
web:
|
web:
|
||||||
|
|
|
@ -5,6 +5,7 @@ async = require "async"
|
||||||
mongojs = require "../../../app/js/mongojs"
|
mongojs = require "../../../app/js/mongojs"
|
||||||
db = mongojs.db
|
db = mongojs.db
|
||||||
ObjectId = mongojs.ObjectId
|
ObjectId = mongojs.ObjectId
|
||||||
|
rclient = require("redis").createClient()
|
||||||
|
|
||||||
MockWebApi = require "./helpers/MockWebApi"
|
MockWebApi = require "./helpers/MockWebApi"
|
||||||
DocUpdaterClient = require "./helpers/DocUpdaterClient"
|
DocUpdaterClient = require "./helpers/DocUpdaterClient"
|
||||||
|
@ -45,6 +46,11 @@ describe "Applying updates to a doc", ->
|
||||||
doc.lines.should.deep.equal @result
|
doc.lines.should.deep.equal @result
|
||||||
done()
|
done()
|
||||||
|
|
||||||
|
it "should push the applied updates to the track changes api", (done) ->
|
||||||
|
rclient.lrange "UncompressedHistoryOps:#{@doc_id}", 0, -1, (error, updates) =>
|
||||||
|
JSON.parse(updates[0]).op.should.deep.equal @update.op
|
||||||
|
done()
|
||||||
|
|
||||||
describe "when the document is loaded", ->
|
describe "when the document is loaded", ->
|
||||||
before (done) ->
|
before (done) ->
|
||||||
[@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]
|
[@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]
|
||||||
|
@ -69,6 +75,11 @@ describe "Applying updates to a doc", ->
|
||||||
doc.lines.should.deep.equal @result
|
doc.lines.should.deep.equal @result
|
||||||
done()
|
done()
|
||||||
|
|
||||||
|
it "should push the applied updates to the track changes api", (done) ->
|
||||||
|
rclient.lrange "UncompressedHistoryOps:#{@doc_id}", 0, -1, (error, updates) =>
|
||||||
|
JSON.parse(updates[0]).op.should.deep.equal @update.op
|
||||||
|
done()
|
||||||
|
|
||||||
describe "when the document has been deleted", ->
|
describe "when the document has been deleted", ->
|
||||||
describe "when the ops come in a single linear order", ->
|
describe "when the ops come in a single linear order", ->
|
||||||
before ->
|
before ->
|
||||||
|
@ -112,6 +123,13 @@ describe "Applying updates to a doc", ->
|
||||||
doc.lines.should.deep.equal @result
|
doc.lines.should.deep.equal @result
|
||||||
done()
|
done()
|
||||||
|
|
||||||
|
it "should push the applied updates to the track changes api", (done) ->
|
||||||
|
rclient.lrange "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
|
||||||
|
done()
|
||||||
|
|
||||||
describe "when older ops come in after the delete", ->
|
describe "when older ops come in after the delete", ->
|
||||||
before ->
|
before ->
|
||||||
[@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]
|
[@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]
|
||||||
|
|
|
@ -4,6 +4,7 @@ chai.should()
|
||||||
async = require "async"
|
async = require "async"
|
||||||
|
|
||||||
MockWebApi = require "./helpers/MockWebApi"
|
MockWebApi = require "./helpers/MockWebApi"
|
||||||
|
MockTrackChangesApi = require "./helpers/MockTrackChangesApi"
|
||||||
DocUpdaterClient = require "./helpers/DocUpdaterClient"
|
DocUpdaterClient = require "./helpers/DocUpdaterClient"
|
||||||
|
|
||||||
describe "Flushing a project", ->
|
describe "Flushing a project", ->
|
||||||
|
@ -40,6 +41,8 @@ describe "Flushing a project", ->
|
||||||
describe "with documents which have been updated", ->
|
describe "with documents which have been updated", ->
|
||||||
before (done) ->
|
before (done) ->
|
||||||
sinon.spy MockWebApi, "setDocumentLines"
|
sinon.spy MockWebApi, "setDocumentLines"
|
||||||
|
sinon.spy MockTrackChangesApi, "flushDoc"
|
||||||
|
|
||||||
async.series @docs.map((doc) =>
|
async.series @docs.map((doc) =>
|
||||||
(callback) =>
|
(callback) =>
|
||||||
DocUpdaterClient.preloadDoc @project_id, doc.id, (error) =>
|
DocUpdaterClient.preloadDoc @project_id, doc.id, (error) =>
|
||||||
|
@ -56,6 +59,7 @@ describe "Flushing a project", ->
|
||||||
|
|
||||||
after ->
|
after ->
|
||||||
MockWebApi.setDocumentLines.restore()
|
MockWebApi.setDocumentLines.restore()
|
||||||
|
MockTrackChangesApi.flushDoc.restore()
|
||||||
|
|
||||||
it "should return a 204 status code", ->
|
it "should return a 204 status code", ->
|
||||||
@statusCode.should.equal 204
|
@statusCode.should.equal 204
|
||||||
|
@ -74,3 +78,13 @@ describe "Flushing a project", ->
|
||||||
callback()
|
callback()
|
||||||
), done
|
), done
|
||||||
|
|
||||||
|
it "should flush the docs in the track changes api", (done) ->
|
||||||
|
# This is done in the background, so wait a little while to ensure it has happened
|
||||||
|
setTimeout () =>
|
||||||
|
async.series @docs.map((doc) =>
|
||||||
|
(callback) =>
|
||||||
|
MockTrackChangesApi.flushDoc.calledWith(doc.id).should.equal true
|
||||||
|
), done
|
||||||
|
done()
|
||||||
|
, 100
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ chai.should()
|
||||||
async = require "async"
|
async = require "async"
|
||||||
|
|
||||||
MockWebApi = require "./helpers/MockWebApi"
|
MockWebApi = require "./helpers/MockWebApi"
|
||||||
|
MockTrackChangesApi = require "./helpers/MockTrackChangesApi"
|
||||||
DocUpdaterClient = require "./helpers/DocUpdaterClient"
|
DocUpdaterClient = require "./helpers/DocUpdaterClient"
|
||||||
mongojs = require "../../../app/js/mongojs"
|
mongojs = require "../../../app/js/mongojs"
|
||||||
db = mongojs.db
|
db = mongojs.db
|
||||||
|
@ -31,6 +32,7 @@ describe "Flushing a doc to Mongo", ->
|
||||||
lines: @lines
|
lines: @lines
|
||||||
}
|
}
|
||||||
sinon.spy MockWebApi, "setDocumentLines"
|
sinon.spy MockWebApi, "setDocumentLines"
|
||||||
|
sinon.spy MockTrackChangesApi, "flushDoc"
|
||||||
|
|
||||||
DocUpdaterClient.sendUpdates @project_id, @doc_id, [@update], (error) =>
|
DocUpdaterClient.sendUpdates @project_id, @doc_id, [@update], (error) =>
|
||||||
throw error if error?
|
throw error if error?
|
||||||
|
@ -40,6 +42,7 @@ describe "Flushing a doc to Mongo", ->
|
||||||
|
|
||||||
after ->
|
after ->
|
||||||
MockWebApi.setDocumentLines.restore()
|
MockWebApi.setDocumentLines.restore()
|
||||||
|
MockTrackChangesApi.flushDoc.restore()
|
||||||
|
|
||||||
it "should flush the updated document to the web api", ->
|
it "should flush the updated document to the web api", ->
|
||||||
MockWebApi.setDocumentLines
|
MockWebApi.setDocumentLines
|
||||||
|
@ -52,6 +55,13 @@ describe "Flushing a doc to Mongo", ->
|
||||||
doc.docOps[0].op.should.deep.equal @update.op
|
doc.docOps[0].op.should.deep.equal @update.op
|
||||||
done()
|
done()
|
||||||
|
|
||||||
|
it "should flush the doc in the track changes api", (done) ->
|
||||||
|
# This is done in the background, so wait a little while to ensure it has happened
|
||||||
|
setTimeout () =>
|
||||||
|
MockTrackChangesApi.flushDoc.calledWith(@doc_id).should.equal true
|
||||||
|
done()
|
||||||
|
, 100
|
||||||
|
|
||||||
describe "when the doc has a large number of ops to be flushed", ->
|
describe "when the doc has a large number of ops to be flushed", ->
|
||||||
before (done) ->
|
before (done) ->
|
||||||
[@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]
|
[@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]
|
||||||
|
@ -93,5 +103,5 @@ describe "Flushing a doc to Mongo", ->
|
||||||
|
|
||||||
it "should not flush the doc to the web api", ->
|
it "should not flush the doc to the web api", ->
|
||||||
MockWebApi.setDocumentLines.called.should.equal false
|
MockWebApi.setDocumentLines.called.should.equal false
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
express = require("express")
|
||||||
|
app = express()
|
||||||
|
|
||||||
|
module.exports = MockTrackChangesApi =
|
||||||
|
flushDoc: (doc_id, callback = (error) ->) ->
|
||||||
|
callback()
|
||||||
|
|
||||||
|
run: () ->
|
||||||
|
app.post "/doc/:doc_id/flush", (req, res, next) =>
|
||||||
|
@flushDoc req.params.doc_id, (error) ->
|
||||||
|
if error?
|
||||||
|
res.send 500
|
||||||
|
else
|
||||||
|
res.send 204
|
||||||
|
|
||||||
|
app.listen 3014, (error) ->
|
||||||
|
throw error if error?
|
||||||
|
|
||||||
|
MockTrackChangesApi.run()
|
||||||
|
|
|
@ -34,7 +34,8 @@ module.exports = MockWebApi =
|
||||||
else
|
else
|
||||||
res.send 204
|
res.send 204
|
||||||
|
|
||||||
app.listen(3000)
|
app.listen 3000, (error) ->
|
||||||
|
throw error if error?
|
||||||
|
|
||||||
MockWebApi.run()
|
MockWebApi.run()
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ describe "DocumentUpdater - flushDocIfLoaded", ->
|
||||||
"./RedisManager": @RedisManager = {}
|
"./RedisManager": @RedisManager = {}
|
||||||
"./PersistenceManager": @PersistenceManager = {}
|
"./PersistenceManager": @PersistenceManager = {}
|
||||||
"./DocOpsManager": @DocOpsManager = {}
|
"./DocOpsManager": @DocOpsManager = {}
|
||||||
|
"./TrackChangesManager": @TrackChangesManager = {}
|
||||||
"logger-sharelatex": @logger = {log: sinon.stub()}
|
"logger-sharelatex": @logger = {log: sinon.stub()}
|
||||||
"./Metrics": @Metrics =
|
"./Metrics": @Metrics =
|
||||||
Timer: class Timer
|
Timer: class Timer
|
||||||
|
@ -25,6 +26,7 @@ describe "DocumentUpdater - flushDocIfLoaded", ->
|
||||||
@RedisManager.getDoc = sinon.stub().callsArgWith(1, null, @lines, @version)
|
@RedisManager.getDoc = sinon.stub().callsArgWith(1, null, @lines, @version)
|
||||||
@PersistenceManager.setDoc = sinon.stub().callsArgWith(3)
|
@PersistenceManager.setDoc = sinon.stub().callsArgWith(3)
|
||||||
@DocOpsManager.flushDocOpsToMongo = sinon.stub().callsArgWith(2)
|
@DocOpsManager.flushDocOpsToMongo = sinon.stub().callsArgWith(2)
|
||||||
|
@TrackChangesManager.flushDocChanges = sinon.stub().callsArg(1)
|
||||||
@DocumentManager.flushDocIfLoaded @project_id, @doc_id, @callback
|
@DocumentManager.flushDocIfLoaded @project_id, @doc_id, @callback
|
||||||
|
|
||||||
it "should get the doc from redis", ->
|
it "should get the doc from redis", ->
|
||||||
|
@ -48,11 +50,17 @@ describe "DocumentUpdater - flushDocIfLoaded", ->
|
||||||
it "should time the execution", ->
|
it "should time the execution", ->
|
||||||
@Metrics.Timer::done.called.should.equal true
|
@Metrics.Timer::done.called.should.equal true
|
||||||
|
|
||||||
|
it "should flush the doc in the track changes api", ->
|
||||||
|
@TrackChangesManager.flushDocChanges
|
||||||
|
.calledWith(@doc_id)
|
||||||
|
.should.equal true
|
||||||
|
|
||||||
describe "when the document is not in Redis", ->
|
describe "when the document is not in Redis", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@RedisManager.getDoc = sinon.stub().callsArgWith(1, null, null, null)
|
@RedisManager.getDoc = sinon.stub().callsArgWith(1, null, null, null)
|
||||||
@PersistenceManager.setDoc = sinon.stub().callsArgWith(3)
|
@PersistenceManager.setDoc = sinon.stub().callsArgWith(3)
|
||||||
@DocOpsManager.flushDocOpsToMongo = sinon.stub().callsArgWith(2)
|
@DocOpsManager.flushDocOpsToMongo = sinon.stub().callsArgWith(2)
|
||||||
|
@TrackChangesManager.flushDocChanges = sinon.stub().callsArg(1)
|
||||||
@DocumentManager.flushDocIfLoaded @project_id, @doc_id, @callback
|
@DocumentManager.flushDocIfLoaded @project_id, @doc_id, @callback
|
||||||
|
|
||||||
it "should get the doc from redis", ->
|
it "should get the doc from redis", ->
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
SandboxedModule = require('sandboxed-module')
|
||||||
|
sinon = require('sinon')
|
||||||
|
require('chai').should()
|
||||||
|
modulePath = require('path').join __dirname, '../../../../app/js/TrackChangesManager'
|
||||||
|
|
||||||
|
describe "TrackChangesManager", ->
|
||||||
|
beforeEach ->
|
||||||
|
@TrackChangesManager = SandboxedModule.require modulePath, requires:
|
||||||
|
"request": @request = {}
|
||||||
|
"settings-sharelatex": @Settings = {}
|
||||||
|
@doc_id = "mock-doc-id"
|
||||||
|
@callback = sinon.stub()
|
||||||
|
|
||||||
|
describe "flushDocChanges", ->
|
||||||
|
beforeEach ->
|
||||||
|
@Settings.apis =
|
||||||
|
trackchanges: url: "http://trackchanges.example.com"
|
||||||
|
|
||||||
|
describe "successfully", ->
|
||||||
|
beforeEach ->
|
||||||
|
@request.post = sinon.stub().callsArgWith(1, null, statusCode: 204)
|
||||||
|
@TrackChangesManager.flushDocChanges @doc_id, @callback
|
||||||
|
|
||||||
|
it "should send a request to the track changes api", ->
|
||||||
|
@request.post
|
||||||
|
.calledWith("#{@Settings.apis.trackchanges.url}/doc/#{@doc_id}/flush")
|
||||||
|
.should.equal true
|
||||||
|
|
||||||
|
it "should return the callback", ->
|
||||||
|
@callback.calledWith(null).should.equal true
|
||||||
|
|
||||||
|
describe "when the track changes api returns an error", ->
|
||||||
|
beforeEach ->
|
||||||
|
@request.post = sinon.stub().callsArgWith(1, null, statusCode: 500)
|
||||||
|
@TrackChangesManager.flushDocChanges @doc_id, @callback
|
||||||
|
|
||||||
|
it "should return the callback with an error", ->
|
||||||
|
@callback.calledWith(new Error("track changes api return non-success code: 500")).should.equal true
|
Loading…
Reference in a new issue