blob: 33df92beb972b883095fc2ad0f7e9943ccba2b6f [file] [log] [blame]
// 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/macros.h"
#include "base/run_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/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"
using captive_portal::CaptivePortalResult;
// 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)>()) {
}
~TestCaptivePortalTabReloader() override {}
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();
}
~MockInterstitialPageDelegate() override {}
private:
// InterstitialPageDelegate implementation:
std::string GetHTMLContents() override { return "HTML Contents"; }
DISALLOW_COPY_AND_ASSIGN(MockInterstitialPageDelegate);
};
class CaptivePortalTabReloaderTest : public ChromeRenderViewHostTestHarness {
public:
// testing::Test:
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());
}
void TearDown() override {
EXPECT_FALSE(tab_reloader().TimerRunning());
tab_reloader_.reset(NULL);
ChromeRenderViewHostTestHarness::TearDown();
}
TestCaptivePortalTabReloader& tab_reloader() { return *tab_reloader_.get(); }
private:
std::unique_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::RunLoop().RunUntilIdle();
EXPECT_FALSE(tab_reloader().TimerRunning());
EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL,
tab_reloader().state());
tab_reloader().OnCaptivePortalResults(
captive_portal::RESULT_INTERNET_CONNECTED,
captive_portal::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(
captive_portal::RESULT_INTERNET_CONNECTED,
captive_portal::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::RunLoop().RunUntilIdle();
EXPECT_FALSE(tab_reloader().TimerRunning());
EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL,
tab_reloader().state());
tab_reloader().OnCaptivePortalResults(captive_portal::RESULT_NO_RESPONSE,
captive_portal::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(
captive_portal::RESULT_INTERNET_CONNECTED,
captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL);
EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
// The user logs in.
tab_reloader().OnCaptivePortalResults(
captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
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::RunLoop().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(
captive_portal::RESULT_INTERNET_CONNECTED,
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(
captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
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::RunLoop().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::RunLoop().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(
captive_portal::RESULT_INTERNET_CONNECTED,
captive_portal::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(
captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
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(
captive_portal::RESULT_INTERNET_CONNECTED,
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.
EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1);
tab_reloader().OnCaptivePortalResults(
captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
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(
captive_portal::RESULT_INTERNET_CONNECTED,
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.
EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1);
tab_reloader().OnCaptivePortalResults(
captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
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(
captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
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(
captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
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::RunLoop().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::RunLoop().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(
captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
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::RunLoop().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(
captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
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::RunLoop().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(
captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
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::RunLoop().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(
captive_portal::RESULT_INTERNET_CONNECTED,
captive_portal::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::RunLoop().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(
captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
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(
captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
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::RunLoop().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(
captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
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(
captive_portal::RESULT_INTERNET_CONNECTED,
captive_portal::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(
captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
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::RunLoop().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::RunLoop().RunUntilIdle();
EXPECT_FALSE(tab_reloader().TimerRunning());
EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL,
tab_reloader().state());
tab_reloader().OnCaptivePortalResults(
captive_portal::RESULT_INTERNET_CONNECTED,
captive_portal::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::RunLoop().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::RunLoop().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(
captive_portal::RESULT_INTERNET_CONNECTED,
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(
captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
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::RunLoop().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::RunLoop().RunUntilIdle();
// Logging in shouldn't do anything.
tab_reloader().OnCaptivePortalResults(
captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
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::RunLoop().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::RunLoop().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::RunLoop().RunUntilIdle();
// Logging in shouldn't do anything.
tab_reloader().OnCaptivePortalResults(
captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
captive_portal::RESULT_INTERNET_CONNECTED);
EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
}