| Index: net/proxy/proxy_service_unittest.cc
 | 
| diff --git a/net/proxy/proxy_service_unittest.cc b/net/proxy/proxy_service_unittest.cc
 | 
| index 0be99f2777ad6562e49918b7ce9f5cad938a98b2..7d794c9929854e6cd931b50243374bdc5a989aaa 100644
 | 
| --- a/net/proxy/proxy_service_unittest.cc
 | 
| +++ b/net/proxy/proxy_service_unittest.cc
 | 
| @@ -28,6 +28,64 @@
 | 
|  namespace net {
 | 
|  namespace {
 | 
|  
 | 
| +// This polling policy will decide to poll every 1 ms.
 | 
| +class ImmediatePollPolicy : public ProxyService::PacPollPolicy {
 | 
| + public:
 | 
| +  ImmediatePollPolicy() {}
 | 
| +
 | 
| +  virtual Mode GetInitialDelay(int error, int64* next_delay_ms) const OVERRIDE {
 | 
| +    *next_delay_ms = 1;
 | 
| +    return MODE_USE_TIMER;
 | 
| +  }
 | 
| +
 | 
| +  virtual Mode GetNextDelay(int64 current_delay_ms,
 | 
| +                            int64* next_delay_ms) const OVERRIDE {
 | 
| +    return GetInitialDelay(OK, next_delay_ms);
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  DISALLOW_COPY_AND_ASSIGN(ImmediatePollPolicy);
 | 
| +};
 | 
| +
 | 
| +// This polling policy chooses a fantastically large delay. In other words, it
 | 
| +// will never trigger a poll
 | 
| +class NeverPollPolicy : public ProxyService::PacPollPolicy {
 | 
| + public:
 | 
| +  NeverPollPolicy() {}
 | 
| +
 | 
| +  virtual Mode GetInitialDelay(int error, int64* next_delay_ms) const OVERRIDE {
 | 
| +    *next_delay_ms = 0xFFFFFFFF;  // Big number of milliseconds!
 | 
| +    return MODE_USE_TIMER;
 | 
| +  }
 | 
| +
 | 
| +  virtual Mode GetNextDelay(int64 current_delay_ms,
 | 
| +                            int64* next_delay_ms) const OVERRIDE {
 | 
| +    return GetInitialDelay(OK, next_delay_ms);
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  DISALLOW_COPY_AND_ASSIGN(NeverPollPolicy);
 | 
| +};
 | 
| +
 | 
| +// This polling policy starts a poll immediately after network activity.
 | 
| +class ImmediateAfterActivityPollPolicy : public ProxyService::PacPollPolicy {
 | 
| + public:
 | 
| +  ImmediateAfterActivityPollPolicy() {}
 | 
| +
 | 
| +  virtual Mode GetInitialDelay(int error, int64* next_delay_ms) const OVERRIDE {
 | 
| +    *next_delay_ms = 0;
 | 
| +    return MODE_START_AFTER_ACTIVITY;
 | 
| +  }
 | 
| +
 | 
| +  virtual Mode GetNextDelay(int64 current_delay_ms,
 | 
| +                            int64* next_delay_ms) const OVERRIDE {
 | 
| +    return GetInitialDelay(OK, next_delay_ms);
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  DISALLOW_COPY_AND_ASSIGN(ImmediateAfterActivityPollPolicy);
 | 
| +};
 | 
| +
 | 
|  // This test fixture is used to partially disable the background polling done by
 | 
|  // the ProxyService (which it uses to detect whenever its PAC script contents or
 | 
|  // WPAD results have changed).
 | 
| @@ -47,8 +105,8 @@ class ProxyServiceTest : public testing::Test {
 | 
|   protected:
 | 
|    virtual void SetUp() OVERRIDE {
 | 
|      testing::Test::SetUp();
 | 
| -    previous_policy_ = ProxyService::set_pac_script_poll_policy(
 | 
| -        ProxyService::POLL_POLICY_NEVER);
 | 
| +    previous_policy_ =
 | 
| +        ProxyService::set_pac_script_poll_policy(&never_poll_policy_);
 | 
|    }
 | 
|  
 | 
|    virtual void TearDown() OVERRIDE {
 | 
| @@ -57,7 +115,9 @@ class ProxyServiceTest : public testing::Test {
 | 
|      testing::Test::TearDown();
 | 
|    }
 | 
|  
 | 
| -  ProxyService::PollPolicy previous_policy_;
 | 
| + private:
 | 
| +  NeverPollPolicy never_poll_policy_;
 | 
| +  const ProxyService::PacPollPolicy* previous_policy_;
 | 
|  };
 | 
|  
 | 
|  const char kValidPacScript1[] = "pac-script-v1-FindProxyForURL";
 | 
| @@ -1956,8 +2016,8 @@ TEST_F(ProxyServiceTest, NetworkChangeTriggersPacRefetch) {
 | 
|  TEST_F(ProxyServiceTest, PACScriptRefetchAfterFailure) {
 | 
|    // Change the retry policy to wait a mere 1 ms before retrying, so the test
 | 
|    // runs quickly.
 | 
| -  ProxyService::set_pac_script_poll_policy(
 | 
| -      ProxyService::POLL_POLICY_IMMEDIATE);
 | 
| +  ImmediatePollPolicy poll_policy;
 | 
| +  ProxyService::set_pac_script_poll_policy(&poll_policy);
 | 
|  
 | 
|    MockProxyConfigService* config_service =
 | 
|        new MockProxyConfigService("http://foopy/proxy.pac");
 | 
| @@ -2063,8 +2123,8 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterFailure) {
 | 
|  TEST_F(ProxyServiceTest, PACScriptRefetchAfterContentChange) {
 | 
|    // Change the retry policy to wait a mere 1 ms before retrying, so the test
 | 
|    // runs quickly.
 | 
| -  ProxyService::set_pac_script_poll_policy(
 | 
| -      ProxyService::POLL_POLICY_IMMEDIATE);
 | 
| +  ImmediatePollPolicy poll_policy;
 | 
| +  ProxyService::set_pac_script_poll_policy(&poll_policy);
 | 
|  
 | 
|    MockProxyConfigService* config_service =
 | 
|        new MockProxyConfigService("http://foopy/proxy.pac");
 | 
| @@ -2175,8 +2235,8 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterContentChange) {
 | 
|  TEST_F(ProxyServiceTest, PACScriptRefetchAfterContentUnchanged) {
 | 
|    // Change the retry policy to wait a mere 1 ms before retrying, so the test
 | 
|    // runs quickly.
 | 
| -  ProxyService::set_pac_script_poll_policy(
 | 
| -      ProxyService::POLL_POLICY_IMMEDIATE);
 | 
| +  ImmediatePollPolicy poll_policy;
 | 
| +  ProxyService::set_pac_script_poll_policy(&poll_policy);
 | 
|  
 | 
|    MockProxyConfigService* config_service =
 | 
|        new MockProxyConfigService("http://foopy/proxy.pac");
 | 
| @@ -2283,8 +2343,8 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterContentUnchanged) {
 | 
|  TEST_F(ProxyServiceTest, PACScriptRefetchAfterSuccess) {
 | 
|    // Change the retry policy to wait a mere 1 ms before retrying, so the test
 | 
|    // runs quickly.
 | 
| -  ProxyService::set_pac_script_poll_policy(
 | 
| -      ProxyService::POLL_POLICY_IMMEDIATE);
 | 
| +  ImmediatePollPolicy poll_policy;
 | 
| +  ProxyService::set_pac_script_poll_policy(&poll_policy);
 | 
|  
 | 
|    MockProxyConfigService* config_service =
 | 
|        new MockProxyConfigService("http://foopy/proxy.pac");
 | 
| @@ -2371,4 +2431,156 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterSuccess) {
 | 
|    EXPECT_TRUE(info2.is_direct());
 | 
|  }
 | 
|  
 | 
| +// Tests that the code which decides at what times to poll the PAC
 | 
| +// script follows the expected policy.
 | 
| +TEST_F(ProxyServiceTest, PACScriptPollingPolicy) {
 | 
| +  // Retrieve the internal polling policy implementation used by ProxyService.
 | 
| +  scoped_ptr<ProxyService::PacPollPolicy> policy =
 | 
| +      ProxyService::CreateDefaultPacPollPolicy();
 | 
| +
 | 
| +  ProxyService::PacPollPolicy::Mode mode;
 | 
| +  int64 delay_ms = -1;
 | 
| +
 | 
| +  // After a failure, we should start polling at 4 seconds.
 | 
| +  mode = policy->GetInitialDelay(ERR_FAILED, &delay_ms);
 | 
| +  EXPECT_EQ(4000, delay_ms);
 | 
| +  EXPECT_EQ(ProxyService::PacPollPolicy::MODE_USE_TIMER, mode);
 | 
| +
 | 
| +  // After a success, we should start polling at 16 seconds.
 | 
| +  mode = policy->GetInitialDelay(OK, &delay_ms);
 | 
| +  EXPECT_EQ(16000, delay_ms);
 | 
| +  EXPECT_EQ(ProxyService::PacPollPolicy::MODE_USE_TIMER, mode);
 | 
| +
 | 
| +  // The delay should be doubled each time.
 | 
| +  mode = policy->GetNextDelay(4000, &delay_ms);
 | 
| +  EXPECT_EQ(8000, delay_ms);
 | 
| +  EXPECT_EQ(ProxyService::PacPollPolicy::MODE_USE_TIMER, mode);
 | 
| +  mode = policy->GetNextDelay(delay_ms, &delay_ms);
 | 
| +  EXPECT_EQ(16000, delay_ms);
 | 
| +  EXPECT_EQ(ProxyService::PacPollPolicy::MODE_USE_TIMER, mode);
 | 
| +
 | 
| +  // Once we reach 32 seconds, the polling should stop being done using
 | 
| +  // a timer, however it should keep doubling.
 | 
| +  mode = policy->GetNextDelay(delay_ms, &delay_ms);
 | 
| +  EXPECT_EQ(32000, delay_ms);
 | 
| +  EXPECT_EQ(ProxyService::PacPollPolicy::MODE_START_AFTER_ACTIVITY, mode);
 | 
| +  mode = policy->GetNextDelay(delay_ms, &delay_ms);
 | 
| +  EXPECT_EQ(64000, delay_ms);
 | 
| +  EXPECT_EQ(ProxyService::PacPollPolicy::MODE_START_AFTER_ACTIVITY, mode);
 | 
| +
 | 
| +  // Once we reach 2 minutes, the polling delay should stop increasing.
 | 
| +  mode = policy->GetNextDelay(delay_ms, &delay_ms);
 | 
| +  EXPECT_EQ(120000, delay_ms);
 | 
| +  EXPECT_EQ(ProxyService::PacPollPolicy::MODE_START_AFTER_ACTIVITY, mode);
 | 
| +  mode = policy->GetNextDelay(delay_ms, &delay_ms);
 | 
| +  EXPECT_EQ(120000, delay_ms);
 | 
| +  EXPECT_EQ(ProxyService::PacPollPolicy::MODE_START_AFTER_ACTIVITY, mode);
 | 
| +}
 | 
| +
 | 
| +// This tests the polling of the PAC script. Specifically, it tests that
 | 
| +// polling occurs in response to user activity.
 | 
| +TEST_F(ProxyServiceTest, PACScriptRefetchAfterActivity) {
 | 
| +  ImmediateAfterActivityPollPolicy poll_policy;
 | 
| +  ProxyService::set_pac_script_poll_policy(&poll_policy);
 | 
| +
 | 
| +  MockProxyConfigService* config_service =
 | 
| +      new MockProxyConfigService("http://foopy/proxy.pac");
 | 
| +
 | 
| +  MockAsyncProxyResolverExpectsBytes* resolver =
 | 
| +      new MockAsyncProxyResolverExpectsBytes;
 | 
| +
 | 
| +  CapturingNetLog log(CapturingNetLog::kUnbounded);
 | 
| +
 | 
| +  ProxyService service(config_service, resolver, &log);
 | 
| +
 | 
| +  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
 | 
| +  service.SetProxyScriptFetchers(fetcher,
 | 
| +                                 new DoNothingDhcpProxyScriptFetcher());
 | 
| +
 | 
| +  // Start 1 request.
 | 
| +
 | 
| +  ProxyInfo info1;
 | 
| +  TestCompletionCallback callback1;
 | 
| +  int rv = service.ResolveProxy(
 | 
| +      GURL("http://request1"), &info1, callback1.callback(), NULL,
 | 
| +      BoundNetLog());
 | 
| +  EXPECT_EQ(ERR_IO_PENDING, rv);
 | 
| +
 | 
| +  // The first request should have triggered initial download of PAC script.
 | 
| +  EXPECT_TRUE(fetcher->has_pending_request());
 | 
| +  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
 | 
| +
 | 
| +  // Nothing has been sent to the resolver yet.
 | 
| +  EXPECT_TRUE(resolver->pending_requests().empty());
 | 
| +
 | 
| +  // At this point the ProxyService should be waiting for the
 | 
| +  // ProxyScriptFetcher to invoke its completion callback, notifying it of
 | 
| +  // PAC script download completion.
 | 
| +  fetcher->NotifyFetchCompletion(OK, kValidPacScript1);
 | 
| +
 | 
| +  // Now that the PAC script is downloaded, the request will have been sent to
 | 
| +  // the proxy resolver.
 | 
| +  EXPECT_EQ(ASCIIToUTF16(kValidPacScript1),
 | 
| +            resolver->pending_set_pac_script_request()->script_data()->utf16());
 | 
| +  resolver->pending_set_pac_script_request()->CompleteNow(OK);
 | 
| +
 | 
| +  ASSERT_EQ(1u, resolver->pending_requests().size());
 | 
| +  EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
 | 
| +
 | 
| +  // Complete the pending request.
 | 
| +  resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
 | 
| +  resolver->pending_requests()[0]->CompleteNow(OK);
 | 
| +
 | 
| +  // Wait for completion callback, and verify that the request ran as expected.
 | 
| +  EXPECT_EQ(OK, callback1.WaitForResult());
 | 
| +  EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
 | 
| +
 | 
| +  // At this point we have initialized the proxy service using a PAC script.
 | 
| +  // Our PAC poller is set to update ONLY in response to network activity,
 | 
| +  // (i.e. another call to ResolveProxy()).
 | 
| +
 | 
| +  ASSERT_FALSE(fetcher->has_pending_request());
 | 
| +  ASSERT_TRUE(resolver->pending_requests().empty());
 | 
| +
 | 
| +  // Start a second request.
 | 
| +  ProxyInfo info2;
 | 
| +  TestCompletionCallback callback2;
 | 
| +  rv = service.ResolveProxy(
 | 
| +      GURL("http://request2"), &info2, callback2.callback(), NULL,
 | 
| +      BoundNetLog());
 | 
| +  EXPECT_EQ(ERR_IO_PENDING, rv);
 | 
| +
 | 
| +  // This request should have sent work to the resolver; complete it.
 | 
| +  ASSERT_EQ(1u, resolver->pending_requests().size());
 | 
| +  EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[0]->url());
 | 
| +  resolver->pending_requests()[0]->results()->UseNamedProxy("request2:80");
 | 
| +  resolver->pending_requests()[0]->CompleteNow(OK);
 | 
| +
 | 
| +  EXPECT_EQ(OK, callback2.WaitForResult());
 | 
| +  EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
 | 
| +
 | 
| +  // In response to getting that resolve request, the poller should have
 | 
| +  // started the next poll, and made it as far as to request the download.
 | 
| +
 | 
| +  EXPECT_TRUE(fetcher->has_pending_request());
 | 
| +  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
 | 
| +
 | 
| +  // This time we will fail the download, to simulate a PAC script change.
 | 
| +  fetcher->NotifyFetchCompletion(ERR_FAILED, "");
 | 
| +
 | 
| +  // Drain the message loop, so ProxyService is notified of the change
 | 
| +  // and has a chance to re-configure itself.
 | 
| +  MessageLoop::current()->RunAllPending();
 | 
| +
 | 
| +  // Start a third request -- this time we expect to get a direct connection
 | 
| +  // since the PAC script poller experienced a failure.
 | 
| +  ProxyInfo info3;
 | 
| +  TestCompletionCallback callback3;
 | 
| +  rv = service.ResolveProxy(
 | 
| +      GURL("http://request3"), &info3, callback3.callback(), NULL,
 | 
| +      BoundNetLog());
 | 
| +  EXPECT_EQ(OK, rv);
 | 
| +  EXPECT_TRUE(info3.is_direct());
 | 
| +}
 | 
| +
 | 
|  }  // namespace net
 | 
| 
 |