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