Bug 833708: Correctly set the active update's errorCode when there isn't enough space in Gonk. r=dhylands
authorMarshall Culpepper <marshall@mozilla.com>
Mon, 25 Feb 2013 21:11:14 -0600
changeset 122982 feed6a5160f70779642c3928884cbe619df4eeb9
parent 122981 162b001c77eaa9f3ac5443f9ae4fe12b3bbc9fb3
child 122983 70814e7dbcb8df7962edaa69dd7d62801526c8a5
push id1387
push userphilringnalda@gmail.com
push dateTue, 26 Feb 2013 22:32:56 +0000
treeherderfx-team@ad4cc4e97774 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdhylands
bugs833708
milestone22.0a1
Bug 833708: Correctly set the active update's errorCode when there isn't enough space in Gonk. r=dhylands
b2g/components/DirectoryProvider.js
b2g/components/UpdatePrompt.js
toolkit/mozapps/update/nsUpdateService.js
toolkit/mozapps/update/test/unit/test_bug833708.js
toolkit/mozapps/update/test/unit/xpcshell.ini
--- a/b2g/components/DirectoryProvider.js
+++ b/b2g/components/DirectoryProvider.js
@@ -43,16 +43,17 @@ let log =
 
 function DirectoryProvider() {
 }
 
 DirectoryProvider.prototype = {
   classID: Components.ID("{9181eb7c-6f87-11e1-90b1-4f59d80dd2e5}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider]),
+  _xpcom_factory: XPCOMUtils.generateSingletonFactory(DirectoryProvider),
 
   getFile: function dp_getFile(prop, persistent) {
 #ifdef MOZ_WIDGET_GONK
     let localProps = ["cachePDir", "webappsDir", "PrefD", "indexedDBPDir",
                       "permissionDBPDir", "UpdRootD"];
     if (localProps.indexOf(prop) != -1) {
       let file = Cc["@mozilla.org/file/local;1"]
                    .createInstance(Ci.nsILocalFile)
@@ -100,16 +101,17 @@ DirectoryProvider.prototype = {
     }
     return requiredSpace <= stat.freeBytes;
   },
 
   findUpdateDirWithFreeSpace: function dp_findUpdateDirWithFreeSpace(requiredSpace, subdir) {
     if (!Services.volumeService) {
       return this.createUpdatesDir(LOCAL_DIR, subdir);
     }
+
     let activeUpdate = Services.um.activeUpdate;
     if (gUseSDCard) {
       if (this.volumeHasFreeSpace(gExtStorage, requiredSpace)) {
         let extUpdateDir = this.createUpdatesDir(gExtStorage, subdir);
         if (extUpdateDir !== null) {
           return extUpdateDir;
         }
         log("Warning: " + gExtStorage + " has enough free space for update " +
@@ -153,17 +155,18 @@ DirectoryProvider.prototype = {
       return updateDir;
     }
 
     // If we've gotten this far, there isn't enough free space to download the patch
     // on either external storage or /data/local. All we can do is report the
     // error and let upstream code handle it more gracefully.
     log("Error: No volume found with " + requiredSpace + " bytes for downloading"+
         " update " + activeUpdate.name);
-    throw Cr.NS_ERROR_FILE_TOO_BIG;
+    activeUpdate.errorCode = Cr.NS_ERROR_FILE_TOO_BIG;
+    return null;
   },
 
   createUpdatesDir: function dp_createUpdatesDir(root, subdir) {
       let dir = Cc["@mozilla.org/file/local;1"]
                    .createInstance(Ci.nsILocalFile);
       dir.initWithPath(root);
       if (!dir.isWritable()) {
         log("Error: " + dir.path + " isn't writable");
--- a/b2g/components/UpdatePrompt.js
+++ b/b2g/components/UpdatePrompt.js
@@ -20,17 +20,16 @@ let log =
   function log_noop(msg) { };
 
 const PREF_APPLY_PROMPT_TIMEOUT          = "b2g.update.apply-prompt-timeout";
 const PREF_APPLY_IDLE_TIMEOUT            = "b2g.update.apply-idle-timeout";
 const PREF_DOWNLOAD_WATCHDOG_TIMEOUT     = "b2g.update.download-watchdog-timeout";
 const PREF_DOWNLOAD_WATCHDOG_MAX_RETRIES = "b2g.update.download-watchdog-max-retries";
 
 const NETWORK_ERROR_OFFLINE = 111;
-const FILE_ERROR_TOO_BIG    = 112;
 const HTTP_ERROR_OFFSET     = 1000;
 
 const STATE_DOWNLOADING = 'downloading';
 
 XPCOMUtils.defineLazyServiceGetter(Services, "aus",
                                    "@mozilla.org/updates/update-service;1",
                                    "nsIApplicationUpdateService");
 
@@ -309,17 +308,18 @@ UpdatePrompt.prototype = {
     // Services.aus.downloadUpdate will return immediately and not
     // call showUpdateDownloaded, so we detect this.
     if (aUpdate.state == "applied" && aUpdate.errorCode == 0) {
       this.showUpdateDownloaded(aUpdate, true);
       return;
     }
 
     log("Error downloading update " + aUpdate.name + ": " + aUpdate.errorCode);
-    if (aUpdate.errorCode == FILE_ERROR_TOO_BIG) {
+    let errorCode = aUpdate.errorCode >>> 0;
+    if (errorCode == Cr.NS_ERROR_FILE_TOO_BIG) {
       aUpdate.statusText = "file-too-big";
     }
     this.showUpdateError(aUpdate);
   },
 
   handleDownloadCancel: function UP_handleDownloadCancel() {
     log("Pausing download");
     Services.aus.pauseDownload();
--- a/toolkit/mozapps/update/nsUpdateService.js
+++ b/toolkit/mozapps/update/nsUpdateService.js
@@ -3494,19 +3494,16 @@ Downloader.prototype = {
    * Get the nsIFile to use for downloading the active update's selected patch
    */
   _getUpdateArchiveFile: function Downloader__getUpdateArchiveFile() {
     var updateArchive;
 #ifdef USE_UPDATE_ARCHIVE_DIR
     try {
       updateArchive = FileUtils.getDir(KEY_UPDATE_ARCHIVE_DIR, [], true);
     } catch (e) {
-      if (e == Cr.NS_ERROR_FILE_TOO_BIG) {
-        this._update.errorCode = FILE_ERROR_TOO_BIG;
-      }
       return null;
     }
 #else
     updateArchive = getUpdatesDir().clone();
 #endif
 
     updateArchive.append(FILE_UPDATE_ARCHIVE);
     return updateArchive;
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/update/test/unit/test_bug833708.js
@@ -0,0 +1,100 @@
+/* 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/.
+ */
+
+AUS_Cu.import("resource://gre/modules/FileUtils.jsm");
+const KEY_UPDATE_ARCHIVE_DIR = "UpdArchD"
+
+let gActiveUpdate = null;
+
+function FakeDirProvider() {}
+FakeDirProvider.prototype = {
+  classID: Components.ID("{f30b43a7-2bfa-4e5f-8c4f-abc7dd4ac486}"),
+  QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsIDirectoryServiceProvider]),
+
+  getFile: function(prop, persistent) {
+    if (prop == KEY_UPDATE_ARCHIVE_DIR) {
+      if (gActiveUpdate) {
+        gActiveUpdate.errorCode = AUS_Cr.NS_ERROR_FILE_TOO_BIG;
+      }
+    }
+    return null;
+  }
+};
+
+function run_test() {
+  do_test_pending();
+  do_register_cleanup(end_test);
+  DEBUG_AUS_TEST = true;
+
+  removeUpdateDirsAndFiles();
+  setUpdateURLOverride();
+  overrideXHR(xhr_pt1);
+  standardInit();
+
+  logTestInfo("testing that error codes set from a directory provider propagate" +
+              "up to AUS.downloadUpdate() correctly");
+
+  gDirProvider = new FakeDirProvider();
+  gOldProvider = AUS_Cc["@mozilla.org/browser/directory-provider;1"]
+                       .createInstance(AUS_Ci.nsIDirectoryServiceProvider);
+
+  gDirService = AUS_Cc["@mozilla.org/file/directory_service;1"]
+                       .getService(AUS_Ci.nsIProperties);
+
+  gDirService.unregisterProvider(gOldProvider);
+  gDirService.registerProvider(gDirProvider);
+
+  Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, true);
+  do_execute_soon(run_test_pt1);
+}
+
+function xhr_pt1() {
+  gXHR.status = 200;
+  gXHR.responseText = gResponseBody;
+  try {
+    var parser = AUS_Cc["@mozilla.org/xmlextras/domparser;1"].
+                 createInstance(AUS_Ci.nsIDOMParser);
+    gXHR.responseXML = parser.parseFromString(gResponseBody, "application/xml");
+  }
+  catch(e) {
+    gXHR.responseXML = null;
+  }
+  var e = { target: gXHR };
+  gXHR.onload(e);
+}
+
+function run_test_pt1() {
+  gUpdates = null;
+  gUpdateCount = null;
+  gCheckFunc = check_test_pt1;
+
+
+  let patches = getRemotePatchString();
+  let updates = getRemoteUpdateString(patches);
+  gResponseBody = getRemoteUpdatesXMLString(updates);
+  gUpdateChecker.checkForUpdates(updateCheckListener, true);
+}
+
+function check_test_pt1() {
+  do_check_eq(gUpdateCount, 1);
+
+  gActiveUpdate = gUpdates[0];
+  do_check_neq(gActiveUpdate, null);
+
+  let state = gAUS.downloadUpdate(gActiveUpdate, true);
+  do_check_eq(state, "null");
+  do_check_eq(gActiveUpdate.errorCode >>> 0 , AUS_Cr.NS_ERROR_FILE_TOO_BIG);
+  do_test_finished();
+}
+
+function end_test() {
+  gDirService.unregisterProvider(gDirProvider);
+  gDirService.registerProvider(gOldProvider);
+  gActiveUpdate = null;
+  gDirService = null;
+  gDirProvider = null;
+
+  cleanUp();
+}
--- a/toolkit/mozapps/update/test/unit/xpcshell.ini
+++ b/toolkit/mozapps/update/test/unit/xpcshell.ini
@@ -27,8 +27,10 @@ skip-if = os == 'android'
 [include:xpcshell_updater_windows.ini]
 run-if = os == 'win'
 [include:xpcshell_updater_xp_unix.ini]
 run-if = os == 'linux' || os == 'mac' || os == 'sunos'
 [test_bug595059.js]
 skip-if = toolkit == "gonk"
 reason = custom nsIUpdatePrompt
 [test_bug794211.js]
+[test_bug833708.js]
+run-if = toolkit == "gonk"