Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / net / proxy / proxy_script_decider_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 <vector>
6
7 #include "base/bind.h"
8 #include "base/memory/weak_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/time/time.h"
14 #include "net/base/net_errors.h"
15 #include "net/base/net_log.h"
16 #include "net/base/net_log_unittest.h"
17 #include "net/base/test_completion_callback.h"
18 #include "net/dns/mock_host_resolver.h"
19 #include "net/proxy/dhcp_proxy_script_fetcher.h"
20 #include "net/proxy/mock_proxy_script_fetcher.h"
21 #include "net/proxy/proxy_config.h"
22 #include "net/proxy/proxy_resolver.h"
23 #include "net/proxy/proxy_script_decider.h"
24 #include "net/proxy/proxy_script_fetcher.h"
25 #include "net/url_request/url_request_context.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27
28 namespace net {
29 namespace {
30
31 enum Error {
32   kFailedDownloading = -100,
33   kFailedParsing = ERR_PAC_SCRIPT_FAILED,
34 };
35
36 class Rules {
37  public:
38   struct Rule {
39     Rule(const GURL& url, int fetch_error, bool is_valid_script)
40         : url(url),
41           fetch_error(fetch_error),
42           is_valid_script(is_valid_script) {
43     }
44
45     base::string16 text() const {
46       if (is_valid_script)
47         return base::UTF8ToUTF16(url.spec() + "!FindProxyForURL");
48       if (fetch_error == OK)
49         return base::UTF8ToUTF16(url.spec() + "!invalid-script");
50       return base::string16();
51     }
52
53     GURL url;
54     int fetch_error;
55     bool is_valid_script;
56   };
57
58   Rule AddSuccessRule(const char* url) {
59     Rule rule(GURL(url), OK /*fetch_error*/, true);
60     rules_.push_back(rule);
61     return rule;
62   }
63
64   void AddFailDownloadRule(const char* url) {
65     rules_.push_back(Rule(GURL(url), kFailedDownloading /*fetch_error*/,
66         false));
67   }
68
69   void AddFailParsingRule(const char* url) {
70     rules_.push_back(Rule(GURL(url), OK /*fetch_error*/, false));
71   }
72
73   const Rule& GetRuleByUrl(const GURL& url) const {
74     for (RuleList::const_iterator it = rules_.begin(); it != rules_.end();
75          ++it) {
76       if (it->url == url)
77         return *it;
78     }
79     LOG(FATAL) << "Rule not found for " << url;
80     return rules_[0];
81   }
82
83   const Rule& GetRuleByText(const base::string16& text) const {
84     for (RuleList::const_iterator it = rules_.begin(); it != rules_.end();
85          ++it) {
86       if (it->text() == text)
87         return *it;
88     }
89     LOG(FATAL) << "Rule not found for " << text;
90     return rules_[0];
91   }
92
93  private:
94   typedef std::vector<Rule> RuleList;
95   RuleList rules_;
96 };
97
98 class RuleBasedProxyScriptFetcher : public ProxyScriptFetcher {
99  public:
100   explicit RuleBasedProxyScriptFetcher(const Rules* rules)
101       : rules_(rules), request_context_(NULL) {}
102
103   virtual void SetRequestContext(URLRequestContext* context) {
104     request_context_ = context;
105   }
106
107   // ProxyScriptFetcher implementation.
108   int Fetch(const GURL& url,
109             base::string16* text,
110             const CompletionCallback& callback) override {
111     const Rules::Rule& rule = rules_->GetRuleByUrl(url);
112     int rv = rule.fetch_error;
113     EXPECT_NE(ERR_UNEXPECTED, rv);
114     if (rv == OK)
115       *text = rule.text();
116     return rv;
117   }
118
119   void Cancel() override {}
120
121   URLRequestContext* GetRequestContext() const override {
122     return request_context_;
123   }
124
125  private:
126   const Rules* rules_;
127   URLRequestContext* request_context_;
128 };
129
130 // A mock retriever, returns asynchronously when CompleteRequests() is called.
131 class MockDhcpProxyScriptFetcher : public DhcpProxyScriptFetcher {
132  public:
133   MockDhcpProxyScriptFetcher();
134   ~MockDhcpProxyScriptFetcher() override;
135
136   int Fetch(base::string16* utf16_text,
137             const CompletionCallback& callback) override;
138   void Cancel() override;
139   const GURL& GetPacURL() const override;
140
141   virtual void SetPacURL(const GURL& url);
142
143   virtual void CompleteRequests(int result, const base::string16& script);
144
145  private:
146   CompletionCallback callback_;
147   base::string16* utf16_text_;
148   GURL gurl_;
149   DISALLOW_COPY_AND_ASSIGN(MockDhcpProxyScriptFetcher);
150 };
151
152 MockDhcpProxyScriptFetcher::MockDhcpProxyScriptFetcher() { }
153
154 MockDhcpProxyScriptFetcher::~MockDhcpProxyScriptFetcher() { }
155
156 int MockDhcpProxyScriptFetcher::Fetch(base::string16* utf16_text,
157                                       const CompletionCallback& callback) {
158   utf16_text_ = utf16_text;
159   callback_ = callback;
160   return ERR_IO_PENDING;
161 }
162
163 void MockDhcpProxyScriptFetcher::Cancel() { }
164
165 const GURL& MockDhcpProxyScriptFetcher::GetPacURL() const {
166   return gurl_;
167 }
168
169 void MockDhcpProxyScriptFetcher::SetPacURL(const GURL& url) {
170   gurl_ = url;
171 }
172
173 void MockDhcpProxyScriptFetcher::CompleteRequests(
174     int result, const base::string16& script) {
175   *utf16_text_ = script;
176   callback_.Run(result);
177 }
178
179 // Succeed using custom PAC script.
180 TEST(ProxyScriptDeciderTest, CustomPacSucceeds) {
181   Rules rules;
182   RuleBasedProxyScriptFetcher fetcher(&rules);
183   DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
184
185   ProxyConfig config;
186   config.set_pac_url(GURL("http://custom/proxy.pac"));
187
188   Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac");
189
190   TestCompletionCallback callback;
191   CapturingNetLog log;
192   ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, &log);
193   EXPECT_EQ(OK, decider.Start(
194       config, base::TimeDelta(), true, callback.callback()));
195   EXPECT_EQ(rule.text(), decider.script_data()->utf16());
196
197   // Check the NetLog was filled correctly.
198   CapturingNetLog::CapturedEntryList entries;
199   log.GetEntries(&entries);
200
201   EXPECT_EQ(4u, entries.size());
202   EXPECT_TRUE(LogContainsBeginEvent(
203       entries, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
204   EXPECT_TRUE(LogContainsBeginEvent(
205       entries, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
206   EXPECT_TRUE(LogContainsEndEvent(
207       entries, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
208   EXPECT_TRUE(LogContainsEndEvent(
209       entries, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
210
211   EXPECT_TRUE(decider.effective_config().has_pac_url());
212   EXPECT_EQ(config.pac_url(), decider.effective_config().pac_url());
213 }
214
215 // Fail downloading the custom PAC script.
216 TEST(ProxyScriptDeciderTest, CustomPacFails1) {
217   Rules rules;
218   RuleBasedProxyScriptFetcher fetcher(&rules);
219   DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
220
221   ProxyConfig config;
222   config.set_pac_url(GURL("http://custom/proxy.pac"));
223
224   rules.AddFailDownloadRule("http://custom/proxy.pac");
225
226   TestCompletionCallback callback;
227   CapturingNetLog log;
228   ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, &log);
229   EXPECT_EQ(kFailedDownloading,
230             decider.Start(config, base::TimeDelta(), true,
231                           callback.callback()));
232   EXPECT_EQ(NULL, decider.script_data());
233
234   // Check the NetLog was filled correctly.
235   CapturingNetLog::CapturedEntryList entries;
236   log.GetEntries(&entries);
237
238   EXPECT_EQ(4u, entries.size());
239   EXPECT_TRUE(LogContainsBeginEvent(
240       entries, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
241   EXPECT_TRUE(LogContainsBeginEvent(
242       entries, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
243   EXPECT_TRUE(LogContainsEndEvent(
244       entries, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
245   EXPECT_TRUE(LogContainsEndEvent(
246       entries, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
247
248   EXPECT_FALSE(decider.effective_config().has_pac_url());
249 }
250
251 // Fail parsing the custom PAC script.
252 TEST(ProxyScriptDeciderTest, CustomPacFails2) {
253   Rules rules;
254   RuleBasedProxyScriptFetcher fetcher(&rules);
255   DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
256
257   ProxyConfig config;
258   config.set_pac_url(GURL("http://custom/proxy.pac"));
259
260   rules.AddFailParsingRule("http://custom/proxy.pac");
261
262   TestCompletionCallback callback;
263   ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, NULL);
264   EXPECT_EQ(kFailedParsing,
265             decider.Start(config, base::TimeDelta(), true,
266                           callback.callback()));
267   EXPECT_EQ(NULL, decider.script_data());
268 }
269
270 // Fail downloading the custom PAC script, because the fetcher was NULL.
271 TEST(ProxyScriptDeciderTest, HasNullProxyScriptFetcher) {
272   Rules rules;
273   DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
274
275   ProxyConfig config;
276   config.set_pac_url(GURL("http://custom/proxy.pac"));
277
278   TestCompletionCallback callback;
279   ProxyScriptDecider decider(NULL, &dhcp_fetcher, NULL);
280   EXPECT_EQ(ERR_UNEXPECTED,
281             decider.Start(config, base::TimeDelta(), true,
282                           callback.callback()));
283   EXPECT_EQ(NULL, decider.script_data());
284 }
285
286 // Succeeds in choosing autodetect (WPAD DNS).
287 TEST(ProxyScriptDeciderTest, AutodetectSuccess) {
288   Rules rules;
289   RuleBasedProxyScriptFetcher fetcher(&rules);
290   DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
291
292   ProxyConfig config;
293   config.set_auto_detect(true);
294
295   Rules::Rule rule = rules.AddSuccessRule("http://wpad/wpad.dat");
296
297   TestCompletionCallback callback;
298   ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, NULL);
299   EXPECT_EQ(OK, decider.Start(
300       config, base::TimeDelta(), true, callback.callback()));
301   EXPECT_EQ(rule.text(), decider.script_data()->utf16());
302
303   EXPECT_TRUE(decider.effective_config().has_pac_url());
304   EXPECT_EQ(rule.url, decider.effective_config().pac_url());
305 }
306
307 class ProxyScriptDeciderQuickCheckTest : public ::testing::Test {
308  public:
309   ProxyScriptDeciderQuickCheckTest()
310       : rule_(rules_.AddSuccessRule("http://wpad/wpad.dat")),
311         fetcher_(&rules_) { }
312
313   void SetUp() override {
314     request_context_.set_host_resolver(&resolver_);
315     fetcher_.SetRequestContext(&request_context_);
316     config_.set_auto_detect(true);
317     decider_.reset(new ProxyScriptDecider(&fetcher_, &dhcp_fetcher_, NULL));
318   }
319
320   int StartDecider() {
321     return decider_->Start(config_, base::TimeDelta(), true,
322                             callback_.callback());
323   }
324
325  protected:
326   scoped_ptr<ProxyScriptDecider> decider_;
327   MockHostResolver resolver_;
328   Rules rules_;
329   Rules::Rule rule_;
330   TestCompletionCallback callback_;
331   RuleBasedProxyScriptFetcher fetcher_;
332   ProxyConfig config_;
333   DoNothingDhcpProxyScriptFetcher dhcp_fetcher_;
334
335  private:
336   URLRequestContext request_context_;
337 };
338
339 // Fails if a synchronous DNS lookup success for wpad causes QuickCheck to fail.
340 TEST_F(ProxyScriptDeciderQuickCheckTest, SyncSuccess) {
341   resolver_.set_synchronous_mode(true);
342   resolver_.rules()->AddRule("wpad", "1.2.3.4");
343
344   EXPECT_EQ(OK, StartDecider());
345   EXPECT_EQ(rule_.text(), decider_->script_data()->utf16());
346
347   EXPECT_TRUE(decider_->effective_config().has_pac_url());
348   EXPECT_EQ(rule_.url, decider_->effective_config().pac_url());
349 }
350
351 // Fails if an asynchronous DNS lookup success for wpad causes QuickCheck to
352 // fail.
353 TEST_F(ProxyScriptDeciderQuickCheckTest, AsyncSuccess) {
354   resolver_.set_ondemand_mode(true);
355   resolver_.rules()->AddRule("wpad", "1.2.3.4");
356
357   EXPECT_EQ(ERR_IO_PENDING, StartDecider());
358   ASSERT_TRUE(resolver_.has_pending_requests());
359   resolver_.ResolveAllPending();
360   callback_.WaitForResult();
361   EXPECT_FALSE(resolver_.has_pending_requests());
362   EXPECT_EQ(rule_.text(), decider_->script_data()->utf16());
363   EXPECT_TRUE(decider_->effective_config().has_pac_url());
364   EXPECT_EQ(rule_.url, decider_->effective_config().pac_url());
365 }
366
367 // Fails if an asynchronous DNS lookup failure (i.e. an NXDOMAIN) still causes
368 // ProxyScriptDecider to yield a PAC URL.
369 TEST_F(ProxyScriptDeciderQuickCheckTest, AsyncFail) {
370   resolver_.set_ondemand_mode(true);
371   resolver_.rules()->AddSimulatedFailure("wpad");
372   EXPECT_EQ(ERR_IO_PENDING, StartDecider());
373   ASSERT_TRUE(resolver_.has_pending_requests());
374   resolver_.ResolveAllPending();
375   callback_.WaitForResult();
376   EXPECT_FALSE(decider_->effective_config().has_pac_url());
377 }
378
379 // Fails if a DNS lookup timeout either causes ProxyScriptDecider to yield a PAC
380 // URL or causes ProxyScriptDecider not to cancel its pending resolution.
381 TEST_F(ProxyScriptDeciderQuickCheckTest, AsyncTimeout) {
382   resolver_.set_ondemand_mode(true);
383   EXPECT_EQ(ERR_IO_PENDING, StartDecider());
384   ASSERT_TRUE(resolver_.has_pending_requests());
385   callback_.WaitForResult();
386   EXPECT_FALSE(resolver_.has_pending_requests());
387   EXPECT_FALSE(decider_->effective_config().has_pac_url());
388 }
389
390 // Fails if DHCP check doesn't take place before QuickCheck.
391 TEST_F(ProxyScriptDeciderQuickCheckTest, QuickCheckInhibitsDhcp) {
392   MockDhcpProxyScriptFetcher dhcp_fetcher;
393   const char *kPac = "function FindProxyForURL(u,h) { return \"DIRECT\"; }";
394   base::string16 pac_contents = base::UTF8ToUTF16(kPac);
395   GURL url("http://foobar/baz");
396   dhcp_fetcher.SetPacURL(url);
397   decider_.reset(new ProxyScriptDecider(&fetcher_, &dhcp_fetcher, NULL));
398   EXPECT_EQ(ERR_IO_PENDING, StartDecider());
399   dhcp_fetcher.CompleteRequests(OK, pac_contents);
400   EXPECT_TRUE(decider_->effective_config().has_pac_url());
401   EXPECT_EQ(decider_->effective_config().pac_url(), url);
402 }
403
404 // Fails if QuickCheck still happens when disabled. To ensure QuickCheck is not
405 // happening, we add a synchronous failing resolver, which would ordinarily
406 // mean a QuickCheck failure, then ensure that our ProxyScriptFetcher is still
407 // asked to fetch.
408 TEST_F(ProxyScriptDeciderQuickCheckTest, QuickCheckDisabled) {
409   const char *kPac = "function FindProxyForURL(u,h) { return \"DIRECT\"; }";
410   resolver_.set_synchronous_mode(true);
411   resolver_.rules()->AddSimulatedFailure("wpad");
412   MockProxyScriptFetcher fetcher;
413   decider_.reset(new ProxyScriptDecider(&fetcher, &dhcp_fetcher_, NULL));
414   EXPECT_EQ(ERR_IO_PENDING, StartDecider());
415   EXPECT_TRUE(fetcher.has_pending_request());
416   fetcher.NotifyFetchCompletion(OK, kPac);
417 }
418
419 TEST_F(ProxyScriptDeciderQuickCheckTest, ExplicitPacUrl) {
420   const char *kCustomUrl = "http://custom/proxy.pac";
421   config_.set_pac_url(GURL(kCustomUrl));
422   Rules::Rule rule = rules_.AddSuccessRule(kCustomUrl);
423   resolver_.rules()->AddSimulatedFailure("wpad");
424   resolver_.rules()->AddRule("custom", "1.2.3.4");
425   EXPECT_EQ(ERR_IO_PENDING, StartDecider());
426   callback_.WaitForResult();
427   EXPECT_TRUE(decider_->effective_config().has_pac_url());
428   EXPECT_EQ(rule.url, decider_->effective_config().pac_url());
429 }
430
431 // Fails at WPAD (downloading), but succeeds in choosing the custom PAC.
432 TEST(ProxyScriptDeciderTest, AutodetectFailCustomSuccess1) {
433   Rules rules;
434   RuleBasedProxyScriptFetcher fetcher(&rules);
435   DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
436
437   ProxyConfig config;
438   config.set_auto_detect(true);
439   config.set_pac_url(GURL("http://custom/proxy.pac"));
440
441   rules.AddFailDownloadRule("http://wpad/wpad.dat");
442   Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac");
443
444   TestCompletionCallback callback;
445   ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, NULL);
446   EXPECT_EQ(OK, decider.Start(
447       config, base::TimeDelta(), true, callback.callback()));
448   EXPECT_EQ(rule.text(), decider.script_data()->utf16());
449
450   EXPECT_TRUE(decider.effective_config().has_pac_url());
451   EXPECT_EQ(rule.url, decider.effective_config().pac_url());
452 }
453
454 // Fails at WPAD (no DHCP config, DNS PAC fails parsing), but succeeds in
455 // choosing the custom PAC.
456 TEST(ProxyScriptDeciderTest, AutodetectFailCustomSuccess2) {
457   Rules rules;
458   RuleBasedProxyScriptFetcher fetcher(&rules);
459   DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
460
461   ProxyConfig config;
462   config.set_auto_detect(true);
463   config.set_pac_url(GURL("http://custom/proxy.pac"));
464   config.proxy_rules().ParseFromString("unused-manual-proxy:99");
465
466   rules.AddFailParsingRule("http://wpad/wpad.dat");
467   Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac");
468
469   TestCompletionCallback callback;
470   CapturingNetLog log;
471
472   ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, &log);
473   EXPECT_EQ(OK, decider.Start(config, base::TimeDelta(),
474                           true, callback.callback()));
475   EXPECT_EQ(rule.text(), decider.script_data()->utf16());
476
477   // Verify that the effective configuration no longer contains auto detect or
478   // any of the manual settings.
479   EXPECT_TRUE(decider.effective_config().Equals(
480       ProxyConfig::CreateFromCustomPacURL(GURL("http://custom/proxy.pac"))));
481
482   // Check the NetLog was filled correctly.
483   // (Note that various states are repeated since both WPAD and custom
484   // PAC scripts are tried).
485   CapturingNetLog::CapturedEntryList entries;
486   log.GetEntries(&entries);
487
488   EXPECT_EQ(10u, entries.size());
489   EXPECT_TRUE(LogContainsBeginEvent(
490       entries, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
491   // This is the DHCP phase, which fails fetching rather than parsing, so
492   // there is no pair of SET_PAC_SCRIPT events.
493   EXPECT_TRUE(LogContainsBeginEvent(
494       entries, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
495   EXPECT_TRUE(LogContainsEndEvent(
496       entries, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
497   EXPECT_TRUE(LogContainsEvent(
498       entries, 3,
499       NetLog::TYPE_PROXY_SCRIPT_DECIDER_FALLING_BACK_TO_NEXT_PAC_SOURCE,
500       NetLog::PHASE_NONE));
501   // This is the DNS phase, which attempts a fetch but fails.
502   EXPECT_TRUE(LogContainsBeginEvent(
503       entries, 4, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
504   EXPECT_TRUE(LogContainsEndEvent(
505       entries, 5, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
506   EXPECT_TRUE(LogContainsEvent(
507       entries, 6,
508       NetLog::TYPE_PROXY_SCRIPT_DECIDER_FALLING_BACK_TO_NEXT_PAC_SOURCE,
509       NetLog::PHASE_NONE));
510   // Finally, the custom PAC URL phase.
511   EXPECT_TRUE(LogContainsBeginEvent(
512       entries, 7, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
513   EXPECT_TRUE(LogContainsEndEvent(
514       entries, 8, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
515   EXPECT_TRUE(LogContainsEndEvent(
516       entries, 9, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
517 }
518
519 // Fails at WPAD (downloading), and fails at custom PAC (downloading).
520 TEST(ProxyScriptDeciderTest, AutodetectFailCustomFails1) {
521   Rules rules;
522   RuleBasedProxyScriptFetcher fetcher(&rules);
523   DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
524
525   ProxyConfig config;
526   config.set_auto_detect(true);
527   config.set_pac_url(GURL("http://custom/proxy.pac"));
528
529   rules.AddFailDownloadRule("http://wpad/wpad.dat");
530   rules.AddFailDownloadRule("http://custom/proxy.pac");
531
532   TestCompletionCallback callback;
533   ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, NULL);
534   EXPECT_EQ(kFailedDownloading,
535             decider.Start(config, base::TimeDelta(), true,
536                           callback.callback()));
537   EXPECT_EQ(NULL, decider.script_data());
538 }
539
540 // Fails at WPAD (downloading), and fails at custom PAC (parsing).
541 TEST(ProxyScriptDeciderTest, AutodetectFailCustomFails2) {
542   Rules rules;
543   RuleBasedProxyScriptFetcher fetcher(&rules);
544   DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
545
546   ProxyConfig config;
547   config.set_auto_detect(true);
548   config.set_pac_url(GURL("http://custom/proxy.pac"));
549
550   rules.AddFailDownloadRule("http://wpad/wpad.dat");
551   rules.AddFailParsingRule("http://custom/proxy.pac");
552
553   TestCompletionCallback callback;
554   ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, NULL);
555   EXPECT_EQ(kFailedParsing,
556             decider.Start(config, base::TimeDelta(), true,
557                           callback.callback()));
558   EXPECT_EQ(NULL, decider.script_data());
559 }
560
561 // This is a copy-paste of CustomPacFails1, with the exception that we give it
562 // a 1 millisecond delay. This means it will now complete asynchronously.
563 // Moreover, we test the NetLog to make sure it logged the pause.
564 TEST(ProxyScriptDeciderTest, CustomPacFails1_WithPositiveDelay) {
565   Rules rules;
566   RuleBasedProxyScriptFetcher fetcher(&rules);
567   DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
568
569   ProxyConfig config;
570   config.set_pac_url(GURL("http://custom/proxy.pac"));
571
572   rules.AddFailDownloadRule("http://custom/proxy.pac");
573
574   TestCompletionCallback callback;
575   CapturingNetLog log;
576   ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, &log);
577   EXPECT_EQ(ERR_IO_PENDING,
578             decider.Start(config, base::TimeDelta::FromMilliseconds(1),
579                       true, callback.callback()));
580
581   EXPECT_EQ(kFailedDownloading, callback.WaitForResult());
582   EXPECT_EQ(NULL, decider.script_data());
583
584   // Check the NetLog was filled correctly.
585   CapturingNetLog::CapturedEntryList entries;
586   log.GetEntries(&entries);
587
588   EXPECT_EQ(6u, entries.size());
589   EXPECT_TRUE(LogContainsBeginEvent(
590       entries, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
591   EXPECT_TRUE(LogContainsBeginEvent(
592       entries, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT));
593   EXPECT_TRUE(LogContainsEndEvent(
594       entries, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT));
595   EXPECT_TRUE(LogContainsBeginEvent(
596       entries, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
597   EXPECT_TRUE(LogContainsEndEvent(
598       entries, 4, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
599   EXPECT_TRUE(LogContainsEndEvent(
600       entries, 5, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
601 }
602
603 // This is a copy-paste of CustomPacFails1, with the exception that we give it
604 // a -5 second delay instead of a 0 ms delay. This change should have no effect
605 // so the rest of the test is unchanged.
606 TEST(ProxyScriptDeciderTest, CustomPacFails1_WithNegativeDelay) {
607   Rules rules;
608   RuleBasedProxyScriptFetcher fetcher(&rules);
609   DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
610
611   ProxyConfig config;
612   config.set_pac_url(GURL("http://custom/proxy.pac"));
613
614   rules.AddFailDownloadRule("http://custom/proxy.pac");
615
616   TestCompletionCallback callback;
617   CapturingNetLog log;
618   ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, &log);
619   EXPECT_EQ(kFailedDownloading,
620             decider.Start(config, base::TimeDelta::FromSeconds(-5),
621                           true, callback.callback()));
622   EXPECT_EQ(NULL, decider.script_data());
623
624   // Check the NetLog was filled correctly.
625   CapturingNetLog::CapturedEntryList entries;
626   log.GetEntries(&entries);
627
628   EXPECT_EQ(4u, entries.size());
629   EXPECT_TRUE(LogContainsBeginEvent(
630       entries, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
631   EXPECT_TRUE(LogContainsBeginEvent(
632       entries, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
633   EXPECT_TRUE(LogContainsEndEvent(
634       entries, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
635   EXPECT_TRUE(LogContainsEndEvent(
636       entries, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
637 }
638
639 class SynchronousSuccessDhcpFetcher : public DhcpProxyScriptFetcher {
640  public:
641   explicit SynchronousSuccessDhcpFetcher(const base::string16& expected_text)
642       : gurl_("http://dhcppac/"), expected_text_(expected_text) {
643   }
644
645   int Fetch(base::string16* utf16_text,
646             const CompletionCallback& callback) override {
647     *utf16_text = expected_text_;
648     return OK;
649   }
650
651   void Cancel() override {}
652
653   const GURL& GetPacURL() const override { return gurl_; }
654
655   const base::string16& expected_text() const {
656     return expected_text_;
657   }
658
659  private:
660   GURL gurl_;
661   base::string16 expected_text_;
662
663   DISALLOW_COPY_AND_ASSIGN(SynchronousSuccessDhcpFetcher);
664 };
665
666 // All of the tests above that use ProxyScriptDecider have tested
667 // failure to fetch a PAC file via DHCP configuration, so we now test
668 // success at downloading and parsing, and then success at downloading,
669 // failure at parsing.
670
671 TEST(ProxyScriptDeciderTest, AutodetectDhcpSuccess) {
672   Rules rules;
673   RuleBasedProxyScriptFetcher fetcher(&rules);
674   SynchronousSuccessDhcpFetcher dhcp_fetcher(
675       base::WideToUTF16(L"http://bingo/!FindProxyForURL"));
676
677   ProxyConfig config;
678   config.set_auto_detect(true);
679
680   rules.AddSuccessRule("http://bingo/");
681   rules.AddFailDownloadRule("http://wpad/wpad.dat");
682
683   TestCompletionCallback callback;
684   ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, NULL);
685   EXPECT_EQ(OK, decider.Start(
686       config, base::TimeDelta(), true, callback.callback()));
687   EXPECT_EQ(dhcp_fetcher.expected_text(),
688             decider.script_data()->utf16());
689
690   EXPECT_TRUE(decider.effective_config().has_pac_url());
691   EXPECT_EQ(GURL("http://dhcppac/"), decider.effective_config().pac_url());
692 }
693
694 TEST(ProxyScriptDeciderTest, AutodetectDhcpFailParse) {
695   Rules rules;
696   RuleBasedProxyScriptFetcher fetcher(&rules);
697   SynchronousSuccessDhcpFetcher dhcp_fetcher(
698       base::WideToUTF16(L"http://bingo/!invalid-script"));
699
700   ProxyConfig config;
701   config.set_auto_detect(true);
702
703   rules.AddFailParsingRule("http://bingo/");
704   rules.AddFailDownloadRule("http://wpad/wpad.dat");
705
706   TestCompletionCallback callback;
707   ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, NULL);
708   // Since there is fallback to DNS-based WPAD, the final error will be that
709   // it failed downloading, not that it failed parsing.
710   EXPECT_EQ(kFailedDownloading,
711       decider.Start(config, base::TimeDelta(), true, callback.callback()));
712   EXPECT_EQ(NULL, decider.script_data());
713
714   EXPECT_FALSE(decider.effective_config().has_pac_url());
715 }
716
717 class AsyncFailDhcpFetcher
718     : public DhcpProxyScriptFetcher,
719       public base::SupportsWeakPtr<AsyncFailDhcpFetcher> {
720  public:
721   AsyncFailDhcpFetcher() {}
722   ~AsyncFailDhcpFetcher() override {}
723
724   int Fetch(base::string16* utf16_text,
725             const CompletionCallback& callback) override {
726     callback_ = callback;
727     base::MessageLoop::current()->PostTask(
728         FROM_HERE,
729         base::Bind(&AsyncFailDhcpFetcher::CallbackWithFailure, AsWeakPtr()));
730     return ERR_IO_PENDING;
731   }
732
733   void Cancel() override { callback_.Reset(); }
734
735   const GURL& GetPacURL() const override { return dummy_gurl_; }
736
737   void CallbackWithFailure() {
738     if (!callback_.is_null())
739       callback_.Run(ERR_PAC_NOT_IN_DHCP);
740   }
741
742  private:
743   GURL dummy_gurl_;
744   CompletionCallback callback_;
745 };
746
747 TEST(ProxyScriptDeciderTest, DhcpCancelledByDestructor) {
748   // This regression test would crash before
749   // http://codereview.chromium.org/7044058/
750   // Thus, we don't care much about actual results (hence no EXPECT or ASSERT
751   // macros below), just that it doesn't crash.
752   Rules rules;
753   RuleBasedProxyScriptFetcher fetcher(&rules);
754
755   scoped_ptr<AsyncFailDhcpFetcher> dhcp_fetcher(new AsyncFailDhcpFetcher());
756
757   ProxyConfig config;
758   config.set_auto_detect(true);
759   rules.AddFailDownloadRule("http://wpad/wpad.dat");
760
761   TestCompletionCallback callback;
762
763   // Scope so ProxyScriptDecider gets destroyed early.
764   {
765     ProxyScriptDecider decider(&fetcher, dhcp_fetcher.get(), NULL);
766     decider.Start(config, base::TimeDelta(), true, callback.callback());
767   }
768
769   // Run the message loop to let the DHCP fetch complete and post the results
770   // back. Before the fix linked to above, this would try to invoke on
771   // the callback object provided by ProxyScriptDecider after it was
772   // no longer valid.
773   base::MessageLoop::current()->RunUntilIdle();
774 }
775
776 }  // namespace
777 }  // namespace net