Skip to content

Commit cd1586e

Browse files
Bug 1972647 - Unenroll from Firefox labs opt-ins during Nimbus initialization if Labs is disabled by policy r=nimbus-reviewers,relud
Differential Revision: https://phabricator.services.mozilla.com/D269921
1 parent 73fb4a2 commit cd1586e

3 files changed

Lines changed: 58 additions & 4 deletions

File tree

‎toolkit/components/nimbus/lib/ExperimentManager.sys.mjs‎

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,10 @@ export class ExperimentManager {
261261
this._handleStudiesOptOut();
262262
}
263263

264+
if (!lazy.ExperimentAPI.labsEnabled) {
265+
this._handleLabsDisabled();
266+
}
267+
264268
lazy.NimbusFeatures.nimbusTelemetry.onUpdate(() => {
265269
// Providing default values ensure we disable metrics when unenrolling.
266270
const cfg = {
@@ -755,7 +759,7 @@ export class ExperimentManager {
755759
if (result.ok) {
756760
// Unenrollment due to studies becoming disabled is handled in
757761
// `_handleStudiesOptOut`. Firefox Labs can only be disabled by policy and
758-
// thus its enabled state cannot change at runtime.
762+
// thus its enabled state cannot change after Nimbus is initialized.
759763
if (result.status === lazy.MatchStatus.DISABLED) {
760764
return false;
761765
}
@@ -938,9 +942,11 @@ export class ExperimentManager {
938942
* Unenroll from all active studies if user opts out.
939943
*/
940944
_handleStudiesOptOut() {
941-
for (const enrollment of this.store
945+
const enrollments = this.store
942946
.getAll()
943-
.filter(e => e.active && !e.isFirefoxLabsOptIn)) {
947+
.filter(e => e.active && !e.isFirefoxLabsOptIn);
948+
949+
for (const enrollment of enrollments) {
944950
this._unenroll(
945951
enrollment,
946952
UnenrollmentCause.fromReason(
@@ -950,6 +956,26 @@ export class ExperimentManager {
950956
}
951957
}
952958

959+
/**
960+
* Unenroll from all active Firefox Labs opt-ins if Labs becomes disabled.
961+
*/
962+
_handleLabsDisabled() {
963+
const enrollments = this.store
964+
.getAll()
965+
.filter(e => e.active && e.isFirefoxLabsOptIn);
966+
967+
for (const enrollment of enrollments) {
968+
this._unenroll(
969+
enrollment,
970+
UnenrollmentCause.fromReason(
971+
lazy.NimbusTelemetry.UnenrollReason.LABS_DISABLED
972+
)
973+
);
974+
}
975+
976+
this.optinRecipes = [];
977+
}
978+
953979
/**
954980
* Generate Normandy UserId respective to a branch
955981
* for a given experiment.

‎toolkit/components/nimbus/lib/RemoteSettingsExperimentLoader.sys.mjs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -815,7 +815,7 @@ export class RemoteSettingsExperimentLoader {
815815
* Resolves when the RemoteSettingsExperimentLoader has updated at least once
816816
* and is not in the middle of an update.
817817
*
818-
* If studies are disabled or the RemoteSettingsExperimentLoader has been
818+
* If Nimbus is disabled or the RemoteSettingsExperimentLoader has been
819819
* disabled (i.e., during shutdown), then this will always resolve
820820
* immediately.
821821
*/

‎toolkit/components/nimbus/test/unit/test_policy.js‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ async function doTest({
4040
policies,
4141
labsEnabled,
4242
studiesEnabled,
43+
existingEnrollments = [],
4344
expectedEnrollments,
4445
expectedOptIns,
4546
}) {
@@ -53,10 +54,26 @@ async function doTest({
5354
"Policy engine is active"
5455
);
5556

57+
let storePath = undefined;
58+
if (existingEnrollments) {
59+
const store = NimbusTestUtils.stubs.store();
60+
await store.init();
61+
62+
for (const slug of existingEnrollments) {
63+
NimbusTestUtils.addEnrollmentForRecipe(
64+
RECIPES.find(e => e.slug === slug),
65+
{ store }
66+
);
67+
}
68+
69+
storePath = await NimbusTestUtils.saveStore(store);
70+
}
71+
5672
const { initExperimentAPI, cleanup, loader } =
5773
await NimbusTestUtils.setupTest({
5874
init: false,
5975
experiments: RECIPES,
76+
storePath,
6077
});
6178

6279
sinon.spy(loader, "updateRecipes");
@@ -145,3 +162,14 @@ add_task(async function testNimbusDisabled() {
145162
expectedOptIns: [],
146163
});
147164
});
165+
166+
add_task(async function testDisableLabsPolicyCausesUnenrollments() {
167+
await doTest({
168+
policies: { UserMessaging: { FirefoxLabs: false } },
169+
labsEnabled: false,
170+
studiesEnabled: true,
171+
expectedEnrollments: ["experiment", "rollout"],
172+
existingEnrollments: ["optin"],
173+
expectedOptIns: [],
174+
});
175+
});

0 commit comments

Comments
 (0)