1
0
Fork 0
firefox/toolkit/components/nimbus/test/unit/test_FirefoxLabs.js
Daniel Baumann 5e9a113729
Adding upstream version 140.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-25 09:37:52 +02:00

293 lines
7.7 KiB
JavaScript

/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
const { FirefoxLabs } = ChromeUtils.importESModule(
"resource://nimbus/FirefoxLabs.sys.mjs"
);
function setupTest({ ...ctx }) {
return NimbusTestUtils.setupTest({ ...ctx, clearTelemetry: true });
}
add_setup(function () {
Services.fog.initializeFOG();
});
add_task(async function test_all() {
const { sandbox, manager, initExperimentAPI, cleanup } = await setupTest({
experiments: [
NimbusTestUtils.factories.recipe("opt-in-rollout", {
isRollout: true,
isFirefoxLabsOptIn: true,
firefoxLabsTitle: "title",
firefoxLabsDescription: "description",
firefoxLabsDescriptionLinks: null,
firefoxLabsGroup: "group",
requiresRestart: false,
}),
NimbusTestUtils.factories.recipe("opt-in-experiment", {
branches: [
{
...NimbusTestUtils.factories.recipe.branches[0],
firefoxLabsTitle: "title",
},
],
isFirefoxLabsOptIn: true,
firefoxLabsTitle: "title",
firefoxLabsDescription: "description",
firefoxLabsDescriptionLinks: null,
firefoxLabsGroup: "group",
requiresRestart: false,
}),
NimbusTestUtils.factories.recipe("targeting-fail", {
targeting: "false",
isRollout: true,
isFirefoxLabsOptIn: true,
firefoxLabsTitle: "title",
firefoxLabsDescription: "description",
firefoxLabsDescriptionLinks: null,
firefoxLabsGroup: "group",
requiresRestart: false,
}),
NimbusTestUtils.factories.recipe("bucketing-fail", {
bucketConfig: {
...NimbusTestUtils.factories.recipe.bucketConfig,
count: 0,
},
isRollout: true,
isFirefoxLabsOptIn: true,
firefoxLabsTitle: "title",
firefoxLabsDescription: "description",
firefoxLabsDescriptionLinks: null,
firefoxLabsGroup: "group",
requiresRestart: false,
}),
NimbusTestUtils.factories.recipe("experiment"),
NimbusTestUtils.factories.recipe("rollout", { isRollout: true }),
],
init: false,
});
// Stub out enrollment because we don't care.
sandbox.stub(manager, "enroll");
await initExperimentAPI();
const labs = await FirefoxLabs.create();
const availableSlugs = Array.from(labs.all(), recipe => recipe.slug).sort();
Assert.deepEqual(
availableSlugs,
["opt-in-rollout", "opt-in-experiment"].sort(),
"Should return all opt in recipes that match targeting and bucketing"
);
await cleanup();
});
add_task(async function test_enroll() {
const recipe = NimbusTestUtils.factories.recipe.withFeatureConfig(
"opt-in",
{ featureId: "nimbus-qa-1" },
{
isRollout: true,
isFirefoxLabsOptIn: true,
firefoxLabsTitle: "placeholder",
firefoxLabsDescription: "placeholder",
firefoxLabsDescriptionLinks: null,
firefoxLabsGroup: "placeholder",
requiresRestart: false,
}
);
const { sandbox, manager, initExperimentAPI, cleanup } = await setupTest({
experiments: [recipe],
init: false,
});
const enrollSpy = sandbox.spy(manager, "enroll");
await initExperimentAPI();
const labs = await FirefoxLabs.create();
await Assert.rejects(
labs.enroll(),
/enroll: slug and branchSlug are required/,
"Should throw when enroll() is called without a slug"
);
await Assert.rejects(
labs.enroll("opt-in"),
/enroll: slug and branchSlug are required/,
"Should throw when enroll() is called without a branch slug"
);
await labs.enroll("bogus", "bogus");
Assert.ok(
enrollSpy.notCalled,
"ExperimentManager.enroll not called for unknown recipe"
);
await labs.enroll(recipe.slug, "bogus");
Assert.ok(
enrollSpy.notCalled,
"ExperimentManager.enroll not called for invalid branch slug"
);
await labs.enroll(recipe.slug, recipe.branches[0].slug);
Assert.ok(
enrollSpy.calledOnceWith(recipe, "rs-loader", { branchSlug: "control" }),
"ExperimentManager.enroll called"
);
Assert.deepEqual(
Glean.nimbusEvents.enrollmentStatus
.testGetValue("events")
?.map(ev => ev.extra),
[
{
slug: recipe.slug,
branch: "control",
status: "Enrolled",
reason: "OptIn",
},
]
);
Assert.ok(manager.store.get(recipe.slug)?.active, "Active enrollment exists");
await labs.unenroll(recipe.slug);
await cleanup();
});
add_task(async function test_reenroll() {
const recipe = NimbusTestUtils.factories.recipe("opt-in", {
isFirefoxLabsOptIn: true,
firefoxLabsTitle: "placeholder",
firefoxLabsDescription: "placeholder",
firefoxLabsDescriptionLinks: null,
firefoxLabsGroup: "placeholder",
requiresRestart: false,
isRollout: true,
});
const { manager, cleanup } = await setupTest({ experiments: [recipe] });
const labs = await FirefoxLabs.create();
Assert.ok(
typeof manager.store.get(recipe.slug) === "undefined",
`No enrollment for ${recipe.slug}`
);
await labs.enroll(recipe.slug, "control");
Assert.ok(
manager.store.get(recipe.slug)?.active,
`Active enrollment for ${recipe.slug}`
);
await labs.unenroll(recipe.slug);
Assert.ok(
manager.store.get(recipe.slug)?.active === false,
`Inactive enrollment for ${recipe.slug}`
);
await ExperimentAPI._rsLoader.updateRecipes();
Assert.ok(
manager.store.get(recipe.slug)?.active === false,
`Inactive enrollment for ${recipe.slug} after updateRecipes()`
);
await labs.enroll(recipe.slug, "control");
Assert.ok(
manager.store.get(recipe.slug)?.active,
`Active enrollment for ${recipe.slug}`
);
await labs.unenroll(recipe.slug);
await cleanup();
});
add_task(async function test_unenroll() {
const { manager, cleanup } = await setupTest({
experiments: [
NimbusTestUtils.factories.recipe.withFeatureConfig(
"rollout",
{ featureId: "nimbus-qa-1" },
{ isRollout: true }
),
NimbusTestUtils.factories.recipe.withFeatureConfig(
"opt-in",
{ featureId: "nimbus-qa-2" },
{
isRollout: true,
isFirefoxLabsOptIn: true,
firefoxLabsTitle: "title",
firefoxLabsDescription: "description",
firefoxLabsDescriptionLinks: null,
firefoxLabsGroup: "group",
requiresRestart: false,
}
),
],
});
const labs = await FirefoxLabs.create();
Assert.ok(manager.store.get("rollout")?.active, "Enrolled in rollout");
Assert.ok(
typeof manager.store.get("opt-in") === "undefined",
"Did not enroll in rollout"
);
await labs.enroll("opt-in", "control");
Assert.ok(manager.store.get("opt-in")?.active, "Enrolled in opt-in");
// Should not throw.
await labs.unenroll("bogus");
// Should not throw.
await labs.unenroll("rollout");
Assert.ok(
manager.store.get("rollout").active,
"Enrolled in rollout after attempting to unenroll with incorrect API"
);
await labs.unenroll("opt-in");
Assert.ok(!manager.store.get("opt-in").active, "Unenrolled from opt-in");
// Should not throw.
await labs.unenroll("opt-in");
Assert.deepEqual(
Glean.nimbusEvents.enrollmentStatus
.testGetValue("events")
?.map(ev => ev.extra),
[
{
branch: "control",
status: "Enrolled",
slug: "rollout",
reason: "Qualified",
},
{
status: "Enrolled",
slug: "opt-in",
reason: "OptIn",
branch: "control",
},
{
branch: "control",
reason: "OptOut",
slug: "opt-in",
status: "Disqualified",
},
]
);
await manager.unenroll("rollout");
await cleanup();
});