[web] make double compile test parameters configurable via env vars (#33406)

* [web] make double compile test parameters configurable via env vars

* [k8s] web: enable double compile test for free compiles on n4 instances

GitOrigin-RevId: 3a5cb8ed6d044fcf3f4c0d2b9d252326bac48511
This commit is contained in:
Jakob Ackermann
2026-05-06 09:22:41 +02:00
committed by Copybot
parent c63d048dd3
commit d97a659f92
2 changed files with 113 additions and 20 deletions

View File

@@ -82,23 +82,25 @@ async function clearBaseHistoryVersion(projectId, userId) {
await rclient.del(_baseHistoryVersionKey(projectId, userId))
}
function getNewCompileBackendClass(projectId, compileBackendClass) {
// Sample x% of projects to move up one bracket.
if (
SplitTestHandler.getPercentile(projectId, 'double-compile', 'release') >=
Settings.apis.clsi_new.sample
) {
return null
function getDoubleCompilePercentile(projectId) {
return SplitTestHandler.getPercentile(projectId, 'double-compile', 'release')
}
function getNewCompileBackendClass(projectId, compileBackendClass) {
let cfg
switch (compileBackendClass) {
case 'c3d':
return 'n4'
cfg = Settings.apis.clsi_new.doubleCompileFree
break
case 'c4d':
return 'n4'
cfg = Settings.apis.clsi_new.doubleCompilePremium
break
default:
throw new Error('unknown ?compileBackendClass')
}
if (!cfg.backendClass || !cfg.sample) return null
if (getDoubleCompilePercentile(projectId) >= cfg.sample) return null
return cfg.backendClass
}
/**

View File

@@ -170,7 +170,14 @@ describe('ClsiManager', function () {
submissionBackendClass: 'c3d',
},
clsi_new: {
doubleCompileFree: {
sample: 100,
backendClass: 'n4',
},
doubleCompilePremium: {
sample: 100,
backendClass: 'n4d',
},
},
},
enablePdfCaching: true,
@@ -1033,9 +1040,93 @@ describe('ClsiManager', function () {
})
})
describe('when a new backend is configured', function () {
describe('when a new backend is configured (free)', function () {
beforeEach(async function (ctx) {
ctx.Settings.apis.clsi_new = { url: 'https://compiles.somewhere.test' }
ctx.Settings.apis.clsi_new.url = 'https://compiles.somewhere.test'
await ctx.ClsiManager.promises.sendRequest(
ctx.project._id,
ctx.user_id,
{
compileBackendClass: 'c3d',
compileGroup: 'standard',
}
)
// wait for the background task to finish
await setTimeout(0)
})
it('makes a request to the new backend', function (ctx) {
expect(ctx.FetchUtils.fetchStringWithResponse).to.have.been.calledTwice
expect(ctx.FetchUtils.fetchStringWithResponse).to.have.been.calledWith(
sinon.match(
url =>
url.host === CLSI_HOST &&
url.pathname ===
`/project/${ctx.project._id}/user/${ctx.user_id}/compile` &&
url.searchParams.get('compileBackendClass') === 'c3d' &&
url.searchParams.get('compileGroup') === 'standard'
)
)
expect(ctx.FetchUtils.fetchStringWithResponse).to.have.been.calledWith(
sinon.match(
url =>
url.toString() ===
`${ctx.Settings.apis.clsi_new.url}/project/${ctx.project._id}/user/${ctx.user_id}/compile?compileBackendClass=n4&compileGroup=standard`
)
)
})
it('should record an event', function (ctx) {
expect(
ctx.AnalyticsManager.recordEventForUserInBackground
).to.have.been.calledWith(ctx.user_id, 'double-compile-result', {
projectId: 'project-id',
compileBackendClass: 'c3d',
newCompileBackendClass: 'n4',
status: 'success',
compileTime: 1337,
newCompileTime: 1337,
clsiServerId: 'newserver',
newClsiServerId: 'clsi-server-id',
pdfSize: 42,
newPdfSize: 42,
})
})
})
describe('when a new backend is configured with low sample', function () {
beforeEach(async function (ctx) {
ctx.Settings.apis.clsi_new.url = 'https://compiles.somewhere.test'
ctx.Settings.apis.clsi_new.doubleCompileFree.sample = 0
await ctx.ClsiManager.promises.sendRequest(
ctx.project._id,
ctx.user_id,
{
compileBackendClass: 'c3d',
compileGroup: 'standard',
}
)
// wait for the background task to finish
await setTimeout(0)
})
it('does not make a request to the new backend', function (ctx) {
expect(ctx.FetchUtils.fetchStringWithResponse).to.have.been.calledOnce
expect(ctx.FetchUtils.fetchStringWithResponse).to.have.been.calledWith(
sinon.match(
url =>
url.host === CLSI_HOST &&
url.pathname ===
`/project/${ctx.project._id}/user/${ctx.user_id}/compile` &&
url.searchParams.get('compileBackendClass') === 'c3d' &&
url.searchParams.get('compileGroup') === 'standard'
)
)
})
})
describe('when a new backend is configured (premium)', function () {
beforeEach(async function (ctx) {
ctx.Settings.apis.clsi_new.url = 'https://compiles.somewhere.test'
await ctx.ClsiManager.promises.sendRequest(
ctx.project._id,
ctx.user_id,
@@ -1064,7 +1155,7 @@ describe('ClsiManager', function () {
sinon.match(
url =>
url.toString() ===
`${ctx.Settings.apis.clsi_new.url}/project/${ctx.project._id}/user/${ctx.user_id}/compile?compileBackendClass=n4&compileGroup=priority`
`${ctx.Settings.apis.clsi_new.url}/project/${ctx.project._id}/user/${ctx.user_id}/compile?compileBackendClass=n4d&compileGroup=priority`
)
)
})
@@ -1074,7 +1165,7 @@ describe('ClsiManager', function () {
).to.have.been.calledWith(ctx.user_id, 'double-compile-result', {
projectId: 'project-id',
compileBackendClass: 'c4d',
newCompileBackendClass: 'n4',
newCompileBackendClass: 'n4d',
status: 'success',
compileTime: 1337,
newCompileTime: 1337,
@@ -1239,7 +1330,7 @@ describe('ClsiManager', function () {
describe('when a new backend is configured', function () {
beforeEach(async function (ctx) {
ctx.Settings.apis.clsi_new = { url: 'https://compiles.somewhere.test' }
ctx.Settings.apis.clsi_new.url = 'https://compiles.somewhere.test'
await ctx.ClsiManager.promises.deleteAuxFiles(
ctx.project._id,
ctx.user_id,
@@ -1256,7 +1347,7 @@ describe('ClsiManager', function () {
).to.have.been.calledWith(ctx.project._id, ctx.user_id, 'c4d')
expect(
ctx.ClsiCookieManager.promises.clearServerId
).to.have.been.calledWith(ctx.project._id, ctx.user_id, 'n4')
).to.have.been.calledWith(ctx.project._id, ctx.user_id, 'n4d')
})
it('should forward delete request', function (ctx) {
@@ -1278,7 +1369,7 @@ describe('ClsiManager', function () {
url.host === 'compiles.somewhere.test' &&
url.pathname ===
`/project/${ctx.project._id}/user/${ctx.user_id}` &&
url.searchParams.get('compileBackendClass') === 'n4' &&
url.searchParams.get('compileBackendClass') === 'n4d' &&
url.searchParams.get('compileGroup') === 'priority' &&
!url.searchParams.has('clsiserverid')
),
@@ -1351,7 +1442,7 @@ describe('ClsiManager', function () {
describe('when a new backend is configured', function () {
beforeEach(async function (ctx) {
ctx.Settings.apis.clsi_new = { url: 'https://compiles.somewhere.test' }
ctx.Settings.apis.clsi_new.url = 'https://compiles.somewhere.test'
await ctx.ClsiManager.promises.wordCount(
ctx.project._id,
ctx.user_id,
@@ -1375,7 +1466,7 @@ describe('ClsiManager', function () {
sinon.match(
url =>
url.toString() ===
`${ctx.Settings.apis.clsi_new.url}/project/${ctx.project._id}/user/${ctx.user_id}/wordcount?compileBackendClass=n4&compileGroup=priority&file=main.tex&image=mock-image-name`
`${ctx.Settings.apis.clsi_new.url}/project/${ctx.project._id}/user/${ctx.user_id}/wordcount?compileBackendClass=n4d&compileGroup=priority&file=main.tex&image=mock-image-name`
)
)
})