Bug 1698795 - Add an option to send exposure once per instance r=k88hudson

Differential Revision: https://phabricator.services.mozilla.com/D110944
This commit is contained in:
Andrei Oprea 2021-04-14 08:59:25 +00:00
Родитель 169f3389c2
Коммит 28193cd188
3 изменённых файлов: 124 добавлений и 8 удалений

Просмотреть файл

@ -353,6 +353,7 @@ add_task(async function test_multistage_zeroOnboarding_experimentAPI() {
*/
add_task(async function test_multistage_aboutwelcome_experimentAPI() {
const sandbox = sinon.createSandbox();
NimbusFeatures.aboutwelcome._sendExposureEventOnce = true;
await setAboutWelcomePref(true);
let {
@ -482,8 +483,7 @@ add_task(async function test_multistage_aboutwelcome_experimentAPI() {
scalars,
"telemetry.event_counts",
"normandy#expose#nimbus_experiment",
// AboutNewTabService.welcomeURL seems to be called multiple times in the process of opening about:welcome, multiple pings get recoreded
2
1
);
await doExperimentCleanup();

Просмотреть файл

@ -361,6 +361,8 @@ class ExperimentFeature {
`No manifest entry for ${featureId}. Please add one to toolkit/components/messaging-system/experiments/ExperimentAPI.jsm`
);
}
// Prevent the instance from sending multiple exposure events
this._sendExposureEventOnce = true;
this._onRemoteReady = null;
this._waitForRemote = new Promise(
resolve => (this._onRemoteReady = resolve)
@ -458,9 +460,14 @@ class ExperimentFeature {
isEnabled({ sendExposureEvent, defaultValue = null } = {}) {
const branch = ExperimentAPI.activateBranch({
featureId: this.featureId,
sendExposureEvent,
sendExposureEvent: sendExposureEvent && this._sendExposureEventOnce,
});
// Prevent future exposure events if user is enrolled in an experiment
if (branch && sendExposureEvent) {
this._sendExposureEventOnce = false;
}
// First, try to return an experiment value if it exists.
if (isBooleanValueDefined(branch?.feature.enabled)) {
return branch.feature.enabled;
@ -490,8 +497,14 @@ class ExperimentFeature {
let userPrefs = this._getUserPrefsValues();
const branch = ExperimentAPI.activateBranch({
featureId: this.featureId,
sendExposureEvent,
sendExposureEvent: sendExposureEvent && this._sendExposureEventOnce,
});
// Prevent future exposure events if user is enrolled in an experiment
if (branch && sendExposureEvent) {
this._sendExposureEventOnce = false;
}
if (branch?.feature?.value) {
return { ...branch.feature.value, ...userPrefs };
}
@ -516,10 +529,17 @@ class ExperimentFeature {
}
recordExposureEvent() {
ExperimentAPI.activateBranch({
if (this._sendExposureEventOnce) {
let experimentData = ExperimentAPI.activateBranch({
featureId: this.featureId,
sendExposureEvent: true,
});
// Exposure only sent if user is enrolled in an experiment
if (experimentData) {
this._sendExposureEventOnce = false;
}
}
}
onUpdate(callback) {

Просмотреть файл

@ -352,3 +352,99 @@ add_task(async function test_record_exposure_event() {
sandbox.restore();
});
add_task(async function test_record_exposure_event_once() {
const { sandbox, manager } = await setupForExperimentFeature();
const featureInstance = new ExperimentFeature("foo", FAKE_FEATURE_MANIFEST);
const exposureSpy = sandbox.spy(ExperimentAPI, "recordExposureEvent");
sandbox.stub(ExperimentAPI, "_store").get(() => manager.store);
manager.store.addExperiment(
ExperimentFakes.experiment("blah", {
featureIds: ["foo"],
branch: {
slug: "treatment",
feature: {
featureId: "foo",
enabled: false,
value: null,
},
},
})
);
featureInstance.recordExposureEvent();
featureInstance.recordExposureEvent();
featureInstance.recordExposureEvent();
Assert.ok(exposureSpy.calledOnce, "Should emit a single exposure event.");
sandbox.restore();
});
add_task(async function test_prevent_double_exposure_getValue() {
const { sandbox, manager } = await setupForExperimentFeature();
const featureInstance = new ExperimentFeature("foo", FAKE_FEATURE_MANIFEST);
const exposureSpy = sandbox.spy(ExperimentAPI, "recordExposureEvent");
sandbox.stub(ExperimentAPI, "_store").get(() => manager.store);
manager.store.addExperiment(
ExperimentFakes.experiment("blah", {
featureIds: ["foo"],
branch: {
slug: "treatment",
feature: {
featureId: "foo",
enabled: false,
value: null,
},
},
})
);
featureInstance.getValue({ sendExposureEvent: true });
featureInstance.getValue({ sendExposureEvent: true });
featureInstance.getValue({ sendExposureEvent: true });
Assert.ok(
exposureSpy.calledOnce,
"Should emit a single exposure event (getValue)."
);
sandbox.restore();
});
add_task(async function test_prevent_double_exposure_isEnabled() {
const { sandbox, manager } = await setupForExperimentFeature();
const featureInstance = new ExperimentFeature("foo", FAKE_FEATURE_MANIFEST);
const exposureSpy = sandbox.spy(ExperimentAPI, "recordExposureEvent");
sandbox.stub(ExperimentAPI, "_store").get(() => manager.store);
manager.store.addExperiment(
ExperimentFakes.experiment("blah", {
featureIds: ["foo"],
branch: {
slug: "treatment",
feature: {
featureId: "foo",
enabled: false,
value: null,
},
},
})
);
featureInstance.isEnabled({ sendExposureEvent: true });
featureInstance.isEnabled({ sendExposureEvent: true });
featureInstance.isEnabled({ sendExposureEvent: true });
Assert.ok(
exposureSpy.calledOnce,
"Should emit a single exposure event (getValue)."
);
sandbox.restore();
});