Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3773)

Unified Diff: chrome/browser/captive_portal/captive_portal_tab_helper_unittest.cc

Issue 10020051: Open a login tab on captive portal detection on SSL loads. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/captive_portal/captive_portal_tab_helper_unittest.cc
===================================================================
--- chrome/browser/captive_portal/captive_portal_tab_helper_unittest.cc (revision 0)
+++ chrome/browser/captive_portal/captive_portal_tab_helper_unittest.cc (revision 0)
@@ -0,0 +1,422 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/captive_portal/captive_portal_tab_helper.h"
+
+#include "base/message_loop.h"
+#include "chrome/browser/captive_portal/captive_portal_service.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "content/public/browser/notification_service.h"
+#include "net/base/net_errors.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace captive_portal {
+
+// Used for testing CaptivePortalTabHelper in isolation from the observer.
+// Exposes a number of private functions and mocks out others.
+class TestCaptivePortalTabHelper : public CaptivePortalTabHelper {
+ public:
+ // |profile| will only be used as a notification source, so we don't need
+ // an actual TestingProfile.
+ explicit TestCaptivePortalTabHelper(Profile* profile)
+ : CaptivePortalTabHelper(profile, NULL) {
+ }
+
+ bool TimerRunning() {
+ return slow_ssl_load_timer_.IsRunning();
+ }
+
+ void SetState(State state) {
+ CaptivePortalTabHelper::SetState(state);
+ }
+
+ State state() {
+ return CaptivePortalTabHelper::state();
+ }
+
+ void set_slow_ssl_load_time(base::TimeDelta slow_ssl_load_time) {
+ EXPECT_FALSE(TimerRunning());
+ CaptivePortalTabHelper::set_slow_ssl_load_time(slow_ssl_load_time);
+ }
+
+ // CaptivePortalTabHelper:
+ virtual void OnLoadStart(bool is_ssl) OVERRIDE {
+ CaptivePortalTabHelper::OnLoadStart(is_ssl);
+ }
+
+ virtual void OnLoadCommitted(int net_error) OVERRIDE {
+ CaptivePortalTabHelper::OnLoadCommitted(net_error);
+ }
+
+ virtual void OnAbort() OVERRIDE {
+ CaptivePortalTabHelper::OnAbort();
+ }
+
+ virtual void OnStopLoading() OVERRIDE {
+ CaptivePortalTabHelper::OnStopLoading();
+ }
+
+ MOCK_METHOD0(ReloadTab, void());
+ MOCK_METHOD0(MaybeOpenCaptivePortalLoginTab, void());
+ MOCK_METHOD0(CheckForCaptivePortal, void());
+};
+
+class CaptivePortalTabHelperTest : public testing::Test {
+ public:
+ CaptivePortalTabHelperTest() : tab_helper_(fake_profile()) {
+ // Most tests don't run the message loop, so don't use a timer for them.
+ tab_helper_.set_slow_ssl_load_time(base::TimeDelta());
+ }
+
+ virtual ~CaptivePortalTabHelperTest() {
+ }
+
+ // testing::Test
+ virtual void TearDown() OVERRIDE {
+ EXPECT_FALSE(tab_helper().TimerRunning());
+ // Run any pending operations, so we fail if we unexpectedly call a
+ // mocked out function.
+ MessageLoop::current()->RunAllPending();
+ }
+
+ void SendNotification(Result previous_result, Result result) {
+ CaptivePortalService::Results results;
+ results.previous_result = previous_result;
+ results.result = result;
+ content::NotificationService::current()->Notify(
+ chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT,
+ content::Source<Profile>(fake_profile()),
+ content::Details<CaptivePortalService::Results>(&results));
+ }
+
+ TestCaptivePortalTabHelper& tab_helper() { return tab_helper_; }
+
+ // This Profile should only be used as a notification source, so we
+ // initialize it to a value that will crash if we dereference it
+ // unexpectedly.
+ Profile* fake_profile() { return reinterpret_cast<Profile*>(17); }
+
+ private:
+ MessageLoop message_loop_;
+
+ testing::StrictMock<TestCaptivePortalTabHelper> tab_helper_;
+};
+
+// Simulates a slow SSL load when the Internet is connected.
+TEST_F(CaptivePortalTabHelperTest, InternetConnected) {
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
+
+ tab_helper().OnLoadStart(true);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_TIMER_RUNNING, tab_helper().state());
+ EXPECT_TRUE(tab_helper().TimerRunning());
+
+ EXPECT_CALL(tab_helper(), CheckForCaptivePortal()).Times(1);
+ MessageLoop::current()->RunAllPending();
+ EXPECT_FALSE(tab_helper().TimerRunning());
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_MAYBE_BROKEN_BY_PORTAL,
+ tab_helper().state());
+
+ SendNotification(RESULT_INTERNET_CONNECTED, RESULT_INTERNET_CONNECTED);
+
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
+ EXPECT_FALSE(tab_helper().TimerRunning());
+
+ tab_helper().OnLoadCommitted(net::OK);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
+}
+
+// Simulates a slow SSL load when the Internet is connected. In this case,
+// we get the timeout error before the timer triggers. Unlikely to happen
+// in practice, but we should still support it.
+TEST_F(CaptivePortalTabHelperTest, InternetConnectedTimeout) {
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
+
+ tab_helper().OnLoadStart(true);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_TIMER_RUNNING, tab_helper().state());
+ EXPECT_TRUE(tab_helper().TimerRunning());
+
+ EXPECT_CALL(tab_helper(), CheckForCaptivePortal()).Times(1);
+ tab_helper().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
+ EXPECT_FALSE(tab_helper().TimerRunning());
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_MAYBE_BROKEN_BY_PORTAL,
+ tab_helper().state());
+
+ SendNotification(RESULT_INTERNET_CONNECTED, RESULT_INTERNET_CONNECTED);
+
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
+}
+
+// Simulates a slow SSL load when captive portal checks return no response.
+TEST_F(CaptivePortalTabHelperTest, NoResponse) {
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
+
+ tab_helper().OnLoadStart(true);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_TIMER_RUNNING, tab_helper().state());
+ EXPECT_TRUE(tab_helper().TimerRunning());
+
+ EXPECT_CALL(tab_helper(), CheckForCaptivePortal()).Times(1);
+ MessageLoop::current()->RunAllPending();
+ EXPECT_FALSE(tab_helper().TimerRunning());
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_MAYBE_BROKEN_BY_PORTAL,
+ tab_helper().state());
+
+ SendNotification(RESULT_NO_RESPONSE, RESULT_NO_RESPONSE);
+
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
+ EXPECT_FALSE(tab_helper().TimerRunning());
+
+ tab_helper().OnLoadCommitted(net::OK);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
+}
+
+// Simulates a slow HTTP load that eventually times out when behind a captive
+// portal, and then times out.
+TEST_F(CaptivePortalTabHelperTest, DoesNothingOnHttp) {
+ tab_helper().OnLoadStart(false);
+ EXPECT_FALSE(tab_helper().TimerRunning());
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
+
+ SendNotification(RESULT_INTERNET_CONNECTED, RESULT_BEHIND_CAPTIVE_PORTAL);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
+ SendNotification(RESULT_BEHIND_CAPTIVE_PORTAL, RESULT_INTERNET_CONNECTED);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
+
+ tab_helper().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
+}
+
+// Simulate the normal login process. The user logs in before the tab finishes
+// loading the error page.
+TEST_F(CaptivePortalTabHelperTest, Login) {
+ tab_helper().OnLoadStart(true);
+
+ EXPECT_CALL(tab_helper(), CheckForCaptivePortal()).Times(1);
+ MessageLoop::current()->RunAllPending();
+ EXPECT_FALSE(tab_helper().TimerRunning());
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_MAYBE_BROKEN_BY_PORTAL,
+ tab_helper().state());
+
+ // The captive portal service tells us we're behind a captive portal.
+ // The tab helper should try and create a new login tab in response.
+ EXPECT_CALL(tab_helper(), MaybeOpenCaptivePortalLoginTab()).Times(1);
+ SendNotification(RESULT_INTERNET_CONNECTED, RESULT_BEHIND_CAPTIVE_PORTAL);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_BROKEN_BY_PORTAL,
+ tab_helper().state());
+ EXPECT_FALSE(tab_helper().TimerRunning());
+
+ // The user logs on from another tab, and a captive portal check is triggered.
+ SendNotification(RESULT_BEHIND_CAPTIVE_PORTAL, RESULT_INTERNET_CONNECTED);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NEEDS_RELOAD, tab_helper().state());
+
+ // The error page commits, which should start an asynchronous reload.
+ tab_helper().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NEEDS_RELOAD, tab_helper().state());
+
+ EXPECT_CALL(tab_helper(), ReloadTab()).Times(1);
+ MessageLoop::current()->RunAllPending();
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
+}
+
+// Simulate the normal login process. The user logs in after the tab finishes
+// loading the error page.
+TEST_F(CaptivePortalTabHelperTest, LoginLate) {
+ tab_helper().OnLoadStart(true);
+
+ EXPECT_CALL(tab_helper(), CheckForCaptivePortal()).Times(1);
+ MessageLoop::current()->RunAllPending();
+ EXPECT_FALSE(tab_helper().TimerRunning());
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_MAYBE_BROKEN_BY_PORTAL,
+ tab_helper().state());
+
+ // The captive portal service tells us we're behind a captive portal.
+ // The tab helper should try and create a new login tab in response.
+ EXPECT_CALL(tab_helper(), MaybeOpenCaptivePortalLoginTab()).Times(1);
+ SendNotification(RESULT_INTERNET_CONNECTED, RESULT_BEHIND_CAPTIVE_PORTAL);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_BROKEN_BY_PORTAL,
+ tab_helper().state());
+ EXPECT_FALSE(tab_helper().TimerRunning());
+
+ // The error page commits.
+ tab_helper().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_BROKEN_BY_PORTAL,
+ tab_helper().state());
+
+ // The user logs on from another tab, and a captive portal check is triggered.
+ EXPECT_CALL(tab_helper(), ReloadTab()).Times(1);
+ SendNotification(RESULT_BEHIND_CAPTIVE_PORTAL, RESULT_INTERNET_CONNECTED);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
+}
+
+// Simulate a login after the tab times out unexpectedly quickly.
+TEST_F(CaptivePortalTabHelperTest, TimeoutFast) {
+ tab_helper().OnLoadStart(true);
+
+ // The error page commits, which should trigger a captive portal check,
+ // since the timer's still running.
+ EXPECT_CALL(tab_helper(), CheckForCaptivePortal()).Times(1);
+ tab_helper().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_MAYBE_BROKEN_BY_PORTAL,
+ tab_helper().state());
+
+ // The captive portal service tells us we're behind a captive portal.
+ // The tab helper should try and create a new login tab in response.
+ EXPECT_CALL(tab_helper(), MaybeOpenCaptivePortalLoginTab()).Times(1);
+ SendNotification(RESULT_INTERNET_CONNECTED, RESULT_BEHIND_CAPTIVE_PORTAL);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_BROKEN_BY_PORTAL,
+ tab_helper().state());
+ EXPECT_FALSE(tab_helper().TimerRunning());
+
+ // The user logs on from another tab, and a captive portal check is triggered.
+ EXPECT_CALL(tab_helper(), ReloadTab()).Times(1);
+ SendNotification(RESULT_BEHIND_CAPTIVE_PORTAL, RESULT_INTERNET_CONNECTED);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
+}
+
+// Simulate the case that a user has already logged in by the time we get
+// our first captive portal result.
+TEST_F(CaptivePortalTabHelperTest, AlreadyLoggedIn) {
+ tab_helper().OnLoadStart(true);
+
+ EXPECT_CALL(tab_helper(), CheckForCaptivePortal()).Times(1);
+ MessageLoop::current()->RunAllPending();
+ EXPECT_FALSE(tab_helper().TimerRunning());
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_MAYBE_BROKEN_BY_PORTAL,
+ tab_helper().state());
+
+ // The user has already logged in. Since the last result indicated we
+ // were behind a captive portal, we decide to reload the tab when we can.
+ SendNotification(RESULT_BEHIND_CAPTIVE_PORTAL, RESULT_INTERNET_CONNECTED);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NEEDS_RELOAD, tab_helper().state());
+
+ // The error page commits, which should start an asynchronous reload.
+ tab_helper().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NEEDS_RELOAD, tab_helper().state());
+
+ EXPECT_CALL(tab_helper(), ReloadTab()).Times(1);
+ MessageLoop::current()->RunAllPending();
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
+}
+
+// Simulate the case that a user has already logged in before the timer
+// triggers.
+TEST_F(CaptivePortalTabHelperTest, AlreadyLoggedInBeforeTimerTriggers) {
+ tab_helper().OnLoadStart(true);
+
+ EXPECT_CALL(tab_helper(), CheckForCaptivePortal()).Times(1);
+ MessageLoop::current()->RunAllPending();
+ EXPECT_FALSE(tab_helper().TimerRunning());
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_MAYBE_BROKEN_BY_PORTAL,
+ tab_helper().state());
+
+ // The user has already logged in. Since the last result indicated we
+ // were behind a captive portal, we decide to reload the tab when we can.
+ SendNotification(RESULT_BEHIND_CAPTIVE_PORTAL, RESULT_INTERNET_CONNECTED);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NEEDS_RELOAD, tab_helper().state());
+
+ // The error page commits, which should start an asynchronous reload.
+ tab_helper().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NEEDS_RELOAD, tab_helper().state());
+
+ EXPECT_CALL(tab_helper(), ReloadTab()).Times(1);
+ MessageLoop::current()->RunAllPending();
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
+}
+
+// Simulate the user logging in while the timer is still running. May happen
+// if the tab is reloaded just before logging in on another tab.
+TEST_F(CaptivePortalTabHelperTest, LogInWhileTimerRunning) {
+ tab_helper().OnLoadStart(true);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_TIMER_RUNNING, tab_helper().state());
+ EXPECT_TRUE(tab_helper().TimerRunning());
+
+ // The user has already logged in.
+ SendNotification(RESULT_BEHIND_CAPTIVE_PORTAL, RESULT_INTERNET_CONNECTED);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NEEDS_RELOAD, tab_helper().state());
+
+ // The error page commits, which should start an asynchronous reload.
+ tab_helper().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NEEDS_RELOAD, tab_helper().state());
+
+ EXPECT_CALL(tab_helper(), ReloadTab()).Times(1);
+ MessageLoop::current()->RunAllPending();
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
+}
+
+// Same as above, but the original load completes instead of committing.
+TEST_F(CaptivePortalTabHelperTest, LogInWhileTimerRunningNoError) {
+ tab_helper().OnLoadStart(true);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_TIMER_RUNNING, tab_helper().state());
+ EXPECT_TRUE(tab_helper().TimerRunning());
+
+ // The user has already logged in.
+ SendNotification(RESULT_BEHIND_CAPTIVE_PORTAL, RESULT_INTERNET_CONNECTED);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NEEDS_RELOAD, tab_helper().state());
+
+ // The error page commits, which should start an asynchronous reload.
+ tab_helper().OnLoadCommitted(net::OK);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
+}
+
+// Simulate a normal page load in a login tab while behind a captive portal.
+TEST_F(CaptivePortalTabHelperTest, LoginTabPageLoad) {
+ tab_helper().SetState(
+ CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE);
+ tab_helper().OnLoadStart(false);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE,
+ tab_helper().state());
+
+ tab_helper().OnLoadCommitted(net::OK);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE,
+ tab_helper().state());
+
+ EXPECT_CALL(tab_helper(), CheckForCaptivePortal()).Times(1);
+ tab_helper().OnStopLoading();
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE,
+ tab_helper().state());
+
+ SendNotification(RESULT_BEHIND_CAPTIVE_PORTAL, RESULT_BEHIND_CAPTIVE_PORTAL);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE,
+ tab_helper().state());
+}
+
+// Simulate a logging on through a login tab via an HTTP page.
+TEST_F(CaptivePortalTabHelperTest, LoginTabLogin) {
+ tab_helper().SetState(
+ CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE);
+ tab_helper().OnLoadStart(false);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE,
+ tab_helper().state());
+
+ tab_helper().OnLoadCommitted(net::OK);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE,
+ tab_helper().state());
+
+ EXPECT_CALL(tab_helper(), CheckForCaptivePortal()).Times(1);
+ tab_helper().OnStopLoading();
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE,
+ tab_helper().state());
+
+ SendNotification(RESULT_BEHIND_CAPTIVE_PORTAL, RESULT_INTERNET_CONNECTED);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_NONE, tab_helper().state());
+}
+
+// Simulate an SSL connection timout in a login tab while behind a captive
+// portal.
+TEST_F(CaptivePortalTabHelperTest, LoginTabTimeout) {
+ // Load starts.
+ tab_helper().SetState(
+ CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE);
+ tab_helper().OnLoadStart(true);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE,
+ tab_helper().state());
+ EXPECT_FALSE(tab_helper().TimerRunning());
+
+ // Page times out.
+ tab_helper().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
+ EXPECT_EQ(CaptivePortalTabHelper::STATE_CAPTIVE_PORTAL_LOGIN_PAGE,
+ tab_helper().state());
+}
+
+} // namespace captive_portal

Powered by Google App Engine
This is Rietveld 408576698