Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

"use strict";
const { ExperimentAPI, _ExperimentFeature: ExperimentFeature } =
ChromeUtils.importESModule("resource://nimbus/ExperimentAPI.sys.mjs");
const { AppConstants } = ChromeUtils.importESModule(
);
async function setupForExperimentFeature() {
const sandbox = sinon.createSandbox();
const manager = ExperimentFakes.manager();
await manager.onStartup();
sandbox.stub(ExperimentAPI, "_store").get(() => manager.store);
return { sandbox, manager };
}
const FEATURE_ID = "testfeature1";
// Note: this gets deleted at the end of tests
const TEST_PREF_BRANCH = "testfeature1.";
const TEST_VARIABLES = {
enabled: {
type: "boolean",
fallbackPref: `${TEST_PREF_BRANCH}enabled`,
},
name: {
type: "string",
fallbackPref: `${TEST_PREF_BRANCH}name`,
},
count: {
type: "int",
fallbackPref: `${TEST_PREF_BRANCH}count`,
},
items: {
type: "json",
fallbackPref: `${TEST_PREF_BRANCH}items`,
},
};
function createInstanceWithVariables(variables) {
return new ExperimentFeature(FEATURE_ID, {
variables,
});
}
add_task(async function test_ExperimentFeature_getFallbackPrefName() {
const instance = createInstanceWithVariables(TEST_VARIABLES);
Assert.equal(
instance.getFallbackPrefName("enabled"),
"testfeature1.enabled",
"should return the fallback preference name"
);
});
add_task(async function test_ExperimentFeature_getVariable_notRegistered() {
const instance = createInstanceWithVariables(TEST_VARIABLES);
if (Cu.isInAutomation || AppConstants.NIGHTLY_BUILD) {
Assert.throws(
() => {
instance.getVariable("non_existant_variable");
},
/Nimbus: Warning - variable "non_existant_variable" is not defined in FeatureManifest\.yaml/,
"should throw in automation for variables not defined in the manifest"
);
} else {
info("Won't throw when running in Beta and release candidates");
}
});
add_task(async function test_ExperimentFeature_getVariable_noFallbackPref() {
const instance = createInstanceWithVariables({
foo: { type: "json" },
});
Assert.equal(
instance.getVariable("foo"),
undefined,
"should return undefined if no values are set and no fallback pref is defined"
);
});
add_task(async function test_ExperimentFeature_getVariable_precedence() {
const { sandbox, manager } = await setupForExperimentFeature();
const instance = createInstanceWithVariables(TEST_VARIABLES);
const prefName = TEST_VARIABLES.items.fallbackPref;
const rollout = ExperimentFakes.rollout(`${FEATURE_ID}-rollout`, {
branch: {
slug: "slug",
features: [
{
featureId: FEATURE_ID,
value: { items: [4, 5, 6] },
},
],
},
});
Services.prefs.clearUserPref(prefName);
Assert.equal(
instance.getVariable("items"),
undefined,
"should return undefined if the fallback pref is not set"
);
// Default pref values
Services.prefs.setStringPref(prefName, JSON.stringify([1, 2, 3]));
Assert.deepEqual(
instance.getVariable("items"),
[1, 2, 3],
"should return the default pref value"
);
// Remote default values
await manager.store.addEnrollment(rollout);
Assert.deepEqual(
instance.getVariable("items"),
[4, 5, 6],
"should return the remote default value over the default pref value"
);
// Experiment values
const doExperimentCleanup = await ExperimentFakes.enrollWithFeatureConfig(
{
featureId: FEATURE_ID,
value: {
items: [7, 8, 9],
},
},
{ manager }
);
Assert.deepEqual(
instance.getVariable("items"),
[7, 8, 9],
"should return the experiment value over the remote value"
);
// Cleanup
Services.prefs.deleteBranch(TEST_PREF_BRANCH);
await doExperimentCleanup();
sandbox.restore();
});
add_task(async function test_ExperimentFeature_getVariable_partial_values() {
const { sandbox, manager } = await setupForExperimentFeature();
const instance = createInstanceWithVariables(TEST_VARIABLES);
const rollout = ExperimentFakes.rollout(`${FEATURE_ID}-rollout`, {
branch: {
slug: "slug",
features: [
{
featureId: FEATURE_ID,
value: { name: "abc" },
},
],
},
});
// Set up a pref value for .enabled,
// a remote value for .name,
// an experiment value for .items
Services.prefs.setBoolPref(TEST_VARIABLES.enabled.fallbackPref, true);
await manager.store.addEnrollment(rollout);
const doExperimentCleanup = await ExperimentFakes.enrollWithFeatureConfig(
{
featureId: FEATURE_ID,
value: {},
},
{ manager }
);
Assert.equal(
instance.getVariable("enabled"),
true,
"should skip missing variables from remote defaults"
);
Assert.equal(
instance.getVariable("name"),
"abc",
"should skip missing variables from experiments"
);
// Cleanup
Services.prefs.getDefaultBranch("").deleteBranch(TEST_PREF_BRANCH);
Services.prefs.deleteBranch(TEST_PREF_BRANCH);
await doExperimentCleanup();
sandbox.restore();
});