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.
6 #include "base/memory/scoped_ptr.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/path_service.h"
9 #include "base/threading/thread_restrictions.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/google/google_util.h"
12 #include "chrome/browser/io_thread.h"
13 #include "chrome/browser/net/dns_probe_test_util.h"
14 #include "chrome/browser/net/net_error_tab_helper.h"
15 #include "chrome/browser/net/url_request_mock_util.h"
16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/tabs/tab_strip_model.h"
18 #include "chrome/common/chrome_paths.h"
19 #include "chrome/common/net/net_error_info.h"
20 #include "chrome/test/base/in_process_browser_test.h"
21 #include "chrome/test/base/ui_test_utils.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/test/browser_test_utils.h"
25 #include "content/test/net/url_request_failed_job.h"
26 #include "content/test/net/url_request_mock_http_job.h"
27 #include "net/base/net_errors.h"
28 #include "net/dns/dns_test_util.h"
29 #include "net/url_request/url_request_filter.h"
30 #include "net/url_request/url_request_job.h"
31 #include "net/url_request/url_request_job_factory.h"
38 using base::MessageLoop;
39 using base::Unretained;
40 using chrome_common_net::DnsProbeStatus;
41 using content::BrowserThread;
42 using content::URLRequestFailedJob;
43 using content::URLRequestMockHTTPJob;
44 using content::WebContents;
45 using google_util::LinkDoctorBaseURL;
46 using net::MockDnsClientRule;
47 using net::NetworkDelegate;
48 using net::URLRequest;
49 using net::URLRequestFilter;
50 using net::URLRequestJob;
51 using net::URLRequestJobFactory;
52 using ui_test_utils::NavigateToURL;
53 using ui_test_utils::NavigateToURLBlockUntilNavigationsComplete;
55 namespace chrome_browser_net {
59 // Wraps DnsProbeService and delays callbacks until someone calls
60 // CallDelayedCallbacks. This allows the DnsProbeBrowserTest to enforce a
61 // stricter ordering of events.
62 class DelayingDnsProbeService : public DnsProbeService {
64 DelayingDnsProbeService() {}
66 virtual ~DelayingDnsProbeService() {
67 EXPECT_TRUE(delayed_probes_.empty());
70 virtual void ProbeDns(const ProbeCallback& callback) OVERRIDE {
71 delayed_probes_.push_back(callback);
74 void StartDelayedProbes() {
75 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
77 std::vector<ProbeCallback> probes;
78 probes.swap(delayed_probes_);
80 for (std::vector<ProbeCallback>::const_iterator i = probes.begin();
81 i != probes.end(); ++i) {
82 DnsProbeService::ProbeDns(*i);
86 int delayed_probe_count() const {
87 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
88 return delayed_probes_.size();
92 std::vector<ProbeCallback> delayed_probes_;
95 FilePath GetMockLinkDoctorFilePath() {
97 PathService::Get(chrome::DIR_TEST_DATA, &root_http);
98 return root_http.AppendASCII("mock-link-doctor.html");
101 class BreakableLinkDoctorProtocolHandler
102 : public URLRequestJobFactory::ProtocolHandler {
104 explicit BreakableLinkDoctorProtocolHandler(
105 const FilePath& mock_link_doctor_file_path)
106 : mock_link_doctor_file_path_(mock_link_doctor_file_path),
107 net_error_(net::OK) {}
109 virtual ~BreakableLinkDoctorProtocolHandler() {}
111 virtual URLRequestJob* MaybeCreateJob(
112 URLRequest* request, NetworkDelegate* network_delegate) const OVERRIDE {
113 if (net_error_ != net::OK) {
114 return new URLRequestFailedJob(request, network_delegate, net_error_);
116 return new URLRequestMockHTTPJob(
117 request, network_delegate, mock_link_doctor_file_path_);
121 void set_net_error(int net_error) { net_error_ = net_error; }
124 const FilePath mock_link_doctor_file_path_;
128 class DnsProbeBrowserTestIOThreadHelper {
130 DnsProbeBrowserTestIOThreadHelper();
132 void SetUpOnIOThread(IOThread* io_thread);
133 void CleanUpOnIOThreadAndDeleteHelper();
135 void SetMockDnsClientRules(MockDnsClientRule::Result system_good_result,
136 MockDnsClientRule::Result public_good_result);
137 void SetLinkDoctorNetError(int link_doctor_net_error);
138 void StartDelayedProbes(int expected_delayed_probe_count);
141 IOThread* io_thread_;
142 DnsProbeService* original_dns_probe_service_;
143 DelayingDnsProbeService* delaying_dns_probe_service_;
144 BreakableLinkDoctorProtocolHandler* protocol_handler_;
145 FilePath mock_link_doctor_file_path_;
148 DnsProbeBrowserTestIOThreadHelper::DnsProbeBrowserTestIOThreadHelper()
150 original_dns_probe_service_(NULL),
151 delaying_dns_probe_service_(NULL),
152 protocol_handler_(NULL),
153 mock_link_doctor_file_path_(GetMockLinkDoctorFilePath()) {}
155 void DnsProbeBrowserTestIOThreadHelper::SetUpOnIOThread(IOThread* io_thread) {
156 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
159 CHECK(!original_dns_probe_service_);
160 CHECK(!delaying_dns_probe_service_);
161 CHECK(!protocol_handler_);
163 io_thread_ = io_thread;
165 delaying_dns_probe_service_ = new DelayingDnsProbeService();
167 IOThread::Globals* globals = io_thread_->globals();
168 original_dns_probe_service_ = globals->dns_probe_service.release();
169 globals->dns_probe_service.reset(delaying_dns_probe_service_);
171 URLRequestFailedJob::AddUrlHandler();
173 scoped_ptr<URLRequestJobFactory::ProtocolHandler> protocol_handler(
174 new BreakableLinkDoctorProtocolHandler(mock_link_doctor_file_path_));
176 static_cast<BreakableLinkDoctorProtocolHandler*>(protocol_handler.get());
177 const GURL link_doctor_base_url = LinkDoctorBaseURL();
178 const std::string link_doctor_host = link_doctor_base_url.host();
179 URLRequestFilter::GetInstance()->AddHostnameProtocolHandler(
180 "http", link_doctor_host, protocol_handler.Pass());
183 void DnsProbeBrowserTestIOThreadHelper::CleanUpOnIOThreadAndDeleteHelper() {
184 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
186 URLRequestFilter::GetInstance()->ClearHandlers();
188 IOThread::Globals* globals = io_thread_->globals();
189 scoped_ptr<DnsProbeService> delaying_dns_probe_service(
190 globals->dns_probe_service.release());
191 globals->dns_probe_service.reset(original_dns_probe_service_);
193 CHECK_EQ(delaying_dns_probe_service_, delaying_dns_probe_service.get());
198 void DnsProbeBrowserTestIOThreadHelper::SetMockDnsClientRules(
199 MockDnsClientRule::Result system_result,
200 MockDnsClientRule::Result public_result) {
201 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
203 DnsProbeService* service = io_thread_->globals()->dns_probe_service.get();
204 service->SetSystemClientForTesting(
205 CreateMockDnsClientForProbes(system_result));
206 service->SetPublicClientForTesting(
207 CreateMockDnsClientForProbes(public_result));
210 void DnsProbeBrowserTestIOThreadHelper::SetLinkDoctorNetError(
211 int link_doctor_net_error) {
212 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
214 protocol_handler_->set_net_error(link_doctor_net_error);
217 void DnsProbeBrowserTestIOThreadHelper::StartDelayedProbes(
218 int expected_delayed_probe_count) {
219 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
221 CHECK(delaying_dns_probe_service_);
223 int actual_delayed_probe_count =
224 delaying_dns_probe_service_->delayed_probe_count();
225 EXPECT_EQ(expected_delayed_probe_count, actual_delayed_probe_count);
227 delaying_dns_probe_service_->StartDelayedProbes();
230 class DnsProbeBrowserTest : public InProcessBrowserTest {
232 DnsProbeBrowserTest();
234 virtual void SetUpOnMainThread() OVERRIDE;
235 virtual void CleanUpOnMainThread() OVERRIDE;
238 void SetLinkDoctorBroken(bool broken);
239 void SetMockDnsClientRules(MockDnsClientRule::Result system_result,
240 MockDnsClientRule::Result public_result);
241 void NavigateToDnsError();
242 void NavigateToOtherError();
244 void StartDelayedProbes(int expected_delayed_probe_count);
245 DnsProbeStatus WaitForSentStatus();
246 int pending_status_count() const { return dns_probe_status_queue_.size(); }
249 bool PageContains(const std::string& expected);
252 void OnDnsProbeStatusSent(DnsProbeStatus dns_probe_status);
254 DnsProbeBrowserTestIOThreadHelper* helper_;
256 bool awaiting_dns_probe_status_;
257 // Queue of statuses received but not yet consumed by WaitForSentStatus().
258 std::list<DnsProbeStatus> dns_probe_status_queue_;
261 DnsProbeBrowserTest::DnsProbeBrowserTest()
262 : helper_(new DnsProbeBrowserTestIOThreadHelper()),
263 awaiting_dns_probe_status_(false) {
266 void DnsProbeBrowserTest::SetUpOnMainThread() {
267 NetErrorTabHelper::set_state_for_testing(
268 NetErrorTabHelper::TESTING_FORCE_ENABLED);
270 BrowserThread::PostTask(
271 BrowserThread::IO, FROM_HERE,
272 Bind(&DnsProbeBrowserTestIOThreadHelper::SetUpOnIOThread,
274 g_browser_process->io_thread()));
276 NetErrorTabHelper* tab_helper = NetErrorTabHelper::FromWebContents(
277 browser()->tab_strip_model()->GetActiveWebContents());
278 tab_helper->set_dns_probe_status_snoop_callback_for_testing(Bind(
279 &DnsProbeBrowserTest::OnDnsProbeStatusSent,
283 void DnsProbeBrowserTest::CleanUpOnMainThread() {
284 BrowserThread::PostTask(
285 BrowserThread::IO, FROM_HERE,
286 Bind(&DnsProbeBrowserTestIOThreadHelper::CleanUpOnIOThreadAndDeleteHelper,
287 Unretained(helper_)));
289 NetErrorTabHelper::set_state_for_testing(
290 NetErrorTabHelper::TESTING_DEFAULT);
293 void DnsProbeBrowserTest::SetLinkDoctorBroken(bool broken) {
294 int net_error = broken ? net::ERR_NAME_NOT_RESOLVED : net::OK;
296 BrowserThread::PostTask(
297 BrowserThread::IO, FROM_HERE,
298 Bind(&DnsProbeBrowserTestIOThreadHelper::SetLinkDoctorNetError,
303 // These two functions wait for two navigations because Link Doctor loads two
304 // pages: a blank page, so the user stops seeing the previous page, and then
305 // either the Link Doctor page or a regular error page. We want to wait for
306 // the error page, so we wait for both loads to finish.
308 void DnsProbeBrowserTest::NavigateToDnsError() {
309 NavigateToURLBlockUntilNavigationsComplete(
311 URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED),
315 void DnsProbeBrowserTest::NavigateToOtherError() {
316 NavigateToURLBlockUntilNavigationsComplete(
318 URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_REFUSED),
322 void DnsProbeBrowserTest::SetMockDnsClientRules(
323 MockDnsClientRule::Result system_result,
324 MockDnsClientRule::Result public_result) {
325 BrowserThread::PostTask(
326 BrowserThread::IO, FROM_HERE,
327 Bind(&DnsProbeBrowserTestIOThreadHelper::SetMockDnsClientRules,
333 void DnsProbeBrowserTest::StartDelayedProbes(
334 int expected_delayed_probe_count) {
335 BrowserThread::PostTask(
336 BrowserThread::IO, FROM_HERE,
337 Bind(&DnsProbeBrowserTestIOThreadHelper::StartDelayedProbes,
339 expected_delayed_probe_count));
342 DnsProbeStatus DnsProbeBrowserTest::WaitForSentStatus() {
343 CHECK(!awaiting_dns_probe_status_);
344 while (dns_probe_status_queue_.empty()) {
345 awaiting_dns_probe_status_ = true;
346 MessageLoop::current()->Run();
347 awaiting_dns_probe_status_ = false;
350 CHECK(!dns_probe_status_queue_.empty());
351 DnsProbeStatus status = dns_probe_status_queue_.front();
352 dns_probe_status_queue_.pop_front();
356 // Check title by roundtripping to renderer, to make sure any probe results
357 // sent before this have been applied.
358 std::string DnsProbeBrowserTest::Title() {
361 WebContents* contents =
362 browser()->tab_strip_model()->GetActiveWebContents();
364 bool rv = content::ExecuteScriptAndExtractString(
366 "domAutomationController.send(document.title);",
374 // Check text by roundtripping to renderer, to make sure any probe results
375 // sent before this have been applied.
376 bool DnsProbeBrowserTest::PageContains(const std::string& expected) {
377 std::string text_content;
379 bool rv = content::ExecuteScriptAndExtractString(
380 browser()->tab_strip_model()->GetActiveWebContents(),
381 "domAutomationController.send(document.body.textContent);",
386 return text_content.find(expected) != std::string::npos;
389 void DnsProbeBrowserTest::OnDnsProbeStatusSent(
390 DnsProbeStatus dns_probe_status) {
391 dns_probe_status_queue_.push_back(dns_probe_status);
392 if (awaiting_dns_probe_status_)
393 MessageLoop::current()->Quit();
396 // Make sure probes don't break non-DNS error pages when Link Doctor loads.
397 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, OtherErrorWithWorkingLinkDoctor) {
398 SetLinkDoctorBroken(false);
400 NavigateToOtherError();
401 EXPECT_EQ("Mock Link Doctor", Title());
403 EXPECT_EQ(0, pending_status_count());
406 // Make sure probes don't break non-DNS error pages when Link Doctor doesn't
408 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, OtherErrorWithBrokenLinkDoctor) {
409 SetLinkDoctorBroken(true);
411 NavigateToOtherError();
412 EXPECT_TRUE(PageContains("CONNECTION_REFUSED"));
414 EXPECT_EQ(0, pending_status_count());
417 // Make sure probes don't break DNS error pages when Link doctor loads.
418 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest,
419 NxdomainProbeResultWithWorkingLinkDoctor) {
420 SetLinkDoctorBroken(false);
421 SetMockDnsClientRules(MockDnsClientRule::OK, MockDnsClientRule::OK);
423 NavigateToDnsError();
424 EXPECT_EQ("Mock Link Doctor", Title());
426 EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
427 EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
428 EXPECT_EQ(0, pending_status_count());
429 EXPECT_EQ("Mock Link Doctor", Title());
431 StartDelayedProbes(1);
433 EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN,
434 WaitForSentStatus());
435 EXPECT_EQ(0, pending_status_count());
436 EXPECT_EQ("Mock Link Doctor", Title());
439 // Make sure probes update DNS error page properly when they're supposed to.
440 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest,
441 NoInternetProbeResultWithBrokenLinkDoctor) {
442 SetLinkDoctorBroken(true);
443 SetMockDnsClientRules(MockDnsClientRule::TIMEOUT,
444 MockDnsClientRule::TIMEOUT);
446 NavigateToDnsError();
448 EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
449 EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
451 // PageContains runs the RunLoop, so make sure nothing hairy happens.
452 EXPECT_EQ(0, pending_status_count());
453 EXPECT_TRUE(PageContains("DNS_PROBE_STARTED"));
454 EXPECT_EQ(0, pending_status_count());
456 StartDelayedProbes(1);
458 EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET,
459 WaitForSentStatus());
461 // PageContains runs the RunLoop, so make sure nothing hairy happens.
462 EXPECT_EQ(0, pending_status_count());
463 EXPECT_TRUE(PageContains("DNS_PROBE_FINISHED_NO_INTERNET"));
464 EXPECT_EQ(0, pending_status_count());
467 // Double-check to make sure sync failures don't explode.
468 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, SyncFailureWithBrokenLinkDoctor) {
469 SetLinkDoctorBroken(true);
470 SetMockDnsClientRules(MockDnsClientRule::FAIL, MockDnsClientRule::FAIL);
472 NavigateToDnsError();
474 EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
475 EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
477 // PageContains runs the RunLoop, so make sure nothing hairy happens.
478 EXPECT_EQ(0, pending_status_count());
479 EXPECT_TRUE(PageContains("DNS_PROBE_STARTED"));
480 EXPECT_EQ(0, pending_status_count());
482 StartDelayedProbes(1);
484 EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE,
485 WaitForSentStatus());
487 // PageContains runs the RunLoop, so make sure nothing hairy happens.
488 EXPECT_EQ(0, pending_status_count());
489 EXPECT_TRUE(PageContains("NAME_NOT_RESOLVED"));
490 EXPECT_EQ(0, pending_status_count());
493 // Make sure probes don't run for subframe DNS errors.
494 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, NoProbeInSubframe) {
495 SetLinkDoctorBroken(false);
497 const FilePath::CharType kIframeDnsErrorHtmlName[] =
498 FILE_PATH_LITERAL("iframe_dns_error.html");
502 URLRequestMockHTTPJob::GetMockUrl(FilePath(kIframeDnsErrorHtmlName)));
504 // By the time NavigateToURL returns, the browser will have seen the failed
505 // provisional load. If a probe was started (or considered but not run),
506 // then the NetErrorTabHelper would have sent a NetErrorInfo message. Thus,
507 // if one hasn't been sent by now, the NetErrorTabHelper has not (and won't)
508 // start a probe for this DNS error.
509 EXPECT_EQ(0, pending_status_count());
512 // Make sure browser sends NOT_RUN properly when probes are disabled.
513 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, ProbesDisabled) {
514 NetErrorTabHelper::set_state_for_testing(
515 NetErrorTabHelper::TESTING_FORCE_DISABLED);
517 SetLinkDoctorBroken(true);
518 SetMockDnsClientRules(MockDnsClientRule::TIMEOUT,
519 MockDnsClientRule::TIMEOUT);
521 NavigateToDnsError();
523 EXPECT_EQ(chrome_common_net::DNS_PROBE_NOT_RUN, WaitForSentStatus());
524 EXPECT_EQ(chrome_common_net::DNS_PROBE_NOT_RUN, WaitForSentStatus());
526 // PageContains runs the RunLoop, so make sure nothing hairy happens.
527 EXPECT_EQ(0, pending_status_count());
528 EXPECT_TRUE(PageContains("NAME_NOT_RESOLVED"));
529 EXPECT_EQ(0, pending_status_count());
534 } // namespace chrome_browser_net