- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / net / dns_probe_browsertest.cc
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 "base/bind.h"
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"
32
33 using base::Bind;
34 using base::Callback;
35 using base::Closure;
36 using base::ConstRef;
37 using base::FilePath;
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;
54
55 namespace chrome_browser_net {
56
57 namespace {
58
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 {
63  public:
64   DelayingDnsProbeService() {}
65
66   virtual ~DelayingDnsProbeService() {
67     EXPECT_TRUE(delayed_probes_.empty());
68   }
69
70   virtual void ProbeDns(const ProbeCallback& callback) OVERRIDE {
71     delayed_probes_.push_back(callback);
72   }
73
74   void StartDelayedProbes() {
75     CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
76
77     std::vector<ProbeCallback> probes;
78     probes.swap(delayed_probes_);
79
80     for (std::vector<ProbeCallback>::const_iterator i = probes.begin();
81          i != probes.end(); ++i) {
82       DnsProbeService::ProbeDns(*i);
83     }
84   }
85
86   int delayed_probe_count() const {
87     CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
88     return delayed_probes_.size();
89   }
90
91  private:
92   std::vector<ProbeCallback> delayed_probes_;
93 };
94
95 FilePath GetMockLinkDoctorFilePath() {
96   FilePath root_http;
97   PathService::Get(chrome::DIR_TEST_DATA, &root_http);
98   return root_http.AppendASCII("mock-link-doctor.html");
99 }
100
101 class BreakableLinkDoctorProtocolHandler
102     : public URLRequestJobFactory::ProtocolHandler {
103  public:
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) {}
108
109   virtual ~BreakableLinkDoctorProtocolHandler() {}
110
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_);
115     } else {
116       return new URLRequestMockHTTPJob(
117           request, network_delegate, mock_link_doctor_file_path_);
118     }
119   }
120
121   void set_net_error(int net_error) { net_error_ = net_error; }
122
123  private:
124   const FilePath mock_link_doctor_file_path_;
125   int net_error_;
126 };
127
128 class DnsProbeBrowserTestIOThreadHelper {
129  public:
130   DnsProbeBrowserTestIOThreadHelper();
131
132   void SetUpOnIOThread(IOThread* io_thread);
133   void CleanUpOnIOThreadAndDeleteHelper();
134
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);
139
140  private:
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_;
146 };
147
148 DnsProbeBrowserTestIOThreadHelper::DnsProbeBrowserTestIOThreadHelper()
149     : io_thread_(NULL),
150       original_dns_probe_service_(NULL),
151       delaying_dns_probe_service_(NULL),
152       protocol_handler_(NULL),
153       mock_link_doctor_file_path_(GetMockLinkDoctorFilePath()) {}
154
155 void DnsProbeBrowserTestIOThreadHelper::SetUpOnIOThread(IOThread* io_thread) {
156   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
157   CHECK(io_thread);
158   CHECK(!io_thread_);
159   CHECK(!original_dns_probe_service_);
160   CHECK(!delaying_dns_probe_service_);
161   CHECK(!protocol_handler_);
162
163   io_thread_ = io_thread;
164
165   delaying_dns_probe_service_ = new DelayingDnsProbeService();
166
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_);
170
171   URLRequestFailedJob::AddUrlHandler();
172
173   scoped_ptr<URLRequestJobFactory::ProtocolHandler> protocol_handler(
174       new BreakableLinkDoctorProtocolHandler(mock_link_doctor_file_path_));
175   protocol_handler_ =
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());
181 }
182
183 void DnsProbeBrowserTestIOThreadHelper::CleanUpOnIOThreadAndDeleteHelper() {
184   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
185
186   URLRequestFilter::GetInstance()->ClearHandlers();
187
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_);
192
193   CHECK_EQ(delaying_dns_probe_service_, delaying_dns_probe_service.get());
194
195   delete this;
196 }
197
198 void DnsProbeBrowserTestIOThreadHelper::SetMockDnsClientRules(
199     MockDnsClientRule::Result system_result,
200     MockDnsClientRule::Result public_result) {
201   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
202
203   DnsProbeService* service = io_thread_->globals()->dns_probe_service.get();
204   service->SetSystemClientForTesting(
205       CreateMockDnsClientForProbes(system_result));
206   service->SetPublicClientForTesting(
207       CreateMockDnsClientForProbes(public_result));
208 }
209
210 void DnsProbeBrowserTestIOThreadHelper::SetLinkDoctorNetError(
211     int link_doctor_net_error) {
212   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
213
214   protocol_handler_->set_net_error(link_doctor_net_error);
215 }
216
217 void DnsProbeBrowserTestIOThreadHelper::StartDelayedProbes(
218     int expected_delayed_probe_count) {
219   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
220
221   CHECK(delaying_dns_probe_service_);
222
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);
226
227   delaying_dns_probe_service_->StartDelayedProbes();
228 }
229
230 class DnsProbeBrowserTest : public InProcessBrowserTest {
231  public:
232   DnsProbeBrowserTest();
233
234   virtual void SetUpOnMainThread() OVERRIDE;
235   virtual void CleanUpOnMainThread() OVERRIDE;
236
237  protected:
238   void SetLinkDoctorBroken(bool broken);
239   void SetMockDnsClientRules(MockDnsClientRule::Result system_result,
240                              MockDnsClientRule::Result public_result);
241   void NavigateToDnsError();
242   void NavigateToOtherError();
243
244   void StartDelayedProbes(int expected_delayed_probe_count);
245   DnsProbeStatus WaitForSentStatus();
246   int pending_status_count() const { return dns_probe_status_queue_.size(); }
247
248   std::string Title();
249   bool PageContains(const std::string& expected);
250
251  private:
252   void OnDnsProbeStatusSent(DnsProbeStatus dns_probe_status);
253
254   DnsProbeBrowserTestIOThreadHelper* helper_;
255
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_;
259 };
260
261 DnsProbeBrowserTest::DnsProbeBrowserTest()
262     : helper_(new DnsProbeBrowserTestIOThreadHelper()),
263       awaiting_dns_probe_status_(false) {
264 }
265
266 void DnsProbeBrowserTest::SetUpOnMainThread() {
267   NetErrorTabHelper::set_state_for_testing(
268       NetErrorTabHelper::TESTING_FORCE_ENABLED);
269
270   BrowserThread::PostTask(
271       BrowserThread::IO, FROM_HERE,
272       Bind(&DnsProbeBrowserTestIOThreadHelper::SetUpOnIOThread,
273            Unretained(helper_),
274            g_browser_process->io_thread()));
275
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,
280       Unretained(this)));
281 }
282
283 void DnsProbeBrowserTest::CleanUpOnMainThread() {
284   BrowserThread::PostTask(
285       BrowserThread::IO, FROM_HERE,
286       Bind(&DnsProbeBrowserTestIOThreadHelper::CleanUpOnIOThreadAndDeleteHelper,
287            Unretained(helper_)));
288
289   NetErrorTabHelper::set_state_for_testing(
290       NetErrorTabHelper::TESTING_DEFAULT);
291 }
292
293 void DnsProbeBrowserTest::SetLinkDoctorBroken(bool broken) {
294   int net_error = broken ? net::ERR_NAME_NOT_RESOLVED : net::OK;
295
296   BrowserThread::PostTask(
297       BrowserThread::IO, FROM_HERE,
298       Bind(&DnsProbeBrowserTestIOThreadHelper::SetLinkDoctorNetError,
299            Unretained(helper_),
300            net_error));
301 }
302
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.
307
308 void DnsProbeBrowserTest::NavigateToDnsError() {
309   NavigateToURLBlockUntilNavigationsComplete(
310       browser(),
311       URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED),
312       2);
313 }
314
315 void DnsProbeBrowserTest::NavigateToOtherError() {
316   NavigateToURLBlockUntilNavigationsComplete(
317       browser(),
318       URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_REFUSED),
319       2);
320 }
321
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,
328            Unretained(helper_),
329            system_result,
330            public_result));
331 }
332
333 void DnsProbeBrowserTest::StartDelayedProbes(
334     int expected_delayed_probe_count) {
335   BrowserThread::PostTask(
336       BrowserThread::IO, FROM_HERE,
337       Bind(&DnsProbeBrowserTestIOThreadHelper::StartDelayedProbes,
338            Unretained(helper_),
339            expected_delayed_probe_count));
340 }
341
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;
348   }
349
350   CHECK(!dns_probe_status_queue_.empty());
351   DnsProbeStatus status = dns_probe_status_queue_.front();
352   dns_probe_status_queue_.pop_front();
353   return status;
354 }
355
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() {
359   std::string title;
360
361   WebContents* contents =
362       browser()->tab_strip_model()->GetActiveWebContents();
363
364   bool rv = content::ExecuteScriptAndExtractString(
365       contents,
366       "domAutomationController.send(document.title);",
367       &title);
368   if (!rv)
369     return "";
370
371   return title;
372 }
373
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;
378
379   bool rv = content::ExecuteScriptAndExtractString(
380       browser()->tab_strip_model()->GetActiveWebContents(),
381       "domAutomationController.send(document.body.textContent);",
382       &text_content);
383   if (!rv)
384     return false;
385
386   return text_content.find(expected) != std::string::npos;
387 }
388
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();
394 }
395
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);
399
400   NavigateToOtherError();
401   EXPECT_EQ("Mock Link Doctor", Title());
402
403   EXPECT_EQ(0, pending_status_count());
404 }
405
406 // Make sure probes don't break non-DNS error pages when Link Doctor doesn't
407 // load.
408 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, OtherErrorWithBrokenLinkDoctor) {
409   SetLinkDoctorBroken(true);
410
411   NavigateToOtherError();
412   EXPECT_TRUE(PageContains("CONNECTION_REFUSED"));
413
414   EXPECT_EQ(0, pending_status_count());
415 }
416
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);
422
423   NavigateToDnsError();
424   EXPECT_EQ("Mock Link Doctor", Title());
425
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());
430
431   StartDelayedProbes(1);
432
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());
437 }
438
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);
445
446   NavigateToDnsError();
447
448   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
449   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
450
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());
455
456   StartDelayedProbes(1);
457
458   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET,
459             WaitForSentStatus());
460
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());
465 }
466
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);
471
472   NavigateToDnsError();
473
474   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
475   EXPECT_EQ(chrome_common_net::DNS_PROBE_STARTED, WaitForSentStatus());
476
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());
481
482   StartDelayedProbes(1);
483
484   EXPECT_EQ(chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE,
485             WaitForSentStatus());
486
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());
491 }
492
493 // Make sure probes don't run for subframe DNS errors.
494 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, NoProbeInSubframe) {
495   SetLinkDoctorBroken(false);
496
497   const FilePath::CharType kIframeDnsErrorHtmlName[] =
498       FILE_PATH_LITERAL("iframe_dns_error.html");
499
500   NavigateToURL(
501       browser(),
502       URLRequestMockHTTPJob::GetMockUrl(FilePath(kIframeDnsErrorHtmlName)));
503
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());
510 }
511
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);
516
517   SetLinkDoctorBroken(true);
518   SetMockDnsClientRules(MockDnsClientRule::TIMEOUT,
519                         MockDnsClientRule::TIMEOUT);
520
521   NavigateToDnsError();
522
523   EXPECT_EQ(chrome_common_net::DNS_PROBE_NOT_RUN, WaitForSentStatus());
524   EXPECT_EQ(chrome_common_net::DNS_PROBE_NOT_RUN, WaitForSentStatus());
525
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());
530 }
531
532 }  // namespace
533
534 }  // namespace chrome_browser_net