OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 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.h" | |
8 #include "base/path_service.h" | |
9 #include "chrome/browser/browser_process.h" | |
10 #include "chrome/browser/google/google_util.h" | |
11 #include "chrome/browser/io_thread.h" | |
12 #include "chrome/browser/net/net_error_tab_helper.h" | |
13 #include "chrome/browser/net/url_request_mock_util.h" | |
14 #include "chrome/browser/ui/browser.h" | |
15 #include "chrome/browser/ui/tabs/tab_strip_model.h" | |
16 #include "chrome/common/chrome_paths.h" | |
17 #include "chrome/common/net/net_error_info.h" | |
18 #include "chrome/test/base/in_process_browser_test.h" | |
19 #include "chrome/test/base/ui_test_utils.h" | |
20 #include "content/public/browser/browser_thread.h" | |
21 #include "content/public/browser/web_contents.h" | |
22 #include "content/public/test/browser_test_utils.h" | |
23 #include "content/test/net/url_request_failed_job.h" | |
24 #include "content/test/net/url_request_mock_http_job.h" | |
25 #include "net/base/net_errors.h" | |
26 #include "net/url_request/url_request_filter.h" | |
27 #include "net/url_request/url_request_job.h" | |
28 #include "net/url_request/url_request_job_factory.h" | |
29 | |
30 namespace { | |
31 | |
32 using base::Bind; | |
33 using base::Callback; | |
34 using base::Closure; | |
35 using base::ConstRef; | |
36 using base::FilePath; | |
37 using base::Unretained; | |
38 using chrome_browser_net::DnsProbeService; | |
39 using chrome_browser_net::NetErrorTabHelper; | |
40 using chrome_browser_net::SetUrlRequestMocksEnabled; | |
41 using chrome_common_net::DnsProbeStatus; | |
42 using content::BrowserThread; | |
43 using content::URLRequestFailedJob; | |
44 using content::URLRequestMockHTTPJob; | |
45 using content::WebContents; | |
46 using google_util::LinkDoctorBaseURL; | |
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 // TODO(ttuttle): Dedupe this and net/base/test_completion_callback.*. | |
56 class TestCompletionCallback { | |
57 public: | |
58 // TODO(ttuttle): Weak pointer instead of Unretained? | |
59 TestCompletionCallback() | |
60 : callback_(Bind(&TestCompletionCallback::DidCall, Unretained(this))), | |
61 waiting_(false), | |
62 called_(false) { | |
63 } | |
64 | |
65 void DidCall() { | |
66 called_ = true; | |
67 if (waiting_) | |
68 MessageLoop::current()->Quit(); | |
69 } | |
70 | |
71 void WaitForCall() { | |
72 DCHECK(!waiting_); | |
73 while (!called_) { | |
74 waiting_ = true; | |
75 MessageLoop::current()->Run(); | |
76 waiting_ = false; | |
77 } | |
78 called_ = false; | |
79 } | |
80 | |
81 const Closure& callback() { | |
82 return callback_; | |
83 } | |
84 | |
85 private: | |
86 Closure callback_; | |
87 bool waiting_; | |
88 bool called_; | |
89 }; | |
90 | |
91 class MockDnsProbeService : public DnsProbeService { | |
mmenke
2013/05/28 18:20:13
I'd rather use the real DnsProbeService. Also thi
Deprecated (see juliatuttle)
2013/06/05 21:01:47
Done.
| |
92 public: | |
93 explicit MockDnsProbeService(const Closure& probe_started_callback) | |
94 : DnsProbeService(), | |
95 probe_started_callback_(probe_started_callback) { | |
96 } | |
97 | |
98 virtual ~MockDnsProbeService() { } | |
99 | |
100 virtual void ProbeDns(const CallbackType& callback) OVERRIDE { | |
101 callbacks_.push_back(callback); | |
102 BrowserThread::PostTask( | |
103 BrowserThread::UI, FROM_HERE, probe_started_callback_); | |
104 } | |
105 | |
106 void CallCallbacks(DnsProbeStatus result) { | |
107 std::vector<CallbackType> callbacks = callbacks_; | |
108 callbacks_.clear(); | |
109 | |
110 for (std::vector<CallbackType>::const_iterator i = callbacks.begin(); | |
111 i != callbacks.end(); ++i) { | |
112 i->Run(result); | |
113 } | |
114 } | |
115 | |
116 int callback_count() { | |
117 return callbacks_.size(); | |
118 } | |
119 | |
120 private: | |
121 const Closure probe_started_callback_; | |
122 std::vector<CallbackType> callbacks_; | |
123 }; | |
124 | |
125 class DnsProbeBrowserTestIOThreadHelper { | |
126 public: | |
127 DnsProbeBrowserTestIOThreadHelper() | |
128 : io_thread_(NULL), | |
129 real_service_(NULL), | |
130 mock_service_(NULL), | |
131 link_doctor_net_error_(net::OK) { | |
132 } | |
133 | |
134 void SetUpOnIOThread( | |
135 IOThread* io_thread, | |
136 const Closure& probe_started_callback, | |
137 const Closure& callback); | |
138 void CleanUpOnIOThread(const Closure& callback); | |
139 | |
140 void SimulateProbeResult( | |
141 DnsProbeStatus result, | |
142 const Closure& callback); | |
143 | |
144 int link_doctor_net_error() const { | |
145 return link_doctor_net_error_; | |
146 } | |
147 void set_link_doctor_net_error(int link_doctor_net_error) { | |
148 link_doctor_net_error_ = link_doctor_net_error; | |
149 } | |
150 | |
151 private: | |
152 IOThread* io_thread_; | |
153 DnsProbeService* real_service_; | |
154 MockDnsProbeService* mock_service_; | |
155 int link_doctor_net_error_; | |
156 }; | |
157 | |
158 class DnsProbeBrowserTest : public InProcessBrowserTest { | |
159 public: | |
160 DnsProbeBrowserTest(); | |
161 | |
162 virtual void SetUpOnMainThread() OVERRIDE; | |
163 virtual void CleanUpOnMainThread() OVERRIDE; | |
164 | |
165 protected: | |
mmenke
2013/05/28 18:20:13
optional: Most test fixtures don't use protected,
Deprecated (see juliatuttle)
2013/06/05 21:01:47
The test cases are implemented as subclasses, I th
| |
166 void SetLinkDoctorBroken(bool broken); | |
167 void NavigateToDnsError(); | |
168 void NavigateToOtherError(); | |
169 void WaitForProbe(); | |
mmenke
2013/05/28 18:20:13
I think "WaitForProbeStart" would be clearer.
Deprecated (see juliatuttle)
2013/06/05 21:01:47
Done.
| |
170 void SimulateProbeResult(DnsProbeStatus result); | |
171 | |
172 bool TitleContains(const std::string& expected); | |
173 bool PageContains(const std::string& expected); | |
174 | |
175 int probe_count() const { return probe_started_count_; } | |
176 | |
177 private: | |
178 void SetLinkDoctorNetError(int net_error); | |
179 void OnProbeStarted(); | |
180 | |
181 DnsProbeBrowserTestIOThreadHelper helper_; | |
182 TestCompletionCallback probe_started_callback_; | |
mmenke
2013/05/28 18:20:13
I think having two variables in this file called p
Deprecated (see juliatuttle)
2013/06/05 21:01:47
Obsolete.
| |
183 int probe_started_count_; | |
184 }; | |
185 | |
186 class BrokenLinkDoctorProtocolHandler | |
187 : public URLRequestJobFactory::ProtocolHandler { | |
188 public: | |
189 explicit BrokenLinkDoctorProtocolHandler( | |
190 DnsProbeBrowserTestIOThreadHelper* helper) | |
191 : helper_(helper) { } | |
192 | |
193 virtual URLRequestJob* MaybeCreateJob( | |
194 URLRequest* request, NetworkDelegate* network_delegate) const OVERRIDE { | |
195 int net_error = helper_->link_doctor_net_error(); | |
196 if (net_error != net::OK) { | |
197 return new URLRequestFailedJob(request, network_delegate, net_error); | |
198 } else { | |
199 FilePath file_path = GetMockLinkDoctorFilePath(); | |
200 return new URLRequestMockHTTPJob(request, network_delegate, file_path); | |
201 } | |
202 } | |
203 | |
204 private: | |
205 FilePath GetMockLinkDoctorFilePath() const { | |
206 FilePath root_http; | |
207 PathService::Get(chrome::DIR_TEST_DATA, &root_http); | |
208 return root_http.AppendASCII("mock-link-doctor.html"); | |
209 } | |
210 | |
211 const DnsProbeBrowserTestIOThreadHelper* helper_; | |
212 }; | |
213 | |
214 DnsProbeBrowserTest::DnsProbeBrowserTest() | |
215 : probe_started_count_(0) { | |
216 } | |
217 | |
218 void DnsProbeBrowserTest::SetUpOnMainThread() { | |
219 NetErrorTabHelper::set_state_for_testing( | |
220 NetErrorTabHelper::TESTING_FORCE_ENABLED); | |
221 | |
222 Closure on_probe_started = | |
223 Bind(&DnsProbeBrowserTest::OnProbeStarted, Unretained(this)); | |
224 | |
225 TestCompletionCallback io_thread_done; | |
226 BrowserThread::PostTask( | |
227 BrowserThread::IO, FROM_HERE, | |
228 Bind(&DnsProbeBrowserTestIOThreadHelper::SetUpOnIOThread, | |
229 Unretained(&helper_), | |
230 g_browser_process->io_thread(), | |
231 ConstRef(on_probe_started), | |
232 ConstRef(io_thread_done.callback()))); | |
233 io_thread_done.WaitForCall(); | |
mmenke
2013/05/28 18:20:13
Waiting on this does not seem to be needed. Any t
Deprecated (see juliatuttle)
2013/06/05 21:01:47
Done.
| |
234 } | |
235 | |
236 void DnsProbeBrowserTestIOThreadHelper::SetUpOnIOThread( | |
mmenke
2013/05/28 18:20:13
DnsProbeBrowserTestIOThreadHelper's functions shou
Deprecated (see juliatuttle)
2013/06/05 21:01:47
My goal was to arrange them in the order of what a
| |
237 IOThread* io_thread, | |
238 const Closure& probe_started_callback, | |
239 const Closure& callback) { | |
240 DCHECK(io_thread); | |
241 DCHECK(!io_thread_ && !real_service_ && !mock_service_); | |
242 | |
243 io_thread_ = io_thread; | |
244 | |
245 mock_service_ = new MockDnsProbeService(probe_started_callback); | |
246 | |
247 real_service_ = io_thread_->globals()->dns_probe_service.release(); | |
248 io_thread_->globals()->dns_probe_service.reset(mock_service_); | |
249 | |
250 // SetUrlRequestMocksEnabled clears the filter list and then adds filters | |
251 // for several things, including the mock link doctor. So, we call it | |
252 // first, then remove the handler it's added for the mock link doctor and | |
253 // add our own. | |
254 SetUrlRequestMocksEnabled(true); | |
255 | |
256 URLRequestFilter* filter = URLRequestFilter::GetInstance(); | |
257 const GURL link_doctor_base_url = LinkDoctorBaseURL(); | |
258 const std::string host = link_doctor_base_url.host(); | |
259 scoped_ptr<URLRequestJobFactory::ProtocolHandler> handler( | |
260 new BrokenLinkDoctorProtocolHandler(this)); | |
261 filter->RemoveHostnameHandler("http", host); | |
262 filter->AddHostnameProtocolHandler("http", host, handler.Pass()); | |
263 | |
264 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); | |
265 } | |
266 | |
267 void DnsProbeBrowserTest::CleanUpOnMainThread() { | |
268 NetErrorTabHelper::set_state_for_testing( | |
269 NetErrorTabHelper::TESTING_DEFAULT); | |
270 | |
271 TestCompletionCallback io_thread_done; | |
272 BrowserThread::PostTask( | |
273 BrowserThread::IO, FROM_HERE, | |
274 Bind(&DnsProbeBrowserTestIOThreadHelper::CleanUpOnIOThread, | |
275 Unretained(&helper_), | |
276 ConstRef(io_thread_done.callback()))); | |
277 io_thread_done.WaitForCall(); | |
mmenke
2013/05/28 18:20:13
Rather than waiting on a callback, how about havin
Deprecated (see juliatuttle)
2013/06/05 21:01:47
Done.
| |
278 } | |
279 | |
280 void DnsProbeBrowserTestIOThreadHelper::CleanUpOnIOThread( | |
281 const Closure& callback) { | |
282 DCHECK(io_thread_ && real_service_ && mock_service_); | |
283 | |
284 SetUrlRequestMocksEnabled(false); | |
285 | |
286 DnsProbeService* mock_service; | |
287 mock_service = io_thread_->globals()->dns_probe_service.release(); | |
288 DCHECK_EQ(mock_service_, mock_service); | |
289 io_thread_->globals()->dns_probe_service.reset(real_service_); | |
290 real_service_ = NULL; | |
291 | |
292 delete mock_service_; | |
293 mock_service_ = NULL; | |
294 | |
295 io_thread_ = NULL; | |
296 | |
297 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); | |
298 } | |
299 | |
300 void DnsProbeBrowserTest::SetLinkDoctorBroken(bool broken) { | |
301 SetLinkDoctorNetError(broken ? net::ERR_NAME_NOT_RESOLVED : net::OK); | |
302 } | |
303 | |
304 // These two functions wait for two navigations because Link Doctor loads two | |
305 // pages: a blank page, so the user stops seeing the previous page, and then | |
306 // either the Link Doctor page or a regular error page. We want to wait for | |
307 // the error page, so we wait for both loads to finish. | |
308 | |
309 void DnsProbeBrowserTest::NavigateToDnsError() { | |
310 NavigateToURLBlockUntilNavigationsComplete( | |
311 browser(), | |
312 URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED), | |
313 2); | |
314 } | |
315 | |
316 void DnsProbeBrowserTest::NavigateToOtherError() { | |
317 NavigateToURLBlockUntilNavigationsComplete( | |
318 browser(), | |
319 URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_REFUSED), | |
320 2); | |
321 } | |
322 | |
323 void DnsProbeBrowserTest::WaitForProbe() { | |
324 probe_started_callback_.WaitForCall(); | |
325 } | |
326 | |
327 void DnsProbeBrowserTest::SimulateProbeResult(DnsProbeStatus result) { | |
328 TestCompletionCallback io_thread_done; | |
329 BrowserThread::PostTask( | |
330 BrowserThread::IO, FROM_HERE, | |
331 Bind(&DnsProbeBrowserTestIOThreadHelper::SimulateProbeResult, | |
332 Unretained(&helper_), | |
333 result, | |
334 ConstRef(io_thread_done.callback()))); | |
335 io_thread_done.WaitForCall(); | |
336 } | |
337 | |
338 void DnsProbeBrowserTestIOThreadHelper::SimulateProbeResult( | |
339 DnsProbeStatus result, | |
340 const Closure& callback) { | |
341 DCHECK(mock_service_); | |
342 mock_service_->CallCallbacks(result); | |
343 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); | |
344 } | |
345 | |
346 bool DnsProbeBrowserTest::TitleContains(const std::string& expected) { | |
mmenke
2013/05/28 18:20:13
Is there a reason not to use TitleWatcher?
Deprecated (see juliatuttle)
2013/06/05 21:01:47
I don't want to wait for it; I expect it to have t
| |
347 std::string title; | |
348 | |
349 WebContents* contents = | |
350 browser()->tab_strip_model()->GetActiveWebContents(); | |
351 | |
352 bool rv = content::ExecuteScriptAndExtractString( | |
353 contents, | |
354 "domAutomationController.send(document.title);", | |
355 &title); | |
356 if (!rv) | |
357 return false; | |
358 | |
359 return title.find(expected) != std::string::npos; | |
360 } | |
361 | |
362 bool DnsProbeBrowserTest::PageContains(const std::string& expected) { | |
363 std::string textContent; | |
mmenke
2013/05/28 18:20:13
text_content.
Deprecated (see juliatuttle)
2013/06/05 21:01:47
Done.
| |
364 | |
365 WebContents* contents = | |
366 browser()->tab_strip_model()->GetActiveWebContents(); | |
mmenke
2013/05/28 18:20:13
optional: Suggest you just inline this, to reduce
Deprecated (see juliatuttle)
2013/06/05 21:01:47
Done.
| |
367 | |
368 bool rv = content::ExecuteScriptAndExtractString( | |
369 contents, | |
370 "domAutomationController.send(document.body.textContent);", | |
371 &textContent); | |
372 if (!rv) | |
373 return false; | |
374 | |
375 return textContent.find(expected) != std::string::npos; | |
376 } | |
377 | |
378 void DnsProbeBrowserTest::SetLinkDoctorNetError(int net_error) { | |
mmenke
2013/05/28 18:20:13
Instead of this, can we just change the link docto
Deprecated (see juliatuttle)
2013/06/05 21:01:47
We can't change it once the tab is created. That'
| |
379 BrowserThread::PostTask( | |
380 BrowserThread::IO, FROM_HERE, | |
381 Bind(&DnsProbeBrowserTestIOThreadHelper::set_link_doctor_net_error, | |
382 Unretained(&helper_), | |
383 net_error)); | |
384 } | |
385 | |
386 void DnsProbeBrowserTest::OnProbeStarted() { | |
387 probe_started_count_++; | |
388 probe_started_callback_.callback().Run(); | |
389 } | |
390 | |
391 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, OtherErrorWithLinkDoctor) { | |
392 SetLinkDoctorBroken(false); | |
393 | |
394 NavigateToOtherError(); | |
395 EXPECT_EQ(0, probe_count()); | |
396 EXPECT_TRUE(TitleContains("Mock Link Doctor")); | |
397 } | |
398 | |
399 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, OtherErrorWithoutLinkDoctor) { | |
400 SetLinkDoctorBroken(true); | |
401 | |
402 NavigateToOtherError(); | |
403 EXPECT_EQ(0, probe_count()); | |
404 EXPECT_TRUE(PageContains("CONNECTION_REFUSED")); | |
405 } | |
406 | |
407 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, NxdomainWithLinkDoctor) { | |
408 SetLinkDoctorBroken(false); | |
409 | |
410 NavigateToDnsError(); | |
411 WaitForProbe(); | |
412 SimulateProbeResult(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN); | |
413 EXPECT_TRUE(TitleContains("Mock Link Doctor")); | |
414 } | |
415 | |
416 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, NoInternetWithoutLinkDoctor) { | |
417 SetLinkDoctorBroken(true); | |
418 | |
419 NavigateToDnsError(); | |
420 WaitForProbe(); | |
421 EXPECT_TRUE(PageContains("DNS_PROBE_STARTED")); | |
422 | |
423 SimulateProbeResult(chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET); | |
424 EXPECT_TRUE(PageContains("DNS_PROBE_FINISHED_NO_INTERNET")); | |
425 } | |
426 | |
427 static const FilePath::CharType kIframeDnsErrorHtmlName[] = | |
428 FILE_PATH_LITERAL("iframe_dns_error.html"); | |
429 | |
430 IN_PROC_BROWSER_TEST_F(DnsProbeBrowserTest, NoProbeInSubframe) { | |
431 SetLinkDoctorBroken(false); | |
432 | |
433 NavigateToURL( | |
434 browser(), | |
435 URLRequestMockHTTPJob::GetMockUrl(FilePath(kIframeDnsErrorHtmlName))); | |
436 EXPECT_EQ(0, probe_count()); | |
437 } | |
438 | |
439 } // namespace | |
OLD | NEW |