Bug 1471628 - Add test for Captive Portal Service r=bagder draft
authorValentin Gosu <valentin.gosu@gmail.com>
Wed, 27 Jun 2018 17:19:42 +0200
changeset 811388 800a118ff82eb341dc41c44eb1f0d98e70722641
parent 810379 6e8e861540e6d8c85c73ab7b2afa1f027fb3750c
child 811464 120511f472e1bc1b126f81c56b7215e5ee6ac869
push id114292
push uservalentin.gosu@gmail.com
push dateWed, 27 Jun 2018 15:20:29 +0000
reviewersbagder
bugs1471628
milestone63.0a1
Bug 1471628 - Add test for Captive Portal Service r=bagder MozReview-Commit-ID: KgMN90ERTh5
netwerk/base/CaptivePortalService.cpp
netwerk/base/nsIOService.cpp
netwerk/test/unit/test_captive_portal_service.js
netwerk/test/unit/xpcshell.ini
--- a/netwerk/base/CaptivePortalService.cpp
+++ b/netwerk/base/CaptivePortalService.cpp
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/net/CaptivePortalService.h"
 #include "mozilla/Services.h"
 #include "mozilla/Preferences.h"
 #include "nsIObserverService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsXULAppAPI.h"
+#include "xpcpublic.h"
 
 static const char16_t kInterfaceName[] = u"captive-portal-inteface";
 
 static const char kOpenCaptivePortalLoginEvent[] = "captive-portal-login";
 static const char kAbortCaptivePortalLoginEvent[] = "captive-portal-login-abort";
 static const char kCaptivePortalLoginSuccessEvent[] = "captive-portal-login-success";
 
 static const uint32_t kDefaultInterval = 60*1000; // check every 60 seconds
@@ -132,16 +133,21 @@ CaptivePortalService::Initialize()
 
 nsresult
 CaptivePortalService::Start()
 {
   if (!mInitialized) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
+  if (xpc::AreNonLocalConnectionsDisabled()
+      && !Preferences::GetBool("network.captive-portal-service.testMode", false)) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
   if (XRE_GetProcessType() != GeckoProcessType_Default) {
     // Doesn't do anything if called in the content process.
     return NS_OK;
   }
 
   if (mStarted) {
     return NS_OK;
   }
--- a/netwerk/base/nsIOService.cpp
+++ b/netwerk/base/nsIOService.cpp
@@ -52,17 +52,16 @@
 #include "mozilla/dom/ClientInfo.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ServiceWorkerDescriptor.h"
 #include "mozilla/net/CaptivePortalService.h"
 #include "mozilla/Unused.h"
 #include "ReferrerPolicy.h"
 #include "nsContentSecurityManager.h"
 #include "nsContentUtils.h"
-#include "xpcpublic.h"
 
 namespace mozilla {
 namespace net {
 
 using mozilla::Maybe;
 using mozilla::dom::ClientInfo;
 using mozilla::dom::ServiceWorkerDescriptor;
 
@@ -1126,17 +1125,17 @@ nsIOService::SetConnectivityInternal(boo
     }
     mConnectivity = aConnectivity;
 
     // This is used for PR_Connect PR_Close telemetry so it is important that
     // we have statistic about network change event even if we are offline.
     mLastConnectivityChange = PR_IntervalNow();
 
     if (mCaptivePortalService) {
-        if (aConnectivity && !xpc::AreNonLocalConnectionsDisabled() && gCaptivePortalEnabled) {
+        if (aConnectivity && gCaptivePortalEnabled) {
             // This will also trigger a captive portal check for the new network
             static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Start();
         } else {
             static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop();
         }
     }
 
     nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
@@ -1270,17 +1269,17 @@ nsIOService::PrefsChanged(nsIPrefBranch 
         if (NS_SUCCEEDED(rv)) {
             mNetworkNotifyChanged = allow;
         }
     }
 
     if (!pref || strcmp(pref, NETWORK_CAPTIVE_PORTAL_PREF) == 0) {
         nsresult rv = prefs->GetBoolPref(NETWORK_CAPTIVE_PORTAL_PREF, &gCaptivePortalEnabled);
         if (NS_SUCCEEDED(rv) && mCaptivePortalService) {
-            if (gCaptivePortalEnabled && !xpc::AreNonLocalConnectionsDisabled()) {
+            if (gCaptivePortalEnabled) {
                 static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Start();
             } else {
                 static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop();
             }
         }
     }
 }
 
new file mode 100644
--- /dev/null
+++ b/netwerk/test/unit/test_captive_portal_service.js
@@ -0,0 +1,90 @@
+"use strict";
+
+ChromeUtils.import("resource://testing-common/httpd.js");
+ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
+
+var httpserver = null;
+XPCOMUtils.defineLazyGetter(this, "cpURI", function() {
+  return "http://localhost:" + httpserver.identity.primaryPort + "/captive.txt";
+});
+
+const SUCCESS_STRING = "success\n";
+let cpResponse = SUCCESS_STRING;
+function contentHandler(metadata, response)
+{
+  response.setHeader("Content-Type", "text/plain");
+  response.bodyOutputStream.write(cpResponse, cpResponse.length);
+}
+
+const PREF_CAPTIVE_ENABLED = "network.captive-portal-service.enabled";
+const PREF_CAPTIVE_TESTMODE = "network.captive-portal-service.testMode";
+const PREF_CAPTIVE_ENDPOINT = "captivedetect.canonicalURL";
+const PREF_CAPTIVE_MINTIME = "network.captive-portal-service.minInterval";
+const PREF_CAPTIVE_MAXTIME = "network.captive-portal-service.maxInterval";
+
+registerCleanupFunction(() => {
+  Services.prefs.clearUserPref(PREF_CAPTIVE_ENABLED);
+  Services.prefs.clearUserPref(PREF_CAPTIVE_TESTMODE);
+  Services.prefs.clearUserPref(PREF_CAPTIVE_ENDPOINT);
+  Services.prefs.clearUserPref(PREF_CAPTIVE_MINTIME);
+  Services.prefs.clearUserPref(PREF_CAPTIVE_MAXTIME);
+
+  httpserver.stop(() => {});
+});
+
+function observerPromise(topic) {
+  return new Promise(resolve => {
+    let observer = {
+      QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
+      observe: function(aSubject, aTopic, aData) {
+        if (aTopic == topic) {
+          Services.obs.removeObserver(observer, topic);
+          resolve(aData);
+        }
+      }
+    }
+    Services.obs.addObserver(observer, topic);
+  });
+}
+
+add_task(function setup(){
+  httpserver = new HttpServer();
+  httpserver.registerPathHandler("/captive.txt", contentHandler);
+  httpserver.start(-1);
+
+  Services.prefs.setCharPref(PREF_CAPTIVE_ENDPOINT, cpURI);
+  Services.prefs.setIntPref(PREF_CAPTIVE_MINTIME, 50);
+  Services.prefs.setIntPref(PREF_CAPTIVE_MAXTIME, 100);
+  Services.prefs.setBoolPref(PREF_CAPTIVE_TESTMODE, true);
+
+});
+
+add_task(async function test_simple()
+{
+  var cps = Cc["@mozilla.org/network/captive-portal-service;1"]
+              .getService(Ci.nsICaptivePortalService);
+  Services.prefs.setBoolPref(PREF_CAPTIVE_ENABLED, false);
+
+  equal(cps.state, Ci.nsICaptivePortalService.UNKNOWN);
+
+  let notification = observerPromise("network:captive-portal-connectivity");
+  // The service is started by nsIOService when the pref becomes true.
+  // We might want to add a method to do this in the future.
+  Services.prefs.setBoolPref(PREF_CAPTIVE_ENABLED, true);
+
+  let observerPayload = await notification;
+  equal(observerPayload, "clear");
+  equal(cps.state, Ci.nsICaptivePortalService.NOT_CAPTIVE);
+
+  cpResponse = "other";
+  notification = observerPromise("captive-portal-login");
+  cps.recheckCaptivePortal();
+  await notification;
+  equal(cps.state, Ci.nsICaptivePortalService.LOCKED_PORTAL);
+
+  cpResponse = SUCCESS_STRING;
+  notification = observerPromise("captive-portal-login-success");
+  cps.recheckCaptivePortal();
+  await notification;
+  equal(cps.state, Ci.nsICaptivePortalService.UNLOCKED_PORTAL);
+});
--- a/netwerk/test/unit/xpcshell.ini
+++ b/netwerk/test/unit/xpcshell.ini
@@ -413,8 +413,10 @@ skip-if = (verify && (os == 'linux'))
 # Test requires http/2, and http/2 server doesn't run on android.
 skip-if = os == "android"
 run-sequentially = node server exceptions dont replay well
 [test_trr.js]
 # http2-using tests require node available
 skip-if = os == "android"
 [test_ioservice.js]
 [test_substituting_protocol_handler.js]
+[test_captive_portal_service.js]
+