mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-23 17:19:37 +02:00
Merge pull request #31444 from overleaf/bg-jpa-use-fetch-in-persistence-manager
remove requestretry from PersistenceManager GitOrigin-RevId: 1fc9ffdfa7879d7ab4f0f4683544d09fe8526f3d
This commit is contained in:
@@ -882,7 +882,7 @@ describe('Applying updates to a doc', function () {
|
||||
JSON.parse(message).should.deep.include({
|
||||
project_id: this.project_id,
|
||||
doc_id: this.doc_id,
|
||||
error: `doc not not found: /project/${this.project_id}/doc/${this.doc_id}`,
|
||||
error: 'doc not found',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -5,6 +5,7 @@ const MockWebApi = require('./helpers/MockWebApi')
|
||||
const DocUpdaterClient = require('./helpers/DocUpdaterClient')
|
||||
const DocUpdaterApp = require('./helpers/DocUpdaterApp')
|
||||
const { RequestFailedError } = require('@overleaf/fetch-utils')
|
||||
const PersistenceManager = require('../../../app/js/PersistenceManager')
|
||||
|
||||
describe('Getting a document', function () {
|
||||
before(async function () {
|
||||
@@ -49,6 +50,53 @@ describe('Getting a document', function () {
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the document is not loaded and the peek option is used', function () {
|
||||
before(async function () {
|
||||
const origGetDocumentController =
|
||||
MockWebApi.getDocumentController.bind(MockWebApi)
|
||||
sinon
|
||||
.stub(MockWebApi, 'getDocumentController')
|
||||
.callsFake((req, res, next) => {
|
||||
expect(req.query.peek).to.equal('true')
|
||||
return origGetDocumentController(req, res, next)
|
||||
})
|
||||
this.project_id = DocUpdaterClient.randomId()
|
||||
this.doc_id = DocUpdaterClient.randomId()
|
||||
sinon.spy(MockWebApi, 'getDocument')
|
||||
|
||||
MockWebApi.insertDoc(this.project_id, this.doc_id, {
|
||||
lines: this.lines,
|
||||
version: this.version,
|
||||
})
|
||||
// This is only used by the resync code and not exposed on the HTTP
|
||||
// api so we are calling it directly.
|
||||
this.returnedDoc = await PersistenceManager.promises.getDoc(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
{ peek: true }
|
||||
)
|
||||
})
|
||||
|
||||
after(function () {
|
||||
MockWebApi.getDocumentController.restore()
|
||||
MockWebApi.getDocument.restore()
|
||||
})
|
||||
|
||||
it('should load the document from the web API with peek=true', function () {
|
||||
MockWebApi.getDocument
|
||||
.calledWith(this.project_id, this.doc_id)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should return the document lines', function () {
|
||||
this.returnedDoc.lines.should.deep.equal(this.lines)
|
||||
})
|
||||
|
||||
it('should return the document at its current version', function () {
|
||||
this.returnedDoc.version.should.equal(this.version)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the document is already loaded', function () {
|
||||
before(async function () {
|
||||
this.project_id = DocUpdaterClient.randomId()
|
||||
@@ -146,11 +194,11 @@ describe('Getting a document', function () {
|
||||
})
|
||||
|
||||
describe('when the web api returns an error', function () {
|
||||
before(function () {
|
||||
beforeEach(function () {
|
||||
sinon.stub(MockWebApi, 'getDocument').rejects(new Error('oops'))
|
||||
})
|
||||
|
||||
after(function () {
|
||||
afterEach(function () {
|
||||
MockWebApi.getDocument.restore()
|
||||
})
|
||||
|
||||
@@ -161,6 +209,133 @@ describe('Getting a document', function () {
|
||||
.to.be.rejectedWith(RequestFailedError)
|
||||
.and.eventually.have.nested.property('response.status', 500)
|
||||
})
|
||||
|
||||
it('should retry the request', async function () {
|
||||
const projectId = DocUpdaterClient.randomId()
|
||||
const docId = DocUpdaterClient.randomId()
|
||||
await expect(DocUpdaterClient.getDoc(projectId, docId))
|
||||
.to.be.rejectedWith(RequestFailedError)
|
||||
.and.eventually.have.nested.property('response.status', 500)
|
||||
expect(MockWebApi.getDocument).to.be.calledTwice
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the web api returns a retryable error on the first attempt', function () {
|
||||
beforeEach(function () {
|
||||
const origGetDocumentController =
|
||||
MockWebApi.getDocumentController.bind(MockWebApi)
|
||||
const getDocumentStub = sinon
|
||||
.stub(MockWebApi, 'getDocumentController')
|
||||
.onCall(0)
|
||||
.callsFake((req, res, next) => {
|
||||
res.destroy() // simulate a network error
|
||||
})
|
||||
getDocumentStub.onCall(1).callsFake(origGetDocumentController)
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
MockWebApi.getDocumentController.restore()
|
||||
})
|
||||
|
||||
it('should return 200', async function () {
|
||||
const projectId = DocUpdaterClient.randomId()
|
||||
const docId = DocUpdaterClient.randomId()
|
||||
MockWebApi.insertDoc(projectId, docId, {
|
||||
lines: this.lines,
|
||||
version: this.version,
|
||||
})
|
||||
|
||||
await expect(
|
||||
DocUpdaterClient.getDoc(projectId, docId)
|
||||
).to.eventually.deep.include({ lines: this.lines, version: this.version })
|
||||
})
|
||||
|
||||
it('should retry the request', async function () {
|
||||
const projectId = DocUpdaterClient.randomId()
|
||||
const docId = DocUpdaterClient.randomId()
|
||||
MockWebApi.insertDoc(projectId, docId, {
|
||||
lines: this.lines,
|
||||
version: this.version,
|
||||
})
|
||||
await expect(
|
||||
DocUpdaterClient.getDoc(projectId, docId)
|
||||
).to.eventually.deep.include({ lines: this.lines, version: this.version })
|
||||
|
||||
expect(MockWebApi.getDocumentController).to.be.calledTwice
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the web api returns a 413 error', function () {
|
||||
beforeEach(function () {
|
||||
sinon
|
||||
.stub(MockWebApi, 'getDocumentController')
|
||||
.callsFake((req, res, next) => {
|
||||
res.sendStatus(413)
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
MockWebApi.getDocumentController.restore()
|
||||
})
|
||||
|
||||
it('should return 413', async function () {
|
||||
const projectId = DocUpdaterClient.randomId()
|
||||
const docId = DocUpdaterClient.randomId()
|
||||
await expect(DocUpdaterClient.getDoc(projectId, docId))
|
||||
.to.be.rejectedWith(RequestFailedError)
|
||||
.and.eventually.have.nested.property('response.status', 413)
|
||||
})
|
||||
|
||||
it('should not retry the request', async function () {
|
||||
const projectId = DocUpdaterClient.randomId()
|
||||
const docId = DocUpdaterClient.randomId()
|
||||
await expect(DocUpdaterClient.getDoc(projectId, docId))
|
||||
.to.be.rejectedWith(RequestFailedError)
|
||||
.and.eventually.have.nested.property('response.status', 413)
|
||||
expect(MockWebApi.getDocumentController).to.be.calledOnce
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the web api returns an incomplete doc', function () {
|
||||
afterEach(function () {
|
||||
MockWebApi.getDocument.restore()
|
||||
})
|
||||
|
||||
it('should return an error for missing lines', async function () {
|
||||
const projectId = DocUpdaterClient.randomId()
|
||||
const docId = DocUpdaterClient.randomId()
|
||||
sinon
|
||||
.stub(MockWebApi, 'getDocument')
|
||||
.resolves({ version: 123, pathname: 'test' })
|
||||
|
||||
await expect(DocUpdaterClient.getDoc(projectId, docId))
|
||||
.to.be.rejectedWith(RequestFailedError)
|
||||
.and.eventually.have.nested.property('response.status', 422)
|
||||
})
|
||||
|
||||
it('should return an error for missing version', async function () {
|
||||
const projectId = DocUpdaterClient.randomId()
|
||||
const docId = DocUpdaterClient.randomId()
|
||||
sinon
|
||||
.stub(MockWebApi, 'getDocument')
|
||||
.resolves({ lines: [''], pathname: 'test' })
|
||||
|
||||
await expect(DocUpdaterClient.getDoc(projectId, docId))
|
||||
.to.be.rejectedWith(RequestFailedError)
|
||||
.and.eventually.have.nested.property('response.status', 422)
|
||||
})
|
||||
|
||||
it('should return an error for missing pathname', async function () {
|
||||
const projectId = DocUpdaterClient.randomId()
|
||||
const docId = DocUpdaterClient.randomId()
|
||||
sinon
|
||||
.stub(MockWebApi, 'getDocument')
|
||||
.resolves({ lines: [''], version: 123 })
|
||||
|
||||
await expect(DocUpdaterClient.getDoc(projectId, docId))
|
||||
.to.be.rejectedWith(RequestFailedError)
|
||||
.and.eventually.have.nested.property('response.status', 422)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the web api http request takes a long time', function () {
|
||||
|
||||
@@ -757,4 +757,163 @@ describe('Setting a document', function () {
|
||||
})
|
||||
}
|
||||
})
|
||||
describe('when the first request returns a connection error', function () {
|
||||
beforeEach(function () {
|
||||
const origSetDocumentController =
|
||||
MockWebApi.setDocumentController.bind(MockWebApi)
|
||||
const setDocumentStub = sinon
|
||||
.stub(MockWebApi, 'setDocumentController')
|
||||
.onCall(0)
|
||||
.callsFake((req, res, next) => {
|
||||
res.destroy() // simulate a network error
|
||||
})
|
||||
setDocumentStub.onCall(1).callsFake(origSetDocumentController)
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
MockWebApi.setDocumentController.restore()
|
||||
})
|
||||
|
||||
it('should retry on connection error and set the document', async function () {
|
||||
this.project_id = DocUpdaterClient.randomId()
|
||||
this.doc_id = DocUpdaterClient.randomId()
|
||||
MockWebApi.insertDoc(this.project_id, this.doc_id, {
|
||||
lines: this.lines,
|
||||
version: this.version,
|
||||
projectHistoryId: this.project_id,
|
||||
})
|
||||
await DocUpdaterClient.preloadDoc(this.project_id, this.doc_id)
|
||||
|
||||
await expect(
|
||||
DocUpdaterClient.setDocLines(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
this.newLines,
|
||||
this.source,
|
||||
this.user_id,
|
||||
false
|
||||
)
|
||||
).to.eventually.deep.include({ rev: '123' })
|
||||
|
||||
expect(MockWebApi.setDocumentController).to.be.calledTwice
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the document does not exist', function () {
|
||||
before(function () {
|
||||
sinon.spy(MockWebApi, 'setDocumentController')
|
||||
})
|
||||
after(function () {
|
||||
MockWebApi.setDocumentController.restore()
|
||||
})
|
||||
|
||||
it('should return 404', async function () {
|
||||
this.project_id = DocUpdaterClient.randomId()
|
||||
this.doc_id = DocUpdaterClient.randomId()
|
||||
MockWebApi.insertDoc(this.project_id, this.doc_id, {
|
||||
lines: this.lines,
|
||||
version: this.version,
|
||||
projectHistoryId: this.project_id,
|
||||
})
|
||||
await DocUpdaterClient.preloadDoc(this.project_id, this.doc_id)
|
||||
MockWebApi.clearDocs()
|
||||
|
||||
await expect(
|
||||
DocUpdaterClient.setDocLines(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
this.newLines,
|
||||
this.source,
|
||||
this.user_id,
|
||||
false
|
||||
)
|
||||
)
|
||||
.to.be.rejectedWith(RequestFailedError)
|
||||
.and.eventually.have.nested.property('response.status', 404)
|
||||
|
||||
expect(MockWebApi.setDocumentController).to.be.calledOnce
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the document is too large', function () {
|
||||
beforeEach(function () {
|
||||
sinon
|
||||
.stub(MockWebApi, 'setDocumentController')
|
||||
.callsFake((req, res, next) => {
|
||||
res.sendStatus(413) // simulate a large file error
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
MockWebApi.setDocumentController.restore()
|
||||
})
|
||||
|
||||
it('should return 413', async function () {
|
||||
this.project_id = DocUpdaterClient.randomId()
|
||||
this.doc_id = DocUpdaterClient.randomId()
|
||||
MockWebApi.insertDoc(this.project_id, this.doc_id, {
|
||||
lines: this.lines,
|
||||
version: this.version,
|
||||
projectHistoryId: this.project_id,
|
||||
})
|
||||
await DocUpdaterClient.preloadDoc(this.project_id, this.doc_id)
|
||||
MockWebApi.clearDocs()
|
||||
|
||||
await expect(
|
||||
DocUpdaterClient.setDocLines(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
this.newLines,
|
||||
this.source,
|
||||
this.user_id,
|
||||
false
|
||||
)
|
||||
)
|
||||
.to.be.rejectedWith(RequestFailedError)
|
||||
.and.eventually.have.nested.property('response.status', 413)
|
||||
expect(MockWebApi.setDocumentController).to.be.calledOnce
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the first request returns a 500 error', function () {
|
||||
beforeEach(function () {
|
||||
const origSetDocumentController =
|
||||
MockWebApi.setDocumentController.bind(MockWebApi)
|
||||
const setDocumentStub = sinon
|
||||
.stub(MockWebApi, 'setDocumentController')
|
||||
.onCall(0)
|
||||
.callsFake((req, res, next) => {
|
||||
res.sendStatus(500)
|
||||
})
|
||||
setDocumentStub.onCall(1).callsFake(origSetDocumentController)
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
MockWebApi.setDocumentController.restore()
|
||||
})
|
||||
|
||||
it('should retry on a 500 error and set the document', async function () {
|
||||
this.project_id = DocUpdaterClient.randomId()
|
||||
this.doc_id = DocUpdaterClient.randomId()
|
||||
MockWebApi.insertDoc(this.project_id, this.doc_id, {
|
||||
lines: this.lines,
|
||||
version: this.version,
|
||||
projectHistoryId: this.project_id,
|
||||
})
|
||||
await DocUpdaterClient.preloadDoc(this.project_id, this.doc_id)
|
||||
|
||||
await expect(
|
||||
DocUpdaterClient.setDocLines(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
this.newLines,
|
||||
this.source,
|
||||
this.user_id,
|
||||
false
|
||||
)
|
||||
).to.eventually.deep.include({ rev: '123' })
|
||||
|
||||
expect(MockWebApi.setDocumentController).to.be.calledTwice
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
let MockWebApi
|
||||
const basicAuth = require('basic-auth')
|
||||
const tsscmp = require('tsscmp')
|
||||
const express = require('express')
|
||||
const bodyParser = require('body-parser')
|
||||
const { expressify } = require('@overleaf/promise-utils')
|
||||
const Settings = require('@overleaf/settings')
|
||||
const app = express()
|
||||
const MAX_REQUEST_SIZE = 2 * (2 * 1024 * 1024 + 64 * 1024)
|
||||
|
||||
@@ -32,38 +35,79 @@ module.exports = MockWebApi = {
|
||||
lastUpdatedAt,
|
||||
lastUpdatedBy
|
||||
) {
|
||||
const doc =
|
||||
this.docs[`${projectId}:${docId}`] ||
|
||||
(this.docs[`${projectId}:${docId}`] = {})
|
||||
if (!(`${projectId}:${docId}` in this.docs)) {
|
||||
return false
|
||||
}
|
||||
const doc = this.docs[`${projectId}:${docId}`]
|
||||
doc.lines = lines
|
||||
doc.version = version
|
||||
doc.ranges = ranges
|
||||
doc.pathname = '/a/b/c.tex'
|
||||
doc.lastUpdatedAt = lastUpdatedAt
|
||||
doc.lastUpdatedBy = lastUpdatedBy
|
||||
return true
|
||||
},
|
||||
|
||||
async getDocument(projectId, docId) {
|
||||
return this.docs[`${projectId}:${docId}`]
|
||||
},
|
||||
|
||||
async getDocumentController(req, res, next) {
|
||||
try {
|
||||
const doc = await this.getDocument(
|
||||
req.params.project_id,
|
||||
req.params.doc_id
|
||||
)
|
||||
if (doc != null) {
|
||||
return res.send(JSON.stringify(doc))
|
||||
} else {
|
||||
return res.sendStatus(404)
|
||||
}
|
||||
} catch (error) {
|
||||
return res.sendStatus(500)
|
||||
}
|
||||
},
|
||||
|
||||
async setDocumentController(req, res, next) {
|
||||
try {
|
||||
const ok = await this.setDocument(
|
||||
req.params.project_id,
|
||||
req.params.doc_id,
|
||||
req.body.lines,
|
||||
req.body.version,
|
||||
req.body.ranges,
|
||||
req.body.lastUpdatedAt,
|
||||
req.body.lastUpdatedBy
|
||||
)
|
||||
if (!ok) {
|
||||
return res.sendStatus(404)
|
||||
}
|
||||
return res.json({ rev: '123' })
|
||||
} catch (error) {
|
||||
return res.sendStatus(500)
|
||||
}
|
||||
},
|
||||
|
||||
run() {
|
||||
app.use((req, res, next) => {
|
||||
const credentials = basicAuth(req)
|
||||
if (
|
||||
!credentials ||
|
||||
!Settings.apis.web.user ||
|
||||
credentials.name !== Settings.apis.web.user ||
|
||||
!Settings.apis.web.pass ||
|
||||
!tsscmp(credentials.pass, Settings.apis.web.pass)
|
||||
) {
|
||||
return res.sendStatus(401)
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
})
|
||||
|
||||
app.get(
|
||||
'/project/:project_id/doc/:doc_id',
|
||||
expressify(async (req, res, next) => {
|
||||
try {
|
||||
const doc = await this.getDocument(
|
||||
req.params.project_id,
|
||||
req.params.doc_id
|
||||
)
|
||||
if (doc != null) {
|
||||
return res.send(JSON.stringify(doc))
|
||||
} else {
|
||||
return res.sendStatus(404)
|
||||
}
|
||||
} catch (error) {
|
||||
return res.sendStatus(500)
|
||||
}
|
||||
await this.getDocumentController(req, res, next)
|
||||
})
|
||||
)
|
||||
|
||||
@@ -71,20 +115,7 @@ module.exports = MockWebApi = {
|
||||
'/project/:project_id/doc/:doc_id',
|
||||
bodyParser.json({ limit: MAX_REQUEST_SIZE }),
|
||||
expressify(async (req, res, next) => {
|
||||
try {
|
||||
await MockWebApi.setDocument(
|
||||
req.params.project_id,
|
||||
req.params.doc_id,
|
||||
req.body.lines,
|
||||
req.body.version,
|
||||
req.body.ranges,
|
||||
req.body.lastUpdatedAt,
|
||||
req.body.lastUpdatedBy
|
||||
)
|
||||
return res.json({ rev: '123' })
|
||||
} catch (error) {
|
||||
return res.sendStatus(500)
|
||||
}
|
||||
await this.setDocumentController(req, res, next)
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ describe('HistoryManager', function () {
|
||||
beforeEach(function () {
|
||||
this.HistoryManager = SandboxedModule.require(modulePath, {
|
||||
requires: {
|
||||
request: (this.request = {}),
|
||||
'@overleaf/fetch-utils': (this.fetchUtils = {
|
||||
fetchNothing: sinon.stub().resolves(),
|
||||
}),
|
||||
|
||||
@@ -1,524 +0,0 @@
|
||||
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 () {
|
||||
this.request = sinon.stub()
|
||||
this.request.defaults = () => this.request
|
||||
this.Metrics = {
|
||||
Timer: class Timer {},
|
||||
inc: sinon.stub(),
|
||||
}
|
||||
this.Metrics.Timer.prototype.done = sinon.stub()
|
||||
this.Settings = {}
|
||||
|
||||
this.PersistenceManager = SandboxedModule.require(modulePath, {
|
||||
requires: {
|
||||
requestretry: this.request,
|
||||
'@overleaf/settings': this.Settings,
|
||||
'./Metrics': this.Metrics,
|
||||
'./Errors': Errors,
|
||||
},
|
||||
})
|
||||
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'
|
||||
this.historyRangesSupport = false
|
||||
this.Settings.apis = {
|
||||
web: {
|
||||
url: (this.url = 'www.example.com'),
|
||||
user: (this.user = 'overleaf'),
|
||||
pass: (this.pass = 'password'),
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
describe('getDoc', function () {
|
||||
beforeEach(function () {
|
||||
this.webResponse = {
|
||||
lines: this.lines,
|
||||
version: this.version,
|
||||
ranges: this.ranges,
|
||||
pathname: this.pathname,
|
||||
projectHistoryId: this.projectHistoryId,
|
||||
historyRangesSupport: this.historyRangesSupport,
|
||||
}
|
||||
})
|
||||
|
||||
describe('with a successful response from the web api', function () {
|
||||
beforeEach(function () {
|
||||
this.request.callsArgWith(
|
||||
1,
|
||||
null,
|
||||
{ statusCode: 200 },
|
||||
JSON.stringify(this.webResponse)
|
||||
)
|
||||
this.PersistenceManager.getDoc(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
this.callback
|
||||
)
|
||||
})
|
||||
|
||||
it('should call the web api', function () {
|
||||
this.request
|
||||
.calledWith({
|
||||
url: `${this.url}/project/${this.project_id}/doc/${this.doc_id}`,
|
||||
method: 'GET',
|
||||
headers: {
|
||||
accept: 'application/json',
|
||||
},
|
||||
auth: {
|
||||
user: this.user,
|
||||
pass: this.pass,
|
||||
sendImmediately: true,
|
||||
},
|
||||
jar: false,
|
||||
timeout: 5000,
|
||||
})
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should call the callback with the doc lines, version and ranges', function () {
|
||||
this.callback
|
||||
.calledWith(
|
||||
null,
|
||||
this.lines,
|
||||
this.version,
|
||||
this.ranges,
|
||||
this.pathname,
|
||||
this.projectHistoryId,
|
||||
this.historyRangesSupport
|
||||
)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should time the execution', function () {
|
||||
this.Metrics.Timer.prototype.done.called.should.equal(true)
|
||||
})
|
||||
|
||||
it('should increment the metric', function () {
|
||||
this.Metrics.inc
|
||||
.calledWith('getDoc', 1, { status: 200 })
|
||||
.should.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('with the peek option', function () {
|
||||
beforeEach(function () {
|
||||
this.request.yields(
|
||||
null,
|
||||
{ statusCode: 200 },
|
||||
JSON.stringify(this.webResponse)
|
||||
)
|
||||
this.PersistenceManager.getDoc(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
{ peek: true },
|
||||
this.callback
|
||||
)
|
||||
})
|
||||
|
||||
it('should call the web api with a peek param', function () {
|
||||
this.request
|
||||
.calledWith({
|
||||
url: `${this.url}/project/${this.project_id}/doc/${this.doc_id}`,
|
||||
qs: { peek: 'true' },
|
||||
method: 'GET',
|
||||
headers: {
|
||||
accept: 'application/json',
|
||||
},
|
||||
auth: {
|
||||
user: this.user,
|
||||
pass: this.pass,
|
||||
sendImmediately: true,
|
||||
},
|
||||
jar: false,
|
||||
timeout: 5000,
|
||||
})
|
||||
.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)
|
||||
this.PersistenceManager.getDoc(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
this.callback
|
||||
)
|
||||
})
|
||||
|
||||
it('should return a generic connection error', function () {
|
||||
this.callback
|
||||
.calledWith(
|
||||
sinon.match
|
||||
.instanceOf(Error)
|
||||
.and(sinon.match.has('message', 'error connecting to web API'))
|
||||
)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should time the execution', function () {
|
||||
this.Metrics.Timer.prototype.done.called.should.equal(true)
|
||||
})
|
||||
|
||||
it('should increment the metric', function () {
|
||||
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 }, '')
|
||||
this.PersistenceManager.getDoc(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
this.callback
|
||||
)
|
||||
})
|
||||
|
||||
it('should return a NotFoundError', function () {
|
||||
this.callback
|
||||
.calledWith(sinon.match.instanceOf(Errors.NotFoundError))
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should time the execution', function () {
|
||||
this.Metrics.Timer.prototype.done.called.should.equal(true)
|
||||
})
|
||||
|
||||
it('should increment the metric', function () {
|
||||
this.Metrics.inc
|
||||
.calledWith('getDoc', 1, { status: 404 })
|
||||
.should.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the request returns 413', function () {
|
||||
beforeEach(function () {
|
||||
this.request.callsArgWith(1, null, { statusCode: 413 }, '')
|
||||
this.PersistenceManager.getDoc(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
this.callback
|
||||
)
|
||||
})
|
||||
|
||||
it('should return a FileTooLargeError', function () {
|
||||
this.callback
|
||||
.calledWith(sinon.match.instanceOf(Errors.FileTooLargeError))
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should time the execution', function () {
|
||||
this.Metrics.Timer.prototype.done.called.should.equal(true)
|
||||
})
|
||||
|
||||
it('should increment the metric', function () {
|
||||
this.Metrics.inc
|
||||
.calledWith('getDoc', 1, { status: 413 })
|
||||
.should.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the request returns an error status code', function () {
|
||||
beforeEach(function () {
|
||||
this.request.callsArgWith(1, null, { statusCode: 500 }, '')
|
||||
this.PersistenceManager.getDoc(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
this.callback
|
||||
)
|
||||
})
|
||||
|
||||
it('should return an error', function () {
|
||||
this.callback
|
||||
.calledWith(sinon.match.instanceOf(Error))
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should time the execution', function () {
|
||||
this.Metrics.Timer.prototype.done.called.should.equal(true)
|
||||
})
|
||||
|
||||
it('should increment the metric', function () {
|
||||
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)
|
||||
)
|
||||
this.PersistenceManager.getDoc(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
this.callback
|
||||
)
|
||||
})
|
||||
|
||||
it('should return and error', function () {
|
||||
this.callback
|
||||
.calledWith(sinon.match.instanceOf(Error))
|
||||
.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)
|
||||
)
|
||||
this.PersistenceManager.getDoc(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
this.callback
|
||||
)
|
||||
})
|
||||
|
||||
it('should return and error', function () {
|
||||
this.callback
|
||||
.calledWith(sinon.match.instanceOf(Error))
|
||||
.should.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
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)
|
||||
)
|
||||
this.PersistenceManager.getDoc(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
this.callback
|
||||
)
|
||||
})
|
||||
|
||||
it('should return and error', function () {
|
||||
this.callback
|
||||
.calledWith(sinon.match.instanceOf(Error))
|
||||
.should.equal(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('setDoc', function () {
|
||||
describe('with a successful response from the web api', function () {
|
||||
beforeEach(function () {
|
||||
this.request.callsArgWith(1, null, { statusCode: 200 })
|
||||
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 () {
|
||||
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,
|
||||
lastUpdatedBy: this.lastUpdatedBy,
|
||||
},
|
||||
method: 'POST',
|
||||
auth: {
|
||||
user: this.user,
|
||||
pass: this.pass,
|
||||
sendImmediately: true,
|
||||
},
|
||||
jar: false,
|
||||
timeout: 5000,
|
||||
})
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should call the callback without error', function () {
|
||||
this.callback.calledWith(null).should.equal(true)
|
||||
})
|
||||
|
||||
it('should time the execution', function () {
|
||||
this.Metrics.Timer.prototype.done.called.should.equal(true)
|
||||
})
|
||||
|
||||
it('should increment the metric', function () {
|
||||
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)
|
||||
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 generic connection error', function () {
|
||||
this.callback
|
||||
.calledWith(
|
||||
sinon.match
|
||||
.instanceOf(Error)
|
||||
.and(sinon.match.has('message', 'error connecting to web API'))
|
||||
)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should time the execution', function () {
|
||||
this.Metrics.Timer.prototype.done.called.should.equal(true)
|
||||
})
|
||||
|
||||
it('should increment the metric', function () {
|
||||
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 }, '')
|
||||
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 () {
|
||||
this.callback
|
||||
.calledWith(sinon.match.instanceOf(Errors.NotFoundError))
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should time the execution', function () {
|
||||
this.Metrics.Timer.prototype.done.called.should.equal(true)
|
||||
})
|
||||
|
||||
it('should increment the metric', function () {
|
||||
this.Metrics.inc
|
||||
.calledWith('setDoc', 1, { status: 404 })
|
||||
.should.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the request returns 413', function () {
|
||||
beforeEach(function () {
|
||||
this.request.callsArgWith(1, null, { statusCode: 413 }, '')
|
||||
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 FileTooLargeError', function () {
|
||||
this.callback
|
||||
.calledWith(sinon.match.instanceOf(Errors.FileTooLargeError))
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should time the execution', function () {
|
||||
this.Metrics.Timer.prototype.done.called.should.equal(true)
|
||||
})
|
||||
|
||||
it('should increment the metric', function () {
|
||||
this.Metrics.inc
|
||||
.calledWith('setDoc', 1, { status: 413 })
|
||||
.should.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the request returns an error status code', function () {
|
||||
beforeEach(function () {
|
||||
this.request.callsArgWith(1, null, { statusCode: 500 }, '')
|
||||
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 () {
|
||||
this.callback
|
||||
.calledWith(sinon.match.instanceOf(Error))
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should time the execution', function () {
|
||||
this.Metrics.Timer.prototype.done.called.should.equal(true)
|
||||
})
|
||||
|
||||
it('should increment the metric', function () {
|
||||
this.Metrics.inc
|
||||
.calledWith('setDoc', 1, { status: 500 })
|
||||
.should.equal(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user