Home | History | Annotate | Download | only in net
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <set>
      6 
      7 #include "base/bind.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/path_service.h"
     11 #include "base/prefs/pref_service.h"
     12 #include "base/run_loop.h"
     13 #include "base/threading/thread_restrictions.h"
     14 #include "chrome/browser/browser_process.h"
     15 #include "chrome/browser/io_thread.h"
     16 #include "chrome/browser/net/dns_probe_test_util.h"
     17 #include "chrome/browser/net/net_error_tab_helper.h"
     18 #include "chrome/browser/net/url_request_mock_util.h"
     19 #include "chrome/browser/profiles/profile.h"
     20 #include "chrome/browser/ui/browser.h"
     21 #include "chrome/browser/ui/browser_commands.h"
     22 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     23 #include "chrome/common/chrome_paths.h"
     24 #include "chrome/common/net/net_error_info.h"
     25 #include "chrome/common/pref_names.h"
     26 #include "chrome/test/base/in_process_browser_test.h"
     27 #include "chrome/test/base/ui_test_utils.h"
     28 #include "components/google/core/browser/google_util.h"
     29 #include "content/public/browser/browser_thread.h"
     30 #include "content/public/browser/web_contents.h"
     31 #include "content/public/test/browser_test_utils.h"
     32 #include "content/public/test/test_navigation_observer.h"
     33 #include "net/base/net_errors.h"
     34 #include "net/dns/dns_test_util.h"
     35 #include "net/test/url_request/url_request_failed_job.h"
     36 #include "net/test/url_request/url_request_mock_http_job.h"
     37 #include "net/url_request/url_request_filter.h"
     38 #include "net/url_request/url_request_interceptor.h"
     39 #include "net/url_request/url_request_job.h"
     40 
     41 using base::Bind;
     42 using base::Callback;
     43 using base::Closure;
     44 using base::ConstRef;
     45 using base::FilePath;
     46 using base::MessageLoop;
     47 using base::Unretained;
     48 using chrome_common_net::DnsProbeStatus;
     49 using content::BrowserThread;
     50 using net::URLRequestFailedJob;
     51 using net::URLRequestMockHTTPJob;
     52 using content::WebContents;
     53 using google_util::LinkDoctorBaseURL;
     54 using net::MockDnsClientRule;
     55 using net::NetworkDelegate;
     56 using net::URLRequest;
     57 using net::URLRequestFilter;
     58 using net::URLRequestInterceptor;
     59 using net::URLRequestJob;
     60 using ui_test_utils::NavigateToURL;
     61 using ui_test_utils::NavigateToURLBlockUntilNavigationsComplete;
     62 
     63 namespace chrome_browser_net {
     64 
     65 namespace {
     66 
     67 // Postable function to run a Closure on the UI thread.  Since
     68 // BrowserThread::PostTask returns a bool, it can't directly be posted to
     69 // another thread.
     70 void RunClosureOnUIThread(const base::Closure& closure) {
     71   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, closure);
     72 }
     73 
     74 // Wraps DnsProbeService and delays callbacks until someone calls
     75 // CallDelayedCallbacks.  This allows the DnsProbeBrowserTest to enforce a
     76 // stricter ordering of events.
     77 class DelayingDnsProbeService : public DnsProbeService {
     78  public:
     79   DelayingDnsProbeService() {}
     80 
     81   virtual ~DelayingDnsProbeService() {
     82     EXPECT_TRUE(delayed_probes_.empty());
     83   }
     84 
     85   virtual void ProbeDns(const ProbeCallback& callback) OVERRIDE {
     86     delayed_probes_.push_back(callback);
     87   }
     88 
     89   void StartDelayedProbes() {
     90     CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     91 
     92     std::vector<ProbeCallback> probes;
     93     probes.swap(delayed_probes_);
     94 
     95     for (std::vector<ProbeCallback>::const_iterator i = probes.begin();
     96          i != probes.end(); ++i) {
     97       DnsProbeService::ProbeDns(*i);
     98     }
     99   }
    100 
    101   int delayed_probe_count() const {
    102     CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    103     return delayed_probes_.size();
    104   }
    105 
    106  private:
    107   std::vector<ProbeCallback> delayed_probes_;
    108 };
    109 
    110 FilePath GetMockLinkDoctorFilePath() {
    111   FilePath root_http;
    112   PathService::Get(chrome::DIR_TEST_DATA, &root_http);
    113   return root_http.AppendASCII("mock-link-doctor.json");
    114 }
    115 
    116 // A request that can be delayed until Resume() is called.  Can also run a
    117 // callback if destroyed without being resumed.  Resume can be called either
    118 // before or after a the request is started.
    119 class DelayableRequest {
    120  public:
    121   // Called by a DelayableRequest if it was set to be delayed, and has been
    122   // destroyed without Undelay being called.
    123   typedef base::Callback<void(DelayableRequest* request)> DestructionCallback;
    124 
    125   virtual void Resume() = 0;
    126 
    127  protected:
    128   virtual ~DelayableRequest() {}
    129 };
    130 
    131 class DelayableURLRequestFailedJob : public URLRequestFailedJob,
    132                                      public DelayableRequest {
    133  public:
    134   // |destruction_callback| is only called if a delayed request is destroyed
    135   // without being resumed.
    136   DelayableURLRequestFailedJob(net::URLRequest* request,
    137                                net::NetworkDelegate* network_delegate,
    138                                int net_error,
    139                                bool should_delay,
    140                                const DestructionCallback& destruction_callback)
    141       : URLRequestFailedJob(request, network_delegate, net_error),
    142         should_delay_(should_delay),
    143         start_delayed_(false),
    144         destruction_callback_(destruction_callback) {}
    145 
    146   virtual void Start() OVERRIDE {
    147     if (should_delay_) {
    148       DCHECK(!start_delayed_);
    149       start_delayed_ = true;
    150       return;
    151     }
    152     URLRequestFailedJob::Start();
    153   }
    154 
    155   virtual void Resume() OVERRIDE {
    156     DCHECK(should_delay_);
    157     should_delay_ = false;
    158     if (start_delayed_) {
    159       start_delayed_ = false;
    160       Start();
    161     }
    162   }
    163 
    164  private:
    165   virtual ~DelayableURLRequestFailedJob() {
    166     if (should_delay_)
    167       destruction_callback_.Run(this);
    168   }
    169 
    170   bool should_delay_;
    171   bool start_delayed_;
    172   const DestructionCallback destruction_callback_;
    173 };
    174 
    175 class DelayableURLRequestMockHTTPJob : public URLRequestMockHTTPJob,
    176                                        public DelayableRequest {
    177  public:
    178   DelayableURLRequestMockHTTPJob(
    179       net::URLRequest* request,
    180       net::NetworkDelegate* network_delegate,
    181       const base::FilePath& file_path,
    182       bool should_delay,
    183       const DestructionCallback& destruction_callback)
    184       : URLRequestMockHTTPJob(
    185             request,
    186             network_delegate,
    187             file_path,
    188             BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
    189                 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)),
    190         should_delay_(should_delay),
    191         start_delayed_(false),
    192         destruction_callback_(destruction_callback) {}
    193 
    194   virtual void Start() OVERRIDE {
    195     if (should_delay_) {
    196       DCHECK(!start_delayed_);
    197       start_delayed_ = true;
    198       return;
    199     }
    200     URLRequestMockHTTPJob::Start();
    201   }
    202 
    203   virtual void Resume() OVERRIDE {
    204     DCHECK(should_delay_);
    205     should_delay_ = false;
    206     if (start_delayed_) {
    207       start_delayed_ = false;
    208       Start();
    209     }
    210   }
    211 
    212  private:
    213   virtual ~DelayableURLRequestMockHTTPJob() {
    214     if (should_delay_)
    215       destruction_callback_.Run(this);
    216   }
    217 
    218   bool should_delay_;
    219   bool start_delayed_;
    220   const DestructionCallback destruction_callback_;
    221 };
    222 
    223 // Interceptor for navigation correction requests.  Can cause requests to
    224 // fail with an error, and/or delay a request until a test allows to continue.
    225 // Also can run a callback when a delayed request is cancelled.
    226 class BreakableCorrectionInterceptor : public URLRequestInterceptor {
    227  public:
    228   explicit BreakableCorrectionInterceptor(
    229       const FilePath& mock_corrections_file_path)
    230       : mock_corrections_file_path_(mock_corrections_file_path),
    231         net_error_(net::OK),
    232         delay_requests_(false),
    233         on_request_destroyed_callback_(
    234             base::Bind(&BreakableCorrectionInterceptor::OnRequestDestroyed,
    235                        base::Unretained(this))) {
    236   }
    237 
    238   virtual ~BreakableCorrectionInterceptor() {
    239     // All delayed requests should have been resumed or cancelled by this point.
    240     EXPECT_TRUE(delayed_requests_.empty());
    241   }
    242 
    243   virtual URLRequestJob* MaybeInterceptRequest(
    244       URLRequest* request,
    245       NetworkDelegate* network_delegate) const OVERRIDE {
    246     if (net_error_ != net::OK) {
    247       DelayableURLRequestFailedJob* job =
    248           new DelayableURLRequestFailedJob(
    249               request, network_delegate, net_error_, delay_requests_,
    250               on_request_destroyed_callback_);
    251       if (delay_requests_)
    252         delayed_requests_.insert(job);
    253       return job;
    254     } else {
    255       DelayableURLRequestMockHTTPJob* job =
    256           new DelayableURLRequestMockHTTPJob(
    257               request, network_delegate, mock_corrections_file_path_,
    258               delay_requests_, on_request_destroyed_callback_);
    259       if (delay_requests_)
    260         delayed_requests_.insert(job);
    261       return job;
    262     }
    263   }
    264 
    265   void set_net_error(int net_error) { net_error_ = net_error; }
    266 
    267   void SetDelayRequests(bool delay_requests) {
    268     delay_requests_ = delay_requests;
    269 
    270     // Resume all delayed requests if no longer delaying requests.
    271     if (!delay_requests) {
    272       while (!delayed_requests_.empty()) {
    273         DelayableRequest* request = *delayed_requests_.begin();
    274         delayed_requests_.erase(request);
    275         request->Resume();
    276       }
    277     }
    278   }
    279 
    280   // Runs |callback| once all delayed requests have been destroyed.  Does not
    281   // wait for delayed requests that have been resumed.
    282   void SetRequestDestructionCallback(const base::Closure& callback) {
    283     ASSERT_TRUE(delayed_request_destruction_callback_.is_null());
    284     if (delayed_requests_.empty()) {
    285       callback.Run();
    286       return;
    287     }
    288     delayed_request_destruction_callback_ = callback;
    289   }
    290 
    291   void OnRequestDestroyed(DelayableRequest* request) {
    292     ASSERT_EQ(1u, delayed_requests_.count(request));
    293     delayed_requests_.erase(request);
    294     if (delayed_requests_.empty() &&
    295         !delayed_request_destruction_callback_.is_null()) {
    296       delayed_request_destruction_callback_.Run();
    297       delayed_request_destruction_callback_.Reset();
    298     }
    299   }
    300 
    301  private:
    302   const FilePath mock_corrections_file_path_;
    303   int net_error_;
    304   bool delay_requests_;
    305 
    306   // Called when a request is destroyed.  Memeber variable because
    307   // MaybeCreateJob is "const", so calling base::Bind in that function does
    308   // not work well.
    309   const DelayableRequest::DestructionCallback on_request_destroyed_callback_;
    310 
    311   // Mutable is needed because MaybeCreateJob is const.
    312   mutable std::set<DelayableRequest*> delayed_requests_;
    313 
    314   base::Closure delayed_request_destruction_callback_;
    315 };
    316 
    317 class DnsProbeBrowserTestIOThreadHelper {
    318  public:
    319   DnsProbeBrowserTestIOThreadHelper();
    320 
    321   void SetUpOnIOThread(IOThread* io_thread);
    322   void CleanUpOnIOThreadAndDeleteHelper();
    323 
    324   void SetMockDnsClientRules(MockDnsClientRule::Result system_good_result,
    325                              MockDnsClientRule::Result public_good_result);
    326   void SetCorrectionServiceNetError(int net_error);
    327   void SetCorrectionServiceDelayRequests(bool delay_requests);
    328   void SetRequestDestructionCallback(const base::Closure& callback);
    329   void StartDelayedProbes(int expected_delayed_probe_count);
    330 
    331  private:
    332   IOThread* io_thread_;
    333   DnsProbeService* original_dns_probe_service_;
    334   DelayingDnsProbeService* delaying_dns_probe_service_;
    335   BreakableCorrectionInterceptor* interceptor_;
    336   FilePath mock_corrections_file_path_;
    337 };
    338 
    339 DnsProbeBrowserTestIOThreadHelper::DnsProbeBrowserTestIOThreadHelper()
    340     : io_thread_(NULL),
    341       original_dns_probe_service_(NULL),
    342       delaying_dns_probe_service_(NULL),
    343       interceptor_(NULL),
    344       mock_corrections_file_path_(GetMockLinkDoctorFilePath()) {}
    345 
    346 void DnsProbeBrowserTestIOThreadHelper::SetUpOnIOThread(IOThread* io_thread) {
    347   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    348   CHECK(io_thread);
    349   CHECK(!io_thread_);
    350   CHECK(!original_dns_probe_service_);
    351   CHECK(!delaying_dns_probe_service_);
    352   CHECK(!interceptor_);
    353 
    354   io_thread_ = io_thread;
    355 
    356   delaying_dns_probe_service_ = new DelayingDnsProbeService();
    357 
    358   IOThread::Globals* globals = io_thread_->globals();
    359   original_dns_probe_service_ = globals->dns_probe_service.release();
    360   globals->dns_probe_service.reset(delaying_dns_probe_service_);
    361 
    362   URLRequestFailedJob::AddUrlHandler();
    363 
    364   interceptor_ =
    365       new BreakableCorrectionInterceptor(mock_corrections_file_path_);
    366   URLRequestFilter::GetInstance()->AddUrlInterceptor(
    367       LinkDoctorBaseURL(), scoped_ptr<URLRequestInterceptor>(interceptor_));
    368 }
    369 
    370 void DnsProbeBrowserTestIOThreadHelper::CleanUpOnIOThreadAndDeleteHelper() {
    371   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    372 
    373   URLRequestFilter::GetInstance()->ClearHandlers();
    374 
    375   IOThread::Globals* globals = io_thread_->globals();
    376   scoped_ptr<DnsProbeService> delaying_dns_probe_service(
    377       globals->dns_probe_service.release());
    378   globals->dns_probe_service.reset(original_dns_probe_service_);
    379 
    380   CHECK_EQ(delaying_dns_probe_service_, delaying_dns_probe_service.get());
    381 
    382   delete this;
    383 }
    384 
    385 void DnsProbeBrowserTestIOThreadHelper::SetMockDnsClientRules(
    386     MockDnsClientRule::Result system_result,
    387     MockDnsClientRule::Result public_result) {
    388   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    389 
    390   DnsProbeService* service = io_thread_->globals()->dns_probe_service.get();
    391   service->SetSystemClientForTesting(
    392       CreateMockDnsClientForProbes(system_result));
    393   service->SetPublicClientForTesting(
    394       CreateMockDnsClientForProbes(public_result));
    395 }
    396 
    397 void DnsProbeBrowserTestIOThreadHelper::SetCorrectionServiceNetError(
    398     int net_error) {
    399   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    400 
    401   interceptor_->set_net_error(net_error);
    402 }
    403 
    404 void DnsProbeBrowserTestIOThreadHelper::SetCorrectionServiceDelayRequests(
    405     bool delay_requests) {
    406   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    407 
    408   interceptor_->SetDelayRequests(delay_requests);
    409 }
    410 
    411 void DnsProbeBrowserTestIOThreadHelper::SetRequestDestructionCallback(
    412     const base::Closure& callback) {
    413   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    414 
    415   interceptor_->SetRequestDestructionCallback(callback);
    416 }
    417 
    418 void DnsProbeBrowserTestIOThreadHelper::StartDelayedProbes(
    419     int expected_delayed_probe_count) {
    420   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    421 
    422   CHECK(delaying_dns_probe_service_);
    423 
    424   int actual_delayed_probe_count =
    425       delaying_dns_probe_service_->delayed_probe_count();
    426   EXPECT_EQ(expected_delayed_probe_count, actual_delayed_probe_count);
    427 
    428   delaying_dns_probe_service_->StartDelayedProbes();
    429 }
    430 
    431 class DnsProbeBrowserTest : public InProcessBrowserTest {
    432  public:
    433   DnsProbeBrowserTest();
    434   virtual ~DnsProbeBrowserTest();
    435 
    436   virtual void SetUpOnMainThread() OVERRIDE;
    437   virtual void TearDownOnMainThread() OVERRIDE;
    438 
    439  protected:
    440   // Sets the browser object that other methods apply to, and that has the
    441   // DnsProbeStatus messages of its currently active tab monitored.
    442   void SetActiveBrowser(Browser* browser);
    443 
    444   void SetCorrectionServiceBroken(bool broken);
    445   void SetCorrectionServiceDelayRequests(bool delay_requests);
    446   void WaitForDelayedRequestDestruction();
    447   void SetMockDnsClientRules(MockDnsClientRule::Result system_result,
    448                              MockDnsClientRule::Result public_result);
    449 
    450   // These functions are often used to wait for two navigations because two
    451   // pages are loaded when navigation corrections are enabled: a blank page, so
    452   // the user stops seeing the previous page, and then the error page, either
    453   // with navigation corrections or without them (If the request failed).
    454   void NavigateToDnsError(int num_navigations);
    455   void NavigateToOtherError(int num_navigations);
    456 
    457   void StartDelayedProbes(int expected_delayed_probe_count);
    458   DnsProbeStatus WaitForSentStatus();
    459   int pending_status_count() const { return dns_probe_status_queue_.size(); }
    460 
    461   std::string Title();
    462   bool PageContains(const std::string& expected);
    463 
    464   // Checks that the local error page is being displayed, without navigation
    465   // corrections, and with the specified status text.  The status text should be
    466   // either a network error or DNS probe status.
    467   void ExpectDisplayingLocalErrorPage(const std::string& status_text);
    468 
    469   // Checks that an error page with mock navigation corrections is being
    470   // displayed, with the specified status text. The status text should be either
    471   // a network error or DNS probe status.
    472   void ExpectDisplayingCorrections(const std::string& status_text);
    473 
    474  private:
    475   void OnDnsProbeStatusSent(DnsProbeStatus dns_probe_status);
    476 
    477   DnsProbeBrowserTestIOThreadHelper* helper_;
    478 
    479   // Browser that methods apply to.
    480   Browser* active_browser_;
    481   // Helper that current has its DnsProbeStatus messages monitored.
    482   NetErrorTabHelper* monitored_tab_helper_;
    483 
    484   bool awaiting_dns_probe_status_;
    485   // Queue of statuses received but not yet consumed by WaitForSentStatus().
    486   std::list<DnsProbeStatus> dns_probe_status_queue_;
    487 };
    488 
    489 DnsProbeBrowserTest::DnsProbeBrowserTest()
    490     : helper_(new DnsProbeBrowserTestIOThreadHelper()),
    491       active_browser_(NULL),
    492       monitored_tab_helper_(NULL),
    493       awaiting_dns_probe_status_(false) {
    494 }
    495 
    496 DnsProbeBrowserTest::~DnsProbeBrowserTest() {
    497   // No tests should have any unconsumed probe statuses.
    498   EXPECT_EQ(0, pending_status_count());
    499 }
    500 
    501 void DnsProbeBrowserTest::SetUpOnMainThread() {
    502   NetErrorTabHelper::set_state_for_testing(
    503       NetErrorTabHelper::TESTING_DEFAULT);
    504 
    505   browser()->profile()->GetPrefs()->SetBoolean(
    506       prefs::kAlternateErrorPagesEnabled, true);
    507 
    508   BrowserThread::PostTask(
    509       BrowserThread::IO, FROM_HERE,
    510       Bind(&DnsProbeBrowserTestIOThreadHelper::SetUpOnIOThread,
    511            Unretained(helper_),
    512            g_browser_process->io_thread()));
    513 
    514   SetActiveBrowser(browser());
    515 }
    516 
    517 void DnsProbeBrowserTest::TearDownOnMainThread() {
    518   BrowserThread::PostTask(
    519       BrowserThread::IO, FROM_HERE,
    520       Bind(&DnsProbeBrowserTestIOThreadHelper::CleanUpOnIOThreadAndDeleteHelper,
    521            Unretained(helper_)));
    522 
    523   NetErrorTabHelper::set_state_for_testing(
    524       NetErrorTabHelper::TESTING_DEFAULT);
    525 }
    526 
    527 void DnsProbeBrowserTest::SetActiveBrowser(Browser* browser) {
    528   // If currently watching a NetErrorTabHelper, stop doing so before start
    529   // watching another.
    530   if (monitored_tab_helper_) {
    531     monitored_tab_helper_->set_dns_probe_status_snoop_callback_for_testing(
    532         NetErrorTabHelper::DnsProbeStatusSnoopCallback());
    533   }
    534   active_browser_ = browser;
    535   monitored_tab_helper_ = NetErrorTabHelper::FromWebContents(
    536       active_browser_->tab_strip_model()->GetActiveWebContents());
    537   monitored_tab_helper_->set_dns_probe_status_snoop_callback_for_testing(
    538       Bind(&DnsProbeBrowserTest::OnDnsProbeStatusSent, Unretained(this)));
    539 }
    540 
    541 void DnsProbeBrowserTest::SetCorrectionServiceBroken(bool broken) {
    542   int net_error = broken ? net::ERR_NAME_NOT_RESOLVED : net::OK;
    543 
    544   BrowserThread::PostTask(
    545       BrowserThread::IO, FROM_HERE,
    546       Bind(&DnsProbeBrowserTestIOThreadHelper::SetCorrectionServiceNetError,
    547            Unretained(helper_),
    548            net_error));
    549 }
    550 
    551 void DnsProbeBrowserTest::SetCorrectionServiceDelayRequests(
    552     bool delay_requests) {
    553   BrowserThread::PostTask(
    554       BrowserThread::IO, FROM_HERE,
    555       Bind(&DnsProbeBrowserTestIOThreadHelper::
    556                SetCorrectionServiceDelayRequests,
    557            Unretained(helper_),
    558            delay_requests));
    559 }
    560 
    561 void DnsProbeBrowserTest::WaitForDelayedRequestDestruction() {
    562   base::RunLoop run_loop;
    563   BrowserThread::PostTask(
    564       BrowserThread::IO, FROM_HERE,
    565       Bind(&DnsProbeBrowserTestIOThreadHelper::SetRequestDestructionCallback,
    566            Unretained(helper_),
    567            base::Bind(&RunClosureOnUIThread,
    568                       run_loop.QuitClosure())));
    569   run_loop.Run();
    570 }
    571 
    572 void DnsProbeBrowserTest::NavigateToDnsError(int num_navigations) {
    573   NavigateToURLBlockUntilNavigationsComplete(
    574       active_browser_,
    575       URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED),
    576       num_navigations);
    577 }
    578 
    579 void DnsProbeBrowserTest::NavigateToOtherError(int num_navigations) {
    580   NavigateToURLBlockUntilNavigationsComplete(
    581       active_browser_,
    582       URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_REFUSED),
    583       num_navigations);
    584 }
    585 
    586 void DnsProbeBrowserTest::SetMockDnsClientRules(
    587     MockDnsClientRule::Result system_result,
    588     MockDnsClientRule::Result public_result) {
    589   BrowserThread::PostTask(
    590       BrowserThread::IO, FROM_HERE,
    591       Bind(&DnsProbeBrowserTestIOThreadHelper::SetMockDnsClientRules,
    592            Unretained(helper_),
    593            system_result,
    594            public_result));
    595 }
    596 
    597 void DnsProbeBrowserTest::StartDelayedProbes(
    598     int expected_delayed_probe_count) {
    599   BrowserThread::PostTask(
    600       BrowserThread::IO, FROM_HERE,
    601       Bind(&DnsProbeBrowserTestIOThreadHelper::StartDelayedProbes,
    602            Unretained(helper_),
    603            expected_delayed_probe_count));
    604 }
    605 
    606 DnsProbeStatus DnsProbeBrowserTest::WaitForSentStatus() {
    607   CHECK(!awaiting_dns_probe_status_);
    608   while (dns_probe_status_queue_.empty()) {
    609     awaiting_dns_probe_status_ = true;
    610     MessageLoop::current()->Run();
    611     awaiting_dns_probe_status_ = false;
    612   }
    613 
    614   CHECK(!dns_probe_status_queue_.empty());
    615   DnsProbeStatus status = dns_probe_status_queue_.front();
    616   dns_probe_status_queue_.pop_front();
    617   return status;
    618 }
    619 
    620 // Check title by roundtripping to renderer, to make sure any probe results
    621 // sent before this have been applied.
    622 std::string DnsProbeBrowserTest::Title() {
    623   std::string title;
    624 
    625   WebContents* contents =
    626       active_browser_->tab_strip_model()->GetActiveWebContents();
    627 
    628   bool rv = content::ExecuteScriptAndExtractString(
    629       contents,
    630       "domAutomationController.send(document.title);",
    631       &title);
    632   if (!rv)
    633     return "";
    634 
    635   return title;
    636 }
    637 
    638 // Check text by roundtripping to renderer, to make sure any probe results
    639 // sent before this have been applied.
    640 bool DnsProbeBrowserTest::PageContains(const std::string& expected) {
    641   std::string text_content;
    642 
    643   bool rv = content::ExecuteScriptAndExtractString(
    644       active_browser_->tab_strip_model()->GetActiveWebContents(),
    645       "domAutomationController.send(document.body.textContent);",
    646       &text_content);
    647   if (!rv)
    648     return false;
    649 
    650   return text_content.find(expected) != std::string::npos;
    651 }
    652 
    653 void DnsProbeBrowserTest::ExpectDisplayingLocalErrorPage(
    654     const std::string& status_text) {
    655   EXPECT_FALSE(PageContains("http://correction1/"));
    656   EXPECT_FALSE(PageContains("http://correction2/"));
    657   EXPECT_TRUE(PageContains(status_text));
    658 }
    659 
    660 void DnsProbeBrowserTest::ExpectDisplayingCorrections(
    661     const std::string& status_text) {
    662   EXPECT_TRUE(PageContains("http://correction1/"));
    663   EXPECT_TRUE(PageContains("http://correction2/"));
    664   EXPECT_TRUE(PageContains(status_text));
    665 }
    666 
    667 void DnsProbeBrowserTest::OnDnsProbeStatusSent(
    668     DnsProbeStatus dns_probe_status) {
    669   dns_probe_status_queue_.push_back(dns_probe_status);
    670   if (awaiting_dns_probe_status_)
    671     MessageLoop::current()->Quit();
    672 }
    673 
    674 // Make sure probes don't break non-DNS error pages when corrections load.
    675 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, OtherErrorWithCorrectionsSuccess) {
    676   SetCorrectionServiceBroken(false);
    677 
    678   NavigateToOtherError(2);
    679   ExpectDisplayingCorrections("ERR_CONNECTION_REFUSED");
    680 }
    681 
    682 // Make sure probes don't break non-DNS error pages when corrections failed to
    683 // load.
    684 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, OtherErrorWithCorrectionsFailure) {
    685   SetCorrectionServiceBroken(true);
    686 
    687   NavigateToOtherError(2);
    688   ExpectDisplayingLocalErrorPage("ERR_CONNECTION_REFUSED");
    689 }
    690 
    691 // Make sure probes don't break DNS error pages when corrections load.
    692 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest,
    693                        NxdomainProbeResultWithWorkingCorrections) {
    694   SetCorrectionServiceBroken(false);
    695   SetMockDnsClientRules(MockDnsClientRule::OK, MockDnsClientRule::OK);
    696 
    697   NavigateToDnsError(2);
    698   ExpectDisplayingCorrections("ERR_NAME_NOT_RESOLVED");
    699 
    700   // One status for committing a blank page before the corrections, and one for
    701   // when the error page with corrections is committed.
    702   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    703   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    704   EXPECT_EQ(0, pending_status_count());
    705   ExpectDisplayingCorrections("ERR_NAME_NOT_RESOLVED");
    706 
    707   StartDelayedProbes(1);
    708 
    709   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN,
    710             WaitForSentStatus());
    711   EXPECT_EQ(0, pending_status_count());
    712   ExpectDisplayingCorrections("ERR_NAME_NOT_RESOLVED");
    713 }
    714 
    715 // Make sure probes don't break corrections when probes complete before the
    716 // corrections load.
    717 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest,
    718                        NxdomainProbeResultWithWorkingSlowCorrections) {
    719   SetCorrectionServiceBroken(false);
    720   SetCorrectionServiceDelayRequests(true);
    721   SetMockDnsClientRules(MockDnsClientRule::OK, MockDnsClientRule::OK);
    722 
    723   NavigateToDnsError(1);
    724   // A blank page should be displayed while the corrections are loaded.
    725   EXPECT_EQ("", Title());
    726 
    727   // A single probe should be triggered by the error page load, and it should
    728   // be ignored.
    729   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    730   EXPECT_EQ(0, pending_status_count());
    731   EXPECT_EQ("", Title());
    732 
    733   StartDelayedProbes(1);
    734   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN,
    735             WaitForSentStatus());
    736   EXPECT_EQ(0, pending_status_count());
    737   EXPECT_EQ("", Title());
    738 
    739   content::TestNavigationObserver observer(
    740       browser()->tab_strip_model()->GetActiveWebContents(), 1);
    741   // The corrections finish loading.
    742   SetCorrectionServiceDelayRequests(false);
    743   // Wait for it to commit.
    744   observer.Wait();
    745   ExpectDisplayingCorrections("ERR_NAME_NOT_RESOLVED");
    746 
    747   // Committing the corections page should trigger sending the probe result
    748   // again.
    749   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN,
    750             WaitForSentStatus());
    751   ExpectDisplayingCorrections("ERR_NAME_NOT_RESOLVED");
    752 }
    753 
    754 // Make sure probes update DNS error page properly when they're supposed to.
    755 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest,
    756                        NoInternetProbeResultWithBrokenCorrections) {
    757   SetCorrectionServiceBroken(true);
    758   SetMockDnsClientRules(MockDnsClientRule::TIMEOUT,
    759                         MockDnsClientRule::TIMEOUT);
    760 
    761   NavigateToDnsError(2);
    762 
    763   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    764   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    765 
    766   // Checking the page runs the RunLoop, so make sure nothing hairy happens.
    767   EXPECT_EQ(0, pending_status_count());
    768   ExpectDisplayingLocalErrorPage("DNS_PROBE_STARTED");
    769   EXPECT_EQ(0, pending_status_count());
    770 
    771   StartDelayedProbes(1);
    772 
    773   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET,
    774             WaitForSentStatus());
    775 
    776   // Checking the page runs the RunLoop, so make sure nothing hairy happens.
    777   EXPECT_EQ(0, pending_status_count());
    778   ExpectDisplayingLocalErrorPage("DNS_PROBE_FINISHED_NO_INTERNET");
    779 }
    780 
    781 // Make sure probes don't break corrections when probes complete before the
    782 // corrections request returns an error.
    783 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest,
    784                        NoInternetProbeResultWithSlowBrokenCorrections) {
    785   SetCorrectionServiceBroken(true);
    786   SetCorrectionServiceDelayRequests(true);
    787   SetMockDnsClientRules(MockDnsClientRule::TIMEOUT,
    788                         MockDnsClientRule::TIMEOUT);
    789 
    790   NavigateToDnsError(1);
    791   // A blank page should be displayed while the corrections load.
    792   EXPECT_EQ("", Title());
    793 
    794   // A single probe should be triggered by the error page load, and it should
    795   // be ignored.
    796   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    797   EXPECT_EQ(0, pending_status_count());
    798   EXPECT_EQ("", Title());
    799 
    800   StartDelayedProbes(1);
    801   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET,
    802             WaitForSentStatus());
    803   EXPECT_EQ("", Title());
    804   EXPECT_EQ(0, pending_status_count());
    805 
    806   content::TestNavigationObserver observer(
    807       browser()->tab_strip_model()->GetActiveWebContents(), 1);
    808   // The corrections request fails.
    809   SetCorrectionServiceDelayRequests(false);
    810   // Wait for the DNS error page to load instead.
    811   observer.Wait();
    812   // The page committing should result in sending the probe results again.
    813   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET,
    814             WaitForSentStatus());
    815 
    816   EXPECT_EQ(0, pending_status_count());
    817   ExpectDisplayingLocalErrorPage("DNS_PROBE_FINISHED_NO_INTERNET");
    818 }
    819 
    820 // Double-check to make sure sync failures don't explode.
    821 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, SyncFailureWithBrokenCorrections) {
    822   SetCorrectionServiceBroken(true);
    823   SetMockDnsClientRules(MockDnsClientRule::FAIL, MockDnsClientRule::FAIL);
    824 
    825   NavigateToDnsError(2);
    826 
    827   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    828   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    829 
    830   // Checking the page runs the RunLoop, so make sure nothing hairy happens.
    831   EXPECT_EQ(0, pending_status_count());
    832   ExpectDisplayingLocalErrorPage("DNS_PROBE_STARTED");
    833   EXPECT_EQ(0, pending_status_count());
    834 
    835   StartDelayedProbes(1);
    836 
    837   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE,
    838             WaitForSentStatus());
    839 
    840   // Checking the page runs the RunLoop, so make sure nothing hairy happens.
    841   EXPECT_EQ(0, pending_status_count());
    842   ExpectDisplayingLocalErrorPage("ERR_NAME_NOT_RESOLVED");
    843   EXPECT_EQ(0, pending_status_count());
    844 }
    845 
    846 // Test that pressing the stop button cancels loading corrections.
    847 // TODO(mmenke):  Add a test for the cross process navigation case.
    848 // TODO(mmenke):  This test could flakily pass due to the timeout on downloading
    849 //                the corrections.  Disable that timeout for browser tests.
    850 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, CorrectionsLoadStopped) {
    851   SetCorrectionServiceDelayRequests(true);
    852   SetCorrectionServiceBroken(true);
    853   SetMockDnsClientRules(MockDnsClientRule::TIMEOUT, MockDnsClientRule::TIMEOUT);
    854 
    855   NavigateToDnsError(1);
    856 
    857   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    858   StartDelayedProbes(1);
    859   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET,
    860             WaitForSentStatus());
    861 
    862   EXPECT_EQ("", Title());
    863   EXPECT_EQ(0, pending_status_count());
    864 
    865   chrome::Stop(browser());
    866   WaitForDelayedRequestDestruction();
    867 
    868   // End up displaying a blank page.
    869   EXPECT_EQ("", Title());
    870 }
    871 
    872 // Test that pressing the stop button cancels the load of corrections, and
    873 // receiving a probe result afterwards does not swap in a DNS error page.
    874 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, CorrectionsLoadStoppedSlowProbe) {
    875   SetCorrectionServiceDelayRequests(true);
    876   SetCorrectionServiceBroken(true);
    877   SetMockDnsClientRules(MockDnsClientRule::TIMEOUT, MockDnsClientRule::TIMEOUT);
    878 
    879   NavigateToDnsError(1);
    880 
    881   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    882 
    883   EXPECT_EQ("", Title());
    884   EXPECT_EQ(0, pending_status_count());
    885 
    886   chrome::Stop(browser());
    887   WaitForDelayedRequestDestruction();
    888 
    889   EXPECT_EQ("", Title());
    890   EXPECT_EQ(0, pending_status_count());
    891 
    892   StartDelayedProbes(1);
    893   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET,
    894             WaitForSentStatus());
    895 
    896   EXPECT_EQ("", Title());
    897 }
    898 
    899 // Make sure probes don't run for subframe DNS errors.
    900 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, NoProbeInSubframe) {
    901   SetCorrectionServiceBroken(false);
    902 
    903   const FilePath::CharType kIframeDnsErrorHtmlName[] =
    904       FILE_PATH_LITERAL("iframe_dns_error.html");
    905 
    906   NavigateToURL(
    907       browser(),
    908       URLRequestMockHTTPJob::GetMockUrl(FilePath(kIframeDnsErrorHtmlName)));
    909 
    910   // By the time NavigateToURL returns, the browser will have seen the failed
    911   // provisional load.  If a probe was started (or considered but not run),
    912   // then the NetErrorTabHelper would have sent a NetErrorInfo message.  Thus,
    913   // if one hasn't been sent by now, the NetErrorTabHelper has not (and won't)
    914   // start a probe for this DNS error.
    915   EXPECT_EQ(0, pending_status_count());
    916 }
    917 
    918 // Make sure browser sends NOT_RUN properly when probes are disabled.
    919 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, ProbesDisabled) {
    920   // Disable probes (And corrections).
    921   browser()->profile()->GetPrefs()->SetBoolean(
    922       prefs::kAlternateErrorPagesEnabled, false);
    923 
    924   SetCorrectionServiceBroken(true);
    925   SetMockDnsClientRules(MockDnsClientRule::TIMEOUT, MockDnsClientRule::TIMEOUT);
    926 
    927   NavigateToDnsError(1);
    928 
    929   EXPECT_EQ(chrome_common_net::DNS_PROBE_NOT_RUN, WaitForSentStatus());
    930 
    931   // Checking the page runs the RunLoop, so make sure nothing hairy happens.
    932   EXPECT_EQ(0, pending_status_count());
    933   ExpectDisplayingLocalErrorPage("ERR_NAME_NOT_RESOLVED");
    934 }
    935 
    936 // Test the case that corrections are disabled, but DNS probes are enabled.
    937 // This is the case with Chromium builds.
    938 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, CorrectionsDisabled) {
    939   // Disable corrections.
    940   browser()->profile()->GetPrefs()->SetBoolean(
    941       prefs::kAlternateErrorPagesEnabled, false);
    942   // Requests to the correction service should work if any are made, so the test
    943   // fails if that happens unexpectedly.
    944   SetCorrectionServiceBroken(false);
    945   // Normally disabling corrections disables DNS probes, so force DNS probes
    946   // to be enabled.
    947   NetErrorTabHelper::set_state_for_testing(
    948       NetErrorTabHelper::TESTING_FORCE_ENABLED);
    949 
    950   SetMockDnsClientRules(MockDnsClientRule::FAIL, MockDnsClientRule::FAIL);
    951 
    952   // Just one commit and one sent status, since corrections are disabled.
    953   NavigateToDnsError(1);
    954   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    955 
    956   // Checking the page runs the RunLoop, so make sure nothing hairy happens.
    957   EXPECT_EQ(0, pending_status_count());
    958   ExpectDisplayingLocalErrorPage("DNS_PROBE_STARTED");
    959   EXPECT_EQ(0, pending_status_count());
    960 
    961   StartDelayedProbes(1);
    962 
    963   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE,
    964             WaitForSentStatus());
    965   EXPECT_EQ(0, pending_status_count());
    966   ExpectDisplayingLocalErrorPage("ERR_NAME_NOT_RESOLVED");
    967 }
    968 
    969 // Test incognito mode.  Corrections should be disabled, but DNS probes are
    970 // still enabled.
    971 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, Incognito) {
    972   // Requests to the correction service should work if any are made, so the test
    973   // will fail if one is requested unexpectedly.
    974   SetCorrectionServiceBroken(false);
    975 
    976   Browser* incognito = CreateIncognitoBrowser();
    977   SetActiveBrowser(incognito);
    978 
    979   SetMockDnsClientRules(MockDnsClientRule::FAIL, MockDnsClientRule::FAIL);
    980 
    981   // Just one commit and one sent status, since the corrections are disabled.
    982   NavigateToDnsError(1);
    983   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    984 
    985   // Checking the page runs the RunLoop, so make sure nothing hairy happens.
    986   EXPECT_EQ(0, pending_status_count());
    987   ExpectDisplayingLocalErrorPage("DNS_PROBE_STARTED");
    988   EXPECT_EQ(0, pending_status_count());
    989 
    990   StartDelayedProbes(1);
    991 
    992   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE,
    993             WaitForSentStatus());
    994   EXPECT_EQ(0, pending_status_count());
    995   ExpectDisplayingLocalErrorPage("ERR_NAME_NOT_RESOLVED");
    996 }
    997 
    998 }  // namespace
    999 
   1000 }  // namespace chrome_browser_net
   1001