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_helper.h"
      6 
      7 #include "base/callback.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "chrome/browser/captive_portal/captive_portal_service.h"
     10 #include "chrome/browser/captive_portal/captive_portal_tab_reloader.h"
     11 #include "chrome/browser/chrome_notification_types.h"
     12 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
     13 #include "content/public/browser/notification_details.h"
     14 #include "content/public/browser/notification_service.h"
     15 #include "content/public/browser/notification_source.h"
     16 #include "content/public/browser/notification_types.h"
     17 #include "content/public/browser/render_view_host.h"
     18 #include "content/public/browser/render_process_host.h"
     19 #include "content/public/browser/web_contents.h"
     20 #include "net/base/net_errors.h"
     21 #include "testing/gmock/include/gmock/gmock.h"
     22 #include "testing/gtest/include/gtest/gtest.h"
     23 
     24 using captive_portal::CaptivePortalResult;
     25 using content::ResourceType;
     26 
     27 namespace {
     28 
     29 const char* const kHttpUrl = "http://whatever.com/";
     30 const char* const kHttpsUrl = "https://whatever.com/";
     31 
     32 // Used for cross-process navigations.  Shouldn't actually matter whether this
     33 // is different from kHttpsUrl, but best to keep things consistent.
     34 const char* const kHttpsUrl2 = "https://cross_process.com/";
     35 
     36 // Error pages use a "data:" URL.  Shouldn't actually matter what this is.
     37 const char* const kErrorPageUrl = "data:blah";
     38 
     39 // Some navigations behave differently depending on if they're cross-process
     40 // or not.
     41 enum NavigationType {
     42   kSameProcess,
     43   kCrossProcess,
     44 };
     45 
     46 }  // namespace
     47 
     48 class MockCaptivePortalTabReloader : public CaptivePortalTabReloader {
     49  public:
     50   MockCaptivePortalTabReloader()
     51       : CaptivePortalTabReloader(NULL, NULL, base::Callback<void()>()) {
     52   }
     53 
     54   MOCK_METHOD1(OnLoadStart, void(bool));
     55   MOCK_METHOD1(OnLoadCommitted, void(int));
     56   MOCK_METHOD0(OnAbort, void());
     57   MOCK_METHOD1(OnRedirect, void(bool));
     58   MOCK_METHOD2(OnCaptivePortalResults,
     59                void(CaptivePortalResult, CaptivePortalResult));
     60 };
     61 
     62 // Inherits from the ChromeRenderViewHostTestHarness to gain access to
     63 // CreateTestWebContents.  Since the tests need to micromanage order of
     64 // WebContentsObserver function calls, does not actually make sure of
     65 // the harness in any other way.
     66 class CaptivePortalTabHelperTest : public ChromeRenderViewHostTestHarness {
     67  public:
     68   CaptivePortalTabHelperTest()
     69       : tab_helper_(NULL),
     70         mock_reloader_(new testing::StrictMock<MockCaptivePortalTabReloader>) {
     71     tab_helper_.SetTabReloaderForTest(mock_reloader_);
     72   }
     73   virtual ~CaptivePortalTabHelperTest() {}
     74 
     75   virtual void SetUp() OVERRIDE {
     76     ChromeRenderViewHostTestHarness::SetUp();
     77     web_contents1_.reset(CreateTestWebContents());
     78     web_contents2_.reset(CreateTestWebContents());
     79   }
     80 
     81   virtual void TearDown() OVERRIDE {
     82     web_contents2_.reset(NULL);
     83     web_contents1_.reset(NULL);
     84     ChromeRenderViewHostTestHarness::TearDown();
     85   }
     86 
     87   // Simulates a successful load of |url|.
     88   void SimulateSuccess(const GURL& url,
     89                        content::RenderViewHost* render_view_host) {
     90     EXPECT_CALL(mock_reloader(), OnLoadStart(url.SchemeIsSecure())).Times(1);
     91     tab_helper().DidStartProvisionalLoadForFrame(
     92         render_view_host->GetMainFrame(), url, false, false);
     93 
     94     EXPECT_CALL(mock_reloader(), OnLoadCommitted(net::OK)).Times(1);
     95     tab_helper().DidCommitProvisionalLoadForFrame(
     96         render_view_host->GetMainFrame(),
     97         url,
     98         ui::PAGE_TRANSITION_LINK);
     99   }
    100 
    101   // Simulates a connection timeout while requesting |url|.
    102   void SimulateTimeout(const GURL& url,
    103                        content::RenderViewHost* render_view_host) {
    104     EXPECT_CALL(mock_reloader(), OnLoadStart(url.SchemeIsSecure())).Times(1);
    105     tab_helper().DidStartProvisionalLoadForFrame(
    106         render_view_host->GetMainFrame(), url, false, false);
    107 
    108     tab_helper().DidFailProvisionalLoad(render_view_host->GetMainFrame(),
    109                                         url,
    110                                         net::ERR_TIMED_OUT,
    111                                         base::string16());
    112 
    113     // Provisional load starts for the error page.
    114     tab_helper().DidStartProvisionalLoadForFrame(
    115         render_view_host->GetMainFrame(), GURL(kErrorPageUrl), true, false);
    116 
    117     EXPECT_CALL(mock_reloader(), OnLoadCommitted(net::ERR_TIMED_OUT)).Times(1);
    118     tab_helper().DidCommitProvisionalLoadForFrame(
    119         render_view_host->GetMainFrame(),
    120         GURL(kErrorPageUrl),
    121         ui::PAGE_TRANSITION_LINK);
    122   }
    123 
    124   // Simulates an abort while requesting |url|.
    125   void SimulateAbort(const GURL& url,
    126                      content::RenderViewHost* render_view_host,
    127                      NavigationType navigation_type) {
    128     EXPECT_CALL(mock_reloader(), OnLoadStart(url.SchemeIsSecure())).Times(1);
    129     tab_helper().DidStartProvisionalLoadForFrame(
    130         render_view_host->GetMainFrame(), url, false, false);
    131 
    132     EXPECT_CALL(mock_reloader(), OnAbort()).Times(1);
    133     if (navigation_type == kSameProcess) {
    134       tab_helper().DidFailProvisionalLoad(render_view_host->GetMainFrame(),
    135                                           url,
    136                                           net::ERR_ABORTED,
    137                                           base::string16());
    138     } else {
    139       // For interrupted provisional cross-process navigations, the
    140       // RenderViewHost is destroyed without sending a DidFailProvisionalLoad
    141       // notification.
    142       tab_helper().RenderViewDeleted(render_view_host);
    143     }
    144 
    145     // Make sure that above call resulted in abort, for tests that continue
    146     // after the abort.
    147     EXPECT_CALL(mock_reloader(), OnAbort()).Times(0);
    148   }
    149 
    150   // Simulates an abort while loading an error page.
    151   void SimulateAbortTimeout(const GURL& url,
    152                             content::RenderViewHost* render_view_host,
    153                             NavigationType navigation_type) {
    154     EXPECT_CALL(mock_reloader(), OnLoadStart(url.SchemeIsSecure())).Times(1);
    155     tab_helper().DidStartProvisionalLoadForFrame(
    156         render_view_host->GetMainFrame(), url, false, false);
    157 
    158     tab_helper().DidFailProvisionalLoad(render_view_host->GetMainFrame(),
    159                                         url,
    160                                         net::ERR_TIMED_OUT,
    161                                         base::string16());
    162 
    163     // Start event for the error page.
    164     tab_helper().DidStartProvisionalLoadForFrame(
    165         render_view_host->GetMainFrame(), url, true, false);
    166 
    167     EXPECT_CALL(mock_reloader(), OnAbort()).Times(1);
    168     if (navigation_type == kSameProcess) {
    169       tab_helper().DidFailProvisionalLoad(render_view_host->GetMainFrame(),
    170                                           url,
    171                                           net::ERR_ABORTED,
    172                                           base::string16());
    173     } else {
    174       // For interrupted provisional cross-process navigations, the
    175       // RenderViewHost is destroyed without sending a DidFailProvisionalLoad
    176       // notification.
    177       tab_helper().RenderViewDeleted(render_view_host);
    178     }
    179 
    180     // Make sure that above call resulted in abort, for tests that continue
    181     // after the abort.
    182     EXPECT_CALL(mock_reloader(), OnAbort()).Times(0);
    183   }
    184 
    185   CaptivePortalTabHelper& tab_helper() {
    186     return tab_helper_;
    187   }
    188 
    189   // Simulates a captive portal redirect by calling the Observe method.
    190   void ObservePortalResult(CaptivePortalResult previous_result,
    191                            CaptivePortalResult result) {
    192     content::Source<Profile> source_profile(NULL);
    193 
    194     CaptivePortalService::Results results;
    195     results.previous_result = previous_result;
    196     results.result = result;
    197     content::Details<CaptivePortalService::Results> details_results(&results);
    198 
    199     EXPECT_CALL(mock_reloader(), OnCaptivePortalResults(previous_result,
    200                                                         result)).Times(1);
    201     tab_helper().Observe(chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT,
    202                          source_profile,
    203                          details_results);
    204   }
    205 
    206   // Simulates a redirect.  Uses OnRedirect rather than Observe, for simplicity.
    207   void OnRedirect(ResourceType type, const GURL& new_url, int child_id) {
    208     tab_helper().OnRedirect(child_id, type, new_url);
    209   }
    210 
    211   MockCaptivePortalTabReloader& mock_reloader() { return *mock_reloader_; }
    212 
    213   void SetIsLoginTab() {
    214     tab_helper().SetIsLoginTab();
    215   }
    216 
    217   content::RenderViewHost* render_view_host1() {
    218     return web_contents1_->GetRenderViewHost();
    219   }
    220 
    221   content::RenderViewHost* render_view_host2() {
    222     return web_contents2_->GetRenderViewHost();
    223   }
    224 
    225   content::RenderFrameHost* main_render_frame1() {
    226     return web_contents1_->GetMainFrame();
    227   }
    228 
    229   content::RenderFrameHost* main_render_frame2() {
    230     return web_contents2_->GetMainFrame();
    231   }
    232 
    233  private:
    234   // Only the RenderViewHosts are used.
    235   scoped_ptr<content::WebContents> web_contents1_;
    236   scoped_ptr<content::WebContents> web_contents2_;
    237 
    238   CaptivePortalTabHelper tab_helper_;
    239 
    240   // Owned by |tab_helper_|.
    241   testing::StrictMock<MockCaptivePortalTabReloader>* mock_reloader_;
    242 
    243   DISALLOW_COPY_AND_ASSIGN(CaptivePortalTabHelperTest);
    244 };
    245 
    246 TEST_F(CaptivePortalTabHelperTest, HttpSuccess) {
    247   SimulateSuccess(GURL(kHttpUrl), render_view_host1());
    248   tab_helper().DidStopLoading(render_view_host1());
    249 }
    250 
    251 TEST_F(CaptivePortalTabHelperTest, HttpTimeout) {
    252   SimulateTimeout(GURL(kHttpUrl), render_view_host1());
    253   tab_helper().DidStopLoading(render_view_host1());
    254 }
    255 
    256 // Same as above, but simulates what happens when the Link Doctor is enabled,
    257 // which adds another provisional load/commit for the error page, after the
    258 // first two.
    259 TEST_F(CaptivePortalTabHelperTest, HttpTimeoutLinkDoctor) {
    260   SimulateTimeout(GURL(kHttpUrl), render_view_host1());
    261 
    262   EXPECT_CALL(mock_reloader(), OnLoadStart(false)).Times(1);
    263   // Provisional load starts for the error page.
    264   tab_helper().DidStartProvisionalLoadForFrame(
    265       main_render_frame1(), GURL(kErrorPageUrl), true, false);
    266 
    267   EXPECT_CALL(mock_reloader(), OnLoadCommitted(net::OK)).Times(1);
    268   tab_helper().DidCommitProvisionalLoadForFrame(main_render_frame1(),
    269                                                 GURL(kErrorPageUrl),
    270                                                 ui::PAGE_TRANSITION_LINK);
    271   tab_helper().DidStopLoading(render_view_host1());
    272 }
    273 
    274 TEST_F(CaptivePortalTabHelperTest, HttpsSuccess) {
    275   SimulateSuccess(GURL(kHttpsUrl), render_view_host1());
    276   tab_helper().DidStopLoading(render_view_host1());
    277   EXPECT_FALSE(tab_helper().IsLoginTab());
    278 }
    279 
    280 TEST_F(CaptivePortalTabHelperTest, HttpsTimeout) {
    281   SimulateTimeout(GURL(kHttpsUrl), render_view_host1());
    282   // Make sure no state was carried over from the timeout.
    283   SimulateSuccess(GURL(kHttpsUrl), render_view_host1());
    284   EXPECT_FALSE(tab_helper().IsLoginTab());
    285 }
    286 
    287 TEST_F(CaptivePortalTabHelperTest, HttpsAbort) {
    288   SimulateAbort(GURL(kHttpsUrl), render_view_host1(), kSameProcess);
    289   // Make sure no state was carried over from the abort.
    290   SimulateSuccess(GURL(kHttpsUrl), render_view_host1());
    291   EXPECT_FALSE(tab_helper().IsLoginTab());
    292 }
    293 
    294 // A cross-process navigation is aborted by a same-site navigation.
    295 TEST_F(CaptivePortalTabHelperTest, AbortCrossProcess) {
    296   SimulateAbort(GURL(kHttpsUrl2), render_view_host2(), kCrossProcess);
    297   // Make sure no state was carried over from the abort.
    298   SimulateSuccess(GURL(kHttpUrl), render_view_host1());
    299   EXPECT_FALSE(tab_helper().IsLoginTab());
    300 }
    301 
    302 // Abort while there's a provisional timeout error page loading.
    303 TEST_F(CaptivePortalTabHelperTest, HttpsAbortTimeout) {
    304   SimulateAbortTimeout(GURL(kHttpsUrl), render_view_host1(), kSameProcess);
    305   // Make sure no state was carried over from the timeout or the abort.
    306   SimulateSuccess(GURL(kHttpsUrl), render_view_host1());
    307   EXPECT_FALSE(tab_helper().IsLoginTab());
    308 }
    309 
    310 // Abort a cross-process navigation while there's a provisional timeout error
    311 // page loading.
    312 TEST_F(CaptivePortalTabHelperTest, AbortTimeoutCrossProcess) {
    313   SimulateAbortTimeout(GURL(kHttpsUrl2), render_view_host2(),
    314                        kCrossProcess);
    315   // Make sure no state was carried over from the timeout or the abort.
    316   SimulateSuccess(GURL(kHttpsUrl), render_view_host1());
    317   EXPECT_FALSE(tab_helper().IsLoginTab());
    318 }
    319 
    320 // Opposite case from above - a same-process error page is aborted in favor of
    321 // a cross-process one.
    322 TEST_F(CaptivePortalTabHelperTest, HttpsAbortTimeoutForCrossProcess) {
    323   SimulateAbortTimeout(GURL(kHttpsUrl), render_view_host1(), kSameProcess);
    324   // Make sure no state was carried over from the timeout or the abort.
    325   SimulateSuccess(GURL(kHttpsUrl2), render_view_host2());
    326   EXPECT_FALSE(tab_helper().IsLoginTab());
    327 }
    328 
    329 // A provisional same-site navigation is interrupted by a cross-process
    330 // navigation without sending an abort first.
    331 TEST_F(CaptivePortalTabHelperTest, UnexpectedProvisionalLoad) {
    332   GURL same_site_url = GURL(kHttpUrl);
    333   GURL cross_process_url = GURL(kHttpsUrl2);
    334 
    335   // A same-site load for the original RenderViewHost starts.
    336   EXPECT_CALL(mock_reloader(),
    337               OnLoadStart(same_site_url.SchemeIsSecure())).Times(1);
    338   tab_helper().DidStartProvisionalLoadForFrame(
    339       main_render_frame1(), same_site_url, false, false);
    340 
    341   // It's unexpectedly interrupted by a cross-process navigation, which starts
    342   // navigating before the old navigation cancels.  We generate an abort message
    343   // for the old navigation.
    344   EXPECT_CALL(mock_reloader(), OnAbort()).Times(1);
    345   EXPECT_CALL(mock_reloader(),
    346               OnLoadStart(cross_process_url.SchemeIsSecure())).Times(1);
    347   tab_helper().DidStartProvisionalLoadForFrame(
    348       main_render_frame2(), cross_process_url, false, false);
    349 
    350   // The cross-process navigation fails.
    351   tab_helper().DidFailProvisionalLoad(main_render_frame2(),
    352                                       cross_process_url,
    353                                       net::ERR_FAILED,
    354                                       base::string16());
    355 
    356   // The same-site navigation finally is aborted.
    357   tab_helper().DidFailProvisionalLoad(main_render_frame1(),
    358                                       same_site_url,
    359                                       net::ERR_ABORTED,
    360                                       base::string16());
    361 
    362   // The provisional load starts for the error page for the cross-process
    363   // navigation.
    364   tab_helper().DidStartProvisionalLoadForFrame(
    365       main_render_frame2(), GURL(kErrorPageUrl), true, false);
    366 
    367   EXPECT_CALL(mock_reloader(), OnLoadCommitted(net::ERR_FAILED)).Times(1);
    368   tab_helper().DidCommitProvisionalLoadForFrame(main_render_frame2(),
    369                                                 GURL(kErrorPageUrl),
    370                                                 ui::PAGE_TRANSITION_TYPED);
    371 }
    372 
    373 // Similar to the above test, except the original RenderViewHost manages to
    374 // commit before its navigation is aborted.
    375 TEST_F(CaptivePortalTabHelperTest, UnexpectedCommit) {
    376   GURL same_site_url = GURL(kHttpUrl);
    377   GURL cross_process_url = GURL(kHttpsUrl2);
    378 
    379   // A same-site load for the original RenderViewHost starts.
    380   EXPECT_CALL(mock_reloader(),
    381               OnLoadStart(same_site_url.SchemeIsSecure())).Times(1);
    382   tab_helper().DidStartProvisionalLoadForFrame(
    383       main_render_frame1(), same_site_url, false, false);
    384 
    385   // It's unexpectedly interrupted by a cross-process navigation, which starts
    386   // navigating before the old navigation cancels.  We generate an abort message
    387   // for the old navigation.
    388   EXPECT_CALL(mock_reloader(), OnAbort()).Times(1);
    389   EXPECT_CALL(mock_reloader(),
    390               OnLoadStart(cross_process_url.SchemeIsSecure())).Times(1);
    391   tab_helper().DidStartProvisionalLoadForFrame(
    392       main_render_frame2(), cross_process_url, false, false);
    393 
    394   // The cross-process navigation fails.
    395   tab_helper().DidFailProvisionalLoad(main_render_frame2(),
    396                                       cross_process_url,
    397                                       net::ERR_FAILED,
    398                                       base::string16());
    399 
    400   // The same-site navigation succeeds.
    401   EXPECT_CALL(mock_reloader(), OnAbort()).Times(1);
    402   EXPECT_CALL(mock_reloader(),
    403               OnLoadStart(same_site_url.SchemeIsSecure())).Times(1);
    404   EXPECT_CALL(mock_reloader(), OnLoadCommitted(net::OK)).Times(1);
    405   tab_helper().DidCommitProvisionalLoadForFrame(
    406       main_render_frame1(), same_site_url, ui::PAGE_TRANSITION_LINK);
    407 }
    408 
    409 // Simulates navigations for a number of subframes, and makes sure no
    410 // CaptivePortalTabHelper function is called.
    411 TEST_F(CaptivePortalTabHelperTest, HttpsSubframe) {
    412   GURL url = GURL(kHttpsUrl);
    413 
    414   content::RenderFrameHostTester* render_frame_host_tester =
    415       content::RenderFrameHostTester::For(main_render_frame1());
    416   content::RenderFrameHost* subframe1 =
    417       render_frame_host_tester->AppendChild("subframe1");
    418 
    419   // Normal load.
    420   tab_helper().DidStartProvisionalLoadForFrame(subframe1, url, false, false);
    421   tab_helper().DidCommitProvisionalLoadForFrame(
    422       subframe1, url, ui::PAGE_TRANSITION_LINK);
    423 
    424   // Timeout.
    425   content::RenderFrameHost* subframe2 =
    426       render_frame_host_tester->AppendChild("subframe2");
    427   tab_helper().DidStartProvisionalLoadForFrame(subframe2, url, false, false);
    428   tab_helper().DidFailProvisionalLoad(
    429       subframe2, url, net::ERR_TIMED_OUT, base::string16());
    430   tab_helper().DidStartProvisionalLoadForFrame(subframe2, url, true, false);
    431   tab_helper().DidFailProvisionalLoad(
    432       subframe2, url, net::ERR_ABORTED, base::string16());
    433 
    434   // Abort.
    435   content::RenderFrameHost* subframe3 =
    436       render_frame_host_tester->AppendChild("subframe3");
    437   tab_helper().DidStartProvisionalLoadForFrame(subframe3, url, false, false);
    438   tab_helper().DidFailProvisionalLoad(
    439       subframe3, url, net::ERR_ABORTED, base::string16());
    440 }
    441 
    442 // Simulates a subframe erroring out at the same time as a provisional load,
    443 // but with a different error code.  Make sure the TabHelper sees the correct
    444 // error.
    445 TEST_F(CaptivePortalTabHelperTest, HttpsSubframeParallelError) {
    446   // URL used by both frames.
    447   GURL url = GURL(kHttpsUrl);
    448   content::RenderFrameHost* subframe =
    449       content::RenderFrameHostTester::For(main_render_frame1())
    450           ->AppendChild("subframe");
    451 
    452   // Loads start.
    453   EXPECT_CALL(mock_reloader(), OnLoadStart(url.SchemeIsSecure())).Times(1);
    454   tab_helper().DidStartProvisionalLoadForFrame(
    455       main_render_frame1(), url, false, false);
    456   tab_helper().DidStartProvisionalLoadForFrame(subframe, url, false, false);
    457 
    458   // Loads return errors.
    459   tab_helper().DidFailProvisionalLoad(
    460       main_render_frame1(), url, net::ERR_UNEXPECTED, base::string16());
    461   tab_helper().DidFailProvisionalLoad(
    462       subframe, url, net::ERR_TIMED_OUT, base::string16());
    463 
    464   // Provisional load starts for the error pages.
    465   tab_helper().DidStartProvisionalLoadForFrame(
    466       main_render_frame1(), url, true, false);
    467   tab_helper().DidStartProvisionalLoadForFrame(subframe, url, true, false);
    468 
    469   // Error page load finishes.
    470   tab_helper().DidCommitProvisionalLoadForFrame(
    471       subframe, url, ui::PAGE_TRANSITION_AUTO_SUBFRAME);
    472   EXPECT_CALL(mock_reloader(), OnLoadCommitted(net::ERR_UNEXPECTED)).Times(1);
    473   tab_helper().DidCommitProvisionalLoadForFrame(
    474       main_render_frame1(), url, ui::PAGE_TRANSITION_LINK);
    475 }
    476 
    477 // Simulates an HTTP to HTTPS redirect, which then times out.
    478 TEST_F(CaptivePortalTabHelperTest, HttpToHttpsRedirectTimeout) {
    479   GURL http_url(kHttpUrl);
    480   EXPECT_CALL(mock_reloader(), OnLoadStart(false)).Times(1);
    481   tab_helper().DidStartProvisionalLoadForFrame(
    482       main_render_frame1(), http_url, false, false);
    483 
    484   GURL https_url(kHttpsUrl);
    485   EXPECT_CALL(mock_reloader(), OnRedirect(true)).Times(1);
    486   OnRedirect(content::RESOURCE_TYPE_MAIN_FRAME,
    487              https_url,
    488              render_view_host1()->GetProcess()->GetID());
    489 
    490   tab_helper().DidFailProvisionalLoad(main_render_frame1(),
    491                                       https_url,
    492                                       net::ERR_TIMED_OUT,
    493                                       base::string16());
    494 
    495   // Provisional load starts for the error page.
    496   tab_helper().DidStartProvisionalLoadForFrame(
    497       main_render_frame1(), GURL(kErrorPageUrl), true, false);
    498 
    499   EXPECT_CALL(mock_reloader(), OnLoadCommitted(net::ERR_TIMED_OUT)).Times(1);
    500   tab_helper().DidCommitProvisionalLoadForFrame(main_render_frame1(),
    501                                                 GURL(kErrorPageUrl),
    502                                                 ui::PAGE_TRANSITION_LINK);
    503 }
    504 
    505 // Simulates an HTTPS to HTTP redirect.
    506 TEST_F(CaptivePortalTabHelperTest, HttpsToHttpRedirect) {
    507   GURL https_url(kHttpsUrl);
    508   EXPECT_CALL(mock_reloader(),
    509               OnLoadStart(https_url.SchemeIsSecure())).Times(1);
    510   tab_helper().DidStartProvisionalLoadForFrame(
    511       main_render_frame1(), https_url, false, false);
    512 
    513   GURL http_url(kHttpUrl);
    514   EXPECT_CALL(mock_reloader(), OnRedirect(http_url.SchemeIsSecure())).Times(1);
    515   OnRedirect(content::RESOURCE_TYPE_MAIN_FRAME, http_url,
    516              render_view_host1()->GetProcess()->GetID());
    517 
    518   EXPECT_CALL(mock_reloader(), OnLoadCommitted(net::OK)).Times(1);
    519   tab_helper().DidCommitProvisionalLoadForFrame(
    520       main_render_frame1(), http_url, ui::PAGE_TRANSITION_LINK);
    521 }
    522 
    523 // Simulates an HTTPS to HTTPS redirect.
    524 TEST_F(CaptivePortalTabHelperTest, HttpToHttpRedirect) {
    525   GURL http_url(kHttpUrl);
    526   EXPECT_CALL(mock_reloader(),
    527               OnLoadStart(http_url.SchemeIsSecure())).Times(1);
    528   tab_helper().DidStartProvisionalLoadForFrame(
    529       main_render_frame1(), http_url, false, false);
    530 
    531   EXPECT_CALL(mock_reloader(), OnRedirect(http_url.SchemeIsSecure())).Times(1);
    532   OnRedirect(content::RESOURCE_TYPE_MAIN_FRAME, http_url,
    533              render_view_host1()->GetProcess()->GetID());
    534 
    535   EXPECT_CALL(mock_reloader(), OnLoadCommitted(net::OK)).Times(1);
    536   tab_helper().DidCommitProvisionalLoadForFrame(
    537       main_render_frame1(), http_url, ui::PAGE_TRANSITION_LINK);
    538 }
    539 
    540 // Tests that a subframe redirect doesn't reset the timer to kick off a captive
    541 // portal probe for the main frame if the main frame request is taking too long.
    542 TEST_F(CaptivePortalTabHelperTest, SubframeRedirect) {
    543   GURL http_url(kHttpUrl);
    544   EXPECT_CALL(mock_reloader(), OnLoadStart(false)).Times(1);
    545   tab_helper().DidStartProvisionalLoadForFrame(
    546       main_render_frame1(), http_url, false, false);
    547 
    548   GURL https_url(kHttpsUrl);
    549   OnRedirect(content::RESOURCE_TYPE_SUB_FRAME,
    550              https_url,
    551              render_view_host1()->GetProcess()->GetID());
    552 
    553   EXPECT_CALL(mock_reloader(), OnLoadCommitted(net::OK)).Times(1);
    554   tab_helper().DidCommitProvisionalLoadForFrame(
    555       main_render_frame1(), GURL(kErrorPageUrl), ui::PAGE_TRANSITION_LINK);
    556 }
    557 
    558 // Simulates a redirect, for another RenderViewHost.
    559 TEST_F(CaptivePortalTabHelperTest, OtherRenderViewHostRedirect) {
    560   GURL http_url(kHttpUrl);
    561   EXPECT_CALL(mock_reloader(), OnLoadStart(false)).Times(1);
    562   tab_helper().DidStartProvisionalLoadForFrame(
    563       main_render_frame1(), http_url, false, false);
    564 
    565   // Another RenderViewHost sees a redirect.  None of the reloader's functions
    566   // should be called.
    567   GURL https_url(kHttpsUrl);
    568   OnRedirect(content::RESOURCE_TYPE_MAIN_FRAME,
    569              https_url,
    570              render_view_host2()->GetProcess()->GetID());
    571 
    572   tab_helper().DidFailProvisionalLoad(main_render_frame1(),
    573                                       https_url,
    574                                       net::ERR_TIMED_OUT,
    575                                       base::string16());
    576 
    577   // Provisional load starts for the error page.
    578   tab_helper().DidStartProvisionalLoadForFrame(
    579       main_render_frame1(), GURL(kErrorPageUrl), true, false);
    580 
    581   EXPECT_CALL(mock_reloader(), OnLoadCommitted(net::ERR_TIMED_OUT)).Times(1);
    582   tab_helper().DidCommitProvisionalLoadForFrame(main_render_frame1(),
    583                                                 GURL(kErrorPageUrl),
    584                                                 ui::PAGE_TRANSITION_LINK);
    585 }
    586 
    587 TEST_F(CaptivePortalTabHelperTest, LoginTabLogin) {
    588   EXPECT_FALSE(tab_helper().IsLoginTab());
    589   SetIsLoginTab();
    590   EXPECT_TRUE(tab_helper().IsLoginTab());
    591 
    592   ObservePortalResult(captive_portal::RESULT_INTERNET_CONNECTED,
    593                       captive_portal::RESULT_INTERNET_CONNECTED);
    594   EXPECT_FALSE(tab_helper().IsLoginTab());
    595 }
    596 
    597 TEST_F(CaptivePortalTabHelperTest, LoginTabError) {
    598   EXPECT_FALSE(tab_helper().IsLoginTab());
    599 
    600   SetIsLoginTab();
    601   EXPECT_TRUE(tab_helper().IsLoginTab());
    602 
    603   ObservePortalResult(captive_portal::RESULT_INTERNET_CONNECTED,
    604                       captive_portal::RESULT_NO_RESPONSE);
    605   EXPECT_FALSE(tab_helper().IsLoginTab());
    606 }
    607 
    608 TEST_F(CaptivePortalTabHelperTest, LoginTabMultipleResultsBeforeLogin) {
    609   EXPECT_FALSE(tab_helper().IsLoginTab());
    610 
    611   SetIsLoginTab();
    612   EXPECT_TRUE(tab_helper().IsLoginTab());
    613 
    614   ObservePortalResult(captive_portal::RESULT_INTERNET_CONNECTED,
    615                       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL);
    616   EXPECT_TRUE(tab_helper().IsLoginTab());
    617 
    618   ObservePortalResult(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
    619                       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL);
    620   EXPECT_TRUE(tab_helper().IsLoginTab());
    621 
    622   ObservePortalResult(captive_portal::RESULT_NO_RESPONSE,
    623                       captive_portal::RESULT_INTERNET_CONNECTED);
    624   EXPECT_FALSE(tab_helper().IsLoginTab());
    625 }
    626 
    627 TEST_F(CaptivePortalTabHelperTest, NoLoginTab) {
    628   EXPECT_FALSE(tab_helper().IsLoginTab());
    629 
    630   ObservePortalResult(captive_portal::RESULT_INTERNET_CONNECTED,
    631                       captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL);
    632   EXPECT_FALSE(tab_helper().IsLoginTab());
    633 
    634   ObservePortalResult(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
    635                       captive_portal::RESULT_NO_RESPONSE);
    636   EXPECT_FALSE(tab_helper().IsLoginTab());
    637 
    638   ObservePortalResult(captive_portal::RESULT_NO_RESPONSE,
    639                       captive_portal::RESULT_INTERNET_CONNECTED);
    640   EXPECT_FALSE(tab_helper().IsLoginTab());
    641 }
    642