262 lines
6.5 KiB
JavaScript
262 lines
6.5 KiB
JavaScript
"use strict";
|
|
|
|
const { NimbusTelemetry } = ChromeUtils.importESModule(
|
|
"resource://nimbus/lib/Telemetry.sys.mjs"
|
|
);
|
|
const { PrefUtils } = ChromeUtils.importESModule(
|
|
"resource://normandy/lib/PrefUtils.sys.mjs"
|
|
);
|
|
|
|
const TEST_FALLBACK_PREF = "testprefbranch.config";
|
|
|
|
add_setup(function test_setup() {
|
|
Services.fog.initializeFOG();
|
|
});
|
|
|
|
function setupTest(options) {
|
|
return NimbusTestUtils.setupTest({
|
|
...options,
|
|
clearTelemetry: true,
|
|
features: [
|
|
new ExperimentFeature("foo", {
|
|
variables: {
|
|
enabled: {
|
|
type: "boolean",
|
|
fallbackPref: "testprefbranch.enabled",
|
|
},
|
|
config: {
|
|
type: "json",
|
|
fallbackPref: TEST_FALLBACK_PREF,
|
|
},
|
|
remoteValue: {
|
|
type: "boolean",
|
|
},
|
|
test: {
|
|
type: "boolean",
|
|
},
|
|
title: {
|
|
type: "string",
|
|
},
|
|
},
|
|
}),
|
|
],
|
|
});
|
|
}
|
|
|
|
add_task(async function test_ExperimentFeature_test_helper_ready() {
|
|
const { manager, cleanup } = await setupTest();
|
|
await manager.store.ready();
|
|
|
|
const cleanupExperiment = await NimbusTestUtils.enrollWithFeatureConfig(
|
|
{
|
|
featureId: "foo",
|
|
value: { remoteValue: "mochitest", enabled: true },
|
|
},
|
|
{
|
|
manager,
|
|
isRollout: true,
|
|
}
|
|
);
|
|
|
|
Assert.equal(
|
|
NimbusFeatures.foo.getVariable("remoteValue"),
|
|
"mochitest",
|
|
"set by remote config"
|
|
);
|
|
|
|
await cleanupExperiment();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_record_exposure_event() {
|
|
Services.fog.testResetFOG();
|
|
|
|
const { sandbox, manager, cleanup } = await setupTest();
|
|
|
|
sandbox.spy(NimbusTelemetry, "recordExposure");
|
|
sandbox.spy(NimbusFeatures.foo, "getEnrollmentMetadata");
|
|
|
|
await NimbusTestUtils.assert.storeIsEmpty(manager.store);
|
|
NimbusFeatures.foo.recordExposureEvent();
|
|
|
|
Assert.ok(
|
|
NimbusTelemetry.recordExposure.notCalled,
|
|
"should not emit an exposure event when no experiment is active"
|
|
);
|
|
|
|
// Check that there aren't any Glean exposure events yet
|
|
var exposureEvents = Glean.nimbusEvents.exposure.testGetValue("events");
|
|
Assert.equal(
|
|
undefined,
|
|
exposureEvents,
|
|
"no Glean exposure events before exposure"
|
|
);
|
|
|
|
await manager.enroll(
|
|
NimbusTestUtils.factories.recipe("blah", {
|
|
branches: [
|
|
{
|
|
slug: "treatment",
|
|
ratio: 1,
|
|
features: [
|
|
{
|
|
featureId: "foo",
|
|
value: { enabled: false },
|
|
},
|
|
],
|
|
},
|
|
],
|
|
}),
|
|
"test"
|
|
);
|
|
|
|
NimbusFeatures.foo.recordExposureEvent();
|
|
|
|
Assert.ok(
|
|
NimbusTelemetry.recordExposure.calledOnce,
|
|
"should emit an exposure event when there is an experiment"
|
|
);
|
|
Assert.equal(
|
|
NimbusFeatures.foo.getEnrollmentMetadata.callCount,
|
|
2,
|
|
"Should be called every time"
|
|
);
|
|
|
|
// Check that the Glean exposure event was recorded.
|
|
exposureEvents = Glean.nimbusEvents.exposure.testGetValue("events");
|
|
// We expect only one event
|
|
Assert.equal(1, exposureEvents.length);
|
|
// And that one event matches the expected
|
|
Assert.equal(
|
|
"blah",
|
|
exposureEvents[0].extra.experiment,
|
|
"Glean.nimbusEvents.exposure recorded with correct experiment slug"
|
|
);
|
|
Assert.equal(
|
|
"treatment",
|
|
exposureEvents[0].extra.branch,
|
|
"Glean.nimbusEvents.exposure recorded with correct branch slug"
|
|
);
|
|
Assert.equal(
|
|
"foo",
|
|
exposureEvents[0].extra.feature_id,
|
|
"Glean.nimbusEvents.exposure recorded with correct feature id"
|
|
);
|
|
|
|
sandbox.restore();
|
|
|
|
await manager.unenroll("blah");
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_record_exposure_event_once() {
|
|
const { sandbox, manager, cleanup } = await setupTest();
|
|
|
|
const exposureSpy = sandbox.spy(NimbusTelemetry, "recordExposure");
|
|
|
|
await manager.enroll(
|
|
NimbusTestUtils.factories.recipe.withFeatureConfig("blah", {
|
|
branchSlug: "treatment",
|
|
featureId: "foo",
|
|
value: { enabled: false },
|
|
}),
|
|
"test"
|
|
);
|
|
|
|
NimbusFeatures.foo.recordExposureEvent({ once: true });
|
|
NimbusFeatures.foo.recordExposureEvent({ once: true });
|
|
NimbusFeatures.foo.recordExposureEvent({ once: true });
|
|
|
|
Assert.ok(
|
|
exposureSpy.calledOnce,
|
|
"Should emit a single exposure event when the once param is true."
|
|
);
|
|
|
|
// Check that the Glean exposure event was recorded.
|
|
let exposureEvents = Glean.nimbusEvents.exposure.testGetValue("events");
|
|
// We expect only one event
|
|
Assert.equal(1, exposureEvents.length);
|
|
|
|
await manager.unenroll("blah");
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_allow_multiple_exposure_events() {
|
|
const { sandbox, manager, cleanup } = await setupTest();
|
|
|
|
const exposureSpy = sandbox.spy(NimbusTelemetry, "recordExposure");
|
|
|
|
// Clear any pre-existing data in Glean
|
|
Services.fog.testResetFOG();
|
|
|
|
let doExperimentCleanup = await NimbusTestUtils.enrollWithFeatureConfig(
|
|
{
|
|
featureId: "foo",
|
|
value: { enabled: false },
|
|
},
|
|
{ manager }
|
|
);
|
|
|
|
NimbusFeatures.foo.recordExposureEvent();
|
|
NimbusFeatures.foo.recordExposureEvent();
|
|
NimbusFeatures.foo.recordExposureEvent();
|
|
|
|
Assert.equal(
|
|
exposureSpy.callCount,
|
|
3,
|
|
"Should emit an exposure event for each function call"
|
|
);
|
|
|
|
// Check that the Glean exposure event was recorded.
|
|
let exposureEvents = Glean.nimbusEvents.exposure.testGetValue("events");
|
|
// We expect 3 events
|
|
Assert.equal(3, exposureEvents.length);
|
|
|
|
await doExperimentCleanup();
|
|
await cleanup();
|
|
});
|
|
|
|
add_task(async function test_onUpdate_after_store_ready() {
|
|
const { sandbox, manager, cleanup } = await setupTest();
|
|
const stub = sandbox.stub();
|
|
|
|
const rollout = NimbusTestUtils.factories.rollout("foo", {
|
|
branch: {
|
|
slug: "slug",
|
|
features: [
|
|
{
|
|
featureId: "foo",
|
|
value: {
|
|
title: "hello",
|
|
enabled: true,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
sandbox.stub(manager.store, "getAllActiveRollouts").returns([rollout]);
|
|
|
|
NimbusFeatures.foo.onUpdate(stub);
|
|
|
|
Assert.ok(stub.calledOnce, "Callback called");
|
|
Assert.equal(stub.firstCall.args[0], "featureUpdate:foo");
|
|
Assert.equal(stub.firstCall.args[1], "rollout-updated");
|
|
|
|
PrefUtils.setPref(TEST_FALLBACK_PREF, JSON.stringify({ foo: true }), {
|
|
branch: "default",
|
|
});
|
|
|
|
Assert.deepEqual(
|
|
NimbusFeatures.foo.getVariable("config"),
|
|
{ foo: true },
|
|
"Feature is ready even when initialized after store update"
|
|
);
|
|
Assert.equal(
|
|
NimbusFeatures.foo.getVariable("title"),
|
|
"hello",
|
|
"Returns the NimbusTestUtils rollout default value"
|
|
);
|
|
|
|
await cleanup();
|
|
});
|