diff options
Diffstat (limited to '')
-rw-r--r-- | toolkit/components/normandy/test/browser/browser_ClientEnvironment.js | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/toolkit/components/normandy/test/browser/browser_ClientEnvironment.js b/toolkit/components/normandy/test/browser/browser_ClientEnvironment.js new file mode 100644 index 0000000000..1b6d2c5ff9 --- /dev/null +++ b/toolkit/components/normandy/test/browser/browser_ClientEnvironment.js @@ -0,0 +1,274 @@ +"use strict"; + +const { TelemetryController } = ChromeUtils.importESModule( + "resource://gre/modules/TelemetryController.sys.mjs" +); + +const { AddonRollouts } = ChromeUtils.importESModule( + "resource://normandy/lib/AddonRollouts.sys.mjs" +); +const { ClientEnvironment } = ChromeUtils.importESModule( + "resource://normandy/lib/ClientEnvironment.sys.mjs" +); +const { PreferenceExperiments } = ChromeUtils.importESModule( + "resource://normandy/lib/PreferenceExperiments.sys.mjs" +); +const { PreferenceRollouts } = ChromeUtils.importESModule( + "resource://normandy/lib/PreferenceRollouts.sys.mjs" +); +const { RecipeRunner } = ChromeUtils.importESModule( + "resource://normandy/lib/RecipeRunner.sys.mjs" +); +const { NormandyTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/NormandyTestUtils.sys.mjs" +); + +add_task(async function testTelemetry() { + // setup + await SpecialPowers.pushPrefEnv({ + set: [["privacy.reduceTimerPrecision", true]], + }); + + await TelemetryController.submitExternalPing("testfoo", { foo: 1 }); + await TelemetryController.submitExternalPing("testbar", { bar: 2 }); + await TelemetryController.submitExternalPing("testfoo", { foo: 3 }); + + // Test it can access telemetry + const telemetry = await ClientEnvironment.telemetry; + is(typeof telemetry, "object", "Telemetry is accesible"); + + // Test it reads different types of telemetry + is( + telemetry.testfoo.payload.foo, + 3, + "telemetry filters pull the latest ping from a type" + ); + is( + telemetry.testbar.payload.bar, + 2, + "telemetry filters pull from submitted telemetry pings" + ); +}); + +add_task(async function testUserId() { + // Test that userId is available + ok(NormandyTestUtils.isUuid(ClientEnvironment.userId), "userId available"); + + // test that it pulls from the right preference + await SpecialPowers.pushPrefEnv({ + set: [["app.normandy.user_id", "fake id"]], + }); + is(ClientEnvironment.userId, "fake id", "userId is pulled from preferences"); +}); + +add_task(async function testDistribution() { + // distribution id defaults to "default" for most builds, and + // "mozilla-MSIX" for MSIX builds. + is( + ClientEnvironment.distribution, + AppConstants.platform === "win" && + Services.sysinfo.getProperty("hasWinPackageId") + ? "mozilla-MSIX" + : "default", + "distribution has a default value" + ); + + // distribution id is read from a preference + Services.prefs + .getDefaultBranch(null) + .setStringPref("distribution.id", "funnelcake"); + is( + ClientEnvironment.distribution, + "funnelcake", + "distribution is read from preferences" + ); + Services.prefs + .getDefaultBranch(null) + .setStringPref("distribution.id", "default"); +}); + +const mockClassify = { country: "FR", request_time: new Date(2017, 1, 1) }; +add_task( + ClientEnvironment.withMockClassify( + mockClassify, + async function testCountryRequestTime() { + // Test that country and request_time pull their data from the server. + is( + await ClientEnvironment.country, + mockClassify.country, + "country is read from the server API" + ); + is( + await ClientEnvironment.request_time, + mockClassify.request_time, + "request_time is read from the server API" + ); + } + ) +); + +add_task(async function testSync() { + is( + ClientEnvironment.syncMobileDevices, + 0, + "syncMobileDevices defaults to zero" + ); + is( + ClientEnvironment.syncDesktopDevices, + 0, + "syncDesktopDevices defaults to zero" + ); + is( + ClientEnvironment.syncTotalDevices, + 0, + "syncTotalDevices defaults to zero" + ); + await SpecialPowers.pushPrefEnv({ + set: [ + ["services.sync.clients.devices.mobile", 5], + ["services.sync.clients.devices.desktop", 4], + ], + }); + is( + ClientEnvironment.syncMobileDevices, + 5, + "syncMobileDevices is read when set" + ); + is( + ClientEnvironment.syncDesktopDevices, + 4, + "syncDesktopDevices is read when set" + ); + is( + ClientEnvironment.syncTotalDevices, + 9, + "syncTotalDevices is read when set" + ); +}); + +add_task(async function testDoNotTrack() { + // doNotTrack defaults to false + ok(!ClientEnvironment.doNotTrack, "doNotTrack has a default value"); + + // doNotTrack is read from a preference + await SpecialPowers.pushPrefEnv({ + set: [["privacy.donottrackheader.enabled", true]], + }); + ok(ClientEnvironment.doNotTrack, "doNotTrack is read from preferences"); +}); + +add_task(async function testExperiments() { + const active = { slug: "active", expired: false }; + const expired = { slug: "expired", expired: true }; + const getAll = sinon + .stub(PreferenceExperiments, "getAll") + .callsFake(async () => [active, expired]); + + const experiments = await ClientEnvironment.experiments; + Assert.deepEqual( + experiments.all, + ["active", "expired"], + "experiments.all returns all stored experiment names" + ); + Assert.deepEqual( + experiments.active, + ["active"], + "experiments.active returns all active experiment names" + ); + Assert.deepEqual( + experiments.expired, + ["expired"], + "experiments.expired returns all expired experiment names" + ); + + getAll.restore(); +}); + +add_task(async function isFirstRun() { + await SpecialPowers.pushPrefEnv({ set: [["app.normandy.first_run", true]] }); + ok(ClientEnvironment.isFirstRun, "isFirstRun is read from preferences"); +}); + +decorate_task( + PreferenceExperiments.withMockExperiments([ + NormandyTestUtils.factories.preferenceStudyFactory({ + branch: "a-test-branch", + }), + ]), + AddonStudies.withStudies([ + NormandyTestUtils.factories.branchedAddonStudyFactory({ + branch: "b-test-branch", + }), + ]), + async function testStudies({ + prefExperiments: [prefExperiment], + addonStudies: [addonStudy], + }) { + Assert.deepEqual( + await ClientEnvironment.studies, + { + pref: { + [prefExperiment.slug]: prefExperiment, + }, + addon: { + [addonStudy.slug]: addonStudy, + }, + }, + "addon and preference studies shold be accessible" + ); + is( + (await ClientEnvironment.studies).pref[prefExperiment.slug].branch, + "a-test-branch", + "A specific preference experiment field should be accessible in the context" + ); + is( + (await ClientEnvironment.studies).addon[addonStudy.slug].branch, + "b-test-branch", + "A specific addon study field should be accessible in the context" + ); + + ok(RecipeRunner.getCapabilities().has("jexl.context.normandy.studies")); + ok(RecipeRunner.getCapabilities().has("jexl.context.env.studies")); + } +); + +decorate_task(PreferenceRollouts.withTestMock(), async function testRollouts() { + const prefRollout = { + slug: "test-rollout", + preference: [], + enrollmentId: "test-enrollment-id-1", + }; + await PreferenceRollouts.add(prefRollout); + const addonRollout = { + slug: "test-rollout-1", + extension: {}, + enrollmentId: "test-enrollment-id-2", + }; + await AddonRollouts.add(addonRollout); + + Assert.deepEqual( + await ClientEnvironment.rollouts, + { + pref: { + [prefRollout.slug]: prefRollout, + }, + addon: { + [addonRollout.slug]: addonRollout, + }, + }, + "addon and preference rollouts should be accessible" + ); + is( + (await ClientEnvironment.rollouts).pref[prefRollout.slug].enrollmentId, + "test-enrollment-id-1", + "A specific preference rollout field should be accessible in the context" + ); + is( + (await ClientEnvironment.rollouts).addon[addonRollout.slug].enrollmentId, + "test-enrollment-id-2", + "A specific addon rollout field should be accessible in the context" + ); + + ok(RecipeRunner.getCapabilities().has("jexl.context.normandy.rollouts")); + ok(RecipeRunner.getCapabilities().has("jexl.context.env.rollouts")); +}); |