Source code
Revision control
Copy as Markdown
Other Tools
/* 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
*/
/**
* This tests the multiple update downloads per Firefox session feature.
*
* This test does some unusual things, compared to the other files in this
* directory. We want to start the updates with aus.checkForBackgroundUpdates()
* to ensure that we test the whole flow. Other tests start update with things
* like aus.downloadUpdate(), but that bypasses some of the exact checks that we
* are trying to test as part of the multiupdate flow.
*
* In order to accomplish all this, we will be using app_update.sjs to serve
* updates XMLs and MARs. Outside of this test, this is really only done
* by browser-chrome mochitests (in ../browser). So we have to do some weird
* things to make it work properly in an xpcshell test. Things like
* defining URL_HTTP_UPDATE_SJS in testConstants.js so that it can be read by
* app_update.sjs in order to provide the correct download URL for MARs, but
* not reading that file here, because URL_HTTP_UPDATE_SJS is already defined
* (as something else) in xpcshellUtilsAUS.js.
*/
const FIRST_UPDATE_VERSION = "999998.0";
const SECOND_UPDATE_VERSION = "999999.0";
/**
* This is like downloadUpdate. The difference is that downloadUpdate assumes
* that an update actually will be downloaded. This function instead verifies
* that we the update wasn't downloaded.
*
* downloadUpdate(), above, uses aus.checkForBackgroundUpdates() to download
* updates to verify that background updates actually will check for subsequent
* updates, but this function will use some slightly different mechanisms. We
* can call aus.downloadUpdate() and check its return value to see if it started
* a download. But this doesn't properly check that the update-available
* notification isn't shown. So we will do an additional check where we follow
* the normal flow a bit more closely by forwarding the results that we got from
* checkForUpdates() to aus.onCheckComplete() and make sure that the update
* prompt isn't shown.
*/
async function testUpdateDoesNotDownload() {
let check = gUpdateChecker.checkForUpdates(gUpdateChecker.BACKGROUND_CHECK);
let result = await check.result;
Assert.ok(result.checksAllowed, "Should be able to check for updates");
Assert.ok(result.succeeded, "Update check should have succeeded");
Assert.equal(
result.updates.length,
1,
"Should have gotten 1 update in update check"
);
let update = result.updates[0];
let downloadResult = await gAUS.downloadUpdate(update, true);
Assert.equal(
downloadResult,
Ci.nsIApplicationUpdateService.DOWNLOAD_FAILURE_GENERIC,
"Expected that we would not start downloading an update"
);
let updateAvailableObserved = false;
let observer = (_subject, _topic, _status) => {
updateAvailableObserved = true;
};
Services.obs.addObserver(observer, "update-available");
await gAUS.onCheckComplete(result);
Services.obs.removeObserver(observer, "update-available");
Assert.equal(
updateAvailableObserved,
false,
"update-available notification should not fire if we aren't going to " +
"download the update."
);
}
async function testUpdateCheckDoesNotStart() {
let updateCheckStarted = await gAUS.checkForBackgroundUpdates();
Assert.equal(
updateCheckStarted,
false,
"Update check should not have started"
);
}
function prepareToDownloadVersion(version, onlyCompleteMar = false) {
let updateUrl = `${gURLData}&useSlowDownloadMar=1&useFirstByteEarly=1&appVersion=${version}`;
if (onlyCompleteMar) {
updateUrl += "&completePatchOnly=1";
}
setUpdateURL(updateUrl);
}
async function multi_update_test(appUpdateAuto) {
await UpdateUtils.setAppUpdateAutoEnabled(appUpdateAuto);
prepareToDownloadVersion(FIRST_UPDATE_VERSION);
await downloadUpdate({
appUpdateAuto,
checkWithAUS: true,
slowDownload: true,
onDownloadStartCallback: async () => {
const readyUpdate = await gUpdateManager.getReadyUpdate();
const downloadingUpdate = await gUpdateManager.getDownloadingUpdate();
Assert.ok(!readyUpdate, "There should not be a ready update yet");
Assert.ok(
!!downloadingUpdate,
"First update download should be in downloadingUpdate"
);
Assert.equal(
downloadingUpdate.state,
STATE_DOWNLOADING,
"downloadingUpdate should be downloading"
);
Assert.equal(
readStatusFile(),
STATE_DOWNLOADING,
"Updater state should be downloading"
);
},
});
let readyUpdate = await gUpdateManager.getReadyUpdate();
let downloadingUpdate = await gUpdateManager.getDownloadingUpdate();
Assert.ok(
!downloadingUpdate,
"First update download should no longer be in downloadingUpdate"
);
Assert.ok(!!readyUpdate, "First update download should be in readyUpdate");
Assert.equal(
readyUpdate.state,
STATE_PENDING,
"readyUpdate should be pending"
);
Assert.equal(
readyUpdate.appVersion,
FIRST_UPDATE_VERSION,
"readyUpdate version should be match the version of the first update"
);
Assert.equal(
readStatusFile(),
STATE_PENDING,
"Updater state should be pending"
);
let existingUpdate = readyUpdate;
await testUpdateDoesNotDownload();
readyUpdate = await gUpdateManager.getReadyUpdate();
Assert.equal(
readyUpdate,
existingUpdate,
"readyUpdate should not have changed when no newer update is available"
);
Assert.equal(
readyUpdate.state,
STATE_PENDING,
"readyUpdate should still be pending"
);
Assert.equal(
readyUpdate.appVersion,
FIRST_UPDATE_VERSION,
"readyUpdate version should be match the version of the first update"
);
Assert.equal(
readStatusFile(),
STATE_PENDING,
"Updater state should still be pending"
);
// With only a complete update available, we should not download the newer
// update when we already have an update ready.
prepareToDownloadVersion(SECOND_UPDATE_VERSION, true);
await testUpdateDoesNotDownload();
readyUpdate = await gUpdateManager.getReadyUpdate();
Assert.equal(
readyUpdate,
existingUpdate,
"readyUpdate should not have changed when no newer partial update is available"
);
Assert.equal(
readyUpdate.state,
STATE_PENDING,
"readyUpdate should still be pending"
);
Assert.equal(
readyUpdate.appVersion,
FIRST_UPDATE_VERSION,
"readyUpdate version should be match the version of the first update"
);
Assert.equal(
readStatusFile(),
STATE_PENDING,
"Updater state should still be pending"
);
prepareToDownloadVersion(SECOND_UPDATE_VERSION);
await downloadUpdate({
appUpdateAuto,
checkWithAUS: true,
slowDownload: true,
onDownloadStartCallback: async () => {
readyUpdate = await gUpdateManager.getReadyUpdate();
downloadingUpdate = await gUpdateManager.getDownloadingUpdate();
Assert.ok(
!!downloadingUpdate,
"Second update download should be in downloadingUpdate"
);
Assert.equal(
downloadingUpdate.state,
STATE_DOWNLOADING,
"downloadingUpdate should be downloading"
);
Assert.ok(
!!readyUpdate,
"First update download should still be in readyUpdate"
);
Assert.equal(
readyUpdate.state,
STATE_PENDING,
"readyUpdate should still be pending"
);
Assert.equal(
readyUpdate.appVersion,
FIRST_UPDATE_VERSION,
"readyUpdate version should be match the version of the first update"
);
Assert.equal(
readStatusFile(),
STATE_PENDING,
"Updater state should match the readyUpdate's state"
);
},
});
readyUpdate = await gUpdateManager.getReadyUpdate();
downloadingUpdate = await gUpdateManager.getDownloadingUpdate();
Assert.ok(
!downloadingUpdate,
"Second update download should no longer be in downloadingUpdate"
);
Assert.ok(!!readyUpdate, "Second update download should be in readyUpdate");
Assert.equal(
readyUpdate.state,
STATE_PENDING,
"readyUpdate should be pending"
);
Assert.equal(
readyUpdate.appVersion,
SECOND_UPDATE_VERSION,
"readyUpdate version should be match the version of the second update"
);
Assert.equal(
readStatusFile(),
STATE_PENDING,
"Updater state should be pending"
);
// Reset the updater to its initial state to test that the complete/partial
// MAR behavior is correct
await reloadUpdateManagerData(true);
// Second parameter forces a complete MAR download.
prepareToDownloadVersion(FIRST_UPDATE_VERSION, true);
await downloadUpdate({
appUpdateAuto,
checkWithAUS: true,
slowDownload: true,
onDownloadStartCallback: async () => {
downloadingUpdate = await gUpdateManager.getDownloadingUpdate();
Assert.equal(
downloadingUpdate.selectedPatch.type,
"complete",
"First update download should be a complete patch"
);
},
});
readyUpdate = await gUpdateManager.getReadyUpdate();
Assert.equal(
readyUpdate.selectedPatch.type,
"complete",
"First update download should be a complete patch"
);
// Even a newer partial update should not be downloaded at this point.
prepareToDownloadVersion(SECOND_UPDATE_VERSION);
await testUpdateCheckDoesNotStart();
}
add_task(async function all_multi_update_tests() {
setupTestCommon(true);
startSjsServer();
Services.prefs.setBoolPref(PREF_APP_UPDATE_DISABLEDFORTESTING, false);
Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, false);
let origAppUpdateAutoVal = await UpdateUtils.getAppUpdateAutoEnabled();
registerCleanupFunction(async () => {
await UpdateUtils.setAppUpdateAutoEnabled(origAppUpdateAutoVal);
});
await multi_update_test(true);
// Reset the update system so we can start again from scratch.
await reloadUpdateManagerData(true);
await multi_update_test(false);
await doTestFinish();
});