Bug 1332295 - do_register_cleanup should support generators and async functions. r=ted
☠☠ backed out by 20a8536b0bfa ☠ ☠
authorMarco Bonardo <mbonardo@mozilla.com>
Thu, 19 Jan 2017 16:07:46 +0100
changeset 340807 c13c36e04303
parent 340806 369da2e22d43
child 340808 ddd06f373719
push id31311
push userphilringnalda@gmail.com
push dateSun, 05 Feb 2017 00:36:57 +0000
treeherdermozilla-central@e581572bc9c1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersted
bugs1332295
milestone54.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 1332295 - do_register_cleanup should support generators and async functions. r=ted MozReview-Commit-ID: BPCwPlWQ8G0
testing/xpcshell/head.js
testing/xpcshell/selftest.py
--- a/testing/xpcshell/head.js
+++ b/testing/xpcshell/head.js
@@ -18,16 +18,17 @@ var _pendingTimers = [];
 var _profileInitialized = false;
 
 // Register the testing-common resource protocol early, to have access to its
 // modules.
 _register_modules_protocol_handler();
 
 var _Promise = Components.utils.import("resource://gre/modules/Promise.jsm", {}).Promise;
 var _PromiseTestUtils = Components.utils.import("resource://testing-common/PromiseTestUtils.jsm", {}).PromiseTestUtils;
+var _Task = Components.utils.import("resource://gre/modules/Task.jsm", {}).Task;
 Components.utils.importGlobalProperties(["XMLHttpRequest"]);
 
 // Support a common assertion library, Assert.jsm.
 var AssertCls = Components.utils.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) {
     do_report_result(false, err.message, err.stack);
@@ -592,37 +593,32 @@ function _execute_test() {
     }
     _testLogger.error(_exception_message(ex),
                       {
                         stack: _format_stack(stack),
                         source_file: filename
                       });
   };
 
-  let func;
-  while ((func = _cleanupFunctions.pop())) {
-    let result;
-    try {
-      result = func();
-    } catch (ex) {
-      reportCleanupError(ex);
-      continue;
-    }
-    if (result && typeof result == "object"
-        && "then" in result && typeof result.then == "function") {
-      // This is a promise, wait until it is satisfied before proceeding
-      let complete = false;
-      let promise = result.then(null, reportCleanupError);
-      promise = promise.then(() => complete = true);
-      let thr = Components.classes["@mozilla.org/thread-manager;1"]
-                  .getService().currentThread;
-      while (!complete) {
-        thr.processNextEvent(true);
+  let complete = _cleanupFunctions.length == 0;
+  _Task.spawn(function*() {
+    for (let func of _cleanupFunctions.reverse()) {
+      try {
+        yield func();
+      } catch (ex) {
+        reportCleanupError(ex);
       }
     }
+    _cleanupFunctions = [];
+  }.bind(this)).catch(reportCleanupError)
+               .then(() => complete = true);
+  let thr = Components.classes["@mozilla.org/thread-manager;1"]
+                      .getService().currentThread;
+  while (!complete) {
+    thr.processNextEvent(true);
   }
 
   // Restore idle service to avoid leaks.
   _fakeIdleService.deactivate();
 
   if (_profileInitialized) {
     // Since we have a profile, we will notify profile shutdown topics at
     // the end of the current test, to ensure correct cleanup on shutdown.
@@ -1510,17 +1506,16 @@ function add_task(funcOrProperties, func
     _gTests.push([funcOrProperties, func]);
   } else {
     do_throw("add_task() should take a function or an object and a function");
   }
 }
 add_task.only = _add_only.bind(undefined, add_task);
 add_task.skip = _add_skip.bind(undefined, add_task);
 
-var _Task = Components.utils.import("resource://gre/modules/Task.jsm", {}).Task;
 _Task.Debugging.maintainStack = true;
 
 
 /**
  * Runs the next test function from the list of async tests.
  */
 var _gRunningTest = null;
 var _gTestIndex = 0; // The index of the currently running test.
--- a/testing/xpcshell/selftest.py
+++ b/testing/xpcshell/selftest.py
@@ -296,22 +296,32 @@ ASYNC_CLEANUP = '''
 function run_test() {
   Components.utils.import("resource://gre/modules/Promise.jsm", this);
 
   // The list of checkpoints in the order we encounter them.
   let checkpoints = [];
 
   // Cleanup tasks, in reverse order
   do_register_cleanup(function cleanup_checkout() {
-    do_check_eq(checkpoints.join(""), "1234");
+    do_check_eq(checkpoints.join(""), "123456");
     do_print("At this stage, the test has succeeded");
     do_throw("Throwing an error to force displaying the log");
   });
 
   do_register_cleanup(function sync_cleanup_2() {
+    checkpoints.push(6);
+  });
+
+  do_register_cleanup(async function async_cleanup_4() {
+    await undefined;
+    checkpoints.push(5);
+  });
+
+  do_register_cleanup(function* async_cleanup_3() {
+    yield undefined;
     checkpoints.push(4);
   });
 
   do_register_cleanup(function async_cleanup_2() {
     let deferred = Promise.defer();
     do_execute_soon(deferred.resolve);
     return deferred.promise.then(function() {
       checkpoints.push(3);
@@ -1179,23 +1189,22 @@ add_test({
         self.writeFile("test_verbose.js", ADD_TEST_VERBOSE)
         self.writeManifest([("test_verbose.js", "verbose = true")])
 
         self.assertTestResult(True)
         self.assertInLog("a message from do_print")
 
     def testAsyncCleanup(self):
         """
-        Check that do_register_cleanup handles nicely cleanup tasks that
-        return a promise
+        Check that do_register_cleanup handles nicely async cleanup tasks
         """
         self.writeFile("test_asyncCleanup.js", ASYNC_CLEANUP)
         self.writeManifest(["test_asyncCleanup.js"])
         self.assertTestResult(False)
-        self.assertInLog("\"1234\" == \"1234\"")
+        self.assertInLog("\"123456\" == \"123456\"")
         self.assertInLog("At this stage, the test has succeeded")
         self.assertInLog("Throwing an error to force displaying the log")
 
     def testNoRunTestAddTest(self):
         """
         Check that add_test() works fine without run_test() in the test file.
         """
         self.writeFile("test_noRunTestAddTest.js", NO_RUN_TEST_ADD_TEST)