Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test gets skipped with pattern: os == 'android' OR os == 'win' && msix
- Manifest: toolkit/mozapps/update/tests/unit_background_update/xpcshell.toml
/* -*- 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
"use strict";
const { BackgroundUpdate } = ChromeUtils.importESModule(
"resource://gre/modules/BackgroundUpdate.sys.mjs"
);
let reasons = () => BackgroundUpdate._reasonsToNotUpdateInstallation();
let REASON = BackgroundUpdate.REASON;
const { EnterprisePolicyTesting } = ChromeUtils.importESModule(
);
const { UpdateService } = ChromeUtils.importESModule(
"resource://gre/modules/UpdateService.sys.mjs"
);
const { sinon } = ChromeUtils.importESModule(
);
// We can't reasonably check NO_MOZ_BACKGROUNDTASKS, nor NO_OMNIJAR.
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_setup(async function test_setup() {
// These tests use per-installation prefs, and those are a shared resource, so
// they require some non-trivial setup.
setupTestCommon(null);
await standardInit();
// 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_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));
result = await checkGleanPing();
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));
result = await checkGleanPing();
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));
result = await checkGleanPing();
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));
result = await checkGleanPing();
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));
result = await checkGleanPing();
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)
);
result = await checkGleanPing();
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)
);
result = await checkGleanPing();
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));
result = await checkGleanPing();
Assert.ok(
result.includes(REASON.WINDOWS_CANNOT_USUALLY_USE_BITS),
"result : " + result.join("', '") + "']"
);
Services.prefs.setBoolPref("app.update.BITS.enabled", true);
result = await reasons();
Assert.ok(!result.includes(REASON.WINDOWS_CANNOT_USUALLY_USE_BITS));
result = await checkGleanPing();
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));
result = await checkGleanPing();
Assert.ok(result.includes(REASON.MANUAL_UPDATE_ONLY));
await setupPolicyEngineWithJson({});
result = await reasons();
Assert.ok(!result.includes(REASON.MANUAL_UPDATE_ONLY));
result = await checkGleanPing();
Assert.ok(!result.includes(REASON.MANUAL_UPDATE_ONLY));
});
add_task(
{
skip_if: () => AppConstants.platform != "win",
},
async function test_unelevated_nimbus_enabled() {
// Enable feature.
Services.prefs.setBoolPref(
"app.update.background.allowUpdatesForUnelevatedInstallations",
true
);
registerCleanupFunction(() => {
Services.prefs.clearUserPref(
"app.update.background.allowUpdatesForUnelevatedInstallations"
);
});
// execute!
let r = await reasons();
Assert.ok(
!r.includes(BackgroundUpdate.REASON.SERVICE_REGISTRY_KEY_MISSING),
`no SERVICE_REGISTRY_KEY_MISSING in ${JSON.stringify(r)}`
);
Assert.ok(
!r.includes(BackgroundUpdate.REASON.APPBASEDIR_NOT_WRITABLE),
`no APPBASEDIR_NOT_WRITABLE in ${JSON.stringify(r)}`
);
// the test directory usually is writable, but we now create a file and keep
// it open, so that the test file can neither be deleted nor recreated and
// appears to be locked. With that we re-execute the test and expect to find
// APPBASEDIR_NOT_WRITABLE in the telemetry data.
let appDirTestFile = Services.dirsvc.get(
XRE_EXECUTABLE_FILE,
Ci.nsIFile
).parent;
appDirTestFile.append(FILE_UPDATE_TEST);
appDirTestFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
var outputStream = Cc[
"@mozilla.org/network/file-output-stream;1"
].createInstance(Ci.nsIFileOutputStream);
// WR_ONLY|CREATE|TRUNC
outputStream.init(appDirTestFile, 0x02 | 0x08 | 0x20, 0o644, null);
registerCleanupFunction(() => {
outputStream.close();
appDirTestFile.remove(false);
});
// after the preperation: execute again!
r = await reasons();
Assert.ok(
r.includes(BackgroundUpdate.REASON.APPBASEDIR_NOT_WRITABLE),
`no APPBASEDIR_NOT_WRITABLE in ${JSON.stringify(r)}`
);
}
);
add_task(
{
skip_if: () => AppConstants.platform != "win",
},
async function test_unelevated_nimbus_disabled() {
// Disable feature.
Services.prefs.setBoolPref(
"app.update.background.allowUpdatesForUnelevatedInstallations",
false
);
registerCleanupFunction(() => {
Services.prefs.clearUserPref(
"app.update.background.allowUpdatesForUnelevatedInstallations"
);
});
let r = await reasons();
Assert.ok(
r.includes(BackgroundUpdate.REASON.SERVICE_REGISTRY_KEY_MISSING),
`SERVICE_REGISTRY_KEY_MISSING in ${JSON.stringify(r)}`
);
}
);
add_task(async () => {
// `setupTestCommon()` calls `do_test_pending()`; this calls
// `do_test_finish()`. The `add_task` schedules this to run after all the
// other tests have completed.
await doTestFinish();
});