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.
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/test_completion_callback.h"
16 #include "net/dns/mock_host_resolver.h"
17 #include "net/log/net_log.h"
18 #include "net/log/net_log_unittest.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"
32 kFailedDownloading
= -100,
33 kFailedParsing
= ERR_PAC_SCRIPT_FAILED
,
39 Rule(const GURL
& url
, int fetch_error
, bool is_valid_script
)
41 fetch_error(fetch_error
),
42 is_valid_script(is_valid_script
) {
45 base::string16
text() const {
47 return base::UTF8ToUTF16(url
.spec() + "!FindProxyForURL");
48 if (fetch_error
== OK
)
49 return base::UTF8ToUTF16(url
.spec() + "!invalid-script");
50 return base::string16();
58 Rule
AddSuccessRule(const char* url
) {
59 Rule
rule(GURL(url
), OK
/*fetch_error*/, true);
60 rules_
.push_back(rule
);
64 void AddFailDownloadRule(const char* url
) {
65 rules_
.push_back(Rule(GURL(url
), kFailedDownloading
/*fetch_error*/,
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();
79 LOG(FATAL
) << "Rule not found for " << url
;
83 const Rule
& GetRuleByText(const base::string16
& text
) const {
84 for (RuleList::const_iterator it
= rules_
.begin(); it
!= rules_
.end();
86 if (it
->text() == text
)
89 LOG(FATAL
) << "Rule not found for " << text
;
94 typedef std::vector
<Rule
> RuleList
;
98 class RuleBasedProxyScriptFetcher
: public ProxyScriptFetcher
{
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
);
119 void Cancel() override
{}
121 URLRequestContext
* GetRequestContext() const override
{
122 return request_context_
;
127 URLRequestContext
* request_context_
;
130 // A mock retriever, returns asynchronously when CompleteRequests() is called.
131 class MockDhcpProxyScriptFetcher
: public DhcpProxyScriptFetcher
{
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
);
146 CompletionCallback callback_
;
147 base::string16
* utf16_text_
;
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 {
169 void MockDhcpProxyScriptFetcher::SetPacURL(const 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
) {
182 RuleBasedProxyScriptFetcher
fetcher(&rules
);
183 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
186 config
.set_pac_url(GURL("http://custom/proxy.pac"));
188 Rules::Rule rule
= rules
.AddSuccessRule("http://custom/proxy.pac");
190 TestCompletionCallback callback
;
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 TestNetLog::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
) {
218 RuleBasedProxyScriptFetcher
fetcher(&rules
);
219 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
222 config
.set_pac_url(GURL("http://custom/proxy.pac"));
224 rules
.AddFailDownloadRule("http://custom/proxy.pac");
226 TestCompletionCallback callback
;
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 TestNetLog::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
) {
254 RuleBasedProxyScriptFetcher
fetcher(&rules
);
255 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
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
) {
273 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
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
) {
289 RuleBasedProxyScriptFetcher
fetcher(&rules
);
290 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
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
{
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
));
321 return decider_
->Start(config_
, base::TimeDelta(), true,
322 callback_
.callback());
326 scoped_ptr
<ProxyScriptDecider
> decider_
;
327 MockHostResolver resolver_
;
330 TestCompletionCallback callback_
;
331 RuleBasedProxyScriptFetcher fetcher_
;
333 DoNothingDhcpProxyScriptFetcher dhcp_fetcher_
;
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
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
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 // Regression test for http://crbug.com/409698.
432 // This test lets the state machine get into state QUICK_CHECK_COMPLETE, then
433 // destroys the decider, causing a cancel.
434 TEST_F(ProxyScriptDeciderQuickCheckTest
, CancelPartway
) {
435 resolver_
.set_synchronous_mode(false);
436 resolver_
.set_ondemand_mode(true);
437 EXPECT_EQ(ERR_IO_PENDING
, StartDecider());
438 decider_
.reset(NULL
);
441 // Fails at WPAD (downloading), but succeeds in choosing the custom PAC.
442 TEST(ProxyScriptDeciderTest
, AutodetectFailCustomSuccess1
) {
444 RuleBasedProxyScriptFetcher
fetcher(&rules
);
445 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
448 config
.set_auto_detect(true);
449 config
.set_pac_url(GURL("http://custom/proxy.pac"));
451 rules
.AddFailDownloadRule("http://wpad/wpad.dat");
452 Rules::Rule rule
= rules
.AddSuccessRule("http://custom/proxy.pac");
454 TestCompletionCallback callback
;
455 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, NULL
);
456 EXPECT_EQ(OK
, decider
.Start(
457 config
, base::TimeDelta(), true, callback
.callback()));
458 EXPECT_EQ(rule
.text(), decider
.script_data()->utf16());
460 EXPECT_TRUE(decider
.effective_config().has_pac_url());
461 EXPECT_EQ(rule
.url
, decider
.effective_config().pac_url());
464 // Fails at WPAD (no DHCP config, DNS PAC fails parsing), but succeeds in
465 // choosing the custom PAC.
466 TEST(ProxyScriptDeciderTest
, AutodetectFailCustomSuccess2
) {
468 RuleBasedProxyScriptFetcher
fetcher(&rules
);
469 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
472 config
.set_auto_detect(true);
473 config
.set_pac_url(GURL("http://custom/proxy.pac"));
474 config
.proxy_rules().ParseFromString("unused-manual-proxy:99");
476 rules
.AddFailParsingRule("http://wpad/wpad.dat");
477 Rules::Rule rule
= rules
.AddSuccessRule("http://custom/proxy.pac");
479 TestCompletionCallback callback
;
482 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, &log
);
483 EXPECT_EQ(OK
, decider
.Start(config
, base::TimeDelta(),
484 true, callback
.callback()));
485 EXPECT_EQ(rule
.text(), decider
.script_data()->utf16());
487 // Verify that the effective configuration no longer contains auto detect or
488 // any of the manual settings.
489 EXPECT_TRUE(decider
.effective_config().Equals(
490 ProxyConfig::CreateFromCustomPacURL(GURL("http://custom/proxy.pac"))));
492 // Check the NetLog was filled correctly.
493 // (Note that various states are repeated since both WPAD and custom
494 // PAC scripts are tried).
495 TestNetLog::CapturedEntryList entries
;
496 log
.GetEntries(&entries
);
498 EXPECT_EQ(10u, entries
.size());
499 EXPECT_TRUE(LogContainsBeginEvent(
500 entries
, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
501 // This is the DHCP phase, which fails fetching rather than parsing, so
502 // there is no pair of SET_PAC_SCRIPT events.
503 EXPECT_TRUE(LogContainsBeginEvent(
504 entries
, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
505 EXPECT_TRUE(LogContainsEndEvent(
506 entries
, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
507 EXPECT_TRUE(LogContainsEvent(
509 NetLog::TYPE_PROXY_SCRIPT_DECIDER_FALLING_BACK_TO_NEXT_PAC_SOURCE
,
510 NetLog::PHASE_NONE
));
511 // This is the DNS phase, which attempts a fetch but fails.
512 EXPECT_TRUE(LogContainsBeginEvent(
513 entries
, 4, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
514 EXPECT_TRUE(LogContainsEndEvent(
515 entries
, 5, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
516 EXPECT_TRUE(LogContainsEvent(
518 NetLog::TYPE_PROXY_SCRIPT_DECIDER_FALLING_BACK_TO_NEXT_PAC_SOURCE
,
519 NetLog::PHASE_NONE
));
520 // Finally, the custom PAC URL phase.
521 EXPECT_TRUE(LogContainsBeginEvent(
522 entries
, 7, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
523 EXPECT_TRUE(LogContainsEndEvent(
524 entries
, 8, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
525 EXPECT_TRUE(LogContainsEndEvent(
526 entries
, 9, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
529 // Fails at WPAD (downloading), and fails at custom PAC (downloading).
530 TEST(ProxyScriptDeciderTest
, AutodetectFailCustomFails1
) {
532 RuleBasedProxyScriptFetcher
fetcher(&rules
);
533 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
536 config
.set_auto_detect(true);
537 config
.set_pac_url(GURL("http://custom/proxy.pac"));
539 rules
.AddFailDownloadRule("http://wpad/wpad.dat");
540 rules
.AddFailDownloadRule("http://custom/proxy.pac");
542 TestCompletionCallback callback
;
543 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, NULL
);
544 EXPECT_EQ(kFailedDownloading
,
545 decider
.Start(config
, base::TimeDelta(), true,
546 callback
.callback()));
547 EXPECT_EQ(NULL
, decider
.script_data());
550 // Fails at WPAD (downloading), and fails at custom PAC (parsing).
551 TEST(ProxyScriptDeciderTest
, AutodetectFailCustomFails2
) {
553 RuleBasedProxyScriptFetcher
fetcher(&rules
);
554 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
557 config
.set_auto_detect(true);
558 config
.set_pac_url(GURL("http://custom/proxy.pac"));
560 rules
.AddFailDownloadRule("http://wpad/wpad.dat");
561 rules
.AddFailParsingRule("http://custom/proxy.pac");
563 TestCompletionCallback callback
;
564 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, NULL
);
565 EXPECT_EQ(kFailedParsing
,
566 decider
.Start(config
, base::TimeDelta(), true,
567 callback
.callback()));
568 EXPECT_EQ(NULL
, decider
.script_data());
571 // This is a copy-paste of CustomPacFails1, with the exception that we give it
572 // a 1 millisecond delay. This means it will now complete asynchronously.
573 // Moreover, we test the NetLog to make sure it logged the pause.
574 TEST(ProxyScriptDeciderTest
, CustomPacFails1_WithPositiveDelay
) {
576 RuleBasedProxyScriptFetcher
fetcher(&rules
);
577 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
580 config
.set_pac_url(GURL("http://custom/proxy.pac"));
582 rules
.AddFailDownloadRule("http://custom/proxy.pac");
584 TestCompletionCallback callback
;
586 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, &log
);
587 EXPECT_EQ(ERR_IO_PENDING
,
588 decider
.Start(config
, base::TimeDelta::FromMilliseconds(1),
589 true, callback
.callback()));
591 EXPECT_EQ(kFailedDownloading
, callback
.WaitForResult());
592 EXPECT_EQ(NULL
, decider
.script_data());
594 // Check the NetLog was filled correctly.
595 TestNetLog::CapturedEntryList entries
;
596 log
.GetEntries(&entries
);
598 EXPECT_EQ(6u, entries
.size());
599 EXPECT_TRUE(LogContainsBeginEvent(
600 entries
, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
601 EXPECT_TRUE(LogContainsBeginEvent(
602 entries
, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT
));
603 EXPECT_TRUE(LogContainsEndEvent(
604 entries
, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT
));
605 EXPECT_TRUE(LogContainsBeginEvent(
606 entries
, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
607 EXPECT_TRUE(LogContainsEndEvent(
608 entries
, 4, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
609 EXPECT_TRUE(LogContainsEndEvent(
610 entries
, 5, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
613 // This is a copy-paste of CustomPacFails1, with the exception that we give it
614 // a -5 second delay instead of a 0 ms delay. This change should have no effect
615 // so the rest of the test is unchanged.
616 TEST(ProxyScriptDeciderTest
, CustomPacFails1_WithNegativeDelay
) {
618 RuleBasedProxyScriptFetcher
fetcher(&rules
);
619 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
622 config
.set_pac_url(GURL("http://custom/proxy.pac"));
624 rules
.AddFailDownloadRule("http://custom/proxy.pac");
626 TestCompletionCallback callback
;
628 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, &log
);
629 EXPECT_EQ(kFailedDownloading
,
630 decider
.Start(config
, base::TimeDelta::FromSeconds(-5),
631 true, callback
.callback()));
632 EXPECT_EQ(NULL
, decider
.script_data());
634 // Check the NetLog was filled correctly.
635 TestNetLog::CapturedEntryList entries
;
636 log
.GetEntries(&entries
);
638 EXPECT_EQ(4u, entries
.size());
639 EXPECT_TRUE(LogContainsBeginEvent(
640 entries
, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
641 EXPECT_TRUE(LogContainsBeginEvent(
642 entries
, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
643 EXPECT_TRUE(LogContainsEndEvent(
644 entries
, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
645 EXPECT_TRUE(LogContainsEndEvent(
646 entries
, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
649 class SynchronousSuccessDhcpFetcher
: public DhcpProxyScriptFetcher
{
651 explicit SynchronousSuccessDhcpFetcher(const base::string16
& expected_text
)
652 : gurl_("http://dhcppac/"), expected_text_(expected_text
) {
655 int Fetch(base::string16
* utf16_text
,
656 const CompletionCallback
& callback
) override
{
657 *utf16_text
= expected_text_
;
661 void Cancel() override
{}
663 const GURL
& GetPacURL() const override
{ return gurl_
; }
665 const base::string16
& expected_text() const {
666 return expected_text_
;
671 base::string16 expected_text_
;
673 DISALLOW_COPY_AND_ASSIGN(SynchronousSuccessDhcpFetcher
);
676 // All of the tests above that use ProxyScriptDecider have tested
677 // failure to fetch a PAC file via DHCP configuration, so we now test
678 // success at downloading and parsing, and then success at downloading,
679 // failure at parsing.
681 TEST(ProxyScriptDeciderTest
, AutodetectDhcpSuccess
) {
683 RuleBasedProxyScriptFetcher
fetcher(&rules
);
684 SynchronousSuccessDhcpFetcher
dhcp_fetcher(
685 base::WideToUTF16(L
"http://bingo/!FindProxyForURL"));
688 config
.set_auto_detect(true);
690 rules
.AddSuccessRule("http://bingo/");
691 rules
.AddFailDownloadRule("http://wpad/wpad.dat");
693 TestCompletionCallback callback
;
694 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, NULL
);
695 EXPECT_EQ(OK
, decider
.Start(
696 config
, base::TimeDelta(), true, callback
.callback()));
697 EXPECT_EQ(dhcp_fetcher
.expected_text(),
698 decider
.script_data()->utf16());
700 EXPECT_TRUE(decider
.effective_config().has_pac_url());
701 EXPECT_EQ(GURL("http://dhcppac/"), decider
.effective_config().pac_url());
704 TEST(ProxyScriptDeciderTest
, AutodetectDhcpFailParse
) {
706 RuleBasedProxyScriptFetcher
fetcher(&rules
);
707 SynchronousSuccessDhcpFetcher
dhcp_fetcher(
708 base::WideToUTF16(L
"http://bingo/!invalid-script"));
711 config
.set_auto_detect(true);
713 rules
.AddFailParsingRule("http://bingo/");
714 rules
.AddFailDownloadRule("http://wpad/wpad.dat");
716 TestCompletionCallback callback
;
717 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, NULL
);
718 // Since there is fallback to DNS-based WPAD, the final error will be that
719 // it failed downloading, not that it failed parsing.
720 EXPECT_EQ(kFailedDownloading
,
721 decider
.Start(config
, base::TimeDelta(), true, callback
.callback()));
722 EXPECT_EQ(NULL
, decider
.script_data());
724 EXPECT_FALSE(decider
.effective_config().has_pac_url());
727 class AsyncFailDhcpFetcher
728 : public DhcpProxyScriptFetcher
,
729 public base::SupportsWeakPtr
<AsyncFailDhcpFetcher
> {
731 AsyncFailDhcpFetcher() {}
732 ~AsyncFailDhcpFetcher() override
{}
734 int Fetch(base::string16
* utf16_text
,
735 const CompletionCallback
& callback
) override
{
736 callback_
= callback
;
737 base::MessageLoop::current()->PostTask(
739 base::Bind(&AsyncFailDhcpFetcher::CallbackWithFailure
, AsWeakPtr()));
740 return ERR_IO_PENDING
;
743 void Cancel() override
{ callback_
.Reset(); }
745 const GURL
& GetPacURL() const override
{ return dummy_gurl_
; }
747 void CallbackWithFailure() {
748 if (!callback_
.is_null())
749 callback_
.Run(ERR_PAC_NOT_IN_DHCP
);
754 CompletionCallback callback_
;
757 TEST(ProxyScriptDeciderTest
, DhcpCancelledByDestructor
) {
758 // This regression test would crash before
759 // http://codereview.chromium.org/7044058/
760 // Thus, we don't care much about actual results (hence no EXPECT or ASSERT
761 // macros below), just that it doesn't crash.
763 RuleBasedProxyScriptFetcher
fetcher(&rules
);
765 scoped_ptr
<AsyncFailDhcpFetcher
> dhcp_fetcher(new AsyncFailDhcpFetcher());
768 config
.set_auto_detect(true);
769 rules
.AddFailDownloadRule("http://wpad/wpad.dat");
771 TestCompletionCallback callback
;
773 // Scope so ProxyScriptDecider gets destroyed early.
775 ProxyScriptDecider
decider(&fetcher
, dhcp_fetcher
.get(), NULL
);
776 decider
.Start(config
, base::TimeDelta(), true, callback
.callback());
779 // Run the message loop to let the DHCP fetch complete and post the results
780 // back. Before the fix linked to above, this would try to invoke on
781 // the callback object provided by ProxyScriptDecider after it was
783 base::MessageLoop::current()->RunUntilIdle();