Skip to content

Commit 82e1fdd

Browse files
authored
User cannot belong to all experiments in an experiment group (#11945)
1 parent a91d737 commit 82e1fdd

File tree

3 files changed

+22
-2
lines changed

3 files changed

+22
-2
lines changed

news/2 Fixes/11943.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Ensure user cannot belong to all experiments in an experiment group.

src/client/common/experiments.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ export class ExperimentsManager implements IExperimentsManager {
150150
public populateUserExperiments(): void {
151151
this.cleanUpExperimentsOptList();
152152
if (Array.isArray(this.experimentStorage.value)) {
153+
const remainingExpriments: ABExperiments = [];
154+
// First process experiments in order of user preference (if they have opted out or opted in).
153155
for (const experiment of this.experimentStorage.value) {
154156
// User cannot belong to NotebookExperiment if they are not using Insiders.
155157
if (
@@ -176,13 +178,19 @@ export class ExperimentsManager implements IExperimentsManager {
176178
expNameOptedInto: experiment.name
177179
});
178180
this.userExperiments.push(experiment);
179-
} else if (this.isUserInRange(experiment.min, experiment.max, experiment.salt)) {
180-
this.userExperiments.push(experiment);
181+
} else {
182+
remainingExpriments.push(experiment);
181183
}
182184
} catch (ex) {
183185
traceError(`Failed to populate experiment list for experiment '${experiment.name}'`, ex);
184186
}
185187
}
188+
189+
// Add users (based on algorithm) to experiments they haven't already opted out of or opted into.
190+
remainingExpriments
191+
.filter((experiment) => this.isUserInRange(experiment.min, experiment.max, experiment.salt))
192+
.filter((experiment) => !this.userExperiments.some((existing) => existing.salt === experiment.salt))
193+
.forEach((experiment) => this.userExperiments.push(experiment));
186194
}
187195
}
188196

src/test/common/experiments.unit.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,17 @@ suite('A/B experiments', () => {
841841
experimentsOptedInto: ['experiment1'],
842842
expectedResult: [{ name: 'experiment1', salt: 'salt', min: 79, max: 94 }]
843843
},
844+
{
845+
testName:
846+
'User experiments list contains the experiment user has opened into and not the control experiment even if user is in the control experiment range',
847+
experimentStorageValue: [
848+
{ name: 'control', salt: 'salt', min: 0, max: 100 },
849+
{ name: 'experiment', salt: 'salt', min: 0, max: 0 }
850+
],
851+
hash: 8187,
852+
experimentsOptedInto: ['experiment'],
853+
expectedResult: [{ name: 'experiment', salt: 'salt', min: 0, max: 0 }]
854+
},
844855
{
845856
testName:
846857
'User experiments list does not contain the experiment if user has both opted in and out of an experiment',

0 commit comments

Comments
 (0)