2017-11-06 12:18:28 -05:00
|
|
|
sinon = require "sinon"
|
|
|
|
chai = require("chai")
|
|
|
|
chai.should()
|
|
|
|
Settings = require('settings-sharelatex')
|
|
|
|
rclient_history = require("redis-sharelatex").createClient(Settings.redis.history)
|
|
|
|
ProjectHistoryKeys = Settings.redis.project_history.key_schema
|
2018-01-26 06:53:49 -05:00
|
|
|
SandboxedModule = require('sandboxed-module')
|
|
|
|
HistoryManagerModulePath = require('path').join __dirname, '../../../app/js/HistoryManager.js'
|
|
|
|
ProjectManagerModulePath = require('path').join __dirname, '../../../app/js/ProjectManager.js'
|
|
|
|
RedisManagerModulePath = require('path').join __dirname, '../../../app/js/RedisManager.js'
|
2017-11-06 12:18:28 -05:00
|
|
|
|
|
|
|
MockWebApi = require "./helpers/MockWebApi"
|
|
|
|
DocUpdaterClient = require "./helpers/DocUpdaterClient"
|
|
|
|
|
|
|
|
describe "Applying updates to a project's structure", ->
|
|
|
|
before ->
|
|
|
|
@user_id = 'user-id-123'
|
|
|
|
|
|
|
|
describe "renaming a file", ->
|
|
|
|
before (done) ->
|
|
|
|
@project_id = DocUpdaterClient.randomId()
|
|
|
|
@fileUpdate =
|
|
|
|
id: DocUpdaterClient.randomId()
|
|
|
|
pathname: '/file-path'
|
|
|
|
newPathname: '/new-file-path'
|
|
|
|
@fileUpdates = [ @fileUpdate ]
|
|
|
|
DocUpdaterClient.sendProjectUpdate @project_id, @user_id, [], @fileUpdates, (error) ->
|
|
|
|
throw error if error?
|
|
|
|
setTimeout done, 200
|
|
|
|
|
2017-11-10 10:01:37 -05:00
|
|
|
it "should push the applied file renames to the project history api", (done) ->
|
2017-11-06 12:18:28 -05:00
|
|
|
rclient_history.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) =>
|
|
|
|
throw error if 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')
|
|
|
|
|
|
|
|
done()
|
|
|
|
|
|
|
|
describe "renaming a document", ->
|
|
|
|
before ->
|
|
|
|
@docUpdate =
|
|
|
|
id: DocUpdaterClient.randomId()
|
|
|
|
pathname: '/doc-path'
|
|
|
|
newPathname: '/new-doc-path'
|
|
|
|
@docUpdates = [ @docUpdate ]
|
|
|
|
|
|
|
|
describe "when the document is not loaded", ->
|
|
|
|
before (done) ->
|
|
|
|
@project_id = DocUpdaterClient.randomId()
|
|
|
|
DocUpdaterClient.sendProjectUpdate @project_id, @user_id, @docUpdates, [], (error) ->
|
|
|
|
throw error if error?
|
|
|
|
setTimeout done, 200
|
|
|
|
|
2017-11-10 10:01:37 -05:00
|
|
|
it "should push the applied doc renames to the project history api", (done) ->
|
2017-11-06 12:18:28 -05:00
|
|
|
rclient_history.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) =>
|
|
|
|
throw error if 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')
|
|
|
|
|
|
|
|
done()
|
|
|
|
|
|
|
|
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, [], (error) ->
|
|
|
|
throw error if error?
|
|
|
|
setTimeout done, 200
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
2017-11-10 10:01:37 -05:00
|
|
|
it "should push the applied doc renames to the project history api", (done) ->
|
2017-11-06 12:18:28 -05:00
|
|
|
rclient_history.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) =>
|
|
|
|
throw error if 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')
|
|
|
|
|
|
|
|
done()
|
2017-11-10 10:01:37 -05:00
|
|
|
|
|
|
|
describe "adding a file", ->
|
|
|
|
before (done) ->
|
|
|
|
@project_id = DocUpdaterClient.randomId()
|
|
|
|
@fileUpdate =
|
|
|
|
id: DocUpdaterClient.randomId()
|
|
|
|
pathname: '/file-path'
|
|
|
|
url: 'filestore.example.com'
|
|
|
|
@fileUpdates = [ @fileUpdate ]
|
|
|
|
DocUpdaterClient.sendProjectUpdate @project_id, @user_id, [], @fileUpdates, (error) ->
|
|
|
|
throw error if error?
|
|
|
|
setTimeout done, 200
|
|
|
|
|
|
|
|
it "should push the file addition to the project history api", (done) ->
|
|
|
|
rclient_history.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) =>
|
|
|
|
throw error if 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')
|
|
|
|
|
|
|
|
done()
|
|
|
|
|
|
|
|
describe "adding a doc", ->
|
|
|
|
before (done) ->
|
|
|
|
@project_id = DocUpdaterClient.randomId()
|
|
|
|
@docUpdate =
|
|
|
|
id: DocUpdaterClient.randomId()
|
|
|
|
pathname: '/file-path'
|
|
|
|
docLines: 'a\nb'
|
|
|
|
@docUpdates = [ @docUpdate ]
|
|
|
|
DocUpdaterClient.sendProjectUpdate @project_id, @user_id, @docUpdates, [], (error) ->
|
|
|
|
throw error if error?
|
|
|
|
setTimeout done, 200
|
|
|
|
|
|
|
|
it "should push the doc addition to the project history api", (done) ->
|
|
|
|
rclient_history.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) =>
|
|
|
|
throw error if 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')
|
|
|
|
|
|
|
|
done()
|
|
|
|
|
2018-01-26 06:53:49 -05:00
|
|
|
describe "with enough updates to flush to the history service", ->
|
|
|
|
before (done) ->
|
|
|
|
@RedisManager = SandboxedModule.require RedisManagerModulePath, requires:
|
|
|
|
"logger-sharelatex": @logger = { log: sinon.stub(), error: sinon.stub() }
|
|
|
|
@HistoryManager = SandboxedModule.require HistoryManagerModulePath, requires:
|
|
|
|
"request": {}
|
|
|
|
"settings-sharelatex": {}
|
|
|
|
"logger-sharelatex": @logger
|
|
|
|
"./HistoryRedisManager": {}
|
|
|
|
@HistoryManager.flushProjectChangesAsync = sinon.stub()
|
|
|
|
@ProjectManager = SandboxedModule.require ProjectManagerModulePath, requires:
|
|
|
|
'./HistoryManager': @HistoryManager
|
|
|
|
'logger-sharelatex' : @logger
|
|
|
|
'./Metrics': @Metrics = {}
|
|
|
|
'./RedisManager': @RedisManager
|
|
|
|
@Metrics.Timer = class Timer
|
|
|
|
done: sinon.stub()
|
|
|
|
|
|
|
|
@project_id = DocUpdaterClient.randomId()
|
|
|
|
@user_id = DocUpdaterClient.randomId()
|
|
|
|
|
|
|
|
updates = []
|
|
|
|
for v in [0..599] # Should flush after 500 ops
|
|
|
|
updates.push
|
|
|
|
id: DocUpdaterClient.randomId(),
|
|
|
|
pathname: '/file-' + v
|
|
|
|
docLines: 'a\nb'
|
|
|
|
|
|
|
|
# Send updates in chunks to causes multiple flushes
|
|
|
|
@ProjectManager.updateProjectWithLocks @project_id, @user_id, updates.slice(0, 250), [], (error) =>
|
|
|
|
throw error if error?
|
|
|
|
@ProjectManager.updateProjectWithLocks @project_id, @user_id, updates.slice(250), [], (error) =>
|
|
|
|
throw error if error?
|
|
|
|
setTimeout done, 2000
|
|
|
|
|
|
|
|
it "should flush project history", ->
|
|
|
|
@HistoryManager.flushProjectChangesAsync.calledWith(@project_id).should.equal true
|