зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1634481 - Add trigger to the reach ping r=andreio
Differential Revision: https://phabricator.services.mozilla.com/D76610
This commit is contained in:
Родитель
a769706988
Коммит
082a6cd662
|
@ -102,6 +102,13 @@ const TOPIC_INTL_LOCALE_CHANGED = "intl:app-locales-changed";
|
|||
const USE_REMOTE_L10N_PREF =
|
||||
"browser.newtabpage.activity-stream.asrouter.useRemoteL10n";
|
||||
|
||||
// Experiment groups that need to report the reach event in Messaging-Experiments.
|
||||
// If you're adding new groups to it, make sure they're also added in the
|
||||
// `messaging_experiments.reach.objects` defined in "toolkit/components/telemetry/Events.yaml"
|
||||
const REACH_EVENT_GROUPS = ["cfr"];
|
||||
const REACH_EVENT_CATEGORY = "messaging_experiments";
|
||||
const REACH_EVENT_METHOD = "reach";
|
||||
|
||||
const MessageLoaderUtils = {
|
||||
STARTPAGE_VERSION,
|
||||
REMOTE_LOADER_CACHE_KEY: "RemoteLoaderCache",
|
||||
|
@ -340,22 +347,47 @@ const MessageLoaderUtils = {
|
|||
MessageLoaderUtils.reportError(e);
|
||||
return [];
|
||||
}
|
||||
return provider.messageGroups
|
||||
.map(group => {
|
||||
let experimentData;
|
||||
try {
|
||||
experimentData = ExperimentAPI.getExperiment({ group });
|
||||
} catch (e) {
|
||||
MessageLoaderUtils.reportError(e);
|
||||
return [];
|
||||
}
|
||||
if (experimentData && experimentData.branch) {
|
||||
return experimentData.branch.value;
|
||||
}
|
||||
|
||||
return [];
|
||||
})
|
||||
.flat();
|
||||
let experiments = [];
|
||||
for (const group of provider.messageGroups) {
|
||||
let experimentData;
|
||||
try {
|
||||
experimentData = ExperimentAPI.getExperiment({ group });
|
||||
} catch (e) {
|
||||
MessageLoaderUtils.reportError(e);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (experimentData && experimentData.branch) {
|
||||
experiments.push(experimentData.branch.value);
|
||||
|
||||
if (!REACH_EVENT_GROUPS.includes(group)) {
|
||||
continue;
|
||||
}
|
||||
// Check other sibling branches for triggers, add them to the return
|
||||
// array if found any. The `forReachEvent` label is used to identify
|
||||
// those branches so that they would only used to record the Reach
|
||||
// event.
|
||||
const branches =
|
||||
(await ExperimentAPI.getAllBranches(experimentData.slug)) || [];
|
||||
for (const branch of branches) {
|
||||
if (
|
||||
branch.slug !== experimentData.branch.slug &&
|
||||
branch.value.trigger
|
||||
) {
|
||||
experiments.push({
|
||||
group,
|
||||
forReachEvent: true,
|
||||
experimentSlug: experimentData.slug,
|
||||
branchSlug: branch.slug,
|
||||
...branch.value,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return experiments;
|
||||
},
|
||||
|
||||
_handleRemoteSettingsUndesiredEvent(event, providerId, dispatchToAS) {
|
||||
|
@ -1962,6 +1994,19 @@ class _ASRouter {
|
|||
await this._sendMessageToTarget(message, target);
|
||||
}
|
||||
|
||||
_recordReachEvent(message) {
|
||||
// Events telemetry only accepts understores for the event `object`
|
||||
const underscored = message.group.split("-").join("_");
|
||||
const extra = { branches: message.branchSlug };
|
||||
Services.telemetry.recordEvent(
|
||||
REACH_EVENT_CATEGORY,
|
||||
REACH_EVENT_METHOD,
|
||||
underscored,
|
||||
message.experimentSlug,
|
||||
extra
|
||||
);
|
||||
}
|
||||
|
||||
async sendTriggerMessage(target, trigger) {
|
||||
await this.loadMessagesFromAllProviders();
|
||||
|
||||
|
@ -1972,14 +2017,32 @@ class _ASRouter {
|
|||
|
||||
const telemetryObject = { port: target.portID };
|
||||
TelemetryStopwatch.start("MS_MESSAGE_REQUEST_TIME_MS", telemetryObject);
|
||||
const message = await this.handleMessageRequest({
|
||||
triggerId: trigger.id,
|
||||
triggerParam: trigger.param,
|
||||
triggerContext: trigger.context,
|
||||
});
|
||||
// Return all the messages so that it can record the Reach event
|
||||
const messages =
|
||||
(await this.handleMessageRequest({
|
||||
triggerId: trigger.id,
|
||||
triggerParam: trigger.param,
|
||||
triggerContext: trigger.context,
|
||||
returnAll: true,
|
||||
})) || [];
|
||||
TelemetryStopwatch.finish("MS_MESSAGE_REQUEST_TIME_MS", telemetryObject);
|
||||
|
||||
await this._sendMessageToTarget(message, target, trigger);
|
||||
// Record the Reach event for all the messages with `forReachEvent`,
|
||||
// only send the first message without forReachEvent to the target
|
||||
const nonReachMessages = [];
|
||||
for (const message of messages) {
|
||||
if (message.forReachEvent) {
|
||||
this._recordReachEvent(message);
|
||||
} else {
|
||||
nonReachMessages.push(message);
|
||||
}
|
||||
}
|
||||
|
||||
await this._sendMessageToTarget(
|
||||
nonReachMessages[0] || null,
|
||||
target,
|
||||
trigger
|
||||
);
|
||||
}
|
||||
|
||||
renderWNMessages(browserWindow, messageIds) {
|
||||
|
|
|
@ -19,98 +19,96 @@ const EXPERIMENT_PAYLOAD = {
|
|||
{
|
||||
slug: "control",
|
||||
ratio: 1,
|
||||
value: [
|
||||
{
|
||||
id: "xman_test_message",
|
||||
content: {
|
||||
text: "This is a test CFR",
|
||||
addon: {
|
||||
id: "954390",
|
||||
icon:
|
||||
"resource://activity-stream/data/content/assets/cfr_fb_container.png",
|
||||
title: "Facebook Container",
|
||||
users: 1455872,
|
||||
author: "Mozilla",
|
||||
rating: 4.5,
|
||||
amo_url:
|
||||
"https://addons.mozilla.org/firefox/addon/facebook-container/",
|
||||
value: {
|
||||
id: "xman_test_message",
|
||||
content: {
|
||||
text: "This is a test CFR",
|
||||
addon: {
|
||||
id: "954390",
|
||||
icon:
|
||||
"resource://activity-stream/data/content/assets/cfr_fb_container.png",
|
||||
title: "Facebook Container",
|
||||
users: 1455872,
|
||||
author: "Mozilla",
|
||||
rating: 4.5,
|
||||
amo_url:
|
||||
"https://addons.mozilla.org/firefox/addon/facebook-container/",
|
||||
},
|
||||
buttons: {
|
||||
primary: {
|
||||
label: {
|
||||
string_id: "cfr-doorhanger-extension-ok-button",
|
||||
},
|
||||
action: {
|
||||
data: {
|
||||
url: null,
|
||||
},
|
||||
type: "INSTALL_ADDON_FROM_URL",
|
||||
},
|
||||
},
|
||||
buttons: {
|
||||
primary: {
|
||||
secondary: [
|
||||
{
|
||||
label: {
|
||||
string_id: "cfr-doorhanger-extension-ok-button",
|
||||
string_id: "cfr-doorhanger-extension-cancel-button",
|
||||
},
|
||||
action: {
|
||||
type: "CANCEL",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: {
|
||||
string_id:
|
||||
"cfr-doorhanger-extension-never-show-recommendation",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: {
|
||||
string_id:
|
||||
"cfr-doorhanger-extension-manage-settings-button",
|
||||
},
|
||||
action: {
|
||||
data: {
|
||||
url: null,
|
||||
origin: "CFR",
|
||||
category: "general-cfraddons",
|
||||
},
|
||||
type: "INSTALL_ADDON_FROM_URL",
|
||||
type: "OPEN_PREFERENCES_PAGE",
|
||||
},
|
||||
},
|
||||
secondary: [
|
||||
{
|
||||
label: {
|
||||
string_id: "cfr-doorhanger-extension-cancel-button",
|
||||
},
|
||||
action: {
|
||||
type: "CANCEL",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: {
|
||||
string_id:
|
||||
"cfr-doorhanger-extension-never-show-recommendation",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: {
|
||||
string_id:
|
||||
"cfr-doorhanger-extension-manage-settings-button",
|
||||
},
|
||||
action: {
|
||||
data: {
|
||||
origin: "CFR",
|
||||
category: "general-cfraddons",
|
||||
},
|
||||
type: "OPEN_PREFERENCES_PAGE",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
category: "cfrAddons",
|
||||
bucket_id: "CFR_M1",
|
||||
info_icon: {
|
||||
label: {
|
||||
string_id: "cfr-doorhanger-extension-sumo-link",
|
||||
},
|
||||
sumo_path: "extensionrecommendations",
|
||||
},
|
||||
heading_text: "Welcome to the experiment",
|
||||
notification_text: {
|
||||
string_id: "cfr-doorhanger-extension-notification2",
|
||||
},
|
||||
},
|
||||
trigger: {
|
||||
id: "openURL",
|
||||
params: [
|
||||
"www.facebook.com",
|
||||
"facebook.com",
|
||||
"www.instagram.com",
|
||||
"instagram.com",
|
||||
"www.whatsapp.com",
|
||||
"whatsapp.com",
|
||||
"web.whatsapp.com",
|
||||
"www.messenger.com",
|
||||
"messenger.com",
|
||||
],
|
||||
},
|
||||
template: "cfr_doorhanger",
|
||||
frequency: {
|
||||
lifetime: 3,
|
||||
category: "cfrAddons",
|
||||
bucket_id: "CFR_M1",
|
||||
info_icon: {
|
||||
label: {
|
||||
string_id: "cfr-doorhanger-extension-sumo-link",
|
||||
},
|
||||
sumo_path: "extensionrecommendations",
|
||||
},
|
||||
heading_text: "Welcome to the experiment",
|
||||
notification_text: {
|
||||
string_id: "cfr-doorhanger-extension-notification2",
|
||||
},
|
||||
targeting: "true",
|
||||
},
|
||||
],
|
||||
trigger: {
|
||||
id: "openURL",
|
||||
params: [
|
||||
"www.facebook.com",
|
||||
"facebook.com",
|
||||
"www.instagram.com",
|
||||
"instagram.com",
|
||||
"www.whatsapp.com",
|
||||
"whatsapp.com",
|
||||
"web.whatsapp.com",
|
||||
"www.messenger.com",
|
||||
"messenger.com",
|
||||
],
|
||||
},
|
||||
template: "cfr_doorhanger",
|
||||
frequency: {
|
||||
lifetime: 3,
|
||||
},
|
||||
targeting: "true",
|
||||
},
|
||||
groups: ["cfr"],
|
||||
},
|
||||
],
|
||||
|
|
|
@ -208,6 +208,7 @@ describe("ASRouter", () => {
|
|||
},
|
||||
ExperimentAPI: {
|
||||
getExperiment: sandbox.stub().returns({ branch: { value: [] } }),
|
||||
getAllBranches: sandbox.stub().returns([{ branch: { value: [] } }]),
|
||||
ready: sandbox.stub().resolves(),
|
||||
},
|
||||
SpecialMessageActions: {
|
||||
|
@ -2349,6 +2350,48 @@ describe("ASRouter", () => {
|
|||
100
|
||||
);
|
||||
});
|
||||
it("should record the Reach event if found any", async () => {
|
||||
let messages = [
|
||||
{
|
||||
id: "foo1",
|
||||
forReachEvent: true,
|
||||
experimentSlug: "exp01",
|
||||
branchSlug: "branch01",
|
||||
group: "cfr",
|
||||
template: "simple_template",
|
||||
trigger: { id: "foo" },
|
||||
content: { title: "Foo1", body: "Foo123-1" },
|
||||
},
|
||||
{
|
||||
id: "foo2",
|
||||
group: "cfr",
|
||||
template: "simple_template",
|
||||
trigger: { id: "bar" },
|
||||
content: { title: "Foo2", body: "Foo123-2" },
|
||||
provider: "onboarding",
|
||||
},
|
||||
{
|
||||
id: "foo3",
|
||||
forReachEvent: true,
|
||||
experimentSlug: "exp02",
|
||||
branchSlug: "branch02",
|
||||
group: "cfr",
|
||||
template: "simple_template",
|
||||
trigger: { id: "foo" },
|
||||
content: { title: "Foo1", body: "Foo123-1" },
|
||||
},
|
||||
];
|
||||
sandbox.stub(Router, "handleMessageRequest").resolves(messages);
|
||||
sandbox.spy(Services.telemetry, "recordEvent");
|
||||
|
||||
const msg = fakeAsyncMessage({
|
||||
type: "TRIGGER",
|
||||
data: { trigger: { id: "foo" } },
|
||||
});
|
||||
|
||||
await Router.onMessage(msg);
|
||||
assert.calledTwice(Services.telemetry.recordEvent);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".includeBundle", () => {
|
||||
|
@ -4002,12 +4045,15 @@ describe("ASRouter", () => {
|
|||
};
|
||||
|
||||
global.ExperimentAPI.getExperiment.returns({
|
||||
branch: { value: ["foo", "bar"] },
|
||||
branch: {
|
||||
slug: "branch01",
|
||||
value: { id: "id01", trigger: { id: "openURL" } },
|
||||
},
|
||||
});
|
||||
|
||||
const result = await MessageLoaderUtils.loadMessagesForProvider(args);
|
||||
|
||||
assert.lengthOf(result.messages, 2);
|
||||
assert.lengthOf(result.messages, 1);
|
||||
});
|
||||
it("should fetch messages from the ExperimentAPI", async () => {
|
||||
global.ExperimentAPI.ready.throws();
|
||||
|
@ -4022,6 +4068,44 @@ describe("ASRouter", () => {
|
|||
assert.notCalled(global.ExperimentAPI.getExperiment);
|
||||
assert.calledOnce(stub);
|
||||
});
|
||||
it("should fetch branches with trigger", async () => {
|
||||
const args = {
|
||||
type: "remote-experiments",
|
||||
messageGroups: ["cfr"],
|
||||
};
|
||||
global.ExperimentAPI.getExperiment.returns({
|
||||
slug: "exp01",
|
||||
branch: {
|
||||
slug: "branch01",
|
||||
value: { id: "id01", trigger: { id: "openURL" } },
|
||||
},
|
||||
});
|
||||
global.ExperimentAPI.getAllBranches.returns([
|
||||
{
|
||||
slug: "branch01",
|
||||
value: { id: "id01", trigger: { id: "openURL" } },
|
||||
},
|
||||
{
|
||||
slug: "branch02",
|
||||
value: { id: "id02", trigger: { id: "openURL" } },
|
||||
},
|
||||
{
|
||||
// This branch should not be loaded as it doesn't have the trigger
|
||||
slug: "branch03",
|
||||
value: { id: "id03" },
|
||||
},
|
||||
]);
|
||||
|
||||
const result = await MessageLoaderUtils.loadMessagesForProvider(args);
|
||||
|
||||
assert.equal(result.messages.length, 2);
|
||||
assert.equal(result.messages[0].id, "id01");
|
||||
assert.equal(result.messages[1].id, "id02");
|
||||
assert.equal(result.messages[1].group, "cfr");
|
||||
assert.equal(result.messages[1].experimentSlug, "exp01");
|
||||
assert.equal(result.messages[1].branchSlug, "branch02");
|
||||
assert.ok(result.messages[1].forReachEvent);
|
||||
});
|
||||
it("should fetch json from url", async () => {
|
||||
let result = await MessageLoaderUtils.loadMessagesForProvider({
|
||||
location: "http://fake.com/endpoint",
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
|
||||
const EXPORTED_SYMBOLS = ["ExperimentManager", "_ExperimentManager"];
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
@ -26,9 +24,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
Sampling: "resource://gre/modules/components-utils/Sampling.jsm",
|
||||
TelemetryEvents: "resource://normandy/lib/TelemetryEvents.jsm",
|
||||
TelemetryEnvironment: "resource://gre/modules/TelemetryEnvironment.jsm",
|
||||
RemoteSettings: "resource://services-settings/remote-settings.js",
|
||||
requestIdleCallback: "resource://gre/modules/Timer.jsm",
|
||||
ASRouterTargeting: "resource://activity-stream/lib/ASRouterTargeting.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "log", () => {
|
||||
|
@ -46,20 +41,6 @@ const TELEMETRY_EXPERIMENT_TYPE_PREFIX = "normandy-";
|
|||
// Also included in telemetry
|
||||
const DEFAULT_EXPERIMENT_TYPE = "messaging_experiment";
|
||||
|
||||
// Experiment groups that are currently collecting the Reach events.
|
||||
//
|
||||
// If you're adding new groups to it, make sure they're also added in the
|
||||
// `messaging_experiments.reach.objects` defined in "toolkit/components/telemetry/Events.yaml"
|
||||
//
|
||||
// Note: although Events telemetry only takes "_", you can still have "-"(s) in
|
||||
// the group names here. They will be automatically swapped whenever needed.
|
||||
const REACH_EVENT_GROUPS = ["cfr"];
|
||||
const REACH_EVENT_CATEGORY = "messaging_experiments";
|
||||
const REACH_EVENT_METHOD = "reach";
|
||||
|
||||
// Experiment recipe collection ID on RemoteSettings
|
||||
const COLLECTION_ID = "messaging-experiments";
|
||||
|
||||
/**
|
||||
* A module for processes Experiment recipes, choosing and storing enrollment state,
|
||||
* and sending experiment-related Telemetry.
|
||||
|
@ -142,10 +123,6 @@ class _ExperimentManager {
|
|||
}
|
||||
}
|
||||
|
||||
if (activeExperiments.length) {
|
||||
requestIdleCallback(() => this.sendReachEvents());
|
||||
}
|
||||
|
||||
this.sessions.delete(sourceToCheck);
|
||||
}
|
||||
|
||||
|
@ -322,88 +299,6 @@ class _ExperimentManager {
|
|||
const index = await Sampling.ratioSample(input, ratios);
|
||||
return branches[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends Reach events for active experiments
|
||||
*
|
||||
* Note:
|
||||
*
|
||||
* * To avoid interrupting the enrollment process, this is done in a browser
|
||||
* idle callback other than in `this.onRecipe()` or `this.enroll()`
|
||||
*
|
||||
* @param {RemoteSettings} remoteSettingsClient for test only
|
||||
*
|
||||
*/
|
||||
async sendReachEvents(remoteSettingsClient) {
|
||||
let recipes;
|
||||
|
||||
for (const group of REACH_EVENT_GROUPS) {
|
||||
const experiment = this.store.getExperimentForGroup(group);
|
||||
if (!experiment) {
|
||||
log.debug("Skipping sending Reach events for no active experiment");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Need recipes for the branches information. Note that it defers the
|
||||
// RemoteSettings call until seeing the first active experiment that
|
||||
// might record a reach event.
|
||||
if (!recipes) {
|
||||
try {
|
||||
const client = remoteSettingsClient || RemoteSettings(COLLECTION_ID);
|
||||
// Do not sync if it's empty, let RemoteSettingsExperimentLoader do that
|
||||
recipes = await client.get({ syncIfEmpty: false });
|
||||
} catch (e) {
|
||||
log.debug(
|
||||
"Reach events not recorded, error getting recipes from remote settings"
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const recipe = recipes.find(
|
||||
recipe => recipe.arguments.slug === experiment.slug
|
||||
);
|
||||
if (!recipe) {
|
||||
log.debug(
|
||||
"Can't find experiment recipe, skipping sending Reach events"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check targeting for every branch, and only record those qualified ones
|
||||
let qualifiedBranches = [];
|
||||
for (const branch of recipe.arguments.branches) {
|
||||
if (
|
||||
branch.value?.content?.targeting &&
|
||||
Boolean(
|
||||
await ASRouterTargeting.isMatch(
|
||||
branch.value.content.targeting,
|
||||
this.filterContext,
|
||||
err => {
|
||||
log.debug("Targeting failed because of an error");
|
||||
Cu.reportError(err);
|
||||
}
|
||||
)
|
||||
)
|
||||
) {
|
||||
qualifiedBranches.push(branch.slug);
|
||||
}
|
||||
}
|
||||
|
||||
if (qualifiedBranches.length) {
|
||||
// Events telemetry only takes underscore
|
||||
const underscored = group.split("-").join("_");
|
||||
const extra = { branches: qualifiedBranches.join(";") };
|
||||
Services.telemetry.recordEvent(
|
||||
REACH_EVENT_CATEGORY,
|
||||
REACH_EVENT_METHOD,
|
||||
underscored,
|
||||
experiment.slug,
|
||||
extra
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ExperimentManager = new _ExperimentManager();
|
||||
|
|
|
@ -1,234 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
const { ExperimentFakes } = ChromeUtils.import(
|
||||
"resource://testing-common/MSTestUtils.jsm"
|
||||
);
|
||||
|
||||
const { TelemetryTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/TelemetryTestUtils.jsm"
|
||||
);
|
||||
|
||||
const EVENT_CATEGORY = "messaging_experiments";
|
||||
const EVENT_METHOD = "reach";
|
||||
const EVENT_OBJECT = "cfr";
|
||||
const COLLECTION_ID = "messaging-experiments";
|
||||
|
||||
const fakeRemoteSettingsClient = {
|
||||
get() {},
|
||||
};
|
||||
|
||||
add_task(async function test_sendReachEvents() {
|
||||
const sandbox = sinon.createSandbox();
|
||||
const manager = ExperimentFakes.manager();
|
||||
const experiment = ExperimentFakes.experiment("cfr_exp_01");
|
||||
const RECIPE_CFR = {
|
||||
arguments: ExperimentFakes.recipe("cfr_exp_01", {
|
||||
branches: [
|
||||
{
|
||||
slug: "control",
|
||||
value: {
|
||||
content: {
|
||||
targeting: "true",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: "variant_1",
|
||||
value: {
|
||||
content: {
|
||||
targeting: "false",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: "variant_2",
|
||||
value: {
|
||||
content: {
|
||||
targeting: "true",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
};
|
||||
const RECIPE_FOO = {
|
||||
arguments: ExperimentFakes.recipe("foo", {
|
||||
branches: [
|
||||
{
|
||||
slug: "control",
|
||||
value: {
|
||||
content: {
|
||||
targeting: "true",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: "variant_1",
|
||||
value: {
|
||||
content: {
|
||||
targeting: "true",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
};
|
||||
sandbox.stub(manager.store, "getExperimentForGroup").returns(experiment);
|
||||
sandbox
|
||||
.stub(fakeRemoteSettingsClient, "get")
|
||||
.returns([RECIPE_CFR, RECIPE_FOO]);
|
||||
|
||||
const extra = { branches: "control;variant_2" };
|
||||
const expectedEvents = [
|
||||
[EVENT_CATEGORY, EVENT_METHOD, EVENT_OBJECT, "cfr_exp_01", extra],
|
||||
];
|
||||
|
||||
Services.telemetry.setEventRecordingEnabled(EVENT_CATEGORY, true);
|
||||
Services.telemetry.clearEvents();
|
||||
|
||||
await manager.sendReachEvents(fakeRemoteSettingsClient);
|
||||
|
||||
TelemetryTestUtils.assertEvents(expectedEvents);
|
||||
|
||||
Services.telemetry.setEventRecordingEnabled(EVENT_CATEGORY, false);
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
add_task(async function test_sendReachEvents_Failuure_RemoteSettings() {
|
||||
const sandbox = sinon.createSandbox();
|
||||
const manager = ExperimentFakes.manager();
|
||||
const experiment = ExperimentFakes.experiment("cfr_exp_01");
|
||||
sandbox.stub(manager.store, "getExperimentForGroup").returns(experiment);
|
||||
sandbox.stub(fakeRemoteSettingsClient, "get").throws();
|
||||
|
||||
Services.telemetry.setEventRecordingEnabled(EVENT_CATEGORY, true);
|
||||
Services.telemetry.clearEvents();
|
||||
|
||||
await manager.sendReachEvents(fakeRemoteSettingsClient);
|
||||
|
||||
TelemetryTestUtils.assertNumberOfEvents(0);
|
||||
|
||||
Services.telemetry.setEventRecordingEnabled(EVENT_CATEGORY, false);
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
add_task(async function test_sendReachEvents_Failure_No_Active() {
|
||||
const sandbox = sinon.createSandbox();
|
||||
const manager = ExperimentFakes.manager();
|
||||
const RECIPE_CFR = {
|
||||
arguments: ExperimentFakes.recipe("cfr_exp_01", {
|
||||
branches: [
|
||||
{
|
||||
slug: "control",
|
||||
value: {
|
||||
content: {
|
||||
targeting: "true",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: "variant_1",
|
||||
value: {
|
||||
content: {
|
||||
targeting: "true",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
};
|
||||
sandbox.stub(manager.store, "getExperimentForGroup").returns(undefined);
|
||||
sandbox.stub(fakeRemoteSettingsClient, "get").resolves([RECIPE_CFR]);
|
||||
|
||||
Services.telemetry.setEventRecordingEnabled(EVENT_CATEGORY, true);
|
||||
Services.telemetry.clearEvents();
|
||||
|
||||
await manager.sendReachEvents(fakeRemoteSettingsClient);
|
||||
|
||||
TelemetryTestUtils.assertNumberOfEvents(0);
|
||||
|
||||
Services.telemetry.setEventRecordingEnabled(EVENT_CATEGORY, false);
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
add_task(async function test_sendReachEvents_Failure_No_Recipe() {
|
||||
const sandbox = sinon.createSandbox();
|
||||
const manager = ExperimentFakes.manager();
|
||||
const experiment = ExperimentFakes.experiment("cfr_exp_01", {
|
||||
active: false,
|
||||
});
|
||||
const RECIPE_CFR = {
|
||||
arguments: ExperimentFakes.recipe("cfr_exp_02", {
|
||||
branches: [
|
||||
{
|
||||
slug: "control",
|
||||
value: {
|
||||
content: {
|
||||
targeting: "true",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: "variant_1",
|
||||
value: {
|
||||
content: {
|
||||
targeting: "true",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
};
|
||||
sandbox.stub(manager.store, "getExperimentForGroup").returns(experiment);
|
||||
sandbox.stub(fakeRemoteSettingsClient, "get").resolves([RECIPE_CFR]);
|
||||
|
||||
Services.telemetry.setEventRecordingEnabled(EVENT_CATEGORY, true);
|
||||
Services.telemetry.clearEvents();
|
||||
|
||||
await manager.sendReachEvents(fakeRemoteSettingsClient);
|
||||
|
||||
TelemetryTestUtils.assertNumberOfEvents(0);
|
||||
|
||||
Services.telemetry.setEventRecordingEnabled(EVENT_CATEGORY, false);
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
add_task(async function test_sendReachEvents_Failure_No_Qualified() {
|
||||
const sandbox = sinon.createSandbox();
|
||||
const manager = ExperimentFakes.manager();
|
||||
const experiment = ExperimentFakes.experiment("cfr_exp_01");
|
||||
const RECIPE_CFR = {
|
||||
arguments: ExperimentFakes.recipe("cfr_exp_01", {
|
||||
branches: [
|
||||
{
|
||||
slug: "control",
|
||||
value: {
|
||||
content: {
|
||||
targeting: "false",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: "variant_1",
|
||||
value: {
|
||||
content: {
|
||||
targeting: "false",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
};
|
||||
sandbox.stub(manager.store, "getExperimentForGroup").returns(experiment);
|
||||
sandbox.stub(fakeRemoteSettingsClient, "get").resolves([RECIPE_CFR]);
|
||||
|
||||
Services.telemetry.setEventRecordingEnabled(EVENT_CATEGORY, true);
|
||||
Services.telemetry.clearEvents();
|
||||
|
||||
await manager.sendReachEvents(fakeRemoteSettingsClient);
|
||||
|
||||
TelemetryTestUtils.assertNumberOfEvents(0);
|
||||
|
||||
Services.telemetry.setEventRecordingEnabled(EVENT_CATEGORY, false);
|
||||
sandbox.restore();
|
||||
});
|
|
@ -5,7 +5,6 @@ firefox-appdir = browser
|
|||
|
||||
[test_ExperimentManager_enroll.js]
|
||||
[test_ExperimentManager_lifecycle.js]
|
||||
[test_ExperimentManager_reach.js]
|
||||
[test_ExperimentManager_unenroll.js]
|
||||
[test_ExperimentStore.js]
|
||||
[test_SharedDataMap.js]
|
||||
|
|
Загрузка…
Ссылка в новой задаче