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