chromium/chrome/browser/captive_portal/captive_portal_browsertest.cc

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <atomic>
#include <iterator>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <tuple>
#include <utility>
#include <vector>

#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/path_service.h"
#include "base/ranges/algorithm.h"
#include "base/run_loop.h"
#include "base/sequence_checker.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/captive_portal/captive_portal_service_factory.h"
#include "chrome/browser/interstitials/security_interstitial_page_test_utils.h"
#include "chrome/browser/net/secure_dns_config.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_navigator_params.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
#include "chrome/common/chrome_paths.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 "components/captive_portal/content/captive_portal_service.h"
#include "components/captive_portal/content/captive_portal_tab_helper.h"
#include "components/captive_portal/content/captive_portal_tab_reloader.h"
#include "components/captive_portal/core/captive_portal_types.h"
#include "components/embedder_support/pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/security_interstitials/content/captive_portal_blocking_page.h"
#include "components/security_interstitials/content/security_interstitial_page.h"
#include "components/security_interstitials/content/security_interstitial_tab_helper.h"
#include "components/security_interstitials/content/ssl_blocking_page.h"
#include "components/security_interstitials/content/ssl_error_handler.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/prerender_test_util.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/url_loader_interceptor.h"
#include "net/base/net_errors.h"
#include "net/cert/x509_certificate.h"
#include "net/dns/mock_host_resolver.h"
#include "net/http/http_util.h"
#include "net/http/transport_security_state.h"
#include "net/test/cert_test_util.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/test_data_directory.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"

#if BUILDFLAG(IS_WIN)
#include "base/win/win_util.h"
#endif

CaptivePortalResult;
BrowserThread;
WebContents;
WebContentsObserver;

namespace {

// Path of the fake login page, when using the TestServer.
const char* const kTestServerLoginPath =;

// Path of a page with an iframe that has a mock SSL timeout, when using the
// TestServer.
const char* const kTestServerIframeTimeoutPath =;

// Path of a page that redirects to kMockHttpsUrl.
const char* const kRedirectToMockHttpsPath =;

// Path of a page that serves a bad SSL certificate.
// The path doesn't matter because all we need is that it's served from a
// server that's configured to serve a bad cert.
const char* const kMockHttpsBadCertPath =;

// The following URLs each have two different behaviors, depending on whether
// URLRequestMockCaptivePortalJobFactory is currently simulating the presence
// of a captive portal or not.  They use different domains so that HSTS can be
// applied to them independently.

// A mock URL for the captive_portal::CaptivePortalService's |test_url|.  When
// behind a captive portal, this URL returns a mock login page.  When connected
// to the Internet, it returns a 204 response.  Uses the name of the login file
// so that reloading it will not request a different URL.
const char* const kMockCaptivePortalTestUrl =;

// Another mock URL for the captive_portal::CaptivePortalService's |test_url|.
// When behind a captive portal, this URL returns a 511 status code and an HTML
// page that redirect to the above URL.  When connected to the Internet, it
// returns a 204 response.
const char* const kMockCaptivePortal511Url =;

// When behind a captive portal, this URL hangs without committing until a call
// to FailJobs.  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 =;

// Same as above, but different domain, so can be used to trigger cross-site
// navigations.
const char* const kMockHttpsUrl2 =;

// Same as kMockHttpsUrl, except the timeout happens instantly.
const char* const kMockHttpsQuickTimeoutUrl =;

// The intercepted URLs used to mock errors.
const char* const kMockHttpConnectionTimeoutErr =;
const char* const kMockHttpsConnectionTimeoutErr =;
const char* const kMockHttpsConnectionUnexpectedErr =;
const char* const kMockHttpConnectionConnectionClosedErr =;
const char* const kMockHttpConnectionSecureDnsErr =;
const char* const kMockHttpsConnectionSecureDnsErr =;

// Expected title of a tab once an HTTPS load completes, when not behind a
// captive portal.
const char* const kInternetConnectedTitle =;

// Expected title of a login page that was created in secure mode.
const char* const kLoginSecureDnsDisabledTitle =;

// Creates a server-side redirect for use with the TestServer.
std::string CreateServerRedirect(const std::string& dest_url) {}

// Returns the total number of tabs across all Browsers, for all Profiles.
int NumTabs() {}

// Returns the total number of loading tabs across all Browsers, for all
// Profiles.
int NumLoadingTabs() {}

bool IsLoginTab(WebContents* web_contents) {}

// Watch for `DidStopLoading` for one WebContents.
struct LoadObserver : public WebContentsObserver {};

// 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 ui_test_utils::AllTabsObserver,
                                public LoadObserver::Observer {};

MultiNavigationObserver::MultiNavigationObserver() {}

MultiNavigationObserver::~MultiNavigationObserver() = default;

std::unique_ptr<base::CheckedObserver>
MultiNavigationObserver::ProcessOneContents(WebContents* web_contents) {}

void MultiNavigationObserver::OnWebContentsDestroyed(
    WebContents* web_contents) {}

void MultiNavigationObserver::OnDidStopLoading(WebContents* web_contents) {}

void MultiNavigationObserver::WaitForNavigations(
    int num_navigations_to_wait_for) {}

int MultiNavigationObserver::NumNavigationsForTab(
    WebContents* web_contents) const {}

// This observer creates a list of loading tabs, and then waits for them all
// to stop loading and have the kInternetConnectedTitle.
//
// This is for the specific purpose of observing tabs time out after logging in
// to a captive portal, which will then cause them to reload.
// MultiNavigationObserver is insufficient for this because there may or may not
// be a DidStopLoading event between the timeout and the reload.
// See bug http://crbug.com/133227
class FailLoadsAfterLoginObserver : public LoadObserver::Observer {};

FailLoadsAfterLoginObserver::FailLoadsAfterLoginObserver()
    :{}

FailLoadsAfterLoginObserver::~FailLoadsAfterLoginObserver() = default;

void FailLoadsAfterLoginObserver::WaitForNavigations() {}

void FailLoadsAfterLoginObserver::OnDidStopLoading(WebContents* contents) {}

// An observer for watching the captive_portal::CaptivePortalService.  It tracks
// the last received result and the total number of received results.
class CaptivePortalObserver {};

CaptivePortalObserver::CaptivePortalObserver(Profile* profile)
    :{}

void CaptivePortalObserver::WaitForResults(int num_results_to_wait_for) {}

void CaptivePortalObserver::Observe(
    const captive_portal::CaptivePortalService::Results& results) {}

// This observer waits for the SSLErrorHandler to start an interstitial timer
// for the given web contents.
class SSLInterstitialTimerObserver {};

SSLInterstitialTimerObserver::SSLInterstitialTimerObserver(
    content::WebContents* web_contents)
    :{}

SSLInterstitialTimerObserver::~SSLInterstitialTimerObserver() {}

void SSLInterstitialTimerObserver::WaitForTimerStarted() {}

void SSLInterstitialTimerObserver::OnTimerStarted(
    content::WebContents* web_contents) {}

// Helper for waiting for a change of the active tab.
// Users can wait for the change via WaitForActiveTabChange method.
// DCHECKs ensure that only one change happens during the lifetime of a
// TabActivationWaiter instance.
class TabActivationWaiter : public TabStripModelObserver {};

}  // namespace

class CaptivePortalBrowserTest : public InProcessBrowserTest {};

CaptivePortalBrowserTest::CaptivePortalBrowserTest()
    :{}

CaptivePortalBrowserTest::~CaptivePortalBrowserTest() = default;

void CaptivePortalBrowserTest::SetUpOnMainThread() {}

bool CaptivePortalBrowserTest::OnIntercept(
    content::URLLoaderInterceptor::RequestParams* params) {}

void CaptivePortalBrowserTest::TearDownOnMainThread() {}

void CaptivePortalBrowserTest::EnableCaptivePortalDetection(
    Profile* profile, bool enabled) {}

void CaptivePortalBrowserTest::RespondToProbeRequests(bool enabled) {}

void CaptivePortalBrowserTest::SetUpCaptivePortalService(Profile* profile,
                                                         const GURL& test_url) {}

bool CaptivePortalBrowserTest::CheckPending(Browser* browser) {}

security_interstitials::SecurityInterstitialPage::TypeID
CaptivePortalBrowserTest::GetInterstitialType(WebContents* contents) const {}

bool CaptivePortalBrowserTest::IsShowingInterstitial(WebContents* contents) {}

captive_portal::CaptivePortalTabReloader::State
CaptivePortalBrowserTest::GetStateOfTabReloader(
    WebContents* web_contents) const {}

captive_portal::CaptivePortalTabReloader::State
CaptivePortalBrowserTest::GetStateOfTabReloaderAt(Browser* browser,
                                                  int index) const {}

int CaptivePortalBrowserTest::NumTabsWithState(
    captive_portal::CaptivePortalTabReloader::State state) const {}

int CaptivePortalBrowserTest::NumBrokenTabs() const {}

int CaptivePortalBrowserTest::NumNeedReloadTabs() const {}

void CaptivePortalBrowserTest::NavigateToPageExpectNoTest(Browser* browser,
                                                          const GURL& url) {}

void CaptivePortalBrowserTest::SlowLoadNoCaptivePortal(
    Browser* browser,
    CaptivePortalResult expected_result) {}

void CaptivePortalBrowserTest::FastTimeoutNoCaptivePortal(
    Browser* browser,
    CaptivePortalResult expected_result) {}

void CaptivePortalBrowserTest::SlowLoadBehindCaptivePortal(
    Browser* browser,
    bool expect_open_login_tab,
    bool expect_new_login_browser,
    Browser** out_login_browser) {}

void CaptivePortalBrowserTest::SlowLoadBehindCaptivePortal(
    Browser* browser,
    bool expect_open_login_tab,
    bool expect_new_login_browser,
    const GURL& hanging_url,
    int expected_portal_checks,
    int expected_login_tab_navigations,
    Browser** out_login_browser) {}

void CaptivePortalBrowserTest::FastTimeoutBehindCaptivePortal(
    Browser* browser,
    bool expect_open_login_tab) {}

void CaptivePortalBrowserTest::FastErrorBehindCaptivePortal(
    Browser* browser,
    bool expect_open_login_tab,
    bool expect_new_login_browser,
    const GURL& error_url,
    Browser** out_login_browser) {}

void CaptivePortalBrowserTest::FastErrorWithInterstitialTimer(
    Browser* browser,
    const GURL& cert_error_url) {}

void CaptivePortalBrowserTest::NavigateLoginTab(Browser* browser,
                                                int num_loading_tabs,
                                                int num_timed_out_tabs) {}

void CaptivePortalBrowserTest::Login(Browser* captive_portal_browser,
                                     int num_loading_tabs,
                                     int num_timed_out_tabs,
                                     int expected_portal_checks) {}

void CaptivePortalBrowserTest::LoginCertError(Browser* browser) {}

void CaptivePortalBrowserTest::FailLoadsAfterLogin(Browser* browser,
                                                   int num_loading_tabs) {}

void CaptivePortalBrowserTest::FailLoadsWithoutLogin(
    Browser* browser,
    int num_loading_tabs,
    Browser* captive_portal_browser) {}

void CaptivePortalBrowserTest::RunNavigateLoadingTabToTimeoutTest(
    Browser* browser,
    const GURL& starting_url,
    const GURL& hanging_url,
    const GURL& timeout_url) {}

void CaptivePortalBrowserTest::SetSlowSSLLoadTime(
    captive_portal::CaptivePortalTabReloader* tab_reloader,
    base::TimeDelta slow_ssl_load_time) {}

captive_portal::CaptivePortalTabReloader*
CaptivePortalBrowserTest::GetTabReloader(WebContents* web_contents) const {}

// Make sure there's no test for a captive portal on HTTP timeouts.
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpTimeout) {}

// 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) {}

// Make sure no captive portal test triggers on HTTPS timeouts of iframes.
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpsIframeTimeout) {}

// 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) {}

// 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) {}

// Checks the case that captive portal detection is disabled.
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, Disabled) {}

// 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) {}

// 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) {}

// 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) {}

// 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) {}

// 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) {}

// 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) {}

// A cert error triggers a captive portal check and results in opening a login
// tab.
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
                       ShowCaptivePortalInterstitialOnCertError) {}

// A cert error triggers a captive portal check and results in opening a login
// tab; that login tab should not itself show a captive portal interstitial.
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
                       CertErrorOnCaptivePortalLoginShowsSSLErrorInterstitial) {}

// Tests this scenario:
// - Portal probe requests are ignored, so that no captive portal result can
//   arrive.
// - A cert error triggers an interstitial timer with a very long timeout.
// - No captive portal results arrive, causing the tab to appear as loading
//   indefinitely (because probe requests are ignored).
// - Stopping the page load shouldn't result in any interstitials.
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
                       InterstitialTimerStopNavigationWhileLoading) {}

// Same as above, but instead of stopping, the loading page is reloaded. The end
// result is the same. (i.e. page load stops, no interstitials shown)
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
                       InterstitialTimerReloadWhileLoading) {}

// Same as |InterstitialTimerReloadWhileLoading_NoSSLError|, but instead of
// reloading, the page is navigated away. The new page should load, and no
// interstitials should be shown.
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
                       InterstitialTimerNavigateAwayWhileLoading) {}

// Same as above, but the hanging load is interrupted by a navigation to the
// same page, this time committing the navigation. This should end up with an
// SSL interstitial when not behind a captive portal. This ensures that a new
// |SSLErrorHandler| is created on a new navigation, even though the tab's
// WebContents doesn't change.
IN_PROC_BROWSER_TEST_F(
    CaptivePortalBrowserTest,
    InterstitialTimerNavigateWhileLoading_EndWithSSLInterstitial) {}

// Same as above, but this time behind a captive portal.
IN_PROC_BROWSER_TEST_F(
    CaptivePortalBrowserTest,
    InterstitialTimerNavigateWhileLoading_EndWithCaptivePortalInterstitial) {}

// A cert error triggers a captive portal check and results in opening a login
// tab.  The user then logs in and the page with the error is reloaded.
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, SSLCertErrorLogin) {}

// 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) {}

// 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) {}

// 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) {}

IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, AbortLoad) {}

// Checks the case where the timed out tab is successfully navigated before
// logging in.
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, NavigateBrokenTab) {}

// Checks that captive portal detection triggers correctly when a same-site
// navigation is cancelled by a navigation to the same site.
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
                       NavigateLoadingTabToTimeoutSingleSite) {}

// Checks that captive portal detection triggers correctly when a same-site
// navigation is cancelled by a navigation to another site.
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
                       NavigateLoadingTabToTimeoutTwoSites) {}

// Checks that captive portal detection triggers correctly when a cross-site
// navigation is cancelled by a navigation to yet another site.
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
                       NavigateLoadingTabToTimeoutThreeSites) {}

// Checks that navigating a timed out tab back clears its state.
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, GoBack) {}

// Checks that navigating back to a timeout triggers captive portal detection.
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, GoBackToTimeout) {}

// 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) {}

// Checks the case where there are two windows, and there's an SSL timeout in
// the background one.
// Disabled:  http://crbug.com/134357
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, DISABLED_TwoWindows) {}

// An HTTP page redirects to an HTTPS page loads slowly before timing out.  A
// captive portal is found, and then the user logs in before the original page
// times out.
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpToHttpsRedirectLogin) {}

// An HTTPS page redirects to an HTTP page.
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpsToHttpRedirect) {}

// Tests the 511 response code, along with an HTML redirect to a login page.
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, Status511) {}

// A slow SSL load starts. The reloader triggers a captive portal check, finds a
// captive portal. The SSL commits with a cert error, triggering another captive
// portal check.
// The second check finds no captive portal. The reloader triggers a reload at
// the same time SSL error handler tries to show an interstitial. Should result
// in an SSL interstitial.
// TODO(crbug.com/40805743): Flaky on all platforms.
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
                       DISABLED_InterstitialTimerCertErrorAfterSlowLoad) {}

// TODO(crbug.com/339524384) Flaky on Windows.
#if BUILDFLAG(IS_WIN)
#define MAYBE_SecureDnsCaptivePortal
#else
#define MAYBE_SecureDnsCaptivePortal
#endif
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, MAYBE_SecureDnsCaptivePortal) {}

// An HTTP load results in a secure DNS error, which triggers a captive portal
// probe that fails. After logging in, the secure DNS error happens again,
// triggering a captive portal probe that now succeeds.
// TODO(crbug.com/339524384) Flaky on Windows.
#if BUILDFLAG(IS_WIN)
#define MAYBE_SecureDnsErrorTriggersCheck
#else
#define MAYBE_SecureDnsErrorTriggersCheck
#endif
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
                       MAYBE_SecureDnsErrorTriggersCheck) {}

// An HTTPS load happens slowly. The reloader triggers a captive portal check,
// which finds a captive portal. The HTTPS load finally completes with a secure
// DNS error, which does not trigger another captive portal check. Only one
// login tab should exist.
// TODO(crbug.com/339524384) Flaky on Windows.
#if BUILDFLAG(IS_WIN)
#define MAYBE_SlowLoadSecureDnsErrorWithCaptivePortal
#else
#define MAYBE_SlowLoadSecureDnsErrorWithCaptivePortal
#endif
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
                       MAYBE_SlowLoadSecureDnsErrorWithCaptivePortal) {}

// An HTTPS load happens slowly. The reloader triggers a captive portal check,
// which finds a captive portal. After logging in, the HTTPS load finally
// completes with a secure DNS error, which triggers another captive portal
// check that should succeed.
// TODO(crbug.com/339524384) Flaky on Windows.
#if BUILDFLAG(IS_WIN)
#define MAYBE_SlowLoadSecureDnsErrorAfterLogin
#else
#define MAYBE_SlowLoadSecureDnsErrorAfterLogin
#endif
IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
                       MAYBE_SlowLoadSecureDnsErrorAfterLogin) {}

class CaptivePortalForPrerenderingTest : public CaptivePortalBrowserTest {};

// Test that CaptivePortalTabHelper doesn't allow navigating on non-primary
// trees via Did[Start|Finish]Navigation.
IN_PROC_BROWSER_TEST_F(CaptivePortalForPrerenderingTest,
                       DontFireOnLoadStartDuringPrerendering) {}

// Test that CaptivePortalTabHelper does not support the redirect navigation on
// non-primary trees.
IN_PROC_BROWSER_TEST_F(CaptivePortalForPrerenderingTest,
                       DontFireOnRedirectDuringPrerendering) {}