mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #12473 from overleaf/ab-server-pro-split-test-overrides
[web] Add split test overrides through settings for non-SaaS env GitOrigin-RevId: 82cb6a573a992e730107f6287e7804cfe0f04aa5
This commit is contained in:
parent
17109393c5
commit
e780a09a15
2 changed files with 102 additions and 6 deletions
|
@ -11,6 +11,7 @@ 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 SplitTestUtils = require('./SplitTestUtils')
|
||||||
|
const Settings = require('@overleaf/settings')
|
||||||
|
|
||||||
const DEFAULT_VARIANT = 'default'
|
const DEFAULT_VARIANT = 'default'
|
||||||
const ALPHA_PHASE = 'alpha'
|
const ALPHA_PHASE = 'alpha'
|
||||||
|
@ -49,7 +50,7 @@ const DEFAULT_ASSIGNMENT = {
|
||||||
*/
|
*/
|
||||||
async function getAssignment(req, res, splitTestName, { sync = false } = {}) {
|
async function getAssignment(req, res, splitTestName, { sync = false } = {}) {
|
||||||
if (!Features.hasFeature('saas')) {
|
if (!Features.hasFeature('saas')) {
|
||||||
return DEFAULT_ASSIGNMENT
|
return _getNonSaasAssignment(splitTestName)
|
||||||
}
|
}
|
||||||
|
|
||||||
const query = req.query || {}
|
const query = req.query || {}
|
||||||
|
@ -107,7 +108,7 @@ async function getAssignmentForUser(
|
||||||
{ sync = false } = {}
|
{ sync = false } = {}
|
||||||
) {
|
) {
|
||||||
if (!Features.hasFeature('saas')) {
|
if (!Features.hasFeature('saas')) {
|
||||||
return DEFAULT_ASSIGNMENT
|
return _getNonSaasAssignment(splitTestName)
|
||||||
}
|
}
|
||||||
|
|
||||||
const analyticsId = await UserAnalyticsIdCache.get(userId)
|
const analyticsId = await UserAnalyticsIdCache.get(userId)
|
||||||
|
@ -131,7 +132,7 @@ async function getAssignmentForMongoUser(
|
||||||
{ sync = false } = {}
|
{ sync = false } = {}
|
||||||
) {
|
) {
|
||||||
if (!Features.hasFeature('saas')) {
|
if (!Features.hasFeature('saas')) {
|
||||||
return DEFAULT_ASSIGNMENT
|
return _getNonSaasAssignment(splitTestName)
|
||||||
}
|
}
|
||||||
|
|
||||||
return _getAssignment(splitTestName, {
|
return _getAssignment(splitTestName, {
|
||||||
|
@ -403,6 +404,18 @@ async function _loadSplitTestInfoInLocals(locals, splitTestName) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _getNonSaasAssignment(splitTestName) {
|
||||||
|
if (Settings.splitTestOverrides?.[splitTestName]) {
|
||||||
|
return {
|
||||||
|
variant: Settings.splitTestOverrides?.[splitTestName],
|
||||||
|
analytics: {
|
||||||
|
segmentation: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DEFAULT_ASSIGNMENT
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getPercentile,
|
getPercentile,
|
||||||
getAssignment: callbackify(getAssignment),
|
getAssignment: callbackify(getAssignment),
|
||||||
|
|
|
@ -2,7 +2,9 @@ const Path = require('path')
|
||||||
const SandboxedModule = require('sandboxed-module')
|
const SandboxedModule = require('sandboxed-module')
|
||||||
const sinon = require('sinon')
|
const sinon = require('sinon')
|
||||||
const { ObjectId } = require('mongodb')
|
const { ObjectId } = require('mongodb')
|
||||||
const { expect } = require('chai')
|
const { assert, expect } = require('chai')
|
||||||
|
const MockRequest = require('../helpers/MockRequest')
|
||||||
|
const MockResponse = require('../helpers/MockResponse')
|
||||||
|
|
||||||
const MODULE_PATH = Path.join(
|
const MODULE_PATH = Path.join(
|
||||||
__dirname,
|
__dirname,
|
||||||
|
@ -39,6 +41,17 @@ describe('SplitTestHandler', function () {
|
||||||
for (const splitTest of this.splitTests) {
|
for (const splitTest of this.splitTests) {
|
||||||
this.SplitTestCache.get.withArgs(splitTest.name).resolves(splitTest)
|
this.SplitTestCache.get.withArgs(splitTest.name).resolves(splitTest)
|
||||||
}
|
}
|
||||||
|
this.Settings = {
|
||||||
|
moduleImportSequence: [],
|
||||||
|
overleaf: {},
|
||||||
|
}
|
||||||
|
this.AnalyticsManager = {
|
||||||
|
getIdsFromSession: sinon.stub(),
|
||||||
|
}
|
||||||
|
this.LocalsHelper = {
|
||||||
|
setSplitTestVariant: sinon.stub(),
|
||||||
|
setSplitTestInfo: sinon.stub(),
|
||||||
|
}
|
||||||
|
|
||||||
this.SplitTestHandler = SandboxedModule.require(MODULE_PATH, {
|
this.SplitTestHandler = SandboxedModule.require(MODULE_PATH, {
|
||||||
requires: {
|
requires: {
|
||||||
|
@ -46,10 +59,14 @@ describe('SplitTestHandler', function () {
|
||||||
'./SplitTestCache': this.SplitTestCache,
|
'./SplitTestCache': this.SplitTestCache,
|
||||||
'../../models/SplitTest': { SplitTest: this.SplitTest },
|
'../../models/SplitTest': { SplitTest: this.SplitTest },
|
||||||
'../User/UserUpdater': {},
|
'../User/UserUpdater': {},
|
||||||
'../Analytics/AnalyticsManager': {},
|
'../Analytics/AnalyticsManager': this.AnalyticsManager,
|
||||||
'./LocalsHelper': {},
|
'./LocalsHelper': this.LocalsHelper,
|
||||||
|
'@overleaf/settings': this.Settings,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.req = new MockRequest()
|
||||||
|
this.res = new MockResponse()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('with an existing user', function () {
|
describe('with an existing user', function () {
|
||||||
|
@ -174,6 +191,72 @@ describe('SplitTestHandler', function () {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('with settings overrides', function () {
|
||||||
|
beforeEach(function () {
|
||||||
|
this.Settings.splitTestOverrides = {
|
||||||
|
'my-test-name': 'foo-1',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not use the override when in SaaS mode', async function () {
|
||||||
|
this.AnalyticsManager.getIdsFromSession.returns({
|
||||||
|
userId: 'abc123abc123',
|
||||||
|
})
|
||||||
|
this.SplitTestCache.get.returns({
|
||||||
|
name: 'my-test-name',
|
||||||
|
versions: [
|
||||||
|
{
|
||||||
|
versionNumber: 0,
|
||||||
|
active: true,
|
||||||
|
variants: [
|
||||||
|
{
|
||||||
|
name: '100-percent-variant',
|
||||||
|
rolloutPercent: 100,
|
||||||
|
rolloutStripes: [{ start: 0, end: 100 }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
const assignment = await this.SplitTestHandler.promises.getAssignment(
|
||||||
|
this.req,
|
||||||
|
this.res,
|
||||||
|
'my-test-name'
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.equal('100-percent-variant', assignment.variant)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should use the override when not in SaaS mode', async function () {
|
||||||
|
this.Settings.splitTestOverrides = {
|
||||||
|
'my-test-name': 'foo-1',
|
||||||
|
}
|
||||||
|
this.Settings.overleaf = undefined
|
||||||
|
|
||||||
|
const assignment = await this.SplitTestHandler.promises.getAssignment(
|
||||||
|
this.req,
|
||||||
|
this.res,
|
||||||
|
'my-test-name'
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.equal('foo-1', assignment.variant)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should use default when not in SaaS mode and no override is provided', async function () {
|
||||||
|
this.Settings.splitTestOverrides = {}
|
||||||
|
this.Settings.overleaf = undefined
|
||||||
|
|
||||||
|
const assignment = await this.SplitTestHandler.promises.getAssignment(
|
||||||
|
this.req,
|
||||||
|
this.res,
|
||||||
|
'my-test-name'
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.equal('default', assignment.variant)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
function makeSplitTest(
|
function makeSplitTest(
|
||||||
|
|
Loading…
Reference in a new issue