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
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 net::URLRequestFailedJob;
51using net::URLRequestMockHTTPJob;
52using content::WebContents;
53using google_util::LinkDoctorBaseURL;
54using net::MockDnsClientRule;
55using net::NetworkDelegate;
56using net::URLRequest;
57using net::URLRequestFilter;
58using net::URLRequestInterceptor;
59using net::URLRequestJob;
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.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.
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(
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.
226class 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
317class 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
339DnsProbeBrowserTestIOThreadHelper::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
346void 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
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::SetCorrectionServiceNetError(
398    int net_error) {
399  CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
400
401  interceptor_->set_net_error(net_error);
402}
403
404void DnsProbeBrowserTestIOThreadHelper::SetCorrectionServiceDelayRequests(
405    bool delay_requests) {
406  CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
407
408  interceptor_->SetDelayRequests(delay_requests);
409}
410
411void DnsProbeBrowserTestIOThreadHelper::SetRequestDestructionCallback(
412    const base::Closure& callback) {
413  CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
414
415  interceptor_->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 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
489DnsProbeBrowserTest::DnsProbeBrowserTest()
490    : helper_(new DnsProbeBrowserTestIOThreadHelper()),
491      active_browser_(NULL),
492      monitored_tab_helper_(NULL),
493      awaiting_dns_probe_status_(false) {
494}
495
496DnsProbeBrowserTest::~DnsProbeBrowserTest() {
497  // No tests should have any unconsumed probe statuses.
498  EXPECT_EQ(0, pending_status_count());
499}
500
501void 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
517void 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
527void 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
541void 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
551void 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
561void 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
572void DnsProbeBrowserTest::NavigateToDnsError(int num_navigations) {
573  NavigateToURLBlockUntilNavigationsComplete(
574      active_browser_,
575      URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED),
576      num_navigations);
577}
578
579void DnsProbeBrowserTest::NavigateToOtherError(int num_navigations) {
580  NavigateToURLBlockUntilNavigationsComplete(
581      active_browser_,
582      URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_REFUSED),
583      num_navigations);
584}
585
586void 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
597void 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
606DnsProbeStatus 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.
622std::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.
640bool 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
653void 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
660void 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
667void 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.
675IN_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.
684IN_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.
692IN_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.
717IN_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.
755IN_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.
783IN_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.
821IN_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.
850IN_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.
874IN_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.
900IN_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.
919IN_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.
938IN_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.
971IN_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