OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "net/proxy/dhcp_proxy_script_fetcher_win.h" | |
6 | |
7 #include <vector> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/bind_helpers.h" | |
11 #include "base/message_loop/message_loop.h" | |
12 #include "base/rand_util.h" | |
13 #include "base/test/test_timeouts.h" | |
14 #include "base/threading/platform_thread.h" | |
15 #include "base/timer/elapsed_timer.h" | |
16 #include "net/base/completion_callback.h" | |
17 #include "net/proxy/dhcp_proxy_script_adapter_fetcher_win.h" | |
18 #include "net/url_request/url_request_test_util.h" | |
19 #include "testing/gtest/include/gtest/gtest.h" | |
20 | |
21 namespace net { | |
22 | |
23 namespace { | |
24 | |
25 TEST(DhcpProxyScriptFetcherWin, AdapterNamesAndPacURLFromDhcp) { | |
26 // This tests our core Win32 implementation without any of the wrappers | |
27 // we layer on top to achieve asynchronous and parallel operations. | |
28 // | |
29 // We don't make assumptions about the environment this unit test is | |
30 // running in, so it just exercises the code to make sure there | |
31 // is no crash and no error returned, but does not assert on the number | |
32 // of interfaces or the information returned via DHCP. | |
33 std::set<std::string> adapter_names; | |
34 DhcpProxyScriptFetcherWin::GetCandidateAdapterNames(&adapter_names); | |
35 for (std::set<std::string>::const_iterator it = adapter_names.begin(); | |
36 it != adapter_names.end(); | |
37 ++it) { | |
38 const std::string& adapter_name = *it; | |
39 DhcpProxyScriptAdapterFetcher::GetPacURLFromDhcp(adapter_name); | |
40 } | |
41 } | |
42 | |
43 // Helper for RealFetch* tests below. | |
44 class RealFetchTester { | |
45 public: | |
46 RealFetchTester() | |
47 : context_(new TestURLRequestContext), | |
48 fetcher_(new DhcpProxyScriptFetcherWin(context_.get())), | |
49 finished_(false), | |
50 on_completion_is_error_(false) { | |
51 // Make sure the test ends. | |
52 timeout_.Start(FROM_HERE, | |
53 base::TimeDelta::FromSeconds(5), this, &RealFetchTester::OnTimeout); | |
54 } | |
55 | |
56 void RunTest() { | |
57 int result = fetcher_->Fetch( | |
58 &pac_text_, | |
59 base::Bind(&RealFetchTester::OnCompletion, base::Unretained(this))); | |
60 if (result != ERR_IO_PENDING) | |
61 finished_ = true; | |
62 } | |
63 | |
64 void RunTestWithCancel() { | |
65 RunTest(); | |
66 fetcher_->Cancel(); | |
67 } | |
68 | |
69 void RunTestWithDeferredCancel() { | |
70 // Put the cancellation into the queue before even running the | |
71 // test to avoid the chance of one of the adapter fetcher worker | |
72 // threads completing before cancellation. See http://crbug.com/86756. | |
73 cancel_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(0), | |
74 this, &RealFetchTester::OnCancelTimer); | |
75 RunTest(); | |
76 } | |
77 | |
78 void OnCompletion(int result) { | |
79 if (on_completion_is_error_) { | |
80 FAIL() << "Received completion for test in which this is error."; | |
81 } | |
82 finished_ = true; | |
83 } | |
84 | |
85 void OnTimeout() { | |
86 OnCompletion(0); | |
87 } | |
88 | |
89 void OnCancelTimer() { | |
90 fetcher_->Cancel(); | |
91 finished_ = true; | |
92 } | |
93 | |
94 void WaitUntilDone() { | |
95 while (!finished_) { | |
96 base::MessageLoop::current()->RunUntilIdle(); | |
97 } | |
98 base::MessageLoop::current()->RunUntilIdle(); | |
99 } | |
100 | |
101 // Attempts to give worker threads time to finish. This is currently | |
102 // very simplistic as completion (via completion callback or cancellation) | |
103 // immediately "detaches" any worker threads, so the best we can do is give | |
104 // them a little time. If we start running into Valgrind leaks, we can | |
105 // do something a bit more clever to track worker threads even when the | |
106 // DhcpProxyScriptFetcherWin state machine has finished. | |
107 void FinishTestAllowCleanup() { | |
108 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(30)); | |
109 } | |
110 | |
111 scoped_ptr<URLRequestContext> context_; | |
112 scoped_ptr<DhcpProxyScriptFetcherWin> fetcher_; | |
113 bool finished_; | |
114 base::string16 pac_text_; | |
115 base::OneShotTimer<RealFetchTester> timeout_; | |
116 base::OneShotTimer<RealFetchTester> cancel_timer_; | |
117 bool on_completion_is_error_; | |
118 }; | |
119 | |
120 TEST(DhcpProxyScriptFetcherWin, RealFetch) { | |
121 // This tests a call to Fetch() with no stubbing out of dependencies. | |
122 // | |
123 // We don't make assumptions about the environment this unit test is | |
124 // running in, so it just exercises the code to make sure there | |
125 // is no crash and no unexpected error returned, but does not assert on | |
126 // results beyond that. | |
127 RealFetchTester fetcher; | |
128 fetcher.RunTest(); | |
129 | |
130 fetcher.WaitUntilDone(); | |
131 fetcher.fetcher_->GetPacURL().possibly_invalid_spec(); | |
132 | |
133 fetcher.FinishTestAllowCleanup(); | |
134 } | |
135 | |
136 TEST(DhcpProxyScriptFetcherWin, RealFetchWithCancel) { | |
137 // Does a Fetch() with an immediate cancel. As before, just | |
138 // exercises the code without stubbing out dependencies. | |
139 RealFetchTester fetcher; | |
140 fetcher.RunTestWithCancel(); | |
141 base::MessageLoop::current()->RunUntilIdle(); | |
142 | |
143 // Attempt to avoid Valgrind leak reports in case worker thread is | |
144 // still running. | |
145 fetcher.FinishTestAllowCleanup(); | |
146 } | |
147 | |
148 // For RealFetchWithDeferredCancel, below. | |
149 class DelayingDhcpProxyScriptAdapterFetcher | |
150 : public DhcpProxyScriptAdapterFetcher { | |
151 public: | |
152 DelayingDhcpProxyScriptAdapterFetcher( | |
153 URLRequestContext* url_request_context, | |
154 scoped_refptr<base::TaskRunner> task_runner) | |
155 : DhcpProxyScriptAdapterFetcher(url_request_context, task_runner) { | |
156 } | |
157 | |
158 class DelayingDhcpQuery : public DhcpQuery { | |
159 public: | |
160 explicit DelayingDhcpQuery() | |
161 : DhcpQuery() { | |
162 } | |
163 | |
164 std::string ImplGetPacURLFromDhcp( | |
165 const std::string& adapter_name) override { | |
166 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20)); | |
167 return DhcpQuery::ImplGetPacURLFromDhcp(adapter_name); | |
168 } | |
169 }; | |
170 | |
171 DhcpQuery* ImplCreateDhcpQuery() override { | |
172 return new DelayingDhcpQuery(); | |
173 } | |
174 }; | |
175 | |
176 // For RealFetchWithDeferredCancel, below. | |
177 class DelayingDhcpProxyScriptFetcherWin | |
178 : public DhcpProxyScriptFetcherWin { | |
179 public: | |
180 explicit DelayingDhcpProxyScriptFetcherWin( | |
181 URLRequestContext* context) | |
182 : DhcpProxyScriptFetcherWin(context) { | |
183 } | |
184 | |
185 DhcpProxyScriptAdapterFetcher* ImplCreateAdapterFetcher() override { | |
186 return new DelayingDhcpProxyScriptAdapterFetcher(url_request_context(), | |
187 GetTaskRunner()); | |
188 } | |
189 }; | |
190 | |
191 TEST(DhcpProxyScriptFetcherWin, RealFetchWithDeferredCancel) { | |
192 // Does a Fetch() with a slightly delayed cancel. As before, just | |
193 // exercises the code without stubbing out dependencies, but | |
194 // introduces a guaranteed 20 ms delay on the worker threads so that | |
195 // the cancel is called before they complete. | |
196 RealFetchTester fetcher; | |
197 fetcher.fetcher_.reset( | |
198 new DelayingDhcpProxyScriptFetcherWin(fetcher.context_.get())); | |
199 fetcher.on_completion_is_error_ = true; | |
200 fetcher.RunTestWithDeferredCancel(); | |
201 fetcher.WaitUntilDone(); | |
202 } | |
203 | |
204 // The remaining tests are to exercise our state machine in various | |
205 // situations, with actual network access fully stubbed out. | |
206 | |
207 class DummyDhcpProxyScriptAdapterFetcher | |
208 : public DhcpProxyScriptAdapterFetcher { | |
209 public: | |
210 DummyDhcpProxyScriptAdapterFetcher(URLRequestContext* context, | |
211 scoped_refptr<base::TaskRunner> runner) | |
212 : DhcpProxyScriptAdapterFetcher(context, runner), | |
213 did_finish_(false), | |
214 result_(OK), | |
215 pac_script_(L"bingo"), | |
216 fetch_delay_ms_(1) { | |
217 } | |
218 | |
219 void Fetch(const std::string& adapter_name, | |
220 const CompletionCallback& callback) override { | |
221 callback_ = callback; | |
222 timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(fetch_delay_ms_), | |
223 this, &DummyDhcpProxyScriptAdapterFetcher::OnTimer); | |
224 } | |
225 | |
226 void Cancel() override { | |
227 timer_.Stop(); | |
228 } | |
229 | |
230 bool DidFinish() const override { | |
231 return did_finish_; | |
232 } | |
233 | |
234 int GetResult() const override { | |
235 return result_; | |
236 } | |
237 | |
238 base::string16 GetPacScript() const override { | |
239 return pac_script_; | |
240 } | |
241 | |
242 void OnTimer() { | |
243 callback_.Run(result_); | |
244 } | |
245 | |
246 void Configure(bool did_finish, | |
247 int result, | |
248 base::string16 pac_script, | |
249 int fetch_delay_ms) { | |
250 did_finish_ = did_finish; | |
251 result_ = result; | |
252 pac_script_ = pac_script; | |
253 fetch_delay_ms_ = fetch_delay_ms; | |
254 } | |
255 | |
256 private: | |
257 bool did_finish_; | |
258 int result_; | |
259 base::string16 pac_script_; | |
260 int fetch_delay_ms_; | |
261 CompletionCallback callback_; | |
262 base::OneShotTimer<DummyDhcpProxyScriptAdapterFetcher> timer_; | |
263 }; | |
264 | |
265 class MockDhcpProxyScriptFetcherWin : public DhcpProxyScriptFetcherWin { | |
266 public: | |
267 class MockAdapterQuery : public AdapterQuery { | |
268 public: | |
269 MockAdapterQuery() { | |
270 } | |
271 | |
272 virtual ~MockAdapterQuery() { | |
273 } | |
274 | |
275 virtual bool ImplGetCandidateAdapterNames( | |
276 std::set<std::string>* adapter_names) override { | |
277 adapter_names->insert( | |
278 mock_adapter_names_.begin(), mock_adapter_names_.end()); | |
279 return true; | |
280 } | |
281 | |
282 std::vector<std::string> mock_adapter_names_; | |
283 }; | |
284 | |
285 MockDhcpProxyScriptFetcherWin(URLRequestContext* context) | |
286 : DhcpProxyScriptFetcherWin(context), | |
287 num_fetchers_created_(0), | |
288 worker_finished_event_(true, false) { | |
289 ResetTestState(); | |
290 } | |
291 | |
292 virtual ~MockDhcpProxyScriptFetcherWin() { | |
293 ResetTestState(); | |
294 } | |
295 | |
296 using DhcpProxyScriptFetcherWin::GetTaskRunner; | |
297 | |
298 // Adds a fetcher object to the queue of fetchers used by | |
299 // |ImplCreateAdapterFetcher()|, and its name to the list of adapters | |
300 // returned by ImplGetCandidateAdapterNames. | |
301 void PushBackAdapter(const std::string& adapter_name, | |
302 DhcpProxyScriptAdapterFetcher* fetcher) { | |
303 adapter_query_->mock_adapter_names_.push_back(adapter_name); | |
304 adapter_fetchers_.push_back(fetcher); | |
305 } | |
306 | |
307 void ConfigureAndPushBackAdapter(const std::string& adapter_name, | |
308 bool did_finish, | |
309 int result, | |
310 base::string16 pac_script, | |
311 base::TimeDelta fetch_delay) { | |
312 scoped_ptr<DummyDhcpProxyScriptAdapterFetcher> adapter_fetcher( | |
313 new DummyDhcpProxyScriptAdapterFetcher(url_request_context(), | |
314 GetTaskRunner())); | |
315 adapter_fetcher->Configure( | |
316 did_finish, result, pac_script, fetch_delay.InMilliseconds()); | |
317 PushBackAdapter(adapter_name, adapter_fetcher.release()); | |
318 } | |
319 | |
320 DhcpProxyScriptAdapterFetcher* ImplCreateAdapterFetcher() override { | |
321 ++num_fetchers_created_; | |
322 return adapter_fetchers_[next_adapter_fetcher_index_++]; | |
323 } | |
324 | |
325 virtual AdapterQuery* ImplCreateAdapterQuery() override { | |
326 DCHECK(adapter_query_.get()); | |
327 return adapter_query_.get(); | |
328 } | |
329 | |
330 base::TimeDelta ImplGetMaxWait() override { | |
331 return max_wait_; | |
332 } | |
333 | |
334 void ImplOnGetCandidateAdapterNamesDone() override { | |
335 worker_finished_event_.Signal(); | |
336 } | |
337 | |
338 void ResetTestState() { | |
339 // Delete any adapter fetcher objects we didn't hand out. | |
340 std::vector<DhcpProxyScriptAdapterFetcher*>::const_iterator it | |
341 = adapter_fetchers_.begin(); | |
342 for (; it != adapter_fetchers_.end(); ++it) { | |
343 if (num_fetchers_created_-- <= 0) { | |
344 delete (*it); | |
345 } | |
346 } | |
347 | |
348 next_adapter_fetcher_index_ = 0; | |
349 num_fetchers_created_ = 0; | |
350 adapter_fetchers_.clear(); | |
351 adapter_query_ = new MockAdapterQuery(); | |
352 max_wait_ = TestTimeouts::tiny_timeout(); | |
353 } | |
354 | |
355 bool HasPendingFetchers() { | |
356 return num_pending_fetchers() > 0; | |
357 } | |
358 | |
359 int next_adapter_fetcher_index_; | |
360 | |
361 // Ownership gets transferred to the implementation class via | |
362 // ImplCreateAdapterFetcher, but any objects not handed out are | |
363 // deleted on destruction. | |
364 std::vector<DhcpProxyScriptAdapterFetcher*> adapter_fetchers_; | |
365 | |
366 scoped_refptr<MockAdapterQuery> adapter_query_; | |
367 | |
368 base::TimeDelta max_wait_; | |
369 int num_fetchers_created_; | |
370 base::WaitableEvent worker_finished_event_; | |
371 }; | |
372 | |
373 class FetcherClient { | |
374 public: | |
375 FetcherClient() | |
376 : context_(new TestURLRequestContext), | |
377 fetcher_(context_.get()), | |
378 finished_(false), | |
379 result_(ERR_UNEXPECTED) { | |
380 } | |
381 | |
382 void RunTest() { | |
383 int result = fetcher_.Fetch( | |
384 &pac_text_, | |
385 base::Bind(&FetcherClient::OnCompletion, base::Unretained(this))); | |
386 ASSERT_EQ(ERR_IO_PENDING, result); | |
387 } | |
388 | |
389 void RunMessageLoopUntilComplete() { | |
390 while (!finished_) { | |
391 base::MessageLoop::current()->RunUntilIdle(); | |
392 } | |
393 base::MessageLoop::current()->RunUntilIdle(); | |
394 } | |
395 | |
396 void RunMessageLoopUntilWorkerDone() { | |
397 DCHECK(fetcher_.adapter_query_.get()); | |
398 while (!fetcher_.worker_finished_event_.TimedWait( | |
399 base::TimeDelta::FromMilliseconds(10))) { | |
400 base::MessageLoop::current()->RunUntilIdle(); | |
401 } | |
402 } | |
403 | |
404 void OnCompletion(int result) { | |
405 finished_ = true; | |
406 result_ = result; | |
407 } | |
408 | |
409 void ResetTestState() { | |
410 finished_ = false; | |
411 result_ = ERR_UNEXPECTED; | |
412 pac_text_ = L""; | |
413 fetcher_.ResetTestState(); | |
414 } | |
415 | |
416 scoped_refptr<base::TaskRunner> GetTaskRunner() { | |
417 return fetcher_.GetTaskRunner(); | |
418 } | |
419 | |
420 scoped_ptr<URLRequestContext> context_; | |
421 MockDhcpProxyScriptFetcherWin fetcher_; | |
422 bool finished_; | |
423 int result_; | |
424 base::string16 pac_text_; | |
425 }; | |
426 | |
427 // We separate out each test's logic so that we can easily implement | |
428 // the ReuseFetcher test at the bottom. | |
429 void TestNormalCaseURLConfiguredOneAdapter(FetcherClient* client) { | |
430 TestURLRequestContext context; | |
431 scoped_ptr<DummyDhcpProxyScriptAdapterFetcher> adapter_fetcher( | |
432 new DummyDhcpProxyScriptAdapterFetcher(&context, | |
433 client->GetTaskRunner())); | |
434 adapter_fetcher->Configure(true, OK, L"bingo", 1); | |
435 client->fetcher_.PushBackAdapter("a", adapter_fetcher.release()); | |
436 client->RunTest(); | |
437 client->RunMessageLoopUntilComplete(); | |
438 ASSERT_EQ(OK, client->result_); | |
439 ASSERT_EQ(L"bingo", client->pac_text_); | |
440 } | |
441 | |
442 TEST(DhcpProxyScriptFetcherWin, NormalCaseURLConfiguredOneAdapter) { | |
443 FetcherClient client; | |
444 TestNormalCaseURLConfiguredOneAdapter(&client); | |
445 } | |
446 | |
447 void TestNormalCaseURLConfiguredMultipleAdapters(FetcherClient* client) { | |
448 client->fetcher_.ConfigureAndPushBackAdapter( | |
449 "most_preferred", true, ERR_PAC_NOT_IN_DHCP, L"", | |
450 base::TimeDelta::FromMilliseconds(1)); | |
451 client->fetcher_.ConfigureAndPushBackAdapter( | |
452 "second", true, OK, L"bingo", base::TimeDelta::FromMilliseconds(50)); | |
453 client->fetcher_.ConfigureAndPushBackAdapter( | |
454 "third", true, OK, L"rocko", base::TimeDelta::FromMilliseconds(1)); | |
455 client->RunTest(); | |
456 client->RunMessageLoopUntilComplete(); | |
457 ASSERT_EQ(OK, client->result_); | |
458 ASSERT_EQ(L"bingo", client->pac_text_); | |
459 } | |
460 | |
461 TEST(DhcpProxyScriptFetcherWin, NormalCaseURLConfiguredMultipleAdapters) { | |
462 FetcherClient client; | |
463 TestNormalCaseURLConfiguredMultipleAdapters(&client); | |
464 } | |
465 | |
466 void TestNormalCaseURLConfiguredMultipleAdaptersWithTimeout( | |
467 FetcherClient* client) { | |
468 client->fetcher_.ConfigureAndPushBackAdapter( | |
469 "most_preferred", true, ERR_PAC_NOT_IN_DHCP, L"", | |
470 base::TimeDelta::FromMilliseconds(1)); | |
471 // This will time out. | |
472 client->fetcher_.ConfigureAndPushBackAdapter( | |
473 "second", false, ERR_IO_PENDING, L"bingo", | |
474 TestTimeouts::action_timeout()); | |
475 client->fetcher_.ConfigureAndPushBackAdapter( | |
476 "third", true, OK, L"rocko", base::TimeDelta::FromMilliseconds(1)); | |
477 client->RunTest(); | |
478 client->RunMessageLoopUntilComplete(); | |
479 ASSERT_EQ(OK, client->result_); | |
480 ASSERT_EQ(L"rocko", client->pac_text_); | |
481 } | |
482 | |
483 TEST(DhcpProxyScriptFetcherWin, | |
484 NormalCaseURLConfiguredMultipleAdaptersWithTimeout) { | |
485 FetcherClient client; | |
486 TestNormalCaseURLConfiguredMultipleAdaptersWithTimeout(&client); | |
487 } | |
488 | |
489 void TestFailureCaseURLConfiguredMultipleAdaptersWithTimeout( | |
490 FetcherClient* client) { | |
491 client->fetcher_.ConfigureAndPushBackAdapter( | |
492 "most_preferred", true, ERR_PAC_NOT_IN_DHCP, L"", | |
493 base::TimeDelta::FromMilliseconds(1)); | |
494 // This will time out. | |
495 client->fetcher_.ConfigureAndPushBackAdapter( | |
496 "second", false, ERR_IO_PENDING, L"bingo", | |
497 TestTimeouts::action_timeout()); | |
498 // This is the first non-ERR_PAC_NOT_IN_DHCP error and as such | |
499 // should be chosen. | |
500 client->fetcher_.ConfigureAndPushBackAdapter( | |
501 "third", true, ERR_PAC_STATUS_NOT_OK, L"", | |
502 base::TimeDelta::FromMilliseconds(1)); | |
503 client->fetcher_.ConfigureAndPushBackAdapter( | |
504 "fourth", true, ERR_NOT_IMPLEMENTED, L"", | |
505 base::TimeDelta::FromMilliseconds(1)); | |
506 client->RunTest(); | |
507 client->RunMessageLoopUntilComplete(); | |
508 ASSERT_EQ(ERR_PAC_STATUS_NOT_OK, client->result_); | |
509 ASSERT_EQ(L"", client->pac_text_); | |
510 } | |
511 | |
512 TEST(DhcpProxyScriptFetcherWin, | |
513 FailureCaseURLConfiguredMultipleAdaptersWithTimeout) { | |
514 FetcherClient client; | |
515 TestFailureCaseURLConfiguredMultipleAdaptersWithTimeout(&client); | |
516 } | |
517 | |
518 void TestFailureCaseNoURLConfigured(FetcherClient* client) { | |
519 client->fetcher_.ConfigureAndPushBackAdapter( | |
520 "most_preferred", true, ERR_PAC_NOT_IN_DHCP, L"", | |
521 base::TimeDelta::FromMilliseconds(1)); | |
522 // This will time out. | |
523 client->fetcher_.ConfigureAndPushBackAdapter( | |
524 "second", false, ERR_IO_PENDING, L"bingo", | |
525 TestTimeouts::action_timeout()); | |
526 // This is the first non-ERR_PAC_NOT_IN_DHCP error and as such | |
527 // should be chosen. | |
528 client->fetcher_.ConfigureAndPushBackAdapter( | |
529 "third", true, ERR_PAC_NOT_IN_DHCP, L"", | |
530 base::TimeDelta::FromMilliseconds(1)); | |
531 client->RunTest(); | |
532 client->RunMessageLoopUntilComplete(); | |
533 ASSERT_EQ(ERR_PAC_NOT_IN_DHCP, client->result_); | |
534 ASSERT_EQ(L"", client->pac_text_); | |
535 } | |
536 | |
537 TEST(DhcpProxyScriptFetcherWin, FailureCaseNoURLConfigured) { | |
538 FetcherClient client; | |
539 TestFailureCaseNoURLConfigured(&client); | |
540 } | |
541 | |
542 void TestFailureCaseNoDhcpAdapters(FetcherClient* client) { | |
543 client->RunTest(); | |
544 client->RunMessageLoopUntilComplete(); | |
545 ASSERT_EQ(ERR_PAC_NOT_IN_DHCP, client->result_); | |
546 ASSERT_EQ(L"", client->pac_text_); | |
547 ASSERT_EQ(0, client->fetcher_.num_fetchers_created_); | |
548 } | |
549 | |
550 TEST(DhcpProxyScriptFetcherWin, FailureCaseNoDhcpAdapters) { | |
551 FetcherClient client; | |
552 TestFailureCaseNoDhcpAdapters(&client); | |
553 } | |
554 | |
555 void TestShortCircuitLessPreferredAdapters(FetcherClient* client) { | |
556 // Here we have a bunch of adapters; the first reports no PAC in DHCP, | |
557 // the second responds quickly with a PAC file, the rest take a long | |
558 // time. Verify that we complete quickly and do not wait for the slow | |
559 // adapters, i.e. we finish before timeout. | |
560 client->fetcher_.ConfigureAndPushBackAdapter( | |
561 "1", true, ERR_PAC_NOT_IN_DHCP, L"", | |
562 base::TimeDelta::FromMilliseconds(1)); | |
563 client->fetcher_.ConfigureAndPushBackAdapter( | |
564 "2", true, OK, L"bingo", | |
565 base::TimeDelta::FromMilliseconds(1)); | |
566 client->fetcher_.ConfigureAndPushBackAdapter( | |
567 "3", true, OK, L"wrongo", TestTimeouts::action_max_timeout()); | |
568 | |
569 // Increase the timeout to ensure the short circuit mechanism has | |
570 // time to kick in before the timeout waiting for more adapters kicks in. | |
571 client->fetcher_.max_wait_ = TestTimeouts::action_timeout(); | |
572 | |
573 base::ElapsedTimer timer; | |
574 client->RunTest(); | |
575 client->RunMessageLoopUntilComplete(); | |
576 ASSERT_TRUE(client->fetcher_.HasPendingFetchers()); | |
577 // Assert that the time passed is definitely less than the wait timer | |
578 // timeout, to get a second signal that it was the shortcut mechanism | |
579 // (in OnFetcherDone) that kicked in, and not the timeout waiting for | |
580 // more adapters. | |
581 ASSERT_GT(client->fetcher_.max_wait_ - (client->fetcher_.max_wait_ / 10), | |
582 timer.Elapsed()); | |
583 } | |
584 | |
585 TEST(DhcpProxyScriptFetcherWin, ShortCircuitLessPreferredAdapters) { | |
586 FetcherClient client; | |
587 TestShortCircuitLessPreferredAdapters(&client); | |
588 } | |
589 | |
590 void TestImmediateCancel(FetcherClient* client) { | |
591 TestURLRequestContext context; | |
592 scoped_ptr<DummyDhcpProxyScriptAdapterFetcher> adapter_fetcher( | |
593 new DummyDhcpProxyScriptAdapterFetcher(&context, | |
594 client->GetTaskRunner())); | |
595 adapter_fetcher->Configure(true, OK, L"bingo", 1); | |
596 client->fetcher_.PushBackAdapter("a", adapter_fetcher.release()); | |
597 client->RunTest(); | |
598 client->fetcher_.Cancel(); | |
599 client->RunMessageLoopUntilWorkerDone(); | |
600 ASSERT_EQ(0, client->fetcher_.num_fetchers_created_); | |
601 } | |
602 | |
603 // Regression test to check that when we cancel immediately, no | |
604 // adapter fetchers get created. | |
605 TEST(DhcpProxyScriptFetcherWin, ImmediateCancel) { | |
606 FetcherClient client; | |
607 TestImmediateCancel(&client); | |
608 } | |
609 | |
610 TEST(DhcpProxyScriptFetcherWin, ReuseFetcher) { | |
611 FetcherClient client; | |
612 | |
613 // The ProxyScriptFetcher interface stipulates that only a single | |
614 // |Fetch()| may be in flight at once, but allows reuse, so test | |
615 // that the state transitions correctly from done to start in all | |
616 // cases we're testing. | |
617 | |
618 typedef void (*FetcherClientTestFunction)(FetcherClient*); | |
619 typedef std::vector<FetcherClientTestFunction> TestVector; | |
620 TestVector test_functions; | |
621 test_functions.push_back(TestNormalCaseURLConfiguredOneAdapter); | |
622 test_functions.push_back(TestNormalCaseURLConfiguredMultipleAdapters); | |
623 test_functions.push_back( | |
624 TestNormalCaseURLConfiguredMultipleAdaptersWithTimeout); | |
625 test_functions.push_back( | |
626 TestFailureCaseURLConfiguredMultipleAdaptersWithTimeout); | |
627 test_functions.push_back(TestFailureCaseNoURLConfigured); | |
628 test_functions.push_back(TestFailureCaseNoDhcpAdapters); | |
629 test_functions.push_back(TestShortCircuitLessPreferredAdapters); | |
630 test_functions.push_back(TestImmediateCancel); | |
631 | |
632 std::random_shuffle(test_functions.begin(), | |
633 test_functions.end(), | |
634 base::RandGenerator); | |
635 for (TestVector::const_iterator it = test_functions.begin(); | |
636 it != test_functions.end(); | |
637 ++it) { | |
638 (*it)(&client); | |
639 client.ResetTestState(); | |
640 } | |
641 | |
642 // Re-do the first test to make sure the last test that was run did | |
643 // not leave things in a bad state. | |
644 (*test_functions.begin())(&client); | |
645 } | |
646 | |
647 } // namespace | |
648 | |
649 } // namespace net | |
OLD | NEW |