Index: chrome/browser/captive_portal/captive_portal_browsertest.cc |
=================================================================== |
--- chrome/browser/captive_portal/captive_portal_browsertest.cc (revision 0) |
+++ chrome/browser/captive_portal/captive_portal_browsertest.cc (revision 0) |
@@ -0,0 +1,1693 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include <map> |
+#include <set> |
+ |
+#include "base/basictypes.h" |
+#include "base/bind.h" |
+#include "base/command_line.h" |
+#include "base/compiler_specific.h" |
+#include "base/file_path.h" |
+#include "base/message_loop.h" |
+#include "base/path_service.h" |
+#include "base/utf_string_conversions.h" |
+#include "chrome/browser/captive_portal/captive_portal_service.h" |
+#include "chrome/browser/captive_portal/captive_portal_service_factory.h" |
+#include "chrome/browser/captive_portal/captive_portal_tab_helper.h" |
+#include "chrome/browser/captive_portal/captive_portal_tab_reloader.h" |
+#include "chrome/browser/net/url_request_mock_util.h" |
+#include "chrome/browser/prefs/pref_service.h" |
+#include "chrome/browser/profiles/profile.h" |
+#include "chrome/browser/ui/browser.h" |
+#include "chrome/browser/ui/browser_finder.h" |
+#include "chrome/browser/ui/browser_navigator.h" |
+#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" |
+#include "chrome/browser/ui/tab_contents/tab_contents.h" |
+#include "chrome/common/chrome_notification_types.h" |
+#include "chrome/common/chrome_paths.h" |
+#include "chrome/common/chrome_switches.h" |
+#include "chrome/common/pref_names.h" |
+#include "chrome/test/base/in_process_browser_test.h" |
+#include "chrome/test/base/ui_test_utils.h" |
+#include "content/public/browser/browser_thread.h" |
+#include "content/public/browser/navigation_controller.h" |
+#include "content/public/browser/notification_observer.h" |
+#include "content/public/browser/notification_registrar.h" |
+#include "content/public/browser/notification_service.h" |
+#include "content/public/browser/notification_types.h" |
+#include "content/public/browser/render_view_host.h" |
+#include "content/public/browser/web_contents.h" |
+#include "content/public/common/url_constants.h" |
+#include "content/test/net/url_request_failed_job.h" |
+#include "content/test/net/url_request_mock_http_job.h" |
+#include "net/base/net_errors.h" |
+#include "net/url_request/url_request_filter.h" |
+#include "net/url_request/url_request_job.h" |
+#include "net/url_request/url_request_status.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+using content::BrowserThread; |
+ |
+namespace captive_portal { |
+ |
+namespace { |
+ |
+// Path of the fake login page, when using the TestServer. |
+const char* const kTestServerLoginPath = "files/captive_portal/login.html"; |
+ |
+// Path of a page with an iframe that has a mock SSL timeout, when using the |
+// TestServer. |
+const char* const kTestServerIframeTimeoutPath = |
+ "files/captive_portal/iframe_timeout.html"; |
+ |
+// The following URLs each have two different behaviors, depending on whether |
+// URLRequestMockCaptivePortalJobFactory is currently simulating the presence |
+// of a captive portal or not. |
+ |
+// A mock URL for the CaptivePortalService's |test_url|. When behind a captive |
+// portal, this URL return a mock login page. When connected to the Internet, |
+// it returns a 204 response. |
+const char* const kMockCaptivePortalTestUrl = |
+ "http://mock.captive.portal/captive_portal_test/"; |
+ |
+// When behind a captive portal, this URL hangs without committing until a call |
+// to URLRequestTimeoutOnDemandJob::FailRequests. When that function is called, |
+// the request will time out. |
+// |
+// When connected to the Internet, this URL returns a non-error page. |
+const char* const kMockHttpsUrl = "https://mock.captive.portal/long_timeout/"; |
+ |
+// Same as kMockHttpsUrl, except the timeout happens instantly. |
+const char* const kMockHttpsQuickTimeoutUrl = |
+ "https://mock.captive.portal/quick_timeout/"; |
+ |
+// Expected title of a tab once an HTTPS load completes, when not behind a |
+// captive portal. |
+const char* const kInternetConnectedTitle = "Title Of Awesomeness"; |
+ |
+// A URL request job that hangs until FailRequests() is called. Started jobs |
+// are stored in a static class variable containing a linked list so that |
+// FailRequests() can locate them. |
+class URLRequestTimeoutOnDemandJob : public net::URLRequestJob, |
+ public base::NonThreadSafe { |
+ public: |
+ // net::URLRequestJob: |
+ virtual void Start() OVERRIDE; |
+ |
+ // All the public static methods below can be called on any thread. |
+ |
+ // Fails all active URLRequestFailOnDemandJobs with connection timeouts. |
+ // Must only be called when there are requests that have been started but not |
+ // yet timed out. |
+ static void FailRequests(); |
+ |
+ // Clears the |waiting_jobs_list_| without having the jobs return anything. |
+ // Used to allow an assertion that jobs are not in the |waiting_jobs_list_| |
+ // when destroyed. Must only be called when there are requests that have |
+ // been started but not yet timed out. |
+ static void AbandonRequests(); |
+ |
+ private: |
+ friend class URLRequestMockCaptivePortalJobFactory; |
+ |
+ explicit URLRequestTimeoutOnDemandJob(net::URLRequest* request); |
+ virtual ~URLRequestTimeoutOnDemandJob(); |
+ |
+ // Attempts to removes |this| from |jobs_|. Returns true if it was removed |
+ // from the list. |
+ bool RemoveFromList(); |
+ |
+ // These do all the work of the corresponding public functions, with the only |
+ // difference being that they must be called on the IO thread. |
+ static void FailRequestsOnIOThread(); |
+ static void AbandonRequestsOnIOThread(); |
+ |
+ // Head of linked list of jobs that have been started and are now waiting to |
+ // be timed out. |
+ static URLRequestTimeoutOnDemandJob* job_list_; |
+ |
+ // The next job that had been started but not yet timed out. |
+ URLRequestTimeoutOnDemandJob* next_job_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(URLRequestTimeoutOnDemandJob); |
+}; |
+ |
+URLRequestTimeoutOnDemandJob* URLRequestTimeoutOnDemandJob::job_list_ = NULL; |
+ |
+void URLRequestTimeoutOnDemandJob::Start() { |
+ EXPECT_TRUE(CalledOnValidThread()); |
+ |
+ // Insert at start of the list. |
+ next_job_ = job_list_; |
+ job_list_ = this; |
+} |
+ |
+// static |
+void URLRequestTimeoutOnDemandJob::FailRequests() { |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::IO, FROM_HERE, |
+ base::Bind(&URLRequestTimeoutOnDemandJob::FailRequestsOnIOThread)); |
+} |
+ |
+// static |
+void URLRequestTimeoutOnDemandJob::AbandonRequests() { |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::IO, FROM_HERE, |
+ base::Bind(&URLRequestTimeoutOnDemandJob::AbandonRequestsOnIOThread)); |
+} |
+ |
+URLRequestTimeoutOnDemandJob::URLRequestTimeoutOnDemandJob( |
+ net::URLRequest* request) |
+ : net::URLRequestJob(request), |
+ next_job_(NULL) { |
+} |
+ |
+URLRequestTimeoutOnDemandJob::~URLRequestTimeoutOnDemandJob() { |
+ // |this| shouldn't be in the list. |
+ EXPECT_FALSE(RemoveFromList()); |
+} |
+ |
+bool URLRequestTimeoutOnDemandJob::RemoveFromList() { |
+ URLRequestTimeoutOnDemandJob** job = &job_list_; |
+ while (*job) { |
+ if (*job == this) { |
+ *job = next_job_; |
+ next_job_ = NULL; |
+ return true; |
+ } |
+ job = &next_job_; |
+ } |
+ |
+ // If the job wasn't in this list, |next_job_| should be NULL. |
+ EXPECT_FALSE(next_job_); |
+ return false; |
+} |
+ |
+// static |
+void URLRequestTimeoutOnDemandJob::FailRequestsOnIOThread() { |
+ ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ EXPECT_TRUE(job_list_); |
+ while (job_list_) { |
+ URLRequestTimeoutOnDemandJob* job = job_list_; |
+ // Since the error notification may result in the job's destruction, remove |
+ // it from the job list before the error. |
+ EXPECT_TRUE(job->RemoveFromList()); |
+ job->NotifyStartError(net::URLRequestStatus( |
+ net::URLRequestStatus::FAILED, |
+ net::ERR_CONNECTION_TIMED_OUT)); |
+ } |
+} |
+ |
+// static |
+void URLRequestTimeoutOnDemandJob::AbandonRequestsOnIOThread() { |
+ ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ EXPECT_TRUE(job_list_); |
+ while (job_list_) |
+ EXPECT_TRUE(job_list_->RemoveFromList()); |
+} |
+ |
+// URLRequestCaptivePortalJobFactory emulates captive portal behavior. |
+// Initially, it emulates being behind a captive portal. When |
+// SetBehindCaptivePortal(false) is called, it emulates behavior when not behind |
+// a captive portal. The class itself is never instantiated. |
+// |
+// It handles requests for kMockCaptivePortalTestUrl, kMockHttpsUrl, and |
+// kMockHttpsQuickTimeoutUrl. |
+class URLRequestMockCaptivePortalJobFactory { |
+ public: |
+ // The public static methods below can be called on any thread. |
+ |
+ // Adds the testing URLs to the net::URLRequestFilter. Should only be called |
+ // once. |
+ static void AddUrlHandlers(); |
+ |
+ // Sets whether or not there is a captive portal. Outstanding requests are |
+ // not affected. |
+ static void SetBehindCaptivePortal(bool behind_captive_portal); |
+ |
+ private: |
+ // These do all the work of the corresponding public functions, with the only |
+ // difference being that they must be called on the IO thread. |
+ static void AddUrlHandlersOnIOThread(); |
+ static void SetBehindCaptivePortalOnIOThread(bool behind_captive_portal); |
+ |
+ // Returns a URLRequestJob that reflects the current captive portal state |
+ // for the URLs: kMockCaptivePortalTestUrl, kMockHttpsUrl, and |
+ // kMockHttpsQuickTimeoutUrl. See documentation of individual URLs for |
+ // actual behavior. |
+ static net::URLRequestJob* Factory(net::URLRequest* request, |
+ const std::string& scheme); |
+ |
+ static bool behind_captive_portal_; |
+ |
+ DISALLOW_IMPLICIT_CONSTRUCTORS(URLRequestMockCaptivePortalJobFactory); |
+}; |
+ |
+bool URLRequestMockCaptivePortalJobFactory::behind_captive_portal_ = true; |
+ |
+// static |
+void URLRequestMockCaptivePortalJobFactory::AddUrlHandlers() { |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::IO, FROM_HERE, |
+ base::Bind( |
+ &URLRequestMockCaptivePortalJobFactory::AddUrlHandlersOnIOThread)); |
+} |
+ |
+// static |
+void URLRequestMockCaptivePortalJobFactory::SetBehindCaptivePortal( |
+ bool behind_captive_portal) { |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::IO, FROM_HERE, |
+ base::Bind( |
+ &URLRequestMockCaptivePortalJobFactory:: |
+ SetBehindCaptivePortalOnIOThread, |
+ behind_captive_portal)); |
+} |
+ |
+// static |
+void URLRequestMockCaptivePortalJobFactory::AddUrlHandlersOnIOThread() { |
+ EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance(); |
+ filter->AddHostnameHandler("http", "mock.captive.portal", |
+ URLRequestMockCaptivePortalJobFactory::Factory); |
+ filter->AddHostnameHandler("https", "mock.captive.portal", |
+ URLRequestMockCaptivePortalJobFactory::Factory); |
+} |
+ |
+// static |
+void URLRequestMockCaptivePortalJobFactory::SetBehindCaptivePortalOnIOThread( |
+ bool behind_captive_portal) { |
+ EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ behind_captive_portal_ = behind_captive_portal; |
+} |
+ |
+// static |
+net::URLRequestJob* URLRequestMockCaptivePortalJobFactory::Factory( |
+ net::URLRequest* request, |
+ const std::string& scheme) { |
+ EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ |
+ // The PathService is threadsafe. |
+ FilePath root_http; |
+ PathService::Get(chrome::DIR_TEST_DATA, &root_http); |
+ |
+ if (scheme == "https") { |
+ if (behind_captive_portal_) { |
+ // If not logged in to the captive portal, HTTPS requests will time out, |
+ // either immediately on on demand. |
+ if (request->url() == GURL(kMockHttpsQuickTimeoutUrl)) |
+ return new URLRequestFailedJob(request, net::ERR_CONNECTION_TIMED_OUT); |
+ return new URLRequestTimeoutOnDemandJob(request); |
+ } |
+ // Once logged in to the portal, HTTPS requests return the page that was |
+ // actually requested. |
+ return new URLRequestMockHTTPJob( |
+ request, |
+ root_http.Append(FILE_PATH_LITERAL("title2.html"))); |
+ } |
+ |
+ // The URL is the captive portal test URL. |
+ |
+ if (behind_captive_portal_) { |
+ // Prior to logging in to the portal, HTTP requests go to the login page. |
+ return new URLRequestMockHTTPJob( |
+ request, |
+ root_http.Append( |
+ FILE_PATH_LITERAL("captive_portal/login.html"))); |
+ } |
+ // After logging in to the portal, the test URL returns a 204 response. |
+ return new URLRequestMockHTTPJob( |
+ request, |
+ root_http.Append( |
+ FILE_PATH_LITERAL("captive_portal/page204.html"))); |
+} |
+ |
+// Creates a server-side redirect for use with the TestServer. |
+std::string CreateServerRedirect(const std::string& dest_url) { |
+ const char* const kServerRedirectBase = "server-redirect?"; |
+ return kServerRedirectBase + dest_url; |
+} |
+ |
+// Returns the total number of loading tabs across all Browsers, for all |
+// Profiles. |
+int NumLoadingTabs() { |
+ int num_loading_tabs = 0; |
+ for (TabContentsIterator tab_contents_it; |
+ !tab_contents_it.done(); |
+ ++tab_contents_it) { |
+ if (tab_contents_it->web_contents()->IsLoading()) |
+ ++num_loading_tabs; |
+ } |
+ return num_loading_tabs; |
+} |
+ |
+bool IsLoginTab(TabContents* tab_contents) { |
+ return tab_contents->captive_portal_tab_helper()->IsLoginTab(); |
+} |
+ |
+// Tracks how many times each tab has been navigated since the Observer was |
+// created. The standard TestNavigationObserver can only watch specific |
+// pre-existing tabs or loads in serial for all tabs. |
+class MultiNavigationObserver : public content::NotificationObserver { |
+ public: |
+ MultiNavigationObserver(); |
+ virtual ~MultiNavigationObserver(); |
+ |
+ // Waits for exactly |num_navigations_to_wait_for| LOAD_STOP |
+ // notifications to have occurred since the construction of |this|. More |
+ // navigations than expected occuring will trigger a expect failure. |
+ void WaitForNavigations(int num_navigations_to_wait_for); |
+ |
+ // Returns the number of LOAD_STOP events that have occurred for |
+ // |web_contents| since this was constructed. |
+ int NumNavigationsForTab(content::WebContents* web_contents) const; |
+ |
+ // The number of LOAD_STOP events since |this| was created. |
+ int num_navigations() const { return num_navigations_; } |
+ |
+ private: |
+ typedef std::map<content::WebContents*, int> TabNavigationMap; |
+ |
+ // content::NotificationObserver: |
+ virtual void Observe(int type, const content::NotificationSource& source, |
+ const content::NotificationDetails& details) OVERRIDE; |
+ |
+ int num_navigations_; |
+ |
+ // Map of how many times each tab has navigated since |this| was created. |
+ TabNavigationMap tab_navigation_map_; |
+ |
+ // Total number of navigations to wait for. Value only matters when |
+ // |waiting_for_navigation_| is true. |
+ int num_navigations_to_wait_for_; |
+ |
+ // True if WaitForNavigations has been called, until |
+ // |num_navigations_to_wait_for_| have been observed. |
+ bool waiting_for_navigation_; |
+ |
+ content::NotificationRegistrar registrar_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(MultiNavigationObserver); |
+}; |
+ |
+MultiNavigationObserver::MultiNavigationObserver() |
+ : num_navigations_(0), |
+ num_navigations_to_wait_for_(0), |
+ waiting_for_navigation_(false) { |
+ registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, |
+ content::NotificationService::AllSources()); |
+} |
+ |
+MultiNavigationObserver::~MultiNavigationObserver() { |
+} |
+ |
+void MultiNavigationObserver::WaitForNavigations( |
+ int num_navigations_to_wait_for) { |
+ // Shouldn't already be waiting for navigations. |
+ EXPECT_FALSE(waiting_for_navigation_); |
+ EXPECT_LT(0, num_navigations_to_wait_for); |
+ if (num_navigations_ < num_navigations_to_wait_for) { |
+ num_navigations_to_wait_for_ = num_navigations_to_wait_for; |
+ waiting_for_navigation_ = true; |
+ ui_test_utils::RunMessageLoop(); |
+ EXPECT_FALSE(waiting_for_navigation_); |
+ } |
+ EXPECT_EQ(num_navigations_, num_navigations_to_wait_for); |
+} |
+ |
+int MultiNavigationObserver::NumNavigationsForTab( |
+ content::WebContents* web_contents) const { |
+ TabNavigationMap::const_iterator tab_navigations = |
+ tab_navigation_map_.find(web_contents); |
+ if (tab_navigations == tab_navigation_map_.end()) |
+ return 0; |
+ return tab_navigations->second; |
+} |
+ |
+void MultiNavigationObserver::Observe( |
+ int type, |
+ const content::NotificationSource& source, |
+ const content::NotificationDetails& details) { |
+ ASSERT_EQ(type, content::NOTIFICATION_LOAD_STOP); |
+ content::NavigationController* controller = |
+ content::Source<content::NavigationController>(source).ptr(); |
+ ++num_navigations_; |
+ ++tab_navigation_map_[controller->GetWebContents()]; |
+ if (waiting_for_navigation_ && |
+ num_navigations_to_wait_for_ == num_navigations_) { |
+ waiting_for_navigation_ = false; |
+ MessageLoopForUI::current()->Quit(); |
+ } |
+} |
+ |
+// An observer for watching the CaptivePortalService. It tracks the last |
+// received result and the total number of received results. |
+class CaptivePortalObserver : public content::NotificationObserver { |
+ public: |
+ explicit CaptivePortalObserver(Profile* profile); |
+ |
+ // Runs the message loop until until at exactly |update_count| capitive portal |
+ // results have been received, since this creation of |this|. Expects no |
+ // additional captive portal results. |
+ void WaitForResults(int num_results_to_wait_for); |
+ |
+ int num_results_received() const { return num_results_received_; } |
+ |
+ Result captive_portal_result() const { |
+ return captive_portal_result_; |
+ } |
+ |
+ private: |
+ // Records results and exits the message loop, if needed. |
+ void Observe(int type, |
+ const content::NotificationSource& source, |
+ const content::NotificationDetails& details); |
+ |
+ // Number of times OnPortalResult has been called since construction. |
+ int num_results_received_; |
+ |
+ // If WaitForResults was called, the total number of updates for which to |
+ // wait. Value doesn't matter when |waiting_for_result_| is false. |
+ int num_results_to_wait_for_; |
+ |
+ bool waiting_for_result_; |
+ |
+ Profile* profile_; |
+ |
+ CaptivePortalService* captive_portal_service_; |
+ |
+ // Last result received. |
+ Result captive_portal_result_; |
+ |
+ content::NotificationRegistrar registrar_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(CaptivePortalObserver); |
+}; |
+ |
+CaptivePortalObserver::CaptivePortalObserver(Profile* profile) |
+ : num_results_received_(0), |
+ num_results_to_wait_for_(0), |
+ waiting_for_result_(false), |
+ profile_(profile), |
+ captive_portal_service_( |
+ CaptivePortalServiceFactory::GetForProfile(profile)), |
+ captive_portal_result_( |
+ captive_portal_service_->last_detection_result()) { |
+ registrar_.Add(this, |
+ chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT, |
+ content::Source<Profile>(profile_)); |
+} |
+ |
+void CaptivePortalObserver::WaitForResults(int num_results_to_wait_for) { |
+ EXPECT_LT(0, num_results_to_wait_for); |
+ EXPECT_FALSE(waiting_for_result_); |
+ if (num_results_received_ < num_results_to_wait_for) { |
+ num_results_to_wait_for_ = num_results_to_wait_for; |
+ waiting_for_result_ = true; |
+ ui_test_utils::RunMessageLoop(); |
+ EXPECT_FALSE(waiting_for_result_); |
+ } |
+ EXPECT_EQ(num_results_received_, num_results_to_wait_for); |
+} |
+ |
+void CaptivePortalObserver::Observe( |
+ int type, |
+ const content::NotificationSource& source, |
+ const content::NotificationDetails& details) { |
+ ASSERT_EQ(type, chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT); |
+ ASSERT_EQ(profile_, content::Source<Profile>(source).ptr()); |
+ |
+ CaptivePortalService::Results* results = |
+ content::Details<CaptivePortalService::Results>(details).ptr(); |
+ |
+ EXPECT_EQ(captive_portal_result_, results->previous_result); |
+ EXPECT_EQ(captive_portal_service_->last_detection_result(), |
+ results->result); |
+ |
+ captive_portal_result_ = results->result; |
+ ++num_results_received_; |
+ |
+ if (waiting_for_result_ && |
+ num_results_to_wait_for_ == num_results_received_) { |
+ waiting_for_result_ = false; |
+ MessageLoop::current()->Quit(); |
+ } |
+} |
+ |
+} // namespace |
+ |
+class CaptivePortalBrowserTest : public InProcessBrowserTest { |
+ public: |
+ CaptivePortalBrowserTest(); |
+ |
+ // InProcessBrowserTest: |
+ virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE; |
+ virtual void SetUpOnMainThread() OVERRIDE; |
+ virtual void CleanUpOnMainThread() OVERRIDE; |
+ |
+ // Sets the captive portal checking preference. Does not affect the command |
+ // line flag, which is set in SetUpCommandLine. |
+ void EnableCaptivePortalDetection(Profile* profile, bool enabled); |
+ |
+ // Sets up the captive portal service for the given profile so that |
+ // all checks go to |test_url|. Also disables all timers. |
+ void SetUpCaptivePortalService(Profile* profile, const GURL& test_url); |
+ |
+ // Returns true if |browser|'s profile is currently running a captive portal |
+ // check. |
+ bool CheckPending(Browser* browser); |
+ |
+ // Returns the CaptivePortalTabReloader::State of |tab_contents|. |
+ CaptivePortalTabReloader::State GetStateOfTabReloader( |
+ TabContents* tab_contents) const; |
+ |
+ // Returns the CaptivePortalTabReloader::State of the indicated tab. |
+ CaptivePortalTabReloader::State GetStateOfTabReloaderAt(Browser* browser, |
+ int index) const; |
+ |
+ // Returns the number of tabs with the given state, across all profiles. |
+ int NumTabsWithState(CaptivePortalTabReloader::State state) const; |
+ |
+ // Returns the number of tabs broken by captive portals, across all profiles. |
+ int NumBrokenTabs() const; |
+ |
+ // Returns the number of tabs that need to be reloaded due to having logged |
+ // in to a captive portal, across all profiles. |
+ int NumNeedReloadTabs() const; |
+ |
+ // Navigates |browser|'s active tab to |url| and expects no captive portal |
+ // test to be triggered. |expected_navigations| is the number of times the |
+ // active tab will end up being navigated. It should be 1, except for the |
+ // Link Doctor page, which acts like two navigations. |
+ void NavigateToPageExpectNoTest(Browser* browser, |
+ const GURL& url, |
+ int expected_navigations); |
+ |
+ // Navigates |browser|'s active tab to an SSL tab that takes a while to load, |
+ // triggering a captive portal check, which is expected to give the result |
+ // |expected_result|. The page finishes loading, with a timeout, after the |
+ // captive portal check. |
+ void SlowLoadNoCaptivePortal(Browser* browser, Result expected_result); |
+ |
+ // Navigates |browser|'s active tab to an SSL timeout, expecting a captive |
+ // portal check to be triggered and return a result which will indicates |
+ // there's no detected captive portal. |
+ void FastTimeoutNoCaptivePortal(Browser* browser, Result expected_result); |
+ |
+ // Navigates the active tab to a slow loading SSL page, which will then |
+ // trigger a captive portal test. The test is expected to find a captive |
+ // portal. The slow loading page will continue to load after the function |
+ // returns, until URLRequestTimeoutOnDemandJob::FailRequests() is called, |
+ // at which point it will timeout. |
+ // |
+ // When |expect_login_tab| is false, no login tab is expected to be opened, |
+ // because one already exists, and the function returns once the captive |
+ // portal test is complete. |
+ // |
+ // If |expect_login_tab| is true, a login tab is then expected to be opened. |
+ // It waits until both the login tab has finished loading, and two captive |
+ // portal tests complete. The second test is triggered by the load of the |
+ // captive portal tab completing. |
+ // |
+ // This function must not be called when the active tab is currently loading. |
+ void SlowLoadBehindCaptivePortal(Browser* browser, bool expect_login_tab); |
+ |
+ // Just like SlowLoadBehindCaptivePortal, except the navigated tab has |
+ // a connection timeout rather having its time trigger, and the function |
+ // waits until that timeout occurs. |
+ void FastTimeoutBehindCaptivePortal(Browser* browser, |
+ bool expect_open_login_tab); |
+ |
+ // Navigates the login tab without logging in. The login tab must be the |
+ // specified browser's active tab. Expects no other tab to change state. |
+ // |num_loading_tabs| and |num_timed_out_tabs| are used as extra checks |
+ // that nothing has gone wrong prior to the function call. |
+ void NavigateLoginTab(Browser* browser, |
+ int num_loading_tabs, |
+ int num_timed_out_tabs); |
+ |
+ // Simulates a login by updating the URLRequestMockCaptivePortalJob's |
+ // behind captive portal state, and navigating the login tab. Waits for |
+ // all broken but not loading tabs to be reloaded. |
+ // |num_loading_tabs| and |num_timed_out_tabs| are used as extra checks |
+ // that nothing has gone wrong prior to the function call. |
+ void Login(Browser* browser, int num_loading_tabs, int num_timed_out_tabs); |
+ |
+ // Makes the slow SSL loads of all active tabs time out at once, and waits for |
+ // them to finish both that load and the automatic reload it should trigger. |
+ // There should be no timed out tabs when this is called. The former login |
+ // tab should be the active tab. |
+ void FailLoadsAfterLogin(Browser* browser, int num_loading_tabs); |
+ |
+ // Makes the slow SSL loads of all active tabs time out at once, and waits for |
+ // them to finish displaying their error pages. The login tab should be the |
+ // active tab. There should be no timed out tabs when this is called. |
+ void FailLoadsWithoutLogin(Browser* browser, int num_loading_tabs); |
+ |
+ // Sets the timeout used by a CaptivePortalTabReloader on slow SSL loads |
+ // before a captive portal check. |
+ void SetSlowSSLLoadTime(CaptivePortalTabReloader* tab_reloader, |
+ base::TimeDelta slow_ssl_load_time); |
+ |
+ CaptivePortalTabReloader* GetTabReloader(TabContents* tab_contents) const; |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(CaptivePortalBrowserTest); |
+}; |
+ |
+CaptivePortalBrowserTest::CaptivePortalBrowserTest() { |
+} |
+ |
+void CaptivePortalBrowserTest::SetUpOnMainThread() { |
+ // Enable mock requests. |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::IO, FROM_HERE, |
+ base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled, true)); |
+ URLRequestMockCaptivePortalJobFactory::AddUrlHandlers(); |
+ |
+ EnableCaptivePortalDetection(browser()->profile(), true); |
+ |
+ // Set the captive portal service to use URLRequestMockCaptivePortalJob's |
+ // mock URL, by default. |
+ SetUpCaptivePortalService(browser()->profile(), |
+ GURL(kMockCaptivePortalTestUrl)); |
+} |
+ |
+void CaptivePortalBrowserTest::CleanUpOnMainThread() { |
+ // No test should have a captive portal check pending on quit. |
+ EXPECT_FALSE(CheckPending(browser())); |
+} |
+ |
+void CaptivePortalBrowserTest::SetUpCommandLine( |
+ CommandLine* command_line) { |
+ command_line->AppendSwitch(switches::kCaptivePortalDetection); |
+} |
+ |
+void CaptivePortalBrowserTest::EnableCaptivePortalDetection( |
+ Profile* profile, bool enabled) { |
+ profile->GetPrefs()->SetBoolean(prefs::kAlternateErrorPagesEnabled, enabled); |
+} |
+ |
+void CaptivePortalBrowserTest::SetUpCaptivePortalService(Profile* profile, |
+ const GURL& test_url) { |
+ CaptivePortalService* captive_portal_service = |
+ CaptivePortalServiceFactory::GetForProfile(profile); |
+ captive_portal_service->set_test_url(test_url); |
+ |
+ // Don't use any non-zero timers. Timers are checked in unit tests. |
+ CaptivePortalService::RecheckPolicy* recheck_policy = |
+ &captive_portal_service->recheck_policy(); |
+ recheck_policy->initial_backoff_no_portal_ms = 0; |
+ recheck_policy->initial_backoff_portal_ms = 0; |
+ recheck_policy->backoff_policy.maximum_backoff_ms = 0; |
+} |
+ |
+bool CaptivePortalBrowserTest::CheckPending(Browser* browser) { |
+ CaptivePortalService* captive_portal_service = |
+ CaptivePortalServiceFactory::GetForProfile(browser->profile()); |
+ |
+ return captive_portal_service->FetchingURL() || |
+ captive_portal_service->TimerRunning(); |
+} |
+ |
+CaptivePortalTabReloader::State CaptivePortalBrowserTest::GetStateOfTabReloader( |
+ TabContents* tab_contents) const { |
+ return GetTabReloader(tab_contents)->state(); |
+} |
+ |
+CaptivePortalTabReloader::State |
+CaptivePortalBrowserTest::GetStateOfTabReloaderAt(Browser* browser, |
+ int index) const { |
+ return GetStateOfTabReloader(browser->GetTabContentsAt(index)); |
+} |
+ |
+int CaptivePortalBrowserTest::NumTabsWithState( |
+ CaptivePortalTabReloader::State state) const { |
+ int num_tabs = 0; |
+ for (TabContentsIterator tab_contents_it; |
+ !tab_contents_it.done(); |
+ ++tab_contents_it) { |
+ if (GetStateOfTabReloader(*tab_contents_it) == state) |
+ ++num_tabs; |
+ } |
+ return num_tabs; |
+} |
+ |
+int CaptivePortalBrowserTest::NumBrokenTabs() const { |
+ return NumTabsWithState(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL); |
+} |
+ |
+int CaptivePortalBrowserTest::NumNeedReloadTabs() const { |
+ return NumTabsWithState(CaptivePortalTabReloader::STATE_NEEDS_RELOAD); |
+} |
+ |
+void CaptivePortalBrowserTest::NavigateToPageExpectNoTest( |
+ Browser* browser, |
+ const GURL& url, |
+ int expected_navigations) { |
+ MultiNavigationObserver navigation_observer; |
+ CaptivePortalObserver portal_observer(browser->profile()); |
+ |
+ ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( |
+ browser, url, expected_navigations); |
+ |
+ // No captive portal checks should have ocurred or be pending, and there |
+ // should be no new tabs. |
+ EXPECT_EQ(0, portal_observer.num_results_received()); |
+ EXPECT_FALSE(CheckPending(browser)); |
+ EXPECT_EQ(1, browser->tab_count()); |
+ EXPECT_EQ(expected_navigations, navigation_observer.num_navigations()); |
+ EXPECT_EQ(0, NumLoadingTabs()); |
+} |
+ |
+void CaptivePortalBrowserTest::SlowLoadNoCaptivePortal( |
+ Browser* browser, Result expected_result) { |
+ CaptivePortalTabReloader* tab_reloader = |
+ GetTabReloader(browser->GetActiveTabContents()); |
+ ASSERT_TRUE(tab_reloader); |
+ SetSlowSSLLoadTime(tab_reloader, base::TimeDelta()); |
+ |
+ MultiNavigationObserver navigation_observer; |
+ CaptivePortalObserver portal_observer(browser->profile()); |
+ ui_test_utils::NavigateToURLWithDisposition(browser, |
+ GURL(kMockHttpsUrl), |
+ CURRENT_TAB, |
+ ui_test_utils::BROWSER_TEST_NONE); |
+ |
+ portal_observer.WaitForResults(1); |
+ |
+ ASSERT_EQ(1, browser->tab_count()); |
+ EXPECT_EQ(expected_result, portal_observer.captive_portal_result()); |
+ EXPECT_EQ(1, portal_observer.num_results_received()); |
+ EXPECT_EQ(0, navigation_observer.num_navigations()); |
+ EXPECT_FALSE(CheckPending(browser)); |
+ |
+ // First tab should still be loading. |
+ EXPECT_EQ(1, NumLoadingTabs()); |
+ |
+ // Original request times out. |
+ URLRequestTimeoutOnDemandJob::FailRequests(); |
+ navigation_observer.WaitForNavigations(1); |
+ |
+ ASSERT_EQ(1, browser->tab_count()); |
+ EXPECT_EQ(1, portal_observer.num_results_received()); |
+ EXPECT_FALSE(CheckPending(browser)); |
+ EXPECT_EQ(0, NumLoadingTabs()); |
+ |
+ // Set a slow SSL load time to prevent the timer from triggering. |
+ SetSlowSSLLoadTime(tab_reloader, base::TimeDelta::FromDays(1)); |
+} |
+ |
+void CaptivePortalBrowserTest::FastTimeoutNoCaptivePortal( |
+ Browser* browser, Result expected_result) { |
+ ASSERT_NE(expected_result, RESULT_BEHIND_CAPTIVE_PORTAL); |
+ |
+ // Set the load time to be large, so the timer won't trigger. The value is |
+ // not restored at the end of the function. |
+ CaptivePortalTabReloader* tab_reloader = |
+ GetTabReloader(browser->GetActiveTabContents()); |
+ ASSERT_TRUE(tab_reloader); |
+ SetSlowSSLLoadTime(tab_reloader, base::TimeDelta::FromHours(1)); |
+ |
+ MultiNavigationObserver navigation_observer; |
+ CaptivePortalObserver portal_observer(browser->profile()); |
+ |
+ // Neither of these should be changed by the navigation. |
+ int active_index = browser->active_index(); |
+ int expected_tab_count = browser->tab_count(); |
+ |
+ ui_test_utils::NavigateToURL( |
+ browser, |
+ URLRequestFailedJob::GetMockHttpsUrl(net::ERR_CONNECTION_TIMED_OUT)); |
+ |
+ // An attempt to detect a captive portal should have started by now. If not, |
+ // abort early to prevent hanging. |
+ ASSERT_TRUE(portal_observer.num_results_received() > 0 || |
+ CheckPending(browser)); |
+ |
+ portal_observer.WaitForResults(1); |
+ navigation_observer.WaitForNavigations(1); |
+ |
+ // Check the result. |
+ EXPECT_EQ(1, portal_observer.num_results_received()); |
+ EXPECT_EQ(expected_result, portal_observer.captive_portal_result()); |
+ |
+ // Check that the right tab was navigated, and there were no extra |
+ // navigations. |
+ EXPECT_EQ(1, navigation_observer.NumNavigationsForTab( |
+ browser->GetWebContentsAt(active_index))); |
+ EXPECT_EQ(0, NumLoadingTabs()); |
+ |
+ // Check the tab's state, and verify no captive portal check is pending. |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, |
+ GetStateOfTabReloaderAt(browser, 0)); |
+ EXPECT_FALSE(CheckPending(browser)); |
+ |
+ // Make sure no login tab was opened. |
+ EXPECT_EQ(expected_tab_count, browser->tab_count()); |
+} |
+ |
+void CaptivePortalBrowserTest::SlowLoadBehindCaptivePortal( |
+ Browser* browser, |
+ bool expect_open_login_tab) { |
+ // Calling this on a tab that's waiting for a load to manually be timed out |
+ // will result in a hang. |
+ ASSERT_FALSE(browser->GetActiveWebContents()->IsLoading()); |
+ |
+ // Trigger a captive portal check quickly. |
+ CaptivePortalTabReloader* tab_reloader = |
+ GetTabReloader(browser->GetActiveTabContents()); |
+ ASSERT_TRUE(tab_reloader); |
+ SetSlowSSLLoadTime(tab_reloader, base::TimeDelta()); |
+ |
+ // Number of tabs expected to be open after the captive portal checks |
+ // have completed. |
+ int initial_tab_count = browser->tab_count(); |
+ int initial_active_index = browser->active_index(); |
+ int initial_loading_tabs = NumLoadingTabs(); |
+ int expected_broken_tabs = NumBrokenTabs(); |
+ if (CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL != |
+ GetStateOfTabReloader(browser->GetActiveTabContents())) { |
+ ++expected_broken_tabs; |
+ } |
+ |
+ MultiNavigationObserver navigation_observer; |
+ CaptivePortalObserver portal_observer(browser->profile()); |
+ ui_test_utils::NavigateToURLWithDisposition(browser, |
+ GURL(kMockHttpsUrl), |
+ CURRENT_TAB, |
+ ui_test_utils::BROWSER_TEST_NONE); |
+ |
+ if (expect_open_login_tab) { |
+ portal_observer.WaitForResults(2); |
+ navigation_observer.WaitForNavigations(1); |
+ EXPECT_EQ(2, portal_observer.num_results_received()); |
+ |
+ ASSERT_EQ(initial_tab_count + 1, browser->tab_count()); |
+ EXPECT_EQ(initial_tab_count, browser->active_index()); |
+ |
+ EXPECT_EQ(1, navigation_observer.NumNavigationsForTab( |
+ browser->GetWebContentsAt(initial_tab_count))); |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, |
+ GetStateOfTabReloader(browser->GetTabContentsAt(1))); |
+ EXPECT_TRUE(IsLoginTab(browser->GetTabContentsAt(1))); |
+ } else { |
+ portal_observer.WaitForResults(1); |
+ EXPECT_EQ(0, navigation_observer.num_navigations()); |
+ EXPECT_EQ(initial_active_index, browser->active_index()); |
+ ASSERT_EQ(initial_tab_count, browser->tab_count()); |
+ EXPECT_EQ(initial_active_index, browser->active_index()); |
+ } |
+ |
+ EXPECT_EQ(initial_loading_tabs + 1, NumLoadingTabs()); |
+ EXPECT_EQ(expected_broken_tabs, NumBrokenTabs()); |
+ EXPECT_EQ(RESULT_BEHIND_CAPTIVE_PORTAL, |
+ portal_observer.captive_portal_result()); |
+ EXPECT_FALSE(CheckPending(browser)); |
+ |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL, |
+ GetStateOfTabReloader( |
+ browser->GetTabContentsAt(initial_active_index))); |
+ |
+ // Reset the load time to be large, so the timer won't trigger on a reload. |
+ SetSlowSSLLoadTime(tab_reloader, base::TimeDelta::FromHours(1)); |
+} |
+ |
+void CaptivePortalBrowserTest::FastTimeoutBehindCaptivePortal( |
+ Browser* browser, |
+ bool expect_open_login_tab) { |
+ // Calling this on a tab that's waiting for a load to manually be timed out |
+ // will result in a hang. |
+ ASSERT_FALSE(browser->GetActiveWebContents()->IsLoading()); |
+ |
+ // Set the load time to be large, so the timer won't trigger. The value is |
+ // not restored at the end of the function. |
+ CaptivePortalTabReloader* tab_reloader = |
+ GetTabReloader(browser->GetActiveTabContents()); |
+ ASSERT_TRUE(tab_reloader); |
+ SetSlowSSLLoadTime(tab_reloader, base::TimeDelta::FromHours(1)); |
+ |
+ // Number of tabs expected to be open after the captive portal checks |
+ // have completed. |
+ int initial_tab_count = browser->tab_count(); |
+ int initial_active_index = browser->active_index(); |
+ int initial_loading_tabs = NumLoadingTabs(); |
+ int expected_broken_tabs = NumBrokenTabs(); |
+ if (CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL != |
+ GetStateOfTabReloader(browser->GetActiveTabContents())) { |
+ ++expected_broken_tabs; |
+ } |
+ |
+ MultiNavigationObserver navigation_observer; |
+ CaptivePortalObserver portal_observer(browser->profile()); |
+ ui_test_utils::NavigateToURLWithDisposition(browser, |
+ GURL(kMockHttpsQuickTimeoutUrl), |
+ CURRENT_TAB, |
+ ui_test_utils::BROWSER_TEST_NONE); |
+ |
+ if (expect_open_login_tab) { |
+ portal_observer.WaitForResults(2); |
+ navigation_observer.WaitForNavigations(2); |
+ EXPECT_EQ(2, portal_observer.num_results_received()); |
+ |
+ ASSERT_EQ(initial_tab_count + 1, browser->tab_count()); |
+ EXPECT_EQ(initial_tab_count, browser->active_index()); |
+ // Make sure that the originally active tab and the captive portal tab have |
+ // each loaded once. |
+ EXPECT_EQ(1, navigation_observer.NumNavigationsForTab( |
+ browser->GetWebContentsAt(initial_active_index))); |
+ EXPECT_EQ(1, navigation_observer.NumNavigationsForTab( |
+ browser->GetWebContentsAt(initial_tab_count))); |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, |
+ GetStateOfTabReloader(browser->GetTabContentsAt(1))); |
+ EXPECT_TRUE(IsLoginTab(browser->GetTabContentsAt(1))); |
+ } else { |
+ portal_observer.WaitForResults(1); |
+ navigation_observer.WaitForNavigations(1); |
+ EXPECT_EQ(1, portal_observer.num_results_received()); |
+ |
+ EXPECT_EQ(initial_active_index, browser->active_index()); |
+ EXPECT_EQ(1, navigation_observer.NumNavigationsForTab( |
+ browser->GetWebContentsAt(initial_active_index))); |
+ ASSERT_EQ(initial_tab_count, browser->tab_count()); |
+ EXPECT_EQ(initial_active_index, browser->active_index()); |
+ } |
+ |
+ EXPECT_EQ(initial_loading_tabs, NumLoadingTabs()); |
+ EXPECT_EQ(expected_broken_tabs, NumBrokenTabs()); |
+ EXPECT_EQ(RESULT_BEHIND_CAPTIVE_PORTAL, |
+ portal_observer.captive_portal_result()); |
+ EXPECT_FALSE(CheckPending(browser)); |
+ |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL, |
+ GetStateOfTabReloader( |
+ browser->GetTabContentsAt(initial_active_index))); |
+} |
+ |
+void CaptivePortalBrowserTest::NavigateLoginTab(Browser* browser, |
+ int num_loading_tabs, |
+ int num_timed_out_tabs) { |
+ MultiNavigationObserver navigation_observer; |
+ CaptivePortalObserver portal_observer(browser->profile()); |
+ |
+ int initial_tab_count = browser->tab_count(); |
+ EXPECT_EQ(num_loading_tabs, NumLoadingTabs()); |
+ EXPECT_EQ(num_timed_out_tabs, NumBrokenTabs() - NumLoadingTabs()); |
+ |
+ int login_tab_index = browser->active_index(); |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, |
+ GetStateOfTabReloader(browser->GetActiveTabContents())); |
+ ASSERT_TRUE(IsLoginTab(browser->GetActiveTabContents())); |
+ |
+ // Do the navigation. |
+ content::RenderViewHost* render_view_host = |
+ browser->GetActiveWebContents()->GetRenderViewHost(); |
+ render_view_host->ExecuteJavascriptInWebFrame( |
+ string16(), |
+ ASCIIToUTF16("submitForm()")); |
+ |
+ portal_observer.WaitForResults(1); |
+ navigation_observer.WaitForNavigations(1); |
+ |
+ // Check the captive portal result. |
+ EXPECT_EQ(RESULT_BEHIND_CAPTIVE_PORTAL, |
+ portal_observer.captive_portal_result()); |
+ EXPECT_EQ(1, portal_observer.num_results_received()); |
+ EXPECT_FALSE(CheckPending(browser)); |
+ |
+ // Make sure not much has changed. |
+ EXPECT_EQ(initial_tab_count, browser->tab_count()); |
+ EXPECT_EQ(num_loading_tabs, NumLoadingTabs()); |
+ EXPECT_EQ(num_loading_tabs + num_timed_out_tabs, NumBrokenTabs()); |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, |
+ GetStateOfTabReloader(browser->GetTabContentsAt(login_tab_index))); |
+ EXPECT_TRUE(IsLoginTab(browser->GetTabContentsAt(login_tab_index))); |
+ |
+ // Make sure there were no unexpected navigations. |
+ EXPECT_EQ(1, navigation_observer.NumNavigationsForTab( |
+ browser->GetWebContentsAt(login_tab_index))); |
+} |
+ |
+void CaptivePortalBrowserTest::Login(Browser* browser, |
+ int num_loading_tabs, |
+ int num_timed_out_tabs) { |
+ // Simulate logging in. |
+ URLRequestMockCaptivePortalJobFactory::SetBehindCaptivePortal(false); |
+ |
+ MultiNavigationObserver navigation_observer; |
+ CaptivePortalObserver portal_observer(browser->profile()); |
+ |
+ int initial_tab_count = browser->tab_count(); |
+ ASSERT_EQ(num_loading_tabs, NumLoadingTabs()); |
+ EXPECT_EQ(num_timed_out_tabs, NumBrokenTabs() - NumLoadingTabs()); |
+ |
+ // Verify that the login page is on top. |
+ int login_tab_index = browser->active_index(); |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, |
+ GetStateOfTabReloader(browser->GetTabContentsAt(login_tab_index))); |
+ ASSERT_TRUE(IsLoginTab(browser->GetTabContentsAt(login_tab_index))); |
+ |
+ // Trigger a navigation. |
+ content::RenderViewHost* render_view_host = |
+ browser->GetActiveWebContents()->GetRenderViewHost(); |
+ render_view_host->ExecuteJavascriptInWebFrame( |
+ string16(), |
+ ASCIIToUTF16("submitForm()")); |
+ |
+ portal_observer.WaitForResults(1); |
+ |
+ // Wait for all the timed out tabs to reload. |
+ navigation_observer.WaitForNavigations(1 + num_timed_out_tabs); |
+ EXPECT_EQ(1, portal_observer.num_results_received()); |
+ |
+ // The tabs that were loading before should still be loading, and now be in |
+ // STATE_NEEDS_RELOAD. |
+ EXPECT_EQ(0, NumBrokenTabs()); |
+ EXPECT_EQ(num_loading_tabs, NumLoadingTabs()); |
+ EXPECT_EQ(num_loading_tabs, NumNeedReloadTabs()); |
+ |
+ // Make sure that the broken tabs have reloaded, and there's no more |
+ // captive portal tab. |
+ EXPECT_EQ(initial_tab_count, browser->tab_count()); |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, |
+ GetStateOfTabReloaderAt(browser, login_tab_index)); |
+ EXPECT_FALSE(IsLoginTab(browser->GetTabContentsAt(login_tab_index))); |
+ |
+ // Make sure there were no unexpected navigations of the login tab. |
+ EXPECT_EQ(1, navigation_observer.NumNavigationsForTab( |
+ browser->GetWebContentsAt(login_tab_index))); |
+} |
+ |
+void CaptivePortalBrowserTest::FailLoadsAfterLogin(Browser* browser, |
+ int num_loading_tabs) { |
+ ASSERT_EQ(num_loading_tabs, NumLoadingTabs()); |
+ ASSERT_EQ(num_loading_tabs, NumNeedReloadTabs()); |
+ EXPECT_EQ(0, NumBrokenTabs()); |
+ |
+ int initial_num_tabs = browser->tab_count(); |
+ int initial_active_tab = browser->active_index(); |
+ |
+ CaptivePortalObserver portal_observer(browser->profile()); |
+ MultiNavigationObserver navigation_observer; |
+ // Connection finally times out. |
+ URLRequestTimeoutOnDemandJob::FailRequests(); |
+ |
+ navigation_observer.WaitForNavigations(2 * num_loading_tabs); |
+ |
+ // No captive portal checks should have ocurred or be pending, and there |
+ // should be no new tabs. |
+ EXPECT_EQ(0, portal_observer.num_results_received()); |
+ EXPECT_FALSE(CheckPending(browser)); |
+ EXPECT_EQ(initial_num_tabs, browser->tab_count()); |
+ |
+ EXPECT_EQ(initial_active_tab, browser->active_index()); |
+ |
+ EXPECT_EQ(0, NumNeedReloadTabs()); |
+ EXPECT_EQ(0, NumLoadingTabs()); |
+ EXPECT_EQ(0, navigation_observer.NumNavigationsForTab( |
+ browser->GetActiveWebContents())); |
+} |
+ |
+void CaptivePortalBrowserTest::FailLoadsWithoutLogin(Browser* browser, |
+ int num_loading_tabs) { |
+ ASSERT_EQ(num_loading_tabs, NumLoadingTabs()); |
+ ASSERT_EQ(0, NumNeedReloadTabs()); |
+ EXPECT_EQ(num_loading_tabs, NumBrokenTabs()); |
+ |
+ int initial_num_tabs = browser->tab_count(); |
+ int login_tab = browser->active_index(); |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, |
+ GetStateOfTabReloader(browser->GetActiveTabContents())); |
+ ASSERT_TRUE(IsLoginTab(browser->GetActiveTabContents())); |
+ |
+ CaptivePortalObserver portal_observer(browser->profile()); |
+ MultiNavigationObserver navigation_observer; |
+ // Connection finally times out. |
+ URLRequestTimeoutOnDemandJob::FailRequests(); |
+ |
+ navigation_observer.WaitForNavigations(num_loading_tabs); |
+ |
+ // No captive portal checks should have ocurred or be pending, and there |
+ // should be no new tabs. |
+ EXPECT_EQ(0, portal_observer.num_results_received()); |
+ EXPECT_FALSE(CheckPending(browser)); |
+ EXPECT_EQ(initial_num_tabs, browser->tab_count()); |
+ |
+ EXPECT_EQ(0, NumNeedReloadTabs()); |
+ EXPECT_EQ(0, NumLoadingTabs()); |
+ EXPECT_EQ(num_loading_tabs, NumBrokenTabs()); |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, |
+ GetStateOfTabReloader(browser->GetActiveTabContents())); |
+ EXPECT_TRUE(IsLoginTab(browser->GetActiveTabContents())); |
+ EXPECT_EQ(login_tab, browser->active_index()); |
+ |
+ EXPECT_EQ(0, navigation_observer.NumNavigationsForTab( |
+ browser->GetWebContentsAt(login_tab))); |
+} |
+ |
+void CaptivePortalBrowserTest::SetSlowSSLLoadTime( |
+ CaptivePortalTabReloader* tab_reloader, |
+ base::TimeDelta slow_ssl_load_time) { |
+ tab_reloader->set_slow_ssl_load_time(slow_ssl_load_time); |
+} |
+ |
+CaptivePortalTabReloader* CaptivePortalBrowserTest::GetTabReloader( |
+ TabContents* tab_contents) const { |
+ return tab_contents->captive_portal_tab_helper()->GetTabReloaderForTest(); |
+} |
+ |
+// Make sure there's no test for a captive portal on HTTP timeouts. This will |
+// also trigger the link doctor page, which results in the load of a second |
+// error page. |
+IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpTimeout) { |
+ GURL url = URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_TIMED_OUT); |
+ NavigateToPageExpectNoTest(browser(), url, 2); |
+} |
+ |
+// Make sure there's no check for a captive portal on HTTPS errors other than |
+// timeouts, when they preempt the slow load timer. |
+IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpsNonTimeoutError) { |
+ GURL url = URLRequestFailedJob::GetMockHttpsUrl(net::ERR_UNEXPECTED); |
+ NavigateToPageExpectNoTest(browser(), url, 1); |
+} |
+ |
+// Make sure no captive portal test triggers on HTTPS timeouts of iframes. |
+IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpsIframeTimeout) { |
+ CaptivePortalObserver portal_observer(browser()->profile()); |
+ |
+ // Use an HTTPS server for the top level page. |
+ net::TestServer https_server(net::TestServer::TYPE_HTTPS, |
+ net::TestServer::kLocalhost, |
+ FilePath(FILE_PATH_LITERAL("chrome/test/data"))); |
+ ASSERT_TRUE(https_server.Start()); |
+ |
+ GURL url = https_server.GetURL(kTestServerIframeTimeoutPath); |
+ NavigateToPageExpectNoTest(browser(), url, 1); |
+} |
+ |
+// Check the captive portal result when the test request reports a network |
+// error. The check is triggered by a slow loading page, and the page |
+// errors out only after getting a captive portal result. |
+IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, RequestFails) { |
+ SetUpCaptivePortalService( |
+ browser()->profile(), |
+ URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_CLOSED)); |
+ SlowLoadNoCaptivePortal(browser(), RESULT_NO_RESPONSE); |
+} |
+ |
+// Same as above, but for the rather unlikely case that the connection times out |
+// before the timer triggers. |
+IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, RequestFailsFastTimout) { |
+ SetUpCaptivePortalService( |
+ browser()->profile(), |
+ URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_CLOSED)); |
+ FastTimeoutNoCaptivePortal(browser(), RESULT_NO_RESPONSE); |
+} |
+ |
+// Checks the case that captive portal detection is disabled. |
+IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, Disabled) { |
+ EnableCaptivePortalDetection(browser()->profile(), false); |
+ SlowLoadNoCaptivePortal(browser(), RESULT_INTERNET_CONNECTED); |
+} |
+ |
+// Checks that we look for a captive portal on HTTPS timeouts and don't reload |
+// the error tab when the captive portal probe gets a 204 response, indicating |
+// there is no captive portal. |
+IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, InternetConnected) { |
+ // Can't just use SetBehindCaptivePortal(false), since then there wouldn't |
+ // be a timeout. |
+ ASSERT_TRUE(test_server()->Start()); |
+ SetUpCaptivePortalService(browser()->profile(), |
+ test_server()->GetURL("nocontent")); |
+ SlowLoadNoCaptivePortal(browser(), RESULT_INTERNET_CONNECTED); |
+} |
+ |
+// Checks that no login page is opened when the HTTP test URL redirects to an |
+// SSL certificate error. |
+IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, RedirectSSLCertError) { |
+ // Need an HTTP TestServer to handle a dynamically created server redirect. |
+ ASSERT_TRUE(test_server()->Start()); |
+ |
+ net::TestServer::HTTPSOptions https_options; |
+ https_options.server_certificate = |
+ net::TestServer::HTTPSOptions::CERT_MISMATCHED_NAME; |
+ net::TestServer https_server(https_options, |
+ FilePath(FILE_PATH_LITERAL("chrome/test/data"))); |
+ ASSERT_TRUE(https_server.Start()); |
+ |
+ GURL ssl_login_url = https_server.GetURL(kTestServerLoginPath); |
+ |
+ CaptivePortalService* captive_portal_service = |
+ CaptivePortalServiceFactory::GetForProfile(browser()->profile()); |
+ ASSERT_TRUE(captive_portal_service); |
+ SetUpCaptivePortalService( |
+ browser()->profile(), |
+ test_server()->GetURL(CreateServerRedirect(ssl_login_url.spec()))); |
+ |
+ SlowLoadNoCaptivePortal(browser(), RESULT_NO_RESPONSE); |
+} |
+ |
+// A slow SSL load triggers a captive portal check. The user logs on before |
+// the SSL page times out. We wait for the timeout and subsequent reload. |
+IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, Login) { |
+ // Load starts, detect captive portal and open up a login tab. |
+ SlowLoadBehindCaptivePortal(browser(), true); |
+ |
+ // Log in. One loading tab, no timed out ones. |
+ Login(browser(), 1, 0); |
+ |
+ string16 expected_title = ASCIIToUTF16(kInternetConnectedTitle); |
+ ui_test_utils::TitleWatcher title_watcher( |
+ browser()->GetWebContentsAt(0), |
+ expected_title); |
+ |
+ // Timeout occurs, and page is automatically reloaded. |
+ FailLoadsAfterLogin(browser(), 1); |
+ |
+ // Double check the tab's title. |
+ EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); |
+} |
+ |
+// Same as above, except we make sure everything works with an incognito |
+// profile. Main issues it tests for are that the incognito has its own |
+// non-NULL captive portal service, and we open the tab in the correct |
+// window. |
+IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, LoginIncognito) { |
+ // This will watch tabs for both profiles, but only used to make sure no |
+ // navigations occur for the non-incognito profile. |
+ MultiNavigationObserver navigation_observer; |
+ CaptivePortalObserver non_incognito_portal_observer(browser()->profile()); |
+ |
+ Browser* incognito_browser = CreateIncognitoBrowser(); |
+ EnableCaptivePortalDetection(incognito_browser->profile(), true); |
+ SetUpCaptivePortalService(incognito_browser->profile(), |
+ GURL(kMockCaptivePortalTestUrl)); |
+ |
+ SlowLoadBehindCaptivePortal(incognito_browser, true); |
+ |
+ EXPECT_EQ(1, browser()->tab_count()); |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, |
+ GetStateOfTabReloaderAt(browser(), 0)); |
+ |
+ Login(incognito_browser, 1, 0); |
+ FailLoadsAfterLogin(incognito_browser, 1); |
+ |
+ EXPECT_EQ(1, browser()->tab_count()); |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, |
+ GetStateOfTabReloaderAt(browser(), 0)); |
+ |
+ EXPECT_EQ(0, navigation_observer.NumNavigationsForTab( |
+ browser()->GetWebContentsAt(0))); |
+ EXPECT_EQ(0, non_incognito_portal_observer.num_results_received()); |
+} |
+ |
+// The captive portal page is opened before the SSL page times out, |
+// but the user logs in only after the page times out. |
+IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, LoginSlow) { |
+ SlowLoadBehindCaptivePortal(browser(), true); |
+ FailLoadsWithoutLogin(browser(), 1); |
+ Login(browser(), 0, 1); |
+} |
+ |
+// Checks the unlikely case that the tab times out before the timer triggers. |
+// This most likely won't happen, but should still work: |
+IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, LoginFastTimeout) { |
+ FastTimeoutBehindCaptivePortal(browser(), true); |
+ Login(browser(), 0, 1); |
+} |
+ |
+// Tries navigating both the tab that encounters an SSL timeout and the |
+// login tab twice, only logging in the second time. |
+IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, LoginExtraNavigations) { |
+ FastTimeoutBehindCaptivePortal(browser(), true); |
+ |
+ // Activate the timed out tab and navigate it to a timeout again. |
+ browser()->ActivateTabAt(0, true); |
+ FastTimeoutBehindCaptivePortal(browser(), false); |
+ |
+ // Activate and navigate the captive portal tab. This should not trigger a |
+ // reload of the tab with the error. |
+ browser()->ActivateTabAt(1, true); |
+ NavigateLoginTab(browser(), 0, 1); |
+ |
+ // Simulate logging in. |
+ Login(browser(), 0, 1); |
+} |
+ |
+// After the first SSL timeout, closes the login tab and makes sure it's opened |
+// it again on a second timeout. |
+IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, CloseLoginTab) { |
+ // First load starts, opens a login tab, and then times out. |
+ SlowLoadBehindCaptivePortal(browser(), true); |
+ FailLoadsWithoutLogin(browser(), 1); |
+ |
+ // Close login tab. |
+ browser()->CloseTab(); |
+ |
+ // Go through the standard slow load login, and make sure it still works. |
+ SlowLoadBehindCaptivePortal(browser(), true); |
+ Login(browser(), 1, 0); |
+ FailLoadsAfterLogin(browser(), 1); |
+} |
+ |
+// Checks that two tabs with SSL timeouts in the same window work. Both |
+// tabs only timeout after logging in. |
+IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, TwoBrokenTabs) { |
+ SlowLoadBehindCaptivePortal(browser(), true); |
+ |
+ // Can't set the TabReloader HTTPS timeout on a new tab without doing some |
+ // acrobatics, so open a new tab at a normal page, and then navigate it to a |
+ // timeout. |
+ MultiNavigationObserver navigation_observer; |
+ CaptivePortalObserver portal_observer(browser()->profile()); |
+ ui_test_utils::NavigateToURLWithDisposition( |
+ browser(), |
+ URLRequestMockHTTPJob::GetMockUrl( |
+ FilePath(FILE_PATH_LITERAL("title2.html"))), |
+ NEW_FOREGROUND_TAB, |
+ ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); |
+ |
+ ASSERT_EQ(3, browser()->tab_count()); |
+ EXPECT_FALSE(CheckPending(browser())); |
+ EXPECT_EQ(0, portal_observer.num_results_received()); |
+ EXPECT_EQ(1, NumLoadingTabs()); |
+ EXPECT_EQ(1, navigation_observer.num_navigations()); |
+ EXPECT_EQ(1, navigation_observer.NumNavigationsForTab( |
+ browser()->GetWebContentsAt(2))); |
+ ASSERT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL, |
+ GetStateOfTabReloaderAt(browser(), 0)); |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, |
+ GetStateOfTabReloader(browser()->GetTabContentsAt(1))); |
+ ASSERT_TRUE(IsLoginTab(browser()->GetTabContentsAt(1))); |
+ ASSERT_EQ(CaptivePortalTabReloader::STATE_NONE, |
+ GetStateOfTabReloaderAt(browser(), 2)); |
+ ASSERT_EQ(2, browser()->active_index()); |
+ |
+ SlowLoadBehindCaptivePortal(browser(), false); |
+ |
+ browser()->ActivateTabAt(1, true); |
+ Login(browser(), 2, 0); |
+ FailLoadsAfterLogin(browser(), 2); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, AbortLoad) { |
+ // Go to the error page. |
+ SlowLoadBehindCaptivePortal(browser(), true); |
+ // The load will be destroyed without returning any result, so remove it from |
+ // the list of jobs that will timeout. |
+ URLRequestTimeoutOnDemandJob::AbandonRequests(); |
+ |
+ CaptivePortalObserver portal_observer(browser()->profile()); |
+ MultiNavigationObserver navigation_observer; |
+ |
+ // Switch back to the hung tab from the login tab, and abort the navigation. |
+ browser()->ActivateTabAt(0, true); |
+ browser()->Stop(); |
+ navigation_observer.WaitForNavigations(1); |
+ |
+ EXPECT_EQ(0, NumBrokenTabs()); |
+ EXPECT_EQ(0, portal_observer.num_results_received()); |
+ EXPECT_FALSE(CheckPending(browser())); |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, |
+ GetStateOfTabReloaderAt(browser(), 0)); |
+ |
+ browser()->ActivateTabAt(1, true); |
+ Login(browser(), 0, 0); |
+} |
+ |
+// Checks the case where the timed out tab is successfully navigated before |
+// logging in. |
+IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, NavigateBrokenTab) { |
+ // Go to the error page. |
+ SlowLoadBehindCaptivePortal(browser(), true); |
+ FailLoadsWithoutLogin(browser(), 1); |
+ |
+ // Navigate the error tab to a non-error page. |
+ browser()->ActivateTabAt(0, true); |
+ ui_test_utils::NavigateToURL(browser(), |
+ URLRequestMockHTTPJob::GetMockUrl( |
+ FilePath(FILE_PATH_LITERAL("title2.html")))); |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, |
+ GetStateOfTabReloaderAt(browser(), 0)); |
+ |
+ // Simulate logging in. |
+ browser()->ActivateTabAt(1, true); |
+ Login(browser(), 0, 0); |
+} |
+ |
+// Navigates a broken, but still loading, tab to another timeout before logging |
+// in. |
+IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, |
+ NavigateBrokenToTimeoutTabWhileLoading) { |
+ // Go to the error page. |
+ SlowLoadBehindCaptivePortal(browser(), true); |
+ URLRequestTimeoutOnDemandJob::AbandonRequests(); |
+ |
+ CaptivePortalTabReloader* tab_reloader = |
+ GetTabReloader(browser()->GetTabContentsAt(0)); |
+ ASSERT_TRUE(tab_reloader); |
+ SetSlowSSLLoadTime(tab_reloader, base::TimeDelta()); |
+ |
+ CaptivePortalObserver portal_observer(browser()->profile()); |
+ MultiNavigationObserver navigation_observer; |
+ |
+ // Navigate the error tab to a non-error page. Can't have ui_test_utils |
+ // do the navigation because it will wait for loading tabs to stop loading |
+ // before navigating. |
+ browser()->ActivateTabAt(0, true); |
+ browser()->OpenURL(content::OpenURLParams(GURL(kMockHttpsUrl), |
+ content::Referrer(), |
+ CURRENT_TAB, |
+ content::PAGE_TRANSITION_TYPED, |
+ false)); |
+ navigation_observer.WaitForNavigations(1); |
+ portal_observer.WaitForResults(1); |
+ EXPECT_FALSE(CheckPending(browser())); |
+ EXPECT_EQ(1, NumLoadingTabs()); |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL, |
+ GetStateOfTabReloaderAt(browser(), 0)); |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, |
+ GetStateOfTabReloader(browser()->GetTabContentsAt(1))); |
+ ASSERT_TRUE(IsLoginTab(browser()->GetTabContentsAt(1))); |
+ |
+ // Simulate logging in. |
+ browser()->ActivateTabAt(1, true); |
+ SetSlowSSLLoadTime(tab_reloader, base::TimeDelta::FromDays(1)); |
+ Login(browser(), 1, 0); |
+ |
+ // Timeout occurs, and page is automatically reloaded. |
+ FailLoadsAfterLogin(browser(), 1); |
+} |
+ |
+// Checks that navigating a timed out tab back clears its state. |
+IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, GoBack) { |
+ // Navigate to a working page. |
+ ui_test_utils::NavigateToURL( |
+ browser(), |
+ URLRequestMockHTTPJob::GetMockUrl( |
+ FilePath(FILE_PATH_LITERAL("title2.html")))); |
+ |
+ // Go to the error page. |
+ SlowLoadBehindCaptivePortal(browser(), true); |
+ FailLoadsWithoutLogin(browser(), 1); |
+ |
+ CaptivePortalObserver portal_observer(browser()->profile()); |
+ MultiNavigationObserver navigation_observer; |
+ |
+ // Activate the error page tab again and go back. |
+ browser()->ActivateTabAt(0, true); |
+ browser()->GoBack(CURRENT_TAB); |
+ navigation_observer.WaitForNavigations(1); |
+ |
+ EXPECT_EQ(1, navigation_observer.NumNavigationsForTab( |
+ browser()->GetWebContentsAt(0))); |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, |
+ GetStateOfTabReloaderAt(browser(), 0)); |
+ EXPECT_EQ(0, portal_observer.num_results_received()); |
+} |
+ |
+// Checks that navigating back to a timeout triggers captive portal detection. |
+IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, GoBackToTimeout) { |
+ // Disable captive portal detection so the first navigation doesn't open a |
+ // login tab. |
+ EnableCaptivePortalDetection(browser()->profile(), false); |
+ |
+ SlowLoadNoCaptivePortal(browser(), RESULT_INTERNET_CONNECTED); |
+ |
+ // Navigate to a working page. |
+ ui_test_utils::NavigateToURL(browser(), |
+ URLRequestMockHTTPJob::GetMockUrl( |
+ FilePath(FILE_PATH_LITERAL("title2.html")))); |
+ ASSERT_EQ(CaptivePortalTabReloader::STATE_NONE, |
+ GetStateOfTabReloaderAt(browser(), 0)); |
+ |
+ EnableCaptivePortalDetection(browser()->profile(), true); |
+ |
+ CaptivePortalTabReloader* tab_reloader = |
+ GetTabReloader(browser()->GetActiveTabContents()); |
+ ASSERT_TRUE(tab_reloader); |
+ SetSlowSSLLoadTime(tab_reloader, base::TimeDelta()); |
+ |
+ // Go to the error page. |
+ MultiNavigationObserver navigation_observer; |
+ CaptivePortalObserver portal_observer(browser()->profile()); |
+ browser()->GoBack(CURRENT_TAB); |
+ |
+ // Wait for both the check triggered by the broken tab and the first load |
+ // of the login tab, and for the login tab to stop loading. |
+ portal_observer.WaitForResults(2); |
+ navigation_observer.WaitForNavigations(1); |
+ |
+ EXPECT_EQ(2, portal_observer.num_results_received()); |
+ ASSERT_FALSE(CheckPending(browser())); |
+ ASSERT_EQ(RESULT_BEHIND_CAPTIVE_PORTAL, |
+ portal_observer.captive_portal_result()); |
+ |
+ ASSERT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL, |
+ GetStateOfTabReloader(browser()->GetTabContentsAt(0))); |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, |
+ GetStateOfTabReloader(browser()->GetTabContentsAt(1))); |
+ ASSERT_TRUE(IsLoginTab(browser()->GetTabContentsAt(1))); |
+ |
+ ASSERT_EQ(2, browser()->tab_count()); |
+ EXPECT_EQ(1, browser()->active_index()); |
+ EXPECT_EQ(1, navigation_observer.NumNavigationsForTab( |
+ browser()->GetWebContentsAt(1))); |
+ EXPECT_EQ(1, NumLoadingTabs()); |
+ |
+ SetSlowSSLLoadTime(tab_reloader, base::TimeDelta::FromDays(1)); |
+ Login(browser(), 1, 0); |
+ FailLoadsAfterLogin(browser(), 1); |
+} |
+ |
+// Checks that reloading a timeout triggers captive portal detection. |
+// Much like the last test, though the captive portal is disabled before |
+// the inital navigation, rather than captive portal detection. |
+IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, ReloadTimeout) { |
+ URLRequestMockCaptivePortalJobFactory::SetBehindCaptivePortal(false); |
+ |
+ // Do the first navigation while not behind a captive portal. |
+ CaptivePortalObserver portal_observer(browser()->profile()); |
+ ui_test_utils::NavigateToURL(browser(), GURL(kMockHttpsUrl)); |
+ ASSERT_EQ(0, portal_observer.num_results_received()); |
+ ASSERT_EQ(1, browser()->tab_count()); |
+ |
+ // A captive portal spontaneously appears. |
+ URLRequestMockCaptivePortalJobFactory::SetBehindCaptivePortal(true); |
+ |
+ CaptivePortalTabReloader* tab_reloader = |
+ GetTabReloader(browser()->GetActiveTabContents()); |
+ ASSERT_TRUE(tab_reloader); |
+ SetSlowSSLLoadTime(tab_reloader, base::TimeDelta()); |
+ |
+ MultiNavigationObserver navigation_observer; |
+ browser()->GetActiveWebContents()->GetController().Reload(true); |
+ |
+ // Wait for the login tab to open, and the two captive portal results from |
+ // opening an it. |
+ portal_observer.WaitForResults(2); |
+ navigation_observer.WaitForNavigations(1); |
+ |
+ ASSERT_EQ(2, portal_observer.num_results_received()); |
+ ASSERT_FALSE(CheckPending(browser())); |
+ ASSERT_EQ(RESULT_BEHIND_CAPTIVE_PORTAL, |
+ portal_observer.captive_portal_result()); |
+ |
+ ASSERT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL, |
+ GetStateOfTabReloader(browser()->GetTabContentsAt(0))); |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, |
+ GetStateOfTabReloader(browser()->GetTabContentsAt(1))); |
+ ASSERT_TRUE(IsLoginTab(browser()->GetTabContentsAt(1))); |
+ |
+ ASSERT_EQ(2, browser()->tab_count()); |
+ EXPECT_EQ(1, browser()->active_index()); |
+ EXPECT_EQ(1, navigation_observer.NumNavigationsForTab( |
+ browser()->GetWebContentsAt(1))); |
+ EXPECT_EQ(1, NumLoadingTabs()); |
+ |
+ SetSlowSSLLoadTime(tab_reloader, base::TimeDelta::FromDays(1)); |
+ Login(browser(), 1, 0); |
+ FailLoadsAfterLogin(browser(), 1); |
+} |
+ |
+// Checks the case where there are two windows, and there's an SSL timeout in |
+// the background one. |
+IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, TwoWindows) { |
+ Browser* browser2 = Browser::Create(browser()->profile()); |
+ // Navigate the new browser window so it'll be shown and we can pick the |
+ // active window. |
+ ui_test_utils::NavigateToURL(browser2, GURL(chrome::kAboutBlankURL)); |
+ |
+ // Generally, |browser2| will be the active window. However, if the |
+ // original browser window lost focus before creating the new one, such as |
+ // when running multiple tests at once, the original browser window may |
+ // remain the profile's active window. |
+ Browser* active_browser = |
+ browser::FindTabbedBrowser(browser()->profile(), true); |
+ Browser* inactive_browser; |
+ if (active_browser == browser2) { |
+ // When only one test is running at a time, the new browser will probably be |
+ // on top, but when multiple tests are running at once, this is not |
+ // guaranteed. |
+ inactive_browser = browser(); |
+ } else { |
+ ASSERT_EQ(active_browser, browser()); |
+ inactive_browser = browser2; |
+ } |
+ |
+ CaptivePortalObserver portal_observer(browser()->profile()); |
+ MultiNavigationObserver navigation_observer; |
+ |
+ // Navigate the tab in the inactive browser to an SSL timeout. Have to use |
+ // browser::NavigateParams and NEW_BACKGROUND_TAB to avoid activating the |
+ // window. |
+ browser::NavigateParams params(inactive_browser, |
+ GURL(kMockHttpsQuickTimeoutUrl), |
+ content::PAGE_TRANSITION_TYPED); |
+ params.disposition = NEW_BACKGROUND_TAB; |
+ params.window_action = browser::NavigateParams::NO_ACTION; |
+ ui_test_utils::NavigateToURL(¶ms); |
+ navigation_observer.WaitForNavigations(2); |
+ |
+ // Make sure the active window hasn't changed, and its new tab is |
+ // active. |
+ ASSERT_EQ(active_browser, |
+ browser::FindTabbedBrowser(browser()->profile(), true)); |
+ ASSERT_EQ(1, active_browser->active_index()); |
+ |
+ // Check that the only two navigated tabs were the new error tab in the |
+ // backround windows, and the login tab in the active window. |
+ EXPECT_EQ(1, navigation_observer.NumNavigationsForTab( |
+ inactive_browser->GetWebContentsAt(1))); |
+ EXPECT_EQ(1, navigation_observer.NumNavigationsForTab( |
+ active_browser->GetWebContentsAt(1))); |
+ EXPECT_EQ(0, NumLoadingTabs()); |
+ |
+ // Check captive portal test results. |
+ portal_observer.WaitForResults(2); |
+ ASSERT_EQ(RESULT_BEHIND_CAPTIVE_PORTAL, |
+ portal_observer.captive_portal_result()); |
+ EXPECT_EQ(2, portal_observer.num_results_received()); |
+ |
+ // Check the inactive browser. |
+ EXPECT_EQ(2, inactive_browser->tab_count()); |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, |
+ GetStateOfTabReloaderAt(inactive_browser, 0)); |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL, |
+ GetStateOfTabReloaderAt(inactive_browser, 1)); |
+ |
+ // Check the active browser. |
+ ASSERT_EQ(2, active_browser->tab_count()); |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, |
+ GetStateOfTabReloaderAt(active_browser, 0)); |
+ EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE, |
+ GetStateOfTabReloaderAt(active_browser, 1)); |
+ EXPECT_TRUE(IsLoginTab(active_browser->GetTabContentsAt(1))); |
+ |
+ // Simulate logging in. |
+ Login(active_browser, 0, 1); |
+} |
+ |
+} // namespace captive_portal |
Property changes on: chrome\browser\captive_portal\captive_portal_browsertest.cc |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |