From d43292cfe69c2a8a9333769f6076e7b384d580d7 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Wed, 19 Jun 2024 11:23:58 +0100 Subject: [PATCH] Merge pull request #18146 from overleaf/ab-one-time-assignments [web] Handle one-time assignments for split tests GitOrigin-RevId: 2d7ec2a878055fdc96475db2129aad308abb2fff --- .../Features/SplitTests/SplitTestHandler.js | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/services/web/app/src/Features/SplitTests/SplitTestHandler.js b/services/web/app/src/Features/SplitTests/SplitTestHandler.js index 39489f0cc7..8e1d2a3d51 100644 --- a/services/web/app/src/Features/SplitTests/SplitTestHandler.js +++ b/services/web/app/src/Features/SplitTests/SplitTestHandler.js @@ -19,6 +19,7 @@ const SplitTestUserGetter = require('./SplitTestUserGetter') const DEFAULT_VARIANT = 'default' const ALPHA_PHASE = 'alpha' const BETA_PHASE = 'beta' +const RELEASE_PHASE = 'release' const DEFAULT_ASSIGNMENT = { variant: DEFAULT_VARIANT, analytics: { @@ -209,6 +210,42 @@ async function getActiveAssignmentsForUser(userId, removeArchived = false) { return assignments } +/** + * Performs a one-time assignment that is not recorded nor reproducible. + * To be used only in cases where we need random assignments that are independent of a user or session. + * If the test is in alpha or beta phase, always returns the default variant. + * @param splitTestName + * @returns {Promise<{variant: string, analytics: {segmentation: {splitTest: string, variant: string, phase: string, versionNumber: number}|{}}}>} + */ +async function getOneTimeAssignment(splitTestName) { + try { + if (!Features.hasFeature('saas')) { + return _getNonSaasAssignment(splitTestName) + } + + const splitTest = await _getSplitTest(splitTestName) + if (!splitTest) { + return DEFAULT_ASSIGNMENT + } + const currentVersion = SplitTestUtils.getCurrentVersion(splitTest) + + if (currentVersion.phase !== RELEASE_PHASE) { + return DEFAULT_ASSIGNMENT + } + + const randomUUID = crypto.randomUUID() + const { selectedVariantName } = await _getAssignmentMetadata( + randomUUID, + undefined, + splitTest + ) + return _makeAssignment(splitTest, selectedVariantName, currentVersion) + } catch (error) { + logger.error({ err: error }, 'Failed to get one time split test assignment') + return DEFAULT_ASSIGNMENT + } +} + /** * Returns an array of valid variant names for the given split test, including default * @@ -537,6 +574,7 @@ module.exports = { getAssignment: callbackify(getAssignment), getAssignmentForMongoUser: callbackify(getAssignmentForMongoUser), getAssignmentForUser: callbackify(getAssignmentForUser), + getOneTimeAssignment: callbackify(getOneTimeAssignment), getActiveAssignmentsForUser: callbackify(getActiveAssignmentsForUser), setOverrideInSession, clearOverridesInSession, @@ -544,6 +582,7 @@ module.exports = { getAssignment, getAssignmentForMongoUser, getAssignmentForUser, + getOneTimeAssignment, getActiveAssignmentsForUser, isSplitTestActive, },