diff --git a/services/document-updater/app/coffee/HttpController.coffee b/services/document-updater/app/coffee/HttpController.coffee index 9918339d6e..ce4d8bf637 100644 --- a/services/document-updater/app/coffee/HttpController.coffee +++ b/services/document-updater/app/coffee/HttpController.coffee @@ -161,10 +161,10 @@ module.exports = HttpController = updateProject: (req, res, next = (error) ->) -> timer = new Metrics.Timer("http.updateProject") project_id = req.params.project_id - {userId, docUpdates, fileUpdates} = req.body - logger.log {project_id, docUpdates, fileUpdates}, "updating project via http" + {userId, docUpdates, fileUpdates, version} = req.body + logger.log {project_id, docUpdates, fileUpdates, version}, "updating project via http" - ProjectManager.updateProjectWithLocks project_id, userId, docUpdates, fileUpdates, (error) -> + ProjectManager.updateProjectWithLocks project_id, userId, docUpdates, fileUpdates, version, (error) -> timer.done() return next(error) if error? logger.log project_id: project_id, "updated project via http" diff --git a/services/document-updater/app/coffee/ProjectHistoryRedisManager.coffee b/services/document-updater/app/coffee/ProjectHistoryRedisManager.coffee index 6de1d8efc9..c92b7277f4 100644 --- a/services/document-updater/app/coffee/ProjectHistoryRedisManager.coffee +++ b/services/document-updater/app/coffee/ProjectHistoryRedisManager.coffee @@ -7,47 +7,49 @@ module.exports = ProjectHistoryRedisManager = queueOps: (project_id, ops..., callback) -> rclient.rpush projectHistoryKeys.projectHistoryOps({project_id}), ops..., callback - queueRenameEntity: (project_id, entity_type, entity_id, user_id, update, callback) -> - update = - pathname: update.pathname - new_pathname: update.newPathname + queueRenameEntity: (project_id, entity_type, entity_id, user_id, projectUpdate, callback) -> + projectUpdate = + pathname: projectUpdate.pathname + new_pathname: projectUpdate.newPathname meta: user_id: user_id ts: new Date() - update[entity_type] = entity_id + version: projectUpdate.version + projectUpdate[entity_type] = entity_id - logger.log {project_id, update}, "queue rename operation to project-history" - jsonUpdate = JSON.stringify(update) + logger.log {project_id, projectUpdate}, "queue rename operation to project-history" + jsonUpdate = JSON.stringify(projectUpdate) ProjectHistoryRedisManager.queueOps project_id, jsonUpdate, callback - queueAddEntity: (project_id, entity_type, entitiy_id, user_id, update, callback = (error) ->) -> - update = - pathname: update.pathname - docLines: update.docLines - url: update.url + queueAddEntity: (project_id, entity_type, entitiy_id, user_id, projectUpdate, callback = (error) ->) -> + projectUpdate = + pathname: projectUpdate.pathname + docLines: projectUpdate.docLines + url: projectUpdate.url meta: user_id: user_id ts: new Date() - update[entity_type] = entitiy_id + version: projectUpdate.version + projectUpdate[entity_type] = entitiy_id - logger.log {project_id, update}, "queue add operation to project-history" - jsonUpdate = JSON.stringify(update) + logger.log {project_id, projectUpdate}, "queue add operation to project-history" + jsonUpdate = JSON.stringify(projectUpdate) ProjectHistoryRedisManager.queueOps project_id, jsonUpdate, callback queueResyncProjectStructure: (project_id, docs, files, callback) -> logger.log {project_id, docs, files}, "queue project structure resync" - update = + projectUpdate = resyncProjectStructure: { docs, files } meta: ts: new Date() - jsonUpdate = JSON.stringify update + jsonUpdate = JSON.stringify projectUpdate ProjectHistoryRedisManager.queueOps project_id, jsonUpdate, callback queueResyncDocContent: (project_id, doc_id, lines, version, pathname, callback) -> logger.log {project_id, doc_id, lines, version, pathname}, "queue doc content resync" - update = + projectUpdate = resyncDocContent: content: lines.join("\n"), version: version @@ -55,5 +57,5 @@ module.exports = ProjectHistoryRedisManager = doc: doc_id meta: ts: new Date() - jsonUpdate = JSON.stringify update + jsonUpdate = JSON.stringify projectUpdate ProjectHistoryRedisManager.queueOps project_id, jsonUpdate, callback diff --git a/services/document-updater/app/coffee/ProjectManager.coffee b/services/document-updater/app/coffee/ProjectManager.coffee index 36ae86363d..eb7acaede1 100644 --- a/services/document-updater/app/coffee/ProjectManager.coffee +++ b/services/document-updater/app/coffee/ProjectManager.coffee @@ -105,39 +105,44 @@ module.exports = ProjectManager = clearProjectState: (project_id, callback = (error) ->) -> RedisManager.clearProjectState project_id, callback - updateProjectWithLocks: (project_id, user_id, docUpdates, fileUpdates, _callback = (error) ->) -> + updateProjectWithLocks: (project_id, user_id, docUpdates, fileUpdates, version, _callback = (error) ->) -> timer = new Metrics.Timer("projectManager.updateProject") callback = (args...) -> timer.done() _callback(args...) + project_version = version + project_subversion = 0 # project versions can have multiple operations + project_ops_length = 0 - handleDocUpdate = (update, cb) -> - doc_id = update.id - if update.docLines? - ProjectHistoryRedisManager.queueAddEntity project_id, 'doc', doc_id, user_id, update, (error, count) -> + handleDocUpdate = (projectUpdate, cb) -> + doc_id = projectUpdate.id + projectUpdate.version = "#{project_version}.#{project_subversion++}" + if projectUpdate.docLines? + ProjectHistoryRedisManager.queueAddEntity project_id, 'doc', doc_id, user_id, projectUpdate, (error, count) -> project_ops_length = count cb(error) else - DocumentManager.renameDocWithLock project_id, doc_id, user_id, update, (error, count) -> + DocumentManager.renameDocWithLock project_id, doc_id, user_id, projectUpdate, (error, count) -> project_ops_length = count cb(error) - handleFileUpdate = (update, cb) -> - file_id = update.id - if update.url? - ProjectHistoryRedisManager.queueAddEntity project_id, 'file', file_id, user_id, update, (error, count) -> + handleFileUpdate = (projectUpdate, cb) -> + file_id = projectUpdate.id + projectUpdate.version = "#{project_version}.#{project_subversion++}" + if projectUpdate.url? + ProjectHistoryRedisManager.queueAddEntity project_id, 'file', file_id, user_id, projectUpdate, (error, count) -> project_ops_length = count cb(error) else - ProjectHistoryRedisManager.queueRenameEntity project_id, 'file', file_id, user_id, update, (error, count) -> + ProjectHistoryRedisManager.queueRenameEntity project_id, 'file', file_id, user_id, projectUpdate, (error, count) -> project_ops_length = count cb(error) - async.each docUpdates, handleDocUpdate, (error) -> + async.eachSeries docUpdates, handleDocUpdate, (error) -> return callback(error) if error? - async.each fileUpdates, handleFileUpdate, (error) -> + async.eachSeries fileUpdates, handleFileUpdate, (error) -> return callback(error) if error? if HistoryManager.shouldFlushHistoryOps(project_ops_length, docUpdates.length + fileUpdates.length, HistoryManager.FLUSH_PROJECT_EVERY_N_OPS) HistoryManager.flushProjectChangesAsync project_id diff --git a/services/document-updater/test/acceptance/coffee/ApplyingUpdatesToProjectStructureTests.coffee b/services/document-updater/test/acceptance/coffee/ApplyingUpdatesToProjectStructureTests.coffee index d060cd918c..5fdf2a9b4d 100644 --- a/services/document-updater/test/acceptance/coffee/ApplyingUpdatesToProjectStructureTests.coffee +++ b/services/document-updater/test/acceptance/coffee/ApplyingUpdatesToProjectStructureTests.coffee @@ -13,6 +13,7 @@ DocUpdaterApp = require "./helpers/DocUpdaterApp" describe "Applying updates to a project's structure", -> before -> @user_id = 'user-id-123' + @version = 1234 describe "renaming a file", -> before (done) -> @@ -24,7 +25,7 @@ describe "Applying updates to a project's structure", -> @fileUpdates = [ @fileUpdate ] DocUpdaterApp.ensureRunning (error) => throw error if error? - DocUpdaterClient.sendProjectUpdate @project_id, @user_id, [], @fileUpdates, (error) -> + DocUpdaterClient.sendProjectUpdate @project_id, @user_id, [], @fileUpdates, @version, (error) -> throw error if error? setTimeout done, 200 @@ -38,6 +39,7 @@ describe "Applying updates to a project's structure", -> 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" done() @@ -52,7 +54,7 @@ describe "Applying updates to a project's structure", -> describe "when the document is not loaded", -> before (done) -> @project_id = DocUpdaterClient.randomId() - DocUpdaterClient.sendProjectUpdate @project_id, @user_id, @docUpdates, [], (error) -> + DocUpdaterClient.sendProjectUpdate @project_id, @user_id, @docUpdates, [], @version, (error) -> throw error if error? setTimeout done, 200 @@ -66,6 +68,7 @@ describe "Applying updates to a project's structure", -> 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" done() @@ -76,7 +79,7 @@ describe "Applying updates to a project's structure", -> DocUpdaterClient.preloadDoc @project_id, @docUpdate.id, (error) => throw error if error? sinon.spy MockWebApi, "getDocument" - DocUpdaterClient.sendProjectUpdate @project_id, @user_id, @docUpdates, [], (error) -> + DocUpdaterClient.sendProjectUpdate @project_id, @user_id, @docUpdates, [], @version, (error) -> throw error if error? setTimeout done, 200 @@ -98,9 +101,77 @@ describe "Applying updates to a project's structure", -> 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" done() + describe "renaming multiple documents and files", -> + before -> + @docUpdate0 = + id: DocUpdaterClient.randomId() + pathname: '/doc-path0' + newPathname: '/new-doc-path0' + @docUpdate1 = + id: DocUpdaterClient.randomId() + pathname: '/doc-path1' + newPathname: '/new-doc-path1' + @docUpdates = [ @docUpdate0, @docUpdate1 ] + @fileUpdate0 = + id: DocUpdaterClient.randomId() + pathname: '/file-path0' + newPathname: '/new-file-path0' + @fileUpdate1 = + id: DocUpdaterClient.randomId() + pathname: '/file-path1' + newPathname: '/new-file-path1' + @fileUpdates = [ @fileUpdate0, @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 + + it "should push the applied doc renames 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 @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" + + 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[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[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" + + done() + + describe "adding a file", -> before (done) -> @project_id = DocUpdaterClient.randomId() @@ -109,7 +180,7 @@ describe "Applying updates to a project's structure", -> pathname: '/file-path' url: 'filestore.example.com' @fileUpdates = [ @fileUpdate ] - DocUpdaterClient.sendProjectUpdate @project_id, @user_id, [], @fileUpdates, (error) -> + DocUpdaterClient.sendProjectUpdate @project_id, @user_id, [], @fileUpdates, @version, (error) -> throw error if error? setTimeout done, 200 @@ -123,6 +194,7 @@ describe "Applying updates to a project's structure", -> 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" done() @@ -134,7 +206,7 @@ describe "Applying updates to a project's structure", -> pathname: '/file-path' docLines: 'a\nb' @docUpdates = [ @docUpdate ] - DocUpdaterClient.sendProjectUpdate @project_id, @user_id, @docUpdates, [], (error) -> + DocUpdaterClient.sendProjectUpdate @project_id, @user_id, @docUpdates, [], @version, (error) -> throw error if error? setTimeout done, 200 @@ -148,6 +220,7 @@ describe "Applying updates to a project's structure", -> 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" done() @@ -155,7 +228,8 @@ describe "Applying updates to a project's structure", -> 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 @@ -168,9 +242,9 @@ describe "Applying updates to a project's structure", -> # Send updates in chunks to causes multiple flushes projectId = @project_id userId = @project_id - DocUpdaterClient.sendProjectUpdate projectId, userId, updates.slice(0, 250), [], (error) -> + DocUpdaterClient.sendProjectUpdate projectId, userId, updates.slice(0, 250), [], @version0, (error) -> throw error if error? - DocUpdaterClient.sendProjectUpdate projectId, userId, updates.slice(250), [], (error) -> + DocUpdaterClient.sendProjectUpdate projectId, userId, updates.slice(250), [], @version1, (error) -> throw error if error? setTimeout done, 2000 @@ -184,6 +258,8 @@ describe "Applying updates to a project's structure", -> before (done) -> @project_id = DocUpdaterClient.randomId() @user_id = DocUpdaterClient.randomId() + @version0 = 12345 + @version1 = @version0 + 1 updates = [] for v in [0..42] # Should flush after 500 ops @@ -197,9 +273,9 @@ describe "Applying updates to a project's structure", -> # Send updates in chunks projectId = @project_id userId = @project_id - DocUpdaterClient.sendProjectUpdate projectId, userId, updates.slice(0, 10), [], (error) -> + DocUpdaterClient.sendProjectUpdate projectId, userId, updates.slice(0, 10), [], @version0, (error) -> throw error if error? - DocUpdaterClient.sendProjectUpdate projectId, userId, updates.slice(10), [], (error) -> + DocUpdaterClient.sendProjectUpdate projectId, userId, updates.slice(10), [], @version1, (error) -> throw error if error? setTimeout done, 2000 diff --git a/services/document-updater/test/acceptance/coffee/helpers/DocUpdaterClient.coffee b/services/document-updater/test/acceptance/coffee/helpers/DocUpdaterClient.coffee index f70271021b..7f50d64372 100644 --- a/services/document-updater/test/acceptance/coffee/helpers/DocUpdaterClient.coffee +++ b/services/document-updater/test/acceptance/coffee/helpers/DocUpdaterClient.coffee @@ -87,9 +87,9 @@ module.exports = DocUpdaterClient = body = JSON.parse(body) callback error, res, body - sendProjectUpdate: (project_id, userId, docUpdates, fileUpdates, callback = (error) ->) -> + sendProjectUpdate: (project_id, userId, docUpdates, fileUpdates, version, callback = (error) ->) -> request.post { url: "http://localhost:3003/project/#{project_id}" - json: { userId, docUpdates, fileUpdates } + json: { userId, docUpdates, fileUpdates, version } }, (error, res, body) -> callback error, res, body diff --git a/services/document-updater/test/unit/coffee/HttpController/HttpControllerTests.coffee b/services/document-updater/test/unit/coffee/HttpController/HttpControllerTests.coffee index b79659cada..fca1614c2d 100644 --- a/services/document-updater/test/unit/coffee/HttpController/HttpControllerTests.coffee +++ b/services/document-updater/test/unit/coffee/HttpController/HttpControllerTests.coffee @@ -512,19 +512,20 @@ describe "HttpController", -> @userId = "user-id-123" @docUpdates = sinon.stub() @fileUpdates = sinon.stub() + @version = 1234567 @req = - body: {@userId, @docUpdates, @fileUpdates} + body: {@userId, @docUpdates, @fileUpdates, @version} params: project_id: @project_id describe "successfully", -> beforeEach -> - @ProjectManager.updateProjectWithLocks = sinon.stub().callsArgWith(4) + @ProjectManager.updateProjectWithLocks = sinon.stub().callsArgWith(5) @HttpController.updateProject(@req, @res, @next) it "should accept the change", -> @ProjectManager.updateProjectWithLocks - .calledWith(@project_id, @userId, @docUpdates, @fileUpdates) + .calledWith(@project_id, @userId, @docUpdates, @fileUpdates, @version) .should.equal true it "should return a successful No Content response", -> @@ -537,7 +538,7 @@ describe "HttpController", -> describe "when an errors occurs", -> beforeEach -> - @ProjectManager.updateProjectWithLocks = sinon.stub().callsArgWith(4, new Error("oops")) + @ProjectManager.updateProjectWithLocks = sinon.stub().callsArgWith(5, new Error("oops")) @HttpController.updateProject(@req, @res, @next) it "should call next with the error", -> diff --git a/services/document-updater/test/unit/coffee/ProjectManager/updateProjectTests.coffee b/services/document-updater/test/unit/coffee/ProjectManager/updateProjectTests.coffee index 7bd5c19848..96d2ccc07b 100644 --- a/services/document-updater/test/unit/coffee/ProjectManager/updateProjectTests.coffee +++ b/services/document-updater/test/unit/coffee/ProjectManager/updateProjectTests.coffee @@ -3,6 +3,7 @@ chai = require('chai') should = chai.should() modulePath = "../../../../app/js/ProjectManager.js" SandboxedModule = require('sandboxed-module') +_ = require('underscore') describe "ProjectManager", -> beforeEach -> @@ -18,6 +19,7 @@ describe "ProjectManager", -> @project_id = "project-id-123" @user_id = "user-id-123" + @version = 1234567 @HistoryManager.shouldFlushHistoryOps = sinon.stub().returns(false) @HistoryManager.flushProjectChangesAsync = sinon.stub() @callback = sinon.stub() @@ -45,19 +47,22 @@ describe "ProjectManager", -> describe "successfully", -> beforeEach -> - @ProjectManager.updateProjectWithLocks @project_id, @user_id, @docUpdates, @fileUpdates, @callback + @ProjectManager.updateProjectWithLocks @project_id, @user_id, @docUpdates, @fileUpdates, @version, @callback it "should rename the docs in the updates", -> + firstDocUpdateWithVersion = _.extend({}, @firstDocUpdate, {version: "#{@version}.0"}) + secondDocUpdateWithVersion = _.extend({}, @secondDocUpdate, {version: "#{@version}.1"}) @DocumentManager.renameDocWithLock - .calledWith(@project_id, @firstDocUpdate.id, @user_id, @firstDocUpdate) + .calledWith(@project_id, @firstDocUpdate.id, @user_id, firstDocUpdateWithVersion) .should.equal true @DocumentManager.renameDocWithLock - .calledWith(@project_id, @secondDocUpdate.id, @user_id, @secondDocUpdate) + .calledWith(@project_id, @secondDocUpdate.id, @user_id, secondDocUpdateWithVersion) .should.equal true it "should rename the files in the updates", -> + firstFileUpdateWithVersion = _.extend({}, @firstFileUpdate, {version: "#{@version}.2"}) @ProjectHistoryRedisManager.queueRenameEntity - .calledWith(@project_id, 'file', @firstFileUpdate.id, @user_id, @firstFileUpdate) + .calledWith(@project_id, 'file', @firstFileUpdate.id, @user_id, firstFileUpdateWithVersion) .should.equal true it "should not flush the history", -> @@ -72,7 +77,7 @@ describe "ProjectManager", -> beforeEach -> @error = new Error('error') @DocumentManager.renameDocWithLock = sinon.stub().yields(@error) - @ProjectManager.updateProjectWithLocks @project_id, @user_id, @docUpdates, @fileUpdates, @callback + @ProjectManager.updateProjectWithLocks @project_id, @user_id, @docUpdates, @fileUpdates, @version, @callback it "should call the callback with the error", -> @callback.calledWith(@error).should.equal true @@ -81,7 +86,7 @@ describe "ProjectManager", -> beforeEach -> @error = new Error('error') @ProjectHistoryRedisManager.queueRenameEntity = sinon.stub().yields(@error) - @ProjectManager.updateProjectWithLocks @project_id, @user_id, @docUpdates, @fileUpdates, @callback + @ProjectManager.updateProjectWithLocks @project_id, @user_id, @docUpdates, @fileUpdates, @version, @callback it "should call the callback with the error", -> @callback.calledWith(@error).should.equal true @@ -89,7 +94,7 @@ describe "ProjectManager", -> describe "with enough ops to flush", -> beforeEach -> @HistoryManager.shouldFlushHistoryOps = sinon.stub().returns(true) - @ProjectManager.updateProjectWithLocks @project_id, @user_id, @docUpdates, @fileUpdates, @callback + @ProjectManager.updateProjectWithLocks @project_id, @user_id, @docUpdates, @fileUpdates, @version, @callback it "should flush the history", -> @HistoryManager.flushProjectChangesAsync @@ -106,26 +111,36 @@ describe "ProjectManager", -> docLines: "a\nb" @docUpdates = [ @firstDocUpdate, @secondDocUpdate ] @firstFileUpdate = - id: 2 + id: 3 url: 'filestore.example.com/2' - @fileUpdates = [ @firstFileUpdate ] + @secondFileUpdate = + id: 4 + url: 'filestore.example.com/3' + @fileUpdates = [ @firstFileUpdate, @secondFileUpdate ] @ProjectHistoryRedisManager.queueAddEntity = sinon.stub().yields() describe "successfully", -> beforeEach -> - @ProjectManager.updateProjectWithLocks @project_id, @user_id, @docUpdates, @fileUpdates, @callback + @ProjectManager.updateProjectWithLocks @project_id, @user_id, @docUpdates, @fileUpdates, @version, @callback it "should add the docs in the updates", -> - @ProjectHistoryRedisManager.queueAddEntity - .calledWith(@project_id, 'doc', @firstDocUpdate.id, @user_id, @firstDocUpdate) + firstDocUpdateWithVersion = _.extend({}, @firstDocUpdate, {version: "#{@version}.0"}) + secondDocUpdateWithVersion = _.extend({}, @secondDocUpdate, {version: "#{@version}.1"}) + @ProjectHistoryRedisManager.queueAddEntity.getCall(0) + .calledWith(@project_id, 'doc', @firstDocUpdate.id, @user_id, firstDocUpdateWithVersion) .should.equal true - @ProjectHistoryRedisManager.queueAddEntity - .calledWith(@project_id, 'doc', @secondDocUpdate.id, @user_id, @secondDocUpdate) + @ProjectHistoryRedisManager.queueAddEntity.getCall(1) + .calledWith(@project_id, 'doc', @secondDocUpdate.id, @user_id, secondDocUpdateWithVersion) .should.equal true it "should add the files in the updates", -> - @ProjectHistoryRedisManager.queueAddEntity - .calledWith(@project_id, 'file', @firstFileUpdate.id, @user_id, @firstFileUpdate) + firstFileUpdateWithVersion = _.extend({}, @firstFileUpdate, {version: "#{@version}.2"}) + secondFileUpdateWithVersion = _.extend({}, @secondFileUpdate, {version: "#{@version}.3"}) + @ProjectHistoryRedisManager.queueAddEntity.getCall(2) + .calledWith(@project_id, 'file', @firstFileUpdate.id, @user_id, firstFileUpdateWithVersion) + .should.equal true + @ProjectHistoryRedisManager.queueAddEntity.getCall(3) + .calledWith(@project_id, 'file', @secondFileUpdate.id, @user_id, secondFileUpdateWithVersion) .should.equal true it "should not flush the history", -> @@ -140,7 +155,7 @@ describe "ProjectManager", -> beforeEach -> @error = new Error('error') @ProjectHistoryRedisManager.queueAddEntity = sinon.stub().yields(@error) - @ProjectManager.updateProjectWithLocks @project_id, @user_id, @docUpdates, @fileUpdates, @callback + @ProjectManager.updateProjectWithLocks @project_id, @user_id, @docUpdates, @fileUpdates, @version, @callback it "should call the callback with the error", -> @callback.calledWith(@error).should.equal true @@ -149,7 +164,7 @@ describe "ProjectManager", -> beforeEach -> @error = new Error('error') @ProjectHistoryRedisManager.queueAddEntity = sinon.stub().yields(@error) - @ProjectManager.updateProjectWithLocks @project_id, @user_id, @docUpdates, @fileUpdates, @callback + @ProjectManager.updateProjectWithLocks @project_id, @user_id, @docUpdates, @fileUpdates, @version, @callback it "should call the callback with the error", -> @callback.calledWith(@error).should.equal true @@ -157,7 +172,7 @@ describe "ProjectManager", -> describe "with enough ops to flush", -> beforeEach -> @HistoryManager.shouldFlushHistoryOps = sinon.stub().returns(true) - @ProjectManager.updateProjectWithLocks @project_id, @user_id, @docUpdates, @fileUpdates, @callback + @ProjectManager.updateProjectWithLocks @project_id, @user_id, @docUpdates, @fileUpdates, @version, @callback it "should flush the history", -> @HistoryManager.flushProjectChangesAsync