Home | History | Annotate | Download | only in captive_portal
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/captive_portal/captive_portal_tab_reloader.h"
      6 
      7 #include "base/callback.h"
      8 #include "base/message_loop/message_loop.h"
      9 #include "chrome/browser/captive_portal/captive_portal_service.h"
     10 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
     11 #include "content/public/browser/interstitial_page.h"
     12 #include "content/public/browser/interstitial_page_delegate.h"
     13 #include "content/public/browser/web_contents.h"
     14 #include "net/base/net_errors.h"
     15 #include "net/cert/cert_status_flags.h"
     16 #include "net/ssl/ssl_info.h"
     17 #include "testing/gmock/include/gmock/gmock.h"
     18 #include "testing/gtest/include/gtest/gtest.h"
     19 #include "url/gurl.h"
     20 
     21 using captive_portal::CaptivePortalResult;
     22 
     23 // Used for testing CaptivePortalTabReloader in isolation from the observer.
     24 // Exposes a number of private functions and mocks out others.
     25 class TestCaptivePortalTabReloader : public CaptivePortalTabReloader {
     26  public:
     27   explicit TestCaptivePortalTabReloader(content::WebContents* web_contents)
     28       : CaptivePortalTabReloader(NULL,
     29                                  web_contents,
     30                                  base::Callback<void(void)>()) {
     31   }
     32 
     33   virtual ~TestCaptivePortalTabReloader() {
     34   }
     35 
     36   bool TimerRunning() {
     37     return slow_ssl_load_timer_.IsRunning();
     38   }
     39 
     40   // The following methods are aliased so they can be publicly accessed by the
     41   // unit tests.
     42 
     43   State state() const {
     44     return CaptivePortalTabReloader::state();
     45   }
     46 
     47   void set_slow_ssl_load_time(base::TimeDelta slow_ssl_load_time) {
     48     EXPECT_FALSE(TimerRunning());
     49     CaptivePortalTabReloader::set_slow_ssl_load_time(slow_ssl_load_time);
     50   }
     51 
     52   // CaptivePortalTabReloader:
     53   MOCK_METHOD0(ReloadTab, void());
     54   MOCK_METHOD0(MaybeOpenCaptivePortalLoginTab, void());
     55   MOCK_METHOD0(CheckForCaptivePortal, void());
     56 
     57  private:
     58   DISALLOW_COPY_AND_ASSIGN(TestCaptivePortalTabReloader);
     59 };
     60 
     61 // Used to test behavior when a WebContents is showing an interstitial page.
     62 class MockInterstitialPageDelegate : public content::InterstitialPageDelegate {
     63  public:
     64   // The newly created MockInterstitialPageDelegate will be owned by the
     65   // WebContents' InterstitialPage, and cleaned up when the WebContents
     66   // destroys it.
     67   explicit MockInterstitialPageDelegate(
     68       content::WebContents* web_contents) {
     69     content::InterstitialPage* interstitial_page =
     70         content::InterstitialPage::Create(
     71             web_contents, true, GURL("http://blah"), this);
     72     interstitial_page->DontCreateViewForTesting();
     73     interstitial_page->Show();
     74   }
     75 
     76   virtual ~MockInterstitialPageDelegate() {
     77   }
     78 
     79  private:
     80   // InterstitialPageDelegate implementation:
     81   virtual std::string GetHTMLContents() OVERRIDE {
     82     return "HTML Contents";
     83   }
     84 
     85   DISALLOW_COPY_AND_ASSIGN(MockInterstitialPageDelegate);
     86 };
     87 
     88 class CaptivePortalTabReloaderTest : public ChromeRenderViewHostTestHarness {
     89  public:
     90   // testing::Test:
     91   virtual void SetUp() OVERRIDE {
     92     ChromeRenderViewHostTestHarness::SetUp();
     93     tab_reloader_.reset(new testing::StrictMock<TestCaptivePortalTabReloader>(
     94         web_contents()));
     95 
     96     // Most tests don't run the message loop, so don't use a timer for them.
     97     tab_reloader_->set_slow_ssl_load_time(base::TimeDelta());
     98   }
     99 
    100   virtual void TearDown() OVERRIDE {
    101     EXPECT_FALSE(tab_reloader().TimerRunning());
    102     tab_reloader_.reset(NULL);
    103     ChromeRenderViewHostTestHarness::TearDown();
    104   }
    105 
    106   TestCaptivePortalTabReloader& tab_reloader() { return *tab_reloader_.get(); }
    107 
    108  private:
    109   scoped_ptr<TestCaptivePortalTabReloader> tab_reloader_;
    110 };
    111 
    112 // Simulates a slow SSL load when the Internet is connected.
    113 TEST_F(CaptivePortalTabReloaderTest, InternetConnected) {
    114   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    115 
    116   tab_reloader().OnLoadStart(true);
    117   EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING,
    118             tab_reloader().state());
    119   EXPECT_TRUE(tab_reloader().TimerRunning());
    120 
    121   EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1);
    122   base::MessageLoop::current()->RunUntilIdle();
    123   EXPECT_FALSE(tab_reloader().TimerRunning());
    124   EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL,
    125             tab_reloader().state());
    126 
    127   tab_reloader().OnCaptivePortalResults(
    128       captive_portal::RESULT_INTERNET_CONNECTED,
    129       captive_portal::RESULT_INTERNET_CONNECTED);
    130 
    131   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    132   EXPECT_FALSE(tab_reloader().TimerRunning());
    133 
    134   tab_reloader().OnLoadCommitted(net::OK);
    135   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    136 }
    137 
    138 // Simulates a slow SSL load when the Internet is connected.  In this case,
    139 // the timeout error occurs before the timer triggers.  Unlikely to happen
    140 // in practice, but best if it still works.
    141 TEST_F(CaptivePortalTabReloaderTest, InternetConnectedTimeout) {
    142   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    143 
    144   tab_reloader().OnLoadStart(true);
    145   EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING,
    146             tab_reloader().state());
    147   EXPECT_TRUE(tab_reloader().TimerRunning());
    148 
    149   EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1);
    150   tab_reloader().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
    151   EXPECT_FALSE(tab_reloader().TimerRunning());
    152   EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL,
    153             tab_reloader().state());
    154 
    155   tab_reloader().OnCaptivePortalResults(
    156       captive_portal::RESULT_INTERNET_CONNECTED,
    157       captive_portal::RESULT_INTERNET_CONNECTED);
    158 
    159   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    160 }
    161 
    162 // Simulates a slow SSL load when captive portal checks return no response.
    163 TEST_F(CaptivePortalTabReloaderTest, NoResponse) {
    164   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    165 
    166   tab_reloader().OnLoadStart(true);
    167   EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING,
    168             tab_reloader().state());
    169   EXPECT_TRUE(tab_reloader().TimerRunning());
    170 
    171   EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1);
    172   base::MessageLoop::current()->RunUntilIdle();
    173   EXPECT_FALSE(tab_reloader().TimerRunning());
    174   EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL,
    175             tab_reloader().state());
    176 
    177   tab_reloader().OnCaptivePortalResults(captive_portal::RESULT_NO_RESPONSE,
    178                                         captive_portal::RESULT_NO_RESPONSE);
    179 
    180   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    181   EXPECT_FALSE(tab_reloader().TimerRunning());
    182 
    183   tab_reloader().OnLoadCommitted(net::OK);
    184   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    185 }
    186 
    187 // Simulates a slow HTTP load when behind a captive portal, that eventually.
    188 // tiems out.  Since it's HTTP, the TabReloader should do nothing.
    189 TEST_F(CaptivePortalTabReloaderTest, DoesNothingOnHttp) {
    190   tab_reloader().OnLoadStart(false);
    191   EXPECT_FALSE(tab_reloader().TimerRunning());
    192   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    193 
    194   tab_reloader().OnCaptivePortalResults(
    195       captive_portal::RESULT_INTERNET_CONNECTED,
    196       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL);
    197   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    198 
    199   // The user logs in.
    200   tab_reloader().OnCaptivePortalResults(
    201       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
    202       captive_portal::RESULT_INTERNET_CONNECTED);
    203   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    204 
    205   // The page times out.
    206   tab_reloader().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
    207   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    208 }
    209 
    210 // Simulate the normal login process.  The user logs in before the error page
    211 // in the original tab commits.
    212 TEST_F(CaptivePortalTabReloaderTest, Login) {
    213   tab_reloader().OnLoadStart(true);
    214 
    215   EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1);
    216   base::MessageLoop::current()->RunUntilIdle();
    217   EXPECT_FALSE(tab_reloader().TimerRunning());
    218   EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL,
    219             tab_reloader().state());
    220 
    221   // The captive portal service detects a captive portal.  The TabReloader
    222   // should try and create a new login tab in response.
    223   EXPECT_CALL(tab_reloader(), MaybeOpenCaptivePortalLoginTab()).Times(1);
    224   tab_reloader().OnCaptivePortalResults(
    225       captive_portal::RESULT_INTERNET_CONNECTED,
    226       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL);
    227   EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
    228             tab_reloader().state());
    229   EXPECT_FALSE(tab_reloader().TimerRunning());
    230 
    231   // The user logs on from another tab, and a captive portal check is triggered.
    232   tab_reloader().OnCaptivePortalResults(
    233       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
    234       captive_portal::RESULT_INTERNET_CONNECTED);
    235   EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD,
    236             tab_reloader().state());
    237 
    238   // The error page commits, which should start an asynchronous reload.
    239   tab_reloader().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
    240   EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD,
    241             tab_reloader().state());
    242 
    243   EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1);
    244   base::MessageLoop::current()->RunUntilIdle();
    245   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    246 }
    247 
    248 // Simulate the normal login process.  The user logs in after the tab finishes
    249 // loading the error page.
    250 TEST_F(CaptivePortalTabReloaderTest, LoginLate) {
    251   tab_reloader().OnLoadStart(true);
    252 
    253   EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1);
    254   base::MessageLoop::current()->RunUntilIdle();
    255   EXPECT_FALSE(tab_reloader().TimerRunning());
    256   EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL,
    257             tab_reloader().state());
    258 
    259   // The captive portal service detects a captive portal.  The TabReloader
    260   // should try and create a new login tab in response.
    261   EXPECT_CALL(tab_reloader(), MaybeOpenCaptivePortalLoginTab()).Times(1);
    262   tab_reloader().OnCaptivePortalResults(
    263       captive_portal::RESULT_INTERNET_CONNECTED,
    264       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL);
    265   EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
    266             tab_reloader().state());
    267   EXPECT_FALSE(tab_reloader().TimerRunning());
    268 
    269   // The error page commits.
    270   tab_reloader().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
    271   EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
    272             tab_reloader().state());
    273 
    274   // The user logs on from another tab, and a captive portal check is triggered.
    275   EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1);
    276   tab_reloader().OnCaptivePortalResults(
    277       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
    278       captive_portal::RESULT_INTERNET_CONNECTED);
    279   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    280 }
    281 
    282 // Simulate a login after the tab times out unexpectedly quickly.
    283 TEST_F(CaptivePortalTabReloaderTest, TimeoutFast) {
    284   tab_reloader().OnLoadStart(true);
    285 
    286   // The error page commits, which should trigger a captive portal check,
    287   // since the timer's still running.
    288   EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1);
    289   tab_reloader().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
    290   EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL,
    291             tab_reloader().state());
    292 
    293   // The captive portal service detects a captive portal.  The TabReloader
    294   // should try and create a new login tab in response.
    295   EXPECT_CALL(tab_reloader(), MaybeOpenCaptivePortalLoginTab()).Times(1);
    296   tab_reloader().OnCaptivePortalResults(
    297       captive_portal::RESULT_INTERNET_CONNECTED,
    298       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL);
    299   EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
    300             tab_reloader().state());
    301   EXPECT_FALSE(tab_reloader().TimerRunning());
    302 
    303   // The user logs on from another tab, and a captive portal check is triggered.
    304   EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1);
    305   tab_reloader().OnCaptivePortalResults(
    306       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
    307       captive_portal::RESULT_INTERNET_CONNECTED);
    308   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    309 }
    310 
    311 // An SSL protocol error triggers a captive portal check behind a captive
    312 // portal.  The user then logs in.
    313 TEST_F(CaptivePortalTabReloaderTest, SSLProtocolError) {
    314   tab_reloader().OnLoadStart(true);
    315 
    316   // The error page commits, which should trigger a captive portal check,
    317   // since the timer's still running.
    318   EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1);
    319   tab_reloader().OnLoadCommitted(net::ERR_SSL_PROTOCOL_ERROR);
    320   EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL,
    321             tab_reloader().state());
    322 
    323   // The captive portal service detects a captive portal.  The TabReloader
    324   // should try and create a new login tab in response.
    325   EXPECT_CALL(tab_reloader(), MaybeOpenCaptivePortalLoginTab()).Times(1);
    326   tab_reloader().OnCaptivePortalResults(
    327       captive_portal::RESULT_INTERNET_CONNECTED,
    328       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL);
    329   EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
    330             tab_reloader().state());
    331   EXPECT_FALSE(tab_reloader().TimerRunning());
    332 
    333   // The user logs on from another tab, and a captive portal check is triggered.
    334   EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1);
    335   tab_reloader().OnCaptivePortalResults(
    336       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
    337       captive_portal::RESULT_INTERNET_CONNECTED);
    338   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    339 }
    340 
    341 // An SSL protocol error triggers a captive portal check behind a captive
    342 // portal.  The user logs in before the results from the captive portal check
    343 // completes.
    344 TEST_F(CaptivePortalTabReloaderTest, SSLProtocolErrorFastLogin) {
    345   tab_reloader().OnLoadStart(true);
    346 
    347   // The error page commits, which should trigger a captive portal check,
    348   // since the timer's still running.
    349   EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1);
    350   tab_reloader().OnLoadCommitted(net::ERR_SSL_PROTOCOL_ERROR);
    351   EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL,
    352             tab_reloader().state());
    353 
    354   // The user has logged in from another tab.  The tab automatically reloads.
    355   EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1);
    356   tab_reloader().OnCaptivePortalResults(
    357       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
    358       captive_portal::RESULT_INTERNET_CONNECTED);
    359   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    360 }
    361 
    362 // An SSL protocol error triggers a captive portal check behind a captive
    363 // portal.  The user logs in before the results from the captive portal check
    364 // completes.  This case is probably not too likely, but should be handled.
    365 TEST_F(CaptivePortalTabReloaderTest, SSLProtocolErrorAlreadyLoggedIn) {
    366   tab_reloader().OnLoadStart(true);
    367 
    368   // The user logs in from another tab before the tab errors out.
    369   tab_reloader().OnCaptivePortalResults(
    370       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
    371       captive_portal::RESULT_INTERNET_CONNECTED);
    372   EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD,
    373             tab_reloader().state());
    374 
    375   // The error page commits, which should trigger a reload.
    376   EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1);
    377   tab_reloader().OnLoadCommitted(net::ERR_SSL_PROTOCOL_ERROR);
    378   base::MessageLoop::current()->RunUntilIdle();
    379   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    380 }
    381 
    382 // Simulate the case that a user has already logged in before the tab receives a
    383 // captive portal result, but a RESULT_BEHIND_CAPTIVE_PORTAL was received
    384 // before the tab started loading.
    385 TEST_F(CaptivePortalTabReloaderTest, AlreadyLoggedIn) {
    386   tab_reloader().OnLoadStart(true);
    387 
    388   EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1);
    389   base::MessageLoop::current()->RunUntilIdle();
    390   EXPECT_FALSE(tab_reloader().TimerRunning());
    391   EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL,
    392             tab_reloader().state());
    393 
    394   // The user has already logged in.  Since the last result found a captive
    395   // portal, the tab will be reloaded if a timeout is committed.
    396   tab_reloader().OnCaptivePortalResults(
    397       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
    398       captive_portal::RESULT_INTERNET_CONNECTED);
    399   EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD,
    400             tab_reloader().state());
    401 
    402   // The error page commits, which should start an asynchronous reload.
    403   tab_reloader().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
    404   EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD,
    405             tab_reloader().state());
    406 
    407   EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1);
    408   base::MessageLoop::current()->RunUntilIdle();
    409   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    410 }
    411 
    412 // Same as above, except the result is received even before the timer triggers,
    413 // due to a captive portal test request from some external source, like a login
    414 // tab.
    415 TEST_F(CaptivePortalTabReloaderTest, AlreadyLoggedInBeforeTimerTriggers) {
    416   tab_reloader().OnLoadStart(true);
    417 
    418   // The user has already logged in.  Since the last result indicated there is
    419   // a captive portal, the tab will be reloaded if it times out.
    420   tab_reloader().OnCaptivePortalResults(
    421       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
    422       captive_portal::RESULT_INTERNET_CONNECTED);
    423   EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD,
    424             tab_reloader().state());
    425   EXPECT_FALSE(tab_reloader().TimerRunning());
    426 
    427   // The error page commits, which should start an asynchronous reload.
    428   tab_reloader().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
    429   EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD,
    430             tab_reloader().state());
    431 
    432   EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1);
    433   base::MessageLoop::current()->RunUntilIdle();
    434   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    435 }
    436 
    437 // Simulate the user logging in while the timer is still running.  May happen
    438 // if the tab is reloaded just before logging in on another tab.
    439 TEST_F(CaptivePortalTabReloaderTest, LoginWhileTimerRunning) {
    440   tab_reloader().OnLoadStart(true);
    441   EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING,
    442             tab_reloader().state());
    443   EXPECT_TRUE(tab_reloader().TimerRunning());
    444 
    445   // The user has already logged in.
    446   tab_reloader().OnCaptivePortalResults(
    447       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
    448       captive_portal::RESULT_INTERNET_CONNECTED);
    449   EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD,
    450             tab_reloader().state());
    451 
    452   // The error page commits, which should start an asynchronous reload.
    453   tab_reloader().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
    454   EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD,
    455             tab_reloader().state());
    456 
    457   EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1);
    458   base::MessageLoop::current()->RunUntilIdle();
    459   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    460 }
    461 
    462 // Simulate a captive portal being detected while the time is still running.
    463 // The captive portal check triggered by the timer detects the captive portal
    464 // again, and then the user logs in.
    465 TEST_F(CaptivePortalTabReloaderTest, BehindPortalResultWhileTimerRunning) {
    466   tab_reloader().OnLoadStart(true);
    467   EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING,
    468             tab_reloader().state());
    469   EXPECT_TRUE(tab_reloader().TimerRunning());
    470 
    471   // The user is behind a captive portal, but since the tab hasn't timed out,
    472   // the message is ignored.
    473   tab_reloader().OnCaptivePortalResults(
    474       captive_portal::RESULT_INTERNET_CONNECTED,
    475       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL);
    476   EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING,
    477             tab_reloader().state());
    478 
    479   // The rest proceeds as normal.
    480   EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1);
    481   base::MessageLoop::current()->RunUntilIdle();
    482   EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL,
    483             tab_reloader().state());
    484 
    485   // The captive portal service detects a captive portal, and this time the
    486   // tab tries to create a login tab.
    487   EXPECT_CALL(tab_reloader(), MaybeOpenCaptivePortalLoginTab()).Times(1);
    488   tab_reloader().OnCaptivePortalResults(
    489       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
    490       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL);
    491   EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
    492             tab_reloader().state());
    493   EXPECT_FALSE(tab_reloader().TimerRunning());
    494 
    495   // The user logs on from another tab, and a captive portal check is triggered.
    496   tab_reloader().OnCaptivePortalResults(
    497       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
    498       captive_portal::RESULT_INTERNET_CONNECTED);
    499   EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD,
    500             tab_reloader().state());
    501 
    502   // The error page commits, which should start an asynchronous reload.
    503   tab_reloader().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
    504   EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD,
    505             tab_reloader().state());
    506 
    507   EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1);
    508   base::MessageLoop::current()->RunUntilIdle();
    509   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    510 }
    511 
    512 // The CaptivePortalService detects the user has logged in to a captive portal
    513 // while the timer is still running, but the original load succeeds, so no
    514 // reload is done.
    515 TEST_F(CaptivePortalTabReloaderTest, LogInWhileTimerRunningNoError) {
    516   tab_reloader().OnLoadStart(true);
    517   EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING,
    518             tab_reloader().state());
    519   EXPECT_TRUE(tab_reloader().TimerRunning());
    520 
    521   // The user has already logged in.
    522   tab_reloader().OnCaptivePortalResults(
    523       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
    524       captive_portal::RESULT_INTERNET_CONNECTED);
    525   EXPECT_FALSE(tab_reloader().TimerRunning());
    526   EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD,
    527             tab_reloader().state());
    528 
    529   // The page successfully commits, so no reload is triggered.
    530   tab_reloader().OnLoadCommitted(net::OK);
    531   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    532 }
    533 
    534 // Simulate the login process when there's an SSL certificate error.
    535 TEST_F(CaptivePortalTabReloaderTest, SSLCertErrorLogin) {
    536   tab_reloader().OnLoadStart(true);
    537   EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING,
    538             tab_reloader().state());
    539 
    540   // The load is interrupted by an interstitial page.  The interstitial page
    541   // is created after the TabReloader is notified.
    542   EXPECT_CALL(tab_reloader(), CheckForCaptivePortal());
    543   net::SSLInfo ssl_info;
    544   ssl_info.SetCertError(net::CERT_STATUS_COMMON_NAME_INVALID);
    545   tab_reloader().OnSSLCertError(ssl_info);
    546   EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL,
    547             tab_reloader().state());
    548   EXPECT_FALSE(tab_reloader().TimerRunning());
    549   // The MockInterstitialPageDelegate will cleaned up by the WebContents.
    550   new MockInterstitialPageDelegate(web_contents());
    551 
    552   // Captive portal probe finds a captive portal.
    553   EXPECT_CALL(tab_reloader(), MaybeOpenCaptivePortalLoginTab()).Times(1);
    554   tab_reloader().OnCaptivePortalResults(
    555       captive_portal::RESULT_INTERNET_CONNECTED,
    556       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL);
    557 
    558   // The user logs in.  Since the interstitial is showing, the page should
    559   // be reloaded, despite still having a provisional load.
    560   EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1);
    561   tab_reloader().OnCaptivePortalResults(
    562       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
    563       captive_portal::RESULT_INTERNET_CONNECTED);
    564 }
    565 
    566 // Simulate an HTTP redirect to HTTPS, when the Internet is connected.
    567 TEST_F(CaptivePortalTabReloaderTest, HttpToHttpsRedirectInternetConnected) {
    568   tab_reloader().OnLoadStart(false);
    569   // There should be no captive portal check pending.
    570   base::MessageLoop::current()->RunUntilIdle();
    571 
    572   // HTTP to HTTPS redirect.
    573   tab_reloader().OnRedirect(true);
    574   EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING,
    575             tab_reloader().state());
    576   EXPECT_TRUE(tab_reloader().TimerRunning());
    577 
    578   EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1);
    579   base::MessageLoop::current()->RunUntilIdle();
    580   EXPECT_FALSE(tab_reloader().TimerRunning());
    581   EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL,
    582             tab_reloader().state());
    583 
    584   tab_reloader().OnCaptivePortalResults(
    585       captive_portal::RESULT_INTERNET_CONNECTED,
    586       captive_portal::RESULT_INTERNET_CONNECTED);
    587 
    588   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    589   EXPECT_FALSE(tab_reloader().TimerRunning());
    590 
    591   tab_reloader().OnLoadCommitted(net::OK);
    592   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    593 }
    594 
    595 // Simulate an HTTP redirect to HTTPS and subsequent Login, when the user logs
    596 // in before the original page commits.
    597 TEST_F(CaptivePortalTabReloaderTest, HttpToHttpsRedirectLogin) {
    598   tab_reloader().OnLoadStart(false);
    599   // There should be no captive portal check pending.
    600   base::MessageLoop::current()->RunUntilIdle();
    601 
    602   // HTTP to HTTPS redirect.
    603   tab_reloader().OnRedirect(true);
    604   EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING,
    605             tab_reloader().state());
    606 
    607   EXPECT_CALL(tab_reloader(), CheckForCaptivePortal()).Times(1);
    608   base::MessageLoop::current()->RunUntilIdle();
    609   EXPECT_FALSE(tab_reloader().TimerRunning());
    610   EXPECT_EQ(CaptivePortalTabReloader::STATE_MAYBE_BROKEN_BY_PORTAL,
    611             tab_reloader().state());
    612 
    613   // The captive portal service detects a captive portal.  The TabReloader
    614   // should try and create a new login tab in response.
    615   EXPECT_CALL(tab_reloader(), MaybeOpenCaptivePortalLoginTab()).Times(1);
    616   tab_reloader().OnCaptivePortalResults(
    617       captive_portal::RESULT_INTERNET_CONNECTED,
    618       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL);
    619   EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
    620             tab_reloader().state());
    621   EXPECT_FALSE(tab_reloader().TimerRunning());
    622 
    623   // The user logs on from another tab, and a captive portal check is triggered.
    624   tab_reloader().OnCaptivePortalResults(
    625       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
    626       captive_portal::RESULT_INTERNET_CONNECTED);
    627   EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD,
    628             tab_reloader().state());
    629 
    630   // The error page commits, which should start an asynchronous reload.
    631   tab_reloader().OnLoadCommitted(net::ERR_CONNECTION_TIMED_OUT);
    632   EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD,
    633             tab_reloader().state());
    634 
    635   EXPECT_CALL(tab_reloader(), ReloadTab()).Times(1);
    636   base::MessageLoop::current()->RunUntilIdle();
    637   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    638 }
    639 
    640 // Simulate the case where an HTTPs page redirects to an HTTPS page, before
    641 // the timer triggers.
    642 TEST_F(CaptivePortalTabReloaderTest, HttpsToHttpRedirect) {
    643   tab_reloader().OnLoadStart(true);
    644   EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING,
    645             tab_reloader().state());
    646 
    647   tab_reloader().OnRedirect(false);
    648   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    649   EXPECT_FALSE(tab_reloader().TimerRunning());
    650 
    651   // There should be no captive portal check pending after the redirect.
    652   base::MessageLoop::current()->RunUntilIdle();
    653 
    654   // Logging in shouldn't do anything.
    655   tab_reloader().OnCaptivePortalResults(
    656       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
    657       captive_portal::RESULT_INTERNET_CONNECTED);
    658   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    659 }
    660 
    661 // Check that an HTTPS to HTTPS redirect results in no timer running.
    662 TEST_F(CaptivePortalTabReloaderTest, HttpsToHttpsRedirect) {
    663   tab_reloader().OnLoadStart(true);
    664   EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING,
    665             tab_reloader().state());
    666 
    667   tab_reloader().OnRedirect(true);
    668   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    669   EXPECT_FALSE(tab_reloader().TimerRunning());
    670   // Nothing should happen.
    671   base::MessageLoop::current()->RunUntilIdle();
    672 }
    673 
    674 // Check that an HTTPS to HTTP to HTTPS redirect results in no timer running.
    675 TEST_F(CaptivePortalTabReloaderTest, HttpsToHttpToHttpsRedirect) {
    676   tab_reloader().OnLoadStart(true);
    677   EXPECT_EQ(CaptivePortalTabReloader::STATE_TIMER_RUNNING,
    678             tab_reloader().state());
    679 
    680   tab_reloader().OnRedirect(false);
    681   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    682   EXPECT_FALSE(tab_reloader().TimerRunning());
    683 
    684   tab_reloader().OnRedirect(true);
    685   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    686   EXPECT_FALSE(tab_reloader().TimerRunning());
    687   // Nothing should happen.
    688   base::MessageLoop::current()->RunUntilIdle();
    689 }
    690 
    691 // Check that an HTTP to HTTP redirect results in the timer not running.
    692 TEST_F(CaptivePortalTabReloaderTest, HttpToHttpRedirect) {
    693   tab_reloader().OnLoadStart(false);
    694   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    695 
    696   tab_reloader().OnRedirect(false);
    697   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    698   EXPECT_FALSE(tab_reloader().TimerRunning());
    699 
    700   // There should be no captive portal check pending after the redirect.
    701   base::MessageLoop::current()->RunUntilIdle();
    702 
    703   // Logging in shouldn't do anything.
    704   tab_reloader().OnCaptivePortalResults(
    705       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
    706       captive_portal::RESULT_INTERNET_CONNECTED);
    707   EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, tab_reloader().state());
    708 }
    709