Bug 934066 - Add a simple parent/child synchronization mechanism for xpcshell tests. r=ted, a=test-only
authorJosh Matthews <josh@joshmatthews.net>
Sat, 02 Nov 2013 09:37:46 -0400
changeset 166562 ca538a59ea6bfa948336cd6c579c95501c4231e5
parent 166561 f1ede627d38ec8b5fc593ffc4bdb5358fdfd598e
child 166563 70b82e1762c2381658c891169e48039a89236300
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersted, test-only
bugs934066
milestone27.0a2
Bug 934066 - Add a simple parent/child synchronization mechanism for xpcshell tests. r=ted, a=test-only
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
@@ -1205,16 +1205,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.
  *