[document-updater] add safe rollback point for history-ot (#25283)

GitOrigin-RevId: d7230dd14a379a27d2c6ab03a006463a18979d06
This commit is contained in:
Jakob Ackermann
2025-05-05 15:24:25 +02:00
committed by Copybot
parent c8a410d358
commit a5e2708eae
4 changed files with 69 additions and 0 deletions

View File

@@ -212,6 +212,8 @@ app.use((error, req, res, next) => {
return res.status(422).json(error.info)
} else if (error instanceof Errors.FileTooLargeError) {
return res.sendStatus(413)
} else if (error instanceof Errors.ProjectMigratedToHistoryOTError) {
return res.status(422).send(error.message)
} else if (error.statusCode === 413) {
return res.status(413).send('request entity too large')
} else {

View File

@@ -5,6 +5,7 @@ class OpRangeNotAvailableError extends OError {}
class ProjectStateChangedError extends OError {}
class DeleteMismatchError extends OError {}
class FileTooLargeError extends OError {}
class ProjectMigratedToHistoryOTError extends OError {}
module.exports = {
NotFoundError,
@@ -12,4 +13,5 @@ module.exports = {
ProjectStateChangedError,
DeleteMismatchError,
FileTooLargeError,
ProjectMigratedToHistoryOTError,
}

View File

@@ -324,6 +324,13 @@ const RedisManager = {
} catch (e) {
return callback(e)
}
if (docLines != null && !Array.isArray(docLines)) {
return callback(
new Errors.ProjectMigratedToHistoryOTError(
'refusing to process doc that was migrated to history-ot'
)
)
}
version = parseInt(version || 0, 10)
// check doc is in requested project

View File

@@ -13,6 +13,11 @@ const { expect } = require('chai')
const MockWebApi = require('./helpers/MockWebApi')
const DocUpdaterClient = require('./helpers/DocUpdaterClient')
const DocUpdaterApp = require('./helpers/DocUpdaterApp')
const Settings = require('@overleaf/settings')
const docUpdaterRedis = require('@overleaf/redis-wrapper').createClient(
Settings.redis.documentupdater
)
const Keys = Settings.redis.documentupdater.key_schema
describe('Getting a document', function () {
before(function (done) {
@@ -109,6 +114,59 @@ describe('Getting a document', function () {
})
})
describe('when the document is migrated (history-ot)', function () {
before(function (done) {
;[this.project_id, this.doc_id] = Array.from([
DocUpdaterClient.randomId(),
DocUpdaterClient.randomId(),
])
MockWebApi.insertDoc(this.project_id, this.doc_id, {
lines: this.lines,
version: this.version,
})
DocUpdaterClient.preloadDoc(this.project_id, this.doc_id, error => {
if (error != null) {
throw error
}
sinon.spy(MockWebApi, 'getDocument')
docUpdaterRedis.set(
Keys.docLines({ doc_id: this.doc_id }),
JSON.stringify({ content: this.lines.join('\n') }),
err => {
if (err) return done(err)
DocUpdaterClient.getDoc(
this.project_id,
this.doc_id,
(error, res, body) => {
if (error) return done(error)
this.res = res
this.body = body
done()
}
)
}
)
})
})
after(function () {
MockWebApi.getDocument.restore()
})
it('should not load the document from the web API', function () {
MockWebApi.getDocument.called.should.equal(false)
})
it('should return an error', function () {
expect(this.res.statusCode).to.equal(422)
expect(this.body).to.equal(
'refusing to process doc that was migrated to history-ot'
)
})
})
describe('when the request asks for some recent ops', function () {
before(function (done) {
;[this.project_id, this.doc_id] = Array.from([