Bug 1446833: Part 1 - Stop throwing raw numeric error codes in xpcshell/head.js. r=florian
authorKris Maglione <maglione.k@gmail.com>
Sun, 18 Mar 2018 15:27:18 -0700
changeset 409128 bd915117e71156d6518ee948f61105263dd5bb4a
parent 409127 3ac9277c6aa998205da26e03e7facc7c1e9eca5b
child 409129 e2a78fa784c69656b837b9034d008046576fa60f
push id33676
push usertoros@mozilla.com
push dateWed, 21 Mar 2018 10:03:44 +0000
treeherdermozilla-central@e636edf00e6f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersflorian
bugs1446833
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1446833: Part 1 - Stop throwing raw numeric error codes in xpcshell/head.js. r=florian The xpcshell harness expects to catch the Cr result codes that it throws, but it often fails when an assertion is used in asynchronous code. That results in a raw numeric error code being reported, with no location information available to figure out why or where the test is failing. Throwing an actual Exception object maintains location information for use when the error is reported. MozReview-Commit-ID: InuytWhDxBP
testing/xpcshell/head.js
--- a/testing/xpcshell/head.js
+++ b/testing/xpcshell/head.js
@@ -30,23 +30,25 @@ var _cleanupFunctions = [];
 var _pendingTimers = [];
 var _profileInitialized = false;
 
 // Assigned in do_load_child_test_harness.
 var _XPCSHELL_PROCESS;
 
 // Register the testing-common resource protocol early, to have access to its
 // modules.
-var _Services = ChromeUtils.import("resource://gre/modules/Services.jsm", {}).Services;
+var _Services = ChromeUtils.import("resource://gre/modules/Services.jsm", null).Services;
 _register_modules_protocol_handler();
 
-var _PromiseTestUtils = ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm", {}).PromiseTestUtils;
-var _Task = ChromeUtils.import("resource://gre/modules/Task.jsm", {}).Task;
+var _PromiseTestUtils = ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm", null).PromiseTestUtils;
+var _Task = ChromeUtils.import("resource://gre/modules/Task.jsm", null).Task;
 
-let _NetUtil = ChromeUtils.import("resource://gre/modules/NetUtil.jsm", {}).NetUtil;
+let _NetUtil = ChromeUtils.import("resource://gre/modules/NetUtil.jsm", null).NetUtil;
+
+let _XPCOMUtils = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", null).XPCOMUtils;
 
 Cu.importGlobalProperties(["XMLHttpRequest"]);
 
 // Support a common assertion library, Assert.jsm.
 var AssertCls = ChromeUtils.import("resource://testing-common/Assert.jsm", null).Assert;
 // Pass a custom report function for xpcshell-test style reporting.
 var Assert = new AssertCls(function(err, message, stack) {
   if (err) {
@@ -126,23 +128,17 @@ try {
 // of the test.
 try {
   let levelNames = {};
   for (let level of ["debug", "info", "warn", "error"]) {
     levelNames[Ci.nsIConsoleMessage[level]] = level;
   }
 
   let listener = {
-    QueryInterface(iid) {
-      if (!iid.equals(Ci.nsISupports) &&
-          !iid.equals(Ci.nsIConsoleListener)) {
-        throw Cr.NS_NOINTERFACE;
-      }
-      return this;
-    },
+    QueryInterface: _XPCOMUtils.generateQI(["nsIConsoleListener"]),
     observe(msg) {
       if (typeof info === "function")
         info("CONSOLE_MESSAGE: (" + levelNames[msg.logLevel] + ") " + msg.toString());
     }
   };
   // Don't use _Services.console here as it causes one of the devtools tests
   // to fail, probably due to initializing Services.console too early.
   // eslint-disable-next-line mozilla/use-services
@@ -173,23 +169,17 @@ function _Timer(func, delay) {
   var timer = Cc["@mozilla.org/timer;1"]
                 .createInstance(Ci.nsITimer);
   timer.initWithCallback(this, delay + _timerFuzz, timer.TYPE_ONE_SHOT);
 
   // Keep timer alive until it fires
   _pendingTimers.push(timer);
 }
 _Timer.prototype = {
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsITimerCallback) ||
-        iid.equals(Ci.nsISupports))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
+  QueryInterface: _XPCOMUtils.generateQI(["nsITimerCallback"]),
 
   notify(timer) {
     _pendingTimers.splice(_pendingTimers.indexOf(timer), 1);
 
     // The current nsITimer implementation can undershoot, but even if it
     // couldn't, paranoia is probably a virtue here given the potential for
     // random orange on tinderboxen.
     var end = Date.now();
@@ -274,30 +264,24 @@ var _fakeIdleService = {
       delete this.originalFactory;
     }
   },
 
   factory: {
     // nsIFactory
     createInstance(aOuter, aIID) {
       if (aOuter) {
-        throw Cr.NS_ERROR_NO_AGGREGATION;
+        throw Components.Exception("", Cr.NS_ERROR_NO_AGGREGATION);
       }
       return _fakeIdleService.QueryInterface(aIID);
     },
     lockFactory(aLock) {
-      throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+      throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
     },
-    QueryInterface(aIID) {
-      if (aIID.equals(Ci.nsIFactory) ||
-          aIID.equals(Ci.nsISupports)) {
-        return this;
-      }
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    }
+    QueryInterface: _XPCOMUtils.generateQI(["nsIFactory"]),
   },
 
   // nsIIdleService
   get idleTime() {
     return 0;
   },
   addIdleObserver() {},
   removeIdleObserver() {},
@@ -306,17 +290,17 @@ var _fakeIdleService = {
     // Useful for testing purposes, see test_get_idle.js.
     if (aIID.equals(Ci.nsIFactory)) {
       return this.factory;
     }
     if (aIID.equals(Ci.nsIIdleService) ||
         aIID.equals(Ci.nsISupports)) {
       return this;
     }
-    throw Cr.NS_ERROR_NO_INTERFACE;
+    throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE);
   }
 };
 
 /**
  * Restores the idle service factory if needed and returns the service's handle.
  * @return A handle to the idle service.
  */
 function do_get_idle() {
@@ -539,17 +523,17 @@ function _execute_test() {
   } catch (e) {
     _passed = false;
     // do_check failures are already logged and set _quit to true and throw
     // NS_ERROR_ABORT. If both of those are true it is likely this exception
     // has already been logged so there is no need to log it again. It's
     // possible that this will mask an NS_ERROR_ABORT that happens after a
     // do_check failure though.
 
-    if (!_quit || e != Cr.NS_ERROR_ABORT) {
+    if (!_quit || e.result != Cr.NS_ERROR_ABORT) {
       let extra = {};
       if (e.fileName) {
         extra.source_file = e.fileName;
         if (e.lineNumber) {
           extra.line_number = e.lineNumber;
         }
       } else {
         extra.source_file = "xpcshell/head.js";
@@ -684,17 +668,17 @@ function executeSoon(callback, aName) {
       try {
         callback();
       } catch (e) {
         // do_check failures are already logged and set _quit to true and throw
         // NS_ERROR_ABORT. If both of those are true it is likely this exception
         // has already been logged so there is no need to log it again. It's
         // possible that this will mask an NS_ERROR_ABORT that happens after a
         // do_check failure though.
-        if (!_quit || e != Cr.NS_ERROR_ABORT) {
+        if (!_quit || e.result != Cr.NS_ERROR_ABORT) {
           let stack = e.stack ? _format_stack(e.stack) : null;
           _testLogger.testStatus(_TEST_NAME,
                                  funcName,
                                  "FAIL",
                                  "PASS",
                                  _exception_message(e),
                                  stack);
           _do_quit();
@@ -731,17 +715,17 @@ function do_throw(error, stack) {
                     });
   _abort_failed_test();
 }
 
 function _abort_failed_test() {
   // Called to abort the test run after all failures are logged.
   _passed = false;
   _do_quit();
-  throw Cr.NS_ERROR_ABORT;
+  throw Components.Exception("", Cr.NS_ERROR_ABORT);
 }
 
 function _format_stack(stack) {
   let normalized;
   if (stack instanceof Ci.nsIStackFrame) {
     let frames = [];
     for (let frame = stack; frame; frame = frame.caller) {
       frames.push(frame.filename + ":" + frame.name + ":" + frame.lineNumber);
@@ -782,17 +766,17 @@ function do_report_unexpected_exception(
 
   _passed = false;
   _testLogger.error(text + "Unexpected exception " + _exception_message(ex),
                     {
                       source_file: filename,
                       stack: _format_stack(ex.stack)
                     });
   _do_quit();
-  throw Cr.NS_ERROR_ABORT;
+  throw Components.Exception("", Cr.NS_ERROR_ABORT);
 }
 
 function do_note_exception(ex, text) {
   let filename = Components.stack.caller.filename;
   _testLogger.info(text + "Swallowed exception " + _exception_message(ex),
                    {
                      source_file: filename,
                      stack: _format_stack(ex.stack)
@@ -1113,23 +1097,17 @@ function do_get_profile(notifyProfileAft
     getFile(prop, persistent) {
       persistent.value = true;
       if (prop == "ProfD" || prop == "ProfLD" || prop == "ProfDS" ||
           prop == "ProfLDS" || prop == "TmpD") {
         return file.clone();
       }
       return null;
     },
-    QueryInterface(iid) {
-      if (iid.equals(Ci.nsIDirectoryServiceProvider) ||
-          iid.equals(Ci.nsISupports)) {
-        return this;
-      }
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    }
+    QueryInterface: _XPCOMUtils.generateQI(["nsIDirectoryServiceProvider"]),
   };
   _Services.dirsvc.QueryInterface(Ci.nsIDirectoryService)
            .registerProvider(provider);
 
   // We need to update the crash events directory when the profile changes.
   if (runningInParent &&
       "@mozilla.org/toolkit/crash-reporter;1" in Cc) {
     let crashReporter =