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 22 namespace captive_portal { 23 24 // Used for testing CaptivePortalTabReloader in isolation from the observer. 25 // Exposes a number of private functions and mocks out others. 26 class 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. 63 class 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 89 class 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. 114 TEST_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. 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(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. 162 TEST_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. 187 TEST_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. 208 TEST_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. 244 TEST_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. 275 TEST_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. 303 TEST_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. 332 TEST_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. 352 TEST_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. 371 TEST_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. 400 TEST_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. 423 TEST_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. 448 TEST_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. 495 TEST_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. 514 TEST_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. 544 TEST_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. 573 TEST_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. 616 TEST_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. 635 TEST_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. 649 TEST_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. 667 TEST_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