Bug 1057689 - Add xpcshell test checking correct notifications and app-offline state r=jduell
authorValentin Gosu <valentin.gosu@gmail.com>
Mon, 01 Sep 2014 17:29:28 +0300
changeset 290106 1686be775813bb687d3e015313f85957ee28af59
parent 290105 c143be9df73e9f540d8d406590e934afb8dea3de
child 290107 530267937f67c9ba12b7b442caff7a36aed1d9e9
push id19656
push usergwagner@mozilla.com
push dateMon, 04 Apr 2016 13:43:23 +0000
treeherderb2g-inbound@e99061fde28a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjduell
bugs1057689
milestone48.0a1
Bug 1057689 - Add xpcshell test checking correct notifications and app-offline state r=jduell Changes NeckoParent to send the ipdl message if !UsingNeckoIPCSecurity() because xpcshell tests don't have TabParents. MozReview-Commit-ID: F50WXzg3TIA
netwerk/ipc/NeckoParent.cpp
netwerk/test/unit_ipc/child_app_offline_notifications.js
netwerk/test/unit_ipc/test_app_offline_notifications.js
netwerk/test/unit_ipc/xpcshell.ini
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -1001,16 +1001,27 @@ NeckoParent::OfflineNotification(nsISupp
         }
         // Once we found the targetAppId, we don't need to continue
         break;
       }
     }
 
   }
 
+  // XPCShells don't have any TabParents
+  // Just send the ipdl message to the child process.
+  if (!UsingNeckoIPCSecurity()) {
+    bool offline = false;
+    gIOService->IsAppOffline(targetAppId, &offline);
+    if (!SendAppOfflineStatus(targetAppId, offline)) {
+      printf_stderr("NeckoParent: "
+                    "SendAppOfflineStatus failed for targetAppId: %u\n", targetAppId);
+    }
+  }
+
   return NS_OK;
 }
 
 bool
 NeckoParent::RecvRemoveSchedulingContext(const nsCString& scid)
 {
   nsCOMPtr<nsISchedulingContextService> scsvc =
     do_GetService("@mozilla.org/network/scheduling-context-service;1");
new file mode 100644
--- /dev/null
+++ b/netwerk/test/unit_ipc/child_app_offline_notifications.js
@@ -0,0 +1,43 @@
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+function is_app_offline(appId) {
+  let ioservice = Cc['@mozilla.org/network/io-service;1'].
+    getService(Ci.nsIIOService);
+  return ioservice.isAppOffline(appId);
+}
+
+var events_observed_no = 0;
+
+// Holds the last observed app-offline event
+var info = null;
+function observer(aSubject, aTopic, aData) {
+  events_observed_no++;
+  info = aSubject.QueryInterface(Ci.nsIAppOfflineInfo);
+  dump("ChildObserver - subject: {" + aSubject.appId + ", " + aSubject.mode + "} ");
+}
+
+// Add observer for the app-offline notification
+function run_test() {
+  Services.obs.addObserver(observer, "network:app-offline-status-changed", false);
+}
+
+// Chech that the app has the proper offline status
+function check_status(appId, status)
+{
+  do_check_eq(is_app_offline(appId), status == Ci.nsIAppOfflineInfo.OFFLINE);
+}
+
+// Check that the app has the proper offline status
+// and that the correct notification has been received
+function check_notification_and_status(appId, status) {
+  do_check_eq(info.appId, appId);
+  do_check_eq(info.mode, status);
+  do_check_eq(is_app_offline(appId), status == Ci.nsIAppOfflineInfo.OFFLINE);
+}
+
+// Remove the observer from the child process
+function finished() {
+  Services.obs.removeObserver(observer, "network:app-offline-status-changed");
+  do_check_eq(events_observed_no, 2);
+}
new file mode 100644
--- /dev/null
+++ b/netwerk/test/unit_ipc/test_app_offline_notifications.js
@@ -0,0 +1,102 @@
+// Checks that app-offline notifications are received in both the parent
+// and the child process, and that after receiving the notification
+// isAppOffline returns the correct value
+
+
+Cu.import("resource://testing-common/httpd.js");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+var test_index = 0;
+var APP_ID = 42;
+var events_observed_no = 0;
+
+function set_app_offline(appId, offline) {
+  let ioservice = Cc['@mozilla.org/network/io-service;1'].
+    getService(Ci.nsIIOService);
+  ioservice.setAppOffline(appId, offline);
+}
+
+function is_app_offline(appId) {
+  let ioservice = Cc['@mozilla.org/network/io-service;1'].
+    getService(Ci.nsIIOService);
+  return ioservice.isAppOffline(appId);
+}
+
+// The expected offline status after running each function,
+// and the next function that should be run.
+
+//                       test0   test1   test2   test3   test4
+let expected_offline = [ false,  true,   true,  false,  false];
+let callbacks =        [ test1,  test2,  test3,  test4,  finished];
+
+function observer(aSubject, aTopic, aData) {
+  events_observed_no++;
+  let info = aSubject.QueryInterface(Ci.nsIAppOfflineInfo);
+  dump("ParentObserver - subject: {" + aSubject.appId + ", " + aSubject.mode + "} " +
+       "topic: " + aTopic + "\n");
+
+  // Check that the correct offline status is in place
+  do_check_eq(is_app_offline(APP_ID), expected_offline[test_index]);
+
+  // Execute the callback for the current test
+  do_execute_soon(callbacks[test_index]);
+}
+
+function run_test() {
+  Services.obs.addObserver(observer, "network:app-offline-status-changed", false);
+
+  test_index = 0;
+  do_check_eq(is_app_offline(APP_ID), expected_offline[test_index]) // The app should be online at first
+  run_test_in_child("child_app_offline_notifications.js", test0);
+}
+
+// Check that the app is online by default in the child
+function test0() {
+  dump("parent: RUNNING: test0\n");
+  test_index = 0;
+  sendCommand('check_status('+APP_ID+','+Ci.nsIAppOfflineInfo.ONLINE+');\n', test1);
+}
+
+// Set the app OFFLINE
+// Check that the notification is emmited in the parent process
+// The observer function will execute test2 which does the check in the child
+function test1() {
+  dump("parent: RUNNING: test1\n");
+  test_index = 1;
+  set_app_offline(APP_ID, Ci.nsIAppOfflineInfo.OFFLINE);
+}
+
+// Checks that child process sees the app OFFLINE
+function test2() {
+  dump("parent: RUNNING: test2\n");
+  test_index = 2;
+  sendCommand('check_notification_and_status('+APP_ID+','+Ci.nsIAppOfflineInfo.OFFLINE+');\n', test3);
+}
+
+// Set the app ONLINE
+// Chech that the notification is received in the parent
+// The observer function will execute test3 and do the check in the child
+function test3() {
+  dump("parent: RUNNING: test3\n");
+  test_index = 3;
+  set_app_offline(APP_ID, Ci.nsIAppOfflineInfo.ONLINE);
+}
+
+// Chech that the app is back online
+function test4() {
+  dump("parent: RUNNING: test4\n");
+  test_index = 4;
+  sendCommand('check_notification_and_status('+APP_ID+','+Ci.nsIAppOfflineInfo.ONLINE+');\n', function() {
+    // Send command to unregister observer on the child
+    sendCommand('finished();\n', finished);
+  });
+}
+
+// Remove observer and end test
+function finished() {
+  dump("parent: RUNNING: finished\n");
+  Services.obs.removeObserver(observer, "network:app-offline-status-changed");
+  do_check_eq(events_observed_no, 2);
+  do_test_finished();
+}
--- a/netwerk/test/unit_ipc/xpcshell.ini
+++ b/netwerk/test/unit_ipc/xpcshell.ini
@@ -1,13 +1,14 @@
 [DEFAULT]
 head = head_channels_clone.js head_cc.js
 tail =
 skip-if = toolkit == 'android' || toolkit == 'gonk'
 support-files = child_app_offline.js
+	child_app_offline_notifications.js
 
 [test_bug528292_wrap.js]
 [test_bug248970_cookie_wrap.js]
 [test_cacheflags_wrap.js]
 [test_cache_jar_wrap.js]
 [test_channel_close_wrap.js]
 [test_cookie_header_wrap.js]
 [test_cookiejars_wrap.js]
@@ -37,8 +38,9 @@ skip-if = true
 [test_simple_wrap.js]
 [test_synthesized_response_wrap.js]
 [test_xmlhttprequest_wrap.js]
 [test_XHR_redirects.js]
 [test_redirect_history_wrap.js]
 [test_reply_without_content_type_wrap.js]
 [test_app_offline_http.js]
 [test_getHost_wrap.js]
+[test_app_offline_notifications.js]