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
41using base::Bind;
42using base::Callback;
43using base::Closure;
44using base::ConstRef;
45using base::FilePath;
46using base::MessageLoop;
47using base::Unretained;
48using chrome_common_net::DnsProbeStatus;
49using content::BrowserThread;
50using content::URLRequestFailedJob;
51using content::URLRequestMockHTTPJob;
52using content::WebContents;
53using google_util::LinkDoctorBaseURL;
54using net::MockDnsClientRule;
55using net::NetworkDelegate;
56using net::URLRequest;
57using net::URLRequestFilter;
58using net::URLRequestJob;
59using net::URLRequestJobFactory;
60using ui_test_utils::NavigateToURL;
61using ui_test_utils::NavigateToURLBlockUntilNavigationsComplete;
62
63namespace chrome_browser_net {
64
65namespace {
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.
70void 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.
77class 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
110FilePath 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.
119class 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
131class 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
175class 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.
221class 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
313class 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
335DnsProbeBrowserTestIOThreadHelper::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
342void 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
370void 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
385void 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
397void 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
404void DnsProbeBrowserTestIOThreadHelper::SetLinkDoctorDelayRequests(
405    bool delay_requests) {
406  CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
407
408  protocol_handler_->SetDelayRequests(delay_requests);
409}
410
411void DnsProbeBrowserTestIOThreadHelper::SetRequestDestructionCallback(
412    const base::Closure& callback) {
413  CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
414
415  protocol_handler_->SetRequestDestructionCallback(callback);
416}
417
418void 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
431class 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
479DnsProbeBrowserTest::DnsProbeBrowserTest()
480    : helper_(new DnsProbeBrowserTestIOThreadHelper()),
481      active_browser_(NULL),
482      monitored_tab_helper_(NULL),
483      awaiting_dns_probe_status_(false) {
484}
485
486DnsProbeBrowserTest::~DnsProbeBrowserTest() {
487  // No tests should have any unconsumed probe statuses.
488  EXPECT_EQ(0, pending_status_count());
489}
490
491void 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
507void 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
517void 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
531void 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
541void 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
549void 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
560void DnsProbeBrowserTest::NavigateToDnsError(int num_navigations) {
561  NavigateToURLBlockUntilNavigationsComplete(
562      active_browser_,
563      URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED),
564      num_navigations);
565}
566
567void DnsProbeBrowserTest::NavigateToOtherError(int num_navigations) {
568  NavigateToURLBlockUntilNavigationsComplete(
569      active_browser_,
570      URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_REFUSED),
571      num_navigations);
572}
573
574void 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
585void 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
594DnsProbeStatus 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.
610std::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.
628bool 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
641void 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.
649IN_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.
658IN_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.
666IN_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.
691IN_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.
729IN_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.
757IN_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.
795IN_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.
824IN_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.
849IN_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.
875IN_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.
894IN_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.
913IN_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.
946IN_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