2020-05-06 06:11:22 -04:00
|
|
|
/* eslint-disable
|
|
|
|
no-return-assign,
|
|
|
|
no-unused-vars,
|
|
|
|
*/
|
|
|
|
// TODO: This file was created by bulk-decaffeinate.
|
|
|
|
// Fix any style issues and re-enable lint.
|
2020-05-06 06:10:51 -04:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|
2020-05-06 06:11:36 -04:00
|
|
|
const sinon = require('sinon')
|
|
|
|
const modulePath = '../../../../app/js/PersistenceManager.js'
|
|
|
|
const SandboxedModule = require('sandboxed-module')
|
|
|
|
const Errors = require('../../../../app/js/Errors')
|
|
|
|
|
|
|
|
describe('PersistenceManager', function () {
|
|
|
|
beforeEach(function () {
|
|
|
|
let Timer
|
|
|
|
this.request = sinon.stub()
|
|
|
|
this.request.defaults = () => this.request
|
|
|
|
this.PersistenceManager = SandboxedModule.require(modulePath, {
|
|
|
|
requires: {
|
|
|
|
requestretry: this.request,
|
2021-07-12 12:47:15 -04:00
|
|
|
'@overleaf/settings': (this.Settings = {}),
|
2020-05-06 06:11:36 -04:00
|
|
|
'./Metrics': (this.Metrics = {
|
|
|
|
Timer: (Timer = (function () {
|
|
|
|
Timer = class Timer {
|
|
|
|
static initClass() {
|
|
|
|
this.prototype.done = sinon.stub()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Timer.initClass()
|
|
|
|
return Timer
|
|
|
|
})()),
|
2021-07-13 07:04:42 -04:00
|
|
|
inc: sinon.stub(),
|
2020-05-06 06:11:36 -04:00
|
|
|
}),
|
2021-07-13 07:04:42 -04:00
|
|
|
'./Errors': Errors,
|
|
|
|
},
|
2020-05-06 06:11:36 -04:00
|
|
|
})
|
|
|
|
this.project_id = 'project-id-123'
|
|
|
|
this.projectHistoryId = 'history-id-123'
|
|
|
|
this.doc_id = 'doc-id-123'
|
|
|
|
this.lines = ['one', 'two', 'three']
|
|
|
|
this.version = 42
|
|
|
|
this.callback = sinon.stub()
|
|
|
|
this.ranges = { comments: 'mock', entries: 'mock' }
|
|
|
|
this.pathname = '/a/b/c.tex'
|
|
|
|
this.lastUpdatedAt = Date.now()
|
|
|
|
this.lastUpdatedBy = 'last-author-id'
|
|
|
|
return (this.Settings.apis = {
|
|
|
|
web: {
|
|
|
|
url: (this.url = 'www.example.com'),
|
|
|
|
user: (this.user = 'sharelatex'),
|
2021-07-13 07:04:42 -04:00
|
|
|
pass: (this.pass = 'password'),
|
|
|
|
},
|
2020-05-06 06:11:36 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('getDoc', function () {
|
|
|
|
beforeEach(function () {
|
|
|
|
return (this.webResponse = {
|
|
|
|
lines: this.lines,
|
|
|
|
version: this.version,
|
|
|
|
ranges: this.ranges,
|
|
|
|
pathname: this.pathname,
|
2021-07-13 07:04:42 -04:00
|
|
|
projectHistoryId: this.projectHistoryId,
|
2020-05-06 06:11:36 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('with a successful response from the web api', function () {
|
|
|
|
beforeEach(function () {
|
|
|
|
this.request.callsArgWith(
|
|
|
|
1,
|
|
|
|
null,
|
|
|
|
{ statusCode: 200 },
|
|
|
|
JSON.stringify(this.webResponse)
|
|
|
|
)
|
|
|
|
return this.PersistenceManager.getDoc(
|
|
|
|
this.project_id,
|
|
|
|
this.doc_id,
|
|
|
|
this.callback
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should call the web api', function () {
|
|
|
|
return this.request
|
|
|
|
.calledWith({
|
|
|
|
url: `${this.url}/project/${this.project_id}/doc/${this.doc_id}`,
|
|
|
|
method: 'GET',
|
|
|
|
headers: {
|
2021-07-13 07:04:42 -04:00
|
|
|
accept: 'application/json',
|
2020-05-06 06:11:36 -04:00
|
|
|
},
|
|
|
|
auth: {
|
|
|
|
user: this.user,
|
|
|
|
pass: this.pass,
|
2021-07-13 07:04:42 -04:00
|
|
|
sendImmediately: true,
|
2020-05-06 06:11:36 -04:00
|
|
|
},
|
|
|
|
jar: false,
|
2021-07-13 07:04:42 -04:00
|
|
|
timeout: 5000,
|
2020-05-06 06:11:36 -04:00
|
|
|
})
|
|
|
|
.should.equal(true)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should call the callback with the doc lines, version and ranges', function () {
|
|
|
|
return this.callback
|
|
|
|
.calledWith(
|
|
|
|
null,
|
|
|
|
this.lines,
|
|
|
|
this.version,
|
|
|
|
this.ranges,
|
|
|
|
this.pathname,
|
|
|
|
this.projectHistoryId
|
|
|
|
)
|
|
|
|
.should.equal(true)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should time the execution', function () {
|
|
|
|
return this.Metrics.Timer.prototype.done.called.should.equal(true)
|
|
|
|
})
|
|
|
|
|
|
|
|
return it('should increment the metric', function () {
|
|
|
|
return this.Metrics.inc
|
|
|
|
.calledWith('getDoc', 1, { status: 200 })
|
|
|
|
.should.equal(true)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('when request returns an error', function () {
|
|
|
|
beforeEach(function () {
|
|
|
|
this.error = new Error('oops')
|
|
|
|
this.error.code = 'EOOPS'
|
|
|
|
this.request.callsArgWith(1, this.error, null, null)
|
|
|
|
return this.PersistenceManager.getDoc(
|
|
|
|
this.project_id,
|
|
|
|
this.doc_id,
|
|
|
|
this.callback
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2021-02-24 09:09:19 -05:00
|
|
|
it('should return a generic connection error', function () {
|
|
|
|
return this.callback
|
|
|
|
.calledWith(
|
|
|
|
sinon.match
|
|
|
|
.instanceOf(Error)
|
|
|
|
.and(sinon.match.has('message', 'error connecting to web API'))
|
|
|
|
)
|
|
|
|
.should.equal(true)
|
2020-05-06 06:11:36 -04:00
|
|
|
})
|
|
|
|
|
|
|
|
it('should time the execution', function () {
|
|
|
|
return this.Metrics.Timer.prototype.done.called.should.equal(true)
|
|
|
|
})
|
|
|
|
|
|
|
|
return it('should increment the metric', function () {
|
|
|
|
return this.Metrics.inc
|
|
|
|
.calledWith('getDoc', 1, { status: 'EOOPS' })
|
|
|
|
.should.equal(true)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('when the request returns 404', function () {
|
|
|
|
beforeEach(function () {
|
|
|
|
this.request.callsArgWith(1, null, { statusCode: 404 }, '')
|
|
|
|
return this.PersistenceManager.getDoc(
|
|
|
|
this.project_id,
|
|
|
|
this.doc_id,
|
|
|
|
this.callback
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should return a NotFoundError', function () {
|
|
|
|
return this.callback
|
2020-05-15 14:29:49 -04:00
|
|
|
.calledWith(sinon.match.instanceOf(Errors.NotFoundError))
|
2020-05-06 06:11:36 -04:00
|
|
|
.should.equal(true)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should time the execution', function () {
|
|
|
|
return this.Metrics.Timer.prototype.done.called.should.equal(true)
|
|
|
|
})
|
|
|
|
|
|
|
|
return it('should increment the metric', function () {
|
|
|
|
return this.Metrics.inc
|
|
|
|
.calledWith('getDoc', 1, { status: 404 })
|
|
|
|
.should.equal(true)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('when the request returns an error status code', function () {
|
|
|
|
beforeEach(function () {
|
|
|
|
this.request.callsArgWith(1, null, { statusCode: 500 }, '')
|
|
|
|
return this.PersistenceManager.getDoc(
|
|
|
|
this.project_id,
|
|
|
|
this.doc_id,
|
|
|
|
this.callback
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should return an error', function () {
|
|
|
|
return this.callback
|
2020-05-15 14:29:49 -04:00
|
|
|
.calledWith(sinon.match.instanceOf(Error))
|
2020-05-06 06:11:36 -04:00
|
|
|
.should.equal(true)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should time the execution', function () {
|
|
|
|
return this.Metrics.Timer.prototype.done.called.should.equal(true)
|
|
|
|
})
|
|
|
|
|
|
|
|
return it('should increment the metric', function () {
|
|
|
|
return this.Metrics.inc
|
|
|
|
.calledWith('getDoc', 1, { status: 500 })
|
|
|
|
.should.equal(true)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('when request returns an doc without lines', function () {
|
|
|
|
beforeEach(function () {
|
|
|
|
delete this.webResponse.lines
|
|
|
|
this.request.callsArgWith(
|
|
|
|
1,
|
|
|
|
null,
|
|
|
|
{ statusCode: 200 },
|
|
|
|
JSON.stringify(this.webResponse)
|
|
|
|
)
|
|
|
|
return this.PersistenceManager.getDoc(
|
|
|
|
this.project_id,
|
|
|
|
this.doc_id,
|
|
|
|
this.callback
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
return it('should return and error', function () {
|
|
|
|
return this.callback
|
2020-05-15 14:29:49 -04:00
|
|
|
.calledWith(sinon.match.instanceOf(Error))
|
2020-05-06 06:11:36 -04:00
|
|
|
.should.equal(true)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('when request returns an doc without a version', function () {
|
|
|
|
beforeEach(function () {
|
|
|
|
delete this.webResponse.version
|
|
|
|
this.request.callsArgWith(
|
|
|
|
1,
|
|
|
|
null,
|
|
|
|
{ statusCode: 200 },
|
|
|
|
JSON.stringify(this.webResponse)
|
|
|
|
)
|
|
|
|
return this.PersistenceManager.getDoc(
|
|
|
|
this.project_id,
|
|
|
|
this.doc_id,
|
|
|
|
this.callback
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
return it('should return and error', function () {
|
|
|
|
return this.callback
|
2020-05-15 14:29:49 -04:00
|
|
|
.calledWith(sinon.match.instanceOf(Error))
|
2020-05-06 06:11:36 -04:00
|
|
|
.should.equal(true)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
return describe('when request returns an doc without a pathname', function () {
|
|
|
|
beforeEach(function () {
|
|
|
|
delete this.webResponse.pathname
|
|
|
|
this.request.callsArgWith(
|
|
|
|
1,
|
|
|
|
null,
|
|
|
|
{ statusCode: 200 },
|
|
|
|
JSON.stringify(this.webResponse)
|
|
|
|
)
|
|
|
|
return this.PersistenceManager.getDoc(
|
|
|
|
this.project_id,
|
|
|
|
this.doc_id,
|
|
|
|
this.callback
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
return it('should return and error', function () {
|
|
|
|
return this.callback
|
2020-05-15 14:29:49 -04:00
|
|
|
.calledWith(sinon.match.instanceOf(Error))
|
2020-05-06 06:11:36 -04:00
|
|
|
.should.equal(true)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
return describe('setDoc', function () {
|
|
|
|
describe('with a successful response from the web api', function () {
|
|
|
|
beforeEach(function () {
|
|
|
|
this.request.callsArgWith(1, null, { statusCode: 200 })
|
|
|
|
return this.PersistenceManager.setDoc(
|
|
|
|
this.project_id,
|
|
|
|
this.doc_id,
|
|
|
|
this.lines,
|
|
|
|
this.version,
|
|
|
|
this.ranges,
|
|
|
|
this.lastUpdatedAt,
|
|
|
|
this.lastUpdatedBy,
|
|
|
|
this.callback
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should call the web api', function () {
|
|
|
|
return this.request
|
|
|
|
.calledWith({
|
|
|
|
url: `${this.url}/project/${this.project_id}/doc/${this.doc_id}`,
|
|
|
|
json: {
|
|
|
|
lines: this.lines,
|
|
|
|
version: this.version,
|
|
|
|
ranges: this.ranges,
|
|
|
|
lastUpdatedAt: this.lastUpdatedAt,
|
2021-07-13 07:04:42 -04:00
|
|
|
lastUpdatedBy: this.lastUpdatedBy,
|
2020-05-06 06:11:36 -04:00
|
|
|
},
|
|
|
|
method: 'POST',
|
|
|
|
auth: {
|
|
|
|
user: this.user,
|
|
|
|
pass: this.pass,
|
2021-07-13 07:04:42 -04:00
|
|
|
sendImmediately: true,
|
2020-05-06 06:11:36 -04:00
|
|
|
},
|
|
|
|
jar: false,
|
2021-07-13 07:04:42 -04:00
|
|
|
timeout: 5000,
|
2020-05-06 06:11:36 -04:00
|
|
|
})
|
|
|
|
.should.equal(true)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should call the callback without error', function () {
|
|
|
|
return this.callback.calledWith(null).should.equal(true)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should time the execution', function () {
|
|
|
|
return this.Metrics.Timer.prototype.done.called.should.equal(true)
|
|
|
|
})
|
|
|
|
|
|
|
|
return it('should increment the metric', function () {
|
|
|
|
return this.Metrics.inc
|
|
|
|
.calledWith('setDoc', 1, { status: 200 })
|
|
|
|
.should.equal(true)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('when request returns an error', function () {
|
|
|
|
beforeEach(function () {
|
|
|
|
this.error = new Error('oops')
|
|
|
|
this.error.code = 'EOOPS'
|
|
|
|
this.request.callsArgWith(1, this.error, null, null)
|
|
|
|
return this.PersistenceManager.setDoc(
|
|
|
|
this.project_id,
|
|
|
|
this.doc_id,
|
|
|
|
this.lines,
|
|
|
|
this.version,
|
|
|
|
this.ranges,
|
|
|
|
this.lastUpdatedAt,
|
|
|
|
this.lastUpdatedBy,
|
|
|
|
this.callback
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2021-02-24 09:09:19 -05:00
|
|
|
it('should return a generic connection error', function () {
|
|
|
|
return this.callback
|
|
|
|
.calledWith(
|
|
|
|
sinon.match
|
|
|
|
.instanceOf(Error)
|
|
|
|
.and(sinon.match.has('message', 'error connecting to web API'))
|
|
|
|
)
|
|
|
|
.should.equal(true)
|
2020-05-06 06:11:36 -04:00
|
|
|
})
|
|
|
|
|
|
|
|
it('should time the execution', function () {
|
|
|
|
return this.Metrics.Timer.prototype.done.called.should.equal(true)
|
|
|
|
})
|
|
|
|
|
|
|
|
return it('should increment the metric', function () {
|
|
|
|
return this.Metrics.inc
|
|
|
|
.calledWith('setDoc', 1, { status: 'EOOPS' })
|
|
|
|
.should.equal(true)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('when the request returns 404', function () {
|
|
|
|
beforeEach(function () {
|
|
|
|
this.request.callsArgWith(1, null, { statusCode: 404 }, '')
|
|
|
|
return this.PersistenceManager.setDoc(
|
|
|
|
this.project_id,
|
|
|
|
this.doc_id,
|
|
|
|
this.lines,
|
|
|
|
this.version,
|
|
|
|
this.ranges,
|
|
|
|
this.lastUpdatedAt,
|
|
|
|
this.lastUpdatedBy,
|
|
|
|
this.callback
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should return a NotFoundError', function () {
|
|
|
|
return this.callback
|
2020-05-15 14:29:49 -04:00
|
|
|
.calledWith(sinon.match.instanceOf(Errors.NotFoundError))
|
2020-05-06 06:11:36 -04:00
|
|
|
.should.equal(true)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should time the execution', function () {
|
|
|
|
return this.Metrics.Timer.prototype.done.called.should.equal(true)
|
|
|
|
})
|
|
|
|
|
|
|
|
return it('should increment the metric', function () {
|
|
|
|
return this.Metrics.inc
|
|
|
|
.calledWith('setDoc', 1, { status: 404 })
|
|
|
|
.should.equal(true)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
return describe('when the request returns an error status code', function () {
|
|
|
|
beforeEach(function () {
|
|
|
|
this.request.callsArgWith(1, null, { statusCode: 500 }, '')
|
|
|
|
return this.PersistenceManager.setDoc(
|
|
|
|
this.project_id,
|
|
|
|
this.doc_id,
|
|
|
|
this.lines,
|
|
|
|
this.version,
|
|
|
|
this.ranges,
|
|
|
|
this.lastUpdatedAt,
|
|
|
|
this.lastUpdatedBy,
|
|
|
|
this.callback
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should return an error', function () {
|
|
|
|
return this.callback
|
2020-05-15 14:29:49 -04:00
|
|
|
.calledWith(sinon.match.instanceOf(Error))
|
2020-05-06 06:11:36 -04:00
|
|
|
.should.equal(true)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should time the execution', function () {
|
|
|
|
return this.Metrics.Timer.prototype.done.called.should.equal(true)
|
|
|
|
})
|
|
|
|
|
|
|
|
return it('should increment the metric', function () {
|
|
|
|
return this.Metrics.inc
|
|
|
|
.calledWith('setDoc', 1, { status: 500 })
|
|
|
|
.should.equal(true)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|