proxy_script_decider_unittest.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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.h"
10#include "base/string_util.h"
11#include "base/time.h"
12#include "base/utf_string_conversions.h"
13#include "net/base/net_errors.h"
14#include "net/base/net_log.h"
15#include "net/base/net_log_unittest.h"
16#include "net/base/test_completion_callback.h"
17#include "net/proxy/dhcp_proxy_script_fetcher.h"
18#include "net/proxy/proxy_config.h"
19#include "net/proxy/proxy_resolver.h"
20#include "net/proxy/proxy_script_decider.h"
21#include "net/proxy/proxy_script_fetcher.h"
22#include "testing/gtest/include/gtest/gtest.h"
23
24namespace net {
25namespace {
26
27enum Error {
28  kFailedDownloading = -100,
29  kFailedParsing = ERR_PAC_SCRIPT_FAILED,
30};
31
32class Rules {
33 public:
34  struct Rule {
35    Rule(const GURL& url, int fetch_error, bool is_valid_script)
36        : url(url),
37          fetch_error(fetch_error),
38          is_valid_script(is_valid_script) {
39    }
40
41    string16 text() const {
42      if (is_valid_script)
43        return UTF8ToUTF16(url.spec() + "!FindProxyForURL");
44      if (fetch_error == OK)
45        return UTF8ToUTF16(url.spec() + "!invalid-script");
46      return string16();
47    }
48
49    GURL url;
50    int fetch_error;
51    bool is_valid_script;
52  };
53
54  Rule AddSuccessRule(const char* url) {
55    Rule rule(GURL(url), OK /*fetch_error*/, true);
56    rules_.push_back(rule);
57    return rule;
58  }
59
60  void AddFailDownloadRule(const char* url) {
61    rules_.push_back(Rule(GURL(url), kFailedDownloading /*fetch_error*/,
62        false));
63  }
64
65  void AddFailParsingRule(const char* url) {
66    rules_.push_back(Rule(GURL(url), OK /*fetch_error*/, false));
67  }
68
69  const Rule& GetRuleByUrl(const GURL& url) const {
70    for (RuleList::const_iterator it = rules_.begin(); it != rules_.end();
71         ++it) {
72      if (it->url == url)
73        return *it;
74    }
75    LOG(FATAL) << "Rule not found for " << url;
76    return rules_[0];
77  }
78
79  const Rule& GetRuleByText(const string16& text) const {
80    for (RuleList::const_iterator it = rules_.begin(); it != rules_.end();
81         ++it) {
82      if (it->text() == text)
83        return *it;
84    }
85    LOG(FATAL) << "Rule not found for " << text;
86    return rules_[0];
87  }
88
89 private:
90  typedef std::vector<Rule> RuleList;
91  RuleList rules_;
92};
93
94class RuleBasedProxyScriptFetcher : public ProxyScriptFetcher {
95 public:
96  explicit RuleBasedProxyScriptFetcher(const Rules* rules) : rules_(rules) {}
97
98  // ProxyScriptFetcher implementation.
99  virtual int Fetch(const GURL& url,
100                    string16* text,
101                    const CompletionCallback& callback) {
102    const Rules::Rule& rule = rules_->GetRuleByUrl(url);
103    int rv = rule.fetch_error;
104    EXPECT_NE(ERR_UNEXPECTED, rv);
105    if (rv == OK)
106      *text = rule.text();
107    return rv;
108  }
109
110  virtual void Cancel() {}
111
112  virtual URLRequestContext* GetRequestContext() const { return NULL; }
113
114 private:
115  const Rules* rules_;
116};
117
118// Succeed using custom PAC script.
119TEST(ProxyScriptDeciderTest, CustomPacSucceeds) {
120  Rules rules;
121  RuleBasedProxyScriptFetcher fetcher(&rules);
122  DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
123
124  ProxyConfig config;
125  config.set_pac_url(GURL("http://custom/proxy.pac"));
126
127  Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac");
128
129  TestCompletionCallback callback;
130  CapturingNetLog log;
131  ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, &log);
132  EXPECT_EQ(OK, decider.Start(
133      config, base::TimeDelta(), true, callback.callback()));
134  EXPECT_EQ(rule.text(), decider.script_data()->utf16());
135
136  // Check the NetLog was filled correctly.
137  CapturingNetLog::CapturedEntryList entries;
138  log.GetEntries(&entries);
139
140  EXPECT_EQ(4u, entries.size());
141  EXPECT_TRUE(LogContainsBeginEvent(
142      entries, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
143  EXPECT_TRUE(LogContainsBeginEvent(
144      entries, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
145  EXPECT_TRUE(LogContainsEndEvent(
146      entries, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
147  EXPECT_TRUE(LogContainsEndEvent(
148      entries, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
149
150  EXPECT_TRUE(decider.effective_config().has_pac_url());
151  EXPECT_EQ(config.pac_url(), decider.effective_config().pac_url());
152}
153
154// Fail downloading the custom PAC script.
155TEST(ProxyScriptDeciderTest, CustomPacFails1) {
156  Rules rules;
157  RuleBasedProxyScriptFetcher fetcher(&rules);
158  DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
159
160  ProxyConfig config;
161  config.set_pac_url(GURL("http://custom/proxy.pac"));
162
163  rules.AddFailDownloadRule("http://custom/proxy.pac");
164
165  TestCompletionCallback callback;
166  CapturingNetLog log;
167  ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, &log);
168  EXPECT_EQ(kFailedDownloading,
169            decider.Start(config, base::TimeDelta(), true,
170                          callback.callback()));
171  EXPECT_EQ(NULL, decider.script_data());
172
173  // Check the NetLog was filled correctly.
174  CapturingNetLog::CapturedEntryList entries;
175  log.GetEntries(&entries);
176
177  EXPECT_EQ(4u, entries.size());
178  EXPECT_TRUE(LogContainsBeginEvent(
179      entries, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
180  EXPECT_TRUE(LogContainsBeginEvent(
181      entries, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
182  EXPECT_TRUE(LogContainsEndEvent(
183      entries, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
184  EXPECT_TRUE(LogContainsEndEvent(
185      entries, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
186
187  EXPECT_FALSE(decider.effective_config().has_pac_url());
188}
189
190// Fail parsing the custom PAC script.
191TEST(ProxyScriptDeciderTest, CustomPacFails2) {
192  Rules rules;
193  RuleBasedProxyScriptFetcher fetcher(&rules);
194  DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
195
196  ProxyConfig config;
197  config.set_pac_url(GURL("http://custom/proxy.pac"));
198
199  rules.AddFailParsingRule("http://custom/proxy.pac");
200
201  TestCompletionCallback callback;
202  ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, NULL);
203  EXPECT_EQ(kFailedParsing,
204            decider.Start(config, base::TimeDelta(), true,
205                          callback.callback()));
206  EXPECT_EQ(NULL, decider.script_data());
207}
208
209// Fail downloading the custom PAC script, because the fetcher was NULL.
210TEST(ProxyScriptDeciderTest, HasNullProxyScriptFetcher) {
211  Rules rules;
212  DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
213
214  ProxyConfig config;
215  config.set_pac_url(GURL("http://custom/proxy.pac"));
216
217  TestCompletionCallback callback;
218  ProxyScriptDecider decider(NULL, &dhcp_fetcher, NULL);
219  EXPECT_EQ(ERR_UNEXPECTED,
220            decider.Start(config, base::TimeDelta(), true,
221                          callback.callback()));
222  EXPECT_EQ(NULL, decider.script_data());
223}
224
225// Succeeds in choosing autodetect (WPAD DNS).
226TEST(ProxyScriptDeciderTest, AutodetectSuccess) {
227  Rules rules;
228  RuleBasedProxyScriptFetcher fetcher(&rules);
229  DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
230
231  ProxyConfig config;
232  config.set_auto_detect(true);
233
234  Rules::Rule rule = rules.AddSuccessRule("http://wpad/wpad.dat");
235
236  TestCompletionCallback callback;
237  ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, NULL);
238  EXPECT_EQ(OK, decider.Start(
239      config, base::TimeDelta(), true, callback.callback()));
240  EXPECT_EQ(rule.text(), decider.script_data()->utf16());
241
242  EXPECT_TRUE(decider.effective_config().has_pac_url());
243  EXPECT_EQ(rule.url, decider.effective_config().pac_url());
244}
245
246// Fails at WPAD (downloading), but succeeds in choosing the custom PAC.
247TEST(ProxyScriptDeciderTest, AutodetectFailCustomSuccess1) {
248  Rules rules;
249  RuleBasedProxyScriptFetcher fetcher(&rules);
250  DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
251
252  ProxyConfig config;
253  config.set_auto_detect(true);
254  config.set_pac_url(GURL("http://custom/proxy.pac"));
255
256  rules.AddFailDownloadRule("http://wpad/wpad.dat");
257  Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac");
258
259  TestCompletionCallback callback;
260  ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, NULL);
261  EXPECT_EQ(OK, decider.Start(
262      config, base::TimeDelta(), true, callback.callback()));
263  EXPECT_EQ(rule.text(), decider.script_data()->utf16());
264
265  EXPECT_TRUE(decider.effective_config().has_pac_url());
266  EXPECT_EQ(rule.url, decider.effective_config().pac_url());
267}
268
269// Fails at WPAD (no DHCP config, DNS PAC fails parsing), but succeeds in
270// choosing the custom PAC.
271TEST(ProxyScriptDeciderTest, AutodetectFailCustomSuccess2) {
272  Rules rules;
273  RuleBasedProxyScriptFetcher fetcher(&rules);
274  DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
275
276  ProxyConfig config;
277  config.set_auto_detect(true);
278  config.set_pac_url(GURL("http://custom/proxy.pac"));
279  config.proxy_rules().ParseFromString("unused-manual-proxy:99");
280
281  rules.AddFailParsingRule("http://wpad/wpad.dat");
282  Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac");
283
284  TestCompletionCallback callback;
285  CapturingNetLog log;
286
287  ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, &log);
288  EXPECT_EQ(OK, decider.Start(config, base::TimeDelta(),
289                          true, callback.callback()));
290  EXPECT_EQ(rule.text(), decider.script_data()->utf16());
291
292  // Verify that the effective configuration no longer contains auto detect or
293  // any of the manual settings.
294  EXPECT_TRUE(decider.effective_config().Equals(
295      ProxyConfig::CreateFromCustomPacURL(GURL("http://custom/proxy.pac"))));
296
297  // Check the NetLog was filled correctly.
298  // (Note that various states are repeated since both WPAD and custom
299  // PAC scripts are tried).
300  CapturingNetLog::CapturedEntryList entries;
301  log.GetEntries(&entries);
302
303  EXPECT_EQ(10u, entries.size());
304  EXPECT_TRUE(LogContainsBeginEvent(
305      entries, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
306  // This is the DHCP phase, which fails fetching rather than parsing, so
307  // there is no pair of SET_PAC_SCRIPT events.
308  EXPECT_TRUE(LogContainsBeginEvent(
309      entries, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
310  EXPECT_TRUE(LogContainsEndEvent(
311      entries, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
312  EXPECT_TRUE(LogContainsEvent(
313      entries, 3,
314      NetLog::TYPE_PROXY_SCRIPT_DECIDER_FALLING_BACK_TO_NEXT_PAC_SOURCE,
315      NetLog::PHASE_NONE));
316  // This is the DNS phase, which attempts a fetch but fails.
317  EXPECT_TRUE(LogContainsBeginEvent(
318      entries, 4, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
319  EXPECT_TRUE(LogContainsEndEvent(
320      entries, 5, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
321  EXPECT_TRUE(LogContainsEvent(
322      entries, 6,
323      NetLog::TYPE_PROXY_SCRIPT_DECIDER_FALLING_BACK_TO_NEXT_PAC_SOURCE,
324      NetLog::PHASE_NONE));
325  // Finally, the custom PAC URL phase.
326  EXPECT_TRUE(LogContainsBeginEvent(
327      entries, 7, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
328  EXPECT_TRUE(LogContainsEndEvent(
329      entries, 8, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
330  EXPECT_TRUE(LogContainsEndEvent(
331      entries, 9, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
332}
333
334// Fails at WPAD (downloading), and fails at custom PAC (downloading).
335TEST(ProxyScriptDeciderTest, AutodetectFailCustomFails1) {
336  Rules rules;
337  RuleBasedProxyScriptFetcher fetcher(&rules);
338  DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
339
340  ProxyConfig config;
341  config.set_auto_detect(true);
342  config.set_pac_url(GURL("http://custom/proxy.pac"));
343
344  rules.AddFailDownloadRule("http://wpad/wpad.dat");
345  rules.AddFailDownloadRule("http://custom/proxy.pac");
346
347  TestCompletionCallback callback;
348  ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, NULL);
349  EXPECT_EQ(kFailedDownloading,
350            decider.Start(config, base::TimeDelta(), true,
351                          callback.callback()));
352  EXPECT_EQ(NULL, decider.script_data());
353}
354
355// Fails at WPAD (downloading), and fails at custom PAC (parsing).
356TEST(ProxyScriptDeciderTest, AutodetectFailCustomFails2) {
357  Rules rules;
358  RuleBasedProxyScriptFetcher fetcher(&rules);
359  DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
360
361  ProxyConfig config;
362  config.set_auto_detect(true);
363  config.set_pac_url(GURL("http://custom/proxy.pac"));
364
365  rules.AddFailDownloadRule("http://wpad/wpad.dat");
366  rules.AddFailParsingRule("http://custom/proxy.pac");
367
368  TestCompletionCallback callback;
369  ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, NULL);
370  EXPECT_EQ(kFailedParsing,
371            decider.Start(config, base::TimeDelta(), true,
372                          callback.callback()));
373  EXPECT_EQ(NULL, decider.script_data());
374}
375
376// This is a copy-paste of CustomPacFails1, with the exception that we give it
377// a 1 millisecond delay. This means it will now complete asynchronously.
378// Moreover, we test the NetLog to make sure it logged the pause.
379TEST(ProxyScriptDeciderTest, CustomPacFails1_WithPositiveDelay) {
380  Rules rules;
381  RuleBasedProxyScriptFetcher fetcher(&rules);
382  DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
383
384  ProxyConfig config;
385  config.set_pac_url(GURL("http://custom/proxy.pac"));
386
387  rules.AddFailDownloadRule("http://custom/proxy.pac");
388
389  TestCompletionCallback callback;
390  CapturingNetLog log;
391  ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, &log);
392  EXPECT_EQ(ERR_IO_PENDING,
393            decider.Start(config, base::TimeDelta::FromMilliseconds(1),
394                      true, callback.callback()));
395
396  EXPECT_EQ(kFailedDownloading, callback.WaitForResult());
397  EXPECT_EQ(NULL, decider.script_data());
398
399  // Check the NetLog was filled correctly.
400  CapturingNetLog::CapturedEntryList entries;
401  log.GetEntries(&entries);
402
403  EXPECT_EQ(6u, entries.size());
404  EXPECT_TRUE(LogContainsBeginEvent(
405      entries, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
406  EXPECT_TRUE(LogContainsBeginEvent(
407      entries, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT));
408  EXPECT_TRUE(LogContainsEndEvent(
409      entries, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT));
410  EXPECT_TRUE(LogContainsBeginEvent(
411      entries, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
412  EXPECT_TRUE(LogContainsEndEvent(
413      entries, 4, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
414  EXPECT_TRUE(LogContainsEndEvent(
415      entries, 5, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
416}
417
418// This is a copy-paste of CustomPacFails1, with the exception that we give it
419// a -5 second delay instead of a 0 ms delay. This change should have no effect
420// so the rest of the test is unchanged.
421TEST(ProxyScriptDeciderTest, CustomPacFails1_WithNegativeDelay) {
422  Rules rules;
423  RuleBasedProxyScriptFetcher fetcher(&rules);
424  DoNothingDhcpProxyScriptFetcher dhcp_fetcher;
425
426  ProxyConfig config;
427  config.set_pac_url(GURL("http://custom/proxy.pac"));
428
429  rules.AddFailDownloadRule("http://custom/proxy.pac");
430
431  TestCompletionCallback callback;
432  CapturingNetLog log;
433  ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, &log);
434  EXPECT_EQ(kFailedDownloading,
435            decider.Start(config, base::TimeDelta::FromSeconds(-5),
436                          true, callback.callback()));
437  EXPECT_EQ(NULL, decider.script_data());
438
439  // Check the NetLog was filled correctly.
440  CapturingNetLog::CapturedEntryList entries;
441  log.GetEntries(&entries);
442
443  EXPECT_EQ(4u, entries.size());
444  EXPECT_TRUE(LogContainsBeginEvent(
445      entries, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
446  EXPECT_TRUE(LogContainsBeginEvent(
447      entries, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
448  EXPECT_TRUE(LogContainsEndEvent(
449      entries, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
450  EXPECT_TRUE(LogContainsEndEvent(
451      entries, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
452}
453
454class SynchronousSuccessDhcpFetcher : public DhcpProxyScriptFetcher {
455 public:
456  explicit SynchronousSuccessDhcpFetcher(const string16& expected_text)
457      : gurl_("http://dhcppac/"), expected_text_(expected_text) {
458  }
459
460  int Fetch(string16* utf16_text, const CompletionCallback& callback) OVERRIDE {
461    *utf16_text = expected_text_;
462    return OK;
463  }
464
465  void Cancel() OVERRIDE {
466  }
467
468  const GURL& GetPacURL() const OVERRIDE {
469    return gurl_;
470  }
471
472  const string16& expected_text() const {
473    return expected_text_;
474  }
475
476 private:
477  GURL gurl_;
478  string16 expected_text_;
479
480  DISALLOW_COPY_AND_ASSIGN(SynchronousSuccessDhcpFetcher);
481};
482
483// All of the tests above that use ProxyScriptDecider have tested
484// failure to fetch a PAC file via DHCP configuration, so we now test
485// success at downloading and parsing, and then success at downloading,
486// failure at parsing.
487
488TEST(ProxyScriptDeciderTest, AutodetectDhcpSuccess) {
489  Rules rules;
490  RuleBasedProxyScriptFetcher fetcher(&rules);
491  SynchronousSuccessDhcpFetcher dhcp_fetcher(
492      WideToUTF16(L"http://bingo/!FindProxyForURL"));
493
494  ProxyConfig config;
495  config.set_auto_detect(true);
496
497  rules.AddSuccessRule("http://bingo/");
498  rules.AddFailDownloadRule("http://wpad/wpad.dat");
499
500  TestCompletionCallback callback;
501  ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, NULL);
502  EXPECT_EQ(OK, decider.Start(
503      config, base::TimeDelta(), true, callback.callback()));
504  EXPECT_EQ(dhcp_fetcher.expected_text(),
505            decider.script_data()->utf16());
506
507  EXPECT_TRUE(decider.effective_config().has_pac_url());
508  EXPECT_EQ(GURL("http://dhcppac/"), decider.effective_config().pac_url());
509}
510
511TEST(ProxyScriptDeciderTest, AutodetectDhcpFailParse) {
512  Rules rules;
513  RuleBasedProxyScriptFetcher fetcher(&rules);
514  SynchronousSuccessDhcpFetcher dhcp_fetcher(
515      WideToUTF16(L"http://bingo/!invalid-script"));
516
517  ProxyConfig config;
518  config.set_auto_detect(true);
519
520  rules.AddFailParsingRule("http://bingo/");
521  rules.AddFailDownloadRule("http://wpad/wpad.dat");
522
523  TestCompletionCallback callback;
524  ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, NULL);
525  // Since there is fallback to DNS-based WPAD, the final error will be that
526  // it failed downloading, not that it failed parsing.
527  EXPECT_EQ(kFailedDownloading,
528      decider.Start(config, base::TimeDelta(), true, callback.callback()));
529  EXPECT_EQ(NULL, decider.script_data());
530
531  EXPECT_FALSE(decider.effective_config().has_pac_url());
532}
533
534class AsyncFailDhcpFetcher
535    : public DhcpProxyScriptFetcher,
536      public base::SupportsWeakPtr<AsyncFailDhcpFetcher> {
537 public:
538  AsyncFailDhcpFetcher() {}
539  ~AsyncFailDhcpFetcher() {}
540
541  int Fetch(string16* utf16_text, const CompletionCallback& callback) OVERRIDE {
542    callback_ = callback;
543    MessageLoop::current()->PostTask(
544        FROM_HERE,
545        base::Bind(&AsyncFailDhcpFetcher::CallbackWithFailure, AsWeakPtr()));
546    return ERR_IO_PENDING;
547  }
548
549  void Cancel() OVERRIDE {
550    callback_.Reset();
551  }
552
553  const GURL& GetPacURL() const OVERRIDE {
554    return dummy_gurl_;
555  }
556
557  void CallbackWithFailure() {
558    if (!callback_.is_null())
559      callback_.Run(ERR_PAC_NOT_IN_DHCP);
560  }
561
562 private:
563  GURL dummy_gurl_;
564  CompletionCallback callback_;
565};
566
567TEST(ProxyScriptDeciderTest, DhcpCancelledByDestructor) {
568  // This regression test would crash before
569  // http://codereview.chromium.org/7044058/
570  // Thus, we don't care much about actual results (hence no EXPECT or ASSERT
571  // macros below), just that it doesn't crash.
572  Rules rules;
573  RuleBasedProxyScriptFetcher fetcher(&rules);
574
575  scoped_ptr<AsyncFailDhcpFetcher> dhcp_fetcher(new AsyncFailDhcpFetcher());
576
577  ProxyConfig config;
578  config.set_auto_detect(true);
579  rules.AddFailDownloadRule("http://wpad/wpad.dat");
580
581  TestCompletionCallback callback;
582
583  // Scope so ProxyScriptDecider gets destroyed early.
584  {
585    ProxyScriptDecider decider(&fetcher, dhcp_fetcher.get(), NULL);
586    decider.Start(config, base::TimeDelta(), true, callback.callback());
587  }
588
589  // Run the message loop to let the DHCP fetch complete and post the results
590  // back. Before the fix linked to above, this would try to invoke on
591  // the callback object provided by ProxyScriptDecider after it was
592  // no longer valid.
593  MessageLoop::current()->RunAllPending();
594}
595
596}  // namespace
597}  // namespace net
598