diff options
Diffstat (limited to 'toolkit/components/telemetry/tests/unit/test_TelemetryReportingPolicy.js')
-rw-r--r-- | toolkit/components/telemetry/tests/unit/test_TelemetryReportingPolicy.js | 399 |
1 files changed, 399 insertions, 0 deletions
diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryReportingPolicy.js b/toolkit/components/telemetry/tests/unit/test_TelemetryReportingPolicy.js new file mode 100644 index 0000000000..01041172d0 --- /dev/null +++ b/toolkit/components/telemetry/tests/unit/test_TelemetryReportingPolicy.js @@ -0,0 +1,399 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test that TelemetryController sends close to shutdown don't lead +// to AsyncShutdown timeouts. + +"use strict"; + +const { TelemetryReportingPolicy } = ChromeUtils.importESModule( + "resource://gre/modules/TelemetryReportingPolicy.sys.mjs" +); +const { UpdateUtils } = ChromeUtils.importESModule( + "resource://gre/modules/UpdateUtils.sys.mjs" +); + +const TEST_CHANNEL = "TestChannelABC"; + +const PREF_MINIMUM_CHANNEL_POLICY_VERSION = + TelemetryUtils.Preferences.MinimumPolicyVersion + ".channel-" + TEST_CHANNEL; + +function fakeShowPolicyTimeout(set, clear) { + let { Policy } = ChromeUtils.importESModule( + "resource://gre/modules/TelemetryReportingPolicy.sys.mjs" + ); + Policy.setShowInfobarTimeout = set; + Policy.clearShowInfobarTimeout = clear; +} + +function fakeResetAcceptedPolicy() { + Services.prefs.clearUserPref(TelemetryUtils.Preferences.AcceptedPolicyDate); + Services.prefs.clearUserPref( + TelemetryUtils.Preferences.AcceptedPolicyVersion + ); +} + +function setMinimumPolicyVersion(aNewPolicyVersion) { + const CHANNEL_NAME = UpdateUtils.getUpdateChannel(false); + // We might have channel-dependent minimum policy versions. + const CHANNEL_DEPENDENT_PREF = + TelemetryUtils.Preferences.MinimumPolicyVersion + + ".channel-" + + CHANNEL_NAME; + + // Does the channel-dependent pref exist? If so, set its value. + if (Services.prefs.getIntPref(CHANNEL_DEPENDENT_PREF, undefined)) { + Services.prefs.setIntPref(CHANNEL_DEPENDENT_PREF, aNewPolicyVersion); + return; + } + + // We don't have a channel specific minimum, so set the common one. + Services.prefs.setIntPref( + TelemetryUtils.Preferences.MinimumPolicyVersion, + aNewPolicyVersion + ); +} + +add_task(async function test_setup() { + // Addon manager needs a profile directory + do_get_profile(true); + await loadAddonManager( + "xpcshell@tests.mozilla.org", + "XPCShell", + "1", + "1.9.2" + ); + finishAddonManagerStartup(); + fakeIntlReady(); + + // Make sure we don't generate unexpected pings due to pref changes. + await setEmptyPrefWatchlist(); + + // Don't bypass the notifications in this test, we'll fake it. + Services.prefs.setBoolPref( + TelemetryUtils.Preferences.BypassNotification, + false + ); + + TelemetryReportingPolicy.setup(); +}); + +add_task( + { + // This tests initialises the search service, but that doesn't currently + // work on Android. + skip_if: () => AppConstants.platform == "android", + }, + async function test_firstRun() { + await Services.search.init(); + + const FIRST_RUN_TIMEOUT_MSEC = 60 * 1000; // 60s + const OTHER_RUNS_TIMEOUT_MSEC = 10 * 1000; // 10s + + Services.prefs.clearUserPref(TelemetryUtils.Preferences.FirstRun); + + let startupTimeout = 0; + fakeShowPolicyTimeout( + (callback, timeout) => (startupTimeout = timeout), + () => {} + ); + TelemetryReportingPolicy.reset(); + + Services.obs.notifyObservers(null, "sessionstore-windows-restored"); + Assert.equal( + startupTimeout, + FIRST_RUN_TIMEOUT_MSEC, + "The infobar display timeout should be 60s on the first run." + ); + + // Run again, and check that we actually wait only 10 seconds. + TelemetryReportingPolicy.reset(); + Services.obs.notifyObservers(null, "sessionstore-windows-restored"); + Assert.equal( + startupTimeout, + OTHER_RUNS_TIMEOUT_MSEC, + "The infobar display timeout should be 10s on other runs." + ); + } +); + +add_task(async function test_prefs() { + TelemetryReportingPolicy.reset(); + + let now = fakeNow(2009, 11, 18); + + // If the date is not valid (earlier than 2012), we don't regard the policy as accepted. + TelemetryReportingPolicy.testInfobarShown(); + Assert.ok(!TelemetryReportingPolicy.testIsUserNotified()); + Assert.equal( + Services.prefs.getStringPref( + TelemetryUtils.Preferences.AcceptedPolicyDate, + null + ), + 0, + "Invalid dates should not make the policy accepted." + ); + + // Check that the notification date and version are correctly saved to the prefs. + now = fakeNow(2012, 11, 18); + TelemetryReportingPolicy.testInfobarShown(); + Assert.equal( + Services.prefs.getStringPref( + TelemetryUtils.Preferences.AcceptedPolicyDate, + null + ), + now.getTime(), + "A valid date must correctly be saved." + ); + + // Now that user is notified, check if we are allowed to upload. + Assert.ok( + TelemetryReportingPolicy.canUpload(), + "We must be able to upload after the policy is accepted." + ); + + // Disable submission and check that we're no longer allowed to upload. + Services.prefs.setBoolPref( + TelemetryUtils.Preferences.DataSubmissionEnabled, + false + ); + Assert.ok( + !TelemetryReportingPolicy.canUpload(), + "We must not be able to upload if data submission is disabled." + ); + + // Turn the submission back on. + Services.prefs.setBoolPref( + TelemetryUtils.Preferences.DataSubmissionEnabled, + true + ); + Assert.ok( + TelemetryReportingPolicy.canUpload(), + "We must be able to upload if data submission is enabled and the policy was accepted." + ); + + // Set a new minimum policy version and check that user is no longer notified. + let newMinimum = + Services.prefs.getIntPref( + TelemetryUtils.Preferences.CurrentPolicyVersion, + 1 + ) + 1; + setMinimumPolicyVersion(newMinimum); + Assert.ok( + !TelemetryReportingPolicy.testIsUserNotified(), + "A greater minimum policy version must invalidate the policy and disable upload." + ); + + // Eventually accept the policy and make sure user is notified. + Services.prefs.setIntPref( + TelemetryUtils.Preferences.CurrentPolicyVersion, + newMinimum + ); + TelemetryReportingPolicy.testInfobarShown(); + Assert.ok( + TelemetryReportingPolicy.testIsUserNotified(), + "Accepting the policy again should show the user as notified." + ); + Assert.ok( + TelemetryReportingPolicy.canUpload(), + "Accepting the policy again should let us upload data." + ); + + // Set a new, per channel, minimum policy version. Start by setting a test current channel. + Services.prefs + .getDefaultBranch("") + .setStringPref("app.update.channel", TEST_CHANNEL); + + // Increase and set the new minimum version, then check that we're not notified anymore. + newMinimum++; + Services.prefs.setIntPref(PREF_MINIMUM_CHANNEL_POLICY_VERSION, newMinimum); + Assert.ok( + !TelemetryReportingPolicy.testIsUserNotified(), + "Increasing the minimum policy version should invalidate the policy." + ); + + // Eventually accept the policy and make sure user is notified. + Services.prefs.setIntPref( + TelemetryUtils.Preferences.CurrentPolicyVersion, + newMinimum + ); + TelemetryReportingPolicy.testInfobarShown(); + Assert.ok( + TelemetryReportingPolicy.testIsUserNotified(), + "Accepting the policy again should show the user as notified." + ); + Assert.ok( + TelemetryReportingPolicy.canUpload(), + "Accepting the policy again should let us upload data." + ); +}); + +add_task(async function test_migratePrefs() { + const DEPRECATED_FHR_PREFS = { + "datareporting.policy.dataSubmissionPolicyAccepted": true, + "datareporting.policy.dataSubmissionPolicyBypassAcceptance": true, + "datareporting.policy.dataSubmissionPolicyResponseType": "foxyeah", + "datareporting.policy.dataSubmissionPolicyResponseTime": + Date.now().toString(), + }; + + // Make sure the preferences are set before setting up the policy. + for (let name in DEPRECATED_FHR_PREFS) { + switch (typeof DEPRECATED_FHR_PREFS[name]) { + case "string": + Services.prefs.setStringPref(name, DEPRECATED_FHR_PREFS[name]); + break; + case "number": + Services.prefs.setIntPref(name, DEPRECATED_FHR_PREFS[name]); + break; + case "boolean": + Services.prefs.setBoolPref(name, DEPRECATED_FHR_PREFS[name]); + break; + } + } + // Set up the policy. + TelemetryReportingPolicy.reset(); + // They should have been removed by now. + for (let name in DEPRECATED_FHR_PREFS) { + Assert.ok( + !Services.prefs.prefHasUserValue(name), + name + " should have been removed." + ); + } +}); + +add_task(async function test_userNotifiedOfCurrentPolicy() { + fakeResetAcceptedPolicy(); + TelemetryReportingPolicy.reset(); + + // User should be reported as not notified by default. + Assert.ok( + !TelemetryReportingPolicy.testIsUserNotified(), + "The initial state should be unnotified." + ); + + // Forcing a policy version should not automatically make the user notified. + Services.prefs.setIntPref( + TelemetryUtils.Preferences.AcceptedPolicyVersion, + TelemetryReportingPolicy.DEFAULT_DATAREPORTING_POLICY_VERSION + ); + Assert.ok( + !TelemetryReportingPolicy.testIsUserNotified(), + "The default state of the date should have a time of 0 and it should therefore fail" + ); + + // Showing the notification bar should make the user notified. + fakeNow(2012, 11, 11); + TelemetryReportingPolicy.testInfobarShown(); + Assert.ok( + TelemetryReportingPolicy.testIsUserNotified(), + "Using the proper API causes user notification to report as true." + ); + + // It is assumed that later versions of the policy will incorporate previous + // ones, therefore this should also return true. + let newVersion = + Services.prefs.getIntPref( + TelemetryUtils.Preferences.CurrentPolicyVersion, + 1 + ) + 1; + Services.prefs.setIntPref( + TelemetryUtils.Preferences.AcceptedPolicyVersion, + newVersion + ); + Assert.ok( + TelemetryReportingPolicy.testIsUserNotified(), + "A future version of the policy should pass." + ); + + newVersion = + Services.prefs.getIntPref( + TelemetryUtils.Preferences.CurrentPolicyVersion, + 1 + ) - 1; + Services.prefs.setIntPref( + TelemetryUtils.Preferences.AcceptedPolicyVersion, + newVersion + ); + Assert.ok( + !TelemetryReportingPolicy.testIsUserNotified(), + "A previous version of the policy should fail." + ); +}); + +add_task(async function test_canSend() { + const TEST_PING_TYPE = "test-ping"; + + PingServer.start(); + Services.prefs.setStringPref( + TelemetryUtils.Preferences.Server, + "http://localhost:" + PingServer.port + ); + + await TelemetryController.testReset(); + TelemetryReportingPolicy.reset(); + + // User should be reported as not notified by default. + Assert.ok( + !TelemetryReportingPolicy.testIsUserNotified(), + "The initial state should be unnotified." + ); + + // Assert if we receive any ping before the policy is accepted. + PingServer.registerPingHandler(() => + Assert.ok(false, "Should not have received any pings now") + ); + await TelemetryController.submitExternalPing(TEST_PING_TYPE, {}); + + // Reset the ping handler. + PingServer.resetPingHandler(); + + // Fake the infobar: this should also trigger the ping send task. + TelemetryReportingPolicy.testInfobarShown(); + let ping = await PingServer.promiseNextPings(1); + Assert.equal(ping.length, 1, "We should have received one ping."); + Assert.equal( + ping[0].type, + TEST_PING_TYPE, + "We should have received the previous ping." + ); + + // Submit another ping, to make sure it gets sent. + await TelemetryController.submitExternalPing(TEST_PING_TYPE, {}); + + // Get the ping and check its type. + ping = await PingServer.promiseNextPings(1); + Assert.equal(ping.length, 1, "We should have received one ping."); + Assert.equal( + ping[0].type, + TEST_PING_TYPE, + "We should have received the new ping." + ); + + // Fake a restart with a pending ping. + await TelemetryController.addPendingPing(TEST_PING_TYPE, {}); + await TelemetryController.testReset(); + + // We should be immediately sending the ping out. + ping = await PingServer.promiseNextPings(1); + Assert.equal(ping.length, 1, "We should have received one ping."); + Assert.equal( + ping[0].type, + TEST_PING_TYPE, + "We should have received the pending ping." + ); + + // Submit another ping, to make sure it gets sent. + await TelemetryController.submitExternalPing(TEST_PING_TYPE, {}); + + // Get the ping and check its type. + ping = await PingServer.promiseNextPings(1); + Assert.equal(ping.length, 1, "We should have received one ping."); + Assert.equal( + ping[0].type, + TEST_PING_TYPE, + "We should have received the new ping." + ); + + await PingServer.stop(); +}); |