mirror of
https://github.com/overleaf/overleaf.git
synced 2024-12-02 02:18:47 -05:00
952 lines
28 KiB
JavaScript
952 lines
28 KiB
JavaScript
/* eslint-disable
|
|
no-return-assign,
|
|
no-unused-vars,
|
|
*/
|
|
// TODO: This file was created by bulk-decaffeinate.
|
|
// Fix any style issues and re-enable lint.
|
|
/*
|
|
* decaffeinate suggestions:
|
|
* DS102: Remove unnecessary code created because of implicit returns
|
|
* DS206: Consider reworking classes to avoid initClass
|
|
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
|
*/
|
|
const sinon = require('sinon')
|
|
const chai = require('chai')
|
|
const should = chai.should()
|
|
const modulePath = '../../../../app/js/HttpController.js'
|
|
const SandboxedModule = require('sandboxed-module')
|
|
const Errors = require('../../../../app/js/Errors.js')
|
|
|
|
describe('HttpController', function () {
|
|
beforeEach(function () {
|
|
let Timer
|
|
this.HttpController = SandboxedModule.require(modulePath, {
|
|
requires: {
|
|
'./DocumentManager': (this.DocumentManager = {}),
|
|
'./HistoryManager': (this.HistoryManager = {
|
|
flushProjectChangesAsync: sinon.stub()
|
|
}),
|
|
'./ProjectManager': (this.ProjectManager = {}),
|
|
'logger-sharelatex': (this.logger = { log: sinon.stub() }),
|
|
'./ProjectFlusher': { flushAllProjects() {} },
|
|
'./DeleteQueueManager': (this.DeleteQueueManager = {}),
|
|
'./Metrics': (this.Metrics = {}),
|
|
'./Errors': Errors
|
|
}
|
|
})
|
|
this.Metrics.Timer = Timer = (function () {
|
|
Timer = class Timer {
|
|
static initClass() {
|
|
this.prototype.done = sinon.stub()
|
|
}
|
|
}
|
|
Timer.initClass()
|
|
return Timer
|
|
})()
|
|
this.project_id = 'project-id-123'
|
|
this.doc_id = 'doc-id-123'
|
|
this.next = sinon.stub()
|
|
return (this.res = {
|
|
send: sinon.stub(),
|
|
sendStatus: sinon.stub(),
|
|
json: sinon.stub()
|
|
})
|
|
})
|
|
|
|
describe('getDoc', function () {
|
|
beforeEach(function () {
|
|
this.lines = ['one', 'two', 'three']
|
|
this.ops = ['mock-op-1', 'mock-op-2']
|
|
this.version = 42
|
|
this.fromVersion = 42
|
|
this.ranges = { changes: 'mock', comments: 'mock' }
|
|
this.pathname = '/a/b/c'
|
|
return (this.req = {
|
|
params: {
|
|
project_id: this.project_id,
|
|
doc_id: this.doc_id
|
|
}
|
|
})
|
|
})
|
|
|
|
describe('when the document exists and no recent ops are requested', function () {
|
|
beforeEach(function () {
|
|
this.DocumentManager.getDocAndRecentOpsWithLock = sinon
|
|
.stub()
|
|
.callsArgWith(
|
|
3,
|
|
null,
|
|
this.lines,
|
|
this.version,
|
|
[],
|
|
this.ranges,
|
|
this.pathname
|
|
)
|
|
return this.HttpController.getDoc(this.req, this.res, this.next)
|
|
})
|
|
|
|
it('should get the doc', function () {
|
|
return this.DocumentManager.getDocAndRecentOpsWithLock
|
|
.calledWith(this.project_id, this.doc_id, -1)
|
|
.should.equal(true)
|
|
})
|
|
|
|
it('should return the doc as JSON', function () {
|
|
return this.res.json
|
|
.calledWith({
|
|
id: this.doc_id,
|
|
lines: this.lines,
|
|
version: this.version,
|
|
ops: [],
|
|
ranges: this.ranges,
|
|
pathname: this.pathname
|
|
})
|
|
.should.equal(true)
|
|
})
|
|
|
|
it('should log the request', function () {
|
|
return this.logger.log
|
|
.calledWith(
|
|
{ doc_id: this.doc_id, project_id: this.project_id },
|
|
'getting doc via http'
|
|
)
|
|
.should.equal(true)
|
|
})
|
|
|
|
return it('should time the request', function () {
|
|
return this.Metrics.Timer.prototype.done.called.should.equal(true)
|
|
})
|
|
})
|
|
|
|
describe('when recent ops are requested', function () {
|
|
beforeEach(function () {
|
|
this.DocumentManager.getDocAndRecentOpsWithLock = sinon
|
|
.stub()
|
|
.callsArgWith(
|
|
3,
|
|
null,
|
|
this.lines,
|
|
this.version,
|
|
this.ops,
|
|
this.ranges,
|
|
this.pathname
|
|
)
|
|
this.req.query = { fromVersion: `${this.fromVersion}` }
|
|
return this.HttpController.getDoc(this.req, this.res, this.next)
|
|
})
|
|
|
|
it('should get the doc', function () {
|
|
return this.DocumentManager.getDocAndRecentOpsWithLock
|
|
.calledWith(this.project_id, this.doc_id, this.fromVersion)
|
|
.should.equal(true)
|
|
})
|
|
|
|
it('should return the doc as JSON', function () {
|
|
return this.res.json
|
|
.calledWith({
|
|
id: this.doc_id,
|
|
lines: this.lines,
|
|
version: this.version,
|
|
ops: this.ops,
|
|
ranges: this.ranges,
|
|
pathname: this.pathname
|
|
})
|
|
.should.equal(true)
|
|
})
|
|
|
|
it('should log the request', function () {
|
|
return this.logger.log
|
|
.calledWith(
|
|
{ doc_id: this.doc_id, project_id: this.project_id },
|
|
'getting doc via http'
|
|
)
|
|
.should.equal(true)
|
|
})
|
|
|
|
return it('should time the request', function () {
|
|
return this.Metrics.Timer.prototype.done.called.should.equal(true)
|
|
})
|
|
})
|
|
|
|
describe('when the document does not exist', function () {
|
|
beforeEach(function () {
|
|
this.DocumentManager.getDocAndRecentOpsWithLock = sinon
|
|
.stub()
|
|
.callsArgWith(3, null, null, null)
|
|
return this.HttpController.getDoc(this.req, this.res, this.next)
|
|
})
|
|
|
|
return it('should call next with NotFoundError', function () {
|
|
return this.next
|
|
.calledWith(new Errors.NotFoundError('not found'))
|
|
.should.equal(true)
|
|
})
|
|
})
|
|
|
|
return describe('when an errors occurs', function () {
|
|
beforeEach(function () {
|
|
this.DocumentManager.getDocAndRecentOpsWithLock = sinon
|
|
.stub()
|
|
.callsArgWith(3, new Error('oops'), null, null)
|
|
return this.HttpController.getDoc(this.req, this.res, this.next)
|
|
})
|
|
|
|
return it('should call next with the error', function () {
|
|
return this.next.calledWith(new Error('oops')).should.equal(true)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('setDoc', function () {
|
|
beforeEach(function () {
|
|
this.lines = ['one', 'two', 'three']
|
|
this.source = 'dropbox'
|
|
this.user_id = 'user-id-123'
|
|
return (this.req = {
|
|
headers: {},
|
|
params: {
|
|
project_id: this.project_id,
|
|
doc_id: this.doc_id
|
|
},
|
|
body: {
|
|
lines: this.lines,
|
|
source: this.source,
|
|
user_id: this.user_id,
|
|
undoing: (this.undoing = true)
|
|
}
|
|
})
|
|
})
|
|
|
|
describe('successfully', function () {
|
|
beforeEach(function () {
|
|
this.DocumentManager.setDocWithLock = sinon.stub().callsArgWith(6)
|
|
return this.HttpController.setDoc(this.req, this.res, this.next)
|
|
})
|
|
|
|
it('should set the doc', function () {
|
|
return this.DocumentManager.setDocWithLock
|
|
.calledWith(
|
|
this.project_id,
|
|
this.doc_id,
|
|
this.lines,
|
|
this.source,
|
|
this.user_id,
|
|
this.undoing
|
|
)
|
|
.should.equal(true)
|
|
})
|
|
|
|
it('should return a successful No Content response', function () {
|
|
return this.res.sendStatus.calledWith(204).should.equal(true)
|
|
})
|
|
|
|
it('should log the request', function () {
|
|
return this.logger.log
|
|
.calledWith(
|
|
{
|
|
doc_id: this.doc_id,
|
|
project_id: this.project_id,
|
|
lines: this.lines,
|
|
source: this.source,
|
|
user_id: this.user_id,
|
|
undoing: this.undoing
|
|
},
|
|
'setting doc via http'
|
|
)
|
|
.should.equal(true)
|
|
})
|
|
|
|
return it('should time the request', function () {
|
|
return this.Metrics.Timer.prototype.done.called.should.equal(true)
|
|
})
|
|
})
|
|
|
|
describe('when an errors occurs', function () {
|
|
beforeEach(function () {
|
|
this.DocumentManager.setDocWithLock = sinon
|
|
.stub()
|
|
.callsArgWith(6, new Error('oops'))
|
|
return this.HttpController.setDoc(this.req, this.res, this.next)
|
|
})
|
|
|
|
return it('should call next with the error', function () {
|
|
return this.next.calledWith(new Error('oops')).should.equal(true)
|
|
})
|
|
})
|
|
|
|
return describe('when the payload is too large', function () {
|
|
beforeEach(function () {
|
|
const lines = []
|
|
for (let _ = 0; _ <= 200000; _++) {
|
|
lines.push('test test test')
|
|
}
|
|
this.req.body.lines = lines
|
|
this.DocumentManager.setDocWithLock = sinon.stub().callsArgWith(6)
|
|
return this.HttpController.setDoc(this.req, this.res, this.next)
|
|
})
|
|
|
|
it('should send back a 406 response', function () {
|
|
return this.res.sendStatus.calledWith(406).should.equal(true)
|
|
})
|
|
|
|
return it('should not call setDocWithLock', function () {
|
|
return this.DocumentManager.setDocWithLock.callCount.should.equal(0)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('flushProject', function () {
|
|
beforeEach(function () {
|
|
return (this.req = {
|
|
params: {
|
|
project_id: this.project_id
|
|
}
|
|
})
|
|
})
|
|
|
|
describe('successfully', function () {
|
|
beforeEach(function () {
|
|
this.ProjectManager.flushProjectWithLocks = sinon.stub().callsArgWith(1)
|
|
return this.HttpController.flushProject(this.req, this.res, this.next)
|
|
})
|
|
|
|
it('should flush the project', function () {
|
|
return this.ProjectManager.flushProjectWithLocks
|
|
.calledWith(this.project_id)
|
|
.should.equal(true)
|
|
})
|
|
|
|
it('should return a successful No Content response', function () {
|
|
return this.res.sendStatus.calledWith(204).should.equal(true)
|
|
})
|
|
|
|
it('should log the request', function () {
|
|
return this.logger.log
|
|
.calledWith(
|
|
{ project_id: this.project_id },
|
|
'flushing project via http'
|
|
)
|
|
.should.equal(true)
|
|
})
|
|
|
|
return it('should time the request', function () {
|
|
return this.Metrics.Timer.prototype.done.called.should.equal(true)
|
|
})
|
|
})
|
|
|
|
return describe('when an errors occurs', function () {
|
|
beforeEach(function () {
|
|
this.ProjectManager.flushProjectWithLocks = sinon
|
|
.stub()
|
|
.callsArgWith(1, new Error('oops'))
|
|
return this.HttpController.flushProject(this.req, this.res, this.next)
|
|
})
|
|
|
|
return it('should call next with the error', function () {
|
|
return this.next.calledWith(new Error('oops')).should.equal(true)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('flushDocIfLoaded', function () {
|
|
beforeEach(function () {
|
|
this.lines = ['one', 'two', 'three']
|
|
this.version = 42
|
|
return (this.req = {
|
|
params: {
|
|
project_id: this.project_id,
|
|
doc_id: this.doc_id
|
|
}
|
|
})
|
|
})
|
|
|
|
describe('successfully', function () {
|
|
beforeEach(function () {
|
|
this.DocumentManager.flushDocIfLoadedWithLock = sinon
|
|
.stub()
|
|
.callsArgWith(2)
|
|
return this.HttpController.flushDocIfLoaded(
|
|
this.req,
|
|
this.res,
|
|
this.next
|
|
)
|
|
})
|
|
|
|
it('should flush the doc', function () {
|
|
return this.DocumentManager.flushDocIfLoadedWithLock
|
|
.calledWith(this.project_id, this.doc_id)
|
|
.should.equal(true)
|
|
})
|
|
|
|
it('should return a successful No Content response', function () {
|
|
return this.res.sendStatus.calledWith(204).should.equal(true)
|
|
})
|
|
|
|
it('should log the request', function () {
|
|
return this.logger.log
|
|
.calledWith(
|
|
{ doc_id: this.doc_id, project_id: this.project_id },
|
|
'flushing doc via http'
|
|
)
|
|
.should.equal(true)
|
|
})
|
|
|
|
return it('should time the request', function () {
|
|
return this.Metrics.Timer.prototype.done.called.should.equal(true)
|
|
})
|
|
})
|
|
|
|
return describe('when an errors occurs', function () {
|
|
beforeEach(function () {
|
|
this.DocumentManager.flushDocIfLoadedWithLock = sinon
|
|
.stub()
|
|
.callsArgWith(2, new Error('oops'))
|
|
return this.HttpController.flushDocIfLoaded(
|
|
this.req,
|
|
this.res,
|
|
this.next
|
|
)
|
|
})
|
|
|
|
return it('should call next with the error', function () {
|
|
return this.next.calledWith(new Error('oops')).should.equal(true)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('deleteDoc', function () {
|
|
beforeEach(function () {
|
|
return (this.req = {
|
|
params: {
|
|
project_id: this.project_id,
|
|
doc_id: this.doc_id
|
|
},
|
|
query: {}
|
|
})
|
|
})
|
|
|
|
describe('successfully', function () {
|
|
beforeEach(function () {
|
|
this.DocumentManager.flushAndDeleteDocWithLock = sinon
|
|
.stub()
|
|
.callsArgWith(3)
|
|
return this.HttpController.deleteDoc(this.req, this.res, this.next)
|
|
})
|
|
|
|
it('should flush and delete the doc', function () {
|
|
return this.DocumentManager.flushAndDeleteDocWithLock
|
|
.calledWith(this.project_id, this.doc_id, {
|
|
ignoreFlushErrors: false
|
|
})
|
|
.should.equal(true)
|
|
})
|
|
|
|
it('should flush project history', function () {
|
|
return this.HistoryManager.flushProjectChangesAsync
|
|
.calledWithExactly(this.project_id)
|
|
.should.equal(true)
|
|
})
|
|
|
|
it('should return a successful No Content response', function () {
|
|
return this.res.sendStatus.calledWith(204).should.equal(true)
|
|
})
|
|
|
|
it('should log the request', function () {
|
|
return this.logger.log
|
|
.calledWith(
|
|
{ doc_id: this.doc_id, project_id: this.project_id },
|
|
'deleting doc via http'
|
|
)
|
|
.should.equal(true)
|
|
})
|
|
|
|
return it('should time the request', function () {
|
|
return this.Metrics.Timer.prototype.done.called.should.equal(true)
|
|
})
|
|
})
|
|
|
|
describe('ignoring errors', function () {
|
|
beforeEach(function () {
|
|
this.req.query.ignore_flush_errors = 'true'
|
|
this.DocumentManager.flushAndDeleteDocWithLock = sinon.stub().yields()
|
|
return this.HttpController.deleteDoc(this.req, this.res, this.next)
|
|
})
|
|
|
|
it('should delete the doc', function () {
|
|
return this.DocumentManager.flushAndDeleteDocWithLock
|
|
.calledWith(this.project_id, this.doc_id, { ignoreFlushErrors: true })
|
|
.should.equal(true)
|
|
})
|
|
|
|
return it('should return a successful No Content response', function () {
|
|
return this.res.sendStatus.calledWith(204).should.equal(true)
|
|
})
|
|
})
|
|
|
|
return describe('when an errors occurs', function () {
|
|
beforeEach(function () {
|
|
this.DocumentManager.flushAndDeleteDocWithLock = sinon
|
|
.stub()
|
|
.callsArgWith(3, new Error('oops'))
|
|
return this.HttpController.deleteDoc(this.req, this.res, this.next)
|
|
})
|
|
|
|
it('should flush project history', function () {
|
|
return this.HistoryManager.flushProjectChangesAsync
|
|
.calledWithExactly(this.project_id)
|
|
.should.equal(true)
|
|
})
|
|
|
|
return it('should call next with the error', function () {
|
|
return this.next.calledWith(new Error('oops')).should.equal(true)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('deleteProject', function () {
|
|
beforeEach(function () {
|
|
return (this.req = {
|
|
params: {
|
|
project_id: this.project_id
|
|
}
|
|
})
|
|
})
|
|
|
|
describe('successfully', function () {
|
|
beforeEach(function () {
|
|
this.ProjectManager.flushAndDeleteProjectWithLocks = sinon
|
|
.stub()
|
|
.callsArgWith(2)
|
|
return this.HttpController.deleteProject(this.req, this.res, this.next)
|
|
})
|
|
|
|
it('should delete the project', function () {
|
|
return this.ProjectManager.flushAndDeleteProjectWithLocks
|
|
.calledWith(this.project_id)
|
|
.should.equal(true)
|
|
})
|
|
|
|
it('should return a successful No Content response', function () {
|
|
return this.res.sendStatus.calledWith(204).should.equal(true)
|
|
})
|
|
|
|
it('should log the request', function () {
|
|
return this.logger.log
|
|
.calledWith(
|
|
{ project_id: this.project_id },
|
|
'deleting project via http'
|
|
)
|
|
.should.equal(true)
|
|
})
|
|
|
|
return it('should time the request', function () {
|
|
return this.Metrics.Timer.prototype.done.called.should.equal(true)
|
|
})
|
|
})
|
|
|
|
describe('with the background=true option from realtime', function () {
|
|
beforeEach(function () {
|
|
this.ProjectManager.queueFlushAndDeleteProject = sinon
|
|
.stub()
|
|
.callsArgWith(1)
|
|
this.req.query = { background: true, shutdown: true }
|
|
return this.HttpController.deleteProject(this.req, this.res, this.next)
|
|
})
|
|
|
|
return it('should queue the flush and delete', function () {
|
|
return this.ProjectManager.queueFlushAndDeleteProject
|
|
.calledWith(this.project_id)
|
|
.should.equal(true)
|
|
})
|
|
})
|
|
|
|
return describe('when an errors occurs', function () {
|
|
beforeEach(function () {
|
|
this.ProjectManager.flushAndDeleteProjectWithLocks = sinon
|
|
.stub()
|
|
.callsArgWith(2, new Error('oops'))
|
|
return this.HttpController.deleteProject(this.req, this.res, this.next)
|
|
})
|
|
|
|
return it('should call next with the error', function () {
|
|
return this.next.calledWith(new Error('oops')).should.equal(true)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('acceptChanges', function () {
|
|
beforeEach(function () {
|
|
return (this.req = {
|
|
params: {
|
|
project_id: this.project_id,
|
|
doc_id: this.doc_id,
|
|
change_id: (this.change_id = 'mock-change-od-1')
|
|
}
|
|
})
|
|
})
|
|
|
|
describe('successfully with a single change', function () {
|
|
beforeEach(function () {
|
|
this.DocumentManager.acceptChangesWithLock = sinon
|
|
.stub()
|
|
.callsArgWith(3)
|
|
return this.HttpController.acceptChanges(this.req, this.res, this.next)
|
|
})
|
|
|
|
it('should accept the change', function () {
|
|
return this.DocumentManager.acceptChangesWithLock
|
|
.calledWith(this.project_id, this.doc_id, [this.change_id])
|
|
.should.equal(true)
|
|
})
|
|
|
|
it('should return a successful No Content response', function () {
|
|
return this.res.sendStatus.calledWith(204).should.equal(true)
|
|
})
|
|
|
|
it('should log the request', function () {
|
|
return this.logger.log
|
|
.calledWith(
|
|
{ project_id: this.project_id, doc_id: this.doc_id },
|
|
'accepting 1 changes via http'
|
|
)
|
|
.should.equal(true)
|
|
})
|
|
|
|
return it('should time the request', function () {
|
|
return this.Metrics.Timer.prototype.done.called.should.equal(true)
|
|
})
|
|
})
|
|
|
|
describe('succesfully with with multiple changes', function () {
|
|
beforeEach(function () {
|
|
this.change_ids = [
|
|
'mock-change-od-1',
|
|
'mock-change-od-2',
|
|
'mock-change-od-3',
|
|
'mock-change-od-4'
|
|
]
|
|
this.req.body = { change_ids: this.change_ids }
|
|
this.DocumentManager.acceptChangesWithLock = sinon
|
|
.stub()
|
|
.callsArgWith(3)
|
|
return this.HttpController.acceptChanges(this.req, this.res, this.next)
|
|
})
|
|
|
|
it('should accept the changes in the body payload', function () {
|
|
return this.DocumentManager.acceptChangesWithLock
|
|
.calledWith(this.project_id, this.doc_id, this.change_ids)
|
|
.should.equal(true)
|
|
})
|
|
|
|
return it('should log the request with the correct number of changes', function () {
|
|
return this.logger.log
|
|
.calledWith(
|
|
{ project_id: this.project_id, doc_id: this.doc_id },
|
|
`accepting ${this.change_ids.length} changes via http`
|
|
)
|
|
.should.equal(true)
|
|
})
|
|
})
|
|
|
|
return describe('when an errors occurs', function () {
|
|
beforeEach(function () {
|
|
this.DocumentManager.acceptChangesWithLock = sinon
|
|
.stub()
|
|
.callsArgWith(3, new Error('oops'))
|
|
return this.HttpController.acceptChanges(this.req, this.res, this.next)
|
|
})
|
|
|
|
return it('should call next with the error', function () {
|
|
return this.next.calledWith(new Error('oops')).should.equal(true)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('deleteComment', function () {
|
|
beforeEach(function () {
|
|
return (this.req = {
|
|
params: {
|
|
project_id: this.project_id,
|
|
doc_id: this.doc_id,
|
|
comment_id: (this.comment_id = 'mock-comment-id')
|
|
}
|
|
})
|
|
})
|
|
|
|
describe('successfully', function () {
|
|
beforeEach(function () {
|
|
this.DocumentManager.deleteCommentWithLock = sinon
|
|
.stub()
|
|
.callsArgWith(3)
|
|
return this.HttpController.deleteComment(this.req, this.res, this.next)
|
|
})
|
|
|
|
it('should accept the change', function () {
|
|
return this.DocumentManager.deleteCommentWithLock
|
|
.calledWith(this.project_id, this.doc_id, this.comment_id)
|
|
.should.equal(true)
|
|
})
|
|
|
|
it('should return a successful No Content response', function () {
|
|
return this.res.sendStatus.calledWith(204).should.equal(true)
|
|
})
|
|
|
|
it('should log the request', function () {
|
|
return this.logger.log
|
|
.calledWith(
|
|
{
|
|
project_id: this.project_id,
|
|
doc_id: this.doc_id,
|
|
comment_id: this.comment_id
|
|
},
|
|
'deleting comment via http'
|
|
)
|
|
.should.equal(true)
|
|
})
|
|
|
|
return it('should time the request', function () {
|
|
return this.Metrics.Timer.prototype.done.called.should.equal(true)
|
|
})
|
|
})
|
|
|
|
return describe('when an errors occurs', function () {
|
|
beforeEach(function () {
|
|
this.DocumentManager.deleteCommentWithLock = sinon
|
|
.stub()
|
|
.callsArgWith(3, new Error('oops'))
|
|
return this.HttpController.deleteComment(this.req, this.res, this.next)
|
|
})
|
|
|
|
return it('should call next with the error', function () {
|
|
return this.next.calledWith(new Error('oops')).should.equal(true)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('getProjectDocsAndFlushIfOld', function () {
|
|
beforeEach(function () {
|
|
this.state = '01234567890abcdef'
|
|
this.docs = [
|
|
{ _id: '1234', lines: 'hello', v: 23 },
|
|
{ _id: '4567', lines: 'world', v: 45 }
|
|
]
|
|
return (this.req = {
|
|
params: {
|
|
project_id: this.project_id
|
|
},
|
|
query: {
|
|
state: this.state
|
|
}
|
|
})
|
|
})
|
|
|
|
describe('successfully', function () {
|
|
beforeEach(function () {
|
|
this.ProjectManager.getProjectDocsAndFlushIfOld = sinon
|
|
.stub()
|
|
.callsArgWith(3, null, this.docs)
|
|
return this.HttpController.getProjectDocsAndFlushIfOld(
|
|
this.req,
|
|
this.res,
|
|
this.next
|
|
)
|
|
})
|
|
|
|
it('should get docs from the project manager', function () {
|
|
return this.ProjectManager.getProjectDocsAndFlushIfOld
|
|
.calledWith(this.project_id, this.state, {})
|
|
.should.equal(true)
|
|
})
|
|
|
|
it('should return a successful response', function () {
|
|
return this.res.send.calledWith(this.docs).should.equal(true)
|
|
})
|
|
|
|
it('should log the request', function () {
|
|
return this.logger.log
|
|
.calledWith(
|
|
{ project_id: this.project_id, exclude: [] },
|
|
'getting docs via http'
|
|
)
|
|
.should.equal(true)
|
|
})
|
|
|
|
it('should log the response', function () {
|
|
return this.logger.log
|
|
.calledWith(
|
|
{ project_id: this.project_id, result: ['1234:23', '4567:45'] },
|
|
'got docs via http'
|
|
)
|
|
.should.equal(true)
|
|
})
|
|
|
|
return it('should time the request', function () {
|
|
return this.Metrics.Timer.prototype.done.called.should.equal(true)
|
|
})
|
|
})
|
|
|
|
describe('when there is a conflict', function () {
|
|
beforeEach(function () {
|
|
this.ProjectManager.getProjectDocsAndFlushIfOld = sinon
|
|
.stub()
|
|
.callsArgWith(
|
|
3,
|
|
new Errors.ProjectStateChangedError('project state changed')
|
|
)
|
|
return this.HttpController.getProjectDocsAndFlushIfOld(
|
|
this.req,
|
|
this.res,
|
|
this.next
|
|
)
|
|
})
|
|
|
|
return it('should return an HTTP 409 Conflict response', function () {
|
|
return this.res.sendStatus.calledWith(409).should.equal(true)
|
|
})
|
|
})
|
|
|
|
return describe('when an error occurs', function () {
|
|
beforeEach(function () {
|
|
this.ProjectManager.getProjectDocsAndFlushIfOld = sinon
|
|
.stub()
|
|
.callsArgWith(3, new Error('oops'))
|
|
return this.HttpController.getProjectDocsAndFlushIfOld(
|
|
this.req,
|
|
this.res,
|
|
this.next
|
|
)
|
|
})
|
|
|
|
return it('should call next with the error', function () {
|
|
return this.next.calledWith(new Error('oops')).should.equal(true)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('updateProject', function () {
|
|
beforeEach(function () {
|
|
this.projectHistoryId = 'history-id-123'
|
|
this.userId = 'user-id-123'
|
|
this.docUpdates = sinon.stub()
|
|
this.fileUpdates = sinon.stub()
|
|
this.version = 1234567
|
|
return (this.req = {
|
|
body: {
|
|
projectHistoryId: this.projectHistoryId,
|
|
userId: this.userId,
|
|
docUpdates: this.docUpdates,
|
|
fileUpdates: this.fileUpdates,
|
|
version: this.version
|
|
},
|
|
params: {
|
|
project_id: this.project_id
|
|
}
|
|
})
|
|
})
|
|
|
|
describe('successfully', function () {
|
|
beforeEach(function () {
|
|
this.ProjectManager.updateProjectWithLocks = sinon
|
|
.stub()
|
|
.callsArgWith(6)
|
|
return this.HttpController.updateProject(this.req, this.res, this.next)
|
|
})
|
|
|
|
it('should accept the change', function () {
|
|
return this.ProjectManager.updateProjectWithLocks
|
|
.calledWith(
|
|
this.project_id,
|
|
this.projectHistoryId,
|
|
this.userId,
|
|
this.docUpdates,
|
|
this.fileUpdates,
|
|
this.version
|
|
)
|
|
.should.equal(true)
|
|
})
|
|
|
|
it('should return a successful No Content response', function () {
|
|
return this.res.sendStatus.calledWith(204).should.equal(true)
|
|
})
|
|
|
|
return it('should time the request', function () {
|
|
return this.Metrics.Timer.prototype.done.called.should.equal(true)
|
|
})
|
|
})
|
|
|
|
return describe('when an errors occurs', function () {
|
|
beforeEach(function () {
|
|
this.ProjectManager.updateProjectWithLocks = sinon
|
|
.stub()
|
|
.callsArgWith(6, new Error('oops'))
|
|
return this.HttpController.updateProject(this.req, this.res, this.next)
|
|
})
|
|
|
|
return it('should call next with the error', function () {
|
|
return this.next.calledWith(new Error('oops')).should.equal(true)
|
|
})
|
|
})
|
|
})
|
|
|
|
return describe('resyncProjectHistory', function () {
|
|
beforeEach(function () {
|
|
this.projectHistoryId = 'history-id-123'
|
|
this.docs = sinon.stub()
|
|
this.files = sinon.stub()
|
|
this.fileUpdates = sinon.stub()
|
|
return (this.req = {
|
|
body: {
|
|
projectHistoryId: this.projectHistoryId,
|
|
docs: this.docs,
|
|
files: this.files
|
|
},
|
|
params: {
|
|
project_id: this.project_id
|
|
}
|
|
})
|
|
})
|
|
|
|
describe('successfully', function () {
|
|
beforeEach(function () {
|
|
this.HistoryManager.resyncProjectHistory = sinon.stub().callsArgWith(4)
|
|
return this.HttpController.resyncProjectHistory(
|
|
this.req,
|
|
this.res,
|
|
this.next
|
|
)
|
|
})
|
|
|
|
it('should accept the change', function () {
|
|
return this.HistoryManager.resyncProjectHistory
|
|
.calledWith(
|
|
this.project_id,
|
|
this.projectHistoryId,
|
|
this.docs,
|
|
this.files
|
|
)
|
|
.should.equal(true)
|
|
})
|
|
|
|
return it('should return a successful No Content response', function () {
|
|
return this.res.sendStatus.calledWith(204).should.equal(true)
|
|
})
|
|
})
|
|
|
|
return describe('when an errors occurs', function () {
|
|
beforeEach(function () {
|
|
this.HistoryManager.resyncProjectHistory = sinon
|
|
.stub()
|
|
.callsArgWith(4, new Error('oops'))
|
|
return this.HttpController.resyncProjectHistory(
|
|
this.req,
|
|
this.res,
|
|
this.next
|
|
)
|
|
})
|
|
|
|
return it('should call next with the error', function () {
|
|
return this.next.calledWith(new Error('oops')).should.equal(true)
|
|
})
|
|
})
|
|
})
|
|
})
|