Files.app: Add ExternalMetadataProvider class.
[chromium-blink-merge.git] / net / proxy / proxy_script_decider_unittest.cc
blob8914f5beed50d265614ba675fbda760505922304
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.
5 #include <vector>
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"
28 namespace net {
29 namespace {
31 enum Error {
32 kFailedDownloading = -100,
33 kFailedParsing = ERR_PAC_SCRIPT_FAILED,
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) {
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();
53 GURL url;
54 int fetch_error;
55 bool is_valid_script;
58 Rule AddSuccessRule(const char* url) {
59 Rule rule(GURL(url), OK /*fetch_error*/, true);
60 rules_.push_back(rule);
61 return rule;
64 void AddFailDownloadRule(const char* url) {
65 rules_.push_back(Rule(GURL(url), kFailedDownloading /*fetch_error*/,
66 false));
69 void AddFailParsingRule(const char* url) {
70 rules_.push_back(Rule(GURL(url), OK /*fetch_error*/, false));
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;
79 LOG(FATAL) << "Rule not found for " << url;
80 return rules_[0];
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;
89 LOG(FATAL) << "Rule not found for " << text;
90 return rules_[0];
93 private:
94 typedef std::vector<Rule> RuleList;
95 RuleList rules_;
98 class RuleBasedProxyScriptFetcher : public ProxyScriptFetcher {
99 public:
100 explicit RuleBasedProxyScriptFetcher(const Rules* rules)
101 : rules_(rules), request_context_(NULL) {}
103 virtual void SetRequestContext(URLRequestContext* context) {
104 request_context_ = context;
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;
119 void Cancel() override {}
121 URLRequestContext* GetRequestContext() const override {
122 return request_context_;
125 private:
126 const Rules* rules_;
127 URLRequestContext* request_context_;
130 // A mock retriever, returns asynchronously when CompleteRequests() is called.
131 class MockDhcpProxyScriptFetcher : public DhcpProxyScriptFetcher {
132 public:
133 MockDhcpProxyScriptFetcher();
134 ~MockDhcpProxyScriptFetcher() override;
136 int Fetch(base::string16* utf16_text,
137 const CompletionCallback& callback) override;
138 void Cancel() override;
139 const GURL& GetPacURL() const override;
141 virtual void SetPacURL(const GURL& url);
143 virtual void CompleteRequests(int result, const base::string16& script);
145 private:
146 CompletionCallback callback_;
147 base::string16* utf16_text_;
148 GURL gurl_;
149 DISALLOW_COPY_AND_ASSIGN(MockDhcpProxyScriptFetcher);
152 MockDhcpProxyScriptFetcher::MockDhcpProxyScriptFetcher() { }
154 MockDhcpProxyScriptFetcher::~MockDhcpProxyScriptFetcher() { }
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;
163 void MockDhcpProxyScriptFetcher::Cancel() { }
165 const GURL& MockDhcpProxyScriptFetcher::GetPacURL() const {
166 return gurl_;
169 void MockDhcpProxyScriptFetcher::SetPacURL(const GURL& url) {
170 gurl_ = url;
173 void MockDhcpProxyScriptFetcher::CompleteRequests(
174 int result, const base::string16& script) {
175 *utf16_text_ = script;
176 callback_.Run(result);
179 // Succeed using custom PAC script.
180 TEST(ProxyScriptDeciderTest, CustomPacSucceeds) {
181 Rules rules;
182 RuleBasedProxyScriptFetcher fetcher(&rules);
183 DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
185 ProxyConfig config;
186 config.set_pac_url(GURL("http://custom/proxy.pac"));
188 Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac");
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());
197 // Check the NetLog was filled correctly.
198 CapturingNetLog::CapturedEntryList entries;
199 log.GetEntries(&entries);
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));
211 EXPECT_TRUE(decider.effective_config().has_pac_url());
212 EXPECT_EQ(config.pac_url(), decider.effective_config().pac_url());
215 // Fail downloading the custom PAC script.
216 TEST(ProxyScriptDeciderTest, CustomPacFails1) {
217 Rules rules;
218 RuleBasedProxyScriptFetcher fetcher(&rules);
219 DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
221 ProxyConfig config;
222 config.set_pac_url(GURL("http://custom/proxy.pac"));
224 rules.AddFailDownloadRule("http://custom/proxy.pac");
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());
234 // Check the NetLog was filled correctly.
235 CapturingNetLog::CapturedEntryList entries;
236 log.GetEntries(&entries);
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));
248 EXPECT_FALSE(decider.effective_config().has_pac_url());
251 // Fail parsing the custom PAC script.
252 TEST(ProxyScriptDeciderTest, CustomPacFails2) {
253 Rules rules;
254 RuleBasedProxyScriptFetcher fetcher(&rules);
255 DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
257 ProxyConfig config;
258 config.set_pac_url(GURL("http://custom/proxy.pac"));
260 rules.AddFailParsingRule("http://custom/proxy.pac");
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());
270 // Fail downloading the custom PAC script, because the fetcher was NULL.
271 TEST(ProxyScriptDeciderTest, HasNullProxyScriptFetcher) {
272 Rules rules;
273 DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
275 ProxyConfig config;
276 config.set_pac_url(GURL("http://custom/proxy.pac"));
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());
286 // Succeeds in choosing autodetect (WPAD DNS).
287 TEST(ProxyScriptDeciderTest, AutodetectSuccess) {
288 Rules rules;
289 RuleBasedProxyScriptFetcher fetcher(&rules);
290 DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
292 ProxyConfig config;
293 config.set_auto_detect(true);
295 Rules::Rule rule = rules.AddSuccessRule("http://wpad/wpad.dat");
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());
303 EXPECT_TRUE(decider.effective_config().has_pac_url());
304 EXPECT_EQ(rule.url, decider.effective_config().pac_url());
307 class ProxyScriptDeciderQuickCheckTest : public ::testing::Test {
308 public:
309 ProxyScriptDeciderQuickCheckTest()
310 : rule_(rules_.AddSuccessRule("http://wpad/wpad.dat")),
311 fetcher_(&rules_) { }
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));
320 int StartDecider() {
321 return decider_->Start(config_, base::TimeDelta(), true,
322 callback_.callback());
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_;
335 private:
336 URLRequestContext request_context_;
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");
344 EXPECT_EQ(OK, StartDecider());
345 EXPECT_EQ(rule_.text(), decider_->script_data()->utf16());
347 EXPECT_TRUE(decider_->effective_config().has_pac_url());
348 EXPECT_EQ(rule_.url, decider_->effective_config().pac_url());
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");
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());
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());
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());
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);
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);
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());
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;
437 ProxyConfig config;
438 config.set_auto_detect(true);
439 config.set_pac_url(GURL("http://custom/proxy.pac"));
441 rules.AddFailDownloadRule("http://wpad/wpad.dat");
442 Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac");
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());
450 EXPECT_TRUE(decider.effective_config().has_pac_url());
451 EXPECT_EQ(rule.url, decider.effective_config().pac_url());
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;
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");
466 rules.AddFailParsingRule("http://wpad/wpad.dat");
467 Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac");
469 TestCompletionCallback callback;
470 CapturingNetLog log;
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());
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"))));
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);
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));
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;
525 ProxyConfig config;
526 config.set_auto_detect(true);
527 config.set_pac_url(GURL("http://custom/proxy.pac"));
529 rules.AddFailDownloadRule("http://wpad/wpad.dat");
530 rules.AddFailDownloadRule("http://custom/proxy.pac");
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());
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;
546 ProxyConfig config;
547 config.set_auto_detect(true);
548 config.set_pac_url(GURL("http://custom/proxy.pac"));
550 rules.AddFailDownloadRule("http://wpad/wpad.dat");
551 rules.AddFailParsingRule("http://custom/proxy.pac");
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());
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;
569 ProxyConfig config;
570 config.set_pac_url(GURL("http://custom/proxy.pac"));
572 rules.AddFailDownloadRule("http://custom/proxy.pac");
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()));
581 EXPECT_EQ(kFailedDownloading, callback.WaitForResult());
582 EXPECT_EQ(NULL, decider.script_data());
584 // Check the NetLog was filled correctly.
585 CapturingNetLog::CapturedEntryList entries;
586 log.GetEntries(&entries);
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));
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;
611 ProxyConfig config;
612 config.set_pac_url(GURL("http://custom/proxy.pac"));
614 rules.AddFailDownloadRule("http://custom/proxy.pac");
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());
624 // Check the NetLog was filled correctly.
625 CapturingNetLog::CapturedEntryList entries;
626 log.GetEntries(&entries);
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));
639 class SynchronousSuccessDhcpFetcher : public DhcpProxyScriptFetcher {
640 public:
641 explicit SynchronousSuccessDhcpFetcher(const base::string16& expected_text)
642 : gurl_("http://dhcppac/"), expected_text_(expected_text) {
645 int Fetch(base::string16* utf16_text,
646 const CompletionCallback& callback) override {
647 *utf16_text = expected_text_;
648 return OK;
651 void Cancel() override {}
653 const GURL& GetPacURL() const override { return gurl_; }
655 const base::string16& expected_text() const {
656 return expected_text_;
659 private:
660 GURL gurl_;
661 base::string16 expected_text_;
663 DISALLOW_COPY_AND_ASSIGN(SynchronousSuccessDhcpFetcher);
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.
671 TEST(ProxyScriptDeciderTest, AutodetectDhcpSuccess) {
672 Rules rules;
673 RuleBasedProxyScriptFetcher fetcher(&rules);
674 SynchronousSuccessDhcpFetcher dhcp_fetcher(
675 base::WideToUTF16(L"http://bingo/!FindProxyForURL"));
677 ProxyConfig config;
678 config.set_auto_detect(true);
680 rules.AddSuccessRule("http://bingo/");
681 rules.AddFailDownloadRule("http://wpad/wpad.dat");
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());
690 EXPECT_TRUE(decider.effective_config().has_pac_url());
691 EXPECT_EQ(GURL("http://dhcppac/"), decider.effective_config().pac_url());
694 TEST(ProxyScriptDeciderTest, AutodetectDhcpFailParse) {
695 Rules rules;
696 RuleBasedProxyScriptFetcher fetcher(&rules);
697 SynchronousSuccessDhcpFetcher dhcp_fetcher(
698 base::WideToUTF16(L"http://bingo/!invalid-script"));
700 ProxyConfig config;
701 config.set_auto_detect(true);
703 rules.AddFailParsingRule("http://bingo/");
704 rules.AddFailDownloadRule("http://wpad/wpad.dat");
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());
714 EXPECT_FALSE(decider.effective_config().has_pac_url());
717 class AsyncFailDhcpFetcher
718 : public DhcpProxyScriptFetcher,
719 public base::SupportsWeakPtr<AsyncFailDhcpFetcher> {
720 public:
721 AsyncFailDhcpFetcher() {}
722 ~AsyncFailDhcpFetcher() override {}
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;
733 void Cancel() override { callback_.Reset(); }
735 const GURL& GetPacURL() const override { return dummy_gurl_; }
737 void CallbackWithFailure() {
738 if (!callback_.is_null())
739 callback_.Run(ERR_PAC_NOT_IN_DHCP);
742 private:
743 GURL dummy_gurl_;
744 CompletionCallback callback_;
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);
755 scoped_ptr<AsyncFailDhcpFetcher> dhcp_fetcher(new AsyncFailDhcpFetcher());
757 ProxyConfig config;
758 config.set_auto_detect(true);
759 rules.AddFailDownloadRule("http://wpad/wpad.dat");
761 TestCompletionCallback callback;
763 // Scope so ProxyScriptDecider gets destroyed early.
765 ProxyScriptDecider decider(&fetcher, dhcp_fetcher.get(), NULL);
766 decider.Start(config, base::TimeDelta(), true, callback.callback());
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();
776 } // namespace
777 } // namespace net