[project-history] report a resync that is still pending after a flush (#36122)

GitOrigin-RevId: ccd4390048c09f732531d2e02a40336fce88a952
This commit is contained in:
Jakob Ackermann
2026-09-17 11:45:55 +00:00
committed by Copybot
parent 9be1b4edb4
commit eb36edac6d
19 changed files with 588 additions and 151 deletions
@@ -214,7 +214,6 @@ describe('ClsiManager', function () {
getChangesWithHistoryId: sinon
.stub()
.resolves({ changes: [], hasMore: false }),
ensureNoResyncPending: sinon.stub().resolves(),
},
getFilestoreBlobURL: sinon.stub().callsFake((historyId, hash) => {
if (hash === GLOBAL_BLOB_HASH) {
@@ -546,6 +545,14 @@ describe('ClsiManager', function () {
)
}
function makeResyncPendingError() {
return new RequestFailedError(
'http://project-history/project/x/flush',
{ method: 'POST' },
{ status: 422 }
)
}
function sendHistoryRequest(ctx, options = {}) {
return ctx.ClsiManager.promises.sendRequest(
null,
@@ -692,16 +699,38 @@ describe('ClsiManager', function () {
})
})
describe('when a resync is pending', function () {
describe('when the flush reports a pending resync then succeeds', function () {
beforeEach(async function (ctx) {
ctx.HistoryManager.promises.ensureNoResyncPending.rejects(
new Errors.HistoryResyncPendingError(
'broken history with pending resync'
)
ctx.HistoryManager.promises.flushProject
.onFirstCall()
.rejects(makeResyncPendingError())
.onSecondCall()
.resolves()
ctx.result = await sendHistoryRequest(ctx, { baseHistoryVersion: -1 })
})
it('should compile from history without downgrading', function (ctx) {
expect(ctx.HistoryManager.promises.flushProject.callCount).to.equal(2)
expect(ctx.HistoryManager.promises.getLatestHistoryWithHistoryId).to
.have.been.called
expect(ctx.DocumentUpdaterHandler.promises.getProjectDocsIfMatch).to
.not.have.been.called
expect(ctx.result.status).to.equal('success')
})
})
describe('when the flush reports a pending resync', function () {
beforeEach(async function (ctx) {
ctx.HistoryManager.promises.flushProject.rejects(
makeResyncPendingError()
)
ctx.result = await sendHistoryRequest(ctx, { baseHistoryVersion: -1 })
})
it('should retry the flush, the resync updates may arrive', function (ctx) {
expect(ctx.HistoryManager.promises.flushProject.callCount).to.equal(3)
})
it('should fall back to a legacy compile', function (ctx) {
expect(
ctx.DocumentUpdaterHandler.promises.getProjectDocsIfMatch
@@ -200,27 +200,6 @@ describe('HistoryManager', function () {
})
})
describe('ensureNoResyncPending', function () {
const projectId = 'project-123'
it('should resolve when no resync is pending', async function (ctx) {
ctx.FetchUtils.fetchJson.resolves({ resyncPending: false })
await ctx.HistoryManager.promises.ensureNoResyncPending(projectId)
ctx.FetchUtils.fetchJson.should.have.been.calledWithMatch(
`${ctx.settings.apis.project_history.url}/project/${projectId}/resync-pending`
)
})
it('should throw a HistoryResyncPendingError when a resync is pending', async function (ctx) {
ctx.FetchUtils.fetchJson.resolves({ resyncPending: true })
const error = await ctx.HistoryManager.promises
.ensureNoResyncPending(projectId)
.catch(err => err)
expect(error).to.be.an('error')
expect(error.name).to.equal('HistoryResyncPendingError')
})
})
describe('injectUserDetails', function () {
beforeEach(function (ctx) {
ctx.user1 = {