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