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/google/google_util.h"
     16 #include "chrome/browser/io_thread.h"
     17 #include "chrome/browser/net/dns_probe_test_util.h"
     18 #include "chrome/browser/net/net_error_tab_helper.h"
     19 #include "chrome/browser/net/url_request_mock_util.h"
     20 #include "chrome/browser/profiles/profile.h"
     21 #include "chrome/browser/ui/browser.h"
     22 #include "chrome/browser/ui/browser_commands.h"
     23 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     24 #include "chrome/common/chrome_paths.h"
     25 #include "chrome/common/net/net_error_info.h"
     26 #include "chrome/common/pref_names.h"
     27 #include "chrome/test/base/in_process_browser_test.h"
     28 #include "chrome/test/base/ui_test_utils.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 "content/test/net/url_request_failed_job.h"
     34 #include "content/test/net/url_request_mock_http_job.h"
     35 #include "net/base/net_errors.h"
     36 #include "net/dns/dns_test_util.h"
     37 #include "net/url_request/url_request_filter.h"
     38 #include "net/url_request/url_request_job.h"
     39 #include "net/url_request/url_request_job_factory.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 content::URLRequestFailedJob;
     51 using content::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::URLRequestJob;
     59 using net::URLRequestJobFactory;
     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.html");
    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(request, network_delegate, file_path),
    185         should_delay_(should_delay),
    186         start_delayed_(false),
    187         destruction_callback_(destruction_callback) {}
    188 
    189   virtual void Start() OVERRIDE {
    190     if (should_delay_) {
    191       DCHECK(!start_delayed_);
    192       start_delayed_ = true;
    193       return;
    194     }
    195     URLRequestMockHTTPJob::Start();
    196   }
    197 
    198   virtual void Resume() OVERRIDE {
    199     DCHECK(should_delay_);
    200     should_delay_ = false;
    201     if (start_delayed_) {
    202       start_delayed_ = false;
    203       Start();
    204     }
    205   }
    206 
    207  private:
    208   virtual ~DelayableURLRequestMockHTTPJob() {
    209     if (should_delay_)
    210       destruction_callback_.Run(this);
    211   }
    212 
    213   bool should_delay_;
    214   bool start_delayed_;
    215   const DestructionCallback destruction_callback_;
    216 };
    217 
    218 // ProtocolHandler for Link Doctor requests.  Can cause requests to fail with
    219 // an error, and/or delay a request until a test allows to continue.  Also can
    220 // run a callback when a delayed request is cancelled.
    221 class BreakableLinkDoctorProtocolHandler
    222     : public URLRequestJobFactory::ProtocolHandler {
    223  public:
    224   explicit BreakableLinkDoctorProtocolHandler(
    225       const FilePath& mock_link_doctor_file_path)
    226       : mock_link_doctor_file_path_(mock_link_doctor_file_path),
    227         net_error_(net::OK),
    228         delay_requests_(false),
    229         on_request_destroyed_callback_(
    230             base::Bind(&BreakableLinkDoctorProtocolHandler::OnRequestDestroyed,
    231                        base::Unretained(this))) {
    232   }
    233 
    234   virtual ~BreakableLinkDoctorProtocolHandler() {
    235     // All delayed requests should have been resumed or cancelled by this point.
    236     EXPECT_TRUE(delayed_requests_.empty());
    237   }
    238 
    239   virtual URLRequestJob* MaybeCreateJob(
    240       URLRequest* request,
    241       NetworkDelegate* network_delegate) const OVERRIDE {
    242     if (net_error_ != net::OK) {
    243       DelayableURLRequestFailedJob* job =
    244           new DelayableURLRequestFailedJob(
    245               request, network_delegate, net_error_, delay_requests_,
    246               on_request_destroyed_callback_);
    247       if (delay_requests_)
    248         delayed_requests_.insert(job);
    249       return job;
    250     } else {
    251       DelayableURLRequestMockHTTPJob* job =
    252           new DelayableURLRequestMockHTTPJob(
    253               request, network_delegate, mock_link_doctor_file_path_,
    254               delay_requests_, on_request_destroyed_callback_);
    255       if (delay_requests_)
    256         delayed_requests_.insert(job);
    257       return job;
    258     }
    259   }
    260 
    261   void set_net_error(int net_error) { net_error_ = net_error; }
    262 
    263   void SetDelayRequests(bool delay_requests) {
    264     delay_requests_ = delay_requests;
    265 
    266     // Resume all delayed requests if no longer delaying requests.
    267     if (!delay_requests) {
    268       while (!delayed_requests_.empty()) {
    269         DelayableRequest* request = *delayed_requests_.begin();
    270         delayed_requests_.erase(request);
    271         request->Resume();
    272       }
    273     }
    274   }
    275 
    276   // Runs |callback| once all delayed requests have been destroyed.  Does not
    277   // wait for delayed requests that have been resumed.
    278   void SetRequestDestructionCallback(const base::Closure& callback) {
    279     ASSERT_TRUE(delayed_request_destruction_callback_.is_null());
    280     if (delayed_requests_.empty()) {
    281       callback.Run();
    282       return;
    283     }
    284     delayed_request_destruction_callback_ = callback;
    285   }
    286 
    287   void OnRequestDestroyed(DelayableRequest* request) {
    288     ASSERT_EQ(1u, delayed_requests_.count(request));
    289     delayed_requests_.erase(request);
    290     if (delayed_requests_.empty() &&
    291         !delayed_request_destruction_callback_.is_null()) {
    292       delayed_request_destruction_callback_.Run();
    293       delayed_request_destruction_callback_.Reset();
    294     }
    295   }
    296 
    297  private:
    298   const FilePath mock_link_doctor_file_path_;
    299   int net_error_;
    300   bool delay_requests_;
    301 
    302   // Called when a request is destroyed.  Memeber variable because
    303   // MaybeCreateJob is "const", so calling base::Bind in that function does
    304   // not work well.
    305   const DelayableRequest::DestructionCallback on_request_destroyed_callback_;
    306 
    307   // Mutable is needed because MaybeCreateJob is const.
    308   mutable std::set<DelayableRequest*> delayed_requests_;
    309 
    310   base::Closure delayed_request_destruction_callback_;
    311 };
    312 
    313 class DnsProbeBrowserTestIOThreadHelper {
    314  public:
    315   DnsProbeBrowserTestIOThreadHelper();
    316 
    317   void SetUpOnIOThread(IOThread* io_thread);
    318   void CleanUpOnIOThreadAndDeleteHelper();
    319 
    320   void SetMockDnsClientRules(MockDnsClientRule::Result system_good_result,
    321                              MockDnsClientRule::Result public_good_result);
    322   void SetLinkDoctorNetError(int link_doctor_net_error);
    323   void SetLinkDoctorDelayRequests(bool delay_requests);
    324   void SetRequestDestructionCallback(const base::Closure& callback);
    325   void StartDelayedProbes(int expected_delayed_probe_count);
    326 
    327  private:
    328   IOThread* io_thread_;
    329   DnsProbeService* original_dns_probe_service_;
    330   DelayingDnsProbeService* delaying_dns_probe_service_;
    331   BreakableLinkDoctorProtocolHandler* protocol_handler_;
    332   FilePath mock_link_doctor_file_path_;
    333 };
    334 
    335 DnsProbeBrowserTestIOThreadHelper::DnsProbeBrowserTestIOThreadHelper()
    336     : io_thread_(NULL),
    337       original_dns_probe_service_(NULL),
    338       delaying_dns_probe_service_(NULL),
    339       protocol_handler_(NULL),
    340       mock_link_doctor_file_path_(GetMockLinkDoctorFilePath()) {}
    341 
    342 void DnsProbeBrowserTestIOThreadHelper::SetUpOnIOThread(IOThread* io_thread) {
    343   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    344   CHECK(io_thread);
    345   CHECK(!io_thread_);
    346   CHECK(!original_dns_probe_service_);
    347   CHECK(!delaying_dns_probe_service_);
    348   CHECK(!protocol_handler_);
    349 
    350   io_thread_ = io_thread;
    351 
    352   delaying_dns_probe_service_ = new DelayingDnsProbeService();
    353 
    354   IOThread::Globals* globals = io_thread_->globals();
    355   original_dns_probe_service_ = globals->dns_probe_service.release();
    356   globals->dns_probe_service.reset(delaying_dns_probe_service_);
    357 
    358   URLRequestFailedJob::AddUrlHandler();
    359 
    360   scoped_ptr<URLRequestJobFactory::ProtocolHandler> protocol_handler(
    361       new BreakableLinkDoctorProtocolHandler(mock_link_doctor_file_path_));
    362   protocol_handler_ =
    363       static_cast<BreakableLinkDoctorProtocolHandler*>(protocol_handler.get());
    364   const GURL link_doctor_base_url = LinkDoctorBaseURL();
    365   const std::string link_doctor_host = link_doctor_base_url.host();
    366   URLRequestFilter::GetInstance()->AddHostnameProtocolHandler(
    367       "http", link_doctor_host, protocol_handler.Pass());
    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::SetLinkDoctorNetError(
    398     int link_doctor_net_error) {
    399   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    400 
    401   protocol_handler_->set_net_error(link_doctor_net_error);
    402 }
    403 
    404 void DnsProbeBrowserTestIOThreadHelper::SetLinkDoctorDelayRequests(
    405     bool delay_requests) {
    406   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    407 
    408   protocol_handler_->SetDelayRequests(delay_requests);
    409 }
    410 
    411 void DnsProbeBrowserTestIOThreadHelper::SetRequestDestructionCallback(
    412     const base::Closure& callback) {
    413   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    414 
    415   protocol_handler_->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 CleanUpOnMainThread() 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 SetLinkDoctorBroken(bool broken);
    445   void SetLinkDoctorDelayRequests(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 the Link
    451   // Doctor loads two pages: a blank page, so the user stops seeing the previous
    452   // page, and then either the Link Doctor page or a regular error page.  Often
    453   // need to wait for both to finish in a row.
    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  private:
    465   void OnDnsProbeStatusSent(DnsProbeStatus dns_probe_status);
    466 
    467   DnsProbeBrowserTestIOThreadHelper* helper_;
    468 
    469   // Browser that methods apply to.
    470   Browser* active_browser_;
    471   // Helper that current has its DnsProbeStatus messages monitored.
    472   NetErrorTabHelper* monitored_tab_helper_;
    473 
    474   bool awaiting_dns_probe_status_;
    475   // Queue of statuses received but not yet consumed by WaitForSentStatus().
    476   std::list<DnsProbeStatus> dns_probe_status_queue_;
    477 };
    478 
    479 DnsProbeBrowserTest::DnsProbeBrowserTest()
    480     : helper_(new DnsProbeBrowserTestIOThreadHelper()),
    481       active_browser_(NULL),
    482       monitored_tab_helper_(NULL),
    483       awaiting_dns_probe_status_(false) {
    484 }
    485 
    486 DnsProbeBrowserTest::~DnsProbeBrowserTest() {
    487   // No tests should have any unconsumed probe statuses.
    488   EXPECT_EQ(0, pending_status_count());
    489 }
    490 
    491 void DnsProbeBrowserTest::SetUpOnMainThread() {
    492   NetErrorTabHelper::set_state_for_testing(
    493       NetErrorTabHelper::TESTING_DEFAULT);
    494 
    495   browser()->profile()->GetPrefs()->SetBoolean(
    496       prefs::kAlternateErrorPagesEnabled, true);
    497 
    498   BrowserThread::PostTask(
    499       BrowserThread::IO, FROM_HERE,
    500       Bind(&DnsProbeBrowserTestIOThreadHelper::SetUpOnIOThread,
    501            Unretained(helper_),
    502            g_browser_process->io_thread()));
    503 
    504   SetActiveBrowser(browser());
    505 }
    506 
    507 void DnsProbeBrowserTest::CleanUpOnMainThread() {
    508   BrowserThread::PostTask(
    509       BrowserThread::IO, FROM_HERE,
    510       Bind(&DnsProbeBrowserTestIOThreadHelper::CleanUpOnIOThreadAndDeleteHelper,
    511            Unretained(helper_)));
    512 
    513   NetErrorTabHelper::set_state_for_testing(
    514       NetErrorTabHelper::TESTING_DEFAULT);
    515 }
    516 
    517 void DnsProbeBrowserTest::SetActiveBrowser(Browser* browser) {
    518   // If currently watching a NetErrorTabHelper, stop doing so before start
    519   // watching another.
    520   if (monitored_tab_helper_) {
    521     monitored_tab_helper_->set_dns_probe_status_snoop_callback_for_testing(
    522         NetErrorTabHelper::DnsProbeStatusSnoopCallback());
    523   }
    524   active_browser_ = browser;
    525   monitored_tab_helper_ = NetErrorTabHelper::FromWebContents(
    526       active_browser_->tab_strip_model()->GetActiveWebContents());
    527   monitored_tab_helper_->set_dns_probe_status_snoop_callback_for_testing(
    528       Bind(&DnsProbeBrowserTest::OnDnsProbeStatusSent, Unretained(this)));
    529 }
    530 
    531 void DnsProbeBrowserTest::SetLinkDoctorBroken(bool broken) {
    532   int net_error = broken ? net::ERR_NAME_NOT_RESOLVED : net::OK;
    533 
    534   BrowserThread::PostTask(
    535       BrowserThread::IO, FROM_HERE,
    536       Bind(&DnsProbeBrowserTestIOThreadHelper::SetLinkDoctorNetError,
    537            Unretained(helper_),
    538            net_error));
    539 }
    540 
    541 void DnsProbeBrowserTest::SetLinkDoctorDelayRequests(bool delay_requests) {
    542   BrowserThread::PostTask(
    543       BrowserThread::IO, FROM_HERE,
    544       Bind(&DnsProbeBrowserTestIOThreadHelper::SetLinkDoctorDelayRequests,
    545            Unretained(helper_),
    546            delay_requests));
    547 }
    548 
    549 void DnsProbeBrowserTest::WaitForDelayedRequestDestruction() {
    550   base::RunLoop run_loop;
    551   BrowserThread::PostTask(
    552       BrowserThread::IO, FROM_HERE,
    553       Bind(&DnsProbeBrowserTestIOThreadHelper::SetRequestDestructionCallback,
    554            Unretained(helper_),
    555            base::Bind(&RunClosureOnUIThread,
    556                       run_loop.QuitClosure())));
    557   run_loop.Run();
    558 }
    559 
    560 void DnsProbeBrowserTest::NavigateToDnsError(int num_navigations) {
    561   NavigateToURLBlockUntilNavigationsComplete(
    562       active_browser_,
    563       URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED),
    564       num_navigations);
    565 }
    566 
    567 void DnsProbeBrowserTest::NavigateToOtherError(int num_navigations) {
    568   NavigateToURLBlockUntilNavigationsComplete(
    569       active_browser_,
    570       URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_REFUSED),
    571       num_navigations);
    572 }
    573 
    574 void DnsProbeBrowserTest::SetMockDnsClientRules(
    575     MockDnsClientRule::Result system_result,
    576     MockDnsClientRule::Result public_result) {
    577   BrowserThread::PostTask(
    578       BrowserThread::IO, FROM_HERE,
    579       Bind(&DnsProbeBrowserTestIOThreadHelper::SetMockDnsClientRules,
    580            Unretained(helper_),
    581            system_result,
    582            public_result));
    583 }
    584 
    585 void DnsProbeBrowserTest::StartDelayedProbes(
    586     int expected_delayed_probe_count) {
    587   BrowserThread::PostTask(
    588       BrowserThread::IO, FROM_HERE,
    589       Bind(&DnsProbeBrowserTestIOThreadHelper::StartDelayedProbes,
    590            Unretained(helper_),
    591            expected_delayed_probe_count));
    592 }
    593 
    594 DnsProbeStatus DnsProbeBrowserTest::WaitForSentStatus() {
    595   CHECK(!awaiting_dns_probe_status_);
    596   while (dns_probe_status_queue_.empty()) {
    597     awaiting_dns_probe_status_ = true;
    598     MessageLoop::current()->Run();
    599     awaiting_dns_probe_status_ = false;
    600   }
    601 
    602   CHECK(!dns_probe_status_queue_.empty());
    603   DnsProbeStatus status = dns_probe_status_queue_.front();
    604   dns_probe_status_queue_.pop_front();
    605   return status;
    606 }
    607 
    608 // Check title by roundtripping to renderer, to make sure any probe results
    609 // sent before this have been applied.
    610 std::string DnsProbeBrowserTest::Title() {
    611   std::string title;
    612 
    613   WebContents* contents =
    614       active_browser_->tab_strip_model()->GetActiveWebContents();
    615 
    616   bool rv = content::ExecuteScriptAndExtractString(
    617       contents,
    618       "domAutomationController.send(document.title);",
    619       &title);
    620   if (!rv)
    621     return "";
    622 
    623   return title;
    624 }
    625 
    626 // Check text by roundtripping to renderer, to make sure any probe results
    627 // sent before this have been applied.
    628 bool DnsProbeBrowserTest::PageContains(const std::string& expected) {
    629   std::string text_content;
    630 
    631   bool rv = content::ExecuteScriptAndExtractString(
    632       active_browser_->tab_strip_model()->GetActiveWebContents(),
    633       "domAutomationController.send(document.body.textContent);",
    634       &text_content);
    635   if (!rv)
    636     return false;
    637 
    638   return text_content.find(expected) != std::string::npos;
    639 }
    640 
    641 void DnsProbeBrowserTest::OnDnsProbeStatusSent(
    642     DnsProbeStatus dns_probe_status) {
    643   dns_probe_status_queue_.push_back(dns_probe_status);
    644   if (awaiting_dns_probe_status_)
    645     MessageLoop::current()->Quit();
    646 }
    647 
    648 // Make sure probes don't break non-DNS error pages when Link Doctor loads.
    649 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, OtherErrorWithWorkingLinkDoctor) {
    650   SetLinkDoctorBroken(false);
    651 
    652   NavigateToOtherError(2);
    653   EXPECT_EQ("Mock Link Doctor", Title());
    654 }
    655 
    656 // Make sure probes don't break non-DNS error pages when Link Doctor doesn't
    657 // load.
    658 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, OtherErrorWithBrokenLinkDoctor) {
    659   SetLinkDoctorBroken(true);
    660 
    661   NavigateToOtherError(2);
    662   EXPECT_TRUE(PageContains("CONNECTION_REFUSED"));
    663 }
    664 
    665 // Make sure probes don't break DNS error pages when Link doctor loads.
    666 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest,
    667                        NxdomainProbeResultWithWorkingLinkDoctor) {
    668   SetLinkDoctorBroken(false);
    669   SetMockDnsClientRules(MockDnsClientRule::OK, MockDnsClientRule::OK);
    670 
    671   NavigateToDnsError(2);
    672   EXPECT_EQ("Mock Link Doctor", Title());
    673 
    674   // One status for committing a blank page before the Link Doctor, and one for
    675   // when the Link Doctor is committed.
    676   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    677   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    678   EXPECT_EQ(0, pending_status_count());
    679   EXPECT_EQ("Mock Link Doctor", Title());
    680 
    681   StartDelayedProbes(1);
    682 
    683   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN,
    684             WaitForSentStatus());
    685   EXPECT_EQ(0, pending_status_count());
    686   EXPECT_EQ("Mock Link Doctor", Title());
    687 }
    688 
    689 // Make sure probes don't break Link Doctor when probes complete before the
    690 // Link Doctor loads.
    691 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest,
    692                        NxdomainProbeResultWithWorkingSlowLinkDoctor) {
    693   SetLinkDoctorBroken(false);
    694   SetLinkDoctorDelayRequests(true);
    695   SetMockDnsClientRules(MockDnsClientRule::OK, MockDnsClientRule::OK);
    696 
    697   NavigateToDnsError(1);
    698   // A blank page should be displayed while the Link Doctor page loads.
    699   EXPECT_EQ("", Title());
    700 
    701   // A single probe should be triggered by the error page load, and it should
    702   // be ignored.
    703   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    704   EXPECT_EQ(0, pending_status_count());
    705   EXPECT_EQ("", Title());
    706 
    707   StartDelayedProbes(1);
    708   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN,
    709             WaitForSentStatus());
    710   EXPECT_EQ(0, pending_status_count());
    711   EXPECT_EQ("", Title());
    712 
    713   content::TestNavigationObserver observer(
    714       browser()->tab_strip_model()->GetActiveWebContents(), 1);
    715   // The Link Doctor page finishes loading.
    716   SetLinkDoctorDelayRequests(false);
    717   // Wait for it to commit.
    718   observer.Wait();
    719   EXPECT_EQ("Mock Link Doctor", Title());
    720 
    721   // Committing the Link Doctor page should trigger sending the probe result
    722   // again.
    723   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN,
    724             WaitForSentStatus());
    725   EXPECT_EQ("Mock Link Doctor", Title());
    726 }
    727 
    728 // Make sure probes update DNS error page properly when they're supposed to.
    729 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest,
    730                        NoInternetProbeResultWithBrokenLinkDoctor) {
    731   SetLinkDoctorBroken(true);
    732   SetMockDnsClientRules(MockDnsClientRule::TIMEOUT,
    733                         MockDnsClientRule::TIMEOUT);
    734 
    735   NavigateToDnsError(2);
    736 
    737   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    738   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    739 
    740   // PageContains runs the RunLoop, so make sure nothing hairy happens.
    741   EXPECT_EQ(0, pending_status_count());
    742   EXPECT_TRUE(PageContains("DNS_PROBE_STARTED"));
    743   EXPECT_EQ(0, pending_status_count());
    744 
    745   StartDelayedProbes(1);
    746 
    747   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET,
    748             WaitForSentStatus());
    749 
    750   // PageContains runs the RunLoop, so make sure nothing hairy happens.
    751   EXPECT_EQ(0, pending_status_count());
    752   EXPECT_TRUE(PageContains("DNS_PROBE_FINISHED_NO_INTERNET"));
    753 }
    754 
    755 // Make sure probes don't break Link Doctor when probes complete before the
    756 // Link Doctor request returns an error.
    757 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest,
    758                        NoInternetProbeResultWithSlowBrokenLinkDoctor) {
    759   SetLinkDoctorBroken(true);
    760   SetLinkDoctorDelayRequests(true);
    761   SetMockDnsClientRules(MockDnsClientRule::TIMEOUT,
    762                         MockDnsClientRule::TIMEOUT);
    763 
    764   NavigateToDnsError(1);
    765   // A blank page should be displayed while the Link Doctor page loads.
    766   EXPECT_EQ("", Title());
    767 
    768   // A single probe should be triggered by the error page load, and it should
    769   // be ignored.
    770   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    771   EXPECT_EQ(0, pending_status_count());
    772   EXPECT_EQ("", Title());
    773 
    774   StartDelayedProbes(1);
    775   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET,
    776             WaitForSentStatus());
    777   EXPECT_EQ("", Title());
    778   EXPECT_EQ(0, pending_status_count());
    779 
    780   content::TestNavigationObserver observer(
    781       browser()->tab_strip_model()->GetActiveWebContents(), 1);
    782   // The Link Doctor request fails.
    783   SetLinkDoctorDelayRequests(false);
    784   // Wait for the DNS error page to load instead.
    785   observer.Wait();
    786   // The page committing should result in sending the probe results again.
    787   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET,
    788             WaitForSentStatus());
    789 
    790   EXPECT_EQ(0, pending_status_count());
    791   EXPECT_TRUE(PageContains("DNS_PROBE_FINISHED_NO_INTERNET"));
    792 }
    793 
    794 // Double-check to make sure sync failures don't explode.
    795 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, SyncFailureWithBrokenLinkDoctor) {
    796   SetLinkDoctorBroken(true);
    797   SetMockDnsClientRules(MockDnsClientRule::FAIL, MockDnsClientRule::FAIL);
    798 
    799   NavigateToDnsError(2);
    800 
    801   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    802   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    803 
    804   // PageContains runs the RunLoop, so make sure nothing hairy happens.
    805   EXPECT_EQ(0, pending_status_count());
    806   EXPECT_TRUE(PageContains("DNS_PROBE_STARTED"));
    807   EXPECT_EQ(0, pending_status_count());
    808 
    809   StartDelayedProbes(1);
    810 
    811   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE,
    812             WaitForSentStatus());
    813 
    814   // PageContains runs the RunLoop, so make sure nothing hairy happens.
    815   EXPECT_EQ(0, pending_status_count());
    816   EXPECT_TRUE(PageContains("NAME_NOT_RESOLVED"));
    817   EXPECT_EQ(0, pending_status_count());
    818 }
    819 
    820 // Test that pressing the stop button cancels loading the Link Doctor page.
    821 // TODO(mmenke):  Add a test for the cross process navigation case.
    822 // TODO(mmenke):  This test could flakily pass due to the timeout on downloading
    823 //                the Link Doctor page.  Disable that timeout for browser tests.
    824 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, LinkDoctorLoadStopped) {
    825   SetLinkDoctorDelayRequests(true);
    826   SetLinkDoctorBroken(true);
    827   SetMockDnsClientRules(MockDnsClientRule::TIMEOUT, MockDnsClientRule::TIMEOUT);
    828 
    829   NavigateToDnsError(1);
    830 
    831   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    832   StartDelayedProbes(1);
    833   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET,
    834             WaitForSentStatus());
    835 
    836   EXPECT_EQ("", Title());
    837   EXPECT_EQ(0, pending_status_count());
    838 
    839   chrome::Stop(browser());
    840   WaitForDelayedRequestDestruction();
    841 
    842   // End up displaying a blank page.
    843   EXPECT_EQ("", Title());
    844 }
    845 
    846 // Test that pressing the stop button cancels the load of the Link Doctor error
    847 // page, and receiving a probe result afterwards does not swap in a DNS error
    848 // page.
    849 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, LinkDoctorLoadStoppedSlowProbe) {
    850   SetLinkDoctorDelayRequests(true);
    851   SetLinkDoctorBroken(true);
    852   SetMockDnsClientRules(MockDnsClientRule::TIMEOUT, MockDnsClientRule::TIMEOUT);
    853 
    854   NavigateToDnsError(1);
    855 
    856   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    857 
    858   EXPECT_EQ("", Title());
    859   EXPECT_EQ(0, pending_status_count());
    860 
    861   chrome::Stop(browser());
    862   WaitForDelayedRequestDestruction();
    863 
    864   EXPECT_EQ("", Title());
    865   EXPECT_EQ(0, pending_status_count());
    866 
    867   StartDelayedProbes(1);
    868   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET,
    869             WaitForSentStatus());
    870 
    871   EXPECT_EQ("", Title());
    872 }
    873 
    874 // Make sure probes don't run for subframe DNS errors.
    875 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, NoProbeInSubframe) {
    876   SetLinkDoctorBroken(false);
    877 
    878   const FilePath::CharType kIframeDnsErrorHtmlName[] =
    879       FILE_PATH_LITERAL("iframe_dns_error.html");
    880 
    881   NavigateToURL(
    882       browser(),
    883       URLRequestMockHTTPJob::GetMockUrl(FilePath(kIframeDnsErrorHtmlName)));
    884 
    885   // By the time NavigateToURL returns, the browser will have seen the failed
    886   // provisional load.  If a probe was started (or considered but not run),
    887   // then the NetErrorTabHelper would have sent a NetErrorInfo message.  Thus,
    888   // if one hasn't been sent by now, the NetErrorTabHelper has not (and won't)
    889   // start a probe for this DNS error.
    890   EXPECT_EQ(0, pending_status_count());
    891 }
    892 
    893 // Make sure browser sends NOT_RUN properly when probes are disabled.
    894 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, ProbesDisabled) {
    895   // Disable probes (And Link Doctor).
    896   browser()->profile()->GetPrefs()->SetBoolean(
    897       prefs::kAlternateErrorPagesEnabled, false);
    898 
    899   SetLinkDoctorBroken(true);
    900   SetMockDnsClientRules(MockDnsClientRule::TIMEOUT, MockDnsClientRule::TIMEOUT);
    901 
    902   NavigateToDnsError(1);
    903 
    904   EXPECT_EQ(chrome_common_net::DNS_PROBE_NOT_RUN, WaitForSentStatus());
    905 
    906   // PageContains runs the RunLoop, so make sure nothing hairy happens.
    907   EXPECT_EQ(0, pending_status_count());
    908   EXPECT_TRUE(PageContains("NAME_NOT_RESOLVED"));
    909 }
    910 
    911 // Test the case that Link Doctor is disabled, but DNS probes are enabled.  This
    912 // is the case with Chromium builds.
    913 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, LinkDoctorDisabled) {
    914   // Disable Link Doctor.
    915   browser()->profile()->GetPrefs()->SetBoolean(
    916       prefs::kAlternateErrorPagesEnabled, false);
    917   // Requests to the Link Doctor should work if any are made, so the test fails
    918   // if that happens unexpectedly.
    919   SetLinkDoctorBroken(false);
    920   // Normally disabling the LinkDoctor disables DNS probes, so force DNS probes
    921   // to be enabled.
    922   NetErrorTabHelper::set_state_for_testing(
    923       NetErrorTabHelper::TESTING_FORCE_ENABLED);
    924 
    925   SetMockDnsClientRules(MockDnsClientRule::FAIL, MockDnsClientRule::FAIL);
    926 
    927   // Just one commit and one sent status, since the Link Doctor is disabled.
    928   NavigateToDnsError(1);
    929   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    930 
    931   // PageContains runs the RunLoop, so make sure nothing hairy happens.
    932   EXPECT_EQ(0, pending_status_count());
    933   EXPECT_TRUE(PageContains("DNS_PROBE_STARTED"));
    934   EXPECT_EQ(0, pending_status_count());
    935 
    936   StartDelayedProbes(1);
    937 
    938   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE,
    939             WaitForSentStatus());
    940   EXPECT_EQ(0, pending_status_count());
    941   EXPECT_TRUE(PageContains("NAME_NOT_RESOLVED"));
    942 }
    943 
    944 // Test incognito mode.  Link Doctor should be disabled, but DNS probes are
    945 // still enabled.
    946 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, Incognito) {
    947   // Requests to the Link Doctor should work if any are made, so the test will
    948   // fail if one is requested unexpectedly.
    949   SetLinkDoctorBroken(false);
    950 
    951   Browser* incognito = CreateIncognitoBrowser();
    952   SetActiveBrowser(incognito);
    953 
    954   SetMockDnsClientRules(MockDnsClientRule::FAIL, MockDnsClientRule::FAIL);
    955 
    956   // Just one commit and one sent status, since the Link Doctor is disabled.
    957   NavigateToDnsError(1);
    958   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
    959 
    960   // PageContains runs the RunLoop, so make sure nothing hairy happens.
    961   EXPECT_EQ(0, pending_status_count());
    962   EXPECT_TRUE(PageContains("DNS_PROBE_STARTED"));
    963   EXPECT_EQ(0, pending_status_count());
    964 
    965   StartDelayedProbes(1);
    966 
    967   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE,
    968             WaitForSentStatus());
    969   EXPECT_EQ(0, pending_status_count());
    970   EXPECT_TRUE(PageContains("NAME_NOT_RESOLVED"));
    971 }
    972 
    973 }  // namespace
    974 
    975 }  // namespace chrome_browser_net
    976