diff options
Diffstat (limited to 'toolkit/mozapps/update/tests/browser')
72 files changed, 4337 insertions, 0 deletions
diff --git a/toolkit/mozapps/update/tests/browser/browser.bits.ini b/toolkit/mozapps/update/tests/browser/browser.bits.ini new file mode 100644 index 0000000000..d3cb7182c3 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser.bits.ini @@ -0,0 +1,79 @@ +[DEFAULT] +skip-if = os != 'win' +reason = BITS is only available on Windows. +dupe-manifest = +tags = appupdate bits +head = head.js +support-files = + ../data/shared.js + ../data/sharedUpdateXML.js + ../data/app_update.sjs + downloadPage.html + testConstants.js + +prefs = + app.update.BITS.enabled=true + app.update.langpack.enabled=true + +# BITS Download Tests +##################### + +# About Dialog Application Update Tests +[browser_aboutDialog_bc_downloading.js] +[browser_aboutDialog_bc_downloading_staging.js] +[browser_aboutDialog_bc_downloading_notify.js] +[browser_aboutDialog_bc_downloaded.js] +[browser_aboutDialog_bc_downloaded_staging.js] +[browser_aboutDialog_bc_downloaded_staged.js] +[browser_aboutDialog_bc_downloaded_stagingFailure.js] +[browser_aboutDialog_fc_downloadAuto.js] +[browser_aboutDialog_fc_downloadAuto_staging.js] +[browser_aboutDialog_fc_downloadOptIn.js] +[browser_aboutDialog_fc_downloadOptIn_staging.js] +[browser_aboutDialog_fc_patch_completeBadSize.js] +[browser_aboutDialog_fc_patch_partialBadSize.js] +[browser_aboutDialog_fc_patch_partialBadSize_complete.js] +[browser_aboutDialog_fc_patch_partialBadSize_completeBadSize.js] +[browser_aboutDialog_bc_multiUpdate.js] + +# about:preferences Application Update Tests +[browser_aboutPrefs_bc_downloading.js] +[browser_aboutPrefs_bc_downloading_staging.js] +[browser_aboutPrefs_bc_downloaded.js] +[browser_aboutPrefs_bc_downloaded_staging.js] +[browser_aboutPrefs_bc_downloaded_stagingFailure.js] +[browser_aboutPrefs_bc_downloaded_staged.js] +[browser_aboutPrefs_fc_downloadAuto.js] +[browser_aboutPrefs_fc_downloadAuto_staging.js] +[browser_aboutPrefs_fc_downloadOptIn.js] +[browser_aboutPrefs_fc_downloadOptIn_staging.js] +[browser_aboutPrefs_fc_patch_completeBadSize.js] +[browser_aboutPrefs_fc_patch_partialBadSize.js] +[browser_aboutPrefs_fc_patch_partialBadSize_complete.js] +[browser_aboutPrefs_fc_patch_partialBadSize_completeBadSize.js] +[browser_aboutPrefs_bc_multiUpdate.js] + +# Doorhanger Application Update Tests +[browser_doorhanger_bc_downloaded.js] +[browser_doorhanger_bc_downloaded_staged.js] +[browser_doorhanger_bc_downloadAutoFailures.js] +[browser_doorhanger_bc_downloadAutoFailures_bgWin.js] +[browser_doorhanger_bc_downloadOptIn.js] +[browser_doorhanger_bc_downloadOptIn_bgWin.js] +[browser_doorhanger_bc_downloadOptIn_staging.js] +[browser_doorhanger_bc_patch_completeBadSize.js] +[browser_doorhanger_bc_patch_partialBadSize.js] +[browser_doorhanger_bc_patch_partialBadSize_complete.js] +[browser_doorhanger_bc_patch_partialBadSize_completeBadSize.js] +[browser_doorhanger_sp_patch_completeApplyFailure.js] +[browser_doorhanger_sp_patch_partialApplyFailure.js] +[browser_doorhanger_sp_patch_partialApplyFailure_complete.js] +[browser_doorhanger_sp_patch_partialApplyFailure_complete_staging.js] +[browser_doorhanger_sp_patch_partialApplyFailure_completeBadSize.js] +[browser_doorhanger_bc_downloaded_disableBITS.js] +[browser_doorhanger_bc_multiUpdate.js] +[browser_doorhanger_bc_multiUpdate_promptWaitTime.js] + +# Telemetry Update Ping Tests +[browser_telemetry_updatePing_downloaded_ready.js] +[browser_telemetry_updatePing_staged_ready.js] diff --git a/toolkit/mozapps/update/tests/browser/browser.ini b/toolkit/mozapps/update/tests/browser/browser.ini new file mode 100644 index 0000000000..eb62df68c3 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser.ini @@ -0,0 +1,100 @@ +[DEFAULT] +dupe-manifest = +tags = appupdate internal +head = head.js +support-files = + ../data/shared.js + ../data/sharedUpdateXML.js + ../data/app_update.sjs + downloadPage.html + testConstants.js +prefs = + app.update.BITS.enabled=false + app.update.langpack.enabled=true + +# About Dialog Application Update Tests +[browser_aboutDialog_bc_downloading.js] +[browser_aboutDialog_bc_downloading_staging.js] +[browser_aboutDialog_bc_downloading_notify.js] +[browser_aboutDialog_bc_downloaded.js] +[browser_aboutDialog_bc_downloaded_staging.js] +[browser_aboutDialog_bc_downloaded_stagingFailure.js] +[browser_aboutDialog_bc_downloaded_staged.js] +[browser_aboutDialog_fc_downloadAuto.js] +skip-if = tsan # Bug 1683730 +[browser_aboutDialog_fc_downloadAuto_staging.js] +[browser_aboutDialog_fc_downloadOptIn.js] +[browser_aboutDialog_fc_downloadOptIn_staging.js] +[browser_aboutDialog_fc_patch_completeBadSize.js] +[browser_aboutDialog_fc_patch_partialBadSize.js] +[browser_aboutDialog_fc_patch_partialBadSize_complete.js] +[browser_aboutDialog_fc_patch_partialBadSize_completeBadSize.js] +[browser_aboutDialog_fc_check_cantApply.js] +skip-if = os != 'win' +reason = test must be able to prevent file deletion. +[browser_aboutDialog_fc_check_malformedXML.js] +[browser_aboutDialog_fc_check_noUpdate.js] +[browser_aboutDialog_fc_check_otherInstance.js] +skip-if = os != 'win' +reason = Windows only feature. +[browser_aboutDialog_fc_check_unsupported.js] +[browser_aboutDialog_bc_multiUpdate.js] + +# about:preferences Application Update Tests +[browser_aboutPrefs_bc_downloading.js] +[browser_aboutPrefs_bc_downloading_staging.js] +[browser_aboutPrefs_bc_downloaded.js] +[browser_aboutPrefs_bc_downloaded_staging.js] +[browser_aboutPrefs_bc_downloaded_stagingFailure.js] +[browser_aboutPrefs_bc_downloaded_staged.js] +[browser_aboutPrefs_fc_downloadAuto.js] +[browser_aboutPrefs_fc_downloadAuto_staging.js] +[browser_aboutPrefs_fc_downloadOptIn.js] +[browser_aboutPrefs_fc_downloadOptIn_staging.js] +[browser_aboutPrefs_fc_patch_completeBadSize.js] +[browser_aboutPrefs_fc_patch_partialBadSize.js] +[browser_aboutPrefs_fc_patch_partialBadSize_complete.js] +[browser_aboutPrefs_fc_patch_partialBadSize_completeBadSize.js] +[browser_aboutPrefs_fc_check_cantApply.js] +skip-if = os != 'win' +reason = test must be able to prevent file deletion. +[browser_aboutPrefs_fc_check_malformedXML.js] +[browser_aboutPrefs_fc_check_noUpdate.js] +[browser_aboutPrefs_fc_check_otherInstance.js] +skip-if = os != 'win' +reason = Windows only feature. +[browser_aboutPrefs_fc_check_unsupported.js] +[browser_aboutPrefs_settings.js] +[browser_aboutPrefs_bc_multiUpdate.js] + +# Doorhanger Application Update Tests +[browser_doorhanger_bc_check_cantApply.js] +skip-if = os != 'win' +reason = test must be able to prevent file deletion. +[browser_doorhanger_bc_check_malformedXML.js] +[browser_doorhanger_bc_check_unsupported.js] +[browser_doorhanger_bc_downloaded.js] +[browser_doorhanger_bc_downloaded_staged.js] +[browser_doorhanger_bc_downloadAutoFailures.js] +[browser_doorhanger_bc_downloadAutoFailures_bgWin.js] +[browser_doorhanger_bc_downloadOptIn.js] +[browser_doorhanger_bc_downloadOptIn_bgWin.js] +[browser_doorhanger_bc_downloadOptIn_staging.js] +[browser_doorhanger_bc_patch_completeBadSize.js] +[browser_doorhanger_bc_patch_partialBadSize.js] +[browser_doorhanger_bc_patch_partialBadSize_complete.js] +[browser_doorhanger_bc_patch_partialBadSize_completeBadSize.js] +[browser_doorhanger_sp_patch_completeApplyFailure.js] +[browser_doorhanger_sp_patch_partialApplyFailure.js] +[browser_doorhanger_sp_patch_partialApplyFailure_complete.js] +[browser_doorhanger_sp_patch_partialApplyFailure_complete_staging.js] +[browser_doorhanger_sp_patch_partialApplyFailure_completeBadSize.js] +[browser_doorhanger_bc_multiUpdate.js] +[browser_doorhanger_bc_multiUpdate_promptWaitTime.js] + +# Elevation Dialog Tests +[browser_elevationDialog.js] + +# Telemetry Update Ping Tests +[browser_telemetry_updatePing_downloaded_ready.js] +[browser_telemetry_updatePing_staged_ready.js] diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloaded.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloaded.js new file mode 100644 index 0000000000..0955750c93 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_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 when the About Dialog is opened. +add_task(async function aboutDialog_backgroundCheck_downloaded() { + let params = { backgroundUpdate: true, waitForUpdateState: STATE_PENDING }; + await runAboutDialogUpdateTest(params, [ + { + panelId: "apply", + checkActiveUpdate: { state: STATE_PENDING }, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloaded_staged.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloaded_staged.js new file mode 100644 index 0000000000..2d7bd64d05 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloaded_staged.js @@ -0,0 +1,28 @@ +/* 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 when the About Dialog is opened. +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 params = { + queryString: "&invalidCompleteSize=1", + backgroundUpdate: true, + continueFile: CONTINUE_STAGING, + waitForUpdateState: STATE_APPLIED, + }; + await runAboutDialogUpdateTest(params, [ + { + panelId: "apply", + checkActiveUpdate: { state: STATE_APPLIED }, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloaded_staging.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloaded_staging.js new file mode 100644 index 0000000000..b5dad7157f --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloaded_staging.js @@ -0,0 +1,56 @@ +/* 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 the About Dialog opened during staging. +add_task(async function aboutDialog_backgroundCheck_downloaded_staging() { + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_STAGING_ENABLED, true]], + }); + + let lankpackCall = mockLangpackInstall(); + + // Since the partial should be successful specify an invalid size for the + // complete update. + let params = { + queryString: "&invalidCompleteSize=1", + backgroundUpdate: true, + waitForUpdateState: STATE_PENDING, + }; + await runAboutDialogUpdateTest(params, [ + { + panelId: "applying", + checkActiveUpdate: { state: STATE_PENDING }, + continueFile: CONTINUE_STAGING, + }, + async aboutDialog => { + // Once the state is applied but langpacks aren't complete the about + // dialog should still be showing applying. + TestUtils.waitForCondition(() => { + return readStatusFile() == STATE_APPLIED; + }); + + let updateDeck = aboutDialog.document.getElementById("updateDeck"); + is( + updateDeck.selectedPanel.id, + "applying", + "UI should still show as applying." + ); + + let { appVersion, resolve } = await lankpackCall; + is( + appVersion, + Services.appinfo.version, + "Should see the right app version." + ); + resolve(); + }, + { + panelId: "apply", + checkActiveUpdate: { state: STATE_APPLIED }, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloaded_stagingFailure.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloaded_stagingFailure.js new file mode 100644 index 0000000000..de78cc7602 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloaded_stagingFailure.js @@ -0,0 +1,31 @@ +/* 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 staging has failed when the About Dialog is +// opened. +add_task( + async function aboutDialog_backgroundCheck_downloaded_stagingFailure() { + gEnv.set("MOZ_TEST_STAGING_ERROR", "1"); + 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 params = { + queryString: "&completePatchOnly=1", + backgroundUpdate: true, + waitForUpdateState: STATE_PENDING, + }; + await runAboutDialogUpdateTest(params, [ + { + panelId: "apply", + checkActiveUpdate: { state: STATE_PENDING }, + continueFile: null, + }, + ]); + } +); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloading.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloading.js new file mode 100644 index 0000000000..9ecf7a3582 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloading.js @@ -0,0 +1,77 @@ +/* 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 About Dialog opened during downloading. +add_task(async function aboutDialog_backgroundCheck_downloading() { + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_NOTIFYDURINGDOWNLOAD, false]], + }); + + let downloadInfo = []; + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) { + downloadInfo[0] = { patchType: "partial", bitsResult: "0" }; + } else { + downloadInfo[0] = { patchType: "partial", internalResult: "0" }; + } + + let lankpackCall = mockLangpackInstall(); + + // Since the partial should be successful specify an invalid size for the + // complete update. + let params = { + queryString: "&useSlowDownloadMar=1&invalidCompleteSize=1", + backgroundUpdate: true, + waitForUpdateState: STATE_DOWNLOADING, + }; + await runAboutDialogUpdateTest(params, [ + async function aboutDialog_downloading() { + is( + PanelUI.notificationPanel.state, + "closed", + "The window's doorhanger is closed." + ); + ok( + !PanelUI.menuButton.hasAttribute("badge-status"), + "The window does not have a badge." + ); + }, + { + panelId: "downloading", + checkActiveUpdate: { state: STATE_DOWNLOADING }, + continueFile: CONTINUE_DOWNLOAD, + downloadInfo, + }, + async aboutDialog => { + // Once the state is pending but langpacks aren't complete the about + // dialog should still be showing downloading. + TestUtils.waitForCondition(() => { + return readStatusFile() == STATE_PENDING; + }); + + let updateDeck = aboutDialog.document.getElementById("updateDeck"); + is( + updateDeck.selectedPanel.id, + "downloading", + "UI should still show as downloading." + ); + + let { appVersion, resolve } = await lankpackCall; + is( + appVersion, + Services.appinfo.version, + "Should see the right app version." + ); + resolve(); + }, + { + panelId: "apply", + checkActiveUpdate: { state: STATE_PENDING }, + continueFile: null, + }, + ]); + + await SpecialPowers.popPrefEnv(); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloading_notify.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloading_notify.js new file mode 100644 index 0000000000..cf067efe7d --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloading_notify.js @@ -0,0 +1,67 @@ +/* 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 +// "notify during download" feature turned on. +add_task(async function aboutDialog_backgroundCheck_downloading_notify() { + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_NOTIFYDURINGDOWNLOAD, true]], + }); + + let downloadInfo = []; + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) { + downloadInfo[0] = { patchType: "partial", bitsResult: "0" }; + } else { + downloadInfo[0] = { patchType: "partial", internalResult: "0" }; + } + + // Since the partial should be successful specify an invalid size for the + // complete update. + let params = { + queryString: "&useSlowDownloadMar=1&invalidCompleteSize=1", + backgroundUpdate: true, + waitForUpdateState: STATE_DOWNLOADING, + }; + await runAboutDialogUpdateTest(params, [ + async function aboutDialog_downloading_notification() { + await TestUtils.waitForCondition( + () => PanelUI.menuButton.hasAttribute("badge-status"), + "Waiting for update badge", + undefined, + 200 + ).catch(e => { + // Instead of throwing let the check below fail the test. + logTestInfo(e); + }); + is( + PanelUI.notificationPanel.state, + "closed", + "The window's doorhanger is closed." + ); + ok( + PanelUI.menuButton.hasAttribute("badge-status"), + "The window has a badge." + ); + is( + PanelUI.menuButton.getAttribute("badge-status"), + "update-downloading", + "The downloading badge is showing for the background window" + ); + }, + { + panelId: "downloading", + checkActiveUpdate: { state: STATE_DOWNLOADING }, + continueFile: CONTINUE_DOWNLOAD, + downloadInfo, + }, + { + panelId: "apply", + checkActiveUpdate: { state: STATE_PENDING }, + continueFile: null, + }, + ]); + + await SpecialPowers.popPrefEnv(); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloading_staging.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloading_staging.js new file mode 100644 index 0000000000..0fa7354bea --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloading_staging.js @@ -0,0 +1,69 @@ +/* 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 About Dialog opened during downloading and stages the update. +add_task(async function aboutDialog_backgroundCheck_downloading_staging() { + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_STAGING_ENABLED, true]], + }); + + let downloadInfo = []; + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) { + downloadInfo[0] = { patchType: "partial", bitsResult: "0" }; + } else { + downloadInfo[0] = { patchType: "partial", internalResult: "0" }; + } + + let lankpackCall = mockLangpackInstall(); + + // Since the partial should be successful specify an invalid size for the + // complete update. + let params = { + queryString: "&useSlowDownloadMar=1&invalidCompleteSize=1", + backgroundUpdate: true, + waitForUpdateState: STATE_DOWNLOADING, + }; + await runAboutDialogUpdateTest(params, [ + { + panelId: "downloading", + checkActiveUpdate: { state: STATE_DOWNLOADING }, + continueFile: CONTINUE_DOWNLOAD, + downloadInfo, + }, + { + panelId: "applying", + checkActiveUpdate: { state: STATE_PENDING }, + continueFile: CONTINUE_STAGING, + }, + async aboutDialog => { + // Once the state is applied but langpacks aren't complete the about + // dialog should still be showing applying. + TestUtils.waitForCondition(() => { + return readStatusFile() == STATE_APPLIED; + }); + + let updateDeck = aboutDialog.document.getElementById("updateDeck"); + is( + updateDeck.selectedPanel.id, + "applying", + "UI should still show as applying." + ); + + let { appVersion, resolve } = await lankpackCall; + is( + appVersion, + Services.appinfo.version, + "Should see the right app version." + ); + resolve(); + }, + { + panelId: "apply", + checkActiveUpdate: { state: STATE_APPLIED }, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_multiUpdate.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_multiUpdate.js new file mode 100644 index 0000000000..b6c893ea15 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_multiUpdate.js @@ -0,0 +1,52 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const FIRST_UPDATE_VERSION = "999998.0"; +const SECOND_UPDATE_VERSION = "999999.0"; + +function prepareToDownloadVersion(version) { + setUpdateURL( + URL_HTTP_UPDATE_SJS + + `?detailsURL=${gDetailsURL}&promptWaitTime=0&appVersion=${version}` + ); +} + +add_task(async function aboutDialog_backgroundCheck_multiUpdate() { + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_STAGING_ENABLED, true]], + }); + + let params = { + version: FIRST_UPDATE_VERSION, + backgroundUpdate: true, + waitForUpdateState: STATE_PENDING, + }; + await runAboutDialogUpdateTest(params, [ + { + panelId: "applying", + checkActiveUpdate: { state: STATE_PENDING }, + continueFile: CONTINUE_STAGING, + }, + { + panelId: "apply", + checkActiveUpdate: { state: STATE_APPLIED }, + continueFile: null, + }, + () => { + prepareToDownloadVersion(SECOND_UPDATE_VERSION); + gAUS.checkForBackgroundUpdates(); + }, + { + 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_aboutDialog_fc_check_cantApply.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_check_cantApply.js new file mode 100644 index 0000000000..cd659ef74b --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_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 params = {}; + await runAboutDialogUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "manualUpdate", + checkActiveUpdate: null, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_check_malformedXML.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_check_malformedXML.js new file mode 100644 index 0000000000..c5ad9df03f --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_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 params = { queryString: "&xmlMalformed=1" }; + await runAboutDialogUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "noUpdatesFound", + checkActiveUpdate: null, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_check_noUpdate.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_check_noUpdate.js new file mode 100644 index 0000000000..2bd23cddf0 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_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 params = { queryString: "&noUpdates=1" }; + await runAboutDialogUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "noUpdatesFound", + checkActiveUpdate: null, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_check_otherInstance.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_check_otherInstance.js new file mode 100644 index 0000000000..fa1110effd --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_check_otherInstance.js @@ -0,0 +1,19 @@ +/* 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 another application instance handling updates. +add_task(async function aboutDialog_foregroundCheck_otherInstance() { + setOtherInstanceHandlingUpdates(); + + let params = {}; + await runAboutDialogUpdateTest(params, [ + { + panelId: "otherInstanceHandlingUpdates", + checkActiveUpdate: null, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_check_unsupported.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_check_unsupported.js new file mode 100644 index 0000000000..22e3425967 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_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 params = { queryString: "&unsupported=1" }; + await runAboutDialogUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "unsupportedSystem", + checkActiveUpdate: null, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_downloadAuto.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_downloadAuto.js new file mode 100644 index 0000000000..a80c9deac8 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_downloadAuto.js @@ -0,0 +1,62 @@ +/* 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() { + let downloadInfo = []; + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) { + downloadInfo[0] = { patchType: "partial", bitsResult: "0" }; + } else { + downloadInfo[0] = { patchType: "partial", internalResult: "0" }; + } + + // Since the partial should be successful specify an invalid size for the + // complete update. + let params = { queryString: "&invalidCompleteSize=1&promptWaitTime=0" }; + await runAboutDialogUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloading", + checkActiveUpdate: { state: STATE_DOWNLOADING }, + continueFile: CONTINUE_DOWNLOAD, + downloadInfo, + }, + async function aboutDialog_restart_notification() { + await TestUtils.waitForCondition( + () => PanelUI.menuButton.hasAttribute("badge-status"), + "Waiting for update badge", + undefined, + 200 + ).catch(e => { + // Instead of throwing let the check below fail the test. + logTestInfo(e); + }); + is( + PanelUI.notificationPanel.state, + "closed", + "The window's doorhanger is closed." + ); + ok( + PanelUI.menuButton.hasAttribute("badge-status"), + "The window has a badge." + ); + is( + PanelUI.menuButton.getAttribute("badge-status"), + "update-restart", + "The restart badge is showing for the background window" + ); + }, + { + panelId: "apply", + checkActiveUpdate: { state: STATE_PENDING }, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_downloadAuto_staging.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_downloadAuto_staging.js new file mode 100644 index 0000000000..e212b0c611 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_downloadAuto_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 an automatic download and update staging. +add_task(async function aboutDialog_foregroundCheck_downloadAuto_staging() { + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_STAGING_ENABLED, true]], + }); + + let downloadInfo = []; + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) { + downloadInfo[0] = { patchType: "partial", bitsResult: "0" }; + } else { + downloadInfo[0] = { patchType: "partial", internalResult: "0" }; + } + + // Since the partial should be successful specify an invalid size for the + // complete update. + let params = { queryString: "&invalidCompleteSize=1" }; + await runAboutDialogUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloading", + checkActiveUpdate: { state: STATE_DOWNLOADING }, + continueFile: CONTINUE_DOWNLOAD, + downloadInfo, + }, + { + 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_aboutDialog_fc_downloadOptIn.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_downloadOptIn.js new file mode 100644 index 0000000000..5a2ff513ad --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_downloadOptIn.js @@ -0,0 +1,44 @@ +/* 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); + + let downloadInfo = []; + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) { + downloadInfo[0] = { patchType: "partial", bitsResult: "0" }; + } else { + downloadInfo[0] = { patchType: "partial", internalResult: "0" }; + } + + // Since the partial should be successful specify an invalid size for the + // complete update. + let params = { queryString: "&invalidCompleteSize=1" }; + await runAboutDialogUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloadAndInstall", + checkActiveUpdate: null, + continueFile: null, + }, + { + panelId: "downloading", + checkActiveUpdate: { state: STATE_DOWNLOADING }, + continueFile: CONTINUE_DOWNLOAD, + downloadInfo, + }, + { + panelId: "apply", + checkActiveUpdate: { state: STATE_PENDING }, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_downloadOptIn_staging.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_downloadOptIn_staging.js new file mode 100644 index 0000000000..3ed331ec64 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_downloadOptIn_staging.js @@ -0,0 +1,52 @@ +/* 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); + + let downloadInfo = []; + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) { + downloadInfo[0] = { patchType: "partial", bitsResult: "0" }; + } else { + downloadInfo[0] = { patchType: "partial", internalResult: "0" }; + } + + // Since the partial should be successful specify an invalid size for the + // complete update. + let params = { queryString: "&invalidCompleteSize=1" }; + await runAboutDialogUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloadAndInstall", + checkActiveUpdate: null, + continueFile: null, + }, + { + panelId: "downloading", + checkActiveUpdate: { state: STATE_DOWNLOADING }, + continueFile: CONTINUE_DOWNLOAD, + downloadInfo, + }, + { + 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_aboutDialog_fc_patch_completeBadSize.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_patch_completeBadSize.js new file mode 100644 index 0000000000..fdc7d3407e --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_patch_completeBadSize.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 complete bad size patch. +add_task(async function aboutDialog_foregroundCheck_completeBadSize() { + let downloadInfo = []; + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) { + downloadInfo[0] = { patchType: "complete", bitsResult: gBadSizeResult }; + downloadInfo[1] = { patchType: "complete", internalResult: gBadSizeResult }; + } else { + downloadInfo[0] = { patchType: "complete", internalResult: gBadSizeResult }; + } + + let params = { queryString: "&completePatchOnly=1&invalidCompleteSize=1" }; + await runAboutDialogUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloading", + checkActiveUpdate: { state: STATE_DOWNLOADING }, + continueFile: CONTINUE_DOWNLOAD, + downloadInfo, + }, + { + panelId: "downloadFailed", + checkActiveUpdate: null, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_patch_partialBadSize.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_patch_partialBadSize.js new file mode 100644 index 0000000000..411fb25969 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_patch_partialBadSize.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 partial bad size patch. +add_task(async function aboutDialog_foregroundCheck_partialBadSize() { + let downloadInfo = []; + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) { + downloadInfo[0] = { patchType: "partial", bitsResult: gBadSizeResult }; + downloadInfo[1] = { patchType: "partial", internalResult: gBadSizeResult }; + } else { + downloadInfo[0] = { patchType: "partial", internalResult: gBadSizeResult }; + } + + let params = { queryString: "&partialPatchOnly=1&invalidPartialSize=1" }; + await runAboutDialogUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloading", + checkActiveUpdate: { state: STATE_DOWNLOADING }, + continueFile: CONTINUE_DOWNLOAD, + downloadInfo, + }, + { + panelId: "downloadFailed", + checkActiveUpdate: null, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_patch_partialBadSize_complete.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_patch_partialBadSize_complete.js new file mode 100644 index 0000000000..396be1e930 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_patch_partialBadSize_complete.js @@ -0,0 +1,38 @@ +/* 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 downloadInfo = []; + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) { + downloadInfo[0] = { patchType: "partial", bitsResult: gBadSizeResult }; + downloadInfo[1] = { patchType: "partial", internalResult: gBadSizeResult }; + downloadInfo[2] = { patchType: "complete", bitsResult: "0" }; + } else { + downloadInfo[0] = { patchType: "partial", internalResult: gBadSizeResult }; + downloadInfo[1] = { patchType: "complete", internalResult: "0" }; + } + + let params = { queryString: "&invalidPartialSize=1" }; + await runAboutDialogUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloading", + checkActiveUpdate: { state: STATE_DOWNLOADING }, + continueFile: CONTINUE_DOWNLOAD, + downloadInfo, + }, + { + panelId: "apply", + checkActiveUpdate: { state: STATE_PENDING }, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_patch_partialBadSize_completeBadSize.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_patch_partialBadSize_completeBadSize.js new file mode 100644 index 0000000000..fb10250a49 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_patch_partialBadSize_completeBadSize.js @@ -0,0 +1,53 @@ +/* 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 downloadInfo = []; + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) { + downloadInfo[0] = { patchType: "partial", bitsResult: gBadSizeResult }; + downloadInfo[1] = { + patchType: "partial", + internalResult: gBadSizeResult, + }; + downloadInfo[2] = { patchType: "complete", bitsResult: gBadSizeResult }; + downloadInfo[3] = { + patchType: "complete", + internalResult: gBadSizeResult, + }; + } else { + downloadInfo[0] = { + patchType: "partial", + internalResult: gBadSizeResult, + }; + downloadInfo[1] = { + patchType: "complete", + internalResult: gBadSizeResult, + }; + } + + let params = { queryString: "&invalidPartialSize=1&invalidCompleteSize=1" }; + await runAboutDialogUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloading", + checkActiveUpdate: { state: STATE_DOWNLOADING }, + continueFile: CONTINUE_DOWNLOAD, + downloadInfo, + }, + { + panelId: "downloadFailed", + checkActiveUpdate: null, + continueFile: null, + }, + ]); + } +); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_bc_downloaded.js b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_bc_downloaded.js new file mode 100644 index 0000000000..6df4ee7ff5 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_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:preferences background check for updates +// with the update downloaded when about:preferences is opened. +add_task(async function aboutPrefs_backgroundCheck_downloaded() { + let params = { backgroundUpdate: true, waitForUpdateState: STATE_PENDING }; + await runAboutPrefsUpdateTest(params, [ + { + panelId: "apply", + checkActiveUpdate: { state: STATE_PENDING }, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_bc_downloaded_staged.js b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_bc_downloaded_staged.js new file mode 100644 index 0000000000..749a8f0b07 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_bc_downloaded_staged.js @@ -0,0 +1,28 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for about:preferences background check for updates +// with the update downloaded and staged when about:preferences is opened. +add_task(async function aboutPrefs_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 params = { + queryString: "&invalidCompleteSize=1", + backgroundUpdate: true, + continueFile: CONTINUE_STAGING, + waitForUpdateState: STATE_APPLIED, + }; + await runAboutPrefsUpdateTest(params, [ + { + panelId: "apply", + checkActiveUpdate: { state: STATE_APPLIED }, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_bc_downloaded_staging.js b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_bc_downloaded_staging.js new file mode 100644 index 0000000000..2d607031f9 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_bc_downloaded_staging.js @@ -0,0 +1,59 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for about:preferences background check for updates +// with the update downloaded and about:preferences opened during staging. +add_task(async function aboutPrefs_backgroundCheck_downloaded_staged() { + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_STAGING_ENABLED, true]], + }); + + let lankpackCall = mockLangpackInstall(); + + // Since the partial should be successful specify an invalid size for the + // complete update. + let params = { + queryString: "&invalidCompleteSize=1", + backgroundUpdate: true, + waitForUpdateState: STATE_PENDING, + }; + await runAboutPrefsUpdateTest(params, [ + { + panelId: "applying", + checkActiveUpdate: { state: STATE_PENDING }, + continueFile: CONTINUE_STAGING, + }, + async tab => { + // Once the state is pending but langpacks aren't complete the about + // dialog should still be showing downloading. + TestUtils.waitForCondition(() => { + return readStatusFile() == STATE_APPLIED; + }); + + let updateDeckId = await SpecialPowers.spawn( + tab.linkedBrowser, + [], + () => { + return content.document.getElementById("updateDeck").selectedPanel.id; + } + ); + + is(updateDeckId, "applying", "UI should still show as applying."); + + let { appVersion, resolve } = await lankpackCall; + is( + appVersion, + Services.appinfo.version, + "Should see the right app version." + ); + resolve(); + }, + { + panelId: "apply", + checkActiveUpdate: { state: STATE_APPLIED }, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_bc_downloaded_stagingFailure.js b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_bc_downloaded_stagingFailure.js new file mode 100644 index 0000000000..3d3d56b2d7 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_bc_downloaded_stagingFailure.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:preferences background check for updates +// with the update downloaded and staging has failed when the about:preferences +// is opened. +add_task(async function aboutPrefs_backgroundCheck_downloaded_stagingFailure() { + gEnv.set("MOZ_TEST_STAGING_ERROR", "1"); + 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 params = { + queryString: "&completePatchOnly=1", + backgroundUpdate: true, + waitForUpdateState: STATE_PENDING, + }; + await runAboutDialogUpdateTest(params, [ + { + panelId: "apply", + checkActiveUpdate: { state: STATE_PENDING }, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_bc_downloading.js b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_bc_downloading.js new file mode 100644 index 0000000000..716652c6f6 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_bc_downloading.js @@ -0,0 +1,63 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for about:preferences background check for updates +// with about:preferences opened during downloading. +add_task(async function aboutPrefs_backgroundCheck_downloading() { + let downloadInfo = []; + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) { + downloadInfo[0] = { patchType: "partial", bitsResult: "0" }; + } else { + downloadInfo[0] = { patchType: "partial", internalResult: "0" }; + } + + let lankpackCall = mockLangpackInstall(); + + // Since the partial should be successful specify an invalid size for the + // complete update. + let params = { + queryString: "&useSlowDownloadMar=1&invalidCompleteSize=1", + backgroundUpdate: true, + waitForUpdateState: STATE_DOWNLOADING, + }; + await runAboutPrefsUpdateTest(params, [ + { + panelId: "downloading", + checkActiveUpdate: { state: STATE_DOWNLOADING }, + continueFile: CONTINUE_DOWNLOAD, + downloadInfo, + }, + async tab => { + // Once the state is pending but langpacks aren't complete the about + // dialog should still be showing downloading. + TestUtils.waitForCondition(() => { + return readStatusFile() == STATE_PENDING; + }); + + let updateDeckId = await SpecialPowers.spawn( + tab.linkedBrowser, + [], + () => { + return content.document.getElementById("updateDeck").selectedPanel.id; + } + ); + + is(updateDeckId, "downloading", "UI should still show as downloading."); + + let { appVersion, resolve } = await lankpackCall; + is( + appVersion, + Services.appinfo.version, + "Should see the right app version." + ); + resolve(); + }, + { + panelId: "apply", + checkActiveUpdate: { state: STATE_PENDING }, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_bc_downloading_staging.js b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_bc_downloading_staging.js new file mode 100644 index 0000000000..ea325d5c34 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_bc_downloading_staging.js @@ -0,0 +1,72 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for about:preferences background check for updates +// with about:preferences opened during downloading and stages the update. +add_task(async function aboutPrefs_backgroundCheck_downloading_staging() { + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_STAGING_ENABLED, true]], + }); + + let downloadInfo = []; + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) { + downloadInfo[0] = { patchType: "partial", bitsResult: "0" }; + } else { + downloadInfo[0] = { patchType: "partial", internalResult: "0" }; + } + + let lankpackCall = mockLangpackInstall(); + + // Since the partial should be successful specify an invalid size for the + // complete update. + let params = { + queryString: "&useSlowDownloadMar=1&invalidCompleteSize=1", + backgroundUpdate: true, + waitForUpdateState: STATE_DOWNLOADING, + }; + await runAboutPrefsUpdateTest(params, [ + { + panelId: "downloading", + checkActiveUpdate: { state: STATE_DOWNLOADING }, + continueFile: CONTINUE_DOWNLOAD, + downloadInfo, + }, + { + panelId: "applying", + checkActiveUpdate: { state: STATE_PENDING }, + continueFile: CONTINUE_STAGING, + }, + async tab => { + // Once the state is pending but langpacks aren't complete the about + // dialog should still be showing downloading. + TestUtils.waitForCondition(() => { + return readStatusFile() == STATE_APPLIED; + }); + + let updateDeckId = await SpecialPowers.spawn( + tab.linkedBrowser, + [], + () => { + return content.document.getElementById("updateDeck").selectedPanel.id; + } + ); + + is(updateDeckId, "applying", "UI should still show as applying."); + + let { appVersion, resolve } = await lankpackCall; + is( + appVersion, + Services.appinfo.version, + "Should see the right app version." + ); + resolve(); + }, + { + panelId: "apply", + checkActiveUpdate: { state: STATE_APPLIED }, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_bc_multiUpdate.js b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_bc_multiUpdate.js new file mode 100644 index 0000000000..9ccf593db5 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_bc_multiUpdate.js @@ -0,0 +1,52 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const FIRST_UPDATE_VERSION = "999998.0"; +const SECOND_UPDATE_VERSION = "999999.0"; + +function prepareToDownloadVersion(version) { + setUpdateURL( + URL_HTTP_UPDATE_SJS + + `?detailsURL=${gDetailsURL}&promptWaitTime=0&appVersion=${version}` + ); +} + +add_task(async function aboutPrefs_backgroundCheck_multiUpdate() { + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_STAGING_ENABLED, true]], + }); + + let params = { + version: FIRST_UPDATE_VERSION, + backgroundUpdate: true, + waitForUpdateState: STATE_PENDING, + }; + await runAboutPrefsUpdateTest(params, [ + { + panelId: "applying", + checkActiveUpdate: { state: STATE_PENDING }, + continueFile: CONTINUE_STAGING, + }, + { + panelId: "apply", + checkActiveUpdate: { state: STATE_APPLIED }, + continueFile: null, + }, + () => { + prepareToDownloadVersion(SECOND_UPDATE_VERSION); + gAUS.checkForBackgroundUpdates(); + }, + { + 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_aboutPrefs_fc_check_cantApply.js b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_check_cantApply.js new file mode 100644 index 0000000000..aac9b33134 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_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:preferences foreground check for updates +// without the ability to apply updates. +add_task(async function aboutPrefs_foregroundCheck_cantApply() { + lockWriteTestFile(); + + let params = {}; + await runAboutPrefsUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "manualUpdate", + checkActiveUpdate: null, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_check_malformedXML.js b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_check_malformedXML.js new file mode 100644 index 0000000000..f59f6d48b3 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_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:preferences foreground check for updates +// with a malformed update XML file. +add_task(async function aboutPrefs_foregroundCheck_malformedXML() { + let params = { queryString: "&xmlMalformed=1" }; + await runAboutPrefsUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "noUpdatesFound", + checkActiveUpdate: null, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_check_noUpdate.js b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_check_noUpdate.js new file mode 100644 index 0000000000..a8f6c072f7 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_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:preferences foreground check for updates +// with no update available. +add_task(async function aboutPrefs_foregroundCheck_noUpdate() { + let params = { queryString: "&noUpdates=1" }; + await runAboutPrefsUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "noUpdatesFound", + checkActiveUpdate: null, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_check_otherInstance.js b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_check_otherInstance.js new file mode 100644 index 0000000000..271c8f2837 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_check_otherInstance.js @@ -0,0 +1,19 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for about:preferences foreground check for updates +// with another application instance handling updates. +add_task(async function aboutPrefs_foregroundCheck_otherInstance() { + setOtherInstanceHandlingUpdates(); + + let params = {}; + await runAboutPrefsUpdateTest(params, [ + { + panelId: "otherInstanceHandlingUpdates", + checkActiveUpdate: null, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_check_unsupported.js b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_check_unsupported.js new file mode 100644 index 0000000000..e18ce31bc4 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_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:preferences foreground check for updates +// with an unsupported update. +add_task(async function aboutPrefs_foregroundCheck_unsupported() { + let params = { queryString: "&unsupported=1" }; + await runAboutPrefsUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "unsupportedSystem", + checkActiveUpdate: null, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_downloadAuto.js b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_downloadAuto.js new file mode 100644 index 0000000000..bd5fd18289 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_downloadAuto.js @@ -0,0 +1,37 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for about:preferences foreground check for updates +// with an automatic download. +add_task(async function aboutPrefs_foregroundCheck_downloadAuto() { + let downloadInfo = []; + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) { + downloadInfo[0] = { patchType: "partial", bitsResult: "0" }; + } else { + downloadInfo[0] = { patchType: "partial", internalResult: "0" }; + } + + // Since the partial should be successful specify an invalid size for the + // complete update. + let params = { queryString: "&invalidCompleteSize=1" }; + await runAboutPrefsUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloading", + checkActiveUpdate: { state: STATE_DOWNLOADING }, + continueFile: CONTINUE_DOWNLOAD, + downloadInfo, + }, + { + panelId: "apply", + checkActiveUpdate: { state: STATE_PENDING }, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_downloadAuto_staging.js b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_downloadAuto_staging.js new file mode 100644 index 0000000000..1d9d082edd --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_downloadAuto_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:preferences foreground check for updates +// with an automatic download and update staging. +add_task(async function aboutPrefs_foregroundCheck_downloadAuto_staging() { + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_STAGING_ENABLED, true]], + }); + + let downloadInfo = []; + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) { + downloadInfo[0] = { patchType: "partial", bitsResult: "0" }; + } else { + downloadInfo[0] = { patchType: "partial", internalResult: "0" }; + } + + // Since the partial should be successful specify an invalid size for the + // complete update. + let params = { queryString: "&invalidCompleteSize=1" }; + await runAboutPrefsUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloading", + checkActiveUpdate: { state: STATE_DOWNLOADING }, + continueFile: CONTINUE_DOWNLOAD, + downloadInfo, + }, + { + 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_aboutPrefs_fc_downloadOptIn.js b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_downloadOptIn.js new file mode 100644 index 0000000000..115e875b74 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_downloadOptIn.js @@ -0,0 +1,44 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for about:preferences foreground check for updates +// with a manual download. +add_task(async function aboutPrefs_foregroundCheck_downloadOptIn() { + await UpdateUtils.setAppUpdateAutoEnabled(false); + + let downloadInfo = []; + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) { + downloadInfo[0] = { patchType: "partial", bitsResult: "0" }; + } else { + downloadInfo[0] = { patchType: "partial", internalResult: "0" }; + } + + // Since the partial should be successful specify an invalid size for the + // complete update. + let params = { queryString: "&invalidCompleteSize=1" }; + await runAboutPrefsUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloadAndInstall", + checkActiveUpdate: null, + continueFile: null, + }, + { + panelId: "downloading", + checkActiveUpdate: { state: STATE_DOWNLOADING }, + continueFile: CONTINUE_DOWNLOAD, + downloadInfo, + }, + { + panelId: "apply", + checkActiveUpdate: { state: STATE_PENDING }, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_downloadOptIn_staging.js b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_downloadOptIn_staging.js new file mode 100644 index 0000000000..cff5d74701 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_downloadOptIn_staging.js @@ -0,0 +1,52 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for about:preferences foreground check for updates +// with a manual download and update staging. +add_task(async function aboutPrefs_foregroundCheck_downloadOptIn_staging() { + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_STAGING_ENABLED, true]], + }); + await UpdateUtils.setAppUpdateAutoEnabled(false); + + let downloadInfo = []; + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) { + downloadInfo[0] = { patchType: "partial", bitsResult: "0" }; + } else { + downloadInfo[0] = { patchType: "partial", internalResult: "0" }; + } + + // Since the partial should be successful specify an invalid size for the + // complete update. + let params = { queryString: "&invalidCompleteSize=1" }; + await runAboutPrefsUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloadAndInstall", + checkActiveUpdate: null, + continueFile: null, + }, + { + panelId: "downloading", + checkActiveUpdate: { state: STATE_DOWNLOADING }, + continueFile: CONTINUE_DOWNLOAD, + downloadInfo, + }, + { + 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_aboutPrefs_fc_patch_completeBadSize.js b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_patch_completeBadSize.js new file mode 100644 index 0000000000..a36d3d9807 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_patch_completeBadSize.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:preferences foreground check for updates +// with a complete bad size patch. +add_task(async function aboutPrefs_foregroundCheck_completeBadSize() { + let downloadInfo = []; + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) { + downloadInfo[0] = { patchType: "complete", bitsResult: gBadSizeResult }; + downloadInfo[1] = { patchType: "complete", internalResult: gBadSizeResult }; + } else { + downloadInfo[0] = { patchType: "complete", internalResult: gBadSizeResult }; + } + + let params = { queryString: "&completePatchOnly=1&invalidCompleteSize=1" }; + await runAboutPrefsUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloading", + checkActiveUpdate: { state: STATE_DOWNLOADING }, + continueFile: CONTINUE_DOWNLOAD, + downloadInfo, + }, + { + panelId: "downloadFailed", + checkActiveUpdate: null, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_patch_partialBadSize.js b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_patch_partialBadSize.js new file mode 100644 index 0000000000..060acd405a --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_patch_partialBadSize.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:preferences foreground check for updates +// with a partial bad size patch. +add_task(async function aboutPrefs_foregroundCheck_partialBadSize() { + let downloadInfo = []; + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) { + downloadInfo[0] = { patchType: "partial", bitsResult: gBadSizeResult }; + downloadInfo[1] = { patchType: "partial", internalResult: gBadSizeResult }; + } else { + downloadInfo[0] = { patchType: "partial", internalResult: gBadSizeResult }; + } + + let params = { queryString: "&partialPatchOnly=1&invalidPartialSize=1" }; + await runAboutPrefsUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloading", + checkActiveUpdate: { state: STATE_DOWNLOADING }, + continueFile: CONTINUE_DOWNLOAD, + downloadInfo, + }, + { + panelId: "downloadFailed", + checkActiveUpdate: null, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_patch_partialBadSize_complete.js b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_patch_partialBadSize_complete.js new file mode 100644 index 0000000000..c6e5b5b20b --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_patch_partialBadSize_complete.js @@ -0,0 +1,38 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for about:preferences foreground check for updates +// with a partial bad size patch and a complete patch. +add_task(async function aboutPrefs_foregroundCheck_partialBadSize_complete() { + let downloadInfo = []; + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) { + downloadInfo[0] = { patchType: "partial", bitsResult: gBadSizeResult }; + downloadInfo[1] = { patchType: "partial", internalResult: gBadSizeResult }; + downloadInfo[2] = { patchType: "complete", bitsResult: "0" }; + } else { + downloadInfo[0] = { patchType: "partial", internalResult: gBadSizeResult }; + downloadInfo[1] = { patchType: "complete", internalResult: "0" }; + } + + let params = { queryString: "&invalidPartialSize=1" }; + await runAboutPrefsUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloading", + checkActiveUpdate: { state: STATE_DOWNLOADING }, + continueFile: CONTINUE_DOWNLOAD, + downloadInfo, + }, + { + panelId: "apply", + checkActiveUpdate: { state: STATE_PENDING }, + continueFile: null, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_patch_partialBadSize_completeBadSize.js b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_patch_partialBadSize_completeBadSize.js new file mode 100644 index 0000000000..62abdc3af5 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_fc_patch_partialBadSize_completeBadSize.js @@ -0,0 +1,53 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for about:preferences foreground check for updates +// with a partial bad size patch and a complete bad size patch. +add_task( + async function aboutPrefs_foregroundCheck_partialBadSize_completeBadSize() { + let downloadInfo = []; + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) { + downloadInfo[0] = { patchType: "partial", bitsResult: gBadSizeResult }; + downloadInfo[1] = { + patchType: "partial", + internalResult: gBadSizeResult, + }; + downloadInfo[2] = { patchType: "complete", bitsResult: gBadSizeResult }; + downloadInfo[3] = { + patchType: "complete", + internalResult: gBadSizeResult, + }; + } else { + downloadInfo[0] = { + patchType: "partial", + internalResult: gBadSizeResult, + }; + downloadInfo[1] = { + patchType: "complete", + internalResult: gBadSizeResult, + }; + } + + let params = { queryString: "&invalidPartialSize=1&invalidCompleteSize=1" }; + await runAboutPrefsUpdateTest(params, [ + { + panelId: "checkingForUpdates", + checkActiveUpdate: null, + continueFile: CONTINUE_CHECK, + }, + { + panelId: "downloading", + checkActiveUpdate: { state: STATE_DOWNLOADING }, + continueFile: CONTINUE_DOWNLOAD, + downloadInfo, + }, + { + panelId: "downloadFailed", + checkActiveUpdate: null, + continueFile: null, + }, + ]); + } +); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_settings.js b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_settings.js new file mode 100644 index 0000000000..8e40e2bbcf --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutPrefs_settings.js @@ -0,0 +1,137 @@ +/* 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/. + */ + +ChromeUtils.import("resource://gre/modules/osfile.jsm", this); + +// Changes, then verifies the value of app.update.auto via the about:preferences +// UI. Requires a tab with about:preferences open to be passed in. +async function changeAndVerifyPref(tab, newConfigValue) { + await SpecialPowers.spawn( + tab.linkedBrowser, + [{ newConfigValue }], + async function({ newConfigValue }) { + let radioId = newConfigValue ? "autoDesktop" : "manualDesktop"; + let radioElement = content.document.getElementById(radioId); + radioElement.click(); + } + ); + + // On Windows, we really need to wait for the change to finish being + // written to the disk before we go to verify anything. Unfortunately, it + // would be difficult to check for quick changes to the attributes of the + // about:preferences controls (to wait for the controls to be disabled and + // re-enabled). So instead, just start the verification by asking the + // Application Update Service for the value of app.update.auto. It already + // serializes reads and writes to the app update config file, so this will not + // resolve until the file write is complete. + let configValueRead = await UpdateUtils.getAppUpdateAutoEnabled(); + is( + configValueRead, + newConfigValue, + "Value returned should have matched the expected value" + ); + + // Only Windows currently has the update configuration JSON file. + if (AppConstants.platform == "win") { + let configFile = getUpdateDirFile(FILE_UPDATE_CONFIG_JSON); + let decoder = new TextDecoder(); + let fileContents = await OS.File.read(configFile.path); + let saveObject = JSON.parse(decoder.decode(fileContents)); + is( + saveObject["app.update.auto"], + newConfigValue, + "Value in file should match expected" + ); + } + + await SpecialPowers.spawn( + tab.linkedBrowser, + [{ newConfigValue }], + async function({ newConfigValue }) { + let updateRadioGroup = content.document.getElementById( + "updateRadioGroup" + ); + is( + updateRadioGroup.value, + `${newConfigValue}`, + "Update preference should match expected" + ); + } + ); +} + +add_task(async function testUpdateAutoPrefUI() { + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:preferences" + ); + + await changeAndVerifyPref(tab, true); + ok( + !gUpdateManager.downloadingUpdate, + "There should not be a downloading update" + ); + ok(!gUpdateManager.readyUpdate, "There should not be a ready update"); + + await changeAndVerifyPref(tab, false); + ok( + !gUpdateManager.downloadingUpdate, + "There should not be a downloading update" + ); + ok(!gUpdateManager.readyUpdate, "There should not be a ready update"); + + let patchProps = { state: STATE_PENDING }; + let patches = getLocalPatchString(patchProps); + let updateProps = { checkInterval: "1" }; + let updates = getLocalUpdateString(updateProps, patches); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + writeStatusFile(STATE_PENDING); + reloadUpdateManagerData(); + ok(!!gUpdateManager.readyUpdate, "There should be a ready update"); + + // A value of 0 will keep the update and a value of 1 will discard the update + // when the prompt service is called when the value of app.update.auto is + // changed to false. + let discardUpdate = 0; + let { prompt } = Services; + let promptService = { + QueryInterface: ChromeUtils.generateQI(["nsIPromptService"]), + confirmEx(...args) { + promptService._confirmExArgs = args; + return discardUpdate; + }, + }; + Services.prompt = promptService; + registerCleanupFunction(() => { + Services.prompt = prompt; + }); + + // Setting the value to false will call the prompt service and with 1 for + // discardUpdate the update won't be discarded so there should still be an + // active update. + discardUpdate = 1; + await changeAndVerifyPref(tab, false); + ok(!!gUpdateManager.readyUpdate, "There should be a ready update"); + + // Setting the value to true should not call the prompt service so there + // should still be an active update even with a value of 0 for + // discardUpdate. + discardUpdate = 0; + await changeAndVerifyPref(tab, true); + ok(!!gUpdateManager.readyUpdate, "There should be a ready update"); + + // Setting the value to false will call the prompt service and with 0 for + // discardUpdate the update should be discarded so there should not be an + // active update. + discardUpdate = 0; + await changeAndVerifyPref(tab, false); + ok( + !gUpdateManager.downloadingUpdate, + "There should not be a downloading update" + ); + ok(!gUpdateManager.readyUpdate, "There should not be a ready update"); + + await BrowserTestUtils.removeTab(tab); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_check_cantApply.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_check_cantApply.js new file mode 100644 index 0000000000..90f4c385cc --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_check_cantApply.js @@ -0,0 +1,18 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function doorhanger_bc_check_cantApply() { + lockWriteTestFile(); + + let params = { checkAttempts: 1, queryString: "&promptWaitTime=0" }; + await runDoorhangerUpdateTest(params, [ + { + notificationId: "update-manual", + button: "button", + checkActiveUpdate: null, + pageURLs: { whatsNew: gDetailsURL, manual: URL_MANUAL_UPDATE }, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_check_malformedXML.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_check_malformedXML.js new file mode 100644 index 0000000000..d83bc70b6f --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_check_malformedXML.js @@ -0,0 +1,26 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function doorhanger_bc_check_malformedXML() { + const maxBackgroundErrors = 10; + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_BACKGROUNDMAXERRORS, maxBackgroundErrors]], + }); + + let params = { + checkAttempts: maxBackgroundErrors, + queryString: "&xmlMalformed=1", + }; + await runDoorhangerUpdateTest(params, [ + { + // If the update check fails 10 consecutive attempts then the manual + // update doorhanger. + notificationId: "update-manual", + button: "button", + checkActiveUpdate: null, + pageURLs: { whatsNew: gDetailsURL, manual: URL_MANUAL_UPDATE }, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_check_unsupported.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_check_unsupported.js new file mode 100644 index 0000000000..17471a0160 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_check_unsupported.js @@ -0,0 +1,94 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for doorhanger background check for updates +// with an unsupported update. +add_task(async function doorhanger_bc_check_unsupported() { + let params = { checkAttempts: 1, queryString: "&unsupported=1" }; + await runDoorhangerUpdateTest(params, [ + { + notificationId: "update-unsupported", + button: "button", + pageURLs: { manual: gDetailsURL }, + }, + async function doorhanger_unsupported_persist() { + await TestUtils.waitForCondition( + () => PanelUI.menuButton.hasAttribute("badge-status"), + "Waiting for update badge", + undefined, + 200 + ).catch(e => { + // Instead of throwing let the check below fail the test. + logTestInfo(e); + }); + is( + PanelUI.notificationPanel.state, + "closed", + "The window's doorhanger is closed." + ); + ok( + PanelUI.menuButton.hasAttribute("badge-status"), + "The window has a badge." + ); + is( + PanelUI.menuButton.getAttribute("badge-status"), + "update-unsupported", + "The correct badge is showing for the background window" + ); + + // Test persistence of the badge when the client has restarted by + // resetting the UpdateListener. + UpdateListener.reset(); + is( + PanelUI.notificationPanel.state, + "closed", + "The window's doorhanger is closed." + ); + ok( + !PanelUI.menuButton.hasAttribute("badge-status"), + "The window does not have a badge." + ); + UpdateListener.init(); + is( + PanelUI.notificationPanel.state, + "closed", + "The window's doorhanger is closed." + ); + ok( + PanelUI.menuButton.hasAttribute("badge-status"), + "The window has a badge." + ); + is( + PanelUI.menuButton.getAttribute("badge-status"), + "update-unsupported", + "The correct badge is showing for the background window." + ); + }, + ]); + + params = { + checkAttempts: 1, + queryString: "&invalidCompleteSize=1&promptWaitTime=0", + }; + await runDoorhangerUpdateTest(params, [ + { + notificationId: "update-restart", + button: "secondaryButton", + checkActiveUpdate: { state: STATE_PENDING }, + }, + async function doorhanger_unsupported_removed() { + // Test that finding an update removes the app.update.unsupported.url + // preference. + let unsupportedURL = Services.prefs.getCharPref( + PREF_APP_UPDATE_UNSUPPORTED_URL, + null + ); + ok( + !unsupportedURL, + "The " + PREF_APP_UPDATE_UNSUPPORTED_URL + " preference was removed." + ); + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadAutoFailures.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadAutoFailures.js new file mode 100644 index 0000000000..23b2569ad9 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadAutoFailures.js @@ -0,0 +1,37 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function doorhanger_bc_downloadAutoFailures() { + const maxBackgroundErrors = 5; + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_BACKGROUNDMAXERRORS, maxBackgroundErrors]], + }); + + let params = { checkAttempts: 1, queryString: "&badURL=1" }; + await runDoorhangerUpdateTest(params, [ + { + // If the update download fails maxBackgroundErrors download attempts then + // show the update available prompt. + notificationId: "update-available", + button: "button", + checkActiveUpdate: null, + pageURLs: { whatsNew: gDefaultWhatsNewURL }, + }, + { + notificationId: "update-available", + button: "button", + checkActiveUpdate: null, + pageURLs: { whatsNew: gDefaultWhatsNewURL }, + }, + { + // If the update process is unable to install the update show the manual + // update doorhanger. + notificationId: "update-manual", + button: "button", + checkActiveUpdate: null, + pageURLs: { whatsNew: gDefaultWhatsNewURL, manual: URL_MANUAL_UPDATE }, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadAutoFailures_bgWin.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadAutoFailures_bgWin.js new file mode 100644 index 0000000000..d8cec82ae5 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadAutoFailures_bgWin.js @@ -0,0 +1,85 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function doorhanger_bc_downloadAutoFailures_bgWin() { + function getBackgroundWindowHandler(destroyWindow) { + return async function() { + await TestUtils.waitForCondition( + () => PanelUI.menuButton.hasAttribute("badge-status"), + "Background window has a badge.", + undefined, + 200 + ).catch(e => { + // Instead of throwing let the check below fail the test. + logTestInfo(e); + }); + ok( + PanelUI.menuButton.hasAttribute("badge-status"), + "PanelUI.menuButton should have a 'badge-status' attribute" + ); + is( + PanelUI.notificationPanel.state, + "closed", + "The doorhanger is not showing for the background window" + ); + is( + PanelUI.menuButton.getAttribute("badge-status"), + "update-available", + "The badge is showing for the background window" + ); + + checkWhatsNewLink( + extraWindow, + "update-available-whats-new", + gDefaultWhatsNewURL + ); + let buttonEl = getNotificationButton( + extraWindow, + "update-available", + "button" + ); + buttonEl.click(); + + if (destroyWindow) { + // The next popup may be shown during closeWindow or promiseFocus + // calls. + let waitForPopupShown = new Promise(resolve => { + window.addEventListener( + "popupshown", + () => { + executeSoon(resolve); + }, + { once: true } + ); + }); + await BrowserTestUtils.closeWindow(extraWindow); + await SimpleTest.promiseFocus(window); + await waitForPopupShown; + } + }; + } + + const maxBackgroundErrors = 5; + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_BACKGROUNDMAXERRORS, maxBackgroundErrors]], + }); + + let extraWindow = await BrowserTestUtils.openNewBrowserWindow(); + await SimpleTest.promiseFocus(extraWindow); + + let params = { checkAttempts: 1, queryString: "&badURL=1", popupShown: true }; + await runDoorhangerUpdateTest(params, [ + getBackgroundWindowHandler(false), + getBackgroundWindowHandler(true), + { + // If the update process is unable to install the update show the manual + // update doorhanger. + notificationId: "update-manual", + button: "button", + checkActiveUpdate: null, + pageURLs: { whatsNew: gDefaultWhatsNewURL, manual: URL_MANUAL_UPDATE }, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadOptIn.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadOptIn.js new file mode 100644 index 0000000000..ece7033ecc --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadOptIn.js @@ -0,0 +1,26 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function doorhanger_bc_downloadOptIn() { + await UpdateUtils.setAppUpdateAutoEnabled(false); + + let params = { + checkAttempts: 1, + queryString: "&invalidCompleteSize=1&promptWaitTime=0", + }; + await runDoorhangerUpdateTest(params, [ + { + notificationId: "update-available", + button: "button", + checkActiveUpdate: null, + pageURLs: { whatsNew: gDefaultWhatsNewURL }, + }, + { + notificationId: "update-restart", + button: "secondaryButton", + checkActiveUpdate: { state: STATE_PENDING }, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadOptIn_bgWin.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadOptIn_bgWin.js new file mode 100644 index 0000000000..f09d6a9ea8 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadOptIn_bgWin.js @@ -0,0 +1,68 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function doorhanger_bc_downloadOptIn_bgWin() { + function getBackgroundWindowHandler() { + return async function() { + await TestUtils.waitForCondition( + () => PanelUI.menuButton.hasAttribute("badge-status"), + "Background window has a badge.", + undefined, + 200 + ).catch(e => { + // Instead of throwing let the check below fail the test. + logTestInfo(e); + }); + ok( + PanelUI.menuButton.hasAttribute("badge-status"), + "PanelUI.menuButton should have a 'badge-status' attribute" + ); + is( + PanelUI.notificationPanel.state, + "closed", + "The doorhanger is not showing for the background window" + ); + is( + PanelUI.menuButton.getAttribute("badge-status"), + "update-available", + "The badge is showing for the background window" + ); + let popupShownPromise = BrowserTestUtils.waitForEvent( + PanelUI.notificationPanel, + "popupshown" + ); + await BrowserTestUtils.closeWindow(extraWindow); + await SimpleTest.promiseFocus(window); + await popupShownPromise; + + checkWhatsNewLink( + window, + "update-available-whats-new", + gDefaultWhatsNewURL + ); + let buttonEl = getNotificationButton( + window, + "update-available", + "button" + ); + buttonEl.click(); + }; + } + + await UpdateUtils.setAppUpdateAutoEnabled(false); + + let extraWindow = await BrowserTestUtils.openNewBrowserWindow(); + await SimpleTest.promiseFocus(extraWindow); + + let params = { checkAttempts: 1, queryString: "&promptWaitTime=0" }; + await runDoorhangerUpdateTest(params, [ + getBackgroundWindowHandler(), + { + notificationId: "update-restart", + button: "secondaryButton", + checkActiveUpdate: { state: STATE_PENDING }, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadOptIn_staging.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadOptIn_staging.js new file mode 100644 index 0000000000..79b9a3d934 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadOptIn_staging.js @@ -0,0 +1,30 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function doorhanger_bc_downloadOptIn_staging() { + await SpecialPowers.pushPrefEnv({ + set: [ + // Tests the app.update.promptWaitTime pref + [PREF_APP_UPDATE_PROMPTWAITTIME, 0], + [PREF_APP_UPDATE_STAGING_ENABLED, true], + ], + }); + await UpdateUtils.setAppUpdateAutoEnabled(false); + + let params = { checkAttempts: 1, queryString: "&invalidCompleteSize=1" }; + await runDoorhangerUpdateTest(params, [ + { + notificationId: "update-available", + button: "button", + checkActiveUpdate: null, + pageURLs: { whatsNew: gDefaultWhatsNewURL }, + }, + { + notificationId: "update-restart", + button: "secondaryButton", + checkActiveUpdate: { state: STATE_APPLIED }, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloaded.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloaded.js new file mode 100644 index 0000000000..e29dad26fa --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloaded.js @@ -0,0 +1,18 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function doorhanger_bc_downloaded() { + let params = { + checkAttempts: 1, + queryString: "&invalidCompleteSize=1&promptWaitTime=0", + }; + await runDoorhangerUpdateTest(params, [ + { + notificationId: "update-restart", + button: "secondaryButton", + checkActiveUpdate: { state: STATE_PENDING }, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloaded_disableBITS.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloaded_disableBITS.js new file mode 100644 index 0000000000..5f89c95322 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloaded_disableBITS.js @@ -0,0 +1,31 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function doorhanger_bc_downloaded_disableBITS() { + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_BITS_ENABLED, true]], + }); + + let params = { + checkAttempts: 1, + queryString: "&promptWaitTime=0&disableBITS=true", + }; + await runDoorhangerUpdateTest(params, [ + { + notificationId: "update-restart", + button: "secondaryButton", + checkActiveUpdate: { state: STATE_PENDING }, + }, + ]); + + let patch = getPatchOfType( + "partial", + gUpdateManager.readyUpdate + ).QueryInterface(Ci.nsIWritablePropertyBag); + ok( + !patch.getProperty("bitsId"), + "The selected patch should not have a bitsId property" + ); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloaded_staged.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloaded_staged.js new file mode 100644 index 0000000000..50416608f2 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloaded_staged.js @@ -0,0 +1,22 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function doorhanger_bc_downloaded_staged() { + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_STAGING_ENABLED, true]], + }); + + let params = { + checkAttempts: 1, + queryString: "&invalidCompleteSize=1&promptWaitTime=0", + }; + await runDoorhangerUpdateTest(params, [ + { + notificationId: "update-restart", + button: "secondaryButton", + checkActiveUpdate: { state: STATE_APPLIED }, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate.js new file mode 100644 index 0000000000..07e7bf51fa --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate.js @@ -0,0 +1,93 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * This test downloads 2 updates sequentially, and ensures that the doorhanger + * and badge do what they are supposed to do: + * First thing after the first download, the doorhanger should be displayed. + * Then download the next update. + * While that update stages, the badge should be hidden to prevent restarting + * to update while the update is staging. + * Once the staging completes, the badge should return. The doorhanger should + * not be shown at this time, because it has already been shown this + * session. + */ + +const FIRST_UPDATE_VERSION = "999998.0"; +const SECOND_UPDATE_VERSION = "999999.0"; + +function prepareToDownloadVersion(version) { + setUpdateURL( + URL_HTTP_UPDATE_SJS + + `?detailsURL=${gDetailsURL}&promptWaitTime=0&appVersion=${version}` + ); +} + +add_task(async function doorhanger_bc_multiUpdate() { + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_STAGING_ENABLED, true]], + }); + + let params = { + checkAttempts: 1, + queryString: "&promptWaitTime=0", + version: FIRST_UPDATE_VERSION, + slowStaging: true, + }; + await runDoorhangerUpdateTest(params, [ + () => { + return continueFileHandler(CONTINUE_STAGING); + }, + { + notificationId: "update-restart", + button: "secondaryButton", + checkActiveUpdate: { state: STATE_APPLIED }, + }, + async () => { + is( + PanelUI.menuButton.getAttribute("badge-status"), + "update-restart", + "Should have restart badge" + ); + + prepareToDownloadVersion(SECOND_UPDATE_VERSION); + let updateSwapped = waitForEvent("update-swap"); + gAUS.checkForBackgroundUpdates(); + await updateSwapped; + // The badge should be hidden while we swap from one update to the other + // to prevent restarting to update while staging is occurring. But since + // it will be waiting on the same event we are waiting on, wait an + // additional tick to let the other update-swap listeners run. + await TestUtils.waitForTick(); + + is( + PanelUI.menuButton.getAttribute("badge-status"), + "", + "Should not have restart badge during staging" + ); + + await continueFileHandler(CONTINUE_STAGING); + + try { + await TestUtils.waitForCondition( + () => + PanelUI.menuButton.getAttribute("badge-status") == "update-restart", + "Waiting for update restart badge to return after staging" + ); + } catch (ex) {} + + is( + PanelUI.menuButton.getAttribute("badge-status"), + "update-restart", + "Restart badge should be restored after staging completes" + ); + is( + PanelUI.notificationPanel.state, + "closed", + "Should not open a second doorhanger" + ); + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate_promptWaitTime.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate_promptWaitTime.js new file mode 100644 index 0000000000..00c61bcbb4 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate_promptWaitTime.js @@ -0,0 +1,89 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * This test downloads 2 updates sequentially, and ensures that the doorhanger + * and badge do what they are supposed to do. However, the first update has a + * long promptWaitTime, and the second has a short one and the badge wait time + * is set to 0. This should result in this behavior: + * First thing after the first download, the badge should be displayed, but + * not the doorhanger. + * Then download the next update. + * While that update stages, the badge should be hidden to prevent restarting + * to update while the update is staging. + * Once the staging completes, the doorhanger should be shown. Despite the + * long promptWaitTime of the initial update, this patch's short wait time + * means that the doorhanger should be shown soon rather than in a long + * time. + */ + +const FIRST_UPDATE_VERSION = "999998.0"; +const SECOND_UPDATE_VERSION = "999999.0"; +const LONG_PROMPT_WAIT_TIME_SEC = 10 * 60 * 60; // 10 hours + +function prepareToDownloadVersion(version, promptWaitTime) { + setUpdateURL( + URL_HTTP_UPDATE_SJS + + `?detailsURL=${gDetailsURL}&promptWaitTime=${promptWaitTime}&appVersion=${version}` + ); +} + +add_task(async function doorhanger_bc_multiUpdate() { + await SpecialPowers.pushPrefEnv({ + set: [ + [PREF_APP_UPDATE_STAGING_ENABLED, true], + [PREF_APP_UPDATE_BADGEWAITTIME, 0], + ], + }); + + let params = { + checkAttempts: 1, + queryString: `&promptWaitTime=${LONG_PROMPT_WAIT_TIME_SEC}`, + version: FIRST_UPDATE_VERSION, + slowStaging: true, + }; + await runDoorhangerUpdateTest(params, [ + async () => { + await continueFileHandler(CONTINUE_STAGING); + + try { + await TestUtils.waitForCondition( + () => + PanelUI.menuButton.getAttribute("badge-status") == "update-restart", + "Waiting for update restart badge to return after staging" + ); + } catch (ex) {} + + is( + PanelUI.menuButton.getAttribute("badge-status"), + "update-restart", + "Should have restart badge" + ); + + prepareToDownloadVersion(SECOND_UPDATE_VERSION, 0); + let updateSwapped = waitForEvent("update-swap"); + gAUS.checkForBackgroundUpdates(); + await updateSwapped; + // The badge should be hidden while we swap from one update to the other + // to prevent restarting to update while staging is occurring. But since + // it will be waiting on the same event we are waiting on, wait an + // additional tick to let the other update-swap listeners run. + await TestUtils.waitForTick(); + + is( + PanelUI.menuButton.getAttribute("badge-status"), + "", + "Should not have restart badge during staging" + ); + + await continueFileHandler(CONTINUE_STAGING); + }, + { + notificationId: "update-restart", + button: "secondaryButton", + checkActiveUpdate: { state: STATE_APPLIED }, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_completeBadSize.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_completeBadSize.js new file mode 100644 index 0000000000..505e4a9ccc --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_completeBadSize.js @@ -0,0 +1,35 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function doorhanger_bc_patch_completeBadSize() { + let params = { + checkAttempts: 1, + queryString: "&completePatchOnly=1&invalidCompleteSize=1", + }; + await runDoorhangerUpdateTest(params, [ + { + // If the update download fails maxBackgroundErrors download attempts then + // show the update available prompt. + notificationId: "update-available", + button: "button", + checkActiveUpdate: null, + pageURLs: { whatsNew: gDefaultWhatsNewURL }, + }, + { + notificationId: "update-available", + button: "button", + checkActiveUpdate: null, + pageURLs: { whatsNew: gDefaultWhatsNewURL }, + }, + { + // If the update process is unable to install the update show the manual + // update doorhanger. + notificationId: "update-manual", + button: "button", + checkActiveUpdate: null, + pageURLs: { whatsNew: gDefaultWhatsNewURL, manual: URL_MANUAL_UPDATE }, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_partialBadSize.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_partialBadSize.js new file mode 100644 index 0000000000..2db72f6b49 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_partialBadSize.js @@ -0,0 +1,35 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function doorhanger_bc_patch_partialBadSize() { + let params = { + checkAttempts: 1, + queryString: "&partialPatchOnly=1&invalidPartialSize=1", + }; + await runDoorhangerUpdateTest(params, [ + { + // If the update download fails maxBackgroundErrors download attempts then + // show the update available prompt. + notificationId: "update-available", + button: "button", + checkActiveUpdate: null, + pageURLs: { whatsNew: gDefaultWhatsNewURL }, + }, + { + notificationId: "update-available", + button: "button", + checkActiveUpdate: null, + pageURLs: { whatsNew: gDefaultWhatsNewURL }, + }, + { + // If the update process is unable to install the update show the manual + // update doorhanger. + notificationId: "update-manual", + button: "button", + checkActiveUpdate: null, + pageURLs: { whatsNew: gDefaultWhatsNewURL, manual: URL_MANUAL_UPDATE }, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_partialBadSize_complete.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_partialBadSize_complete.js new file mode 100644 index 0000000000..f3c9b1f51f --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_partialBadSize_complete.js @@ -0,0 +1,18 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function doorhanger_bc_patch_partialBadSize_complete() { + let params = { + checkAttempts: 1, + queryString: "&invalidPartialSize=1&promptWaitTime=0", + }; + await runDoorhangerUpdateTest(params, [ + { + notificationId: "update-restart", + button: "secondaryButton", + checkActiveUpdate: { state: STATE_PENDING }, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_partialBadSize_completeBadSize.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_partialBadSize_completeBadSize.js new file mode 100644 index 0000000000..4a84571e15 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_partialBadSize_completeBadSize.js @@ -0,0 +1,35 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function doorhanger_bc_patch_partialBadSize_completeBadSize() { + let params = { + checkAttempts: 1, + queryString: "&invalidPartialSize=1&invalidCompleteSize=1", + }; + await runDoorhangerUpdateTest(params, [ + { + // If the update download fails maxBackgroundErrors download attempts then + // show the update available prompt. + notificationId: "update-available", + button: "button", + checkActiveUpdate: null, + pageURLs: { whatsNew: gDefaultWhatsNewURL }, + }, + { + notificationId: "update-available", + button: "button", + checkActiveUpdate: null, + pageURLs: { whatsNew: gDefaultWhatsNewURL }, + }, + { + // If the update process is unable to install the update show the manual + // update doorhanger. + notificationId: "update-manual", + button: "button", + checkActiveUpdate: null, + pageURLs: { whatsNew: gDefaultWhatsNewURL, manual: URL_MANUAL_UPDATE }, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_completeApplyFailure.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_completeApplyFailure.js new file mode 100644 index 0000000000..616b399c21 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_completeApplyFailure.js @@ -0,0 +1,23 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function doorhanger_sp_patch_completeApplyFailure() { + let patchProps = { state: STATE_PENDING }; + let patches = getLocalPatchString(patchProps); + let updateProps = { checkInterval: "1" }; + let updates = getLocalUpdateString(updateProps, patches); + + let params = { updates }; + await runDoorhangerUpdateTest(params, [ + { + // If the update process is unable to install the update show the manual + // update doorhanger. + notificationId: "update-manual", + button: "button", + checkActiveUpdate: null, + pageURLs: { whatsNew: gDefaultWhatsNewURL, manual: URL_MANUAL_UPDATE }, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure.js new file mode 100644 index 0000000000..a390627b59 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure.js @@ -0,0 +1,22 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function doorhanger_sp_patch_partialApplyFailure() { + let patchProps = { type: "partial", state: STATE_PENDING }; + let patches = getLocalPatchString(patchProps); + let updateProps = { isCompleteUpdate: "false", checkInterval: "1" }; + let updates = getLocalUpdateString(updateProps, patches); + + let params = { updates }; + await runDoorhangerUpdateTest(params, [ + { + // If there is only an invalid patch show the manual update doorhanger. + notificationId: "update-manual", + button: "button", + checkActiveUpdate: null, + pageURLs: { whatsNew: gDefaultWhatsNewURL, manual: URL_MANUAL_UPDATE }, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure_complete.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure_complete.js new file mode 100644 index 0000000000..bf533dab04 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure_complete.js @@ -0,0 +1,22 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function doorhanger_sp_patch_partialApplyFailure_complete() { + let patchProps = { type: "partial", state: STATE_PENDING }; + let patches = getLocalPatchString(patchProps); + patchProps = { selected: "false" }; + patches += getLocalPatchString(patchProps); + let updateProps = { isCompleteUpdate: "false", promptWaitTime: "0" }; + let updates = getLocalUpdateString(updateProps, patches); + + let params = { updates }; + await runDoorhangerUpdateTest(params, [ + { + notificationId: "update-restart", + button: "secondaryButton", + checkActiveUpdate: { state: STATE_PENDING }, + }, + ]); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure_completeBadSize.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure_completeBadSize.js new file mode 100644 index 0000000000..4c5f2279f2 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure_completeBadSize.js @@ -0,0 +1,32 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task( + async function doorhanger_sp_patch_partialApplyFailure_completeBadSize() { + // Because of the way the test is simulating failure it has to pretend it has + // already retried. + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_DOWNLOAD_MAXATTEMPTS, 0]], + }); + + let patchProps = { type: "partial", state: STATE_PENDING }; + let patches = getLocalPatchString(patchProps); + patchProps = { size: "1234", selected: "false" }; + patches += getLocalPatchString(patchProps); + let updateProps = { isCompleteUpdate: "false" }; + let updates = getLocalUpdateString(updateProps, patches); + + let params = { updates }; + await runDoorhangerUpdateTest(params, [ + { + // If there is only an invalid patch show the manual update doorhanger. + notificationId: "update-manual", + button: "button", + checkActiveUpdate: null, + pageURLs: { whatsNew: gDefaultWhatsNewURL, manual: URL_MANUAL_UPDATE }, + }, + ]); + } +); diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure_complete_staging.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure_complete_staging.js new file mode 100644 index 0000000000..a99c04b0be --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure_complete_staging.js @@ -0,0 +1,28 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task( + async function doorhanger_sp_patch_partialApplyFailure_complete_staging() { + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_STAGING_ENABLED, true]], + }); + + let patchProps = { type: "partial", state: STATE_PENDING }; + let patches = getLocalPatchString(patchProps); + patchProps = { selected: "false" }; + patches += getLocalPatchString(patchProps); + let updateProps = { isCompleteUpdate: "false", promptWaitTime: "0" }; + let updates = getLocalUpdateString(updateProps, patches); + + let params = { updates }; + await runDoorhangerUpdateTest(params, [ + { + notificationId: "update-restart", + button: "secondaryButton", + checkActiveUpdate: { state: STATE_APPLIED }, + }, + ]); + } +); diff --git a/toolkit/mozapps/update/tests/browser/browser_elevationDialog.js b/toolkit/mozapps/update/tests/browser/browser_elevationDialog.js new file mode 100644 index 0000000000..6aa32a7fc9 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_elevationDialog.js @@ -0,0 +1,139 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function elevation_dialog() { + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_DISABLEDFORTESTING, false]], + }); + + // Create a mock of nsIAppStartup's quit method so clicking the restart button + // won't restart the application. + let { startup } = Services; + let appStartup = { + QueryInterface: ChromeUtils.generateQI(["nsIAppStartup"]), + quit(mode) { + if (elevationDialog) { + elevationDialog.close(); + elevationDialog = null; + } + }, + }; + Services.startup = appStartup; + registerCleanupFunction(() => { + Services.startup = startup; + }); + + registerCleanupFunction(async () => { + let win = Services.wm.getMostRecentWindow("Update:Elevation"); + if (win) { + win.close(); + await TestUtils.waitForCondition( + () => !Services.wm.getMostRecentWindow("Update:Elevation"), + "The Update Elevation dialog should have closed" + ); + } + }); + + // Test clicking the "Restart Later" button + let elevationDialog = await waitForElevationDialog(); + await TestUtils.waitForTick(); + elevationDialog.document.getElementById("elevateExtra2").click(); + await TestUtils.waitForCondition( + () => !Services.wm.getMostRecentWindow("Update:Elevation"), + "The Update Elevation dialog should have closed" + ); + ok(!!gUpdateManager.readyUpdate, "There should be a ready update"); + is( + gUpdateManager.readyUpdate.state, + STATE_PENDING_ELEVATE, + "The ready update state should equal " + STATE_PENDING_ELEVATE + ); + is( + readStatusFile(), + STATE_PENDING_ELEVATE, + "The status file state should equal " + STATE_PENDING_ELEVATE + ); + + // Test clicking the "No Thanks" button + elevationDialog = await waitForElevationDialog(); + await TestUtils.waitForTick(); + elevationDialog.document.getElementById("elevateExtra1").click(); + await TestUtils.waitForCondition( + () => !Services.wm.getMostRecentWindow("Update:Elevation"), + "The Update Elevation dialog should have closed" + ); + ok(!gUpdateManager.readyUpdate, "There should not be a ready update"); + is( + readStatusFile(), + STATE_NONE, + "The status file state should equal " + STATE_NONE + ); + + // Test clicking the "Restart <brandShortName>" button + elevationDialog = await waitForElevationDialog(); + await TestUtils.waitForTick(); + elevationDialog.document.getElementById("elevateAccept").click(); + await TestUtils.waitForCondition( + () => !Services.wm.getMostRecentWindow("Update:Elevation"), + "The Update Elevation dialog should have closed" + ); + ok(!!gUpdateManager.readyUpdate, "There should be a ready update"); + is( + gUpdateManager.readyUpdate.state, + STATE_PENDING_ELEVATE, + "The active update state should equal " + STATE_PENDING_ELEVATE + ); + is( + readStatusFile(), + STATE_PENDING, + "The status file state should equal " + STATE_PENDING + ); +}); + +/** + * Waits for the Update Elevation Dialog to load. + * + * @return A promise that returns the domWindow for the Update Elevation Dialog + * and resolves when the Update Elevation Dialog loads. + */ +function waitForElevationDialog() { + return new Promise(resolve => { + var listener = { + onOpenWindow: aXULWindow => { + debugDump("Update Elevation dialog shown..."); + Services.wm.removeListener(listener); + + async function elevationDialogOnLoad() { + domwindow.removeEventListener("load", elevationDialogOnLoad, true); + let chromeURI = + "chrome://mozapps/content/update/updateElevation.xhtml"; + is( + domwindow.document.location.href, + chromeURI, + "Update Elevation appeared" + ); + resolve(domwindow); + } + + var domwindow = aXULWindow.docShell.domWindow; + domwindow.addEventListener("load", elevationDialogOnLoad, true); + }, + onCloseWindow: aXULWindow => {}, + }; + + Services.wm.addListener(listener); + // Add the active-update.xml and update.status files used for these tests, + // reload the update manager, and then simulate startup so the Update + // Elevation Dialog is opened. + let patchProps = { state: STATE_PENDING_ELEVATE }; + let patches = getLocalPatchString(patchProps); + let updateProps = { checkInterval: "1" }; + let updates = getLocalUpdateString(updateProps, patches); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + writeStatusFile(STATE_PENDING_ELEVATE); + reloadUpdateManagerData(); + testPostUpdateProcessing(); + }); +} diff --git a/toolkit/mozapps/update/tests/browser/browser_telemetry_updatePing_downloaded_ready.js b/toolkit/mozapps/update/tests/browser/browser_telemetry_updatePing_downloaded_ready.js new file mode 100644 index 0000000000..01070dd1a6 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_telemetry_updatePing_downloaded_ready.js @@ -0,0 +1,69 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +ChromeUtils.import( + "resource://testing-common/TelemetryArchiveTesting.jsm", + this +); + +/** + * Test that UpdatePing telemetry with a payload reason of ready is sent for a + * staged update. + * + * Please note that this is really a Telemetry test, not an + * "update UI" test like the rest of the tests in this directory. + * This test does not live in toolkit/components/telemetry/tests to prevent + * duplicating the code for all the test dependencies. Unfortunately, due + * to a limitation in the build system, we were not able to simply reference + * the dependencies as "support-files" in the test manifest. + */ +add_task(async function telemetry_updatePing_ready() { + let archiveChecker = new TelemetryArchiveTesting.Checker(); + await archiveChecker.promiseInit(); + + let updateParams = ""; + await runTelemetryUpdateTest(updateParams, "update-downloaded"); + + // We cannot control when the ping will be generated/archived after we trigger + // an update, so let's make sure to have one before moving on with validation. + let updatePing; + await TestUtils.waitForCondition( + async function() { + // Check that the ping made it into the Telemetry archive. + // The test data is defined in ../data/sharedUpdateXML.js + updatePing = await archiveChecker.promiseFindPing("update", [ + [["payload", "reason"], "ready"], + [["payload", "targetBuildId"], "20080811053724"], + ]); + return !!updatePing; + }, + "Make sure the ping is generated before trying to validate it.", + 500, + 100 + ); + + ok(updatePing, "The 'update' ping must be correctly sent."); + + // We don't know the exact value for the other fields, so just check + // that they're available. + for (let f of ["targetVersion", "targetChannel", "targetDisplayVersion"]) { + ok( + f in updatePing.payload, + `${f} must be available in the update ping payload.` + ); + ok( + typeof updatePing.payload[f] == "string", + `${f} must have the correct format.` + ); + } + + // Also make sure that the ping contains both a client id and an + // environment section. + ok("clientId" in updatePing, "The update ping must report a client id."); + ok( + "environment" in updatePing, + "The update ping must report the environment." + ); +}); diff --git a/toolkit/mozapps/update/tests/browser/browser_telemetry_updatePing_staged_ready.js b/toolkit/mozapps/update/tests/browser/browser_telemetry_updatePing_staged_ready.js new file mode 100644 index 0000000000..4d87fab5e7 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_telemetry_updatePing_staged_ready.js @@ -0,0 +1,73 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +ChromeUtils.import( + "resource://testing-common/TelemetryArchiveTesting.jsm", + this +); + +/** + * Test that UpdatePing telemetry with a payload reason of ready is sent for a + * staged update. + * + * Please note that this is really a Telemetry test, not an + * "update UI" test like the rest of the tests in this directory. + * This test does not live in toolkit/components/telemetry/tests to prevent + * duplicating the code for all the test dependencies. Unfortunately, due + * to a limitation in the build system, we were not able to simply reference + * the dependencies as "support-files" in the test manifest. + */ +add_task(async function telemetry_updatePing_ready() { + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_STAGING_ENABLED, true]], + }); + + let archiveChecker = new TelemetryArchiveTesting.Checker(); + await archiveChecker.promiseInit(); + + let updateParams = ""; + await runTelemetryUpdateTest(updateParams, "update-staged"); + + // We cannot control when the ping will be generated/archived after we trigger + // an update, so let's make sure to have one before moving on with validation. + let updatePing; + await TestUtils.waitForCondition( + async function() { + // Check that the ping made it into the Telemetry archive. + // The test data is defined in ../data/sharedUpdateXML.js + updatePing = await archiveChecker.promiseFindPing("update", [ + [["payload", "reason"], "ready"], + [["payload", "targetBuildId"], "20080811053724"], + ]); + return !!updatePing; + }, + "Make sure the ping is generated before trying to validate it.", + 500, + 100 + ); + + ok(updatePing, "The 'update' ping must be correctly sent."); + + // We don't know the exact value for the other fields, so just check + // that they're available. + for (let f of ["targetVersion", "targetChannel", "targetDisplayVersion"]) { + ok( + f in updatePing.payload, + `${f} must be available in the update ping payload.` + ); + ok( + typeof updatePing.payload[f] == "string", + `${f} must have the correct format.` + ); + } + + // Also make sure that the ping contains both a client id and an + // environment section. + ok("clientId" in updatePing, "The update ping must report a client id."); + ok( + "environment" in updatePing, + "The update ping must report the environment." + ); +}); diff --git a/toolkit/mozapps/update/tests/browser/downloadPage.html b/toolkit/mozapps/update/tests/browser/downloadPage.html new file mode 100644 index 0000000000..4810e2e0d6 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/downloadPage.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html> +<head> + <title>Download page</title> + <meta charset="utf-8"> +</head> +<body> +<!-- just use simple.mar since we have it available and it will result in a download dialog --> +<a id="download-link" href="http://example.com/browser/browser/base/content/test/appUpdate/simple.mar" data-link-type="download"> + Download +</a> +</body> +</html> diff --git a/toolkit/mozapps/update/tests/browser/head.js b/toolkit/mozapps/update/tests/browser/head.js new file mode 100644 index 0000000000..7f77ad44df --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/head.js @@ -0,0 +1,1189 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { AppConstants } = ChromeUtils.import( + "resource://gre/modules/AppConstants.jsm" +); + +ChromeUtils.defineModuleGetter( + this, + "AppMenuNotifications", + "resource://gre/modules/AppMenuNotifications.jsm" +); +ChromeUtils.defineModuleGetter( + this, + "DownloadUtils", + "resource://gre/modules/DownloadUtils.jsm" +); +ChromeUtils.defineModuleGetter( + this, + "UpdateListener", + "resource://gre/modules/UpdateListener.jsm" +); +const { XPIInstall } = ChromeUtils.import( + "resource://gre/modules/addons/XPIInstall.jsm" +); + +const BIN_SUFFIX = AppConstants.platform == "win" ? ".exe" : ""; +const FILE_UPDATER_BIN = + "updater" + (AppConstants.platform == "macosx" ? ".app" : BIN_SUFFIX); +const FILE_UPDATER_BIN_BAK = FILE_UPDATER_BIN + ".bak"; + +const LOG_FUNCTION = info; + +const MAX_UPDATE_COPY_ATTEMPTS = 10; + +const DATA_URI_SPEC = + "chrome://mochitests/content/browser/toolkit/mozapps/update/tests/browser/"; +/* import-globals-from testConstants.js */ +Services.scriptloader.loadSubScript(DATA_URI_SPEC + "testConstants.js", this); + +var gURLData = URL_HOST + "/" + REL_PATH_DATA; +const URL_MANUAL_UPDATE = gURLData + "downloadPage.html"; + +const gBadSizeResult = Cr.NS_ERROR_UNEXPECTED.toString(); + +/* import-globals-from ../data/shared.js */ +Services.scriptloader.loadSubScript(DATA_URI_SPEC + "shared.js", this); + +let gOriginalUpdateAutoValue = null; + +// Some elements append a trailing /. After the chrome tests are removed this +// code can be changed so URL_HOST already has a trailing /. +const gDetailsURL = URL_HOST + "/"; +const gDefaultWhatsNewURL = URL_HTTP_UPDATE_SJS + "?uiURL=DETAILS"; + +// Set to true to log additional information for debugging. To log additional +// information for individual tests set gDebugTest to false here and to true +// globally in the test. +gDebugTest = false; + +// This is to accommodate the TV task which runs the tests with --verify. +requestLongerTimeout(10); + +/** + * Common tasks to perform for all tests before each one has started. + */ +add_task(async function setupTestCommon() { + await SpecialPowers.pushPrefEnv({ + set: [ + [PREF_APP_UPDATE_BADGEWAITTIME, 1800], + [PREF_APP_UPDATE_DOWNLOAD_ATTEMPTS, 0], + [PREF_APP_UPDATE_DOWNLOAD_MAXATTEMPTS, 2], + [PREF_APP_UPDATE_LOG, gDebugTest], + [PREF_APP_UPDATE_PROMPTWAITTIME, 3600], + [PREF_APP_UPDATE_SERVICE_ENABLED, false], + // Disable activity stream to prevent errors when opening pages during + // TV runs. See bug 1548422 for an example. + ["browser.library.activity-stream.enabled", false], + ], + }); + + // We need to keep the update sync manager from thinking two instances are + // running because of the mochitest parent instance, which means we need to + // override the directory service with a fake executable path and then reset + // the lock. But leaving the directory service overridden causes problems for + // these tests, so we need to restore the real service immediately after. + // To form the path, we'll use the real executable path with a token appended + // (the path needs to be absolute, but not to point to a real file). + // This block is loosely copied from adjustGeneralPaths() in another update + // test file, xpcshellUtilsAUS.js, but this is a much more limited version; + // it's been copied here both because the full function is overkill and also + // because making it general enough to run in both xpcshell and mochitest + // would have been unreasonably difficult. + let exePath = Services.dirsvc.get(XRE_EXECUTABLE_FILE, Ci.nsIFile); + let dirProvider = { + getFile: function AGP_DP_getFile(aProp, aPersistent) { + // Set the value of persistent to false so when this directory provider is + // unregistered it will revert back to the original provider. + aPersistent.value = false; + switch (aProp) { + case XRE_EXECUTABLE_FILE: + exePath.append("browser-test"); + return exePath; + } + return null; + }, + QueryInterface: ChromeUtils.generateQI(["nsIDirectoryServiceProvider"]), + }; + let ds = Services.dirsvc.QueryInterface(Ci.nsIDirectoryService); + ds.QueryInterface(Ci.nsIProperties).undefine(XRE_EXECUTABLE_FILE); + ds.registerProvider(dirProvider); + + let syncManager = Cc["@mozilla.org/updates/update-sync-manager;1"].getService( + Ci.nsIUpdateSyncManager + ); + syncManager.resetLock(); + + ds.unregisterProvider(dirProvider); + + setUpdateTimerPrefs(); + reloadUpdateManagerData(true); + removeUpdateFiles(true); + UpdateListener.reset(); + AppMenuNotifications.removeNotification(/.*/); + // Most app update mochitest-browser-chrome tests expect auto update to be + // enabled. Those that don't will explicitly change this. + await setAppUpdateAutoEnabledHelper(true); +}); + +/** + * Common tasks to perform for all tests after each one has finished. + */ +registerCleanupFunction(async () => { + AppMenuNotifications.removeNotification(/.*/); + gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", ""); + gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", ""); + gEnv.set("MOZ_TEST_STAGING_ERROR", ""); + UpdateListener.reset(); + AppMenuNotifications.removeNotification(/.*/); + reloadUpdateManagerData(true); + // Pass false when the log files are needed for troubleshooting the tests. + removeUpdateFiles(true); + // Always try to restore the original updater files. If none of the updater + // backup files are present then this is just a no-op. + await finishTestRestoreUpdaterBackup(); + // Reset the update lock once again so that we know the lock we're + // interested in here will be closed properly (normally that happens during + // XPCOM shutdown, but that isn't consistent during tests). + let syncManager = Cc["@mozilla.org/updates/update-sync-manager;1"].getService( + Ci.nsIUpdateSyncManager + ); + syncManager.resetLock(); +}); + +/** + * Overrides the add-ons manager language pack staging with a mocked version. + * The returned promise resolves when language pack staging begins returning an + * object with the new appVersion and platformVersion and functions to resolve + * or reject the install. + */ +function mockLangpackInstall() { + let original = XPIInstall.stageLangpacksForAppUpdate; + registerCleanupFunction(() => { + XPIInstall.stageLangpacksForAppUpdate = original; + }); + + let stagingCall = PromiseUtils.defer(); + XPIInstall.stageLangpacksForAppUpdate = (appVersion, platformVersion) => { + let result = PromiseUtils.defer(); + stagingCall.resolve({ + appVersion, + platformVersion, + resolve: result.resolve, + reject: result.reject, + }); + + return result.promise; + }; + + return stagingCall.promise; +} + +/** + * 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 = getUpdateDirFile(FILE_UPDATE_TEST).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); + }); +} + +/** + * Closes the update mutex handle in nsUpdateService.js if it exists and then + * creates a new update mutex handle so the update code thinks there is another + * instance of the application handling updates. + * + * @throws If the function is called on a platform other than Windows. + */ +function setOtherInstanceHandlingUpdates() { + if (AppConstants.platform != "win") { + throw new Error("Windows only test function called"); + } + gAUS.observe(null, "test-close-handle-update-mutex", ""); + let handle = createMutex(getPerInstallationMutexName()); + registerCleanupFunction(() => { + closeHandle(handle); + }); +} + +/** + * Gets the update version info for the update url parameters to send to + * 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 app_update.sjs. + */ +function getVersionParams(aAppVersion) { + let appInfo = Services.appinfo; + return "&appVersion=" + (aAppVersion ? aAppVersion : appInfo.version); +} + +/** + * Prevent nsIUpdateTimerManager from notifying nsIApplicationUpdateService + * to check for updates by setting the app update last update time to the + * current time minus one minute in seconds and the interval time to 12 hours + * in seconds. + */ +function setUpdateTimerPrefs() { + let now = Math.round(Date.now() / 1000) - 60; + Services.prefs.setIntPref(PREF_APP_UPDATE_LASTUPDATETIME, now); + Services.prefs.setIntPref(PREF_APP_UPDATE_INTERVAL, 43200); +} + +/* + * Sets the value of the App Auto Update setting and sets it back to the + * original value at the start of the test when the test finishes. + * + * @param enabled + * The value to set App Auto Update to. + */ +async function setAppUpdateAutoEnabledHelper(enabled) { + if (gOriginalUpdateAutoValue == null) { + gOriginalUpdateAutoValue = await UpdateUtils.getAppUpdateAutoEnabled(); + registerCleanupFunction(async () => { + await UpdateUtils.setAppUpdateAutoEnabled(gOriginalUpdateAutoValue); + }); + } + await UpdateUtils.setAppUpdateAutoEnabled(enabled); +} + +/** + * Gets the specified button for the notification. + * + * @param win + * The window to get the notification button for. + * @param notificationId + * The ID of the notification to get the button for. + * @param button + * The anonid of the button to get. + * @return The button element. + */ +function getNotificationButton(win, notificationId, button) { + let notification = win.document.getElementById( + `appMenu-${notificationId}-notification` + ); + ok(!notification.hidden, `${notificationId} notification is showing`); + return notification[button]; +} + +/** + * Ensures that the "What's new" link with the provided ID is displayed and + * matches the url parameter provided. + * + * @param win + * The window to get the "What's new" link for. + * @param id + * The ID of the "What's new" link element. + * @param url + * The URL to check against. + */ +function checkWhatsNewLink(win, id, url) { + let whatsNewLink = win.document.getElementById(id); + ok(!whatsNewLink.hidden, "What's new link is not hidden."); + is(whatsNewLink.href, url, `What's new link href should equal ${url}`); +} + +/** + * 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 (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 TestUtils.waitForTick(); + await setupTestUpdater(); + return; + } + await moveRealUpdater(); + } + })(); +} + +/** + * Backs up the real updater and tries again on failure since Windows debug + * builds at times leave the file in use. After success it will call + * copyTestUpdater to continue the setup of the test updater. + */ +function moveRealUpdater() { + return (async function() { + try { + // Move away the real updater + let greBinDir = getGREBinDir(); + let updater = greBinDir.clone(); + updater.append(FILE_UPDATER_BIN); + updater.moveTo(greBinDir, FILE_UPDATER_BIN_BAK); + + let greDir = getGREDir(); + let updateSettingsIni = greDir.clone(); + updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI); + if (updateSettingsIni.exists()) { + updateSettingsIni.moveTo(greDir, FILE_UPDATE_SETTINGS_INI_BAK); + } + + let precomplete = greDir.clone(); + precomplete.append(FILE_PRECOMPLETE); + if (precomplete.exists()) { + precomplete.moveTo(greDir, FILE_PRECOMPLETE_BAK); + } + } catch (e) { + logTestInfo( + "Attempt to move the real updater out of the way failed... " + + "will try again, Exception: " + + e + ); + await TestUtils.waitForTick(); + await moveRealUpdater(); + return; + } + + await copyTestUpdater(); + })(); +} + +/** + * 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() { + try { + // Copy the test updater + let greBinDir = getGREBinDir(); + let testUpdaterDir = Services.dirsvc.get("CurWorkD", Ci.nsIFile); + let relPath = REL_PATH_DATA; + let pathParts = relPath.split("/"); + for (let i = 0; i < pathParts.length; ++i) { + testUpdaterDir.append(pathParts[i]); + } + + let testUpdater = testUpdaterDir.clone(); + testUpdater.append(FILE_UPDATER_BIN); + testUpdater.copyToFollowingLinks(greBinDir, FILE_UPDATER_BIN); + + let greDir = getGREDir(); + let updateSettingsIni = greDir.clone(); + updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI); + writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS); + + let precomplete = greDir.clone(); + precomplete.append(FILE_PRECOMPLETE); + writeFile(precomplete, PRECOMPLETE_CONTENTS); + } catch (e) { + if (attempt < MAX_UPDATE_COPY_ATTEMPTS) { + logTestInfo( + "Attempt to copy the test updater failed... " + + "will try again, Exception: " + + e + ); + await TestUtils.waitForTick(); + await copyTestUpdater(attempt++); + } + } + })(); +} + +/** + * Restores the updater and updater related file that if there a backup exists. + * This is called in setupTestUpdater before the backup of the real updater is + * done in case the previous test failed to restore the file when a test has + * finished. This is also called in finishTestRestoreUpdaterBackup to restore + * the files when a test finishes. + */ +function restoreUpdaterBackup() { + let greBinDir = getGREBinDir(); + let updater = greBinDir.clone(); + let updaterBackup = greBinDir.clone(); + updater.append(FILE_UPDATER_BIN); + updaterBackup.append(FILE_UPDATER_BIN_BAK); + if (updaterBackup.exists()) { + if (updater.exists()) { + updater.remove(true); + } + updaterBackup.moveTo(greBinDir, FILE_UPDATER_BIN); + } + + let greDir = getGREDir(); + let updateSettingsIniBackup = greDir.clone(); + updateSettingsIniBackup.append(FILE_UPDATE_SETTINGS_INI_BAK); + if (updateSettingsIniBackup.exists()) { + let updateSettingsIni = greDir.clone(); + updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI); + if (updateSettingsIni.exists()) { + updateSettingsIni.remove(false); + } + updateSettingsIniBackup.moveTo(greDir, FILE_UPDATE_SETTINGS_INI); + } + + let precomplete = greDir.clone(); + let precompleteBackup = greDir.clone(); + precomplete.append(FILE_PRECOMPLETE); + precompleteBackup.append(FILE_PRECOMPLETE_BAK); + if (precompleteBackup.exists()) { + if (precomplete.exists()) { + precomplete.remove(false); + } + precompleteBackup.moveTo(greDir, FILE_PRECOMPLETE); + } else if (precomplete.exists()) { + if (readFile(precomplete) == PRECOMPLETE_CONTENTS) { + precomplete.remove(false); + } + } +} + +/** + * When a test finishes this will repeatedly attempt to restore the real updater + * and the other files for the updater if a backup of the file exists. + */ +function finishTestRestoreUpdaterBackup() { + return (async function() { + try { + // Windows debug builds keep the updater file in use for a short period of + // time after the updater process exits. + restoreUpdaterBackup(); + } catch (e) { + logTestInfo( + "Attempt to restore the backed up updater failed... " + + "will try again, Exception: " + + e + ); + + 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.xhtml"; + 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(); + }); +} + +/** + * Return the first UpdatePatch with the given type. + * + * @param type + * The type of the patch ("complete" or "partial") + * @param update + * The nsIUpdate to select a patch from. + * @return A nsIUpdatePatch object matching the type specified + */ +function getPatchOfType(type, update) { + if (update) { + for (let i = 0; i < update.patchCount; ++i) { + let patch = update.getPatchAt(i); + if (patch && patch.type == type) { + return patch; + } + } + } + return null; +} + +/** + * Runs a Doorhanger update test. This will set various common prefs for + * updating and runs the provided list of steps. + * + * @param params + * An object containing parameters used to run the test. + * @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 runDoorhangerUpdateTest(params, steps) { + function processDoorhangerStep(step) { + if (typeof step == "function") { + return step(); + } + + const { notificationId, button, checkActiveUpdate, pageURLs } = step; + return (async function() { + if (!params.popupShown && !PanelUI.isNotificationPanelOpen) { + await BrowserTestUtils.waitForEvent( + PanelUI.notificationPanel, + "popupshown" + ); + } + const shownNotificationId = AppMenuNotifications.activeNotification.id; + is( + shownNotificationId, + notificationId, + "The right notification showed up." + ); + + if (checkActiveUpdate) { + let activeUpdate = + checkActiveUpdate.state == STATE_DOWNLOADING + ? gUpdateManager.downloadingUpdate + : gUpdateManager.readyUpdate; + ok(!!activeUpdate, "There should be an active update"); + is( + activeUpdate.state, + checkActiveUpdate.state, + `The active update state should equal ${checkActiveUpdate.state}` + ); + } else { + ok( + !gUpdateManager.downloadingUpdate, + "There should not be a downloading update" + ); + ok(!gUpdateManager.readyUpdate, "There should not be a ready update"); + } + + if (pageURLs && pageURLs.whatsNew !== undefined) { + checkWhatsNewLink( + window, + `${notificationId}-whats-new`, + pageURLs.whatsNew + ); + } + + let buttonEl = getNotificationButton(window, notificationId, button); + buttonEl.click(); + + if (pageURLs && pageURLs.manual !== undefined) { + await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + is( + gBrowser.selectedBrowser.currentURI.spec, + pageURLs.manual, + `The page's url should equal ${pageURLs.manual}` + ); + gBrowser.removeTab(gBrowser.selectedTab); + } + })(); + } + + return (async function() { + if (params.slowStaging) { + gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "1"); + } else { + gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1"); + } + await SpecialPowers.pushPrefEnv({ + set: [ + [PREF_APP_UPDATE_DISABLEDFORTESTING, false], + [PREF_APP_UPDATE_URL_DETAILS, gDetailsURL], + [PREF_APP_UPDATE_URL_MANUAL, URL_MANUAL_UPDATE], + ], + }); + + await setupTestUpdater(); + + let queryString = params.queryString ? params.queryString : ""; + let updateURL = + URL_HTTP_UPDATE_SJS + + "?detailsURL=" + + gDetailsURL + + queryString + + getVersionParams(params.version); + setUpdateURL(updateURL); + + if (params.checkAttempts) { + // Perform a background check doorhanger test. + executeSoon(() => { + (async function() { + gAUS.checkForBackgroundUpdates(); + for (var i = 0; i < params.checkAttempts - 1; i++) { + await waitForEvent("update-error", "check-attempt-failed"); + gAUS.checkForBackgroundUpdates(); + } + })(); + }); + } else { + // Perform a startup processing doorhanger test. + writeStatusFile(STATE_FAILED_CRC_ERROR); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(params.updates), true); + reloadUpdateManagerData(); + testPostUpdateProcessing(); + } + + for (let step of steps) { + await processDoorhangerStep(step); + } + })(); +} + +/** + * Runs an About Dialog update test. This will set various common prefs for + * updating and runs the provided list of steps. + * + * @param params + * An object containing parameters used to run the test. + * @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(params, steps) { + let aboutDialog; + function processAboutDialogStep(step) { + if (typeof step == "function") { + return step(aboutDialog); + } + + const { panelId, checkActiveUpdate, continueFile, downloadInfo } = step; + return (async function() { + let updateDeck = aboutDialog.document.getElementById("updateDeck"); + await TestUtils.waitForCondition( + () => + updateDeck.selectedPanel && updateDeck.selectedPanel.id == panelId, + "Waiting for the expected panel ID: " + panelId, + undefined, + 200 + ).catch(e => { + // Instead of throwing let the check below fail the test so the panel + // ID and the expected panel ID is printed in the log. + logTestInfo(e); + }); + let selectedPanel = updateDeck.selectedPanel; + is(selectedPanel.id, panelId, "The panel ID should equal " + panelId); + + if (checkActiveUpdate) { + let activeUpdate = + checkActiveUpdate.state == STATE_DOWNLOADING + ? gUpdateManager.downloadingUpdate + : gUpdateManager.readyUpdate; + ok(!!activeUpdate, "There should be an active update"); + is( + activeUpdate.state, + checkActiveUpdate.state, + "The active update state should equal " + checkActiveUpdate.state + ); + } else { + ok( + !gUpdateManager.downloadingUpdate, + "There should not be a downloading update" + ); + ok(!gUpdateManager.readyUpdate, "There should not be a ready update"); + } + + if (panelId == "downloading") { + for (let i = 0; i < downloadInfo.length; ++i) { + let data = downloadInfo[i]; + // The About Dialog tests always specify a continue file. + await continueFileHandler(continueFile); + let patch = getPatchOfType( + data.patchType, + gUpdateManager.downloadingUpdate + ); + // The update is removed early when the last download fails so check + // that there is a patch before proceeding. + let isLastPatch = i == downloadInfo.length - 1; + if (!isLastPatch || patch) { + let resultName = data.bitsResult ? "bitsResult" : "internalResult"; + patch.QueryInterface(Ci.nsIWritablePropertyBag); + await TestUtils.waitForCondition( + () => patch.getProperty(resultName) == data[resultName], + "Waiting for expected patch property " + + resultName + + " value: " + + data[resultName], + undefined, + 200 + ).catch(e => { + // Instead of throwing let the check below fail the test so the + // property value and the expected property value is printed in + // the log. + logTestInfo(e); + }); + is( + "" + patch.getProperty(resultName), + data[resultName], + "The patch property " + + resultName + + " value should equal " + + data[resultName] + ); + + // Check the download status text. It should be something like, + // "1.4 of 1.4 KB". + let expectedText = DownloadUtils.getTransferTotal( + data[resultName] == gBadSizeResult ? 0 : patch.size, + patch.size + ); + Assert.ok( + expectedText, + "Sanity check: Expected download status text should be non-empty" + ); + Assert.equal( + aboutDialog.downloadStatus.textContent, + expectedText, + "Download status text should be correct" + ); + } + } + } else 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 link = selectedPanel.querySelector("label.text-link"); + is( + link.href, + gDetailsURL, + `The panel's link href should equal ${gDetailsURL}` + ); + } + + let buttonPanels = ["downloadAndInstall", "apply"]; + if (buttonPanels.includes(panelId)) { + let buttonEl = selectedPanel.querySelector("button"); + await TestUtils.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() { + gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "1"); + await SpecialPowers.pushPrefEnv({ + set: [ + [PREF_APP_UPDATE_DISABLEDFORTESTING, false], + [PREF_APP_UPDATE_URL_MANUAL, gDetailsURL], + ], + }); + + await setupTestUpdater(); + + let queryString = params.queryString ? params.queryString : ""; + let updateURL = + URL_HTTP_UPDATE_SJS + + "?detailsURL=" + + gDetailsURL + + queryString + + getVersionParams(params.version); + if (params.backgroundUpdate) { + setUpdateURL(updateURL); + gAUS.checkForBackgroundUpdates(); + if (params.continueFile) { + await continueFileHandler(params.continueFile); + } + if (params.waitForUpdateState) { + let whichUpdate = + params.waitForUpdateState == STATE_DOWNLOADING + ? "downloadingUpdate" + : "readyUpdate"; + await TestUtils.waitForCondition( + () => + gUpdateManager[whichUpdate] && + gUpdateManager[whichUpdate].state == params.waitForUpdateState, + "Waiting for update state: " + params.waitForUpdateState, + undefined, + 200 + ).catch(e => { + // Instead of throwing let the check below fail the test so the panel + // ID and the expected panel ID is printed in the log. + logTestInfo(e); + }); + // Display the UI after the update state equals the expected value. + is( + gUpdateManager[whichUpdate].state, + params.waitForUpdateState, + "The update state value should equal " + params.waitForUpdateState + ); + } + } else { + updateURL += "&slowUpdateCheck=1&useSlowDownloadMar=1"; + setUpdateURL(updateURL); + } + + aboutDialog = await waitForAboutDialog(); + registerCleanupFunction(() => { + aboutDialog.close(); + }); + + for (let step of steps) { + await processAboutDialogStep(step); + } + })(); +} + +/** + * Runs an about:preferences update test. This will set various common prefs for + * updating and runs the provided list of steps. + * + * @param params + * An object containing parameters used to run the test. + * @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 runAboutPrefsUpdateTest(params, steps) { + let tab; + function processAboutPrefsStep(step) { + if (typeof step == "function") { + return step(tab); + } + + const { panelId, checkActiveUpdate, continueFile, downloadInfo } = step; + return (async function() { + await SpecialPowers.spawn( + tab.linkedBrowser, + [{ panelId }], + async ({ panelId }) => { + let updateDeck = content.document.getElementById("updateDeck"); + await ContentTaskUtils.waitForCondition( + () => + updateDeck.selectedPanel && + updateDeck.selectedPanel.id == panelId, + "Waiting for the expected panel ID: " + panelId, + undefined, + 200 + ).catch(e => { + // Instead of throwing let the check below fail the test so the panel + // ID and the expected panel ID is printed in the log. Use info here + // instead of logTestInfo since logTestInfo isn't available in the + // content task. + info(e); + }); + is( + updateDeck.selectedPanel.id, + panelId, + "The panel ID should equal " + panelId + ); + } + ); + + if (checkActiveUpdate) { + let activeUpdate = + checkActiveUpdate.state == STATE_DOWNLOADING + ? gUpdateManager.downloadingUpdate + : gUpdateManager.readyUpdate; + ok(!!activeUpdate, "There should be an active update"); + is( + activeUpdate.state, + checkActiveUpdate.state, + "The active update state should equal " + checkActiveUpdate.state + ); + } else { + ok( + !gUpdateManager.downloadingUpdate, + "There should not be a downloading update" + ); + ok(!gUpdateManager.readyUpdate, "There should not be a ready update"); + } + + if (panelId == "downloading") { + for (let i = 0; i < downloadInfo.length; ++i) { + let data = downloadInfo[i]; + // The About Dialog tests always specify a continue file. + await continueFileHandler(continueFile); + let patch = getPatchOfType( + data.patchType, + gUpdateManager.downloadingUpdate + ); + // The update is removed early when the last download fails so check + // that there is a patch before proceeding. + let isLastPatch = i == downloadInfo.length - 1; + if (!isLastPatch || patch) { + let resultName = data.bitsResult ? "bitsResult" : "internalResult"; + patch.QueryInterface(Ci.nsIWritablePropertyBag); + await TestUtils.waitForCondition( + () => patch.getProperty(resultName) == data[resultName], + "Waiting for expected patch property " + + resultName + + " value: " + + data[resultName], + undefined, + 200 + ).catch(e => { + // Instead of throwing let the check below fail the test so the + // property value and the expected property value is printed in + // the log. + logTestInfo(e); + }); + is( + "" + patch.getProperty(resultName), + data[resultName], + "The patch property " + + resultName + + " value should equal " + + data[resultName] + ); + + // Check the download status text. It should be something like, + // "Downloading update — 1.4 of 1.4 KB". We check only the second + // part to make sure that the downloaded size is updated correctly. + let actualText = await SpecialPowers.spawn( + tab.linkedBrowser, + [], + () => content.document.getElementById("downloading").textContent + ); + let expectedSuffix = DownloadUtils.getTransferTotal( + data[resultName] == gBadSizeResult ? 0 : patch.size, + patch.size + ); + Assert.ok( + expectedSuffix, + "Sanity check: Expected download status text should be non-empty" + ); + Assert.ok( + actualText.endsWith(expectedSuffix), + "Download status text should end as expected: " + + JSON.stringify({ actualText, expectedSuffix }) + ); + } + } + } else if (continueFile) { + await continueFileHandler(continueFile); + } + + await SpecialPowers.spawn( + tab.linkedBrowser, + [{ panelId, gDetailsURL }], + async ({ panelId, gDetailsURL }) => { + let linkPanels = [ + "downloadFailed", + "manualUpdate", + "unsupportedSystem", + ]; + if (linkPanels.includes(panelId)) { + let selectedPanel = content.document.getElementById("updateDeck") + .selectedPanel; + // The unsupportedSystem panel uses the update's detailsURL and the + // downloadFailed and manualUpdate panels use the app.update.url.manual + // preference. + let selector = "label.text-link"; + // The downloadFailed panel in about:preferences uses an anchor + // instead of a label for the link. + if (selectedPanel.id == "downloadFailed") { + selector = "a.text-link"; + } + let link = selectedPanel.querySelector(selector); + is( + link.href, + gDetailsURL, + `The panel's link href should equal ${gDetailsURL}` + ); + } + + let buttonPanels = ["downloadAndInstall", "apply"]; + if (buttonPanels.includes(panelId)) { + let selectedPanel = content.document.getElementById("updateDeck") + .selectedPanel; + let buttonEl = selectedPanel.querySelector("button"); + // Note: The about:preferences doesn't focus the button like the + // About Dialog does. + ok(!buttonEl.disabled, "The button should be enabled"); + // Don't click the button on the apply panel since this will restart + // the application. + if (selectedPanel.id != "apply") { + buttonEl.click(); + } + } + } + ); + })(); + } + + return (async function() { + gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "1"); + await SpecialPowers.pushPrefEnv({ + set: [ + [PREF_APP_UPDATE_DISABLEDFORTESTING, false], + [PREF_APP_UPDATE_URL_MANUAL, gDetailsURL], + ], + }); + + await setupTestUpdater(); + + let queryString = params.queryString ? params.queryString : ""; + let updateURL = + URL_HTTP_UPDATE_SJS + + "?detailsURL=" + + gDetailsURL + + queryString + + getVersionParams(params.version); + if (params.backgroundUpdate) { + setUpdateURL(updateURL); + gAUS.checkForBackgroundUpdates(); + if (params.continueFile) { + await continueFileHandler(params.continueFile); + } + if (params.waitForUpdateState) { + // Wait until the update state equals the expected value before + // displaying the UI. + let whichUpdate = + params.waitForUpdateState == STATE_DOWNLOADING + ? "downloadingUpdate" + : "readyUpdate"; + await TestUtils.waitForCondition( + () => + gUpdateManager[whichUpdate] && + gUpdateManager[whichUpdate].state == params.waitForUpdateState, + "Waiting for update state: " + params.waitForUpdateState, + undefined, + 200 + ).catch(e => { + // Instead of throwing let the check below fail the test so the panel + // ID and the expected panel ID is printed in the log. + logTestInfo(e); + }); + is( + gUpdateManager[whichUpdate].state, + params.waitForUpdateState, + "The update state value should equal " + params.waitForUpdateState + ); + } + } else { + updateURL += "&slowUpdateCheck=1&useSlowDownloadMar=1"; + setUpdateURL(updateURL); + } + + tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:preferences" + ); + registerCleanupFunction(async () => { + await BrowserTestUtils.removeTab(tab); + }); + + // Scroll the UI into view so it is easier to troubleshoot tests. + await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { + content.document.getElementById("updatesCategory").scrollIntoView(); + }); + + for (let step of steps) { + await processAboutPrefsStep(step); + } + })(); +} + +/** + * Removes the modified update-settings.ini file so the updater will fail to + * stage an update. + */ +function removeUpdateSettingsIni() { + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_STAGING_ENABLED)) { + let greDir = getGREDir(); + let updateSettingsIniBak = greDir.clone(); + updateSettingsIniBak.append(FILE_UPDATE_SETTINGS_INI_BAK); + if (updateSettingsIniBak.exists()) { + let updateSettingsIni = greDir.clone(); + updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI); + updateSettingsIni.remove(false); + } + } +} + +/** + * Runs a telemetry update test. This will set various common prefs for + * updating, checks for an update, and waits for the specified observer + * notification. + * + * @param updateParams + * Params which will be sent to app_update.sjs. + * @param event + * The observer notification to wait for before proceeding. + * @param stageFailure (optional) + * Whether to force a staging failure by removing the modified + * update-settings.ini file. + * @return A promise which will resolve after the . + */ +function runTelemetryUpdateTest(updateParams, event, stageFailure = false) { + return (async function() { + Services.telemetry.clearScalars(); + gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1"); + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_DISABLEDFORTESTING, false]], + }); + + await setupTestUpdater(); + + if (stageFailure) { + removeUpdateSettingsIni(); + } + + let updateURL = + URL_HTTP_UPDATE_SJS + + "?detailsURL=" + + gDetailsURL + + updateParams + + getVersionParams(); + setUpdateURL(updateURL); + gAUS.checkForBackgroundUpdates(); + await waitForEvent(event); + })(); +} diff --git a/toolkit/mozapps/update/tests/browser/testConstants.js b/toolkit/mozapps/update/tests/browser/testConstants.js new file mode 100644 index 0000000000..915391054b --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/testConstants.js @@ -0,0 +1,7 @@ +const REL_PATH_DATA = "browser/toolkit/mozapps/update/tests/browser/"; +const URL_HOST = "http://127.0.0.1:8888"; +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"; |