зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1650104 - Enable reach event for Moments Page experiments r=andreio
Differential Revision: https://phabricator.services.mozilla.com/D82770
This commit is contained in:
Родитель
396a329ec4
Коммит
dc03a7eeaf
|
@ -111,7 +111,7 @@ const USE_REMOTE_L10N_PREF =
|
||||||
// Experiment groups that need to report the reach event in Messaging-Experiments.
|
// 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
|
// 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"
|
// `messaging_experiments.reach.objects` defined in "toolkit/components/telemetry/Events.yaml"
|
||||||
const REACH_EVENT_GROUPS = ["cfr"];
|
const REACH_EVENT_GROUPS = ["cfr", "moments-page"];
|
||||||
const REACH_EVENT_CATEGORY = "messaging_experiments";
|
const REACH_EVENT_CATEGORY = "messaging_experiments";
|
||||||
const REACH_EVENT_METHOD = "reach";
|
const REACH_EVENT_METHOD = "reach";
|
||||||
|
|
||||||
|
@ -383,7 +383,7 @@ const MessageLoaderUtils = {
|
||||||
) {
|
) {
|
||||||
experiments.push({
|
experiments.push({
|
||||||
group,
|
group,
|
||||||
forReachEvent: true,
|
forReachEvent: { sent: false },
|
||||||
experimentSlug: experimentData.slug,
|
experimentSlug: experimentData.slug,
|
||||||
branchSlug: branch.slug,
|
branchSlug: branch.slug,
|
||||||
...branch.value,
|
...branch.value,
|
||||||
|
@ -2045,7 +2045,10 @@ class _ASRouter {
|
||||||
const nonReachMessages = [];
|
const nonReachMessages = [];
|
||||||
for (const message of messages) {
|
for (const message of messages) {
|
||||||
if (message.forReachEvent) {
|
if (message.forReachEvent) {
|
||||||
|
if (!message.forReachEvent.sent) {
|
||||||
this._recordReachEvent(message);
|
this._recordReachEvent(message);
|
||||||
|
message.forReachEvent.sent = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
nonReachMessages.push(message);
|
nonReachMessages.push(message);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,13 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||||
const SYSTEM_TICK_INTERVAL = 5 * 60 * 1000;
|
const SYSTEM_TICK_INTERVAL = 5 * 60 * 1000;
|
||||||
const HOMEPAGE_OVERRIDE_PREF = "browser.startup.homepage_override.once";
|
const HOMEPAGE_OVERRIDE_PREF = "browser.startup.homepage_override.once";
|
||||||
|
|
||||||
|
// For the "reach" event of Messaging Experiments
|
||||||
|
const REACH_EVENT_CATEGORY = "messaging_experiments";
|
||||||
|
const REACH_EVENT_METHOD = "reach";
|
||||||
|
// Note it's not "moments-page" as Telemetry Events only accepts understores
|
||||||
|
// for the event `object`
|
||||||
|
const REACH_EVENT_OBJECT = "moments_page";
|
||||||
|
|
||||||
class _MomentsPageHub {
|
class _MomentsPageHub {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.id = "moments-page-hub";
|
this.id = "moments-page-hub";
|
||||||
|
@ -97,16 +104,42 @@ class _MomentsPageHub {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_recordReachEvent(message) {
|
||||||
|
const extra = { branches: message.branchSlug };
|
||||||
|
Services.telemetry.recordEvent(
|
||||||
|
REACH_EVENT_CATEGORY,
|
||||||
|
REACH_EVENT_METHOD,
|
||||||
|
REACH_EVENT_OBJECT,
|
||||||
|
message.experimentSlug,
|
||||||
|
extra
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async messageRequest({ triggerId, template }) {
|
async messageRequest({ triggerId, template }) {
|
||||||
const telemetryObject = { triggerId };
|
const telemetryObject = { triggerId };
|
||||||
TelemetryStopwatch.start("MS_MESSAGE_REQUEST_TIME_MS", telemetryObject);
|
TelemetryStopwatch.start("MS_MESSAGE_REQUEST_TIME_MS", telemetryObject);
|
||||||
const message = await this._handleMessageRequest({
|
const messages = await this._handleMessageRequest({
|
||||||
triggerId,
|
triggerId,
|
||||||
template,
|
template,
|
||||||
|
returnAll: true,
|
||||||
});
|
});
|
||||||
TelemetryStopwatch.finish("MS_MESSAGE_REQUEST_TIME_MS", telemetryObject);
|
TelemetryStopwatch.finish("MS_MESSAGE_REQUEST_TIME_MS", telemetryObject);
|
||||||
if (message) {
|
|
||||||
this.executeAction(message);
|
// Record the "reach" event for all the messages with `forReachEvent`,
|
||||||
|
// only execute action for the first message without forReachEvent.
|
||||||
|
const nonReachMessages = [];
|
||||||
|
for (const message of messages) {
|
||||||
|
if (message.forReachEvent) {
|
||||||
|
if (!message.forReachEvent.sent) {
|
||||||
|
this._recordReachEvent(message);
|
||||||
|
message.forReachEvent.sent = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nonReachMessages.push(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nonReachMessages.length) {
|
||||||
|
this.executeAction(nonReachMessages[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2333,7 +2333,7 @@ describe("ASRouter", () => {
|
||||||
let messages = [
|
let messages = [
|
||||||
{
|
{
|
||||||
id: "foo1",
|
id: "foo1",
|
||||||
forReachEvent: true,
|
forReachEvent: { sent: false },
|
||||||
experimentSlug: "exp01",
|
experimentSlug: "exp01",
|
||||||
branchSlug: "branch01",
|
branchSlug: "branch01",
|
||||||
group: "cfr",
|
group: "cfr",
|
||||||
|
@ -2351,7 +2351,7 @@ describe("ASRouter", () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "foo3",
|
id: "foo3",
|
||||||
forReachEvent: true,
|
forReachEvent: { sent: false },
|
||||||
experimentSlug: "exp02",
|
experimentSlug: "exp02",
|
||||||
branchSlug: "branch02",
|
branchSlug: "branch02",
|
||||||
group: "cfr",
|
group: "cfr",
|
||||||
|
@ -2371,6 +2371,30 @@ describe("ASRouter", () => {
|
||||||
await Router.onMessage(msg);
|
await Router.onMessage(msg);
|
||||||
assert.calledTwice(Services.telemetry.recordEvent);
|
assert.calledTwice(Services.telemetry.recordEvent);
|
||||||
});
|
});
|
||||||
|
it("should not record the Reach event if it's already sent", async () => {
|
||||||
|
let messages = [
|
||||||
|
{
|
||||||
|
id: "foo1",
|
||||||
|
forReachEvent: { sent: true },
|
||||||
|
experimentSlug: "exp01",
|
||||||
|
branchSlug: "branch01",
|
||||||
|
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.notCalled(Services.telemetry.recordEvent);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe(".includeBundle", () => {
|
describe(".includeBundle", () => {
|
||||||
|
@ -4109,7 +4133,7 @@ describe("ASRouter", () => {
|
||||||
assert.equal(result.messages[1].group, "cfr");
|
assert.equal(result.messages[1].group, "cfr");
|
||||||
assert.equal(result.messages[1].experimentSlug, "exp01");
|
assert.equal(result.messages[1].experimentSlug, "exp01");
|
||||||
assert.equal(result.messages[1].branchSlug, "branch02");
|
assert.equal(result.messages[1].branchSlug, "branch02");
|
||||||
assert.ok(result.messages[1].forReachEvent);
|
assert.deepEqual(result.messages[1].forReachEvent, { sent: false });
|
||||||
});
|
});
|
||||||
it("should fetch json from url", async () => {
|
it("should fetch json from url", async () => {
|
||||||
let result = await MessageLoaderUtils.loadMessagesForProvider({
|
let result = await MessageLoaderUtils.loadMessagesForProvider({
|
||||||
|
|
|
@ -20,10 +20,10 @@ describe("MomentsPageHub", () => {
|
||||||
globals = new GlobalOverrider();
|
globals = new GlobalOverrider();
|
||||||
sandbox = sinon.createSandbox();
|
sandbox = sinon.createSandbox();
|
||||||
instance = new _MomentsPageHub();
|
instance = new _MomentsPageHub();
|
||||||
const [msg] = (await PanelTestProvider.getMessages()).filter(
|
const messages = (await PanelTestProvider.getMessages()).filter(
|
||||||
({ template }) => template === "update_action"
|
({ template }) => template === "update_action"
|
||||||
);
|
);
|
||||||
handleMessageRequestStub = sandbox.stub().resolves(msg);
|
handleMessageRequestStub = sandbox.stub().resolves(messages);
|
||||||
addImpressionStub = sandbox.stub();
|
addImpressionStub = sandbox.stub();
|
||||||
blockMessageByIdStub = sandbox.stub();
|
blockMessageByIdStub = sandbox.stub();
|
||||||
getStringPrefStub = sandbox.stub();
|
getStringPrefStub = sandbox.stub();
|
||||||
|
@ -39,6 +39,9 @@ describe("MomentsPageHub", () => {
|
||||||
getStringPref: getStringPrefStub,
|
getStringPref: getStringPrefStub,
|
||||||
setStringPref: setStringPrefStub,
|
setStringPref: setStringPrefStub,
|
||||||
},
|
},
|
||||||
|
telemetry: {
|
||||||
|
recordEvent: () => {},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -101,12 +104,13 @@ describe("MomentsPageHub", () => {
|
||||||
assert.calledWithExactly(handleMessageRequestStub, {
|
assert.calledWithExactly(handleMessageRequestStub, {
|
||||||
triggerId: "trigger",
|
triggerId: "trigger",
|
||||||
template: "template",
|
template: "template",
|
||||||
|
returnAll: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("shouldn't do anything if no message is provided", async () => {
|
it("shouldn't do anything if no message is provided", async () => {
|
||||||
// Reset the call from `instance.init`
|
// Reset the call from `instance.init`
|
||||||
setStringPrefStub.reset();
|
setStringPrefStub.reset();
|
||||||
handleMessageRequestStub.resolves(null);
|
handleMessageRequestStub.resolves([]);
|
||||||
await instance.messageRequest({ triggerId: "trigger" });
|
await instance.messageRequest({ triggerId: "trigger" });
|
||||||
|
|
||||||
assert.notCalled(setStringPrefStub);
|
assert.notCalled(setStringPrefStub);
|
||||||
|
@ -136,6 +140,59 @@ describe("MomentsPageHub", () => {
|
||||||
{ triggerId: "trigger" }
|
{ triggerId: "trigger" }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it("should record Reach event for the Moments page experiment", async () => {
|
||||||
|
const momentsMessages = (await PanelTestProvider.getMessages()).filter(
|
||||||
|
({ template }) => template === "update_action"
|
||||||
|
);
|
||||||
|
const messages = [
|
||||||
|
{
|
||||||
|
forReachEvent: { sent: false },
|
||||||
|
experimentSlug: "foo",
|
||||||
|
branchSlug: "bar",
|
||||||
|
},
|
||||||
|
...momentsMessages,
|
||||||
|
];
|
||||||
|
handleMessageRequestStub.resolves(messages);
|
||||||
|
sandbox.spy(global.Services.telemetry, "recordEvent");
|
||||||
|
sandbox.spy(instance, "executeAction");
|
||||||
|
|
||||||
|
await instance.messageRequest({ triggerId: "trigger" });
|
||||||
|
|
||||||
|
assert.calledOnce(global.Services.telemetry.recordEvent);
|
||||||
|
assert.calledOnce(instance.executeAction);
|
||||||
|
});
|
||||||
|
it("should not record the Reach event if it's already sent", async () => {
|
||||||
|
const messages = [
|
||||||
|
{
|
||||||
|
forReachEvent: { sent: true },
|
||||||
|
experimentSlug: "foo",
|
||||||
|
branchSlug: "bar",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
handleMessageRequestStub.resolves(messages);
|
||||||
|
sandbox.spy(global.Services.telemetry, "recordEvent");
|
||||||
|
|
||||||
|
await instance.messageRequest({ triggerId: "trigger" });
|
||||||
|
|
||||||
|
assert.notCalled(global.Services.telemetry.recordEvent);
|
||||||
|
});
|
||||||
|
it("should not trigger the action if it's only for the Reach event", async () => {
|
||||||
|
const messages = [
|
||||||
|
{
|
||||||
|
forReachEvent: { sent: false },
|
||||||
|
experimentSlug: "foo",
|
||||||
|
branchSlug: "bar",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
handleMessageRequestStub.resolves(messages);
|
||||||
|
sandbox.spy(global.Services.telemetry, "recordEvent");
|
||||||
|
sandbox.spy(instance, "executeAction");
|
||||||
|
|
||||||
|
await instance.messageRequest({ triggerId: "trigger" });
|
||||||
|
|
||||||
|
assert.calledOnce(global.Services.telemetry.recordEvent);
|
||||||
|
assert.notCalled(instance.executeAction);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
describe("executeAction", () => {
|
describe("executeAction", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
@ -147,7 +204,7 @@ describe("MomentsPageHub", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("should set HOMEPAGE_OVERRIDE_PREF on `moments-wnp` action", async () => {
|
it("should set HOMEPAGE_OVERRIDE_PREF on `moments-wnp` action", async () => {
|
||||||
const msg = await handleMessageRequestStub();
|
const [msg] = await handleMessageRequestStub();
|
||||||
sandbox.useFakeTimers();
|
sandbox.useFakeTimers();
|
||||||
instance.executeAction(msg);
|
instance.executeAction(msg);
|
||||||
|
|
||||||
|
@ -165,7 +222,7 @@ describe("MomentsPageHub", () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("should block after taking the action", async () => {
|
it("should block after taking the action", async () => {
|
||||||
const msg = await handleMessageRequestStub();
|
const [msg] = await handleMessageRequestStub();
|
||||||
instance.executeAction(msg);
|
instance.executeAction(msg);
|
||||||
|
|
||||||
assert.calledOnce(blockMessageByIdStub);
|
assert.calledOnce(blockMessageByIdStub);
|
||||||
|
@ -174,7 +231,7 @@ describe("MomentsPageHub", () => {
|
||||||
it("should compute expire based on expireDelta", async () => {
|
it("should compute expire based on expireDelta", async () => {
|
||||||
sandbox.spy(instance, "getExpirationDate");
|
sandbox.spy(instance, "getExpirationDate");
|
||||||
|
|
||||||
const msg = await handleMessageRequestStub();
|
const [msg] = await handleMessageRequestStub();
|
||||||
instance.executeAction(msg);
|
instance.executeAction(msg);
|
||||||
|
|
||||||
assert.calledOnce(instance.getExpirationDate);
|
assert.calledOnce(instance.getExpirationDate);
|
||||||
|
@ -186,7 +243,7 @@ describe("MomentsPageHub", () => {
|
||||||
it("should compute expire based on expireDelta", async () => {
|
it("should compute expire based on expireDelta", async () => {
|
||||||
sandbox.spy(instance, "getExpirationDate");
|
sandbox.spy(instance, "getExpirationDate");
|
||||||
|
|
||||||
const msg = await handleMessageRequestStub();
|
const [msg] = await handleMessageRequestStub();
|
||||||
const msgWithExpire = {
|
const msgWithExpire = {
|
||||||
...msg,
|
...msg,
|
||||||
content: {
|
content: {
|
||||||
|
@ -212,7 +269,7 @@ describe("MomentsPageHub", () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("should send user telemetry", async () => {
|
it("should send user telemetry", async () => {
|
||||||
const msg = await handleMessageRequestStub();
|
const [msg] = await handleMessageRequestStub();
|
||||||
const sendUserEventTelemetrySpy = sandbox.spy(
|
const sendUserEventTelemetrySpy = sandbox.spy(
|
||||||
instance,
|
instance,
|
||||||
"sendUserEventTelemetry"
|
"sendUserEventTelemetry"
|
||||||
|
|
Загрузка…
Ссылка в новой задаче