fune/toolkit/components/normandy/test/browser/browser_actions_PreferenceExperimentAction.js
Edouard Oger d391c790bc Bug 1532514 - Update sinon to v7.2.7. r=markh
Differential Revision: https://phabricator.services.mozilla.com/D22046

--HG--
extra : moz-landing-system : lando
2019-03-12 19:32:40 +00:00

261 lines
8.2 KiB
JavaScript

/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
ChromeUtils.import("resource://gre/modules/components-utils/Sampling.jsm", this);
ChromeUtils.import("resource://gre/modules/Services.jsm", this);
ChromeUtils.import("resource://gre/modules/Preferences.jsm", this);
ChromeUtils.import("resource://gre/modules/TelemetryEnvironment.jsm", this);
ChromeUtils.import("resource://normandy/lib/ClientEnvironment.jsm", this);
ChromeUtils.import("resource://normandy/lib/PreferenceExperiments.jsm", this);
ChromeUtils.import("resource://normandy/lib/TelemetryEvents.jsm", this);
ChromeUtils.import("resource://normandy/lib/Uptake.jsm", this);
ChromeUtils.import("resource://normandy/actions/PreferenceExperimentAction.jsm", this);
function argumentsFactory(args) {
return {
slug: "test",
preferenceName: "fake.preference",
preferenceType: "string",
preferenceBranchType: "default",
branches: [
{ slug: "test", value: "foo", ratio: 1 },
],
isHighPopulation: false,
...args,
};
}
function preferenceExperimentFactory(args) {
return recipeFactory({
name: "preference-experiment",
arguments: argumentsFactory(args),
});
}
decorate_task(
withStub(Uptake, "reportRecipe"),
async function run_without_errors(reportRecipe) {
const action = new PreferenceExperimentAction();
const recipe = preferenceExperimentFactory();
await action.runRecipe(recipe);
await action.finalize();
// runRecipe catches exceptions thrown by _run(), so
// explicitly check for reported success here.
Assert.deepEqual(reportRecipe.args,
[[recipe, Uptake.RECIPE_SUCCESS]]);
}
);
decorate_task(
withStub(Uptake, "reportRecipe"),
withStub(Uptake, "reportAction"),
withPrefEnv({set: [["app.shield.optoutstudies.enabled", false]]}),
async function checks_disabled(reportRecipe, reportAction) {
const action = new PreferenceExperimentAction();
action.log = mockLogger();
const recipe = preferenceExperimentFactory();
await action.runRecipe(recipe);
Assert.deepEqual(action.log.info.args,
[["User has opted out of preference experiments. Disabling this action."]]);
Assert.deepEqual(action.log.warn.args,
[["Skipping recipe preference-experiment because PreferenceExperimentAction " +
"was disabled during preExecution."]]);
await action.finalize();
Assert.deepEqual(action.log.debug.args,
[["Skipping post-execution hook for PreferenceExperimentAction because it is disabled."]]);
Assert.deepEqual(reportRecipe.args,
[[recipe, Uptake.RECIPE_ACTION_DISABLED]]);
Assert.deepEqual(reportAction.args,
[[action.name, Uptake.ACTION_SUCCESS]]);
}
);
decorate_task(
withStub(PreferenceExperiments, "start"),
PreferenceExperiments.withMockExperiments([]),
async function enroll_user_if_never_been_in_experiment(startStub) {
const action = new PreferenceExperimentAction();
const recipe = preferenceExperimentFactory({
slug: "test",
preferenceName: "fake.preference",
preferenceBranchType: "user",
branches: [
{ slug: "branch1", value: "branch1", ratio: 1 },
{ slug: "branch2", value: "branch2", ratio: 1 },
],
});
sinon.stub(action, "chooseBranch").callsFake(async function(slug, branches) {
return branches[0];
});
await action.runRecipe(recipe);
await action.finalize();
Assert.deepEqual(startStub.args, [[{
name: "test",
branch: "branch1",
preferenceName: "fake.preference",
preferenceValue: "branch1",
preferenceBranchType: "user",
preferenceType: "string",
experimentType: "exp",
}]]);
}
);
decorate_task(
withStub(PreferenceExperiments, "markLastSeen"),
PreferenceExperiments.withMockExperiments([{name: "test", expired: false}]),
async function markSeen_if_experiment_active(markLastSeenStub) {
const action = new PreferenceExperimentAction();
const recipe = preferenceExperimentFactory({
slug: "test",
});
await action.runRecipe(recipe);
await action.finalize();
Assert.deepEqual(markLastSeenStub.args, [["test"]]);
}
);
decorate_task(
withStub(PreferenceExperiments, "markLastSeen"),
PreferenceExperiments.withMockExperiments([{name: "test", expired: true}]),
async function dont_markSeen_if_experiment_expired(markLastSeenStub) {
const action = new PreferenceExperimentAction();
const recipe = preferenceExperimentFactory({
slug: "test",
});
await action.runRecipe(recipe);
await action.finalize();
Assert.deepEqual(markLastSeenStub.args, [], "markLastSeen was not called");
}
);
decorate_task(
withStub(PreferenceExperiments, "start"),
async function do_nothing_if_enrollment_paused(startStub) {
const action = new PreferenceExperimentAction();
const recipe = preferenceExperimentFactory({
isEnrollmentPaused: true,
});
await action.runRecipe(recipe);
await action.finalize();
Assert.deepEqual(startStub.args, [], "start was not called");
}
);
decorate_task(
withStub(PreferenceExperiments, "stop"),
PreferenceExperiments.withMockExperiments([
{name: "seen", expired: false},
{name: "unseen", expired: false},
]),
async function stop_experiments_not_seen(stopStub) {
const action = new PreferenceExperimentAction();
const recipe = preferenceExperimentFactory({
slug: "seen",
});
await action.runRecipe(recipe);
await action.finalize();
Assert.deepEqual(stopStub.args,
[["unseen", {resetValue: true, reason: "recipe-not-seen"}]]);
}
);
decorate_task(
withStub(PreferenceExperiments, "start"),
withStub(Uptake, "reportRecipe"),
PreferenceExperiments.withMockExperiments([
{
name: "conflict",
preferenceName: "conflict.pref",
expired: false,
},
]),
async function do_nothing_if_preference_is_already_being_tested(startStub, reportRecipeStub) {
const action = new PreferenceExperimentAction();
const recipe = preferenceExperimentFactory({
slug: "new",
preferenceName: "conflict.pref",
});
action.chooseBranch = sinon.stub().callsFake(async function(slug, branches) {
return branches[0];
});
await action.runRecipe(recipe);
await action.finalize();
Assert.deepEqual(reportRecipeStub.args,
[[recipe, Uptake.RECIPE_EXECUTION_ERROR]]);
Assert.deepEqual(startStub.args, [], "start not called");
// No way to get access to log message/Error thrown
}
);
decorate_task(
withStub(PreferenceExperiments, "start"),
PreferenceExperiments.withMockExperiments([]),
async function experimentType_with_isHighPopulation_false(startStub) {
const action = new PreferenceExperimentAction();
const recipe = preferenceExperimentFactory({
isHighPopulation: false,
});
await action.runRecipe(recipe);
await action.finalize();
Assert.deepEqual(startStub.args[0][0].experimentType, "exp");
}
);
decorate_task(
withStub(PreferenceExperiments, "start"),
PreferenceExperiments.withMockExperiments([]),
async function experimentType_with_isHighPopulation_true(startStub) {
const action = new PreferenceExperimentAction();
const recipe = preferenceExperimentFactory({
isHighPopulation: true,
});
await action.runRecipe(recipe);
await action.finalize();
Assert.deepEqual(startStub.args[0][0].experimentType, "exp-highpop");
}
);
decorate_task(
withStub(Sampling, "ratioSample"),
async function chooseBranch_uses_ratioSample(ratioSampleStub) {
ratioSampleStub.returns(Promise.resolve(1));
const action = new PreferenceExperimentAction();
const branches = [
{ value: "branch0", ratio: 1 },
{ value: "branch1", ratio: 2 },
];
const sandbox = sinon.createSandbox();
let result;
try {
sandbox.stub(ClientEnvironment, "userId").get(() => "fake-id");
result = await action.chooseBranch("exp-slug", branches);
} finally {
sandbox.restore();
}
Assert.deepEqual(ratioSampleStub.args,
[["fake-id-exp-slug-branch", [1, 2]]]);
Assert.deepEqual(result, branches[1]);
}
);