| // 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_reloader.h" |
| |
| #include "base/callback.h" |
| #include "base/message_loop/message_loop.h" |
| #include "chrome/browser/captive_portal/captive_portal_service.h" |
| #include "chrome/test/base/chrome_render_view_host_test_harness.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/interstitial_page.h" |
| #include "content/public/browser/interstitial_page_delegate.h" |
| #include "content/public/browser/web_contents.h" |
| #include "net/base/net_errors.h" |
| #include "net/cert/cert_status_flags.h" |
| #include "net/ssl/ssl_info.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "url/gurl.h" |
| |
| namespace captive_portal { |
| |
| // Used for testing CaptivePortalTabReloader in isolation from the observer. |
| // Exposes a number of private functions and mocks out others. |
| class TestCaptivePortalTabReloader : public CaptivePortalTabReloader { |
| public: |
| explicit TestCaptivePortalTabReloader(content::WebContents* web_contents) |
| : CaptivePortalTabReloader(NULL, |
| web_contents, |
| base::Callback<void(void)>()) { |
| } |
| |
| virtual ~TestCaptivePortalTabReloader() { |
| } |
| |
| bool TimerRunning() { |
| return slow_ssl_load_timer_.IsRunning(); |
| } |
| |
| // The following methods are aliased so they can be publicly accessed by the |
| // unit tests. |
| |
| State state() const { |
| return CaptivePortalTabReloader::state(); |
| } |
| |
| void set_slow_ssl_load_time(base::TimeDelta slow_ssl_load_time) { |
| EXPECT_FALSE(TimerRunning()); |
| CaptivePortalTabReloader::set_slow_ssl_load_time(slow_ssl_load_time); |
| } |
| |
| // CaptivePortalTabReloader: |
| MOCK_METHOD0(ReloadTab, void()); |
| MOCK_METHOD0(MaybeOpenCaptivePortalLoginTab, void()); |
| MOCK_METHOD0(CheckForCaptivePortal, void()); |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(TestCaptivePortalTabReloader); |
| }; |
| |
| // Used to test behavior when a WebContents is showing an interstitial page. |
| class MockInterstitialPageDelegate : public content::InterstitialPageDelegate { |
| public: |
| // The newly created MockInterstitialPageDelegate will be owned by the |
| // WebContents' InterstitialPage, and cleaned up when the WebContents |
| // destroys it. |
| explicit MockInterstitialPageDelegate( |
| content::WebContents* web_contents) { |
| content::InterstitialPage* interstitial_page = |
| content::InterstitialPage::Create( |
| web_contents, true, GURL("http://blah"), this); |
| interstitial_page->DontCreateViewForTesting(); |
| interstitial_page->Show(); |
| } |
| |
| virtual ~MockInterstitialPageDelegate() { |
| } |
| |
| private: |
| // InterstitialPageDelegate implementation: |
| virtual std::string GetHTMLContents() OVERRIDE { |
| return "HTML Contents"; |
| } |
| |
| DISALLOW_COPY_AND_ASSIGN(MockInterstitialPageDelegate); |
| }; |
| |
| class CaptivePortalTabReloaderTest : public ChromeRenderViewHostTestHarness { |
| public: |
| // testing::Test: |
| virtual void SetUp() OVERRIDE { |
| ChromeRenderViewHostTestHarness::SetUp(); |
| tab_reloader_.reset(new testing::StrictMock<TestCaptivePortalTabReloader>( |
| web_contents())); |
| |
| // Most tests don't run the message loop, so don't use a timer for them. |
| tab_reloader_->set_slow_ssl_load_time(base::TimeDelta()); |
| } |
| |
| virtual void TearDown() OVERRIDE { |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| tab_reloader_.reset(NULL); |
| ChromeRenderViewHostTestHarness::TearDown(); |
| } |
| |
| TestCaptivePortalTabReloader& tab_reloader() { return *tab_reloader_.get(); } |
| |
| private: |
| scoped_ptr<TestCaptivePortalTabReloader> tab_reloader_; |
| }; |
| |
| // Simulates a slow SSL load when the Internet is connected. |
| TEST_F(CaptivePortalTabReloaderTest, InternetConnected) { |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| |
| tab_reloader().OnLoadStart(true); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING, |
| tab_reloader().state()); |
| EXPECT_TRUE(tab_reloader().TimerRunning()); |
| |
| EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1); |
| base::MessageLoop::current()->RunUntilIdle(); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL, |
| tab_reloader().state()); |
| |
| tab_reloader().OnCaptivePortalResults(RESULT_INTERNET_CONNECTED, |
| RESULT_INTERNET_CONNECTED); |
| |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| |
| tab_reloader().OnLoadCommitted(net::OK); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| } |
| |
| // Simulates a slow SSL load when the Internet is connected. In this case, |
| // the timeout error occurs before the timer triggers. Unlikely to happen |
| // in practice, but best if it still works. |
| TEST_F(CaptivePortalTabReloaderTest, InternetConnectedTimeout) { |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| |
| tab_reloader().OnLoadStart(true); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING, |
| tab_reloader().state()); |
| EXPECT_TRUE(tab_reloader().TimerRunning()); |
| |
| EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1); |
| tab_reloader().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL, |
| tab_reloader().state()); |
| |
| tab_reloader().OnCaptivePortalResults(RESULT_INTERNET_CONNECTED, |
| RESULT_INTERNET_CONNECTED); |
| |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| } |
| |
| // Simulates a slow SSL load when captive portal checks return no response. |
| TEST_F(CaptivePortalTabReloaderTest, NoResponse) { |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| |
| tab_reloader().OnLoadStart(true); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING, |
| tab_reloader().state()); |
| EXPECT_TRUE(tab_reloader().TimerRunning()); |
| |
| EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1); |
| base::MessageLoop::current()->RunUntilIdle(); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL, |
| tab_reloader().state()); |
| |
| tab_reloader().OnCaptivePortalResults(RESULT_NO_RESPONSE, RESULT_NO_RESPONSE); |
| |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| |
| tab_reloader().OnLoadCommitted(net::OK); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| } |
| |
| // Simulates a slow HTTP load when behind a captive portal, that eventually. |
| // tiems out. Since it's HTTP, the TabReloader should do nothing. |
| TEST_F(CaptivePortalTabReloaderTest, DoesNothingOnHttp) { |
| tab_reloader().OnLoadStart(false); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| |
| tab_reloader().OnCaptivePortalResults(RESULT_INTERNET_CONNECTED, |
| RESULT_BEHIND_CAPTIVE_PORTAL); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| |
| // The user logs in. |
| tab_reloader().OnCaptivePortalResults(RESULT_BEHIND_CAPTIVE_PORTAL, |
| RESULT_INTERNET_CONNECTED); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| |
| // The page times out. |
| tab_reloader().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| } |
| |
| // Simulate the normal login process. The user logs in before the error page |
| // in the original tab commits. |
| TEST_F(CaptivePortalTabReloaderTest, Login) { |
| tab_reloader().OnLoadStart(true); |
| |
| EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1); |
| base::MessageLoop::current()->RunUntilIdle(); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL, |
| tab_reloader().state()); |
| |
| // The captive portal service detects a captive portal. The TabReloader |
| // should try and create a new login tab in response. |
| EXPECT_CALL(tab_reloader(), MaybeOpenCaptivePortalLoginTab()).Times(1); |
| tab_reloader().OnCaptivePortalResults(RESULT_INTERNET_CONNECTED, |
| RESULT_BEHIND_CAPTIVE_PORTAL); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL, |
| tab_reloader().state()); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| |
| // The user logs on from another tab, and a captive portal check is triggered. |
| tab_reloader().OnCaptivePortalResults(RESULT_BEHIND_CAPTIVE_PORTAL, |
| RESULT_INTERNET_CONNECTED); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD, |
| tab_reloader().state()); |
| |
| // The error page commits, which should start an asynchronous reload. |
| tab_reloader().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD, |
| tab_reloader().state()); |
| |
| EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1); |
| base::MessageLoop::current()->RunUntilIdle(); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| } |
| |
| // Simulate the normal login process. The user logs in after the tab finishes |
| // loading the error page. |
| TEST_F(CaptivePortalTabReloaderTest, LoginLate) { |
| tab_reloader().OnLoadStart(true); |
| |
| EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1); |
| base::MessageLoop::current()->RunUntilIdle(); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL, |
| tab_reloader().state()); |
| |
| // The captive portal service detects a captive portal. The TabReloader |
| // should try and create a new login tab in response. |
| EXPECT_CALL(tab_reloader(), MaybeOpenCaptivePortalLoginTab()).Times(1); |
| tab_reloader().OnCaptivePortalResults(RESULT_INTERNET_CONNECTED, |
| RESULT_BEHIND_CAPTIVE_PORTAL); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL, |
| tab_reloader().state()); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| |
| // The error page commits. |
| tab_reloader().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL, |
| tab_reloader().state()); |
| |
| // The user logs on from another tab, and a captive portal check is triggered. |
| EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1); |
| tab_reloader().OnCaptivePortalResults(RESULT_BEHIND_CAPTIVE_PORTAL, |
| RESULT_INTERNET_CONNECTED); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| } |
| |
| // Simulate a login after the tab times out unexpectedly quickly. |
| TEST_F(CaptivePortalTabReloaderTest, TimeoutFast) { |
| tab_reloader().OnLoadStart(true); |
| |
| // The error page commits, which should trigger a captive portal check, |
| // since the timer's still running. |
| EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1); |
| tab_reloader().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL, |
| tab_reloader().state()); |
| |
| // The captive portal service detects a captive portal. The TabReloader |
| // should try and create a new login tab in response. |
| EXPECT_CALL(tab_reloader(), MaybeOpenCaptivePortalLoginTab()).Times(1); |
| tab_reloader().OnCaptivePortalResults(RESULT_INTERNET_CONNECTED, |
| RESULT_BEHIND_CAPTIVE_PORTAL); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL, |
| tab_reloader().state()); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| |
| // The user logs on from another tab, and a captive portal check is triggered. |
| EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1); |
| tab_reloader().OnCaptivePortalResults(RESULT_BEHIND_CAPTIVE_PORTAL, |
| RESULT_INTERNET_CONNECTED); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| } |
| |
| // An SSL protocol error triggers a captive portal check behind a captive |
| // portal. The user then logs in. |
| TEST_F(CaptivePortalTabReloaderTest, SSLProtocolError) { |
| tab_reloader().OnLoadStart(true); |
| |
| // The error page commits, which should trigger a captive portal check, |
| // since the timer's still running. |
| EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1); |
| tab_reloader().OnLoadCommitted(net::ERR_SSL_PROTOCOL_ERROR); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL, |
| tab_reloader().state()); |
| |
| // The captive portal service detects a captive portal. The TabReloader |
| // should try and create a new login tab in response. |
| EXPECT_CALL(tab_reloader(), MaybeOpenCaptivePortalLoginTab()).Times(1); |
| tab_reloader().OnCaptivePortalResults(RESULT_INTERNET_CONNECTED, |
| RESULT_BEHIND_CAPTIVE_PORTAL); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL, |
| tab_reloader().state()); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| |
| // The user logs on from another tab, and a captive portal check is triggered. |
| EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1); |
| tab_reloader().OnCaptivePortalResults(RESULT_BEHIND_CAPTIVE_PORTAL, |
| RESULT_INTERNET_CONNECTED); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| } |
| |
| // An SSL protocol error triggers a captive portal check behind a captive |
| // portal. The user logs in before the results from the captive portal check |
| // completes. |
| TEST_F(CaptivePortalTabReloaderTest, SSLProtocolErrorFastLogin) { |
| tab_reloader().OnLoadStart(true); |
| |
| // The error page commits, which should trigger a captive portal check, |
| // since the timer's still running. |
| EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1); |
| tab_reloader().OnLoadCommitted(net::ERR_SSL_PROTOCOL_ERROR); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL, |
| tab_reloader().state()); |
| |
| // The user has logged in from another tab. The tab automatically reloads. |
| EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1); |
| tab_reloader().OnCaptivePortalResults(RESULT_BEHIND_CAPTIVE_PORTAL, |
| RESULT_INTERNET_CONNECTED); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| } |
| |
| // An SSL protocol error triggers a captive portal check behind a captive |
| // portal. The user logs in before the results from the captive portal check |
| // completes. This case is probably not too likely, but should be handled. |
| TEST_F(CaptivePortalTabReloaderTest, SSLProtocolErrorAlreadyLoggedIn) { |
| tab_reloader().OnLoadStart(true); |
| |
| // The user logs in from another tab before the tab errors out. |
| tab_reloader().OnCaptivePortalResults(RESULT_BEHIND_CAPTIVE_PORTAL, |
| RESULT_INTERNET_CONNECTED); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD, |
| tab_reloader().state()); |
| |
| // The error page commits, which should trigger a reload. |
| EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1); |
| tab_reloader().OnLoadCommitted(net::ERR_SSL_PROTOCOL_ERROR); |
| base::MessageLoop::current()->RunUntilIdle(); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| } |
| |
| // Simulate the case that a user has already logged in before the tab receives a |
| // captive portal result, but a RESULT_BEHIND_CAPTIVE_PORTAL was received |
| // before the tab started loading. |
| TEST_F(CaptivePortalTabReloaderTest, AlreadyLoggedIn) { |
| tab_reloader().OnLoadStart(true); |
| |
| EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1); |
| base::MessageLoop::current()->RunUntilIdle(); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL, |
| tab_reloader().state()); |
| |
| // The user has already logged in. Since the last result found a captive |
| // portal, the tab will be reloaded if a timeout is committed. |
| tab_reloader().OnCaptivePortalResults(RESULT_BEHIND_CAPTIVE_PORTAL, |
| RESULT_INTERNET_CONNECTED); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD, |
| tab_reloader().state()); |
| |
| // The error page commits, which should start an asynchronous reload. |
| tab_reloader().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD, |
| tab_reloader().state()); |
| |
| EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1); |
| base::MessageLoop::current()->RunUntilIdle(); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| } |
| |
| // Same as above, except the result is received even before the timer triggers, |
| // due to a captive portal test request from some external source, like a login |
| // tab. |
| TEST_F(CaptivePortalTabReloaderTest, AlreadyLoggedInBeforeTimerTriggers) { |
| tab_reloader().OnLoadStart(true); |
| |
| // The user has already logged in. Since the last result indicated there is |
| // a captive portal, the tab will be reloaded if it times out. |
| tab_reloader().OnCaptivePortalResults(RESULT_BEHIND_CAPTIVE_PORTAL, |
| RESULT_INTERNET_CONNECTED); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD, |
| tab_reloader().state()); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| |
| // The error page commits, which should start an asynchronous reload. |
| tab_reloader().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD, |
| tab_reloader().state()); |
| |
| EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1); |
| base::MessageLoop::current()->RunUntilIdle(); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().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(CaptivePortalTabReloaderTest, LoginWhileTimerRunning) { |
| tab_reloader().OnLoadStart(true); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING, |
| tab_reloader().state()); |
| EXPECT_TRUE(tab_reloader().TimerRunning()); |
| |
| // The user has already logged in. |
| tab_reloader().OnCaptivePortalResults(RESULT_BEHIND_CAPTIVE_PORTAL, |
| RESULT_INTERNET_CONNECTED); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD, |
| tab_reloader().state()); |
| |
| // The error page commits, which should start an asynchronous reload. |
| tab_reloader().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD, |
| tab_reloader().state()); |
| |
| EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1); |
| base::MessageLoop::current()->RunUntilIdle(); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| } |
| |
| // Simulate a captive portal being detected while the time is still running. |
| // The captive portal check triggered by the timer detects the captive portal |
| // again, and then the user logs in. |
| TEST_F(CaptivePortalTabReloaderTest, BehindPortalResultWhileTimerRunning) { |
| tab_reloader().OnLoadStart(true); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING, |
| tab_reloader().state()); |
| EXPECT_TRUE(tab_reloader().TimerRunning()); |
| |
| // The user is behind a captive portal, but since the tab hasn't timed out, |
| // the message is ignored. |
| tab_reloader().OnCaptivePortalResults(RESULT_INTERNET_CONNECTED, |
| RESULT_BEHIND_CAPTIVE_PORTAL); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING, |
| tab_reloader().state()); |
| |
| // The rest proceeds as normal. |
| EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1); |
| base::MessageLoop::current()->RunUntilIdle(); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL, |
| tab_reloader().state()); |
| |
| // The captive portal service detects a captive portal, and this time the |
| // tab tries to create a login tab. |
| EXPECT_CALL(tab_reloader(), MaybeOpenCaptivePortalLoginTab()).Times(1); |
| tab_reloader().OnCaptivePortalResults(RESULT_BEHIND_CAPTIVE_PORTAL, |
| RESULT_BEHIND_CAPTIVE_PORTAL); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL, |
| tab_reloader().state()); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| |
| // The user logs on from another tab, and a captive portal check is triggered. |
| tab_reloader().OnCaptivePortalResults(RESULT_BEHIND_CAPTIVE_PORTAL, |
| RESULT_INTERNET_CONNECTED); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD, |
| tab_reloader().state()); |
| |
| // The error page commits, which should start an asynchronous reload. |
| tab_reloader().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD, |
| tab_reloader().state()); |
| |
| EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1); |
| base::MessageLoop::current()->RunUntilIdle(); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| } |
| |
| // The CaptivePortalService detects the user has logged in to a captive portal |
| // while the timer is still running, but the original load succeeds, so no |
| // reload is done. |
| TEST_F(CaptivePortalTabReloaderTest, LogInWhileTimerRunningNoError) { |
| tab_reloader().OnLoadStart(true); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING, |
| tab_reloader().state()); |
| EXPECT_TRUE(tab_reloader().TimerRunning()); |
| |
| // The user has already logged in. |
| tab_reloader().OnCaptivePortalResults(RESULT_BEHIND_CAPTIVE_PORTAL, |
| RESULT_INTERNET_CONNECTED); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD, |
| tab_reloader().state()); |
| |
| // The page successfully commits, so no reload is triggered. |
| tab_reloader().OnLoadCommitted(net::OK); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| } |
| |
| // Simulate the login process when there's an SSL certificate error. |
| TEST_F(CaptivePortalTabReloaderTest, SSLCertErrorLogin) { |
| tab_reloader().OnLoadStart(true); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING, |
| tab_reloader().state()); |
| |
| // The load is interrupted by an interstitial page. The interstitial page |
| // is created after the TabReloader is notified. |
| EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()); |
| net::SSLInfo ssl_info; |
| ssl_info.SetCertError(net::CERT_STATUS_COMMON_NAME_INVALID); |
| tab_reloader().OnSSLCertError(ssl_info); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL, |
| tab_reloader().state()); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| // The MockInterstitialPageDelegate will cleaned up by the WebContents. |
| new MockInterstitialPageDelegate(web_contents()); |
| |
| // Captive portal probe finds a captive portal. |
| EXPECT_CALL(tab_reloader(), MaybeOpenCaptivePortalLoginTab()).Times(1); |
| tab_reloader().OnCaptivePortalResults(RESULT_INTERNET_CONNECTED, |
| RESULT_BEHIND_CAPTIVE_PORTAL); |
| |
| // The user logs in. Since the interstitial is showing, the page should |
| // be reloaded, despite still having a provisional load. |
| EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1); |
| tab_reloader().OnCaptivePortalResults(RESULT_BEHIND_CAPTIVE_PORTAL, |
| RESULT_INTERNET_CONNECTED); |
| } |
| |
| // Simulate an HTTP redirect to HTTPS, when the Internet is connected. |
| TEST_F(CaptivePortalTabReloaderTest, HttpToHttpsRedirectInternetConnected) { |
| tab_reloader().OnLoadStart(false); |
| // There should be no captive portal check pending. |
| base::MessageLoop::current()->RunUntilIdle(); |
| |
| // HTTP to HTTPS redirect. |
| tab_reloader().OnRedirect(true); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING, |
| tab_reloader().state()); |
| EXPECT_TRUE(tab_reloader().TimerRunning()); |
| |
| EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1); |
| base::MessageLoop::current()->RunUntilIdle(); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL, |
| tab_reloader().state()); |
| |
| tab_reloader().OnCaptivePortalResults(RESULT_INTERNET_CONNECTED, |
| RESULT_INTERNET_CONNECTED); |
| |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| |
| tab_reloader().OnLoadCommitted(net::OK); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| } |
| |
| // Simulate an HTTP redirect to HTTPS and subsequent Login, when the user logs |
| // in before the original page commits. |
| TEST_F(CaptivePortalTabReloaderTest, HttpToHttpsRedirectLogin) { |
| tab_reloader().OnLoadStart(false); |
| // There should be no captive portal check pending. |
| base::MessageLoop::current()->RunUntilIdle(); |
| |
| // HTTP to HTTPS redirect. |
| tab_reloader().OnRedirect(true); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING, |
| tab_reloader().state()); |
| |
| EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1); |
| base::MessageLoop::current()->RunUntilIdle(); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL, |
| tab_reloader().state()); |
| |
| // The captive portal service detects a captive portal. The TabReloader |
| // should try and create a new login tab in response. |
| EXPECT_CALL(tab_reloader(), MaybeOpenCaptivePortalLoginTab()).Times(1); |
| tab_reloader().OnCaptivePortalResults(RESULT_INTERNET_CONNECTED, |
| RESULT_BEHIND_CAPTIVE_PORTAL); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL, |
| tab_reloader().state()); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| |
| // The user logs on from another tab, and a captive portal check is triggered. |
| tab_reloader().OnCaptivePortalResults(RESULT_BEHIND_CAPTIVE_PORTAL, |
| RESULT_INTERNET_CONNECTED); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD, |
| tab_reloader().state()); |
| |
| // The error page commits, which should start an asynchronous reload. |
| tab_reloader().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD, |
| tab_reloader().state()); |
| |
| EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1); |
| base::MessageLoop::current()->RunUntilIdle(); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| } |
| |
| // Simulate the case where an HTTPs page redirects to an HTTPS page, before |
| // the timer triggers. |
| TEST_F(CaptivePortalTabReloaderTest, HttpsToHttpRedirect) { |
| tab_reloader().OnLoadStart(true); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING, |
| tab_reloader().state()); |
| |
| tab_reloader().OnRedirect(false); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| |
| // There should be no captive portal check pending after the redirect. |
| base::MessageLoop::current()->RunUntilIdle(); |
| |
| // Logging in shouldn't do anything. |
| tab_reloader().OnCaptivePortalResults(RESULT_BEHIND_CAPTIVE_PORTAL, |
| RESULT_INTERNET_CONNECTED); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| } |
| |
| // Check that an HTTPS to HTTPS redirect results in no timer running. |
| TEST_F(CaptivePortalTabReloaderTest, HttpsToHttpsRedirect) { |
| tab_reloader().OnLoadStart(true); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING, |
| tab_reloader().state()); |
| |
| tab_reloader().OnRedirect(true); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, |
| tab_reloader().state()); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| // Nothing should happen. |
| base::MessageLoop::current()->RunUntilIdle(); |
| } |
| |
| // Check that an HTTPS to HTTP to HTTPS redirect results in no timer running. |
| TEST_F(CaptivePortalTabReloaderTest, HttpsToHttpToHttpsRedirect) { |
| tab_reloader().OnLoadStart(true); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING, |
| tab_reloader().state()); |
| |
| tab_reloader().OnRedirect(false); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| |
| tab_reloader().OnRedirect(true); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, |
| tab_reloader().state()); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| // Nothing should happen. |
| base::MessageLoop::current()->RunUntilIdle(); |
| } |
| |
| // Check that an HTTP to HTTP redirect results in the timer not running. |
| TEST_F(CaptivePortalTabReloaderTest, HttpToHttpRedirect) { |
| tab_reloader().OnLoadStart(false); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| |
| tab_reloader().OnRedirect(false); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| EXPECT_FALSE(tab_reloader().TimerRunning()); |
| |
| // There should be no captive portal check pending after the redirect. |
| base::MessageLoop::current()->RunUntilIdle(); |
| |
| // Logging in shouldn't do anything. |
| tab_reloader().OnCaptivePortalResults(RESULT_BEHIND_CAPTIVE_PORTAL, |
| RESULT_INTERNET_CONNECTED); |
| EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state()); |
| } |
| |
| } // namespace captive_portal |