Bug 934066 - Add a simple parent/child synchronization mechanism for xpcshell tests. r=ted
authorJosh Matthews <josh@joshmatthews.net>
Sat, 02 Nov 2013 09:37:46 -0400
changeset 156823 43c41041fe372ade34f0a5fba3f9a81fb90cf05d
parent 156822 dcb2d54db943cbdd41e0c766a58911528c682d99
child 156824 85e1efd3e28b47a5a88fd76bdd8b8cc5a969aba2
push id25689
push userryanvm@gmail.com
push dateThu, 21 Nov 2013 19:41:16 +0000
treeherdermozilla-central@cdbe5f3adeff [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersted
bugs934066
milestone28.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 934066 - Add a simple parent/child synchronization mechanism for xpcshell tests. r=ted
dom/tests/unit/test_geolocation_reset_accuracy.js
dom/tests/unit/test_geolocation_reset_accuracy_wrap.js
testing/xpcshell/head.js
--- a/dom/tests/unit/test_geolocation_reset_accuracy.js
+++ b/dom/tests/unit/test_geolocation_reset_accuracy.js
@@ -27,16 +27,17 @@ var provider = {
   watch: function() {
   },
   shutdown: function() {
   },
   setHighAccuracy: function(enable) {
     this._isHigh = enable;
     if (enable) {
       this._seenHigh = true;
+      do_execute_soon(stop_high_accuracy_watch);
     }
   },
   _isHigh: false,
   _seenHigh: false
 };
 
 let runningInParent = true;
 try {
@@ -53,16 +54,19 @@ function successCallback()
 }
 
 function errorCallback()
 {
   do_check_true(false);
   do_test_finished();
 }
 
+var geolocation;
+var watchID2;
+
 function run_test()
 {
   if (runningInParent) {
     // XPCShell does not get a profile by default. The geolocation service
     // depends on the settings service which uses IndexedDB and IndexedDB
     // needs a place where it can store databases.
     do_get_profile();
 
@@ -73,28 +77,31 @@ function run_test()
     catMan.nsICategoryManager.addCategoryEntry(categoryName, "unit test",
                                                providerContract, false, true);
 
     var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
     prefs.setBoolPref("geo.testing.ignore_ipc_principal", true);
     prefs.setBoolPref("geo.wifi.scan", false);
   }
 
-  let geolocation = Cc["@mozilla.org/geolocation;1"].createInstance(Ci.nsISupports);
-
   do_test_pending();
 
+  geolocation = Cc["@mozilla.org/geolocation;1"].createInstance(Ci.nsISupports);
   let watchID1 = geolocation.watchPosition(successCallback, errorCallback);
-  let watchID2 = geolocation.watchPosition(successCallback, errorCallback,
-                                           {enableHighAccuracy: true});
+  watchID2 = geolocation.watchPosition(successCallback, errorCallback,
+                                       {enableHighAccuracy: true});
 
-  do_timeout(5000, function() {
+  if (!runningInParent) {
+    do_await_remote_message('high_acc_enabled', stop_high_accuracy_watch);
+  }
+}
+
+function stop_high_accuracy_watch() {
     geolocation.clearWatch(watchID2);
-    do_timeout(1000, check_results);
-  });
+    check_results();
 }
 
 function check_results()
 {
   if (runningInParent) {
     // check the provider was set to high accuracy during the test
     do_check_true(provider._seenHigh);
     // check the provider is not currently set to high accuracy
--- a/dom/tests/unit/test_geolocation_reset_accuracy_wrap.js
+++ b/dom/tests/unit/test_geolocation_reset_accuracy_wrap.js
@@ -27,16 +27,17 @@ var provider = {
   watch: function() {
   },
   shutdown: function() {
   },
   setHighAccuracy: function(enable) {
     this._isHigh = enable;
     if (enable) {
       this._seenHigh = true;
+      do_send_remote_message('high_acc_enabled');
     }
   },
   _isHigh: false,
   _seenHigh: false
 };
 
 function run_test()
 {
--- a/testing/xpcshell/head.js
+++ b/testing/xpcshell/head.js
@@ -1232,16 +1232,58 @@ function run_test_in_child(testFile, opt
   var testPath = do_get_file(testFile).path.replace(/\\/g, "/");
   do_test_pending("run in child");
   sendCommand("_log('child_test_start', {_message: 'CHILD-TEST-STARTED'}); "
               + "const _TEST_FILE=['" + testPath + "']; _execute_test(); "
               + "_log('child_test_end', {_message: 'CHILD-TEST-COMPLETED'});",
               callback);
 }
 
+/**
+ * Execute a given function as soon as a particular cross-process message is received.
+ * Must be paired with do_send_remote_message or equivalent ProcessMessageManager calls.
+ */
+function do_await_remote_message(name, callback)
+{
+  var listener = {
+    receiveMessage: function(message) {
+      if (message.name == name) {
+        mm.removeMessageListener(name, listener);
+        callback();
+        do_test_finished();
+      }
+    }
+  };
+
+  var mm;
+  if (runningInParent) {
+    mm = Cc["@mozilla.org/parentprocessmessagemanager;1"].getService(Ci.nsIMessageBroadcaster);
+  } else {
+    mm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsISyncMessageSender);
+  }
+  do_test_pending();
+  mm.addMessageListener(name, listener);
+}
+
+/**
+ * Asynchronously send a message to all remote processes. Pairs with do_await_remote_message
+ * or equivalent ProcessMessageManager listeners.
+ */
+function do_send_remote_message(name) {
+  var mm;
+  var sender;
+  if (runningInParent) {
+    mm = Cc["@mozilla.org/parentprocessmessagemanager;1"].getService(Ci.nsIMessageBroadcaster);
+    sender = 'broadcastAsyncMessage';
+  } else {
+    mm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsISyncMessageSender);
+    sender = 'sendAsyncMessage';
+  }
+  mm[sender](name);
+}
 
 /**
  * Add a test function to the list of tests that are to be run asynchronously.
  *
  * Each test function must call run_next_test() when it's done. Test files
  * should call run_next_test() in their run_test function to execute all
  * async tests.
  *