summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/update/tests/unit_background_update
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /toolkit/mozapps/update/tests/unit_background_update
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/mozapps/update/tests/unit_background_update')
-rw-r--r--toolkit/mozapps/update/tests/unit_background_update/head.js18
-rw-r--r--toolkit/mozapps/update/tests/unit_background_update/test_backgroundupdate_exitcodes.js80
-rw-r--r--toolkit/mozapps/update/tests/unit_background_update/test_backgroundupdate_glean.js222
-rw-r--r--toolkit/mozapps/update/tests/unit_background_update/test_backgroundupdate_reason_schedule.js116
-rw-r--r--toolkit/mozapps/update/tests/unit_background_update/test_backgroundupdate_reason_update.js199
-rw-r--r--toolkit/mozapps/update/tests/unit_background_update/xpcshell.ini23
6 files changed, 658 insertions, 0 deletions
diff --git a/toolkit/mozapps/update/tests/unit_background_update/head.js b/toolkit/mozapps/update/tests/unit_background_update/head.js
new file mode 100644
index 0000000000..089fe32977
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_background_update/head.js
@@ -0,0 +1,18 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/* import-globals-from ../data/xpcshellUtilsAUS.js */
+load("xpcshellUtilsAUS.js");
+gIsServiceTest = false;
+
+const { BackgroundTasksTestUtils } = ChromeUtils.import(
+ "resource://testing-common/BackgroundTasksTestUtils.jsm"
+);
+BackgroundTasksTestUtils.init(this);
+const do_backgroundtask = BackgroundTasksTestUtils.do_backgroundtask.bind(
+ BackgroundTasksTestUtils
+);
+const setupProfileService = BackgroundTasksTestUtils.setupProfileService.bind(
+ BackgroundTasksTestUtils
+);
diff --git a/toolkit/mozapps/update/tests/unit_background_update/test_backgroundupdate_exitcodes.js b/toolkit/mozapps/update/tests/unit_background_update/test_backgroundupdate_exitcodes.js
new file mode 100644
index 0000000000..7ce3f27d66
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_background_update/test_backgroundupdate_exitcodes.js
@@ -0,0 +1,80 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * vim: sw=4 ts=4 sts=4 et
+ * 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";
+
+// This test exercises functionality and also ensures the exit codes,
+// which are a public API, do not change over time.
+const { EXIT_CODE } = ChromeUtils.import(
+ "resource://gre/modules/BackgroundUpdate.jsm"
+).BackgroundUpdate;
+
+setupProfileService();
+
+// Ensure launched background tasks don't see this xpcshell as a concurrent
+// instance.
+let syncManager = Cc["@mozilla.org/updates/update-sync-manager;1"].getService(
+ Ci.nsIUpdateSyncManager
+);
+let lockFile = do_get_profile();
+lockFile.append("customExePath");
+lockFile.append("customExe");
+syncManager.resetLock(lockFile);
+
+add_task(async function test_default_profile_does_not_exist() {
+ // Pretend there's no default profile.
+ let exitCode = await do_backgroundtask("backgroundupdate", {
+ extraEnv: {
+ MOZ_BACKGROUNDTASKS_NO_DEFAULT_PROFILE: "1",
+ },
+ });
+ Assert.equal(EXIT_CODE.DEFAULT_PROFILE_DOES_NOT_EXIST, exitCode);
+ Assert.equal(11, exitCode);
+});
+
+add_task(async function test_default_profile_cannot_be_locked() {
+ // Now, lock the default profile.
+ let profileService = Cc["@mozilla.org/toolkit/profile-service;1"].getService(
+ Ci.nsIToolkitProfileService
+ );
+
+ let file = do_get_profile();
+ file.append("profile_cannot_be_locked");
+
+ let profile = profileService.createUniqueProfile(
+ file,
+ "test_default_profile"
+ );
+ let lock = profile.lock({});
+
+ try {
+ let exitCode = await do_backgroundtask("backgroundupdate", {
+ extraEnv: {
+ MOZ_BACKGROUNDTASKS_DEFAULT_PROFILE_PATH: lock.directory.path,
+ },
+ });
+ Assert.equal(EXIT_CODE.DEFAULT_PROFILE_CANNOT_BE_LOCKED, exitCode);
+ Assert.equal(12, exitCode);
+ } finally {
+ lock.unlock();
+ }
+});
+
+add_task(async function test_default_profile_cannot_be_read() {
+ // Finally, provide an empty default profile, one without prefs.
+ let file = do_get_profile();
+ file.append("profile_cannot_be_read");
+
+ await IOUtils.makeDirectory(file.path);
+
+ let exitCode = await do_backgroundtask("backgroundupdate", {
+ extraEnv: {
+ MOZ_BACKGROUNDTASKS_DEFAULT_PROFILE_PATH: file.path,
+ },
+ });
+ Assert.equal(EXIT_CODE.DEFAULT_PROFILE_CANNOT_BE_READ, exitCode);
+ Assert.equal(13, exitCode);
+});
diff --git a/toolkit/mozapps/update/tests/unit_background_update/test_backgroundupdate_glean.js b/toolkit/mozapps/update/tests/unit_background_update/test_backgroundupdate_glean.js
new file mode 100644
index 0000000000..4a7d1502a5
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_background_update/test_backgroundupdate_glean.js
@@ -0,0 +1,222 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * vim: sw=4 ts=4 sts=4 et
+ * 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 { ASRouterTargeting } = ChromeUtils.import(
+ "resource://activity-stream/lib/ASRouterTargeting.jsm"
+);
+
+const { BackgroundUpdate } = ChromeUtils.import(
+ "resource://gre/modules/BackgroundUpdate.jsm"
+);
+
+const { maybeSubmitBackgroundUpdatePing } = ChromeUtils.import(
+ "resource://gre/modules/backgroundtasks/BackgroundTask_backgroundupdate.jsm"
+);
+
+XPCOMUtils.defineLazyServiceGetter(
+ this,
+ "UpdateService",
+ "@mozilla.org/updates/update-service;1",
+ "nsIApplicationUpdateService"
+);
+
+add_setup(function test_setup() {
+ // FOG needs a profile directory to put its data in.
+ do_get_profile();
+
+ // We need to initialize it once, otherwise operations will be stuck in the pre-init queue.
+ Services.fog.initializeFOG();
+
+ setupProfileService();
+});
+
+add_task(async function test_record_update_environment() {
+ await BackgroundUpdate.recordUpdateEnvironment();
+
+ let pingSubmitted = false;
+ let appUpdateAutoEnabled = await UpdateUtils.getAppUpdateAutoEnabled();
+ let backgroundUpdateEnabled = await UpdateUtils.readUpdateConfigSetting(
+ "app.update.background.enabled"
+ );
+ GleanPings.backgroundUpdate.testBeforeNextSubmit(reason => {
+ Assert.equal(reason, "backgroundupdate_task");
+
+ pingSubmitted = true;
+ Assert.equal(
+ Services.prefs.getBoolPref("app.update.service.enabled", false),
+ Glean.update.serviceEnabled.testGetValue()
+ );
+
+ Assert.equal(
+ appUpdateAutoEnabled,
+ Glean.update.autoDownload.testGetValue()
+ );
+
+ Assert.equal(
+ backgroundUpdateEnabled,
+ Glean.update.backgroundUpdate.testGetValue()
+ );
+
+ Assert.equal(
+ UpdateUtils.UpdateChannel,
+ Glean.update.channel.testGetValue()
+ );
+ Assert.equal(
+ !Services.policies || Services.policies.isAllowed("appUpdate"),
+ Glean.update.enabled.testGetValue()
+ );
+
+ Assert.equal(
+ UpdateService.canUsuallyApplyUpdates,
+ Glean.update.canUsuallyApplyUpdates.testGetValue()
+ );
+ Assert.equal(
+ UpdateService.canUsuallyCheckForUpdates,
+ Glean.update.canUsuallyCheckForUpdates.testGetValue()
+ );
+ Assert.equal(
+ UpdateService.canUsuallyStageUpdates,
+ Glean.update.canUsuallyStageUpdates.testGetValue()
+ );
+ Assert.equal(
+ UpdateService.canUsuallyUseBits,
+ Glean.update.canUsuallyUseBits.testGetValue()
+ );
+ });
+
+ // There's nothing async in this function atm, but it's annotated async, so..
+ await maybeSubmitBackgroundUpdatePing();
+
+ ok(pingSubmitted, "'background-update' ping was submitted");
+});
+
+async function do_readTargeting(content, beforeNextSubmitCallback) {
+ let profileService = Cc["@mozilla.org/toolkit/profile-service;1"].getService(
+ Ci.nsIToolkitProfileService
+ );
+
+ let file = do_get_profile();
+ file.append("profile_cannot_be_locked");
+
+ let profile = profileService.createUniqueProfile(
+ file,
+ "test_default_profile"
+ );
+
+ let targetingSnapshot = profile.rootDir.clone();
+ targetingSnapshot.append("targeting.snapshot.json");
+
+ if (content) {
+ await IOUtils.writeUTF8(targetingSnapshot.path, content);
+ }
+
+ let lock = profile.lock({});
+
+ Services.fog.testResetFOG();
+ try {
+ await BackgroundUpdate.readFirefoxMessagingSystemTargetingSnapshot(lock);
+ } finally {
+ lock.unlock();
+ }
+
+ let pingSubmitted = false;
+ GleanPings.backgroundUpdate.testBeforeNextSubmit(reason => {
+ pingSubmitted = true;
+ return beforeNextSubmitCallback(reason);
+ });
+
+ // There's nothing async in this function atm, but it's annotated async, so..
+ await maybeSubmitBackgroundUpdatePing();
+
+ ok(pingSubmitted, "'background-update' ping was submitted");
+}
+
+// Missing targeting is anticipated.
+add_task(async function test_targeting_missing() {
+ await do_readTargeting(null, reason => {
+ Assert.equal(false, Glean.backgroundUpdate.targetingExists.testGetValue());
+
+ Assert.equal(
+ false,
+ Glean.backgroundUpdate.targetingException.testGetValue()
+ );
+ });
+});
+
+// Malformed JSON yields an exception.
+add_task(async function test_targeting_exception() {
+ await do_readTargeting("{", reason => {
+ Assert.equal(false, Glean.backgroundUpdate.targetingExists.testGetValue());
+
+ Assert.equal(
+ true,
+ Glean.backgroundUpdate.targetingException.testGetValue()
+ );
+ });
+});
+
+// Well formed targeting values are reflected into the Glean telemetry.
+add_task(async function test_targeting_exists() {
+ // We can't take a full environment snapshot under `xpcshell`; these are just
+ // the items we need.
+ let target = {
+ currentDate: ASRouterTargeting.Environment.currentDate,
+ profileAgeCreated: ASRouterTargeting.Environment.profileAgeCreated,
+ firefoxVersion: ASRouterTargeting.Environment.firefoxVersion,
+ };
+ let targetSnapshot = await ASRouterTargeting.getEnvironmentSnapshot(target);
+
+ await do_readTargeting(JSON.stringify(targetSnapshot), reason => {
+ Assert.equal(true, Glean.backgroundUpdate.targetingExists.testGetValue());
+
+ Assert.equal(
+ false,
+ Glean.backgroundUpdate.targetingException.testGetValue()
+ );
+
+ // `environment.firefoxVersion` is a positive integer.
+ Assert.ok(
+ Glean.backgroundUpdate.targetingEnvFirefoxVersion.testGetValue() > 0
+ );
+
+ Assert.equal(
+ targetSnapshot.environment.firefoxVersion,
+ Glean.backgroundUpdate.targetingEnvFirefoxVersion.testGetValue()
+ );
+
+ let profileAge = Glean.backgroundUpdate.targetingEnvProfileAge.testGetValue();
+
+ Assert.ok(profileAge instanceof Date);
+ Assert.ok(0 < profileAge.getTime());
+ Assert.ok(profileAge.getTime() < Date.now());
+
+ // `environment.profileAgeCreated` is an integer, milliseconds since the
+ // Unix epoch.
+ let targetProfileAge = new Date(
+ targetSnapshot.environment.profileAgeCreated
+ );
+ // Our `time_unit: day` has Glean round to the nearest day *in the local
+ // timezone*, so we must do the same.
+ targetProfileAge.setHours(0, 0, 0, 0);
+
+ Assert.equal(targetProfileAge.toISOString(), profileAge.toISOString());
+
+ let currentDate = Glean.backgroundUpdate.targetingEnvCurrentDate.testGetValue();
+
+ Assert.ok(0 < currentDate.getTime());
+ Assert.ok(currentDate.getTime() < Date.now());
+
+ // `environment.currentDate` is in ISO string format.
+ let targetCurrentDate = new Date(targetSnapshot.environment.currentDate);
+ // Our `time_unit: day` has Glean round to the nearest day *in the local
+ // timezone*, so we must do the same.
+ targetCurrentDate.setHours(0, 0, 0, 0);
+
+ Assert.equal(targetCurrentDate.toISOString(), currentDate.toISOString());
+ });
+});
diff --git a/toolkit/mozapps/update/tests/unit_background_update/test_backgroundupdate_reason_schedule.js b/toolkit/mozapps/update/tests/unit_background_update/test_backgroundupdate_reason_schedule.js
new file mode 100644
index 0000000000..61b1f57252
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_background_update/test_backgroundupdate_reason_schedule.js
@@ -0,0 +1,116 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * vim: sw=4 ts=4 sts=4 et
+ * 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 { BackgroundUpdate } = ChromeUtils.import(
+ "resource://gre/modules/BackgroundUpdate.jsm"
+);
+let reasons = () => BackgroundUpdate._reasonsToNotScheduleUpdates();
+let REASON = BackgroundUpdate.REASON;
+
+const { AddonTestUtils } = ChromeUtils.import(
+ "resource://testing-common/AddonTestUtils.jsm"
+);
+const { ExtensionTestUtils } = ChromeUtils.import(
+ "resource://testing-common/ExtensionXPCShellUtils.jsm"
+);
+
+setupProfileService();
+
+// Setup that allows to install a langpack.
+ExtensionTestUtils.init(this);
+
+AddonTestUtils.init(this);
+AddonTestUtils.overrideCertDB();
+
+AddonTestUtils.createAppInfo(
+ "xpcshell@tests.mozilla.org",
+ "XPCShell",
+ "42",
+ "42"
+);
+
+add_task(
+ {
+ skip_if: () => !AppConstants.MOZ_BACKGROUNDTASKS,
+ },
+ async function test_reasons_schedule_langpacks() {
+ await AddonTestUtils.promiseStartupManager();
+
+ Services.prefs.setBoolPref("app.update.langpack.enabled", true);
+
+ let result = await reasons();
+ Assert.ok(
+ !result.includes(REASON.LANGPACK_INSTALLED),
+ "Reasons does not include LANGPACK_INSTALLED"
+ );
+
+ // Install a langpack.
+ let langpack = {
+ "manifest.json": {
+ name: "test Language Pack",
+ version: "1.0",
+ manifest_version: 2,
+ browser_specific_settings: {
+ gecko: {
+ id: "@test-langpack",
+ strict_min_version: "42.0",
+ strict_max_version: "42.0",
+ },
+ },
+ langpack_id: "fr",
+ languages: {
+ fr: {
+ chrome_resources: {
+ global: "chrome/fr/locale/fr/global/",
+ },
+ version: "20171001190118",
+ },
+ },
+ sources: {
+ browser: {
+ base_path: "browser/",
+ },
+ },
+ },
+ };
+
+ await Promise.all([
+ TestUtils.topicObserved("webextension-langpack-startup"),
+ AddonTestUtils.promiseInstallXPI(langpack),
+ ]);
+
+ result = await reasons();
+ Assert.ok(
+ result.includes(REASON.LANGPACK_INSTALLED),
+ "Reasons include LANGPACK_INSTALLED"
+ );
+
+ // Now turn off langpack updating.
+ Services.prefs.setBoolPref("app.update.langpack.enabled", false);
+
+ result = await reasons();
+ Assert.ok(
+ !result.includes(REASON.LANGPACK_INSTALLED),
+ "Reasons does not include LANGPACK_INSTALLED"
+ );
+ }
+);
+
+add_task(
+ {
+ skip_if: () => !AppConstants.MOZ_BACKGROUNDTASKS,
+ },
+ async function test_reasons_schedule_default_profile() {
+ // It's difficult to arrange a default profile in a testing environment, so
+ // this is not as thorough as we'd like.
+ let result = await reasons();
+
+ Assert.ok(result.includes(REASON.NO_DEFAULT_PROFILE_EXISTS));
+ Assert.ok(result.includes(REASON.NOT_DEFAULT_PROFILE));
+ }
+);
diff --git a/toolkit/mozapps/update/tests/unit_background_update/test_backgroundupdate_reason_update.js b/toolkit/mozapps/update/tests/unit_background_update/test_backgroundupdate_reason_update.js
new file mode 100644
index 0000000000..81b7086401
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_background_update/test_backgroundupdate_reason_update.js
@@ -0,0 +1,199 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * vim: sw=4 ts=4 sts=4 et
+ * 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 { BackgroundUpdate } = ChromeUtils.import(
+ "resource://gre/modules/BackgroundUpdate.jsm"
+);
+let reasons = () => BackgroundUpdate._reasonsToNotUpdateInstallation();
+let REASON = BackgroundUpdate.REASON;
+const { EnterprisePolicyTesting } = ChromeUtils.importESModule(
+ "resource://testing-common/EnterprisePolicyTesting.sys.mjs"
+);
+const { UpdateService } = ChromeUtils.import(
+ "resource://gre/modules/UpdateService.jsm"
+);
+
+const { sinon } = ChromeUtils.import("resource://testing-common/Sinon.jsm");
+
+// We can't reasonably check NO_MOZ_BACKGROUNDTASKS, nor NO_OMNIJAR.
+
+// These tests use per-installation prefs, and those are a shared resource, so
+// they require some non-trivial setup.
+setupTestCommon(null);
+standardInit();
+
+function setup_enterprise_policy_testing() {
+ // This initializes the policy engine for xpcshell tests
+ let policies = Cc["@mozilla.org/enterprisepolicies;1"].getService(
+ Ci.nsIObserver
+ );
+ policies.observe(null, "policies-startup", null);
+}
+setup_enterprise_policy_testing();
+
+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);
+}
+
+add_task(async function test_reasons_update_no_app_update_auto() {
+ let prev = await UpdateUtils.getAppUpdateAutoEnabled();
+ try {
+ await UpdateUtils.setAppUpdateAutoEnabled(false);
+ let result = await reasons();
+ Assert.ok(result.includes(REASON.NO_APP_UPDATE_AUTO));
+
+ await UpdateUtils.setAppUpdateAutoEnabled(true);
+ result = await reasons();
+ Assert.ok(!result.includes(REASON.NO_APP_UPDATE_AUTO));
+ } finally {
+ await UpdateUtils.setAppUpdateAutoEnabled(prev);
+ }
+});
+
+add_task(async function test_reasons_update_no_app_update_background_enabled() {
+ let prev = await UpdateUtils.readUpdateConfigSetting(
+ "app.update.background.enabled"
+ );
+ try {
+ await UpdateUtils.writeUpdateConfigSetting(
+ "app.update.background.enabled",
+ false
+ );
+ let result = await reasons();
+ Assert.ok(result.includes(REASON.NO_APP_UPDATE_BACKGROUND_ENABLED));
+
+ await UpdateUtils.writeUpdateConfigSetting(
+ "app.update.background.enabled",
+ true
+ );
+ result = await reasons();
+ Assert.ok(!result.includes(REASON.NO_APP_UPDATE_BACKGROUND_ENABLED));
+ } finally {
+ await UpdateUtils.writeUpdateConfigSetting(
+ "app.update.background.enabled",
+ prev
+ );
+ }
+});
+
+add_task(async function test_reasons_update_cannot_usually_check() {
+ // It's difficult to arrange the conditions in a testing environment, so
+ // we'll use mocks to get a little assurance.
+ let result = await reasons();
+ Assert.ok(!result.includes(REASON.CANNOT_USUALLY_CHECK));
+
+ let sandbox = sinon.createSandbox();
+ try {
+ sandbox
+ .stub(UpdateService.prototype, "canUsuallyCheckForUpdates")
+ .get(() => false);
+ result = await reasons();
+ Assert.ok(result.includes(REASON.CANNOT_USUALLY_CHECK));
+ } finally {
+ sandbox.restore();
+ }
+});
+
+add_task(async function test_reasons_update_can_usually_stage_or_appl() {
+ // It's difficult to arrange the conditions in a testing environment, so
+ // we'll use mocks to get a little assurance.
+ let sandbox = sinon.createSandbox();
+ try {
+ sandbox
+ .stub(UpdateService.prototype, "canUsuallyStageUpdates")
+ .get(() => true);
+ sandbox
+ .stub(UpdateService.prototype, "canUsuallyApplyUpdates")
+ .get(() => true);
+ let result = await reasons();
+ Assert.ok(
+ !result.includes(REASON.CANNOT_USUALLY_STAGE_AND_CANNOT_USUALLY_APPLY)
+ );
+
+ sandbox
+ .stub(UpdateService.prototype, "canUsuallyStageUpdates")
+ .get(() => false);
+ sandbox
+ .stub(UpdateService.prototype, "canUsuallyApplyUpdates")
+ .get(() => false);
+ result = await reasons();
+ Assert.ok(
+ result.includes(REASON.CANNOT_USUALLY_STAGE_AND_CANNOT_USUALLY_APPLY)
+ );
+ } finally {
+ sandbox.restore();
+ }
+});
+
+add_task(
+ {
+ skip_if: () =>
+ !AppConstants.MOZ_BITS_DOWNLOAD || AppConstants.platform != "win",
+ },
+ async function test_reasons_update_can_usually_use_bits() {
+ let prev = Services.prefs.getBoolPref("app.update.BITS.enabled");
+
+ // Here we use mocks to "get by" preconditions that are not
+ // satisfied in the testing environment.
+ let sandbox = sinon.createSandbox();
+ try {
+ sandbox
+ .stub(UpdateService.prototype, "canUsuallyStageUpdates")
+ .get(() => true);
+ sandbox
+ .stub(UpdateService.prototype, "canUsuallyApplyUpdates")
+ .get(() => true);
+
+ Services.prefs.setBoolPref("app.update.BITS.enabled", false);
+ let result = await reasons();
+ Assert.ok(result.includes(REASON.WINDOWS_CANNOT_USUALLY_USE_BITS));
+
+ Services.prefs.setBoolPref("app.update.BITS.enabled", true);
+ result = await reasons();
+ Assert.ok(!result.includes(REASON.WINDOWS_CANNOT_USUALLY_USE_BITS));
+ } finally {
+ sandbox.restore();
+ Services.prefs.setBoolPref("app.update.BITS.enabled", prev);
+ }
+ }
+);
+
+add_task(async function test_reasons_update_manual_update_only() {
+ await setupPolicyEngineWithJson({
+ policies: {
+ ManualAppUpdateOnly: true,
+ },
+ });
+ Assert.equal(
+ Services.policies.status,
+ Ci.nsIEnterprisePolicies.ACTIVE,
+ "Engine is active"
+ );
+
+ let result = await reasons();
+ Assert.ok(result.includes(REASON.MANUAL_UPDATE_ONLY));
+
+ await setupPolicyEngineWithJson({});
+
+ result = await reasons();
+ Assert.ok(!result.includes(REASON.MANUAL_UPDATE_ONLY));
+});
+
+add_task(() => {
+ // `setupTestCommon()` calls `do_test_pending()`; this calls
+ // `do_test_finish()`. The `add_task` schedules this to run after all the
+ // other tests have completed.
+ doTestFinish();
+});
diff --git a/toolkit/mozapps/update/tests/unit_background_update/xpcshell.ini b/toolkit/mozapps/update/tests/unit_background_update/xpcshell.ini
new file mode 100644
index 0000000000..dff65608e9
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_background_update/xpcshell.ini
@@ -0,0 +1,23 @@
+# 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/.
+
+[DEFAULT]
+firefox-appdir = browser
+skip-if =
+ toolkit == 'android'
+ (os == 'win' && msix) # Our updater is disabled in MSIX builds
+head = head.js
+support-files =
+ ../data/shared.js
+ ../data/sharedUpdateXML.js
+ ../data/xpcshellUtilsAUS.js
+
+[test_backgroundupdate_exitcodes.js]
+run-sequentially = very high failure rate in parallel
+skip-if =
+ os == "win" && os_version == "6.1" # Skip on Azure - frequent failure
+
+[test_backgroundupdate_glean.js]
+[test_backgroundupdate_reason_update.js]
+[test_backgroundupdate_reason_schedule.js]