зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1670293 - RSExperimentLoader should expose evaluateJexl for testing r=andreio
Differential Revision: https://phabricator.services.mozilla.com/D104401
This commit is contained in:
Родитель
0bdf21e675
Коммит
f4213fbbfe
|
@ -117,32 +117,48 @@ class _RemoteSettingsExperimentLoader {
|
|||
this._initialized = false;
|
||||
}
|
||||
|
||||
async evaluateJexl(jexlString, customContext) {
|
||||
if (customContext && !customContext.experiment) {
|
||||
throw new Error(
|
||||
"Expected an .experiment property in second param of this function"
|
||||
);
|
||||
}
|
||||
|
||||
const context = TargetingContext.combineContexts(
|
||||
customContext,
|
||||
this.manager.createTargetingContext(),
|
||||
ASRouterTargeting.Environment
|
||||
);
|
||||
|
||||
log.debug("Testing targeting expression:", jexlString);
|
||||
const targetingContext = new TargetingContext(context);
|
||||
|
||||
let result = false;
|
||||
try {
|
||||
result = await targetingContext.evalWithDefault(jexlString);
|
||||
} catch (e) {
|
||||
log.debug("Targeting failed because of an error");
|
||||
Cu.reportError(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks targeting of a recipe if it is defined
|
||||
* @param {Recipe} recipe
|
||||
* @param {{[key: string]: any}} customContext A custom filter context
|
||||
* @returns {Promise<boolean>} Should we process the recipe?
|
||||
*/
|
||||
async checkTargeting(recipe, customContext = {}) {
|
||||
const context = TargetingContext.combineContexts(
|
||||
{ experiment: recipe },
|
||||
customContext,
|
||||
ASRouterTargeting.Environment
|
||||
);
|
||||
const { targeting } = recipe;
|
||||
if (!targeting) {
|
||||
async checkTargeting(recipe) {
|
||||
if (!recipe.targeting) {
|
||||
log.debug("No targeting for recipe, so it matches automatically");
|
||||
return true;
|
||||
}
|
||||
log.debug("Testing targeting expression:", targeting);
|
||||
const targetingContext = new TargetingContext(context);
|
||||
let result = false;
|
||||
try {
|
||||
result = await targetingContext.evalWithDefault(targeting);
|
||||
} catch (e) {
|
||||
log.debug("Targeting failed because of an error");
|
||||
Cu.reportError(e);
|
||||
}
|
||||
|
||||
const result = await this.evaluateJexl(recipe.targeting, {
|
||||
experiment: recipe,
|
||||
});
|
||||
|
||||
return Boolean(result);
|
||||
}
|
||||
|
||||
|
@ -172,10 +188,8 @@ class _RemoteSettingsExperimentLoader {
|
|||
|
||||
let matches = 0;
|
||||
if (recipes && !loadingError) {
|
||||
const context = this.manager.createTargetingContext();
|
||||
|
||||
for (const r of recipes) {
|
||||
if (await this.checkTargeting(r, context)) {
|
||||
if (await this.checkTargeting(r)) {
|
||||
matches++;
|
||||
log.debug(`${r.id} matched`);
|
||||
await this.manager.onRecipe(r, "rs-loader");
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
[DEFAULT]
|
||||
|
||||
[browser_remotesettings_experiment_enroll.js]
|
||||
[browser_experiment_evaluate_jexl.js]
|
||||
tags = remote-settings
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
"use strict";
|
||||
|
||||
const { RemoteSettingsExperimentLoader } = ChromeUtils.import(
|
||||
"resource://messaging-system/lib/RemoteSettingsExperimentLoader.jsm"
|
||||
);
|
||||
const { ExperimentManager } = ChromeUtils.import(
|
||||
"resource://messaging-system/experiments/ExperimentManager.jsm"
|
||||
);
|
||||
const { ExperimentFakes } = ChromeUtils.import(
|
||||
"resource://testing-common/MSTestUtils.jsm"
|
||||
);
|
||||
|
||||
add_task(async function setup() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["messaging-system.log", "all"],
|
||||
["app.shield.optoutstudies.enabled", true],
|
||||
],
|
||||
});
|
||||
|
||||
registerCleanupFunction(async () => {
|
||||
await SpecialPowers.popPrefEnv();
|
||||
});
|
||||
});
|
||||
|
||||
const FAKE_CONTEXT = {
|
||||
experiment: ExperimentFakes.recipe("fake-test-experiment"),
|
||||
};
|
||||
|
||||
add_task(async function test_throws_if_no_experiment_in_context() {
|
||||
await Assert.rejects(
|
||||
RemoteSettingsExperimentLoader.evaluateJexl("true", { customThing: 1 }),
|
||||
/Expected an .experiment property/,
|
||||
"should throw if experiment is not passed to the custom context"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_evaluate_jexl() {
|
||||
Assert.deepEqual(
|
||||
await RemoteSettingsExperimentLoader.evaluateJexl(
|
||||
`["hello"]`,
|
||||
FAKE_CONTEXT
|
||||
),
|
||||
["hello"],
|
||||
"should return the evaluated result of a jexl expression"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_evaluate_custom_context() {
|
||||
const result = await RemoteSettingsExperimentLoader.evaluateJexl(
|
||||
"experiment.slug",
|
||||
FAKE_CONTEXT
|
||||
);
|
||||
Assert.equal(
|
||||
result,
|
||||
"fake-test-experiment",
|
||||
"should have the custom .experiment context"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_evaluate_active_experiments() {
|
||||
const result = await RemoteSettingsExperimentLoader.evaluateJexl(
|
||||
"isFirstStartup",
|
||||
FAKE_CONTEXT
|
||||
);
|
||||
Assert.equal(
|
||||
typeof result,
|
||||
"boolean",
|
||||
"should have a .isFirstStartup property from ExperimentManager "
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_evaluate_active_experiments() {
|
||||
// Add an experiment to active experiments
|
||||
const slug = "foo" + Date.now();
|
||||
ExperimentManager.store.addExperiment(ExperimentFakes.experiment(slug));
|
||||
registerCleanupFunction(() => {
|
||||
ExperimentManager.store._deleteForTests(slug);
|
||||
});
|
||||
|
||||
Assert.equal(
|
||||
await RemoteSettingsExperimentLoader.evaluateJexl(
|
||||
`"${slug}" in activeExperiments`,
|
||||
FAKE_CONTEXT
|
||||
),
|
||||
true,
|
||||
"should find an active experiment"
|
||||
);
|
||||
|
||||
Assert.equal(
|
||||
await RemoteSettingsExperimentLoader.evaluateJexl(
|
||||
`"does-not-exist-fake" in activeExperiments`,
|
||||
FAKE_CONTEXT
|
||||
),
|
||||
false,
|
||||
"should not find an experiment that doesn't exist"
|
||||
);
|
||||
});
|
Загрузка…
Ссылка в новой задаче