Bug 816306: Part 2 - Report update HTTP errors to Gaia, and accompanying tests. r=fabrice
authorMarshall Culpepper <marshall@mozilla.com>
Thu, 10 Jan 2013 18:13:39 +0100
changeset 118437 5be4511b8225fbe33e31b584027dd896bb49bbf1
parent 118436 64624cab8dc13a6d78d25a8f131c88c4d5746778
child 118438 b28889afccbee0dd3709230913d85acc0138f723
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersfabrice
bugs816306
milestone21.0a1
Bug 816306: Part 2 - Report update HTTP errors to Gaia, and accompanying tests. r=fabrice
b2g/components/UpdatePrompt.js
toolkit/mozapps/update/test/marionette/data/bad.xml
toolkit/mozapps/update/test/marionette/data/err.cgi
toolkit/mozapps/update/test/marionette/update-tests.ini
toolkit/mozapps/update/test/marionette/update_test_status.js
toolkit/mozapps/update/test/marionette/update_test_status.py
--- a/b2g/components/UpdatePrompt.js
+++ b/b2g/components/UpdatePrompt.js
@@ -17,17 +17,18 @@ let log =
   VERBOSE ?
   function log_dump(msg) { dump("UpdatePrompt: "+ msg +"\n"); } :
   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 NETWORK_ERROR_OFFLINE = 111;
-const FILE_ERROR_TOO_BIG = 112;
+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");
 
 XPCOMUtils.defineLazyServiceGetter(Services, "um",
@@ -67,18 +68,28 @@ UpdateCheckListener.prototype = {
       return;
     }
 
     this._updatePrompt.setUpdateStatus("check-complete");
     this._updatePrompt.showUpdateAvailable(update);
   },
 
   onError: function UCL_onError(request, update) {
-    if (update.errorCode == NETWORK_ERROR_OFFLINE) {
+    // nsIUpdate uses a signed integer for errorCode while any platform errors
+    // require all 32 bits.
+    let errorCode = update.errorCode >>> 0;
+    let isNSError = (errorCode >>> 31) == 1;
+
+    if (errorCode == NETWORK_ERROR_OFFLINE) {
       this._updatePrompt.setUpdateStatus("retry-when-online");
+    } else if (isNSError) {
+      this._updatePrompt.setUpdateStatus("check-error-" + errorCode);
+    } else if (errorCode > HTTP_ERROR_OFFSET) {
+      let httpErrorCode = errorCode - HTTP_ERROR_OFFSET;
+      this._updatePrompt.setUpdateStatus("check-error-http-" + httpErrorCode);
     }
 
     Services.aus.QueryInterface(Ci.nsIUpdateCheckListener);
     Services.aus.onError(request, update);
   },
 
   onProgress: function UCL_onProgress(request, position, totalSize) {
     Services.aus.QueryInterface(Ci.nsIUpdateCheckListener);
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/update/test/marionette/data/bad.xml
@@ -0,0 +1,1 @@
+<updates
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/update/test/marionette/data/err.cgi
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+print "Status: $QUERY_STRING\r\n\r\n"
--- a/toolkit/mozapps/update/test/marionette/update-tests.ini
+++ b/toolkit/mozapps/update/test/marionette/update-tests.ini
@@ -1,7 +1,8 @@
 [DEFAULT]
 smoketest = false
 
 [update_test_ota_simple.py]
+[update_test_status.py]
 
 ; smoketests
 [include:update-smoketests.ini]
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/update/test/marionette/update_test_status.js
@@ -0,0 +1,56 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const TEST_URL = "http://localhost";
+
+setPref("b2g.update.apply-idle-timeout", 0);
+setPref("app.update.backgroundErrors", 0);
+setPref("app.update.backgroundMaxErrors", 100);
+
+function forceCheckAndTestStatus(status, next) {
+  let mozSettings = window.navigator.mozSettings;
+  let forceSent = false;
+
+  mozSettings.addObserver("gecko.updateStatus", function statusObserver(setting) {
+    if (!forceSent) {
+      return;
+    }
+
+    mozSettings.removeObserver("gecko.updateStatus", statusObserver);
+    is(setting.settingValue, status, "gecko.updateStatus");
+    next();
+  });
+
+  sendContentEvent("force-update-check");
+  forceSent = true;
+}
+
+function testBadXml() {
+  setPref("app.update.url.override", TEST_URL + "/bad.xml");
+  forceCheckAndTestStatus("check-error-http-200", testAccessDenied);
+}
+
+function testAccessDenied() {
+  setPref("app.update.url.override", TEST_URL + "/cgi-bin/err.cgi?403");
+  forceCheckAndTestStatus("check-error-http-403", testNoUpdateXml);
+}
+
+function testNoUpdateXml() {
+  setPref("app.update.url.override", TEST_URL + "/none.html");
+  forceCheckAndTestStatus("check-error-http-404", testInternalServerError);
+}
+
+function testInternalServerError() {
+  setPref("app.update.url.override", TEST_URL + "/cgi-bin/err.cgi?500");
+  forceCheckAndTestStatus("check-error-http-500", testBadHostStatus);
+}
+
+function testBadHostStatus() {
+  setPref("app.update.url.override", "http://bad-host-doesnt-exist-sorry.com");
+  forceCheckAndTestStatus("check-error-" + Cr.NS_ERROR_UNKNOWN_HOST, cleanUp);
+}
+
+// Update test functions
+function preUpdate() {
+  testBadXml();
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/update/test/marionette/update_test_status.py
@@ -0,0 +1,29 @@
+from b2g_update_test import B2GUpdateTestCase, OTA, FOTA
+import os
+
+this_dir = os.path.abspath(os.path.dirname(__file__))
+update_test_dir = os.path.dirname(this_dir)
+
+class UpdateTestStatus(B2GUpdateTestCase):
+    B2G_UPDATES = "/data/local/b2g-updates"
+
+    def setUp(self):
+        # Stage a phony update to get the http server up and running
+        mar_path = os.path.join(update_test_dir, "unit", "data", "simple.mar")
+        self.stage_update(complete_mar=mar_path)
+
+        bad_xml = os.path.join(this_dir, "data", "bad.xml")
+        err_cgi = os.path.join(this_dir, "data", "err.cgi")
+        self.runner.adb.push(bad_xml, self.B2G_UPDATES + "/bad.xml")
+        self.runner.adb.shell("mkdir " + self.B2G_UPDATES + "/cgi-bin")
+        self.runner.adb.push(err_cgi, self.B2G_UPDATES + "/cgi-bin/err.cgi")
+        self.runner.adb.shell("chmod 755 " + self.B2G_UPDATES + "/cgi-bin/err.cgi")
+
+        B2GUpdateTestCase.setUp(self)
+
+    def test_status(self):
+        self.marionette.set_script_timeout(30 * 1000)
+        status_js = os.path.join(os.path.dirname(__file__),
+                                 "update_test_status.js")
+        self.execute_update_test(status_js)
+