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