mirror of
https://github.com/overleaf/overleaf.git
synced 2024-09-16 02:52:31 -04:00
Merge pull request #10266 from overleaf/ab-split-test-no-serialization
[web] Skip mongoose object transformations for the split test cache GitOrigin-RevId: 8fb5420f6f938c0ab7cfe1ca82c107c7ce3522ca
This commit is contained in:
parent
28c1cc2ea9
commit
10c6bd20ab
6 changed files with 57 additions and 46 deletions
|
@ -1,5 +1,4 @@
|
||||||
const SplitTestManager = require('./SplitTestManager')
|
const SplitTestManager = require('./SplitTestManager')
|
||||||
const { SplitTest } = require('../../models/SplitTest')
|
|
||||||
const { CacheLoader } = require('cache-flow')
|
const { CacheLoader } = require('cache-flow')
|
||||||
|
|
||||||
class SplitTestCache extends CacheLoader {
|
class SplitTestCache extends CacheLoader {
|
||||||
|
@ -10,18 +9,19 @@ class SplitTestCache extends CacheLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
async load(name) {
|
async load(name) {
|
||||||
return await SplitTestManager.getSplitTest({
|
const splitTest = await SplitTestManager.getSplitTest({
|
||||||
name,
|
name,
|
||||||
archived: { $ne: true },
|
archived: { $ne: true },
|
||||||
})
|
})
|
||||||
|
return splitTest?.toObject()
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize(value) {
|
serialize(value) {
|
||||||
return value ? value.toObject() : undefined
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
deserialize(value) {
|
deserialize(value) {
|
||||||
return new SplitTest(value)
|
return value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ const { SplitTest } = require('../../models/SplitTest')
|
||||||
const UserAnalyticsIdCache = require('../Analytics/UserAnalyticsIdCache')
|
const UserAnalyticsIdCache = require('../Analytics/UserAnalyticsIdCache')
|
||||||
const { getAnalyticsIdFromMongoUser } = require('../Analytics/AnalyticsHelper')
|
const { getAnalyticsIdFromMongoUser } = require('../Analytics/AnalyticsHelper')
|
||||||
const Features = require('../../infrastructure/Features')
|
const Features = require('../../infrastructure/Features')
|
||||||
|
const SplitTestUtils = require('./SplitTestUtils')
|
||||||
|
|
||||||
const DEFAULT_VARIANT = 'default'
|
const DEFAULT_VARIANT = 'default'
|
||||||
const ALPHA_PHASE = 'alpha'
|
const ALPHA_PHASE = 'alpha'
|
||||||
|
@ -191,7 +192,7 @@ async function getActiveAssignmentsForUser(userId) {
|
||||||
*/
|
*/
|
||||||
async function _getVariantNames(splitTestName) {
|
async function _getVariantNames(splitTestName) {
|
||||||
const splitTest = await SplitTestCache.get(splitTestName)
|
const splitTest = await SplitTestCache.get(splitTestName)
|
||||||
const currentVersion = splitTest?.getCurrentVersion()
|
const currentVersion = SplitTestUtils.getCurrentVersion(splitTest)
|
||||||
if (currentVersion?.active) {
|
if (currentVersion?.active) {
|
||||||
return currentVersion.variants.map(v => v.name).concat([DEFAULT_VARIANT])
|
return currentVersion.variants.map(v => v.name).concat([DEFAULT_VARIANT])
|
||||||
} else {
|
} else {
|
||||||
|
@ -208,7 +209,7 @@ async function _getAssignment(
|
||||||
}
|
}
|
||||||
|
|
||||||
const splitTest = await SplitTestCache.get(splitTestName)
|
const splitTest = await SplitTestCache.get(splitTestName)
|
||||||
const currentVersion = splitTest?.getCurrentVersion()
|
const currentVersion = SplitTestUtils.getCurrentVersion(splitTest)
|
||||||
if (!currentVersion?.active) {
|
if (!currentVersion?.active) {
|
||||||
return DEFAULT_ASSIGNMENT
|
return DEFAULT_ASSIGNMENT
|
||||||
}
|
}
|
||||||
|
@ -251,7 +252,7 @@ async function _getAssignment(
|
||||||
}
|
}
|
||||||
|
|
||||||
async function _getAssignmentMetadata(analyticsId, user, splitTest) {
|
async function _getAssignmentMetadata(analyticsId, user, splitTest) {
|
||||||
const currentVersion = splitTest.getCurrentVersion()
|
const currentVersion = SplitTestUtils.getCurrentVersion(splitTest)
|
||||||
const phase = currentVersion.phase
|
const phase = currentVersion.phase
|
||||||
if (
|
if (
|
||||||
(phase === ALPHA_PHASE && !user?.alphaProgram) ||
|
(phase === ALPHA_PHASE && !user?.alphaProgram) ||
|
||||||
|
@ -398,10 +399,10 @@ async function _getUser(id) {
|
||||||
async function _loadSplitTestInfoInLocals(locals, splitTestName) {
|
async function _loadSplitTestInfoInLocals(locals, splitTestName) {
|
||||||
const splitTest = await SplitTestCache.get(splitTestName)
|
const splitTest = await SplitTestCache.get(splitTestName)
|
||||||
if (splitTest) {
|
if (splitTest) {
|
||||||
const phase = splitTest.getCurrentVersion().phase
|
const phase = SplitTestUtils.getCurrentVersion(splitTest).phase
|
||||||
LocalsHelper.setSplitTestInfo(locals, splitTestName, {
|
LocalsHelper.setSplitTestInfo(locals, splitTestName, {
|
||||||
phase,
|
phase,
|
||||||
badgeInfo: splitTest.toObject().badgeInfo?.[phase],
|
badgeInfo: splitTest.badgeInfo?.[phase],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
const { SplitTest } = require('../../models/SplitTest')
|
const { SplitTest } = require('../../models/SplitTest')
|
||||||
|
const SplitTestUtils = require('./SplitTestUtils')
|
||||||
const OError = require('@overleaf/o-error')
|
const OError = require('@overleaf/o-error')
|
||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
|
|
||||||
|
@ -89,7 +90,7 @@ async function updateSplitTestConfig(name, configuration) {
|
||||||
if (splitTest.archived) {
|
if (splitTest.archived) {
|
||||||
throw new OError('Cannot update an archived split test', { name })
|
throw new OError('Cannot update an archived split test', { name })
|
||||||
}
|
}
|
||||||
const lastVersion = splitTest.getCurrentVersion().toObject()
|
const lastVersion = SplitTestUtils.getCurrentVersion(splitTest).toObject()
|
||||||
if (configuration.phase !== lastVersion.phase) {
|
if (configuration.phase !== lastVersion.phase) {
|
||||||
throw new OError(
|
throw new OError(
|
||||||
`Cannot update with different phase - use /switch-to-next-phase endpoint instead`
|
`Cannot update with different phase - use /switch-to-next-phase endpoint instead`
|
||||||
|
@ -145,7 +146,7 @@ async function switchToNextPhase(name) {
|
||||||
name,
|
name,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const lastVersionCopy = splitTest.getCurrentVersion().toObject()
|
const lastVersionCopy = SplitTestUtils.getCurrentVersion(splitTest).toObject()
|
||||||
lastVersionCopy.versionNumber++
|
lastVersionCopy.versionNumber++
|
||||||
if (lastVersionCopy.phase === ALPHA_PHASE) {
|
if (lastVersionCopy.phase === ALPHA_PHASE) {
|
||||||
lastVersionCopy.phase = BETA_PHASE
|
lastVersionCopy.phase = BETA_PHASE
|
||||||
|
@ -189,13 +190,13 @@ async function revertToPreviousVersion(name, versionNumber) {
|
||||||
`Cannot revert split test with ID '${name}' to previous version: split test must have at least 2 versions`
|
`Cannot revert split test with ID '${name}' to previous version: split test must have at least 2 versions`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
const previousVersion = splitTest.getVersion(versionNumber)
|
const previousVersion = SplitTestUtils.getVersion(splitTest, versionNumber)
|
||||||
if (!previousVersion) {
|
if (!previousVersion) {
|
||||||
throw new OError(
|
throw new OError(
|
||||||
`Cannot revert split test with ID '${name}' to version number ${versionNumber}: version not found`
|
`Cannot revert split test with ID '${name}' to version number ${versionNumber}: version not found`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
const lastVersion = splitTest.getCurrentVersion()
|
const lastVersion = SplitTestUtils.getCurrentVersion(splitTest)
|
||||||
if (
|
if (
|
||||||
lastVersion.phase === RELEASE_PHASE &&
|
lastVersion.phase === RELEASE_PHASE &&
|
||||||
previousVersion.phase !== RELEASE_PHASE
|
previousVersion.phase !== RELEASE_PHASE
|
||||||
|
@ -217,7 +218,8 @@ async function archive(name) {
|
||||||
throw new OError(`Split test with ID '${name}' is already archived`)
|
throw new OError(`Split test with ID '${name}' is already archived`)
|
||||||
}
|
}
|
||||||
splitTest.archived = true
|
splitTest.archived = true
|
||||||
const previousVersionCopy = splitTest.getCurrentVersion().toObject()
|
const previousVersionCopy =
|
||||||
|
SplitTestUtils.getCurrentVersion(splitTest).toObject()
|
||||||
previousVersionCopy.versionNumber += 1
|
previousVersionCopy.versionNumber += 1
|
||||||
previousVersionCopy.active = false
|
previousVersionCopy.active = false
|
||||||
splitTest.versions.push(previousVersionCopy)
|
splitTest.versions.push(previousVersionCopy)
|
||||||
|
|
20
services/web/app/src/Features/SplitTests/SplitTestUtils.js
Normal file
20
services/web/app/src/Features/SplitTests/SplitTestUtils.js
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
const _ = require('lodash')
|
||||||
|
|
||||||
|
function getCurrentVersion(splitTest) {
|
||||||
|
if (splitTest?.versions?.length > 0) {
|
||||||
|
return _.maxBy(splitTest.versions, 'versionNumber')
|
||||||
|
} else {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getVersion(splitTest, versionNumber) {
|
||||||
|
return _.find(splitTest.versions || [], {
|
||||||
|
versionNumber,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getCurrentVersion,
|
||||||
|
getVersion,
|
||||||
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
const mongoose = require('../infrastructure/Mongoose')
|
const mongoose = require('../infrastructure/Mongoose')
|
||||||
const { Schema } = mongoose
|
const { Schema } = mongoose
|
||||||
const _ = require('lodash')
|
|
||||||
|
|
||||||
const MIN_NAME_LENGTH = 3
|
const MIN_NAME_LENGTH = 3
|
||||||
const MAX_NAME_LENGTH = 200
|
const MAX_NAME_LENGTH = 200
|
||||||
|
@ -147,20 +146,6 @@ const SplitTestSchema = new Schema({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
SplitTestSchema.methods.getCurrentVersion = function () {
|
|
||||||
if (this.versions && this.versions.length > 0) {
|
|
||||||
return _.maxBy(this.versions, 'versionNumber')
|
|
||||||
} else {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SplitTestSchema.methods.getVersion = function (versionNumber) {
|
|
||||||
return _.find(this.versions || [], {
|
|
||||||
versionNumber,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
SplitTest: mongoose.model('SplitTest', SplitTestSchema),
|
SplitTest: mongoose.model('SplitTest', SplitTestSchema),
|
||||||
SplitTestSchema,
|
SplitTestSchema,
|
||||||
|
|
|
@ -176,28 +176,31 @@ describe('SplitTestHandler', function () {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
function makeSplitTest(name, opts = {}) {
|
function makeSplitTest(
|
||||||
const {
|
name,
|
||||||
|
{
|
||||||
active = true,
|
active = true,
|
||||||
analyticsEnabled = active,
|
analyticsEnabled = active,
|
||||||
phase = 'release',
|
phase = 'release',
|
||||||
versionNumber = 1,
|
versionNumber = 1,
|
||||||
} = opts
|
} = {}
|
||||||
|
) {
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
getCurrentVersion: sinon.stub().returns({
|
versions: [
|
||||||
active,
|
{
|
||||||
analyticsEnabled,
|
active,
|
||||||
phase,
|
analyticsEnabled,
|
||||||
versionNumber,
|
phase,
|
||||||
variants: [
|
versionNumber,
|
||||||
{
|
variants: [
|
||||||
name: 'variant-1',
|
{
|
||||||
rolloutPercent: 100,
|
name: 'variant-1',
|
||||||
rolloutStripes: [{ start: 0, end: 100 }],
|
rolloutPercent: 100,
|
||||||
},
|
rolloutStripes: [{ start: 0, end: 100 }],
|
||||||
],
|
},
|
||||||
}),
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue