summaryrefslogtreecommitdiffstats
path: root/comm/mail/components/enterprisepolicies/tests
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/components/enterprisepolicies/tests')
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/browser.ini32
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/browser_policies_setAndLockPref_API.js179
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/browser_policy_app_auto_update.js92
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/browser_policy_app_update.js41
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/browser_policy_background_app_update.js104
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/browser_policy_block_about.js87
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/browser_policy_cookie_settings.js323
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/browser_policy_disable_masterpassword.js90
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/browser_policy_disable_safemode.js49
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/browser_policy_disable_telemetry.js21
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/browser_policy_downloads.js147
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/browser_policy_extensions.js120
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/browser_policy_extensionsettings.js261
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/browser_policy_extensionsettings2.js73
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/browser_policy_handlers.js183
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/browser_policy_masterpassword.js104
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/browser_policy_passwordmanager.js27
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/disable_app_update/browser.ini15
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/disable_app_update/browser_policy_disable_app_update.js109
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/disable_app_update/config_disable_app_update.json5
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/disable_developer_tools/browser.ini13
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/disable_developer_tools/browser_policy_disable_developer_tools.js55
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/disable_developer_tools/config_disable_developer_tools.json5
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/extensionsettings.html23
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/hardware_acceleration/browser.ini12
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/hardware_acceleration/browser_policy_hardware_acceleration.js9
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/hardware_acceleration/disable_hardware_acceleration.json5
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/head.js103
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/policytest_v0.1.xpibin0 -> 305 bytes
-rw-r--r--comm/mail/components/enterprisepolicies/tests/browser/policytest_v0.2.xpibin0 -> 297 bytes
-rw-r--r--comm/mail/components/enterprisepolicies/tests/moz.build16
-rw-r--r--comm/mail/components/enterprisepolicies/tests/xpcshell/head.js140
-rw-r--r--comm/mail/components/enterprisepolicies/tests/xpcshell/test_3rdparty.js22
-rw-r--r--comm/mail/components/enterprisepolicies/tests/xpcshell/test_appupdatepin.js80
-rw-r--r--comm/mail/components/enterprisepolicies/tests/xpcshell/test_appupdateurl.js25
-rw-r--r--comm/mail/components/enterprisepolicies/tests/xpcshell/test_bug1658259.js44
-rw-r--r--comm/mail/components/enterprisepolicies/tests/xpcshell/test_clear_blocked_cookies.js118
-rw-r--r--comm/mail/components/enterprisepolicies/tests/xpcshell/test_macosparser_unflatten.js110
-rw-r--r--comm/mail/components/enterprisepolicies/tests/xpcshell/test_policy_search_engine.js490
-rw-r--r--comm/mail/components/enterprisepolicies/tests/xpcshell/test_preferences.js255
-rw-r--r--comm/mail/components/enterprisepolicies/tests/xpcshell/test_proxy.js122
-rw-r--r--comm/mail/components/enterprisepolicies/tests/xpcshell/test_requestedlocales.js47
-rw-r--r--comm/mail/components/enterprisepolicies/tests/xpcshell/test_runOnce_helper.js21
-rw-r--r--comm/mail/components/enterprisepolicies/tests/xpcshell/test_simple_pref_policies.js378
-rw-r--r--comm/mail/components/enterprisepolicies/tests/xpcshell/test_sorted_alphabetically.js48
-rw-r--r--comm/mail/components/enterprisepolicies/tests/xpcshell/xpcshell.ini18
46 files changed, 4221 insertions, 0 deletions
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/browser.ini b/comm/mail/components/enterprisepolicies/tests/browser/browser.ini
new file mode 100644
index 0000000000..9c709131a2
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/browser.ini
@@ -0,0 +1,32 @@
+[DEFAULT]
+head = head.js
+prefs =
+ mail.provider.suppress_dialog_on_startup=true
+ mail.spotlight.firstRunDone=true
+ mail.winsearch.firstRunDone=true
+ mailnews.start_page.override_url=about:blank
+ mailnews.start_page.url=about:blank
+subsuite = thunderbird
+support-files =
+ policytest_v0.1.xpi
+ policytest_v0.2.xpi
+ extensionsettings.html
+
+[browser_policies_setAndLockPref_API.js]
+[browser_policy_app_auto_update.js]
+skip-if = os == 'win' && msix # Updater is disabled in MSIX builds
+[browser_policy_app_update.js]
+skip-if = os == 'win' && msix # Updater is disabled in MSIX builds
+[browser_policy_background_app_update.js]
+skip-if = os == 'win' && msix # Updater is disabled in MSIX builds
+[browser_policy_block_about.js]
+[browser_policy_cookie_settings.js]
+[browser_policy_disable_safemode.js]
+[browser_policy_disable_telemetry.js]
+[browser_policy_downloads.js]
+[browser_policy_extensions.js]
+[browser_policy_extensionsettings.js]
+[browser_policy_extensionsettings2.js]
+[browser_policy_handlers.js]
+[browser_policy_masterpassword.js]
+[browser_policy_passwordmanager.js]
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/browser_policies_setAndLockPref_API.js b/comm/mail/components/enterprisepolicies/tests/browser/browser_policies_setAndLockPref_API.js
new file mode 100644
index 0000000000..0cad8e5aa3
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/browser_policies_setAndLockPref_API.js
@@ -0,0 +1,179 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+let { Policies, setAndLockPref, PoliciesUtils } = ChromeUtils.importESModule(
+ "resource:///modules/policies/Policies.sys.mjs"
+);
+
+add_task(async function test_API_directly() {
+ await setupPolicyEngineWithJson("");
+ setAndLockPref("policies.test.boolPref", true);
+ checkLockedPref("policies.test.boolPref", true);
+
+ // Check that a previously-locked pref can be changed
+ // (it will be unlocked first).
+ setAndLockPref("policies.test.boolPref", false);
+ checkLockedPref("policies.test.boolPref", false);
+
+ setAndLockPref("policies.test.intPref", 2);
+ checkLockedPref("policies.test.intPref", 2);
+
+ setAndLockPref("policies.test.stringPref", "policies test");
+ checkLockedPref("policies.test.stringPref", "policies test");
+
+ PoliciesUtils.setDefaultPref(
+ "policies.test.lockedPref",
+ "policies test",
+ true
+ );
+ checkLockedPref("policies.test.lockedPref", "policies test");
+
+ // Test that user values do not override the prefs, and the get*Pref call
+ // still return the value set through setAndLockPref
+ Services.prefs.setBoolPref("policies.test.boolPref", true);
+ checkLockedPref("policies.test.boolPref", false);
+
+ Services.prefs.setIntPref("policies.test.intPref", 10);
+ checkLockedPref("policies.test.intPref", 2);
+
+ Services.prefs.setStringPref("policies.test.stringPref", "policies test");
+ checkLockedPref("policies.test.stringPref", "policies test");
+
+ try {
+ // Test that a non-integer value is correctly rejected, even though
+ // typeof(val) == "number"
+ setAndLockPref("policies.test.intPref", 1.5);
+ ok(false, "Integer value should be rejected");
+ } catch (ex) {
+ ok(true, "Integer value was rejected");
+ }
+});
+
+add_task(async function test_API_through_policies() {
+ // Ensure that the values received by the policies have the correct
+ // type to make sure things are properly working.
+
+ // Implement functions to handle the three simple policies
+ // that will be added to the schema.
+ Policies.bool_policy = {
+ onBeforeUIStartup(manager, param) {
+ setAndLockPref("policies.test2.boolPref", param);
+ },
+ };
+
+ Policies.int_policy = {
+ onBeforeUIStartup(manager, param) {
+ setAndLockPref("policies.test2.intPref", param);
+ },
+ };
+
+ Policies.string_policy = {
+ onBeforeUIStartup(manager, param) {
+ setAndLockPref("policies.test2.stringPref", param);
+ },
+ };
+
+ await setupPolicyEngineWithJson(
+ // policies.json
+ {
+ policies: {
+ bool_policy: true,
+ int_policy: 42,
+ string_policy: "policies test 2",
+ },
+ },
+
+ // custom schema
+ {
+ properties: {
+ bool_policy: {
+ type: "boolean",
+ },
+
+ int_policy: {
+ type: "integer",
+ },
+
+ string_policy: {
+ type: "string",
+ },
+ },
+ }
+ );
+
+ is(
+ Services.policies.status,
+ Ci.nsIEnterprisePolicies.ACTIVE,
+ "Engine is active"
+ );
+
+ // The expected values come from config_setAndLockPref.json
+ checkLockedPref("policies.test2.boolPref", true);
+ checkLockedPref("policies.test2.intPref", 42);
+ checkLockedPref("policies.test2.stringPref", "policies test 2");
+
+ delete Policies.bool_policy;
+ delete Policies.int_policy;
+ delete Policies.string_policy;
+});
+
+add_task(async function test_pref_tracker() {
+ // Tests the test harness functionality that tracks usage of
+ // the setAndLockPref and setDefualtPref APIs.
+
+ let defaults = Services.prefs.getDefaultBranch("");
+
+ // Test prefs that had a default value and got changed to another
+ defaults.setIntPref("test1.pref1", 10);
+ defaults.setStringPref("test1.pref2", "test");
+
+ setAndLockPref("test1.pref1", 20);
+ PoliciesUtils.setDefaultPref("test1.pref2", "NEW VALUE");
+ setAndLockPref("test1.pref3", "NEW VALUE");
+ PoliciesUtils.setDefaultPref("test1.pref4", 20);
+
+ PoliciesPrefTracker.restoreDefaultValues();
+
+ is(
+ Services.prefs.getIntPref("test1.pref1"),
+ 10,
+ "Expected value for test1.pref1"
+ );
+ is(
+ Services.prefs.getStringPref("test1.pref2"),
+ "test",
+ "Expected value for test1.pref2"
+ );
+ is(
+ Services.prefs.prefIsLocked("test1.pref1"),
+ false,
+ "test1.pref1 got unlocked"
+ );
+ ok(
+ !Services.prefs.getStringPref("test1.pref3", undefined),
+ "test1.pref3 should have had its value unset"
+ );
+ is(
+ Services.prefs.getIntPref("test1.pref4", -1),
+ -1,
+ "test1.pref4 should have had its value unset"
+ );
+
+ // Test a pref that had a default value and a user value
+ defaults.setIntPref("test2.pref1", 10);
+ Services.prefs.setIntPref("test2.pref1", 20);
+
+ setAndLockPref("test2.pref1", 20);
+
+ PoliciesPrefTracker.restoreDefaultValues();
+
+ is(Services.prefs.getIntPref("test2.pref1"), 20, "Correct user value");
+ is(defaults.getIntPref("test2.pref1"), 10, "Correct default value");
+ is(
+ Services.prefs.prefIsLocked("test2.pref1"),
+ false,
+ "felipe pref is not locked"
+ );
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_app_auto_update.js b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_app_auto_update.js
new file mode 100644
index 0000000000..433408642f
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_app_auto_update.js
@@ -0,0 +1,92 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+ChromeUtils.defineESModuleGetters(this, {
+ UpdateUtils: "resource://gre/modules/UpdateUtils.sys.mjs",
+});
+
+async function test_app_update_auto(expectedEnabled, expectedLocked) {
+ let actualEnabled = await UpdateUtils.getAppUpdateAutoEnabled();
+ is(
+ actualEnabled,
+ expectedEnabled,
+ `Actual auto update enabled setting should match the expected value of ${expectedEnabled}`
+ );
+
+ let actualLocked = UpdateUtils.appUpdateAutoSettingIsLocked();
+ is(
+ actualLocked,
+ expectedLocked,
+ `Auto update enabled setting ${
+ expectedLocked ? "should" : "should not"
+ } be locked`
+ );
+
+ let setSuccess = true;
+ try {
+ await UpdateUtils.setAppUpdateAutoEnabled(actualEnabled);
+ } catch (error) {
+ setSuccess = false;
+ }
+ is(
+ setSuccess,
+ !expectedLocked,
+ `Setting auto update ${expectedLocked ? "should" : "should not"} fail`
+ );
+
+ let tabmail = document.getElementById("tabmail");
+ let prefsTabMode = tabmail.tabModes.preferencesTab;
+
+ let prefsDocument = await new Promise(resolve => {
+ Services.obs.addObserver(function documentLoaded(subject) {
+ if (subject.URL == "about:preferences") {
+ Services.obs.removeObserver(documentLoaded, "chrome-document-loaded");
+ resolve(subject);
+ }
+ }, "chrome-document-loaded");
+ window.openPreferencesTab("paneGeneral", "updateApp");
+ });
+
+ await new Promise(resolve => setTimeout(resolve));
+
+ is(
+ prefsDocument.getElementById("updateSettingsContainer").hidden,
+ expectedLocked,
+ `When auto update ${
+ expectedLocked ? "is" : "isn't"
+ } locked, the corresponding preferences entry ${
+ expectedLocked ? "should" : "shouldn't"
+ } be hidden`
+ );
+
+ tabmail.closeTab(prefsTabMode.tabs[0]);
+}
+
+add_task(async function test_app_auto_update_policy() {
+ let originalUpdateAutoValue = await UpdateUtils.getAppUpdateAutoEnabled();
+ registerCleanupFunction(async () => {
+ await UpdateUtils.setAppUpdateAutoEnabled(originalUpdateAutoValue);
+ });
+
+ await UpdateUtils.setAppUpdateAutoEnabled(true);
+ await test_app_update_auto(true, false);
+
+ await setupPolicyEngineWithJson({
+ policies: {
+ AppAutoUpdate: false,
+ },
+ });
+ await test_app_update_auto(false, true);
+
+ await setupPolicyEngineWithJson({});
+ await UpdateUtils.setAppUpdateAutoEnabled(false);
+ await test_app_update_auto(false, false);
+
+ await setupPolicyEngineWithJson({
+ policies: {
+ AppAutoUpdate: true,
+ },
+ });
+ await test_app_update_auto(true, true);
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_app_update.js b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_app_update.js
new file mode 100644
index 0000000000..14a9c92bc5
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_app_update.js
@@ -0,0 +1,41 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+ChromeUtils.defineESModuleGetters(this, {
+ UpdateUtils: "resource://gre/modules/UpdateUtils.sys.mjs",
+});
+var updateService = Cc["@mozilla.org/updates/update-service;1"].getService(
+ Ci.nsIApplicationUpdateService
+);
+
+// This test is intended to ensure that nsIUpdateService::canCheckForUpdates
+// is true before the "DisableAppUpdate" policy is applied. Testing that
+// nsIUpdateService::canCheckForUpdates is false after the "DisableAppUpdate"
+// policy is applied needs to occur in a different test since the policy does
+// not properly take effect unless it is applied during application startup.
+add_task(async function test_updates_pre_policy() {
+ // Turn off automatic update before we set app.update.disabledForTesting to
+ // false so that we don't cause an actual update.
+ let originalUpdateAutoValue = await UpdateUtils.getAppUpdateAutoEnabled();
+ await UpdateUtils.setAppUpdateAutoEnabled(false);
+ registerCleanupFunction(async () => {
+ await UpdateUtils.setAppUpdateAutoEnabled(originalUpdateAutoValue);
+ });
+
+ await SpecialPowers.pushPrefEnv({
+ set: [["app.update.disabledForTesting", false]],
+ });
+
+ is(
+ Services.policies.isAllowed("appUpdate"),
+ true,
+ "Since no policies have been set, appUpdate should be allowed by default"
+ );
+
+ is(
+ updateService.canCheckForUpdates,
+ true,
+ "Should be able to check for updates before any policies are in effect."
+ );
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_background_app_update.js b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_background_app_update.js
new file mode 100644
index 0000000000..4c0369df3d
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_background_app_update.js
@@ -0,0 +1,104 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+ChromeUtils.defineESModuleGetters(this, {
+ UpdateUtils: "resource://gre/modules/UpdateUtils.sys.mjs",
+});
+
+const PREF_NAME = "app.update.background.enabled";
+
+async function test_background_update_pref(expectedEnabled, expectedLocked) {
+ let actualEnabled = await UpdateUtils.readUpdateConfigSetting(PREF_NAME);
+ is(
+ actualEnabled,
+ expectedEnabled,
+ `Actual background update enabled setting should be ${expectedEnabled}`
+ );
+
+ let actualLocked = UpdateUtils.appUpdateSettingIsLocked(PREF_NAME);
+ is(
+ actualLocked,
+ expectedLocked,
+ `Background update enabled setting ${
+ expectedLocked ? "should" : "should not"
+ } be locked`
+ );
+
+ let setSuccess = true;
+ try {
+ await UpdateUtils.writeUpdateConfigSetting(PREF_NAME, actualEnabled);
+ } catch (error) {
+ setSuccess = false;
+ }
+ is(
+ setSuccess,
+ !expectedLocked,
+ `Setting background update pref ${
+ expectedLocked ? "should" : "should not"
+ } fail`
+ );
+
+ if (AppConstants.MOZ_UPDATER && AppConstants.MOZ_UPDATE_AGENT) {
+ let shouldShowUI =
+ !expectedLocked && UpdateUtils.PER_INSTALLATION_PREFS_SUPPORTED;
+ await BrowserTestUtils.withNewTab("about:preferences", browser => {
+ is(
+ browser.contentDocument.getElementById("backgroundUpdate").hidden,
+ !shouldShowUI,
+ `When background update ${
+ expectedLocked ? "is" : "isn't"
+ } locked, and per-installation prefs ${
+ UpdateUtils.PER_INSTALLATION_PREFS_SUPPORTED ? "are" : "aren't"
+ } supported, the corresponding preferences entry ${
+ shouldShowUI ? "shouldn't" : "should"
+ } be hidden`
+ );
+ });
+ } else {
+ // The backgroundUpdate element is #ifdef'ed out if MOZ_UPDATER and
+ // MOZ_UPDATE_AGENT are not both defined.
+ info(
+ "Warning: UI testing skipped because support for background update is " +
+ "not present"
+ );
+ }
+}
+
+add_task(async function test_background_app_update_policy() {
+ // Turn on the background update UI so we can test it.
+ await SpecialPowers.pushPrefEnv({
+ set: [["app.update.background.scheduling.enabled", true]],
+ });
+
+ const origBackgroundUpdateVal = await UpdateUtils.readUpdateConfigSetting(
+ PREF_NAME
+ );
+ registerCleanupFunction(async () => {
+ await UpdateUtils.writeUpdateConfigSetting(
+ PREF_NAME,
+ origBackgroundUpdateVal
+ );
+ });
+
+ await UpdateUtils.writeUpdateConfigSetting(PREF_NAME, true);
+ await test_background_update_pref(true, false);
+
+ await setupPolicyEngineWithJson({
+ policies: {
+ BackgroundAppUpdate: false,
+ },
+ });
+ await test_background_update_pref(false, true);
+
+ await setupPolicyEngineWithJson({});
+ await UpdateUtils.writeUpdateConfigSetting(PREF_NAME, false);
+ await test_background_update_pref(false, false);
+
+ await setupPolicyEngineWithJson({
+ policies: {
+ BackgroundAppUpdate: true,
+ },
+ });
+ await test_background_update_pref(true, true);
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_block_about.js b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_block_about.js
new file mode 100644
index 0000000000..4be9c7fee8
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_block_about.js
@@ -0,0 +1,87 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+const { PromiseTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/PromiseTestUtils.sys.mjs"
+);
+
+const ABOUT_CONTRACT = "@mozilla.org/network/protocol/about;1?what=";
+
+const policiesToTest = [
+ {
+ policies: {
+ BlockAboutAddons: true,
+ },
+ urls: ["about:addons"],
+ },
+
+ {
+ policies: {
+ BlockAboutConfig: true,
+ },
+ urls: ["about:config"],
+ },
+ {
+ policies: {
+ BlockAboutProfiles: true,
+ },
+ urls: ["about:profiles"],
+ },
+
+ {
+ policies: {
+ BlockAboutSupport: true,
+ },
+ urls: ["about:support"],
+ },
+
+ {
+ policies: {
+ DisableDeveloperTools: true,
+ },
+ urls: ["about:debugging", "about:devtools-toolbox"],
+ },
+ {
+ policies: {
+ DisableTelemetry: true,
+ },
+ urls: ["about:telemetry"],
+ },
+];
+
+add_task(async function testAboutTask() {
+ for (let policyToTest of policiesToTest) {
+ let policyJSON = { policies: {} };
+ policyJSON.policies = policyToTest.policies;
+ for (let url of policyToTest.urls) {
+ if (url.startsWith("about")) {
+ let feature = url.split(":")[1];
+ let aboutModule = Cc[ABOUT_CONTRACT + feature].getService(
+ Ci.nsIAboutModule
+ );
+ let chromeURL = aboutModule.getChromeURI(Services.io.newURI(url)).spec;
+ await testPageBlockedByPolicy(policyJSON, chromeURL);
+ }
+ await testPageBlockedByPolicy(policyJSON, url);
+ }
+ }
+});
+
+async function testPageBlockedByPolicy(policyJSON, page) {
+ await EnterprisePolicyTesting.setupPolicyEngineWithJson(policyJSON);
+
+ await withNewTab({ url: "about:blank" }, async browser => {
+ BrowserTestUtils.loadURIString(browser, page);
+ await BrowserTestUtils.browserLoaded(browser, false, page, true);
+ await SpecialPowers.spawn(browser, [page], async function (innerPage) {
+ ok(
+ content.document.documentURI.startsWith(
+ "about:neterror?e=blockedByPolicy"
+ ),
+ content.document.documentURI +
+ " should start with about:neterror?e=blockedByPolicy"
+ );
+ });
+ });
+}
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_cookie_settings.js b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_cookie_settings.js
new file mode 100644
index 0000000000..f43500d723
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_cookie_settings.js
@@ -0,0 +1,323 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+const { UrlClassifierTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/UrlClassifierTestUtils.sys.mjs"
+);
+Services.cookies.QueryInterface(Ci.nsICookieService);
+
+function restore_prefs() {
+ // Bug 1617611: Fix all the tests broken by "cookies SameSite=lax by default"
+ Services.prefs.clearUserPref("network.cookie.sameSite.laxByDefault");
+ Services.prefs.clearUserPref("network.cookie.cookieBehavior");
+ Services.prefs.clearUserPref(
+ "network.cookieJarSettings.unblocked_for_testing"
+ );
+ Services.prefs.clearUserPref(
+ "network.cookie.rejectForeignWithExceptions.enabled"
+ );
+}
+
+registerCleanupFunction(restore_prefs);
+
+async function fake_profile_change() {
+ await new Promise(resolve => {
+ Services.obs.addObserver(function waitForDBClose() {
+ Services.obs.removeObserver(waitForDBClose, "cookie-db-closed");
+ resolve();
+ }, "cookie-db-closed");
+ Services.cookies
+ .QueryInterface(Ci.nsIObserver)
+ .observe(null, "profile-before-change", "shutdown-persist");
+ });
+ await new Promise(resolve => {
+ Services.obs.addObserver(function waitForDBOpen() {
+ Services.obs.removeObserver(waitForDBOpen, "cookie-db-read");
+ resolve();
+ }, "cookie-db-read");
+ Services.cookies
+ .QueryInterface(Ci.nsIObserver)
+ .observe(null, "profile-do-change", "");
+ });
+}
+
+async function test_cookie_settings({
+ cookiesEnabled,
+ thirdPartyCookiesEnabled,
+ cookieJarSettingsLocked,
+}) {
+ let firstPartyURI = NetUtil.newURI("https://example.com/");
+ let thirdPartyURI = NetUtil.newURI("https://example.org/");
+ let channel = NetUtil.newChannel({
+ uri: firstPartyURI,
+ loadUsingSystemPrincipal: true,
+ });
+ channel.QueryInterface(
+ Ci.nsIHttpChannelInternal
+ ).forceAllowThirdPartyCookie = true;
+ Services.cookies.removeAll();
+ Services.cookies.setCookieStringFromHttp(firstPartyURI, "key=value", channel);
+ Services.cookies.setCookieStringFromHttp(thirdPartyURI, "key=value", channel);
+
+ let expectedFirstPartyCookies = 1;
+ let expectedThirdPartyCookies = 1;
+ if (!cookiesEnabled) {
+ expectedFirstPartyCookies = 0;
+ }
+ if (!cookiesEnabled || !thirdPartyCookiesEnabled) {
+ expectedThirdPartyCookies = 0;
+ }
+ is(
+ Services.cookies.countCookiesFromHost(firstPartyURI.host),
+ expectedFirstPartyCookies,
+ "Number of first-party cookies should match expected"
+ );
+ is(
+ Services.cookies.countCookiesFromHost(thirdPartyURI.host),
+ expectedThirdPartyCookies,
+ "Number of third-party cookies should match expected"
+ );
+
+ // Add a cookie so we can check if it persists past the end of the session
+ // but, first remove existing cookies set by this host to put us in a known state
+ Services.cookies.removeAll();
+ Services.cookies.setCookieStringFromHttp(
+ firstPartyURI,
+ "key=value; max-age=1000",
+ channel
+ );
+
+ await fake_profile_change();
+
+ // Now check if the cookie persisted or not
+ let expectedCookieCount = 1;
+ if (!cookiesEnabled) {
+ expectedCookieCount = 0;
+ }
+ is(
+ Services.cookies.countCookiesFromHost(firstPartyURI.host),
+ expectedCookieCount,
+ "Number of cookies was not what expected after restarting session"
+ );
+
+ is(
+ Services.prefs.prefIsLocked("network.cookie.cookieBehavior"),
+ cookieJarSettingsLocked,
+ "Cookie behavior pref lock status should be what is expected"
+ );
+
+ window.openPreferencesTab("panePrivacy");
+ await BrowserTestUtils.browserLoaded(
+ window.preferencesTabType.tab.browser,
+ undefined,
+ url => url.startsWith("about:preferences")
+ );
+ let { contentDocument } = window.preferencesTabType.tab.browser;
+ await TestUtils.waitForCondition(() =>
+ contentDocument.getElementById("acceptCookies")
+ );
+ let expectControlsDisabled = !cookiesEnabled || cookieJarSettingsLocked;
+
+ for (let id of ["acceptCookies", "showCookiesButton"]) {
+ is(
+ contentDocument.getElementById(id).disabled,
+ cookieJarSettingsLocked,
+ `#${id} disabled status should match expected`
+ );
+ }
+ for (let id of ["acceptThirdPartyMenu"]) {
+ is(
+ contentDocument.getElementById(id).disabled,
+ expectControlsDisabled,
+ `#${id} disabled status should match expected`
+ );
+ }
+
+ is(
+ contentDocument.getElementById("cookieExceptions").disabled,
+ cookieJarSettingsLocked,
+ "#cookieExceptions disabled status should matched expected"
+ );
+
+ let tabmail = document.getElementById("tabmail");
+ tabmail.closeTab(window.preferencesTabType.tab);
+}
+
+add_task(async function prepare_tracker_tables() {
+ await UrlClassifierTestUtils.addTestTrackers();
+});
+
+add_task(async function test_initial_state() {
+ Services.prefs.setBoolPref(
+ "network.cookieJarSettings.unblocked_for_testing",
+ true
+ );
+ Services.prefs.setBoolPref(
+ "network.cookie.rejectForeignWithExceptions.enabled",
+ false
+ );
+ Services.prefs.setBoolPref("network.cookie.sameSite.laxByDefault", false);
+ await test_cookie_settings({
+ cookiesEnabled: true,
+ thirdPartyCookiesEnabled: true,
+ cookieJarSettingsLocked: false,
+ });
+ restore_prefs();
+});
+
+add_task(async function test_undefined_unlocked() {
+ Services.prefs.setIntPref("network.cookie.cookieBehavior", 3);
+ Services.prefs.setBoolPref(
+ "network.cookieJarSettings.unblocked_for_testing",
+ true
+ );
+ Services.prefs.setBoolPref(
+ "network.cookie.rejectForeignWithExceptions.enabled",
+ false
+ );
+ await setupPolicyEngineWithJson({
+ policies: {
+ Cookies: {},
+ },
+ });
+ is(
+ Services.prefs.getIntPref("network.cookie.cookieBehavior", undefined),
+ 3,
+ "An empty cookie policy should not have changed the cookieBehavior preference"
+ );
+ restore_prefs();
+});
+
+add_task(async function test_disabled() {
+ Services.prefs.setBoolPref(
+ "network.cookieJarSettings.unblocked_for_testing",
+ true
+ );
+ Services.prefs.setBoolPref(
+ "network.cookie.rejectForeignWithExceptions.enabled",
+ false
+ );
+ await setupPolicyEngineWithJson({
+ policies: {
+ Cookies: {
+ Default: false,
+ },
+ },
+ });
+
+ await test_cookie_settings({
+ cookiesEnabled: false,
+ thirdPartyCookiesEnabled: true,
+ cookieJarSettingsLocked: false,
+ });
+ restore_prefs();
+});
+
+add_task(async function test_third_party_disabled() {
+ Services.prefs.setBoolPref(
+ "network.cookieJarSettings.unblocked_for_testing",
+ true
+ );
+ Services.prefs.setBoolPref(
+ "network.cookie.rejectForeignWithExceptions.enabled",
+ false
+ );
+ await setupPolicyEngineWithJson({
+ policies: {
+ Cookies: {
+ AcceptThirdParty: "never",
+ },
+ },
+ });
+
+ await test_cookie_settings({
+ cookiesEnabled: true,
+ thirdPartyCookiesEnabled: false,
+ cookieJarSettingsLocked: false,
+ });
+ restore_prefs();
+});
+
+add_task(async function test_disabled_and_third_party_disabled() {
+ Services.prefs.setBoolPref(
+ "network.cookieJarSettings.unblocked_for_testing",
+ true
+ );
+ Services.prefs.setBoolPref(
+ "network.cookie.rejectForeignWithExceptions.enabled",
+ false
+ );
+ await setupPolicyEngineWithJson({
+ policies: {
+ Cookies: {
+ Default: false,
+ AcceptThirdParty: "never",
+ },
+ },
+ });
+
+ await test_cookie_settings({
+ cookiesEnabled: false,
+ thirdPartyCookiesEnabled: false,
+ cookieJarSettingsLocked: false,
+ });
+ restore_prefs();
+});
+
+add_task(async function test_disabled_and_third_party_disabled_locked() {
+ Services.prefs.setBoolPref(
+ "network.cookieJarSettings.unblocked_for_testing",
+ true
+ );
+ Services.prefs.setBoolPref(
+ "network.cookie.rejectForeignWithExceptions.enabled",
+ false
+ );
+ await setupPolicyEngineWithJson({
+ policies: {
+ Cookies: {
+ Default: false,
+ AcceptThirdParty: "never",
+ Locked: true,
+ },
+ },
+ });
+
+ await test_cookie_settings({
+ cookiesEnabled: false,
+ thirdPartyCookiesEnabled: false,
+ cookieJarSettingsLocked: true,
+ });
+ restore_prefs();
+});
+
+add_task(async function test_undefined_locked() {
+ Services.prefs.setBoolPref(
+ "network.cookieJarSettings.unblocked_for_testing",
+ true
+ );
+ Services.prefs.setBoolPref(
+ "network.cookie.rejectForeignWithExceptions.enabled",
+ false
+ );
+ Services.prefs.setBoolPref("network.cookie.sameSite.laxByDefault", false);
+ await setupPolicyEngineWithJson({
+ policies: {
+ Cookies: {
+ Locked: true,
+ },
+ },
+ });
+
+ await test_cookie_settings({
+ cookiesEnabled: true,
+ thirdPartyCookiesEnabled: true,
+ cookieJarSettingsLocked: true,
+ });
+ restore_prefs();
+});
+
+add_task(async function prepare_tracker_tables() {
+ await UrlClassifierTestUtils.cleanupTestTrackers();
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_disable_masterpassword.js b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_disable_masterpassword.js
new file mode 100644
index 0000000000..b69787422e
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_disable_masterpassword.js
@@ -0,0 +1,90 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const MASTER_PASSWORD = "omgsecret!";
+const mpToken = Cc["@mozilla.org/security/pk11tokendb;1"]
+ .getService(Ci.nsIPK11TokenDB)
+ .getInternalKeyToken();
+
+async function checkDeviceManager({ buttonIsDisabled }) {
+ let deviceManagerWindow = window.openDialog(
+ "chrome://pippki/content/device_manager.xhtml",
+ "",
+ ""
+ );
+ await BrowserTestUtils.waitForEvent(deviceManagerWindow, "load");
+
+ let tree = deviceManagerWindow.document.getElementById("device_tree");
+ ok(tree, "The device tree exists");
+
+ // Find and select the item related to the internal key token
+ for (let i = 0; i < tree.view.rowCount; i++) {
+ tree.view.selection.select(i);
+
+ try {
+ let selected_token = deviceManagerWindow.selected_slot.getToken();
+ if (selected_token.isInternalKeyToken) {
+ break;
+ }
+ } catch (e) {}
+ }
+
+ // Check to see if the button was updated correctly
+ let changePwButton =
+ deviceManagerWindow.document.getElementById("change_pw_button");
+ is(
+ changePwButton.getAttribute("disabled") == "true",
+ buttonIsDisabled,
+ "Change Password button is in the correct state: " + buttonIsDisabled
+ );
+
+ await BrowserTestUtils.closeWindow(deviceManagerWindow);
+}
+
+async function checkAboutPreferences({ checkboxIsDisabled }) {
+ await BrowserTestUtils.withNewTab(
+ "about:preferences#privacy",
+ async browser => {
+ is(
+ browser.contentDocument.getElementById("useMasterPassword").disabled,
+ checkboxIsDisabled,
+ "Primary Password checkbox is in the correct state: " +
+ checkboxIsDisabled
+ );
+ }
+ );
+}
+
+add_task(async function test_policy_disable_masterpassword() {
+ ok(!mpToken.hasPassword, "Starting the test with no password");
+
+ // No password and no policy: access to setting a primary password
+ // should be enabled.
+ await checkDeviceManager({ buttonIsDisabled: false });
+ await checkAboutPreferences({ checkboxIsDisabled: false });
+
+ await setupPolicyEngineWithJson({
+ policies: {
+ DisableMasterPasswordCreation: true,
+ },
+ });
+
+ // With the `DisableMasterPasswordCreation: true` policy active, the
+ // UI entry points for creating a Primary Password should be disabled.
+ await checkDeviceManager({ buttonIsDisabled: true });
+ await checkAboutPreferences({ checkboxIsDisabled: true });
+
+ mpToken.changePassword("", MASTER_PASSWORD);
+ ok(mpToken.hasPassword, "Master password was set");
+
+ // If a Primary Password is already set, there's no point in disabling
+ // the
+ await checkDeviceManager({ buttonIsDisabled: false });
+ await checkAboutPreferences({ checkboxIsDisabled: false });
+
+ // Clean up
+ mpToken.changePassword(MASTER_PASSWORD, "");
+ ok(!mpToken.hasPassword, "Master password was cleaned up");
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_disable_safemode.js b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_disable_safemode.js
new file mode 100644
index 0000000000..3ce719b5f1
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_disable_safemode.js
@@ -0,0 +1,49 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+add_setup(async function () {
+ await setupPolicyEngineWithJson({
+ policies: {
+ DisableSafeMode: true,
+ },
+ });
+});
+
+add_task(async function test_help_menu() {
+ buildHelpMenu();
+ let safeModeMenu = document.getElementById("helpTroubleshootMode");
+ is(
+ safeModeMenu.getAttribute("disabled"),
+ "true",
+ "The `Restart with Add-ons Disabled...` item should be disabled"
+ );
+ let safeModeAppMenu = document.getElementById("appmenu_troubleshootMode");
+ is(
+ safeModeAppMenu.getAttribute("disabled"),
+ "true",
+ "The `Restart with Add-ons Disabled...` appmenu item should be disabled"
+ );
+});
+
+add_task(async function test_safemode_from_about_support() {
+ await withNewTab({ url: "about:support" }, browser => {
+ let button = content.document.getElementById("restart-in-safe-mode-button");
+ is(
+ button.getAttribute("disabled"),
+ "true",
+ "The `Restart with Add-ons Disabled...` button should be disabled"
+ );
+ });
+});
+
+add_task(async function test_safemode_from_about_profiles() {
+ await withNewTab({ url: "about:profiles" }, browser => {
+ let button = content.document.getElementById("restart-in-safe-mode-button");
+ is(
+ button.getAttribute("disabled"),
+ "true",
+ "The `Restart with Add-ons Disabled...` button should be disabled"
+ );
+ });
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_disable_telemetry.js b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_disable_telemetry.js
new file mode 100644
index 0000000000..600be47763
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_disable_telemetry.js
@@ -0,0 +1,21 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function test_policy_disable_telemetry() {
+ const { TelemetryReportingPolicy } = ChromeUtils.importESModule(
+ "resource://gre/modules/TelemetryReportingPolicy.sys.mjs"
+ );
+
+ ok(TelemetryReportingPolicy, "TelemetryReportingPolicy exists");
+ is(TelemetryReportingPolicy.canUpload(), true, "Telemetry is enabled");
+
+ await setupPolicyEngineWithJson({
+ policies: {
+ DisableTelemetry: true,
+ },
+ });
+
+ is(TelemetryReportingPolicy.canUpload(), false, "Telemetry is disabled");
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_downloads.js b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_downloads.js
new file mode 100644
index 0000000000..520fcc67aa
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_downloads.js
@@ -0,0 +1,147 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+ChromeUtils.defineESModuleGetters(this, {
+ FileUtils: "resource://gre/modules/FileUtils.sys.mjs",
+});
+
+add_task(async function test_defaultdownload() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ DefaultDownloadDirectory: "${home}/Downloads",
+ PromptForDownloadLocation: false,
+ },
+ });
+
+ window.openPreferencesTab("paneGeneral");
+ await BrowserTestUtils.browserLoaded(
+ window.preferencesTabType.tab.browser,
+ undefined,
+ url => url.startsWith("about:preferences")
+ );
+ let { contentDocument } = window.preferencesTabType.tab.browser;
+ await TestUtils.waitForCondition(() =>
+ contentDocument.getElementById("alwaysAsk")
+ );
+ await new Promise(resolve =>
+ window.preferencesTabType.tab.browser.contentWindow.setTimeout(resolve)
+ );
+ is(
+ window.preferencesTabType.tab.browser.contentDocument.getElementById(
+ "alwaysAsk"
+ ).disabled,
+ true,
+ "alwaysAsk should be disabled."
+ );
+ is(
+ window.preferencesTabType.tab.browser.contentDocument.getElementById(
+ "saveTo"
+ ).selected,
+ true,
+ "saveTo should be selected."
+ );
+ is(
+ window.preferencesTabType.tab.browser.contentDocument.getElementById(
+ "saveTo"
+ ).disabled,
+ true,
+ "saveTo should be disabled."
+ );
+ let home = FileUtils.getFile("Home", []).path;
+ is(
+ Services.prefs.getStringPref("browser.download.dir"),
+ home + "/Downloads",
+ "browser.download.dir should be ${home}/Downloads."
+ );
+ is(
+ Services.prefs.getBoolPref("browser.download.useDownloadDir"),
+ true,
+ "browser.download.useDownloadDir should be true."
+ );
+ is(
+ Services.prefs.prefIsLocked("browser.download.useDownloadDir"),
+ true,
+ "browser.download.useDownloadDir should be locked."
+ );
+
+ let tabmail = document.getElementById("tabmail");
+ tabmail.closeTab(window.preferencesTabType.tab);
+});
+
+add_task(async function test_download() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ DownloadDirectory: "${home}/Documents",
+ },
+ });
+
+ window.openPreferencesTab("paneGeneral");
+ await BrowserTestUtils.browserLoaded(
+ window.preferencesTabType.tab.browser,
+ undefined,
+ url => url.startsWith("about:preferences")
+ );
+ let { contentDocument } = window.preferencesTabType.tab.browser;
+ await TestUtils.waitForCondition(() =>
+ contentDocument.getElementById("alwaysAsk")
+ );
+ await new Promise(resolve =>
+ window.preferencesTabType.tab.browser.contentWindow.setTimeout(resolve)
+ );
+ is(
+ window.preferencesTabType.tab.browser.contentDocument.getElementById(
+ "alwaysAsk"
+ ).disabled,
+ true,
+ "alwaysAsk should be disabled."
+ );
+ is(
+ window.preferencesTabType.tab.browser.contentDocument.getElementById(
+ "saveTo"
+ ).selected,
+ true,
+ "saveTo should be selected."
+ );
+ is(
+ window.preferencesTabType.tab.browser.contentDocument.getElementById(
+ "saveTo"
+ ).disabled,
+ true,
+ "saveTo should be disabled."
+ );
+ is(
+ window.preferencesTabType.tab.browser.contentDocument.getElementById(
+ "downloadFolder"
+ ).disabled,
+ true,
+ "downloadFolder should be disabled."
+ );
+ is(
+ window.preferencesTabType.tab.browser.contentDocument.getElementById(
+ "chooseFolder"
+ ).disabled,
+ true,
+ "chooseFolder should be disabled."
+ );
+ let home = FileUtils.getFile("Home", []).path;
+ is(
+ Services.prefs.getStringPref("browser.download.dir"),
+ home + "/Documents",
+ "browser.download.dir should be ${home}/Documents."
+ );
+ is(
+ Services.prefs.getBoolPref("browser.download.useDownloadDir"),
+ true,
+ "browser.download.useDownloadDir should be true."
+ );
+ is(
+ Services.prefs.prefIsLocked("browser.download.useDownloadDir"),
+ true,
+ "browser.download.useDownloadDir should be locked."
+ );
+
+ let tabmail = document.getElementById("tabmail");
+ tabmail.closeTab(window.preferencesTabType.tab);
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_extensions.js b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_extensions.js
new file mode 100644
index 0000000000..062fa2b714
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_extensions.js
@@ -0,0 +1,120 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+const ADDON_ID = "policytest@mozilla.com";
+const BASE_URL =
+ "http://mochi.test:8888/browser/comm/mail/components/enterprisepolicies/tests/browser";
+
+async function isExtensionLocked(win, addonID) {
+ let addonCard = await BrowserTestUtils.waitForCondition(() => {
+ return win.document.querySelector(`addon-card[addon-id="${addonID}"]`);
+ }, `Get addon-card for "${addonID}"`);
+ let disableBtn = addonCard.querySelector('[action="toggle-disabled"]');
+ let removeBtn = addonCard.querySelector('panel-item[action="remove"]');
+ ok(removeBtn.disabled, "Remove button should be disabled");
+ ok(disableBtn.hidden, "Disable button should be hidden");
+}
+
+add_task(async function test_addon_install() {
+ let installPromise = waitForAddonInstall(ADDON_ID);
+ await setupPolicyEngineWithJson({
+ policies: {
+ Extensions: {
+ Install: [`${BASE_URL}/policytest_v0.1.xpi`],
+ Locked: [ADDON_ID],
+ },
+ },
+ });
+ await installPromise;
+ let addon = await AddonManager.getAddonByID(ADDON_ID);
+ isnot(addon, null, "Addon not installed.");
+ is(addon.version, "0.1", "Addon version is correct");
+
+ Assert.deepEqual(
+ addon.installTelemetryInfo,
+ { source: "enterprise-policy" },
+ "Got the expected addon.installTelemetryInfo"
+ );
+});
+
+add_task(async function test_addon_locked() {
+ let tabmail = document.getElementById("tabmail");
+ let index = tabmail.tabInfo.length;
+ await window.openAddonsMgr("addons://list/extension");
+ let tab = tabmail.tabInfo[index];
+ let browser = tab.browser;
+
+ await isExtensionLocked(browser.contentWindow, ADDON_ID);
+
+ tabmail.closeTab(tab);
+});
+
+add_task(async function test_addon_reinstall() {
+ // Test that uninstalling and reinstalling the same addon ID works as expected.
+ // This can be used to update an addon.
+
+ let uninstallPromise = waitForAddonUninstall(ADDON_ID);
+ let installPromise = waitForAddonInstall(ADDON_ID);
+ await setupPolicyEngineWithJson({
+ policies: {
+ Extensions: {
+ Uninstall: [ADDON_ID],
+ Install: [`${BASE_URL}/policytest_v0.2.xpi`],
+ },
+ },
+ });
+
+ // Older version was uninstalled
+ await uninstallPromise;
+
+ // New version was installed
+ await installPromise;
+
+ let addon = await AddonManager.getAddonByID(ADDON_ID);
+ isnot(
+ addon,
+ null,
+ "Addon still exists because the policy was used to update it."
+ );
+ is(addon.version, "0.2", "New version is correct");
+});
+
+add_task(async function test_addon_uninstall() {
+ EnterprisePolicyTesting.resetRunOnceState();
+
+ let uninstallPromise = waitForAddonUninstall(ADDON_ID);
+ await setupPolicyEngineWithJson({
+ policies: {
+ Extensions: {
+ Uninstall: [ADDON_ID],
+ },
+ },
+ });
+ await uninstallPromise;
+ let addon = await AddonManager.getAddonByID(ADDON_ID);
+ is(addon, null, "Addon should be uninstalled.");
+});
+
+add_task(async function test_addon_download_failure() {
+ // Test that if the download fails, the runOnce pref
+ // is cleared so that the download will happen again.
+
+ let installPromise = waitForAddonInstall(ADDON_ID);
+ await setupPolicyEngineWithJson({
+ policies: {
+ Extensions: {
+ Install: [`${BASE_URL}/policytest_invalid.xpi`],
+ },
+ },
+ });
+
+ await installPromise;
+ is(
+ Services.prefs.prefHasUserValue(
+ "browser.policies.runOncePerModification.extensionsInstall"
+ ),
+ false,
+ "runOnce pref should be unset"
+ );
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_extensionsettings.js b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_extensionsettings.js
new file mode 100644
index 0000000000..7fced9c1ad
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_extensionsettings.js
@@ -0,0 +1,261 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+/* eslint-disable @microsoft/sdl/no-insecure-url */
+
+const BASE_URL =
+ "http://mochi.test:8888/browser/comm/mail/components/enterprisepolicies/tests/browser/";
+
+async function openTab(url) {
+ let tab = window.openContentTab(url, null, null);
+ if (
+ tab.browser.webProgress?.isLoadingDocument ||
+ tab.browser.currentURI?.spec == "about:blank"
+ ) {
+ await BrowserTestUtils.browserLoaded(tab.browser);
+ }
+ return tab;
+}
+
+/**
+ * Wait for the given PopupNotification to display
+ *
+ * @param {string} name
+ * The name of the notification to wait for.
+ *
+ * @returns {Promise}
+ * Resolves with the notification window.
+ */
+function promisePopupNotificationShown(name) {
+ return new Promise(resolve => {
+ function popupshown() {
+ let notification = PopupNotifications.getNotification(name);
+ if (!notification) {
+ return;
+ }
+
+ ok(notification, `${name} notification shown`);
+ ok(PopupNotifications.isPanelOpen, "notification panel open");
+
+ PopupNotifications.panel.removeEventListener("popupshown", popupshown);
+ resolve(PopupNotifications.panel.firstElementChild);
+ }
+
+ PopupNotifications.panel.addEventListener("popupshown", popupshown);
+ });
+}
+
+function dismissNotification(win = window) {
+ return new Promise(resolve => {
+ function popuphidden() {
+ PopupNotifications.panel.removeEventListener("popuphidden", popuphidden);
+ resolve();
+ }
+ PopupNotifications.panel.addEventListener("popuphidden", popuphidden);
+ executeSoon(function () {
+ EventUtils.synthesizeKey("VK_ESCAPE", {}, win);
+ });
+ });
+}
+
+add_setup(async function setupTestEnvironment() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["extensions.InstallTrigger.enabled", true],
+ ["extensions.InstallTriggerImpl.enabled", true],
+ // Relax the user input requirements while running this test.
+ ["xpinstall.userActivation.required", false],
+ ],
+ });
+});
+
+add_task(async function test_install_source_blocked_link() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ ExtensionSettings: {
+ "*": {
+ install_sources: ["http://blocks.other.install.sources/*"],
+ },
+ },
+ },
+ });
+ let popupPromise = promisePopupNotificationShown(
+ "addon-install-policy-blocked"
+ );
+ let tab = await openTab(`${BASE_URL}extensionsettings.html`);
+
+ await SpecialPowers.spawn(tab.linkedBrowser, [], () => {
+ content.document.getElementById("policytest").click();
+ });
+ await popupPromise;
+ await dismissNotification();
+ document.getElementById("tabmail").closeTab(tab);
+});
+
+add_task(async function test_install_source_blocked_installtrigger() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ ExtensionSettings: {
+ "*": {
+ install_sources: ["http://blocks.other.install.sources/*"],
+ blocked_install_message: "blocked_install_message",
+ },
+ },
+ },
+ });
+ let popupPromise = promisePopupNotificationShown(
+ "addon-install-policy-blocked"
+ );
+ let tab = await openTab(`${BASE_URL}extensionsettings.html`);
+
+ await SpecialPowers.spawn(tab.linkedBrowser, [], () => {
+ content.document.getElementById("policytest_installtrigger").click();
+ });
+ let popup = await popupPromise;
+ let description = popup.querySelector(".popup-notification-description");
+ ok(
+ description.textContent.endsWith("blocked_install_message"),
+ "Custom install message present"
+ );
+ await dismissNotification();
+ document.getElementById("tabmail").closeTab(tab);
+});
+
+add_task(async function test_install_source_blocked_otherdomain() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ ExtensionSettings: {
+ "*": {
+ install_sources: ["http://mochi.test/*"],
+ },
+ },
+ },
+ });
+ let popupPromise = promisePopupNotificationShown(
+ "addon-install-policy-blocked"
+ );
+ let tab = await openTab(`${BASE_URL}extensionsettings.html`);
+
+ await SpecialPowers.spawn(tab.linkedBrowser, [], () => {
+ content.document.getElementById("policytest_otherdomain").click();
+ });
+ await popupPromise;
+ await dismissNotification();
+ document.getElementById("tabmail").closeTab(tab);
+});
+
+add_task(async function test_install_source_blocked_direct() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ ExtensionSettings: {
+ "*": {
+ install_sources: ["http://blocks.other.install.sources/*"],
+ },
+ },
+ },
+ });
+ let popupPromise = promisePopupNotificationShown(
+ "addon-install-policy-blocked"
+ );
+ let tab = await openTab(`${BASE_URL}extensionsettings.html`);
+
+ await SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [{ baseUrl: BASE_URL }],
+ async function ({ baseUrl }) {
+ content.document.location.href = baseUrl + "policytest_v0.1.xpi";
+ }
+ );
+ await popupPromise;
+ await dismissNotification();
+ document.getElementById("tabmail").closeTab(tab);
+});
+
+add_task(async function test_install_source_allowed_link() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ ExtensionSettings: {
+ "*": {
+ install_sources: ["http://mochi.test/*"],
+ },
+ },
+ },
+ });
+ let popupPromise = promisePopupNotificationShown("addon-webext-permissions");
+ let tab = await openTab(`${BASE_URL}extensionsettings.html`);
+
+ await SpecialPowers.spawn(tab.linkedBrowser, [], () => {
+ content.document.getElementById("policytest").click();
+ });
+ await popupPromise;
+ await dismissNotification();
+ document.getElementById("tabmail").closeTab(tab);
+});
+
+add_task(async function test_install_source_allowed_installtrigger() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ ExtensionSettings: {
+ "*": {
+ install_sources: ["http://mochi.test/*"],
+ },
+ },
+ },
+ });
+ let popupPromise = promisePopupNotificationShown("addon-webext-permissions");
+ let tab = await openTab(`${BASE_URL}extensionsettings.html`);
+
+ await SpecialPowers.spawn(tab.linkedBrowser, [], () => {
+ content.document.getElementById("policytest_installtrigger").click();
+ });
+ await popupPromise;
+ await dismissNotification();
+ document.getElementById("tabmail").closeTab(tab);
+});
+
+add_task(async function test_install_source_allowed_otherdomain() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ ExtensionSettings: {
+ "*": {
+ install_sources: ["http://mochi.test/*", "http://example.org/*"],
+ },
+ },
+ },
+ });
+ let popupPromise = promisePopupNotificationShown("addon-webext-permissions");
+ let tab = await openTab(`${BASE_URL}extensionsettings.html`);
+
+ await SpecialPowers.spawn(tab.linkedBrowser, [], () => {
+ content.document.getElementById("policytest_otherdomain").click();
+ });
+ await popupPromise;
+ await dismissNotification();
+ document.getElementById("tabmail").closeTab(tab);
+});
+
+add_task(async function test_install_source_allowed_direct() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ ExtensionSettings: {
+ "*": {
+ install_sources: ["http://mochi.test/*"],
+ },
+ },
+ },
+ });
+ let popupPromise = promisePopupNotificationShown("addon-webext-permissions");
+ let tab = await openTab(`${BASE_URL}extensionsettings.html`);
+
+ await SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [{ baseUrl: BASE_URL }],
+ async function ({ baseUrl }) {
+ content.document.location.href = baseUrl + "policytest_v0.1.xpi";
+ }
+ );
+ await popupPromise;
+ await dismissNotification();
+ document.getElementById("tabmail").closeTab(tab);
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_extensionsettings2.js b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_extensionsettings2.js
new file mode 100644
index 0000000000..e335d70fe0
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_extensionsettings2.js
@@ -0,0 +1,73 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+const ADDON_ID = "policytest@mozilla.com";
+const BASE_URL =
+ "http://mochi.test:8888/browser/comm/mail/components/enterprisepolicies/tests/browser";
+
+async function isExtensionLockedAndUpdateDisabled(win, addonID) {
+ let addonCard = await BrowserTestUtils.waitForCondition(() => {
+ return win.document.querySelector(`addon-card[addon-id="${addonID}"]`);
+ }, `Get addon-card for "${addonID}"`);
+ let disableBtn = addonCard.querySelector('[action="toggle-disabled"]');
+ let removeBtn = addonCard.querySelector('panel-item[action="remove"]');
+ ok(removeBtn.disabled, "Remove button should be disabled");
+ ok(disableBtn.hidden, "Disable button should be hidden");
+ let updateRow = addonCard.querySelector(".addon-detail-row-updates");
+ is(updateRow.hidden, true, "Update row should be hidden");
+}
+
+add_task(async function test_addon_install() {
+ let installPromise = waitForAddonInstall(ADDON_ID);
+ await setupPolicyEngineWithJson({
+ policies: {
+ ExtensionSettings: {
+ "policytest@mozilla.com": {
+ install_url: `${BASE_URL}/policytest_v0.1.xpi`,
+ installation_mode: "force_installed",
+ updates_disabled: true,
+ },
+ },
+ },
+ });
+ await installPromise;
+ let addon = await AddonManager.getAddonByID(ADDON_ID);
+ isnot(addon, null, "Addon not installed.");
+ is(addon.version, "0.1", "Addon version is correct");
+
+ Assert.deepEqual(
+ addon.installTelemetryInfo,
+ { source: "enterprise-policy" },
+ "Got the expected addon.installTelemetryInfo"
+ );
+});
+
+add_task(async function test_addon_locked_update_disabled() {
+ let tabmail = document.getElementById("tabmail");
+ let index = tabmail.tabInfo.length;
+ await window.openAddonsMgr("addons://detail/" + encodeURIComponent(ADDON_ID));
+ let tab = tabmail.tabInfo[index];
+ let browser = tab.browser;
+ let win = browser.contentWindow;
+
+ await isExtensionLockedAndUpdateDisabled(win, ADDON_ID);
+
+ tabmail.closeTab(tab);
+});
+
+add_task(async function test_addon_uninstall() {
+ let uninstallPromise = waitForAddonUninstall(ADDON_ID);
+ await setupPolicyEngineWithJson({
+ policies: {
+ ExtensionSettings: {
+ "policytest@mozilla.com": {
+ installation_mode: "blocked",
+ },
+ },
+ },
+ });
+ await uninstallPromise;
+ let addon = await AddonManager.getAddonByID(ADDON_ID);
+ is(addon, null, "Addon should be uninstalled.");
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_handlers.js b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_handlers.js
new file mode 100644
index 0000000000..6242625756
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_handlers.js
@@ -0,0 +1,183 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const gMIMEService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
+
+const gExternalProtocolService = Cc[
+ "@mozilla.org/uriloader/external-protocol-service;1"
+].getService(Ci.nsIExternalProtocolService);
+
+const gHandlerService = Cc[
+ "@mozilla.org/uriloader/handler-service;1"
+].getService(Ci.nsIHandlerService);
+
+// This seems odd, but for test purposes, this just has to be a file that we know exists,
+// and by using this file, we don't have to worry about different platforms.
+let exeFile = Services.dirsvc.get("XREExeF", Ci.nsIFile);
+
+add_task(async function test_valid_handlers() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ Handlers: {
+ mimeTypes: {
+ "application/marimba": {
+ action: "useHelperApp",
+ ask: true,
+ handlers: [
+ {
+ name: "Launch",
+ path: exeFile.path,
+ },
+ ],
+ },
+ },
+ schemes: {
+ fake_scheme: {
+ action: "useHelperApp",
+ ask: false,
+ handlers: [
+ {
+ name: "Name",
+ uriTemplate: "https://www.example.org/?%s",
+ },
+ ],
+ },
+ },
+ extensions: {
+ txt: {
+ action: "saveToDisk",
+ ask: false,
+ },
+ },
+ },
+ },
+ });
+
+ let handlerInfo = gMIMEService.getFromTypeAndExtension(
+ "application/marimba",
+ ""
+ );
+ is(handlerInfo.preferredAction, handlerInfo.useHelperApp);
+ is(handlerInfo.alwaysAskBeforeHandling, true);
+ is(handlerInfo.preferredApplicationHandler.name, "Launch");
+ is(handlerInfo.preferredApplicationHandler.executable.path, exeFile.path);
+
+ handlerInfo.preferredApplicationHandler = null;
+ gHandlerService.store(handlerInfo);
+
+ handlerInfo = handlerInfo = gMIMEService.getFromTypeAndExtension(
+ "application/marimba",
+ ""
+ );
+ is(handlerInfo.preferredApplicationHandler, null);
+
+ gHandlerService.remove(handlerInfo);
+
+ handlerInfo = gExternalProtocolService.getProtocolHandlerInfo("fake_scheme");
+ is(handlerInfo.preferredAction, handlerInfo.useHelperApp);
+ is(handlerInfo.alwaysAskBeforeHandling, false);
+ is(handlerInfo.preferredApplicationHandler.name, "Name");
+ is(
+ handlerInfo.preferredApplicationHandler.uriTemplate,
+ "https://www.example.org/?%s"
+ );
+
+ handlerInfo.preferredApplicationHandler = null;
+ gHandlerService.store(handlerInfo);
+
+ handlerInfo = gExternalProtocolService.getProtocolHandlerInfo("fake_scheme");
+ is(handlerInfo.preferredApplicationHandler, null);
+
+ gHandlerService.remove(handlerInfo);
+
+ handlerInfo = gMIMEService.getFromTypeAndExtension("", "txt");
+ is(handlerInfo.preferredAction, handlerInfo.saveToDisk);
+ is(handlerInfo.alwaysAskBeforeHandling, false);
+
+ handlerInfo.preferredApplicationHandler = null;
+ gHandlerService.store(handlerInfo);
+ handlerInfo = gMIMEService.getFromTypeAndExtension("", "txt");
+ is(handlerInfo.preferredApplicationHandler, null);
+
+ gHandlerService.remove(handlerInfo);
+});
+
+add_task(async function test_no_handler() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ Handlers: {
+ schemes: {
+ no_handler: {
+ action: "useHelperApp",
+ },
+ },
+ },
+ },
+ });
+
+ let handlerInfo =
+ gExternalProtocolService.getProtocolHandlerInfo("no_handler");
+ is(handlerInfo.preferredAction, handlerInfo.alwaysAsk);
+ is(handlerInfo.alwaysAskBeforeHandling, true);
+ is(handlerInfo.preferredApplicationHandler, null);
+
+ gHandlerService.remove(handlerInfo);
+});
+
+add_task(async function test_bad_web_handler1() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ Handlers: {
+ schemes: {
+ bas_web_handler1: {
+ action: "useHelperApp",
+ handlers: [
+ {
+ name: "Name",
+ uriTemplate: "https://www.example.org/?%s",
+ },
+ ],
+ },
+ },
+ },
+ },
+ });
+
+ let handlerInfo =
+ gExternalProtocolService.getProtocolHandlerInfo("bad_web_handler1");
+ is(handlerInfo.preferredAction, handlerInfo.alwaysAsk);
+ is(handlerInfo.alwaysAskBeforeHandling, true);
+ is(handlerInfo.preferredApplicationHandler, null);
+
+ gHandlerService.remove(handlerInfo);
+});
+
+add_task(async function test_bad_web_handler2() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ Handlers: {
+ schemes: {
+ bas_web_handler1: {
+ action: "useHelperApp",
+ handlers: [
+ {
+ name: "Name",
+ uriTemplate: "https://www.example.org/",
+ },
+ ],
+ },
+ },
+ },
+ },
+ });
+
+ let handlerInfo =
+ gExternalProtocolService.getProtocolHandlerInfo("bad_web_handler1");
+ is(handlerInfo.preferredAction, handlerInfo.alwaysAsk);
+ is(handlerInfo.alwaysAskBeforeHandling, true);
+ is(handlerInfo.preferredApplicationHandler, null);
+
+ gHandlerService.remove(handlerInfo);
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_masterpassword.js b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_masterpassword.js
new file mode 100644
index 0000000000..8320897341
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_masterpassword.js
@@ -0,0 +1,104 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+let { LoginTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/LoginTestUtils.sys.mjs"
+);
+
+// Test that once a password is set, you can't unset it
+add_task(async function test_policy_masterpassword_set() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ PrimaryPassword: true,
+ },
+ });
+
+ LoginTestUtils.primaryPassword.enable();
+
+ window.openPreferencesTab("panePrivacy");
+ await BrowserTestUtils.browserLoaded(
+ window.preferencesTabType.tab.browser,
+ undefined,
+ url => url.startsWith("about:preferences")
+ );
+ let { contentDocument } = window.preferencesTabType.tab.browser;
+ await TestUtils.waitForCondition(() =>
+ contentDocument.getElementById("useMasterPassword")
+ );
+
+ is(
+ contentDocument.getElementById("useMasterPassword").disabled,
+ true,
+ "Primary Password checkbox should be disabled"
+ );
+
+ let tabmail = document.getElementById("tabmail");
+ tabmail.closeTab(window.preferencesTabType.tab);
+
+ LoginTestUtils.primaryPassword.disable();
+});
+
+// Test that password can't be removed in changemp.xhtml
+add_task(async function test_policy_nochangemp() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ PrimaryPassword: true,
+ },
+ });
+
+ LoginTestUtils.primaryPassword.enable();
+
+ let changeMPWindow = window.openDialog(
+ "chrome://mozapps/content/preferences/changemp.xhtml",
+ "",
+ ""
+ );
+ await BrowserTestUtils.waitForEvent(changeMPWindow, "load");
+
+ is(
+ changeMPWindow.document.getElementById("admin").hidden,
+ true,
+ "Admin message should not be visible because there is a password."
+ );
+
+ changeMPWindow.document.getElementById("oldpw").value =
+ LoginTestUtils.primaryPassword.masterPassword;
+
+ is(
+ changeMPWindow.document.getElementById("changemp").getButton("accept")
+ .disabled,
+ true,
+ "OK button should not be enabled if there is an old password."
+ );
+
+ await BrowserTestUtils.closeWindow(changeMPWindow);
+
+ LoginTestUtils.primaryPassword.disable();
+});
+
+// Test that admin message shows
+add_task(async function test_policy_admin() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ PrimaryPassword: true,
+ },
+ });
+
+ let changeMPWindow = window.openDialog(
+ "chrome://mozapps/content/preferences/changemp.xhtml",
+ "",
+ ""
+ );
+ await BrowserTestUtils.waitForEvent(changeMPWindow, "load");
+
+ is(
+ changeMPWindow.document.getElementById("admin").hidden,
+ false,
+ true,
+ "Admin message should not be hidden because there is not a password."
+ );
+
+ await BrowserTestUtils.closeWindow(changeMPWindow);
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_passwordmanager.js b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_passwordmanager.js
new file mode 100644
index 0000000000..1f74d46754
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/browser_policy_passwordmanager.js
@@ -0,0 +1,27 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function test_pwmanagerbutton() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ PasswordManagerEnabled: false,
+ },
+ });
+
+ window.openPreferencesTab("panePrivacy");
+ await BrowserTestUtils.browserLoaded(window.preferencesTabType.tab.browser);
+ await new Promise(resolve => setTimeout(resolve));
+
+ is(
+ window.preferencesTabType.tab.browser.contentDocument.getElementById(
+ "showPasswords"
+ ).disabled,
+ true,
+ "showPasswords should be disabled."
+ );
+
+ let tabmail = document.getElementById("tabmail");
+ tabmail.closeTab(window.preferencesTabType.tab);
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/disable_app_update/browser.ini b/comm/mail/components/enterprisepolicies/tests/browser/disable_app_update/browser.ini
new file mode 100644
index 0000000000..73162633db
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/disable_app_update/browser.ini
@@ -0,0 +1,15 @@
+[DEFAULT]
+prefs =
+ mail.provider.suppress_dialog_on_startup=true
+ mail.spotlight.firstRunDone=true
+ mail.winsearch.firstRunDone=true
+ mailnews.start_page.override_url=about:blank
+ mailnews.start_page.url=about:blank
+ app.update.disabledForTesting=false
+ browser.policies.alternatePath='<test-root>/comm/mail/components/enterprisepolicies/tests/browser/disable_app_update/config_disable_app_update.json'
+subsuite = thunderbird
+support-files =
+ config_disable_app_update.json
+skip-if = os == 'win' && msix # Updater is disabled in MSIX builds
+
+[browser_policy_disable_app_update.js]
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/disable_app_update/browser_policy_disable_app_update.js b/comm/mail/components/enterprisepolicies/tests/browser/disable_app_update/browser_policy_disable_app_update.js
new file mode 100644
index 0000000000..28dcd780d1
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/disable_app_update/browser_policy_disable_app_update.js
@@ -0,0 +1,109 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+var updateService = Cc["@mozilla.org/updates/update-service;1"].getService(
+ Ci.nsIApplicationUpdateService
+);
+
+add_task(async function test_updates_post_policy() {
+ is(
+ Services.policies.isAllowed("appUpdate"),
+ false,
+ "appUpdate should be disabled by policy."
+ );
+
+ is(
+ updateService.canCheckForUpdates,
+ false,
+ "Should not be able to check for updates with DisableAppUpdate enabled."
+ );
+});
+
+add_task(async function test_update_preferences_ui() {
+ let tabmail = document.getElementById("tabmail");
+ let prefsTabMode = tabmail.tabModes.preferencesTab;
+
+ let prefsDocument = await new Promise(resolve => {
+ Services.obs.addObserver(function documentLoaded(subject) {
+ if (subject.URL == "about:preferences") {
+ Services.obs.removeObserver(documentLoaded, "chrome-document-loaded");
+ resolve(subject);
+ }
+ }, "chrome-document-loaded");
+ window.openPreferencesTab("paneGeneral", "updateApp");
+ });
+
+ await new Promise(resolve => setTimeout(resolve));
+
+ let setting = prefsDocument.getElementById("updateSettingsContainer");
+ is(
+ setting.hidden,
+ true,
+ "Update choices should be disabled when app update is locked by policy"
+ );
+
+ tabmail.closeTab(prefsTabMode.tabs[0]);
+});
+
+add_task(async function test_update_about_ui() {
+ let aboutDialog = await waitForAboutDialog();
+ let panelId = "policyDisabled";
+
+ await BrowserTestUtils.waitForCondition(
+ () =>
+ aboutDialog.gAppUpdater.selectedPanel &&
+ aboutDialog.gAppUpdater.selectedPanel.id == panelId,
+ 'Waiting for expected panel ID - expected "' + panelId + '"'
+ );
+ is(
+ aboutDialog.gAppUpdater.selectedPanel.id,
+ panelId,
+ "The About Dialog panel Id should equal " + panelId
+ );
+
+ // Make sure that we still remain on the "disabled by policy" panel after
+ // `AppUpdater.stop()` is called.
+ aboutDialog.gAppUpdater._appUpdater.stop();
+ is(
+ aboutDialog.gAppUpdater.selectedPanel.id,
+ panelId,
+ "The About Dialog panel Id should still equal " + panelId
+ );
+
+ aboutDialog.close();
+});
+
+/**
+ * Waits for the About Dialog to load.
+ *
+ * @returns A promise that returns the domWindow for the About Dialog and
+ * resolves when the About Dialog loads.
+ */
+function waitForAboutDialog() {
+ return new Promise(resolve => {
+ var listener = {
+ onOpenWindow: aAppWindow => {
+ Services.wm.removeListener(listener);
+
+ async function aboutDialogOnLoad() {
+ domwindow.removeEventListener("load", aboutDialogOnLoad, true);
+ let chromeURI = "chrome://messenger/content/aboutDialog.xhtml";
+ is(
+ domwindow.document.location.href,
+ chromeURI,
+ "About dialog appeared"
+ );
+ resolve(domwindow);
+ }
+
+ var domwindow = aAppWindow.docShell.domWindow;
+ domwindow.addEventListener("load", aboutDialogOnLoad, true);
+ },
+ onCloseWindow: aAppWindow => {},
+ };
+
+ Services.wm.addListener(listener);
+ openAboutDialog();
+ });
+}
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/disable_app_update/config_disable_app_update.json b/comm/mail/components/enterprisepolicies/tests/browser/disable_app_update/config_disable_app_update.json
new file mode 100644
index 0000000000..f36622021f
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/disable_app_update/config_disable_app_update.json
@@ -0,0 +1,5 @@
+{
+ "policies": {
+ "DisableAppUpdate": true
+ }
+}
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/disable_developer_tools/browser.ini b/comm/mail/components/enterprisepolicies/tests/browser/disable_developer_tools/browser.ini
new file mode 100644
index 0000000000..b40dff605b
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/disable_developer_tools/browser.ini
@@ -0,0 +1,13 @@
+[DEFAULT]
+prefs =
+ mail.provider.suppress_dialog_on_startup=true
+ mail.spotlight.firstRunDone=true
+ mail.winsearch.firstRunDone=true
+ mailnews.start_page.override_url=about:blank
+ mailnews.start_page.url=about:blank
+ browser.policies.alternatePath='<test-root>/comm/mail/components/enterprisepolicies/tests/browser/disable_developer_tools/config_disable_developer_tools.json'
+subsuite = thunderbird
+support-files =
+ config_disable_developer_tools.json
+
+[browser_policy_disable_developer_tools.js]
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/disable_developer_tools/browser_policy_disable_developer_tools.js b/comm/mail/components/enterprisepolicies/tests/browser/disable_developer_tools/browser_policy_disable_developer_tools.js
new file mode 100644
index 0000000000..35ad87ab4d
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/disable_developer_tools/browser_policy_disable_developer_tools.js
@@ -0,0 +1,55 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function test_updates_post_policy() {
+ is(
+ Services.policies.isAllowed("devtools"),
+ false,
+ "devtools should be disabled by policy."
+ );
+
+ is(
+ Services.prefs.getBoolPref("devtools.policy.disabled"),
+ true,
+ "devtools dedicated disabled pref is set to true"
+ );
+
+ Services.prefs.setBoolPref("devtools.policy.disabled", false);
+
+ is(
+ Services.prefs.getBoolPref("devtools.policy.disabled"),
+ true,
+ "devtools dedicated disabled pref can not be updated"
+ );
+
+ await expectErrorPage("about:devtools-toolbox");
+ await expectErrorPage("about:debugging");
+
+ info("Check that devtools menu items are hidden");
+ let devtoolsMenu = window.document.getElementById("devtoolsMenu");
+ ok(devtoolsMenu.hidden, "The Web Developer item of the tools menu is hidden");
+});
+
+const expectErrorPage = async function (url) {
+ let tabmail = document.getElementById("tabmail");
+ let index = tabmail.tabInfo.length;
+ window.openContentTab("about:blank");
+ let tab = tabmail.tabInfo[index];
+ let browser = tab.browser;
+
+ BrowserTestUtils.loadURIString(browser, url);
+ await BrowserTestUtils.browserLoaded(browser, false, url, true);
+ await SpecialPowers.spawn(browser, [url], async function () {
+ ok(
+ content.document.documentURI.startsWith(
+ "about:neterror?e=blockedByPolicy"
+ ),
+ content.document.documentURI +
+ " should start with about:neterror?e=blockedByPolicy"
+ );
+ });
+
+ tabmail.closeTab(tab);
+};
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/disable_developer_tools/config_disable_developer_tools.json b/comm/mail/components/enterprisepolicies/tests/browser/disable_developer_tools/config_disable_developer_tools.json
new file mode 100644
index 0000000000..08c393dec6
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/disable_developer_tools/config_disable_developer_tools.json
@@ -0,0 +1,5 @@
+{
+ "policies": {
+ "DisableDeveloperTools": true
+ }
+}
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/extensionsettings.html b/comm/mail/components/enterprisepolicies/tests/browser/extensionsettings.html
new file mode 100644
index 0000000000..a54c011968
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/extensionsettings.html
@@ -0,0 +1,23 @@
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<script type="text/javascript">
+function installTrigger(url) {
+ InstallTrigger.install({extension: url});
+}
+</script>
+</head>
+<body>
+<p>
+<a id="policytest" href="policytest_v0.1.xpi">policytest@mozilla.com</a>
+</p>
+<p>
+<a id="policytest_installtrigger" onclick="installTrigger(this.href);return false;" href="policytest_v0.1.xpi">policytest@mozilla.com</a>
+</p>
+<p>
+<a id="policytest_otherdomain" href="http://example.org:80/browser/comm/mail/components/enterprisepolicies/tests/browser/policytest_v0.1.xpi">policytest@mozilla.com</a>
+</p>
+</body>
+</html>
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/hardware_acceleration/browser.ini b/comm/mail/components/enterprisepolicies/tests/browser/hardware_acceleration/browser.ini
new file mode 100644
index 0000000000..01e3e74e22
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/hardware_acceleration/browser.ini
@@ -0,0 +1,12 @@
+[DEFAULT]
+prefs =
+ browser.policies.alternatePath='<test-root>/browser/components/enterprisepolicies/tests/browser/hardware_acceleration/disable_hardware_acceleration.json'
+ mail.provider.suppress_dialog_on_startup=true
+ mail.spotlight.firstRunDone=true
+ mail.winsearch.firstRunDone=true
+ mailnews.start_page.override_url=about:blank
+ mailnews.start_page.url=about:blank
+support-files =
+ disable_hardware_acceleration.json
+
+[browser_policy_hardware_acceleration.js]
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/hardware_acceleration/browser_policy_hardware_acceleration.js b/comm/mail/components/enterprisepolicies/tests/browser/hardware_acceleration/browser_policy_hardware_acceleration.js
new file mode 100644
index 0000000000..59ca2a3631
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/hardware_acceleration/browser_policy_hardware_acceleration.js
@@ -0,0 +1,9 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function test_policy_hardware_acceleration() {
+ let winUtils = Services.wm.getMostRecentWindow("").windowUtils;
+ is(winUtils.layerManagerType, "Basic", "Hardware acceleration disabled");
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/hardware_acceleration/disable_hardware_acceleration.json b/comm/mail/components/enterprisepolicies/tests/browser/hardware_acceleration/disable_hardware_acceleration.json
new file mode 100644
index 0000000000..acbdc0a3f4
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/hardware_acceleration/disable_hardware_acceleration.json
@@ -0,0 +1,5 @@
+{
+ "policies": {
+ "HardwareAcceleration": false
+ }
+}
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/head.js b/comm/mail/components/enterprisepolicies/tests/browser/head.js
new file mode 100644
index 0000000000..b557ea3d22
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/head.js
@@ -0,0 +1,103 @@
+/* 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";
+
+const { EnterprisePolicyTesting, PoliciesPrefTracker } =
+ ChromeUtils.importESModule(
+ "resource://testing-common/EnterprisePolicyTesting.sys.mjs"
+ );
+
+PoliciesPrefTracker.start();
+
+async function setupPolicyEngineWithJson(json, customSchema) {
+ PoliciesPrefTracker.restoreDefaultValues();
+ if (typeof json != "object") {
+ let filePath = getTestFilePath(json ? json : "non-existing-file.json");
+ return EnterprisePolicyTesting.setupPolicyEngineWithJson(
+ filePath,
+ customSchema
+ );
+ }
+ return EnterprisePolicyTesting.setupPolicyEngineWithJson(json, customSchema);
+}
+
+function checkLockedPref(prefName, prefValue) {
+ EnterprisePolicyTesting.checkPolicyPref(prefName, prefValue, true);
+}
+
+function checkUnlockedPref(prefName, prefValue) {
+ EnterprisePolicyTesting.checkPolicyPref(prefName, prefValue, false);
+}
+
+async function withNewTab(options, taskFn) {
+ let tab = window.openContentTab(options.url);
+ await BrowserTestUtils.browserLoaded(tab.browser);
+
+ let result = await taskFn(tab.browser);
+
+ let tabmail = document.getElementById("tabmail");
+ tabmail.closeTab(tab);
+ return Promise.resolve(result);
+}
+
+add_setup(async function policies_headjs_startWithCleanSlate() {
+ if (Services.policies.status != Ci.nsIEnterprisePolicies.INACTIVE) {
+ await setupPolicyEngineWithJson("");
+ }
+ is(
+ Services.policies.status,
+ Ci.nsIEnterprisePolicies.INACTIVE,
+ "Engine is inactive at the start of the test"
+ );
+});
+
+registerCleanupFunction(async function policies_headjs_finishWithCleanSlate() {
+ if (Services.policies.status != Ci.nsIEnterprisePolicies.INACTIVE) {
+ await setupPolicyEngineWithJson("");
+ }
+ is(
+ Services.policies.status,
+ Ci.nsIEnterprisePolicies.INACTIVE,
+ "Engine is inactive at the end of the test"
+ );
+
+ EnterprisePolicyTesting.resetRunOnceState();
+ PoliciesPrefTracker.stop();
+});
+
+function waitForAddonInstall(addon_id) {
+ return new Promise(resolve => {
+ let listener = {
+ onInstallEnded(install, addon) {
+ if (addon.id == addon_id) {
+ AddonManager.removeInstallListener(listener);
+ resolve();
+ }
+ },
+ onDownloadFailed() {
+ AddonManager.removeInstallListener(listener);
+ resolve();
+ },
+ onInstallFailed() {
+ AddonManager.removeInstallListener(listener);
+ resolve();
+ },
+ };
+ AddonManager.addInstallListener(listener);
+ });
+}
+
+function waitForAddonUninstall(addon_id) {
+ return new Promise(resolve => {
+ let listener = {};
+ listener.onUninstalled = addon => {
+ if (addon.id == addon_id) {
+ AddonManager.removeAddonListener(listener);
+ resolve();
+ }
+ };
+ AddonManager.addAddonListener(listener);
+ });
+}
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/policytest_v0.1.xpi b/comm/mail/components/enterprisepolicies/tests/browser/policytest_v0.1.xpi
new file mode 100644
index 0000000000..ee2a6289ee
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/policytest_v0.1.xpi
Binary files differ
diff --git a/comm/mail/components/enterprisepolicies/tests/browser/policytest_v0.2.xpi b/comm/mail/components/enterprisepolicies/tests/browser/policytest_v0.2.xpi
new file mode 100644
index 0000000000..59d589eba9
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/browser/policytest_v0.2.xpi
Binary files differ
diff --git a/comm/mail/components/enterprisepolicies/tests/moz.build b/comm/mail/components/enterprisepolicies/tests/moz.build
new file mode 100644
index 0000000000..c5014bbc67
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/moz.build
@@ -0,0 +1,16 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+BROWSER_CHROME_MANIFESTS += [
+ "browser/browser.ini",
+ "browser/disable_app_update/browser.ini",
+ "browser/disable_developer_tools/browser.ini",
+ "browser/hardware_acceleration/browser.ini",
+]
+
+XPCSHELL_TESTS_MANIFESTS += [
+ "xpcshell/xpcshell.ini",
+]
diff --git a/comm/mail/components/enterprisepolicies/tests/xpcshell/head.js b/comm/mail/components/enterprisepolicies/tests/xpcshell/head.js
new file mode 100644
index 0000000000..2fcf00a21b
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/xpcshell/head.js
@@ -0,0 +1,140 @@
+/* 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";
+
+const lazy = {};
+
+const { Preferences } = ChromeUtils.importESModule(
+ "resource://gre/modules/Preferences.sys.mjs"
+);
+const { updateAppInfo, getAppInfo } = ChromeUtils.importESModule(
+ "resource://testing-common/AppInfo.sys.mjs"
+);
+const { FileTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/FileTestUtils.sys.mjs"
+);
+const { PermissionTestUtils } = ChromeUtils.import(
+ "resource://testing-common/PermissionTestUtils.jsm"
+);
+ChromeUtils.defineESModuleGetters(lazy, {
+ SearchTestUtils: "resource://testing-common/SearchTestUtils.sys.mjs",
+});
+const { EnterprisePolicyTesting } = ChromeUtils.importESModule(
+ "resource://testing-common/EnterprisePolicyTesting.sys.mjs"
+);
+
+updateAppInfo({
+ name: "XPCShell",
+ ID: "xpcshell@tests.mozilla.org",
+ version: "48",
+ platformVersion: "48",
+});
+
+// This initializes the policy engine for xpcshell tests
+let policies = Cc["@mozilla.org/enterprisepolicies;1"].getService(
+ Ci.nsIObserver
+);
+policies.observe(null, "policies-startup", null);
+
+async function setupPolicyEngineWithJson(json, customSchema) {
+ if (typeof json != "object") {
+ let filePath = do_get_file(json ? json : "non-existing-file.json").path;
+ return EnterprisePolicyTesting.setupPolicyEngineWithJson(
+ filePath,
+ customSchema
+ );
+ }
+ return EnterprisePolicyTesting.setupPolicyEngineWithJson(json, customSchema);
+}
+
+/**
+ * Loads a new enterprise policy, and re-initialise the search service
+ * with the new policy. Also waits for the search service to write the settings
+ * file to disk.
+ *
+ * @param {object} policy
+ * The enterprise policy to use.
+ * @param {object} customSchema
+ * A custom schema to use to validate the enterprise policy.
+ */
+async function setupPolicyEngineWithJsonWithSearch(json, customSchema) {
+ Services.search.wrappedJSObject.reset();
+ if (typeof json != "object") {
+ let filePath = do_get_file(json ? json : "non-existing-file.json").path;
+ await EnterprisePolicyTesting.setupPolicyEngineWithJson(
+ filePath,
+ customSchema
+ );
+ } else {
+ await EnterprisePolicyTesting.setupPolicyEngineWithJson(json, customSchema);
+ }
+ let settingsWritten = lazy.SearchTestUtils.promiseSearchNotification(
+ "write-settings-to-disk-complete"
+ );
+ await Services.search.init();
+ return settingsWritten;
+}
+
+function checkLockedPref(prefName, prefValue) {
+ equal(
+ Preferences.locked(prefName),
+ true,
+ `Pref ${prefName} is correctly locked`
+ );
+ equal(
+ Preferences.get(prefName),
+ prefValue,
+ `Pref ${prefName} has the correct value`
+ );
+}
+
+function checkUnlockedPref(prefName, prefValue) {
+ equal(
+ Preferences.locked(prefName),
+ false,
+ `Pref ${prefName} is correctly unlocked`
+ );
+ equal(
+ Preferences.get(prefName),
+ prefValue,
+ `Pref ${prefName} has the correct value`
+ );
+}
+
+function checkUserPref(prefName, prefValue) {
+ equal(
+ Preferences.get(prefName),
+ prefValue,
+ `Pref ${prefName} has the correct value`
+ );
+}
+
+function checkClearPref(prefName, prefValue) {
+ equal(
+ Services.prefs.prefHasUserValue(prefName),
+ false,
+ `Pref ${prefName} has no user value`
+ );
+}
+
+function checkDefaultPref(prefName, prefValue) {
+ let defaultPrefBranch = Services.prefs.getDefaultBranch("");
+ let prefType = defaultPrefBranch.getPrefType(prefName);
+ notEqual(
+ prefType,
+ Services.prefs.PREF_INVALID,
+ `Pref ${prefName} is set on the default branch`
+ );
+}
+
+function checkUnsetPref(prefName) {
+ let defaultPrefBranch = Services.prefs.getDefaultBranch("");
+ let prefType = defaultPrefBranch.getPrefType(prefName);
+ equal(
+ prefType,
+ Services.prefs.PREF_INVALID,
+ `Pref ${prefName} is not set on the default branch`
+ );
+}
diff --git a/comm/mail/components/enterprisepolicies/tests/xpcshell/test_3rdparty.js b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_3rdparty.js
new file mode 100644
index 0000000000..b9dabb758d
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_3rdparty.js
@@ -0,0 +1,22 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+add_setup(async function () {
+ await setupPolicyEngineWithJson({
+ policies: {
+ "3rdparty": {
+ Extensions: {
+ "3rdparty-policy@mozilla.com": {
+ string: "value",
+ },
+ },
+ },
+ },
+ });
+
+ let extensionPolicy = Services.policies.getExtensionPolicy(
+ "3rdparty-policy@mozilla.com"
+ );
+ deepEqual(extensionPolicy, { string: "value" });
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/xpcshell/test_appupdatepin.js b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_appupdatepin.js
new file mode 100644
index 0000000000..01e3810a05
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_appupdatepin.js
@@ -0,0 +1,80 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const { TelemetryTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/TelemetryTestUtils.sys.mjs"
+);
+
+/**
+ * Note that these tests only ensure that the pin is properly added to the
+ * update URL and to the telemetry. They do not test that the update applied
+ * will be of the correct version. This is because we are not attempting to have
+ * Thunderbird check if the update provided is valid given the pin, we are leaving
+ * it to the update server (Balrog) to find and serve the correct version.
+ */
+
+async function test_update_pin(pinString, pinIsValid = true) {
+ await setupPolicyEngineWithJson({
+ policies: {
+ AppUpdateURL: "https://www.example.com/update.xml",
+ AppUpdatePin: pinString,
+ },
+ });
+ Services.telemetry.clearScalars();
+
+ equal(
+ Services.policies.status,
+ Ci.nsIEnterprisePolicies.ACTIVE,
+ "Engine is active"
+ );
+
+ let policies = Services.policies.getActivePolicies();
+ equal(
+ "AppUpdatePin" in policies,
+ pinIsValid,
+ "AppUpdatePin policy should only be active if the pin was valid."
+ );
+
+ let checker = Cc["@mozilla.org/updates/update-checker;1"].getService(
+ Ci.nsIUpdateChecker
+ );
+ let updateURL = await checker.getUpdateURL(checker.BACKGROUND_CHECK);
+
+ let expected = pinIsValid
+ ? `https://www.example.com/update.xml?pin=${pinString}`
+ : "https://www.example.com/update.xml";
+
+ equal(updateURL, expected, "App Update URL should match expected URL.");
+
+ let scalars = TelemetryTestUtils.getProcessScalars("parent", false, true);
+ if (pinIsValid) {
+ TelemetryTestUtils.assertScalar(
+ scalars,
+ "update.version_pin",
+ pinString,
+ "Update pin telemetry should be set"
+ );
+ } else {
+ TelemetryTestUtils.assertScalarUnset(scalars, "update.version_pin");
+ }
+}
+
+add_task(async function test_app_update_pin() {
+ await test_update_pin("102.");
+ await test_update_pin("102.0.");
+ await test_update_pin("102.1.");
+ await test_update_pin("102.1.1", false);
+ await test_update_pin("102.1.1.", false);
+ await test_update_pin("102", false);
+ await test_update_pin("foobar", false);
+ await test_update_pin("-102.1.", false);
+ await test_update_pin("102.-1.", false);
+ await test_update_pin("102a.1.", false);
+ await test_update_pin("102.1a.", false);
+ await test_update_pin("0102.1.", false);
+ // Should not accept version numbers that will never be in Balrog's pinning
+ // table (i.e. versions before 102.0).
+ await test_update_pin("101.1.", false);
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/xpcshell/test_appupdateurl.js b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_appupdateurl.js
new file mode 100644
index 0000000000..48d04e1a8d
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_appupdateurl.js
@@ -0,0 +1,25 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function test_app_update_URL() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ AppUpdateURL: "https://www.example.com/",
+ },
+ });
+
+ equal(
+ Services.policies.status,
+ Ci.nsIEnterprisePolicies.ACTIVE,
+ "Engine is active"
+ );
+
+ let checker = Cc["@mozilla.org/updates/update-checker;1"].getService(
+ Ci.nsIUpdateChecker
+ );
+ let expected = await checker.getUpdateURL(checker.BACKGROUND_CHECK);
+
+ equal("https://www.example.com/", expected, "Correct app update URL");
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/xpcshell/test_bug1658259.js b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_bug1658259.js
new file mode 100644
index 0000000000..1449e664c2
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_bug1658259.js
@@ -0,0 +1,44 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function test_bug1658259_1() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ OfferToSaveLogins: false,
+ OfferToSaveLoginsDefault: true,
+ },
+ });
+ checkLockedPref("signon.rememberSignons", false);
+});
+
+add_task(async function test_bug1658259_2() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ OfferToSaveLogins: true,
+ OfferToSaveLoginsDefault: false,
+ },
+ });
+ checkLockedPref("signon.rememberSignons", true);
+});
+
+add_task(async function test_bug1658259_3() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ OfferToSaveLoginsDefault: true,
+ OfferToSaveLogins: false,
+ },
+ });
+ checkLockedPref("signon.rememberSignons", false);
+});
+
+add_task(async function test_bug1658259_4() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ OfferToSaveLoginsDefault: false,
+ OfferToSaveLogins: true,
+ },
+ });
+ checkLockedPref("signon.rememberSignons", true);
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/xpcshell/test_clear_blocked_cookies.js b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_clear_blocked_cookies.js
new file mode 100644
index 0000000000..17149f787f
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_clear_blocked_cookies.js
@@ -0,0 +1,118 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+const HOSTNAME_DOMAIN = "browser_policy_clear_blocked_cookies.com";
+const ORIGIN_DOMAIN = "browser_policy_clear_blocked_cookies.org";
+
+add_setup(async function () {
+ const expiry = Date.now() + 24 * 60 * 60;
+ Services.cookies.add(
+ HOSTNAME_DOMAIN,
+ "/",
+ "secure",
+ "true",
+ true,
+ false,
+ false,
+ expiry,
+ {},
+ Ci.nsICookie.SAMESITE_NONE,
+ Ci.nsICookie.SCHEME_HTTPS
+ );
+ Services.cookies.add(
+ HOSTNAME_DOMAIN,
+ "/",
+ "insecure",
+ "true",
+ false,
+ false,
+ false,
+ expiry,
+ {},
+ Ci.nsICookie.SAMESITE_NONE,
+ Ci.nsICookie.SCHEME_HTTP
+ );
+ Services.cookies.add(
+ ORIGIN_DOMAIN,
+ "/",
+ "secure",
+ "true",
+ true,
+ false,
+ false,
+ expiry,
+ {},
+ Ci.nsICookie.SAMESITE_NONE,
+ Ci.nsICookie.SCHEME_HTTPS
+ );
+ Services.cookies.add(
+ ORIGIN_DOMAIN,
+ "/",
+ "insecure",
+ "true",
+ false,
+ false,
+ false,
+ expiry,
+ {},
+ Ci.nsICookie.SAMESITE_NONE,
+ Ci.nsICookie.SCHEME_HTTP
+ );
+ Services.cookies.add(
+ "example.net",
+ "/",
+ "secure",
+ "true",
+ true,
+ false,
+ false,
+ expiry,
+ {},
+ Ci.nsICookie.SAMESITE_NONE,
+ Ci.nsICookie.SCHEME_HTTPS
+ );
+ await setupPolicyEngineWithJson({
+ policies: {
+ Cookies: {
+ Block: [`http://${HOSTNAME_DOMAIN}`, `https://${ORIGIN_DOMAIN}:8080`],
+ },
+ },
+ });
+});
+
+function retrieve_all_cookies(host) {
+ const values = [];
+ for (let cookie of Services.cookies.getCookiesFromHost(host, {})) {
+ values.push({
+ host: cookie.host,
+ name: cookie.name,
+ path: cookie.path,
+ });
+ }
+ return values;
+}
+
+add_task(async function test_cookies_for_blocked_sites_cleared() {
+ const cookies = {
+ hostname: retrieve_all_cookies(HOSTNAME_DOMAIN),
+ origin: retrieve_all_cookies(ORIGIN_DOMAIN),
+ keep: retrieve_all_cookies("example.net"),
+ };
+ const expected = {
+ hostname: [],
+ origin: [],
+ keep: [{ host: "example.net", name: "secure", path: "/" }],
+ };
+ equal(
+ JSON.stringify(cookies),
+ JSON.stringify(expected),
+ "All stored cookies for blocked origins should be cleared"
+ );
+});
+
+add_task(function teardown() {
+ for (let host of [HOSTNAME_DOMAIN, ORIGIN_DOMAIN, "example.net"]) {
+ Services.cookies.removeCookiesWithOriginAttributes("{}", host);
+ }
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/xpcshell/test_macosparser_unflatten.js b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_macosparser_unflatten.js
new file mode 100644
index 0000000000..096852612c
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_macosparser_unflatten.js
@@ -0,0 +1,110 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+let { macOSPoliciesParser } = ChromeUtils.importESModule(
+ "resource://gre/modules/policies/macOSPoliciesParser.sys.mjs"
+);
+
+add_task(async function test_object_unflatten() {
+ // Note: these policies are just examples and they won't actually
+ // run through the policy engine on this test. We're just testing
+ // that the unflattening algorithm produces the correct output.
+ let input = {
+ DisplayBookmarksToolbar: true,
+
+ Homepage__URL: "https://www.mozilla.org",
+ Homepage__Locked: "true",
+ Homepage__Additional__0: "https://extra-homepage-1.example.com",
+ Homepage__Additional__1: "https://extra-homepage-2.example.com",
+
+ WebsiteFilter__Block__0: "*://*.example.org/*",
+ WebsiteFilter__Block__1: "*://*.example.net/*",
+ WebsiteFilter__Exceptions__0: "*://*.example.org/*exception*",
+
+ Permissions__Camera__Allow__0: "https://www.example.com",
+
+ Permissions__Notifications__Allow__0: "https://www.example.com",
+ Permissions__Notifications__Allow__1: "https://www.example.org",
+ Permissions__Notifications__Block__0: "https://www.example.net",
+
+ Permissions__Notifications__BlockNewRequests: true,
+ Permissions__Notifications__Locked: true,
+
+ Bookmarks__0__Title: "Bookmark 1",
+ Bookmarks__0__URL: "https://bookmark1.example.com",
+
+ Bookmarks__1__Title: "Bookmark 2",
+ Bookmarks__1__URL: "https://bookmark2.example.com",
+ Bookmarks__1__Folder: "Folder",
+ };
+
+ let expected = {
+ DisplayBookmarksToolbar: true,
+
+ Homepage: {
+ URL: "https://www.mozilla.org",
+ Locked: "true",
+ Additional: [
+ "https://extra-homepage-1.example.com",
+ "https://extra-homepage-2.example.com",
+ ],
+ },
+
+ WebsiteFilter: {
+ Block: ["*://*.example.org/*", "*://*.example.net/*"],
+ Exceptions: ["*://*.example.org/*exception*"],
+ },
+
+ Permissions: {
+ Camera: {
+ Allow: ["https://www.example.com"],
+ },
+
+ Notifications: {
+ Allow: ["https://www.example.com", "https://www.example.org"],
+ Block: ["https://www.example.net"],
+ BlockNewRequests: true,
+ Locked: true,
+ },
+ },
+
+ Bookmarks: [
+ {
+ Title: "Bookmark 1",
+ URL: "https://bookmark1.example.com",
+ },
+ {
+ Title: "Bookmark 2",
+ URL: "https://bookmark2.example.com",
+ Folder: "Folder",
+ },
+ ],
+ };
+
+ let unflattened = macOSPoliciesParser.unflatten(input);
+
+ deepEqual(unflattened, expected, "Input was unflattened correctly.");
+});
+
+add_task(async function test_array_unflatten() {
+ let input = {
+ Foo__1: 1,
+ Foo__5: 5,
+ Foo__10: 10,
+ Foo__30: 30,
+ Foo__51: 51, // This one should not be included as the limit is 50
+ };
+
+ let unflattened = macOSPoliciesParser.unflatten(input);
+ equal(unflattened.Foo.length, 31, "Array size is correct");
+
+ let expected = {
+ Foo: [, 1, , , , 5], // eslint-disable-line no-sparse-arrays
+ };
+ expected.Foo[10] = 10;
+ expected.Foo[30] = 30;
+
+ deepEqual(unflattened, expected, "Array was unflattened correctly.");
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/xpcshell/test_policy_search_engine.js b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_policy_search_engine.js
new file mode 100644
index 0000000000..be16829867
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_policy_search_engine.js
@@ -0,0 +1,490 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+const { SearchTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/SearchTestUtils.sys.mjs"
+);
+const { TestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/TestUtils.sys.mjs"
+);
+var { AddonTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/AddonTestUtils.sys.mjs"
+);
+
+Services.prefs.setBoolPref("browser.search.log", true);
+SearchTestUtils.init(this);
+
+AddonTestUtils.init(this, false);
+AddonTestUtils.createAppInfo(
+ "xpcshell@tests.mozilla.org",
+ "XPCShell",
+ "48",
+ "48"
+);
+
+add_setup(async () => {
+ await AddonTestUtils.promiseStartupManager();
+ await Services.search.init();
+ console.log("done init");
+});
+
+add_task(async function test_install_and_set_default() {
+ // Make sure we are starting in an expected state to avoid false positive
+ // test results.
+ Assert.notEqual(
+ (await Services.search.getDefault()).name,
+ "MozSearch",
+ "Default search engine should not be MozSearch when test starts"
+ );
+ Assert.equal(
+ Services.search.getEngineByName("Foo"),
+ null,
+ 'Engine "Foo" should not be present when test starts'
+ );
+
+ await setupPolicyEngineWithJsonWithSearch({
+ policies: {
+ SearchEngines: {
+ Add: [
+ {
+ Name: "MozSearch",
+ URLTemplate: "http://example.com/?q={searchTerms}",
+ },
+ ],
+ Default: "MozSearch",
+ },
+ },
+ });
+ // Get in line, because the Search policy callbacks are async.
+ await TestUtils.waitForTick();
+
+ // If this passes, it means that the new search engine was properly installed
+ // *and* was properly set as the default.
+ Assert.equal(
+ (await Services.search.getDefault()).name,
+ "MozSearch",
+ "Specified search engine should be the default"
+ );
+
+ // Clean up
+ await setupPolicyEngineWithJsonWithSearch({});
+ EnterprisePolicyTesting.resetRunOnceState();
+});
+
+add_task(async function test_install_and_set_default_private() {
+ // Make sure we are starting in an expected state to avoid false positive
+ // test results.
+ Assert.notEqual(
+ (await Services.search.getDefaultPrivate()).name,
+ "MozSearch",
+ "Default search engine should not be MozSearch when test starts"
+ );
+ Assert.equal(
+ Services.search.getEngineByName("Foo"),
+ null,
+ 'Engine "Foo" should not be present when test starts'
+ );
+
+ await setupPolicyEngineWithJsonWithSearch({
+ policies: {
+ SearchEngines: {
+ Add: [
+ {
+ Name: "MozSearch",
+ URLTemplate: "http://example.com/?q={searchTerms}",
+ },
+ ],
+ DefaultPrivate: "MozSearch",
+ },
+ },
+ });
+ // Get in line, because the Search policy callbacks are async.
+ await TestUtils.waitForTick();
+
+ // If this passes, it means that the new search engine was properly installed
+ // *and* was properly set as the default.
+ Assert.equal(
+ (await Services.search.getDefaultPrivate()).name,
+ "MozSearch",
+ "Specified search engine should be the default private engine"
+ );
+
+ // Clean up
+ await setupPolicyEngineWithJsonWithSearch({});
+ EnterprisePolicyTesting.resetRunOnceState();
+});
+
+// Same as the last test, but with "PreventInstalls" set to true to make sure
+// it does not prevent search engines from being installed properly
+add_task(async function test_install_and_set_default_prevent_installs() {
+ Assert.notEqual(
+ (await Services.search.getDefault()).name,
+ "MozSearch",
+ "Default search engine should not be MozSearch when test starts"
+ );
+ Assert.equal(
+ Services.search.getEngineByName("Foo"),
+ null,
+ 'Engine "Foo" should not be present when test starts'
+ );
+
+ await setupPolicyEngineWithJsonWithSearch({
+ policies: {
+ SearchEngines: {
+ Add: [
+ {
+ Name: "MozSearch",
+ URLTemplate: "http://example.com/?q={searchTerms}",
+ },
+ ],
+ Default: "MozSearch",
+ PreventInstalls: true,
+ },
+ },
+ });
+ // Get in line, because the Search policy callbacks are async.
+ await TestUtils.waitForTick();
+
+ Assert.equal(
+ (await Services.search.getDefault()).name,
+ "MozSearch",
+ "Specified search engine should be the default"
+ );
+
+ // Clean up
+ await setupPolicyEngineWithJsonWithSearch({});
+ EnterprisePolicyTesting.resetRunOnceState();
+});
+
+add_task(async function test_install_and_remove() {
+ let iconURL =
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=";
+
+ Assert.equal(
+ Services.search.getEngineByName("Foo"),
+ null,
+ 'Engine "Foo" should not be present when test starts'
+ );
+
+ await setupPolicyEngineWithJsonWithSearch({
+ policies: {
+ SearchEngines: {
+ Add: [
+ {
+ Name: "Foo",
+ URLTemplate: "http://example.com/?q={searchTerms}",
+ IconURL: iconURL,
+ },
+ ],
+ },
+ },
+ });
+ // Get in line, because the Search policy callbacks are async.
+ await TestUtils.waitForTick();
+
+ // If this passes, it means that the new search engine was properly installed
+
+ let engine = Services.search.getEngineByName("Foo");
+ Assert.notEqual(engine, null, "Specified search engine should be installed");
+
+ Assert.equal(
+ engine.wrappedJSObject.iconURI.spec,
+ iconURL,
+ "Icon should be present"
+ );
+ Assert.equal(
+ engine.wrappedJSObject.queryCharset,
+ "UTF-8",
+ "Should default to utf-8"
+ );
+
+ await setupPolicyEngineWithJsonWithSearch({
+ policies: {
+ SearchEngines: {
+ Remove: ["Foo"],
+ },
+ },
+ });
+ // Get in line, because the Search policy callbacks are async.
+ await TestUtils.waitForTick();
+
+ // If this passes, it means that the specified engine was properly removed
+ Assert.equal(
+ Services.search.getEngineByName("Foo"),
+ null,
+ "Specified search engine should not be installed"
+ );
+
+ await setupPolicyEngineWithJsonWithSearch({});
+ EnterprisePolicyTesting.resetRunOnceState();
+});
+
+add_task(async function test_install_post_method_engine() {
+ Assert.equal(
+ Services.search.getEngineByName("Post"),
+ null,
+ 'Engine "Post" should not be present when test starts'
+ );
+
+ await setupPolicyEngineWithJsonWithSearch({
+ policies: {
+ SearchEngines: {
+ Add: [
+ {
+ Name: "Post",
+ Method: "POST",
+ PostData: "q={searchTerms}&anotherParam=yes",
+ URLTemplate: "http://example.com/",
+ },
+ ],
+ },
+ },
+ });
+ // Get in line, because the Search policy callbacks are async.
+ await TestUtils.waitForTick();
+
+ let engine = Services.search.getEngineByName("Post");
+ Assert.notEqual(engine, null, "Specified search engine should be installed");
+
+ Assert.equal(
+ engine.wrappedJSObject._urls[0].method,
+ "POST",
+ "Method should be POST"
+ );
+
+ let submission = engine.getSubmission("term", "text/html");
+ Assert.notEqual(submission.postData, null, "Post data should not be null");
+
+ let scriptableInputStream = Cc[
+ "@mozilla.org/scriptableinputstream;1"
+ ].createInstance(Ci.nsIScriptableInputStream);
+ scriptableInputStream.init(submission.postData);
+ Assert.equal(
+ scriptableInputStream.read(scriptableInputStream.available()),
+ "q=term&anotherParam=yes",
+ "Post data should be present"
+ );
+
+ await setupPolicyEngineWithJsonWithSearch({});
+ EnterprisePolicyTesting.resetRunOnceState();
+});
+
+add_task(async function test_install_with_encoding() {
+ // Make sure we are starting in an expected state to avoid false positive
+ // test results.
+ Assert.equal(
+ Services.search.getEngineByName("Encoding"),
+ null,
+ 'Engine "Encoding" should not be present when test starts'
+ );
+
+ await setupPolicyEngineWithJsonWithSearch({
+ policies: {
+ SearchEngines: {
+ Add: [
+ {
+ Name: "Encoding",
+ Encoding: "windows-1252",
+ URLTemplate: "http://example.com/?q={searchTerms}",
+ },
+ ],
+ },
+ },
+ });
+ // Get in line, because the Search policy callbacks are async.
+ await TestUtils.waitForTick();
+
+ let engine = Services.search.getEngineByName("Encoding");
+ Assert.equal(
+ engine.wrappedJSObject.queryCharset,
+ "windows-1252",
+ "Should have correct encoding"
+ );
+
+ // Clean up
+ await setupPolicyEngineWithJsonWithSearch({});
+ EnterprisePolicyTesting.resetRunOnceState();
+});
+
+add_task(async function test_install_and_update() {
+ await setupPolicyEngineWithJsonWithSearch({
+ policies: {
+ SearchEngines: {
+ Add: [
+ {
+ Name: "ToUpdate",
+ URLTemplate: "http://initial.example.com/?q={searchTerms}",
+ },
+ ],
+ },
+ },
+ });
+ // Get in line, because the Search policy callbacks are async.
+ await TestUtils.waitForTick();
+
+ let engine = Services.search.getEngineByName("ToUpdate");
+ Assert.notEqual(engine, null, "Specified search engine should be installed");
+
+ Assert.equal(
+ engine.getSubmission("test").uri.spec,
+ "http://initial.example.com/?q=test",
+ "Initial submission URL should be correct."
+ );
+
+ await setupPolicyEngineWithJsonWithSearch({
+ policies: {
+ SearchEngines: {
+ Add: [
+ {
+ Name: "ToUpdate",
+ URLTemplate: "http://update.example.com/?q={searchTerms}",
+ },
+ ],
+ },
+ },
+ });
+ // Get in line, because the Search policy callbacks are async.
+ await TestUtils.waitForTick();
+
+ engine = Services.search.getEngineByName("ToUpdate");
+ Assert.notEqual(engine, null, "Specified search engine should be installed");
+
+ Assert.equal(
+ engine.getSubmission("test").uri.spec,
+ "http://update.example.com/?q=test",
+ "Updated Submission URL should be correct."
+ );
+
+ // Clean up
+ await setupPolicyEngineWithJsonWithSearch({});
+ EnterprisePolicyTesting.resetRunOnceState();
+});
+
+add_task(async function test_install_with_suggest() {
+ // Make sure we are starting in an expected state to avoid false positive
+ // test results.
+ Assert.equal(
+ Services.search.getEngineByName("Suggest"),
+ null,
+ 'Engine "Suggest" should not be present when test starts'
+ );
+
+ await setupPolicyEngineWithJsonWithSearch({
+ policies: {
+ SearchEngines: {
+ Add: [
+ {
+ Name: "Suggest",
+ URLTemplate: "http://example.com/?q={searchTerms}",
+ SuggestURLTemplate: "http://suggest.example.com/?q={searchTerms}",
+ },
+ ],
+ },
+ },
+ });
+ // Get in line, because the Search policy callbacks are async.
+ await TestUtils.waitForTick();
+
+ let engine = Services.search.getEngineByName("Suggest");
+
+ Assert.equal(
+ engine.getSubmission("test", "application/x-suggestions+json").uri.spec,
+ "http://suggest.example.com/?q=test",
+ "Updated Submission URL should be correct."
+ );
+
+ // Clean up
+ await setupPolicyEngineWithJsonWithSearch({});
+ EnterprisePolicyTesting.resetRunOnceState();
+});
+
+add_task(async function test_install_and_restart_keeps_settings() {
+ // Make sure we are starting in an expected state to avoid false positive
+ // test results.
+ Assert.equal(
+ Services.search.getEngineByName("Settings"),
+ null,
+ 'Engine "Settings" should not be present when test starts'
+ );
+
+ await setupPolicyEngineWithJsonWithSearch({
+ policies: {
+ SearchEngines: {
+ Add: [
+ {
+ Name: "Settings",
+ URLTemplate: "http://example.com/?q={searchTerms}",
+ },
+ ],
+ },
+ },
+ });
+ // Get in line, because the Search policy callbacks are async.
+ await TestUtils.waitForTick();
+
+ let settingsWritten = SearchTestUtils.promiseSearchNotification(
+ "write-settings-to-disk-complete"
+ );
+ let engine = Services.search.getEngineByName("Settings");
+ engine.hidden = true;
+ engine.alias = "settings";
+ await settingsWritten;
+
+ await setupPolicyEngineWithJsonWithSearch({
+ policies: {
+ SearchEngines: {
+ Add: [
+ {
+ Name: "Settings",
+ URLTemplate: "http://example.com/?q={searchTerms}",
+ },
+ ],
+ },
+ },
+ });
+
+ engine = Services.search.getEngineByName("Settings");
+
+ Assert.ok(engine.hidden, "Should have kept the engine hidden after restart");
+ Assert.equal(
+ engine.alias,
+ "settings",
+ "Should have kept the engine alias after restart"
+ );
+
+ // Clean up
+ await setupPolicyEngineWithJsonWithSearch({});
+ EnterprisePolicyTesting.resetRunOnceState();
+});
+
+add_task(async function test_reset_default() {
+ await setupPolicyEngineWithJsonWithSearch({
+ policies: {
+ SearchEngines: {
+ Remove: ["DuckDuckGo"],
+ },
+ },
+ });
+ // Get in line, because the Search policy callbacks are async.
+ await TestUtils.waitForTick();
+
+ let engine = Services.search.getEngineByName("DuckDuckGo");
+
+ Assert.equal(
+ engine.hidden,
+ true,
+ "Application specified engine should be hidden."
+ );
+
+ await Services.search.restoreDefaultEngines();
+
+ engine = Services.search.getEngineByName("DuckDuckGo");
+ Assert.equal(
+ engine.hidden,
+ false,
+ "Application specified engine should not be hidden"
+ );
+
+ EnterprisePolicyTesting.resetRunOnceState();
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/xpcshell/test_preferences.js b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_preferences.js
new file mode 100644
index 0000000000..6ad883fe42
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_preferences.js
@@ -0,0 +1,255 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const OLD_PREFERENCES_TESTS = [
+ {
+ policies: {
+ Preferences: {
+ "network.IDN_show_punycode": true,
+ "accessibility.force_disabled": 1,
+ "security.default_personal_cert": "Select Automatically",
+ // "geo.enabled": 1,
+ "extensions.getAddons.showPane": 0,
+ },
+ },
+ lockedPrefs: {
+ "network.IDN_show_punycode": true,
+ "accessibility.force_disabled": 1,
+ "security.default_personal_cert": "Select Automatically",
+ // "geo.enabled": true,
+ "extensions.getAddons.showPane": false,
+ },
+ },
+];
+
+const NEW_PREFERENCES_TESTS = [
+ {
+ policies: {
+ Preferences: {
+ "browser.policies.test.default.boolean": {
+ Value: true,
+ Status: "default",
+ },
+ "browser.policies.test.default.string": {
+ Value: "string",
+ Status: "default",
+ },
+ "browser.policies.test.default.number": {
+ Value: 11,
+ Status: "default",
+ },
+ "browser.policies.test.locked.boolean": {
+ Value: true,
+ Status: "locked",
+ },
+ "browser.policies.test.locked.string": {
+ Value: "string",
+ Status: "locked",
+ },
+ "browser.policies.test.locked.number": {
+ Value: 11,
+ Status: "locked",
+ },
+ "browser.policies.test.user.boolean": {
+ Value: true,
+ Status: "user",
+ },
+ "browser.policies.test.user.string": {
+ Value: "string",
+ Status: "user",
+ },
+ "browser.policies.test.user.number": {
+ Value: 11,
+ Status: "user",
+ },
+ "mail.openMessageBehavior": {
+ Value: 1,
+ Status: "locked",
+ },
+ "mailnews.display.prefer_plaintext": {
+ Value: true,
+ Status: "locked",
+ },
+ "chat.enabled": {
+ Value: false,
+ Status: "locked",
+ },
+ "calendar.agenda.days": {
+ Value: 21,
+ Status: "locked",
+ },
+ },
+ },
+ defaultPrefs: {
+ "browser.policies.test.default.boolean": true,
+ "browser.policies.test.default.string": "string",
+ "browser.policies.test.default.number": 11,
+ },
+ lockedPrefs: {
+ "browser.policies.test.locked.boolean": true,
+ "browser.policies.test.locked.string": "string",
+ "browser.policies.test.locked.number": 11,
+ "mail.openMessageBehavior": 1,
+ "mailnews.display.prefer_plaintext": true,
+ "chat.enabled": false,
+ "calendar.agenda.days": 21,
+ },
+ userPrefs: {
+ "browser.policies.test.user.boolean": true,
+ "browser.policies.test.user.string": "string",
+ "browser.policies.test.user.number": 11,
+ },
+ },
+ {
+ policies: {
+ Preferences: {
+ "browser.policies.test.user.boolean": {
+ Status: "clear",
+ },
+ "browser.policies.test.user.string": {
+ Status: "clear",
+ },
+ "browser.policies.test.user.number": {
+ Status: "clear",
+ },
+ },
+ },
+
+ clearPrefs: {
+ "browser.policies.test.user.boolean": true,
+ "browser.policies.test.user.string": "string",
+ "browser.policies.test.user.number": 11,
+ },
+ },
+];
+
+const BAD_PREFERENCES_TESTS = [
+ {
+ policies: {
+ Preferences: {
+ "not.a.valid.branch": {
+ Value: true,
+ Status: "default",
+ },
+ "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer":
+ {
+ Value: true,
+ Status: "default",
+ },
+ },
+ },
+ defaultPrefs: {
+ "not.a.valid.branch": true,
+ "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer": true,
+ },
+ },
+];
+
+add_task(async function test_old_preferences() {
+ for (let test of OLD_PREFERENCES_TESTS) {
+ await setupPolicyEngineWithJson({
+ policies: test.policies,
+ });
+
+ info("Checking policy: " + Object.keys(test.policies)[0]);
+
+ for (let [prefName, prefValue] of Object.entries(test.lockedPrefs || {})) {
+ checkLockedPref(prefName, prefValue);
+ }
+ }
+});
+
+add_task(async function test_new_preferences() {
+ for (let test of NEW_PREFERENCES_TESTS) {
+ await setupPolicyEngineWithJson({
+ policies: test.policies,
+ });
+
+ info("Checking policy: " + Object.keys(test.policies)[0]);
+
+ for (let [prefName, prefValue] of Object.entries(test.lockedPrefs || {})) {
+ checkLockedPref(prefName, prefValue);
+ }
+
+ for (let [prefName, prefValue] of Object.entries(test.defaultPrefs || {})) {
+ checkDefaultPref(prefName, prefValue);
+ }
+
+ for (let [prefName, prefValue] of Object.entries(test.userPrefs || {})) {
+ checkUserPref(prefName, prefValue);
+ }
+
+ for (let [prefName, prefValue] of Object.entries(test.clearPrefs || {})) {
+ checkClearPref(prefName, prefValue);
+ }
+ }
+});
+
+add_task(async function test_bad_preferences() {
+ for (let test of BAD_PREFERENCES_TESTS) {
+ await setupPolicyEngineWithJson({
+ policies: test.policies,
+ });
+
+ info("Checking policy: " + Object.keys(test.policies)[0]);
+
+ for (let prefName of Object.entries(test.defaultPrefs || {})) {
+ checkUnsetPref(prefName);
+ }
+ }
+});
+
+add_task(async function test_user_default_preference() {
+ Services.prefs
+ .getDefaultBranch("")
+ .setBoolPref("browser.policies.test.override", true);
+
+ await setupPolicyEngineWithJson({
+ policies: {
+ Preferences: {
+ "browser.policies.test.override": {
+ Value: true,
+ Status: "user",
+ },
+ },
+ },
+ });
+
+ checkUserPref("browser.policies.test.override", true);
+});
+
+add_task(async function test_security_preference() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ Preferences: {
+ "security.this.should.not.work": {
+ Value: true,
+ Status: "default",
+ },
+ },
+ },
+ });
+
+ checkUnsetPref("security.this.should.not.work");
+});
+
+add_task(async function test_bug_1666836() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ Preferences: {
+ "browser.tabs.warnOnClose": {
+ Value: 0,
+ Status: "default",
+ },
+ },
+ },
+ });
+
+ equal(
+ Preferences.get("browser.tabs.warnOnClose"),
+ false,
+ `browser.tabs.warnOnClose should be false`
+ );
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/xpcshell/test_proxy.js b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_proxy.js
new file mode 100644
index 0000000000..ef5ad1e178
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_proxy.js
@@ -0,0 +1,122 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+add_task(async function test_proxy_modes_and_autoconfig() {
+ // Directly test the proxy Mode and AutoconfigURL parameters through
+ // the API instead of the policy engine, because the test harness
+ // uses these prefs, and changing them interfere with the harness.
+
+ // Checks that every Mode value translates correctly to the expected pref value
+ let { ProxyPolicies, PROXY_TYPES_MAP } = ChromeUtils.importESModule(
+ "resource:///modules/policies/ProxyPolicies.sys.mjs"
+ );
+
+ for (let [mode, expectedValue] of PROXY_TYPES_MAP) {
+ ProxyPolicies.configureProxySettings({ Mode: mode }, (_, value) => {
+ equal(value, expectedValue, "Correct proxy mode");
+ });
+ }
+
+ let autoconfigURL = new URL("data:text/plain,test");
+ ProxyPolicies.configureProxySettings(
+ { AutoConfigURL: autoconfigURL },
+ (_, value) => {
+ equal(value, autoconfigURL.href, "AutoconfigURL correctly set");
+ }
+ );
+});
+
+add_task(async function test_proxy_boolean_settings() {
+ // Tests that both false and true values are correctly set and locked
+ await setupPolicyEngineWithJson({
+ policies: {
+ Proxy: {
+ UseProxyForDNS: false,
+ AutoLogin: false,
+ },
+ },
+ });
+
+ checkUnlockedPref("network.proxy.socks_remote_dns", false);
+ checkUnlockedPref("signon.autologin.proxy", false);
+
+ await setupPolicyEngineWithJson({
+ policies: {
+ Proxy: {
+ UseProxyForDNS: true,
+ AutoLogin: true,
+ },
+ },
+ });
+
+ checkUnlockedPref("network.proxy.socks_remote_dns", true);
+ checkUnlockedPref("signon.autologin.proxy", true);
+});
+
+add_task(async function test_proxy_socks_and_passthrough() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ Proxy: {
+ SOCKSVersion: 4,
+ Passthrough: "a, b, c",
+ },
+ },
+ });
+
+ checkUnlockedPref("network.proxy.socks_version", 4);
+ checkUnlockedPref("network.proxy.no_proxies_on", "a, b, c");
+});
+
+add_task(async function test_proxy_addresses() {
+ function checkProxyPref(proxytype, address, port) {
+ checkUnlockedPref(`network.proxy.${proxytype}`, address);
+ checkUnlockedPref(`network.proxy.${proxytype}_port`, port);
+ }
+
+ await setupPolicyEngineWithJson({
+ policies: {
+ Proxy: {
+ HTTPProxy: "http.proxy.example.com:10",
+ SSLProxy: "ssl.proxy.example.com:30",
+ SOCKSProxy: "socks.proxy.example.com:40",
+ },
+ },
+ });
+
+ checkProxyPref("http", "http.proxy.example.com", 10);
+ checkProxyPref("ssl", "ssl.proxy.example.com", 30);
+ checkProxyPref("socks", "socks.proxy.example.com", 40);
+
+ // Do the same, but now use the UseHTTPProxyForAllProtocols option
+ // and check that it takes effect.
+ await setupPolicyEngineWithJson({
+ policies: {
+ Proxy: {
+ HTTPProxy: "http.proxy.example.com:10",
+ // FTP support was removed in bug 1574475
+ // Setting an FTPProxy should result in a warning but should not fail
+ FTPProxy: "ftp.proxy.example.com:20",
+ SSLProxy: "ssl.proxy.example.com:30",
+ SOCKSProxy: "socks.proxy.example.com:40",
+ UseHTTPProxyForAllProtocols: true,
+ },
+ },
+ });
+
+ checkProxyPref("http", "http.proxy.example.com", 10);
+ checkProxyPref("ssl", "http.proxy.example.com", 10);
+ checkProxyPref("socks", "http.proxy.example.com", 10);
+
+ // Make sure the FTPProxy setting did nothing
+ Assert.equal(
+ Preferences.has("network.proxy.ftp"),
+ false,
+ "network.proxy.ftp should not be set"
+ );
+ Assert.equal(
+ Preferences.has("network.proxy.ftp_port"),
+ false,
+ "network.proxy.ftp_port should not be set"
+ );
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/xpcshell/test_requestedlocales.js b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_requestedlocales.js
new file mode 100644
index 0000000000..6c298cee5a
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_requestedlocales.js
@@ -0,0 +1,47 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const REQ_LOC_CHANGE_EVENT = "intl:requested-locales-changed";
+
+function promiseLocaleChanged(requestedLocale) {
+ return new Promise(resolve => {
+ let localeObserver = {
+ observe(aSubject, aTopic, aData) {
+ switch (aTopic) {
+ case REQ_LOC_CHANGE_EVENT:
+ let reqLocs = Services.locale.requestedLocales;
+ equal(reqLocs[0], requestedLocale);
+ Services.obs.removeObserver(localeObserver, REQ_LOC_CHANGE_EVENT);
+ resolve();
+ }
+ },
+ };
+ Services.obs.addObserver(localeObserver, REQ_LOC_CHANGE_EVENT);
+ });
+}
+
+add_task(async function test_requested_locale_array() {
+ let originalLocales = Services.locale.requestedLocales;
+ let localePromise = promiseLocaleChanged("de");
+ await setupPolicyEngineWithJson({
+ policies: {
+ RequestedLocales: ["de"],
+ },
+ });
+ await localePromise;
+ Services.locale.requestedLocales = originalLocales;
+});
+
+add_task(async function test_requested_locale_string() {
+ let originalLocales = Services.locale.requestedLocales;
+ let localePromise = promiseLocaleChanged("fr");
+ await setupPolicyEngineWithJson({
+ policies: {
+ RequestedLocales: "fr",
+ },
+ });
+ await localePromise;
+ Services.locale.requestedLocales = originalLocales;
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/xpcshell/test_runOnce_helper.js b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_runOnce_helper.js
new file mode 100644
index 0000000000..c8e73b3422
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_runOnce_helper.js
@@ -0,0 +1,21 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+let { runOnce } = ChromeUtils.importESModule(
+ "resource:///modules/policies/Policies.sys.mjs"
+);
+
+let runCount = 0;
+function callback() {
+ runCount++;
+}
+
+add_task(async function test_runonce_helper() {
+ runOnce("test_action", callback);
+ equal(runCount, 1, "Callback ran for the first time.");
+
+ runOnce("test_action", callback);
+ equal(runCount, 1, "Callback didn't run again.");
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/xpcshell/test_simple_pref_policies.js b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_simple_pref_policies.js
new file mode 100644
index 0000000000..90da242a72
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_simple_pref_policies.js
@@ -0,0 +1,378 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/*
+ * Use this file to add tests to policies that are
+ * simple pref flips.
+ *
+ * It's best to make a test to actually test the feature
+ * instead of the pref flip, but if that feature is well
+ * covered by tests, including that its pref actually works,
+ * it's OK to have the policy test here just to ensure
+ * that the right pref values are set.
+ */
+
+const POLICIES_TESTS = [
+ /*
+ * Example:
+ * {
+ * // Policies to be set at once through the engine
+ * policies: { "DisableFoo": true, "ConfigureBar": 42 },
+ *
+ * // Locked prefs to check
+ * lockedPrefs: { "feature.foo": false },
+ *
+ * // Unlocked prefs to check
+ * unlockedPrefs: { "bar.baz": 42 }
+ * },
+ */
+
+ // POLICY: RememberPasswords
+ {
+ policies: { OfferToSaveLogins: false },
+ lockedPrefs: { "signon.rememberSignons": false },
+ },
+ {
+ policies: { OfferToSaveLogins: true },
+ lockedPrefs: { "signon.rememberSignons": true },
+ },
+
+ // POLICY: DisableSecurityBypass
+ {
+ policies: {
+ DisableSecurityBypass: {
+ InvalidCertificate: true,
+ SafeBrowsing: true,
+ },
+ },
+ lockedPrefs: {
+ "security.certerror.hideAddException": true,
+ "browser.safebrowsing.allowOverride": false,
+ },
+ },
+
+ // POLICY: DisableBuiltinPDFViewer
+ {
+ policies: { DisableBuiltinPDFViewer: true },
+ lockedPrefs: { "pdfjs.disabled": true },
+ },
+
+ // POLICY: Authentication
+ {
+ policies: {
+ Authentication: {
+ SPNEGO: ["a.com", "b.com"],
+ Delegated: ["a.com", "b.com"],
+ NTLM: ["a.com", "b.com"],
+ AllowNonFQDN: {
+ SPNEGO: true,
+ NTLM: true,
+ },
+ AllowProxies: {
+ SPNEGO: false,
+ NTLM: false,
+ },
+ PrivateBrowsing: true,
+ },
+ },
+ lockedPrefs: {
+ "network.negotiate-auth.trusted-uris": "a.com, b.com",
+ "network.negotiate-auth.delegation-uris": "a.com, b.com",
+ "network.automatic-ntlm-auth.trusted-uris": "a.com, b.com",
+ "network.automatic-ntlm-auth.allow-non-fqdn": true,
+ "network.negotiate-auth.allow-non-fqdn": true,
+ "network.automatic-ntlm-auth.allow-proxies": false,
+ "network.negotiate-auth.allow-proxies": false,
+ "network.auth.private-browsing-sso": true,
+ },
+ },
+
+ // POLICY: Authentication (unlocked)
+ {
+ policies: {
+ Authentication: {
+ SPNEGO: ["a.com", "b.com"],
+ Delegated: ["a.com", "b.com"],
+ NTLM: ["a.com", "b.com"],
+ AllowNonFQDN: {
+ SPNEGO: true,
+ NTLM: true,
+ },
+ AllowProxies: {
+ SPNEGO: false,
+ NTLM: false,
+ },
+ PrivateBrowsing: true,
+ Locked: false,
+ },
+ },
+ unlockedPrefs: {
+ "network.negotiate-auth.trusted-uris": "a.com, b.com",
+ "network.negotiate-auth.delegation-uris": "a.com, b.com",
+ "network.automatic-ntlm-auth.trusted-uris": "a.com, b.com",
+ "network.automatic-ntlm-auth.allow-non-fqdn": true,
+ "network.negotiate-auth.allow-non-fqdn": true,
+ "network.automatic-ntlm-auth.allow-proxies": false,
+ "network.negotiate-auth.allow-proxies": false,
+ "network.auth.private-browsing-sso": true,
+ },
+ },
+
+ // POLICY: Certificates (true)
+ {
+ policies: {
+ Certificates: {
+ ImportEnterpriseRoots: true,
+ },
+ },
+ lockedPrefs: {
+ "security.enterprise_roots.enabled": true,
+ },
+ },
+
+ // POLICY: Certificates (false)
+ {
+ policies: {
+ Certificates: {
+ ImportEnterpriseRoots: false,
+ },
+ },
+ lockedPrefs: {
+ "security.enterprise_roots.enabled": false,
+ },
+ },
+
+ // POLICY: InstallAddons.Default (block addon installs)
+ {
+ policies: {
+ InstallAddonsPermission: {
+ Default: false,
+ },
+ },
+ lockedPrefs: {
+ "xpinstall.enabled": false,
+ },
+ },
+
+ // POLICY: DNSOverHTTPS Locked
+ {
+ policies: {
+ DNSOverHTTPS: {
+ Enabled: true,
+ ProviderURL: "http://example.com/provider",
+ ExcludedDomains: ["example.com", "example.org"],
+ Locked: true,
+ },
+ },
+ lockedPrefs: {
+ "network.trr.mode": 2,
+ "network.trr.uri": "http://example.com/provider",
+ "network.trr.excluded-domains": "example.com,example.org",
+ },
+ },
+
+ // POLICY: DNSOverHTTPS Unlocked
+ {
+ policies: {
+ DNSOverHTTPS: {
+ Enabled: false,
+ ProviderURL: "http://example.com/provider",
+ ExcludedDomains: ["example.com", "example.org"],
+ },
+ },
+ unlockedPrefs: {
+ "network.trr.mode": 5,
+ "network.trr.uri": "http://example.com/provider",
+ "network.trr.excluded-domains": "example.com,example.org",
+ },
+ },
+
+ // POLICY: SSLVersionMin/SSLVersionMax (1)
+ {
+ policies: {
+ SSLVersionMin: "tls1",
+ SSLVersionMax: "tls1.1",
+ },
+ lockedPrefs: {
+ "security.tls.version.min": 1,
+ "security.tls.version.max": 2,
+ },
+ },
+
+ // POLICY: SSLVersionMin/SSLVersionMax (2)
+ {
+ policies: {
+ SSLVersionMin: "tls1.2",
+ SSLVersionMax: "tls1.3",
+ },
+ lockedPrefs: {
+ "security.tls.version.min": 3,
+ "security.tls.version.max": 4,
+ },
+ },
+
+ // POLICY: CaptivePortal
+ {
+ policies: {
+ CaptivePortal: false,
+ },
+ lockedPrefs: {
+ "network.captive-portal-service.enabled": false,
+ },
+ },
+
+ // POLICY: NetworkPrediction
+ {
+ policies: {
+ NetworkPrediction: false,
+ },
+ lockedPrefs: {
+ "network.dns.disablePrefetch": true,
+ "network.dns.disablePrefetchFromHTTPS": true,
+ },
+ },
+
+ // POLICY: ExtensionUpdate
+ {
+ policies: {
+ ExtensionUpdate: false,
+ },
+ lockedPrefs: {
+ "extensions.update.enabled": false,
+ },
+ },
+
+ // POLICY: OfferToSaveLoginsDefault
+ {
+ policies: {
+ OfferToSaveLoginsDefault: false,
+ },
+ unlockedPrefs: {
+ "signon.rememberSignons": false,
+ },
+ },
+
+ // POLICY: PDFjs
+
+ {
+ policies: {
+ PDFjs: {
+ Enabled: false,
+ EnablePermissions: true,
+ },
+ },
+ lockedPrefs: {
+ "pdfjs.disabled": true,
+ "pdfjs.enablePermissions": true,
+ },
+ },
+
+ // POLICY: DisabledCiphers
+ {
+ policies: {
+ DisabledCiphers: {
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: false,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: false,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: false,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: false,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: false,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: false,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: false,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: false,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: false,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: false,
+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA: false,
+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA: false,
+ TLS_RSA_WITH_AES_128_GCM_SHA256: false,
+ TLS_RSA_WITH_AES_256_GCM_SHA384: false,
+ TLS_RSA_WITH_AES_128_CBC_SHA: false,
+ TLS_RSA_WITH_AES_256_CBC_SHA: false,
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA: false,
+ },
+ },
+ lockedPrefs: {
+ "security.ssl3.ecdhe_rsa_aes_128_gcm_sha256": true,
+ "security.ssl3.ecdhe_ecdsa_aes_128_gcm_sha256": true,
+ "security.ssl3.ecdhe_ecdsa_chacha20_poly1305_sha256": true,
+ "security.ssl3.ecdhe_rsa_chacha20_poly1305_sha256": true,
+ "security.ssl3.ecdhe_ecdsa_aes_256_gcm_sha384": true,
+ "security.ssl3.ecdhe_rsa_aes_256_gcm_sha384": true,
+ "security.ssl3.ecdhe_rsa_aes_128_sha": true,
+ "security.ssl3.ecdhe_ecdsa_aes_128_sha": true,
+ "security.ssl3.ecdhe_rsa_aes_256_sha": true,
+ "security.ssl3.ecdhe_ecdsa_aes_256_sha": true,
+ "security.ssl3.dhe_rsa_aes_128_sha": true,
+ "security.ssl3.dhe_rsa_aes_256_sha": true,
+ "security.ssl3.rsa_aes_128_gcm_sha256": true,
+ "security.ssl3.rsa_aes_256_gcm_sha384": true,
+ "security.ssl3.rsa_aes_128_sha": true,
+ "security.ssl3.rsa_aes_256_sha": true,
+ "security.ssl3.deprecated.rsa_des_ede3_sha": true,
+ },
+ },
+
+ {
+ policies: {
+ DisabledCiphers: {
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: true,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: true,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: true,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: true,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: true,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: true,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: true,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: true,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: true,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: true,
+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA: true,
+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA: true,
+ TLS_RSA_WITH_AES_128_GCM_SHA256: true,
+ TLS_RSA_WITH_AES_256_GCM_SHA384: true,
+ TLS_RSA_WITH_AES_128_CBC_SHA: true,
+ TLS_RSA_WITH_AES_256_CBC_SHA: true,
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA: true,
+ },
+ },
+ lockedPrefs: {
+ "security.ssl3.ecdhe_rsa_aes_128_gcm_sha256": false,
+ "security.ssl3.ecdhe_ecdsa_aes_128_gcm_sha256": false,
+ "security.ssl3.ecdhe_ecdsa_chacha20_poly1305_sha256": false,
+ "security.ssl3.ecdhe_rsa_chacha20_poly1305_sha256": false,
+ "security.ssl3.ecdhe_ecdsa_aes_256_gcm_sha384": false,
+ "security.ssl3.ecdhe_rsa_aes_256_gcm_sha384": false,
+ "security.ssl3.ecdhe_rsa_aes_128_sha": false,
+ "security.ssl3.ecdhe_ecdsa_aes_128_sha": false,
+ "security.ssl3.ecdhe_rsa_aes_256_sha": false,
+ "security.ssl3.ecdhe_ecdsa_aes_256_sha": false,
+ "security.ssl3.dhe_rsa_aes_128_sha": false,
+ "security.ssl3.dhe_rsa_aes_256_sha": false,
+ "security.ssl3.rsa_aes_128_gcm_sha256": false,
+ "security.ssl3.rsa_aes_256_gcm_sha384": false,
+ "security.ssl3.rsa_aes_128_sha": false,
+ "security.ssl3.rsa_aes_256_sha": false,
+ "security.ssl3.deprecated.rsa_des_ede3_sha": false,
+ },
+ },
+];
+
+add_task(async function test_policy_simple_prefs() {
+ for (let test of POLICIES_TESTS) {
+ await setupPolicyEngineWithJson({
+ policies: test.policies,
+ });
+
+ info("Checking policy: " + Object.keys(test.policies)[0]);
+
+ for (let [prefName, prefValue] of Object.entries(test.lockedPrefs || {})) {
+ checkLockedPref(prefName, prefValue);
+ }
+
+ for (let [prefName, prefValue] of Object.entries(
+ test.unlockedPrefs || {}
+ )) {
+ checkUnlockedPref(prefName, prefValue);
+ }
+ }
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/xpcshell/test_sorted_alphabetically.js b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_sorted_alphabetically.js
new file mode 100644
index 0000000000..0d246c850c
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/xpcshell/test_sorted_alphabetically.js
@@ -0,0 +1,48 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+function checkArrayIsSorted(array, msg) {
+ let sorted = true;
+ let sortedArray = array.slice().sort(function (a, b) {
+ return a.localeCompare(b);
+ });
+
+ for (let i = 0; i < array.length; i++) {
+ if (array[i] != sortedArray[i]) {
+ sorted = false;
+ break;
+ }
+ }
+ ok(sorted, msg);
+}
+
+add_task(async function test_policies_sorted() {
+ let { schema } = ChromeUtils.importESModule(
+ "resource:///modules/policies/schema.sys.mjs"
+ );
+ let { Policies } = ChromeUtils.importESModule(
+ "resource:///modules/policies/Policies.sys.mjs"
+ );
+
+ checkArrayIsSorted(
+ Object.keys(schema.properties),
+ "policies-schema.json is alphabetically sorted."
+ );
+ checkArrayIsSorted(
+ Object.keys(Policies),
+ "Policies.jsm is alphabetically sorted."
+ );
+});
+
+add_task(async function check_naming_conventions() {
+ let { schema } = ChromeUtils.importESModule(
+ "resource:///modules/policies/schema.sys.mjs"
+ );
+ equal(
+ Object.keys(schema.properties).some(key => key.includes("__")),
+ false,
+ "Can't use __ in a policy name as it's used as a delimiter"
+ );
+});
diff --git a/comm/mail/components/enterprisepolicies/tests/xpcshell/xpcshell.ini b/comm/mail/components/enterprisepolicies/tests/xpcshell/xpcshell.ini
new file mode 100644
index 0000000000..ab47cca7bd
--- /dev/null
+++ b/comm/mail/components/enterprisepolicies/tests/xpcshell/xpcshell.ini
@@ -0,0 +1,18 @@
+[DEFAULT]
+firefox-appdir = browser
+head = head.js
+
+[test_3rdparty.js]
+[test_appupdatepin.js]
+[test_appupdateurl.js]
+[test_bug1658259.js]
+[test_clear_blocked_cookies.js]
+[test_macosparser_unflatten.js]
+skip-if = os != 'mac'
+[test_policy_search_engine.js]
+[test_preferences.js]
+[test_proxy.js]
+[test_requestedlocales.js]
+[test_runOnce_helper.js]
+[test_simple_pref_policies.js]
+[test_sorted_alphabetically.js]