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 |