From fa80d81a6d1b149b8fa07066561253a67cbce340 Mon Sep 17 00:00:00 2001 From: Robert Strong Date: Wed, 16 Jan 2019 13:21:55 -0800 Subject: [PATCH] Bug 599233 - add about dialog app update tests. r=mhowell Adds disabledForTesting checks to the about dialog app update code Makes a copy of update.sjs for browser-chrome tests so the changes don't break chrome tests Prepares for the removal of the chrome tests and the old app update UI Adds 14 tests for app update in the about dialog --HG-- rename : toolkit/mozapps/update/tests/data/update.sjs => toolkit/mozapps/update/tests/browser/app_update.sjs rename : toolkit/mozapps/update/tests/data/update.sjs => toolkit/mozapps/update/tests/chrome/update.sjs --- .../base/content/aboutDialog-appUpdater.js | 20 +- .../update/tests/browser/app_update.sjs | 241 ++++++++++++++ .../mozapps/update/tests/browser/browser.ini | 24 ++ .../browser/browser_about_bc_downloaded.js | 17 + .../browser_about_bc_downloaded_staged.js | 25 ++ .../browser_about_fc_check_cantApply.js | 24 ++ .../browser_about_fc_check_malformedXML.js | 22 ++ .../browser_about_fc_check_noUpdate.js | 22 ++ .../browser_about_fc_check_unsupported.js | 22 ++ .../browser/browser_about_fc_downloadAuto.js | 29 ++ .../browser_about_fc_downloadAuto_staging.js | 40 +++ .../browser/browser_about_fc_downloadOptIn.js | 36 +++ .../browser_about_fc_downloadOptIn_staging.js | 46 +++ .../browser_about_fc_patch_completeBadSize.js | 27 ++ .../browser_about_fc_patch_partialBadSize.js | 27 ++ ..._about_fc_patch_partialBadSize_complete.js | 32 ++ ...fc_patch_partialBadSize_completeBadSize.js | 32 ++ .../browser/browser_updatesBasicPrompt.js | 1 - .../tests/browser/browser_updatesCantApply.js | 19 +- toolkit/mozapps/update/tests/browser/head.js | 298 +++++++++++++++--- .../update/tests/browser/testConstants.js | 5 +- .../mozapps/update/tests/chrome/chrome.ini | 1 + .../update/tests/{data => chrome}/update.sjs | 0 toolkit/mozapps/update/tests/moz.build | 2 - toolkit/mozapps/update/updater/updater.cpp | 27 ++ 25 files changed, 977 insertions(+), 62 deletions(-) create mode 100644 toolkit/mozapps/update/tests/browser/app_update.sjs create mode 100644 toolkit/mozapps/update/tests/browser/browser_about_bc_downloaded.js create mode 100644 toolkit/mozapps/update/tests/browser/browser_about_bc_downloaded_staged.js create mode 100644 toolkit/mozapps/update/tests/browser/browser_about_fc_check_cantApply.js create mode 100644 toolkit/mozapps/update/tests/browser/browser_about_fc_check_malformedXML.js create mode 100644 toolkit/mozapps/update/tests/browser/browser_about_fc_check_noUpdate.js create mode 100644 toolkit/mozapps/update/tests/browser/browser_about_fc_check_unsupported.js create mode 100644 toolkit/mozapps/update/tests/browser/browser_about_fc_downloadAuto.js create mode 100644 toolkit/mozapps/update/tests/browser/browser_about_fc_downloadAuto_staging.js create mode 100644 toolkit/mozapps/update/tests/browser/browser_about_fc_downloadOptIn.js create mode 100644 toolkit/mozapps/update/tests/browser/browser_about_fc_downloadOptIn_staging.js create mode 100644 toolkit/mozapps/update/tests/browser/browser_about_fc_patch_completeBadSize.js create mode 100644 toolkit/mozapps/update/tests/browser/browser_about_fc_patch_partialBadSize.js create mode 100644 toolkit/mozapps/update/tests/browser/browser_about_fc_patch_partialBadSize_complete.js create mode 100644 toolkit/mozapps/update/tests/browser/browser_about_fc_patch_partialBadSize_completeBadSize.js rename toolkit/mozapps/update/tests/{data => chrome}/update.sjs (100%) diff --git a/browser/base/content/aboutDialog-appUpdater.js b/browser/base/content/aboutDialog-appUpdater.js index d70d5c61a817..f138e3de6591 100644 --- a/browser/base/content/aboutDialog-appUpdater.js +++ b/browser/base/content/aboutDialog-appUpdater.js @@ -13,8 +13,9 @@ ChromeUtils.import("resource://gre/modules/DownloadUtils.jsm"); ChromeUtils.defineModuleGetter(this, "UpdateUtils", "resource://gre/modules/UpdateUtils.jsm"); -const PREF_APP_UPDATE_CANCELATIONS_OSX = "app.update.cancelations.osx"; -const PREF_APP_UPDATE_ELEVATE_NEVER = "app.update.elevate.never"; +const PREF_APP_UPDATE_CANCELATIONS_OSX = "app.update.cancelations.osx"; +const PREF_APP_UPDATE_ELEVATE_NEVER = "app.update.elevate.never"; +const PREF_APP_UPDATE_DISABLEDFORTESTING = "app.update.disabledForTesting"; var gAppUpdater; @@ -131,7 +132,20 @@ appUpdater.prototype = // true when updating has been disabled by enterprise policy get updateDisabledByPolicy() { - return Services.policies && !Services.policies.isAllowed("appUpdate"); + return Services.policies && !Services.policies.isAllowed("appUpdate") || + this.disabledForTesting; + }, + + get disabledForTesting() { + let marionetteRunning = false; + + if ("nsIMarionette" in Ci) { + marionetteRunning = Cc["@mozilla.org/remote/marionette;1"]. + createInstance(Ci.nsIMarionette).running; + } + + return (Cu.isInAutomation || marionetteRunning) && + Services.prefs.getBoolPref(PREF_APP_UPDATE_DISABLEDFORTESTING, false); }, // true when updating in background is enabled. diff --git a/toolkit/mozapps/update/tests/browser/app_update.sjs b/toolkit/mozapps/update/tests/browser/app_update.sjs new file mode 100644 index 000000000000..290d25fa27e9 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/app_update.sjs @@ -0,0 +1,241 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/** + * Server side http server script for application update tests. + */ + +function getTestDataFile(aFilename) { + let file = Cc["@mozilla.org/file/directory_service;1"]. + getService(Ci.nsIProperties).get("CurWorkD", Ci.nsIFile); + let pathParts = REL_PATH_DATA.split("/"); + for (let i = 0; i < pathParts.length; ++i) { + file.append(pathParts[i]); + } + if (aFilename) { + file.append(aFilename); + } + return file; +} + +function loadHelperScript(aScriptFile) { + let io = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); + let scriptSpec = io.newFileURI(aScriptFile).spec; + let scriptloader = Cc["@mozilla.org/moz/jssubscript-loader;1"]. + getService(Ci.mozIJSSubScriptLoader); + scriptloader.loadSubScript(scriptSpec, this); +} + +var scriptFile = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile); +scriptFile.initWithPath(getState("__LOCATION__")); +scriptFile = scriptFile.parent; +scriptFile.append("testConstants.js"); +loadHelperScript(scriptFile); + +scriptFile = getTestDataFile("sharedUpdateXML.js"); +loadHelperScript(scriptFile); + +const SERVICE_URL = URL_HOST + "/" + REL_PATH_DATA + FILE_SIMPLE_MAR; +const BAD_SERVICE_URL = URL_HOST + "/" + REL_PATH_DATA + "not_here.mar"; + +const SLOW_RESPONSE_INTERVAL = 10; +var gSlowDownloadTimer; +var gSlowCheckTimer; + +function handleRequest(aRequest, aResponse) { + let params = { }; + if (aRequest.queryString) { + params = parseQueryString(aRequest.queryString); + } + + let statusCode = params.statusCode ? parseInt(params.statusCode) : 200; + let statusReason = params.statusReason ? params.statusReason : "OK"; + aResponse.setStatusLine(aRequest.httpVersion, statusCode, statusReason); + aResponse.setHeader("Cache-Control", "no-cache", false); + + // When a mar download is started by the update service it can finish + // downloading before the ui has loaded. By specifying a serviceURL for the + // update patch that points to this file and has a slowDownloadMar param the + // mar will be downloaded asynchronously which will allow the ui to load + // before the download completes. + if (params.slowDownloadMar) { + aResponse.processAsync(); + aResponse.setHeader("Content-Type", "binary/octet-stream"); + aResponse.setHeader("Content-Length", SIZE_SIMPLE_MAR); + var continueFile = getTestDataFile(CONTINUE_DOWNLOAD); + var contents = readFileBytes(getTestDataFile(FILE_SIMPLE_MAR)); + gSlowDownloadTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + gSlowDownloadTimer.initWithCallback(function(aTimer) { + if (continueFile.exists()) { + try { + // If the continue file is in use try again the next time the timer + // fires. + continueFile.remove(false); + gSlowDownloadTimer.cancel(); + aResponse.write(contents); + aResponse.finish(); + } catch (e) { + } + } + }, SLOW_RESPONSE_INTERVAL, Ci.nsITimer.TYPE_REPEATING_SLACK); + return; + } + + if (params.uiURL) { + aResponse.write("" + + params.uiURL + "

this is a test mar that will not " + + "affect your build."); + return; + } + + if (params.xmlMalformed) { + respond(aResponse, params, "xml error"); + return; + } + + if (params.noUpdates) { + respond(aResponse, params, getRemoteUpdatesXMLString("")); + return; + } + + if (params.unsupported) { + let detailsURL = params.detailsURL ? params.detailsURL : URL_HOST; + let unsupportedXML = getRemoteUpdatesXMLString(" \n"); + respond(aResponse, params, unsupportedXML); + return; + } + + let size; + let patches = ""; + let url = ""; + if (params.useSlowDownloadMar) { + url = URL_HTTP_UPDATE_SJS + "?slowDownloadMar=1" + } else { + url = params.badURL ? BAD_SERVICE_URL : SERVICE_URL + } + if (!params.partialPatchOnly) { + size = SIZE_SIMPLE_MAR + (params.invalidCompleteSize ? "1" : ""); + let patchProps = {type: "complete", + url: url, + size: size}; + patches += getRemotePatchString(patchProps); + } + + if (!params.completePatchOnly) { + size = SIZE_SIMPLE_MAR + (params.invalidPartialSize ? "1" : ""); + let patchProps = {type: "partial", + url: url, + size: size}; + patches += getRemotePatchString(patchProps); + } + + let updateProps = {}; + if (params.type) { + updateProps.type = params.type; + } + + if (params.name) { + updateProps.name = params.name; + } + + if (params.appVersion) { + updateProps.appVersion = params.appVersion; + } + + if (params.displayVersion) { + updateProps.displayVersion = params.displayVersion; + } + + if (params.buildID) { + updateProps.buildID = params.buildID; + } + + if (params.promptWaitTime) { + updateProps.promptWaitTime = params.promptWaitTime; + } + + let updates = getRemoteUpdateString(updateProps, patches); + let xml = getRemoteUpdatesXMLString(updates); + respond(aResponse, params, xml); +} + +function respond(aResponse, aParams, aResponseString) { + if (aParams.slowUpdateCheck) { + aResponse.processAsync(); + var continueFile = getTestDataFile(CONTINUE_CHECK); + gSlowCheckTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + gSlowCheckTimer.initWithCallback(function(aTimer) { + if (continueFile.exists()) { + try { + // If the continue file is in use try again the next time the timer + // fires. + continueFile.remove(false); + gSlowCheckTimer.cancel(); + aResponse.write(aResponseString); + aResponse.finish(); + } catch (e) { + } + } + }, SLOW_RESPONSE_INTERVAL, Ci.nsITimer.TYPE_REPEATING_SLACK); + } else { + aResponse.write(aResponseString); + } +} + +/** + * Helper function to create a JS object representing the url parameters from + * the request's queryString. + * + * @param aQueryString + * The request's query string. + * @return A JS object representing the url parameters from the request's + * queryString. + */ +function parseQueryString(aQueryString) { + let paramArray = aQueryString.split("&"); + let regex = /^([^=]+)=(.*)$/; + let params = {}; + for (let i = 0, sz = paramArray.length; i < sz; i++) { + let match = regex.exec(paramArray[i]); + if (!match) { + throw "Bad parameter in queryString! '" + paramArray[i] + "'"; + } + params[decodeURIComponent(match[1])] = decodeURIComponent(match[2]); + } + + return params; +} + +/** + * Reads the binary contents of a file and returns it as a string. + * + * @param aFile + * The file to read from. + * @return The contents of the file as a string. + */ +function readFileBytes(aFile) { + let fis = Cc["@mozilla.org/network/file-input-stream;1"]. + createInstance(Ci.nsIFileInputStream); + fis.init(aFile, -1, -1, false); + let bis = Cc["@mozilla.org/binaryinputstream;1"]. + createInstance(Ci.nsIBinaryInputStream); + bis.setInputStream(fis); + let data = []; + let count = fis.available(); + while (count > 0) { + let bytes = bis.readByteArray(Math.min(65535, count)); + data.push(String.fromCharCode.apply(null, bytes)); + count -= bytes.length; + if (bytes.length == 0) { + throw "Nothing read from input stream!"; + } + } + data.join(''); + fis.close(); + return data.toString(); +} diff --git a/toolkit/mozapps/update/tests/browser/browser.ini b/toolkit/mozapps/update/tests/browser/browser.ini index dc24d67a4a19..45cafb031a87 100644 --- a/toolkit/mozapps/update/tests/browser/browser.ini +++ b/toolkit/mozapps/update/tests/browser/browser.ini @@ -4,7 +4,30 @@ support-files = head.js downloadPage.html testConstants.js + app_update.sjs +[browser_about_bc_downloaded.js] +[browser_about_bc_downloaded_staged.js] +skip-if = asan +reason = Bug 1168003 +[browser_about_fc_check_cantApply.js] +skip-if = os != 'win' +reason = test must be able to prevent file deletion. +[browser_about_fc_check_malformedXML.js] +[browser_about_fc_check_noUpdate.js] +[browser_about_fc_check_unsupported.js] +[browser_about_fc_downloadAuto.js] +[browser_about_fc_downloadAuto_staging.js] +skip-if = asan +reason = Bug 1168003 +[browser_about_fc_downloadOptIn.js] +[browser_about_fc_downloadOptIn_staging.js] +skip-if = asan +reason = Bug 1168003 +[browser_about_fc_patch_completeBadSize.js] +[browser_about_fc_patch_partialBadSize.js] +[browser_about_fc_patch_partialBadSize_complete.js] +[browser_about_fc_patch_partialBadSize_completeBadSize.js] [browser_TelemetryUpdatePing.js] [browser_updateAutoPrefUI.js] skip-if = os != 'win' @@ -17,6 +40,7 @@ reason = Bug 1168003 [browser_updatesBasicPromptNoStaging.js] [browser_updatesCantApply.js] skip-if = os != 'win' +reason = test must be able to prevent file deletion. [browser_updatesCompleteAndPartialPatchesWithBadCompleteSize.js] [browser_updatesCompleteAndPartialPatchesWithBadPartialSize.js] [browser_updatesCompleteAndPartialPatchesWithBadSizes.js] diff --git a/toolkit/mozapps/update/tests/browser/browser_about_bc_downloaded.js b/toolkit/mozapps/update/tests/browser/browser_about_bc_downloaded.js new file mode 100644 index 000000000000..d75278ae1650 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_about_bc_downloaded.js @@ -0,0 +1,17 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for About Dialog background check for updates +// with the update downloaded. +add_task(async function aboutDialog_backgroundCheck_downloaded() { + let updateParams = ""; + await runAboutDialogUpdateTest(updateParams, true, [ + { + panelId: "apply", + checkActiveUpdate: {state: STATE_PENDING}, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_about_bc_downloaded_staged.js b/toolkit/mozapps/update/tests/browser/browser_about_bc_downloaded_staged.js new file mode 100644 index 000000000000..bb868df9ad50 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_about_bc_downloaded_staged.js @@ -0,0 +1,25 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for About Dialog background check for updates +// with the update downloaded and staged. +add_task(async function aboutDialog_backgroundCheck_downloaded_staged() { + await SpecialPowers.pushPrefEnv({ + set: [ + [PREF_APP_UPDATE_STAGING_ENABLED, true], + ], + }); + + // Since the partial should be successful specify an invalid size for the + // complete update. + let updateParams = "&invalidCompleteSize=1"; + await runAboutDialogUpdateTest(updateParams, true, [ + { + panelId: "apply", + checkActiveUpdate: {state: STATE_APPLIED}, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_about_fc_check_cantApply.js b/toolkit/mozapps/update/tests/browser/browser_about_fc_check_cantApply.js new file mode 100644 index 000000000000..f31ec3928c90 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_about_fc_check_cantApply.js @@ -0,0 +1,24 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for About Dialog foreground check for updates +// without the ability to apply updates. +add_task(async function aboutDialog_foregroundCheck_cantApply() { + lockWriteTestFile(); + + let updateParams = ""; + await runAboutDialogUpdateTest(updateParams, false, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "manualUpdate", + checkActiveUpdate: null, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_about_fc_check_malformedXML.js b/toolkit/mozapps/update/tests/browser/browser_about_fc_check_malformedXML.js new file mode 100644 index 000000000000..389a2903d9ec --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_about_fc_check_malformedXML.js @@ -0,0 +1,22 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for About Dialog foreground check for updates +// with a malformed update XML file. +add_task(async function aboutDialog_foregroundCheck_malformedXML() { + let updateParams = "&xmlMalformed=1"; + await runAboutDialogUpdateTest(updateParams, false, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "noUpdatesFound", + checkActiveUpdate: null, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_about_fc_check_noUpdate.js b/toolkit/mozapps/update/tests/browser/browser_about_fc_check_noUpdate.js new file mode 100644 index 000000000000..d0974a2b3acc --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_about_fc_check_noUpdate.js @@ -0,0 +1,22 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for About Dialog foreground check for updates +// with no update available. +add_task(async function aboutDialog_foregroundCheck_noUpdate() { + let updateParams = "&noUpdates=1"; + await runAboutDialogUpdateTest(updateParams, false, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "noUpdatesFound", + checkActiveUpdate: null, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_about_fc_check_unsupported.js b/toolkit/mozapps/update/tests/browser/browser_about_fc_check_unsupported.js new file mode 100644 index 000000000000..0b0703139871 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_about_fc_check_unsupported.js @@ -0,0 +1,22 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for About Dialog foreground check for updates +// with an unsupported update. +add_task(async function aboutDialog_foregroundCheck_unsupported() { + let updateParams = "&unsupported=1"; + await runAboutDialogUpdateTest(updateParams, false, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "unsupportedSystem", + checkActiveUpdate: null, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_about_fc_downloadAuto.js b/toolkit/mozapps/update/tests/browser/browser_about_fc_downloadAuto.js new file mode 100644 index 000000000000..ac38cca64d63 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_about_fc_downloadAuto.js @@ -0,0 +1,29 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for About Dialog foreground check for updates +// with an automatic download. +add_task(async function aboutDialog_foregroundCheck_downloadAuto() { + // Since the partial should be successful specify an invalid size for the + // complete update. + let updateParams = "&invalidCompleteSize=1"; + await runAboutDialogUpdateTest(updateParams, false, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloading", + checkActiveUpdate: {state: STATE_DOWNLOADING}, + continueFile: CONTINUE_DOWNLOAD, + }, + { + panelId: "apply", + checkActiveUpdate: {state: STATE_PENDING}, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_about_fc_downloadAuto_staging.js b/toolkit/mozapps/update/tests/browser/browser_about_fc_downloadAuto_staging.js new file mode 100644 index 000000000000..14c8fa7e610a --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_about_fc_downloadAuto_staging.js @@ -0,0 +1,40 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for About Dialog foreground check for updates +// with an automatic download and update staging. +add_task(async function aboutDialog_foregroundCheck_downloadAuto_staging() { + await SpecialPowers.pushPrefEnv({ + set: [ + [PREF_APP_UPDATE_STAGING_ENABLED, true], + ], + }); + + // Since the partial should be successful specify an invalid size for the + // complete update. + let updateParams = "&invalidCompleteSize=1"; + await runAboutDialogUpdateTest(updateParams, false, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloading", + checkActiveUpdate: {state: STATE_DOWNLOADING}, + continueFile: CONTINUE_DOWNLOAD, + }, + { + panelId: "applying", + checkActiveUpdate: {state: STATE_PENDING}, + continueFile: CONTINUE_STAGING, + }, + { + panelId: "apply", + checkActiveUpdate: {state: STATE_APPLIED}, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_about_fc_downloadOptIn.js b/toolkit/mozapps/update/tests/browser/browser_about_fc_downloadOptIn.js new file mode 100644 index 000000000000..b8185336d9f3 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_about_fc_downloadOptIn.js @@ -0,0 +1,36 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for About Dialog foreground check for updates +// with a manual download. +add_task(async function aboutDialog_foregroundCheck_downloadOptIn() { + await UpdateUtils.setAppUpdateAutoEnabled(false); + + // Since the partial should be successful specify an invalid size for the + // complete update. + let updateParams = "&invalidCompleteSize=1"; + await runAboutDialogUpdateTest(updateParams, false, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloadAndInstall", + checkActiveUpdate: null, + continueFile: null, + }, + { + panelId: "downloading", + checkActiveUpdate: {state: STATE_DOWNLOADING}, + continueFile: CONTINUE_DOWNLOAD, + }, + { + panelId: "apply", + checkActiveUpdate: {state: STATE_PENDING}, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_about_fc_downloadOptIn_staging.js b/toolkit/mozapps/update/tests/browser/browser_about_fc_downloadOptIn_staging.js new file mode 100644 index 000000000000..58efd0ee8623 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_about_fc_downloadOptIn_staging.js @@ -0,0 +1,46 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for About Dialog foreground check for updates +// with a manual download and update staging. +add_task(async function aboutDialog_foregroundCheck_downloadOptIn_staging() { + await SpecialPowers.pushPrefEnv({ + set: [ + [PREF_APP_UPDATE_STAGING_ENABLED, true], + ], + }); + await UpdateUtils.setAppUpdateAutoEnabled(false); + + // Since the partial should be successful specify an invalid size for the + // complete update. + let updateParams = "&invalidCompleteSize=1"; + await runAboutDialogUpdateTest(updateParams, false, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloadAndInstall", + checkActiveUpdate: null, + continueFile: null, + }, + { + panelId: "downloading", + checkActiveUpdate: {state: STATE_DOWNLOADING}, + continueFile: CONTINUE_DOWNLOAD, + }, + { + panelId: "applying", + checkActiveUpdate: {state: STATE_PENDING}, + continueFile: CONTINUE_STAGING, + }, + { + panelId: "apply", + checkActiveUpdate: {state: STATE_APPLIED}, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_about_fc_patch_completeBadSize.js b/toolkit/mozapps/update/tests/browser/browser_about_fc_patch_completeBadSize.js new file mode 100644 index 000000000000..1fc0e77e6669 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_about_fc_patch_completeBadSize.js @@ -0,0 +1,27 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for About Dialog foreground check for updates +// with a complete bad size patch. +add_task(async function aboutDialog_foregroundCheck_completeBadSize() { + let updateParams = "&completePatchOnly=1&invalidCompleteSize=1"; + await runAboutDialogUpdateTest(updateParams, false, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloading", + checkActiveUpdate: {state: STATE_DOWNLOADING}, + continueFile: CONTINUE_DOWNLOAD, + }, + { + panelId: "downloadFailed", + checkActiveUpdate: null, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_about_fc_patch_partialBadSize.js b/toolkit/mozapps/update/tests/browser/browser_about_fc_patch_partialBadSize.js new file mode 100644 index 000000000000..e3ef71f023cc --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_about_fc_patch_partialBadSize.js @@ -0,0 +1,27 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for About Dialog foreground check for updates +// with a partial bad size patch. +add_task(async function aboutDialog_foregroundCheck_partialBadSize() { + let updateParams = "&partialPatchOnly=1&invalidPartialSize=1"; + await runAboutDialogUpdateTest(updateParams, false, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloading", + checkActiveUpdate: {state: STATE_DOWNLOADING}, + continueFile: CONTINUE_DOWNLOAD, + }, + { + panelId: "downloadFailed", + checkActiveUpdate: null, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_about_fc_patch_partialBadSize_complete.js b/toolkit/mozapps/update/tests/browser/browser_about_fc_patch_partialBadSize_complete.js new file mode 100644 index 000000000000..93e69c9a36a2 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_about_fc_patch_partialBadSize_complete.js @@ -0,0 +1,32 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for About Dialog foreground check for updates +// with a partial bad size patch and a complete patch. +add_task(async function aboutDialog_foregroundCheck_partialBadSize_complete() { + let updateParams = "&invalidPartialSize=1"; + await runAboutDialogUpdateTest(updateParams, false, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloading", + checkActiveUpdate: {state: STATE_DOWNLOADING}, + continueFile: CONTINUE_DOWNLOAD, + }, + { + panelId: "downloading", + checkActiveUpdate: {state: STATE_DOWNLOADING}, + continueFile: CONTINUE_DOWNLOAD, + }, + { + panelId: "apply", + checkActiveUpdate: {state: STATE_PENDING}, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_about_fc_patch_partialBadSize_completeBadSize.js b/toolkit/mozapps/update/tests/browser/browser_about_fc_patch_partialBadSize_completeBadSize.js new file mode 100644 index 000000000000..484bec54ed7d --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_about_fc_patch_partialBadSize_completeBadSize.js @@ -0,0 +1,32 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for About Dialog foreground check for updates +// with a partial bad size patch and a complete bad size patch. +add_task(async function aboutDialog_foregroundCheck_partialBadSize_completeBadSize() { + let updateParams = "&invalidPartialSize=1&invalidCompleteSize=1"; + await runAboutDialogUpdateTest(updateParams, false, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloading", + checkActiveUpdate: {state: STATE_DOWNLOADING}, + continueFile: CONTINUE_DOWNLOAD, + }, + { + panelId: "downloading", + checkActiveUpdate: {state: STATE_DOWNLOADING}, + continueFile: CONTINUE_DOWNLOAD, + }, + { + panelId: "downloadFailed", + checkActiveUpdate: null, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_updatesBasicPrompt.js b/toolkit/mozapps/update/tests/browser/browser_updatesBasicPrompt.js index f15f67d318bb..fbd9478ff94a 100644 --- a/toolkit/mozapps/update/tests/browser/browser_updatesBasicPrompt.js +++ b/toolkit/mozapps/update/tests/browser/browser_updatesBasicPrompt.js @@ -5,7 +5,6 @@ add_task(async function testBasicPrompt() { await UpdateUtils.setAppUpdateAutoEnabled(false); let updateParams = "promptWaitTime=0"; - gUseTestUpdater = true; await runUpdateTest(updateParams, 1, [ { diff --git a/toolkit/mozapps/update/tests/browser/browser_updatesCantApply.js b/toolkit/mozapps/update/tests/browser/browser_updatesCantApply.js index a3e3cf1119cb..dd7a6482aa6e 100644 --- a/toolkit/mozapps/update/tests/browser/browser_updatesCantApply.js +++ b/toolkit/mozapps/update/tests/browser/browser_updatesCantApply.js @@ -1,13 +1,9 @@ add_task(async function testBasicPrompt() { SpecialPowers.pushPrefEnv({set: [[PREF_APP_UPDATE_SERVICE_ENABLED, false]]}); + lockWriteTestFile(); let updateParams = "promptWaitTime=0"; - let file = getWriteTestFile(); - file.create(file.NORMAL_FILE_TYPE, 0o444); - file.fileAttributesWin |= file.WFA_READONLY; - file.fileAttributesWin &= ~file.WFA_READWRITE; - await runUpdateTest(updateParams, 1, [ { notificationId: "update-manual", @@ -17,20 +13,7 @@ add_task(async function testBasicPrompt() { is(gBrowser.selectedBrowser.currentURI.spec, URL_MANUAL_UPDATE, "Landed on manual update page."); gBrowser.removeTab(gBrowser.selectedTab); - getWriteTestFile(); }, }, ]); }); - -function getWriteTestFile() { - let file = getUpdatesRootDir(); - file.append(FILE_UPDATE_TEST); - file.QueryInterface(Ci.nsILocalFileWin); - if (file.exists()) { - file.fileAttributesWin |= file.WFA_READWRITE; - file.fileAttributesWin &= ~file.WFA_READONLY; - file.remove(true); - } - return file; -} diff --git a/toolkit/mozapps/update/tests/browser/head.js b/toolkit/mozapps/update/tests/browser/head.js index c4d4498f3f64..41d1137de75e 100644 --- a/toolkit/mozapps/update/tests/browser/head.js +++ b/toolkit/mozapps/update/tests/browser/head.js @@ -16,12 +16,9 @@ const FILE_UPDATER_BIN_BAK = FILE_UPDATER_BIN + ".bak"; const PREF_APP_UPDATE_INTERVAL = "app.update.interval"; const PREF_APP_UPDATE_LASTUPDATETIME = "app.update.lastUpdateTime.background-update-timer"; -let gRembemberedPrefs = []; - const DATA_URI_SPEC = "chrome://mochitests/content/browser/toolkit/mozapps/update/tests/browser/"; var DEBUG_AUS_TEST = true; -var gUseTestUpdater = false; const LOG_FUNCTION = info; @@ -38,33 +35,105 @@ const URL_MANUAL_UPDATE = gURLData + "downloadPage.html"; const gEnv = Cc["@mozilla.org/process/environment;1"]. getService(Ci.nsIEnvironment); -const NOTIFICATIONS = [ - "update-available", - "update-manual", - "update-restart", -]; - let gOriginalUpdateAutoValue = null; /** - * Delay for a very short period. Useful for moving the code after this - * to the back of the event loop. + * Creates the continue file used to signal that update staging or the mock http + * server should continue. The delay this creates allows the tests to verify the + * user interfaces before they auto advance to phases of an update. The continue + * file for staging will be deleted by the test updater and the continue file + * for update check and update download requests will be deleted by the test + * http server handler implemented in app_update.sjs. The test returns a promise + * so the test can wait on the deletion of the continue file when necessary. * - * @return A promise which will resolve after a very short period. + * @param leafName + * The leafName of the file to create. This should be one of the + * folowing constants that are defined in testConstants.js: + * CONTINUE_CHECK + * CONTINUE_DOWNLOAD + * CONTINUE_STAGING + * @return Promise + * Resolves when the file is deleted. + * Rejects if timeout is exceeded or condition ever throws. + * @throws If the file already exists. */ -function delay() { - return new Promise(resolve => executeSoon(resolve)); +async function continueFileHandler(leafName) { + // The default number of retries of 50 in TestUtils.waitForCondition is + // sufficient for test http server requests. The total time to wait with the + // default interval of 100 is approximately 5 seconds. + let retries = undefined; + let continueFile; + if (leafName == CONTINUE_STAGING) { + debugDump("creating " + leafName + " file for slow update staging"); + // Use 100 retries for staging requests to lessen the likelihood of tests + // intermittently failing on debug builds due to launching the updater. The + // total time to wait with the default interval of 100 is approximately 10 + // seconds. The test updater uses the same values. + retries = 100; + continueFile = getUpdatesPatchDir(); + continueFile.append(leafName); + } else { + debugDump("creating " + leafName + " file for slow http server requests"); + continueFile = Services.dirsvc.get("CurWorkD", Ci.nsIFile); + let continuePath = REL_PATH_DATA + leafName; + let continuePathParts = continuePath.split("/"); + for (let i = 0; i < continuePathParts.length; ++i) { + continueFile.append(continuePathParts[i]); + } + } + if (continueFile.exists()) { + throw new Error("The continue file should not exist, path: " + + continueFile.path); + } + continueFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE); + return BrowserTestUtils.waitForCondition(() => + (!continueFile.exists()), + "Waiting for file to be deleted, path: " + continueFile.path, + undefined, retries); + +} + +/** + * Creates and locks the app update write test file so it is possible to test + * when the user doesn't have write access to update. Since this is only + * possible on Windows the function throws when it is called on other platforms. + * This uses registerCleanupFunction to remove the lock and the file when the + * test completes. + * + * @throws If the function is called on a platform other than Windows. + */ +function lockWriteTestFile() { + if (AppConstants.platform != "win") { + throw new Error("Windows only test function called"); + } + let file = getUpdatesRootDir(); + file.append(FILE_UPDATE_TEST); + file.QueryInterface(Ci.nsILocalFileWin); + // Remove the file if it exists just in case. + if (file.exists()) { + file.fileAttributesWin |= file.WFA_READWRITE; + file.fileAttributesWin &= ~file.WFA_READONLY; + file.remove(false); + } + file.create(file.NORMAL_FILE_TYPE, 0o444); + file.fileAttributesWin |= file.WFA_READONLY; + file.fileAttributesWin &= ~file.WFA_READWRITE; + registerCleanupFunction(() => { + file.fileAttributesWin |= file.WFA_READWRITE; + file.fileAttributesWin &= ~file.WFA_READONLY; + file.remove(false); + }); } /** * Gets the update version info for the update url parameters to send to - * update.sjs. + * app_update.sjs. * * @param aAppVersion (optional) * The application version for the update snippet. If not specified the * current application version will be used. * @return The url parameters for the application and platform version to send - * to update.sjs. + * to app_update.sjs. */ function getVersionParams(aAppVersion) { let appInfo = Services.appinfo; @@ -124,7 +193,7 @@ add_task(async function setDefaults() { * everything is cleaned up afterwards. * * @param updateParams - * URL-encoded params which will be sent to update.sjs. + * Params which will be sent to app_update.sjs. * @param checkAttempts * How many times to check for updates. Useful for testing the UI * for check failures. @@ -318,21 +387,20 @@ function checkWhatsNewLink(win, id, url) { } /** - * For tests that use the test updater restores the backed up real updater if - * it exists and tries again on failure since Windows debug builds at times - * leave the file in use. After success moveRealUpdater is called to continue - * the setup of the test updater. For tests that don't use the test updater - * runTest will be called. + * For staging tests the test updater must be used and this restores the backed + * up real updater if it exists and tries again on failure since Windows debug + * builds at times leave the file in use. After success moveRealUpdater is + * called to continue the setup of the test updater. */ function setupTestUpdater() { return (async function() { - if (gUseTestUpdater) { + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_STAGING_ENABLED)) { try { restoreUpdaterBackup(); } catch (e) { logTestInfo("Attempt to restore the backed up updater failed... " + "will try again, Exception: " + e); - await delay(); + await TestUtils.waitForTick(); await setupTestUpdater(); return; } @@ -357,7 +425,7 @@ function moveRealUpdater() { } catch (e) { logTestInfo("Attempt to move the real updater out of the way failed... " + "will try again, Exception: " + e); - await delay(); + await TestUtils.waitForTick(); await moveRealUpdater(); return; } @@ -367,9 +435,8 @@ function moveRealUpdater() { } /** - * Copies the test updater so it can be used by tests and tries again on failure - * since Windows debug builds at times leave the file in use. After success it - * will call runTest to continue the test. + * Copies the test updater and tries again on failure since Windows debug builds + * at times leave the file in use. */ function copyTestUpdater(attempt = 0) { return (async function() { @@ -391,7 +458,7 @@ function copyTestUpdater(attempt = 0) { if (attempt < MAX_UPDATE_COPY_ATTEMPTS) { logTestInfo("Attempt to copy the test updater failed... " + "will try again, Exception: " + e); - await delay(); + await TestUtils.waitForTick(); await copyTestUpdater(attempt + 1); } } @@ -401,9 +468,7 @@ function copyTestUpdater(attempt = 0) { /** * Restores the updater that was backed up. This is called in setupTestUpdater * before the backup of the real updater is done in case the previous test - * failed to restore the updater, in finishTestDefaultWaitForWindowClosed when - * the test has finished, and in test_9999_cleanup.xul after all tests have - * finished. + * failed to restore the updater when the test has finished. */ function restoreUpdaterBackup() { let baseAppDir = getAppBaseDir(); @@ -420,13 +485,12 @@ function restoreUpdaterBackup() { } /** - * When a test finishes this will repeatedly attempt to restore the real updater - * for tests that use the test updater and then call - * finishTestDefaultWaitForWindowClosed after the restore is successful. + * When a staging test finishes this will repeatedly attempt to restore the real + * updater. */ function finishTestRestoreUpdaterBackup() { return (async function() { - if (gUseTestUpdater) { + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_STAGING_ENABLED)) { try { // Windows debug builds keep the updater file in use for a short period of // time after the updater process exits. @@ -435,9 +499,169 @@ function finishTestRestoreUpdaterBackup() { logTestInfo("Attempt to restore the backed up updater failed... " + "will try again, Exception: " + e); - await delay(); + await TestUtils.waitForTick(); await finishTestRestoreUpdaterBackup(); } } })(); } + +/** + * Waits for the About Dialog to load. + * + * @return 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: aXULWindow => { + debugDump("About dialog shown..."); + Services.wm.removeListener(listener); + + async function aboutDialogOnLoad() { + domwindow.removeEventListener("load", aboutDialogOnLoad, true); + let chromeURI = "chrome://browser/content/aboutDialog.xul"; + is(domwindow.document.location.href, chromeURI, "About dialog appeared"); + resolve(domwindow); + } + + var domwindow = aXULWindow.docShell.domWindow; + domwindow.addEventListener("load", aboutDialogOnLoad, true); + }, + onCloseWindow: aXULWindow => {}, + }; + + Services.wm.addListener(listener); + openAboutDialog(); + }); +} + +/** + * Runs an About Dialog update test. This will set various common prefs for + * updating and runs the provided list of steps. + * + * @param updateParams + * Params which will be sent to app_update.sjs. + * @param backgroundUpdate + * If true a background check will be performed before opening the About + * Dialog. + * @param steps + * An array of test steps to perform. A step will either be an object + * containing expected conditions and actions or a function to call. + * @return A promise which will resolve once all of the steps have been run. + */ +function runAboutDialogUpdateTest(updateParams, backgroundUpdate, steps) { + let aboutDialog; + function processAboutDialogStep(step) { + if (typeof(step) == "function") { + return step(); + } + + // Helper function to get the selected panel. + function getSelectedPanel() { + return aboutDialog.document.getElementById("updateDeck").selectedPanel; + } + + // Helper function to get the selected panel's button. + function getSelectedPanelButton() { + return getSelectedPanel().querySelector("button"); + } + + // Helper function to get the selected panel's label with a class of + // text-link. + function getSelectedLabelLink() { + return getSelectedPanel().querySelector("label.text-link"); + } + + const {panelId, checkActiveUpdate, continueFile} = step; + return (async function() { + await BrowserTestUtils.waitForCondition(() => + (getSelectedPanel() && getSelectedPanel().id == panelId), + "Waiting for expected panel ID - expected \"" + panelId + "\""); + + // Skip when checkActiveUpdate evaluates to false. + if (checkActiveUpdate) { + ok(!!gUpdateManager.activeUpdate, "There should be an active update"); + is(gUpdateManager.activeUpdate.state, checkActiveUpdate.state, + "The active update state should equal " + checkActiveUpdate.state); + } else { + ok(!gUpdateManager.activeUpdate, + "There should not be an active update"); + } + + if (continueFile) { + await continueFileHandler(continueFile); + } + + let linkPanels = ["downloadFailed", "manualUpdate", "unsupportedSystem"]; + if (linkPanels.includes(panelId)) { + // The unsupportedSystem panel uses the update's detailsURL and the + // downloadFailed and manualUpdate panels use the app.update.url.manual + // preference. + let labelLink = getSelectedLabelLink(); + is(labelLink.href, URL_HOST, + "The panel's link href should equal the expected value"); + } + + let buttonPanels = ["downloadAndInstall", "apply"]; + if (buttonPanels.includes(panelId)) { + let buttonEl = getSelectedPanelButton(); + await BrowserTestUtils.waitForCondition(() => + (aboutDialog.document.activeElement == buttonEl), + "The button should receive focus"); + ok(!buttonEl.disabled, "The button should be enabled"); + // Don't click the button on the apply panel since this will restart the + // application. + if (panelId != "apply") { + buttonEl.click(); + } + } + })(); + } + + return (async function() { + await SpecialPowers.pushPrefEnv({ + set: [ + [PREF_APP_UPDATE_SERVICE_ENABLED, false], + [PREF_APP_UPDATE_DISABLEDFORTESTING, false], + [PREF_APP_UPDATE_URL_MANUAL, URL_HOST], + ], + }); + registerCleanupFunction(() => { + gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", ""); + UpdateListener.reset(); + cleanUpUpdates(); + }); + + gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "1"); + setUpdateTimerPrefs(); + removeUpdateDirsAndFiles(); + + await setupTestUpdater(); + + let url = URL_HTTP_UPDATE_SJS + "?detailsURL=" + URL_HOST + + updateParams + getVersionParams(); + if (backgroundUpdate) { + setUpdateURL(url); + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_STAGING_ENABLED)) { + // Don't wait on the deletion of the continueStaging file + continueFileHandler(CONTINUE_STAGING); + } + gAUS.checkForBackgroundUpdates(); + await waitForEvent("update-downloaded"); + } else { + url += "&slowUpdateCheck=1&useSlowDownloadMar=1"; + setUpdateURL(url); + } + + aboutDialog = await waitForAboutDialog(); + + for (let step of steps) { + await processAboutDialogStep(step); + } + + aboutDialog.close(); + await finishTestRestoreUpdaterBackup(); + })(); +} diff --git a/toolkit/mozapps/update/tests/browser/testConstants.js b/toolkit/mozapps/update/tests/browser/testConstants.js index 1929f2f6f121..06a2784451df 100644 --- a/toolkit/mozapps/update/tests/browser/testConstants.js +++ b/toolkit/mozapps/update/tests/browser/testConstants.js @@ -1,4 +1,7 @@ const REL_PATH_DATA = "browser/toolkit/mozapps/update/tests/browser/"; const URL_HOST = "http://example.com"; -const URL_PATH_UPDATE_XML = "/" + REL_PATH_DATA + "update.sjs"; +const URL_PATH_UPDATE_XML = "/" + REL_PATH_DATA + "app_update.sjs"; const URL_HTTP_UPDATE_SJS = URL_HOST + URL_PATH_UPDATE_XML; +const CONTINUE_CHECK = "continueCheck"; +const CONTINUE_DOWNLOAD = "continueDownload"; +const CONTINUE_STAGING = "continueStaging"; diff --git a/toolkit/mozapps/update/tests/chrome/chrome.ini b/toolkit/mozapps/update/tests/chrome/chrome.ini index 1ceb5d7279a7..f7e8cbaf6e9d 100644 --- a/toolkit/mozapps/update/tests/chrome/chrome.ini +++ b/toolkit/mozapps/update/tests/chrome/chrome.ini @@ -6,6 +6,7 @@ tags = appupdate support-files = testConstants.js + update.sjs utils.js # mochitest-chrome tests must start with "test_" and are executed in sorted diff --git a/toolkit/mozapps/update/tests/data/update.sjs b/toolkit/mozapps/update/tests/chrome/update.sjs similarity index 100% rename from toolkit/mozapps/update/tests/data/update.sjs rename to toolkit/mozapps/update/tests/chrome/update.sjs diff --git a/toolkit/mozapps/update/tests/moz.build b/toolkit/mozapps/update/tests/moz.build index 88d5c14326b2..97a40efb2436 100644 --- a/toolkit/mozapps/update/tests/moz.build +++ b/toolkit/mozapps/update/tests/moz.build @@ -65,14 +65,12 @@ TEST_HARNESS_FILES.testing.mochitest.browser.toolkit.mozapps.update.tests.browse 'data/shared.js', 'data/sharedUpdateXML.js', 'data/simple.mar', - 'data/update.sjs', ] TEST_HARNESS_FILES.testing.mochitest.chrome.toolkit.mozapps.update.tests.chrome += [ 'data/shared.js', 'data/sharedUpdateXML.js', 'data/simple.mar', - 'data/update.sjs', ] FINAL_TARGET_FILES += [ diff --git a/toolkit/mozapps/update/updater/updater.cpp b/toolkit/mozapps/update/updater/updater.cpp index 6d6bfe6923c4..aa8d15270113 100644 --- a/toolkit/mozapps/update/updater/updater.cpp +++ b/toolkit/mozapps/update/updater/updater.cpp @@ -2459,6 +2459,33 @@ static void UpdateThreadFunc(void *param) { // this can cause tests to timeout. if (EnvHasValue("MOZ_TEST_SKIP_UPDATE_STAGE")) { rv = OK; + } else if (EnvHasValue("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE")) { + // The following is to simulate staging so the UI tests have time to + // show that the update is being staged. + NS_tchar continueFilePath[MAXPATHLEN] = {NS_T('\0')}; + NS_tsnprintf(continueFilePath, + sizeof(continueFilePath) / sizeof(continueFilePath[0]), + NS_T("%s/continueStaging"), gPatchDirPath); + // Use 100 retries for staging requests to lessen the likelihood of + // tests intermittently failing on debug builds due to launching the + // updater. The total time to wait with the default interval of 100 ms + // is approximately 10 seconds. The tests use the same values. + const int max_retries = 100; + int retries = 1; + while (retries++ < max_retries) { +#ifdef XP_WIN + Sleep(100); +#else + usleep(100000); +#endif + // Continue after the continue file exists and it is successfully + // removed. + if (!NS_taccess(continueFilePath, F_OK) && + !NS_tremove(continueFilePath)) { + break; + } + } + rv = OK; } else { rv = CopyInstallDirToDestDir(); }