/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; // Pass an empty scope object to the import to prevent "leaked window property" // errors in tests. var Preferences = ChromeUtils.import("resource://gre/modules/Preferences.jsm", {}).Preferences; var TelemetryReportingPolicy = ChromeUtils.import("resource://gre/modules/TelemetryReportingPolicy.jsm", {}).TelemetryReportingPolicy; const PREF_BRANCH = "datareporting.policy."; const PREF_BYPASS_NOTIFICATION = PREF_BRANCH + "dataSubmissionPolicyBypassNotification"; const PREF_CURRENT_POLICY_VERSION = PREF_BRANCH + "currentPolicyVersion"; const PREF_ACCEPTED_POLICY_VERSION = PREF_BRANCH + "dataSubmissionPolicyAcceptedVersion"; const PREF_ACCEPTED_POLICY_DATE = PREF_BRANCH + "dataSubmissionPolicyNotifiedTime"; const TEST_POLICY_VERSION = 37; function fakeShowPolicyTimeout(set, clear) { let reportingPolicy = ChromeUtils.import("resource://gre/modules/TelemetryReportingPolicy.jsm", null).Policy; reportingPolicy.setShowInfobarTimeout = set; reportingPolicy.clearShowInfobarTimeout = clear; } function sendSessionRestoredNotification() { let reportingPolicyImpl = ChromeUtils.import("resource://gre/modules/TelemetryReportingPolicy.jsm", null).TelemetryReportingPolicyImpl; reportingPolicyImpl.observe(null, "sessionstore-windows-restored", null); } /** * Wait for a tick. */ function promiseNextTick() { return new Promise(resolve => executeSoon(resolve)); } /** * Wait for a notification to be shown in a notification box. * @param {Object} aNotificationBox The notification box. * @return {Promise} Resolved when the notification is displayed. */ function promiseWaitForAlertActive(aNotificationBox) { let deferred = PromiseUtils.defer(); aNotificationBox.stack.addEventListener("AlertActive", function() { deferred.resolve(); }, {once: true}); return deferred.promise; } /** * Wait for a notification to be closed. * @param {Object} aNotification The notification. * @return {Promise} Resolved when the notification is closed. */ function promiseWaitForNotificationClose(aNotification) { let deferred = PromiseUtils.defer(); waitForNotificationClose(aNotification, deferred.resolve); return deferred.promise; } function triggerInfoBar(expectedTimeoutMs) { let showInfobarCallback = null; let timeoutMs = null; fakeShowPolicyTimeout((callback, timeout) => { showInfobarCallback = callback; timeoutMs = timeout; }, () => {}); sendSessionRestoredNotification(); Assert.ok(!!showInfobarCallback, "Must have a timer callback."); if (expectedTimeoutMs !== undefined) { Assert.equal(timeoutMs, expectedTimeoutMs, "Timeout should match"); } showInfobarCallback(); } var checkInfobarButton = async function(aNotification) { // Check that the button on the data choices infobar does the right thing. let buttons = aNotification.getElementsByTagName("button"); Assert.equal(buttons.length, 1, "There is 1 button in the data reporting notification."); let button = buttons[0]; // Click on the button. button.click(); // Wait for the preferences panel to open. await promiseNextTick(); }; add_task(async function setup() { const bypassNotification = Preferences.get(PREF_BYPASS_NOTIFICATION, true); const currentPolicyVersion = Preferences.get(PREF_CURRENT_POLICY_VERSION, 1); // Register a cleanup function to reset our preferences. registerCleanupFunction(() => { Preferences.set(PREF_BYPASS_NOTIFICATION, bypassNotification); Preferences.set(PREF_CURRENT_POLICY_VERSION, currentPolicyVersion); return closeAllNotifications(); }); // Don't skip the infobar visualisation. Preferences.set(PREF_BYPASS_NOTIFICATION, false); // Set the current policy version. Preferences.set(PREF_CURRENT_POLICY_VERSION, TEST_POLICY_VERSION); }); function clearAcceptedPolicy() { // Reset the accepted policy. Preferences.reset(PREF_ACCEPTED_POLICY_VERSION); Preferences.reset(PREF_ACCEPTED_POLICY_DATE); } add_task(async function test_single_window() { clearAcceptedPolicy(); // Close all the notifications, then try to trigger the data choices infobar. await closeAllNotifications(); // Make sure that we have a coherent initial state. Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_VERSION, 0), 0, "No version should be set on init."); Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_DATE, 0), 0, "No date should be set on init."); Assert.ok(!TelemetryReportingPolicy.testIsUserNotified(), "User not notified about datareporting policy."); let alertShownPromise = promiseWaitForAlertActive(gNotificationBox); Assert.ok(!TelemetryReportingPolicy.canUpload(), "User should not be allowed to upload."); // Wait for the infobar to be displayed. triggerInfoBar(10 * 1000); await alertShownPromise; Assert.equal(gNotificationBox.allNotifications.length, 1, "Notification Displayed."); Assert.ok(TelemetryReportingPolicy.canUpload(), "User should be allowed to upload now."); await promiseNextTick(); let promiseClosed = promiseWaitForNotificationClose(gNotificationBox.currentNotification); await checkInfobarButton(gNotificationBox.currentNotification); await promiseClosed; Assert.equal(gNotificationBox.allNotifications.length, 0, "No notifications remain."); // Check that we are still clear to upload and that the policy data is saved. Assert.ok(TelemetryReportingPolicy.canUpload()); Assert.equal(TelemetryReportingPolicy.testIsUserNotified(), true, "User notified about datareporting policy."); Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_VERSION, 0), TEST_POLICY_VERSION, "Version pref set."); Assert.greater(parseInt(Preferences.get(PREF_ACCEPTED_POLICY_DATE, null), 10), -1, "Date pref set."); }); add_task(async function test_multiple_windows() { clearAcceptedPolicy(); // Close all the notifications, then try to trigger the data choices infobar. await closeAllNotifications(); // Ensure we see the notification on all windows and that action on one window // results in dismiss on every window. let otherWindow = await BrowserTestUtils.openNewBrowserWindow(); Assert.ok(otherWindow.gNotificationBox, "2nd window has a global notification box."); // Make sure that we have a coherent initial state. Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_VERSION, 0), 0, "No version should be set on init."); Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_DATE, 0), 0, "No date should be set on init."); Assert.ok(!TelemetryReportingPolicy.testIsUserNotified(), "User not notified about datareporting policy."); let showAlertPromises = [ promiseWaitForAlertActive(gNotificationBox), promiseWaitForAlertActive(otherWindow.gNotificationBox), ]; Assert.ok(!TelemetryReportingPolicy.canUpload(), "User should not be allowed to upload."); // Wait for the infobars. triggerInfoBar(10 * 1000); await Promise.all(showAlertPromises); // Both notification were displayed. Close one and check that both gets closed. let closeAlertPromises = [ promiseWaitForNotificationClose(gNotificationBox.currentNotification), promiseWaitForNotificationClose(otherWindow.gNotificationBox.currentNotification), ]; gNotificationBox.currentNotification.close(); await Promise.all(closeAlertPromises); // Close the second window we opened. await BrowserTestUtils.closeWindow(otherWindow); // Check that we are clear to upload and that the policy data us saved. Assert.ok(TelemetryReportingPolicy.canUpload(), "User should be allowed to upload now."); Assert.equal(TelemetryReportingPolicy.testIsUserNotified(), true, "User notified about datareporting policy."); Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_VERSION, 0), TEST_POLICY_VERSION, "Version pref set."); Assert.greater(parseInt(Preferences.get(PREF_ACCEPTED_POLICY_DATE, null), 10), -1, "Date pref set."); });