Home | History | Annotate | Download | only in proxy
      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 "net/proxy/multi_threaded_proxy_resolver.h"
      6 
      7 #include "base/message_loop/message_loop.h"
      8 #include "base/stl_util.h"
      9 #include "base/strings/string_util.h"
     10 #include "base/strings/stringprintf.h"
     11 #include "base/strings/utf_string_conversions.h"
     12 #include "base/synchronization/waitable_event.h"
     13 #include "base/threading/platform_thread.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/proxy/proxy_info.h"
     19 #include "testing/gtest/include/gtest/gtest.h"
     20 #include "url/gurl.h"
     21 
     22 namespace net {
     23 
     24 namespace {
     25 
     26 // A synchronous mock ProxyResolver implementation, which can be used in
     27 // conjunction with MultiThreadedProxyResolver.
     28 //       - returns a single-item proxy list with the query's host.
     29 class MockProxyResolver : public ProxyResolver {
     30  public:
     31   MockProxyResolver()
     32       : ProxyResolver(true /*expects_pac_bytes*/),
     33         wrong_loop_(base::MessageLoop::current()),
     34         request_count_(0),
     35         purge_count_(0) {}
     36 
     37   // ProxyResolver implementation.
     38   virtual int GetProxyForURL(const GURL& query_url,
     39                              ProxyInfo* results,
     40                              const CompletionCallback& callback,
     41                              RequestHandle* request,
     42                              const BoundNetLog& net_log) OVERRIDE {
     43     if (resolve_latency_ != base::TimeDelta())
     44       base::PlatformThread::Sleep(resolve_latency_);
     45 
     46     CheckIsOnWorkerThread();
     47 
     48     EXPECT_TRUE(callback.is_null());
     49     EXPECT_TRUE(request == NULL);
     50 
     51     // Write something into |net_log| (doesn't really have any meaning.)
     52     net_log.BeginEvent(NetLog::TYPE_PAC_JAVASCRIPT_ALERT);
     53 
     54     results->UseNamedProxy(query_url.host());
     55 
     56     // Return a success code which represents the request's order.
     57     return request_count_++;
     58   }
     59 
     60   virtual void CancelRequest(RequestHandle request) OVERRIDE {
     61     NOTREACHED();
     62   }
     63 
     64   virtual LoadState GetLoadState(RequestHandle request) const OVERRIDE {
     65     NOTREACHED();
     66     return LOAD_STATE_IDLE;
     67   }
     68 
     69   virtual void CancelSetPacScript() OVERRIDE {
     70     NOTREACHED();
     71   }
     72 
     73   virtual int SetPacScript(
     74       const scoped_refptr<ProxyResolverScriptData>& script_data,
     75       const CompletionCallback& callback) OVERRIDE {
     76     CheckIsOnWorkerThread();
     77     last_script_data_ = script_data;
     78     return OK;
     79   }
     80 
     81   virtual void PurgeMemory() OVERRIDE {
     82     CheckIsOnWorkerThread();
     83     ++purge_count_;
     84   }
     85 
     86   int purge_count() const { return purge_count_; }
     87   int request_count() const { return request_count_; }
     88 
     89   const ProxyResolverScriptData* last_script_data() const {
     90     return last_script_data_.get();
     91   }
     92 
     93   void SetResolveLatency(base::TimeDelta latency) {
     94     resolve_latency_ = latency;
     95   }
     96 
     97  private:
     98   void CheckIsOnWorkerThread() {
     99     // We should be running on the worker thread -- while we don't know the
    100     // message loop of MultiThreadedProxyResolver's worker thread, we do
    101     // know that it is going to be distinct from the loop running the
    102     // test, so at least make sure it isn't the main loop.
    103     EXPECT_NE(base::MessageLoop::current(), wrong_loop_);
    104   }
    105 
    106   base::MessageLoop* wrong_loop_;
    107   int request_count_;
    108   int purge_count_;
    109   scoped_refptr<ProxyResolverScriptData> last_script_data_;
    110   base::TimeDelta resolve_latency_;
    111 };
    112 
    113 
    114 // A mock synchronous ProxyResolver which can be set to block upon reaching
    115 // GetProxyForURL().
    116 // TODO(eroman): WaitUntilBlocked() *must* be called before calling Unblock(),
    117 //               otherwise there will be a race on |should_block_| since it is
    118 //               read without any synchronization.
    119 class BlockableProxyResolver : public MockProxyResolver {
    120  public:
    121   BlockableProxyResolver()
    122       : should_block_(false),
    123         unblocked_(true, true),
    124         blocked_(true, false) {
    125   }
    126 
    127   void Block() {
    128     should_block_ = true;
    129     unblocked_.Reset();
    130   }
    131 
    132   void Unblock() {
    133     should_block_ = false;
    134     blocked_.Reset();
    135     unblocked_.Signal();
    136   }
    137 
    138   void WaitUntilBlocked() {
    139     blocked_.Wait();
    140   }
    141 
    142   virtual int GetProxyForURL(const GURL& query_url,
    143                              ProxyInfo* results,
    144                              const CompletionCallback& callback,
    145                              RequestHandle* request,
    146                              const BoundNetLog& net_log) OVERRIDE {
    147     if (should_block_) {
    148       blocked_.Signal();
    149       unblocked_.Wait();
    150     }
    151 
    152     return MockProxyResolver::GetProxyForURL(
    153         query_url, results, callback, request, net_log);
    154   }
    155 
    156  private:
    157   bool should_block_;
    158   base::WaitableEvent unblocked_;
    159   base::WaitableEvent blocked_;
    160 };
    161 
    162 // ForwardingProxyResolver forwards all requests to |impl|.
    163 class ForwardingProxyResolver : public ProxyResolver {
    164  public:
    165   explicit ForwardingProxyResolver(ProxyResolver* impl)
    166       : ProxyResolver(impl->expects_pac_bytes()),
    167         impl_(impl) {}
    168 
    169   virtual int GetProxyForURL(const GURL& query_url,
    170                              ProxyInfo* results,
    171                              const CompletionCallback& callback,
    172                              RequestHandle* request,
    173                              const BoundNetLog& net_log) OVERRIDE {
    174     return impl_->GetProxyForURL(
    175         query_url, results, callback, request, net_log);
    176   }
    177 
    178   virtual void CancelRequest(RequestHandle request) OVERRIDE {
    179     impl_->CancelRequest(request);
    180   }
    181 
    182   virtual LoadState GetLoadState(RequestHandle request) const OVERRIDE {
    183     NOTREACHED();
    184     return LOAD_STATE_IDLE;
    185   }
    186 
    187   virtual void CancelSetPacScript() OVERRIDE {
    188     impl_->CancelSetPacScript();
    189   }
    190 
    191   virtual int SetPacScript(
    192       const scoped_refptr<ProxyResolverScriptData>& script_data,
    193       const CompletionCallback& callback) OVERRIDE {
    194     return impl_->SetPacScript(script_data, callback);
    195   }
    196 
    197   virtual void PurgeMemory() OVERRIDE {
    198     impl_->PurgeMemory();
    199   }
    200 
    201  private:
    202   ProxyResolver* impl_;
    203 };
    204 
    205 // This factory returns ProxyResolvers that forward all requests to
    206 // |resolver|.
    207 class ForwardingProxyResolverFactory : public ProxyResolverFactory {
    208  public:
    209   explicit ForwardingProxyResolverFactory(ProxyResolver* resolver)
    210       : ProxyResolverFactory(resolver->expects_pac_bytes()),
    211         resolver_(resolver) {}
    212 
    213   virtual ProxyResolver* CreateProxyResolver() OVERRIDE {
    214     return new ForwardingProxyResolver(resolver_);
    215   }
    216 
    217  private:
    218   ProxyResolver* resolver_;
    219 };
    220 
    221 // This factory returns new instances of BlockableProxyResolver.
    222 class BlockableProxyResolverFactory : public ProxyResolverFactory {
    223  public:
    224   BlockableProxyResolverFactory() : ProxyResolverFactory(true) {}
    225 
    226   virtual ~BlockableProxyResolverFactory() {
    227     STLDeleteElements(&resolvers_);
    228   }
    229 
    230   virtual ProxyResolver* CreateProxyResolver() OVERRIDE {
    231     BlockableProxyResolver* resolver = new BlockableProxyResolver;
    232     resolvers_.push_back(resolver);
    233     return new ForwardingProxyResolver(resolver);
    234   }
    235 
    236   std::vector<BlockableProxyResolver*> resolvers() {
    237     return resolvers_;
    238   }
    239 
    240  private:
    241   std::vector<BlockableProxyResolver*> resolvers_;
    242 };
    243 
    244 TEST(MultiThreadedProxyResolverTest, SingleThread_Basic) {
    245   const size_t kNumThreads = 1u;
    246   scoped_ptr<MockProxyResolver> mock(new MockProxyResolver);
    247   MultiThreadedProxyResolver resolver(
    248       new ForwardingProxyResolverFactory(mock.get()), kNumThreads);
    249 
    250   int rv;
    251 
    252   EXPECT_TRUE(resolver.expects_pac_bytes());
    253 
    254   // Call SetPacScriptByData() -- verify that it reaches the synchronous
    255   // resolver.
    256   TestCompletionCallback set_script_callback;
    257   rv = resolver.SetPacScript(
    258       ProxyResolverScriptData::FromUTF8("pac script bytes"),
    259       set_script_callback.callback());
    260   EXPECT_EQ(ERR_IO_PENDING, rv);
    261   EXPECT_EQ(OK, set_script_callback.WaitForResult());
    262   EXPECT_EQ(ASCIIToUTF16("pac script bytes"),
    263             mock->last_script_data()->utf16());
    264 
    265   // Start request 0.
    266   TestCompletionCallback callback0;
    267   CapturingBoundNetLog log0;
    268   ProxyInfo results0;
    269   rv = resolver.GetProxyForURL(GURL("http://request0"), &results0,
    270                                callback0.callback(), NULL, log0.bound());
    271   EXPECT_EQ(ERR_IO_PENDING, rv);
    272 
    273   // Wait for request 0 to finish.
    274   rv = callback0.WaitForResult();
    275   EXPECT_EQ(0, rv);
    276   EXPECT_EQ("PROXY request0:80", results0.ToPacString());
    277 
    278   // The mock proxy resolver should have written 1 log entry. And
    279   // on completion, this should have been copied into |log0|.
    280   // We also have 1 log entry that was emitted by the
    281   // MultiThreadedProxyResolver.
    282   CapturingNetLog::CapturedEntryList entries0;
    283   log0.GetEntries(&entries0);
    284 
    285   ASSERT_EQ(2u, entries0.size());
    286   EXPECT_EQ(NetLog::TYPE_SUBMITTED_TO_RESOLVER_THREAD, entries0[0].type);
    287 
    288   // Start 3 more requests (request1 to request3).
    289 
    290   TestCompletionCallback callback1;
    291   ProxyInfo results1;
    292   rv = resolver.GetProxyForURL(GURL("http://request1"), &results1,
    293                                callback1.callback(), NULL, BoundNetLog());
    294   EXPECT_EQ(ERR_IO_PENDING, rv);
    295 
    296   TestCompletionCallback callback2;
    297   ProxyInfo results2;
    298   rv = resolver.GetProxyForURL(GURL("http://request2"), &results2,
    299                                callback2.callback(), NULL, BoundNetLog());
    300   EXPECT_EQ(ERR_IO_PENDING, rv);
    301 
    302   TestCompletionCallback callback3;
    303   ProxyInfo results3;
    304   rv = resolver.GetProxyForURL(GURL("http://request3"), &results3,
    305                                callback3.callback(), NULL, BoundNetLog());
    306   EXPECT_EQ(ERR_IO_PENDING, rv);
    307 
    308   // Wait for the requests to finish (they must finish in the order they were
    309   // started, which is what we check for from their magic return value)
    310 
    311   rv = callback1.WaitForResult();
    312   EXPECT_EQ(1, rv);
    313   EXPECT_EQ("PROXY request1:80", results1.ToPacString());
    314 
    315   rv = callback2.WaitForResult();
    316   EXPECT_EQ(2, rv);
    317   EXPECT_EQ("PROXY request2:80", results2.ToPacString());
    318 
    319   rv = callback3.WaitForResult();
    320   EXPECT_EQ(3, rv);
    321   EXPECT_EQ("PROXY request3:80", results3.ToPacString());
    322 
    323   // Ensure that PurgeMemory() reaches the wrapped resolver and happens on the
    324   // right thread.
    325   EXPECT_EQ(0, mock->purge_count());
    326   resolver.PurgeMemory();
    327   // There is no way to get a callback directly when PurgeMemory() completes, so
    328   // we queue up a dummy request after the PurgeMemory() call and wait until it
    329   // finishes to ensure PurgeMemory() has had a chance to run.
    330   TestCompletionCallback dummy_callback;
    331   rv = resolver.SetPacScript(ProxyResolverScriptData::FromUTF8("dummy"),
    332                              dummy_callback.callback());
    333   EXPECT_EQ(OK, dummy_callback.WaitForResult());
    334   EXPECT_EQ(1, mock->purge_count());
    335 }
    336 
    337 // Tests that the NetLog is updated to include the time the request was waiting
    338 // to be scheduled to a thread.
    339 TEST(MultiThreadedProxyResolverTest,
    340      SingleThread_UpdatesNetLogWithThreadWait) {
    341   const size_t kNumThreads = 1u;
    342   scoped_ptr<BlockableProxyResolver> mock(new BlockableProxyResolver);
    343   MultiThreadedProxyResolver resolver(
    344       new ForwardingProxyResolverFactory(mock.get()), kNumThreads);
    345 
    346   int rv;
    347 
    348   // Initialize the resolver.
    349   TestCompletionCallback init_callback;
    350   rv = resolver.SetPacScript(ProxyResolverScriptData::FromUTF8("foo"),
    351                              init_callback.callback());
    352   EXPECT_EQ(OK, init_callback.WaitForResult());
    353 
    354   // Block the proxy resolver, so no request can complete.
    355   mock->Block();
    356 
    357   // Start request 0.
    358   ProxyResolver::RequestHandle request0;
    359   TestCompletionCallback callback0;
    360   ProxyInfo results0;
    361   CapturingBoundNetLog log0;
    362   rv = resolver.GetProxyForURL(GURL("http://request0"), &results0,
    363                                callback0.callback(), &request0, log0.bound());
    364   EXPECT_EQ(ERR_IO_PENDING, rv);
    365 
    366   // Start 2 more requests (request1 and request2).
    367 
    368   TestCompletionCallback callback1;
    369   ProxyInfo results1;
    370   CapturingBoundNetLog log1;
    371   rv = resolver.GetProxyForURL(GURL("http://request1"), &results1,
    372                                callback1.callback(), NULL, log1.bound());
    373   EXPECT_EQ(ERR_IO_PENDING, rv);
    374 
    375   ProxyResolver::RequestHandle request2;
    376   TestCompletionCallback callback2;
    377   ProxyInfo results2;
    378   CapturingBoundNetLog log2;
    379   rv = resolver.GetProxyForURL(GURL("http://request2"), &results2,
    380                                callback2.callback(), &request2, log2.bound());
    381   EXPECT_EQ(ERR_IO_PENDING, rv);
    382 
    383   // Unblock the worker thread so the requests can continue running.
    384   mock->WaitUntilBlocked();
    385   mock->Unblock();
    386 
    387   // Check that request 0 completed as expected.
    388   // The NetLog has 1 entry that came from the MultiThreadedProxyResolver, and
    389   // 1 entry from the mock proxy resolver.
    390   EXPECT_EQ(0, callback0.WaitForResult());
    391   EXPECT_EQ("PROXY request0:80", results0.ToPacString());
    392 
    393   CapturingNetLog::CapturedEntryList entries0;
    394   log0.GetEntries(&entries0);
    395 
    396   ASSERT_EQ(2u, entries0.size());
    397   EXPECT_EQ(NetLog::TYPE_SUBMITTED_TO_RESOLVER_THREAD,
    398             entries0[0].type);
    399 
    400   // Check that request 1 completed as expected.
    401   EXPECT_EQ(1, callback1.WaitForResult());
    402   EXPECT_EQ("PROXY request1:80", results1.ToPacString());
    403 
    404   CapturingNetLog::CapturedEntryList entries1;
    405   log1.GetEntries(&entries1);
    406 
    407   ASSERT_EQ(4u, entries1.size());
    408   EXPECT_TRUE(LogContainsBeginEvent(
    409       entries1, 0,
    410       NetLog::TYPE_WAITING_FOR_PROXY_RESOLVER_THREAD));
    411   EXPECT_TRUE(LogContainsEndEvent(
    412       entries1, 1,
    413       NetLog::TYPE_WAITING_FOR_PROXY_RESOLVER_THREAD));
    414 
    415   // Check that request 2 completed as expected.
    416   EXPECT_EQ(2, callback2.WaitForResult());
    417   EXPECT_EQ("PROXY request2:80", results2.ToPacString());
    418 
    419   CapturingNetLog::CapturedEntryList entries2;
    420   log2.GetEntries(&entries2);
    421 
    422   ASSERT_EQ(4u, entries2.size());
    423   EXPECT_TRUE(LogContainsBeginEvent(
    424       entries2, 0,
    425       NetLog::TYPE_WAITING_FOR_PROXY_RESOLVER_THREAD));
    426   EXPECT_TRUE(LogContainsEndEvent(
    427       entries2, 1,
    428       NetLog::TYPE_WAITING_FOR_PROXY_RESOLVER_THREAD));
    429 }
    430 
    431 // Cancel a request which is in progress, and then cancel a request which
    432 // is pending.
    433 TEST(MultiThreadedProxyResolverTest, SingleThread_CancelRequest) {
    434   const size_t kNumThreads = 1u;
    435   scoped_ptr<BlockableProxyResolver> mock(new BlockableProxyResolver);
    436   MultiThreadedProxyResolver resolver(
    437       new ForwardingProxyResolverFactory(mock.get()),
    438                                       kNumThreads);
    439 
    440   int rv;
    441 
    442   // Initialize the resolver.
    443   TestCompletionCallback init_callback;
    444   rv = resolver.SetPacScript(ProxyResolverScriptData::FromUTF8("foo"),
    445                              init_callback.callback());
    446   EXPECT_EQ(OK, init_callback.WaitForResult());
    447 
    448   // Block the proxy resolver, so no request can complete.
    449   mock->Block();
    450 
    451   // Start request 0.
    452   ProxyResolver::RequestHandle request0;
    453   TestCompletionCallback callback0;
    454   ProxyInfo results0;
    455   rv = resolver.GetProxyForURL(GURL("http://request0"), &results0,
    456                                callback0.callback(), &request0, BoundNetLog());
    457   EXPECT_EQ(ERR_IO_PENDING, rv);
    458 
    459   // Wait until requests 0 reaches the worker thread.
    460   mock->WaitUntilBlocked();
    461 
    462   // Start 3 more requests (request1 : request3).
    463 
    464   TestCompletionCallback callback1;
    465   ProxyInfo results1;
    466   rv = resolver.GetProxyForURL(GURL("http://request1"), &results1,
    467                                callback1.callback(), NULL, BoundNetLog());
    468   EXPECT_EQ(ERR_IO_PENDING, rv);
    469 
    470   ProxyResolver::RequestHandle request2;
    471   TestCompletionCallback callback2;
    472   ProxyInfo results2;
    473   rv = resolver.GetProxyForURL(GURL("http://request2"), &results2,
    474                                callback2.callback(), &request2, BoundNetLog());
    475   EXPECT_EQ(ERR_IO_PENDING, rv);
    476 
    477   TestCompletionCallback callback3;
    478   ProxyInfo results3;
    479   rv = resolver.GetProxyForURL(GURL("http://request3"), &results3,
    480                                callback3.callback(), NULL, BoundNetLog());
    481   EXPECT_EQ(ERR_IO_PENDING, rv);
    482 
    483   // Cancel request0 (inprogress) and request2 (pending).
    484   resolver.CancelRequest(request0);
    485   resolver.CancelRequest(request2);
    486 
    487   // Unblock the worker thread so the requests can continue running.
    488   mock->Unblock();
    489 
    490   // Wait for requests 1 and 3 to finish.
    491 
    492   rv = callback1.WaitForResult();
    493   EXPECT_EQ(1, rv);
    494   EXPECT_EQ("PROXY request1:80", results1.ToPacString());
    495 
    496   rv = callback3.WaitForResult();
    497   // Note that since request2 was cancelled before reaching the resolver,
    498   // the request count is 2 and not 3 here.
    499   EXPECT_EQ(2, rv);
    500   EXPECT_EQ("PROXY request3:80", results3.ToPacString());
    501 
    502   // Requests 0 and 2 which were cancelled, hence their completion callbacks
    503   // were never summoned.
    504   EXPECT_FALSE(callback0.have_result());
    505   EXPECT_FALSE(callback2.have_result());
    506 }
    507 
    508 // Test that deleting MultiThreadedProxyResolver while requests are
    509 // outstanding cancels them (and doesn't leak anything).
    510 TEST(MultiThreadedProxyResolverTest, SingleThread_CancelRequestByDeleting) {
    511   const size_t kNumThreads = 1u;
    512   scoped_ptr<BlockableProxyResolver> mock(new BlockableProxyResolver);
    513   scoped_ptr<MultiThreadedProxyResolver> resolver(
    514       new MultiThreadedProxyResolver(
    515           new ForwardingProxyResolverFactory(mock.get()), kNumThreads));
    516 
    517   int rv;
    518 
    519   // Initialize the resolver.
    520   TestCompletionCallback init_callback;
    521   rv = resolver->SetPacScript(ProxyResolverScriptData::FromUTF8("foo"),
    522                               init_callback.callback());
    523   EXPECT_EQ(OK, init_callback.WaitForResult());
    524 
    525   // Block the proxy resolver, so no request can complete.
    526   mock->Block();
    527 
    528   // Start 3 requests.
    529 
    530   TestCompletionCallback callback0;
    531   ProxyInfo results0;
    532   rv = resolver->GetProxyForURL(GURL("http://request0"), &results0,
    533                                 callback0.callback(), NULL, BoundNetLog());
    534   EXPECT_EQ(ERR_IO_PENDING, rv);
    535 
    536   TestCompletionCallback callback1;
    537   ProxyInfo results1;
    538   rv = resolver->GetProxyForURL(GURL("http://request1"), &results1,
    539                                 callback1.callback(), NULL, BoundNetLog());
    540   EXPECT_EQ(ERR_IO_PENDING, rv);
    541 
    542   TestCompletionCallback callback2;
    543   ProxyInfo results2;
    544   rv = resolver->GetProxyForURL(GURL("http://request2"), &results2,
    545                                 callback2.callback(), NULL, BoundNetLog());
    546   EXPECT_EQ(ERR_IO_PENDING, rv);
    547 
    548   // Wait until request 0 reaches the worker thread.
    549   mock->WaitUntilBlocked();
    550 
    551   // Add some latency, to improve the chance that when
    552   // MultiThreadedProxyResolver is deleted below we are still running inside
    553   // of the worker thread. The test will pass regardless, so this race doesn't
    554   // cause flakiness. However the destruction during execution is a more
    555   // interesting case to test.
    556   mock->SetResolveLatency(base::TimeDelta::FromMilliseconds(100));
    557 
    558   // Unblock the worker thread and delete the underlying
    559   // MultiThreadedProxyResolver immediately.
    560   mock->Unblock();
    561   resolver.reset();
    562 
    563   // Give any posted tasks a chance to run (in case there is badness).
    564   base::MessageLoop::current()->RunUntilIdle();
    565 
    566   // Check that none of the outstanding requests were completed.
    567   EXPECT_FALSE(callback0.have_result());
    568   EXPECT_FALSE(callback1.have_result());
    569   EXPECT_FALSE(callback2.have_result());
    570 }
    571 
    572 // Cancel an outstanding call to SetPacScriptByData().
    573 TEST(MultiThreadedProxyResolverTest, SingleThread_CancelSetPacScript) {
    574   const size_t kNumThreads = 1u;
    575   scoped_ptr<BlockableProxyResolver> mock(new BlockableProxyResolver);
    576   MultiThreadedProxyResolver resolver(
    577       new ForwardingProxyResolverFactory(mock.get()), kNumThreads);
    578 
    579   int rv;
    580 
    581   TestCompletionCallback set_pac_script_callback;
    582   rv = resolver.SetPacScript(ProxyResolverScriptData::FromUTF8("data"),
    583                              set_pac_script_callback.callback());
    584   EXPECT_EQ(ERR_IO_PENDING, rv);
    585 
    586   // Cancel the SetPacScriptByData request.
    587   resolver.CancelSetPacScript();
    588 
    589   // Start another SetPacScript request
    590   TestCompletionCallback set_pac_script_callback2;
    591   rv = resolver.SetPacScript(ProxyResolverScriptData::FromUTF8("data2"),
    592                              set_pac_script_callback2.callback());
    593   EXPECT_EQ(ERR_IO_PENDING, rv);
    594 
    595   // Wait for the initialization to complete.
    596 
    597   rv = set_pac_script_callback2.WaitForResult();
    598   EXPECT_EQ(0, rv);
    599   EXPECT_EQ(ASCIIToUTF16("data2"), mock->last_script_data()->utf16());
    600 
    601   // The first SetPacScript callback should never have been completed.
    602   EXPECT_FALSE(set_pac_script_callback.have_result());
    603 }
    604 
    605 // Tests setting the PAC script once, lazily creating new threads, and
    606 // cancelling requests.
    607 TEST(MultiThreadedProxyResolverTest, ThreeThreads_Basic) {
    608   const size_t kNumThreads = 3u;
    609   BlockableProxyResolverFactory* factory = new BlockableProxyResolverFactory;
    610   MultiThreadedProxyResolver resolver(factory, kNumThreads);
    611 
    612   int rv;
    613 
    614   EXPECT_TRUE(resolver.expects_pac_bytes());
    615 
    616   // Call SetPacScriptByData() -- verify that it reaches the synchronous
    617   // resolver.
    618   TestCompletionCallback set_script_callback;
    619   rv = resolver.SetPacScript(
    620       ProxyResolverScriptData::FromUTF8("pac script bytes"),
    621       set_script_callback.callback());
    622   EXPECT_EQ(ERR_IO_PENDING, rv);
    623   EXPECT_EQ(OK, set_script_callback.WaitForResult());
    624   // One thread has been provisioned (i.e. one ProxyResolver was created).
    625   ASSERT_EQ(1u, factory->resolvers().size());
    626   EXPECT_EQ(ASCIIToUTF16("pac script bytes"),
    627             factory->resolvers()[0]->last_script_data()->utf16());
    628 
    629   const int kNumRequests = 9;
    630   TestCompletionCallback callback[kNumRequests];
    631   ProxyInfo results[kNumRequests];
    632   ProxyResolver::RequestHandle request[kNumRequests];
    633 
    634   // Start request 0 -- this should run on thread 0 as there is nothing else
    635   // going on right now.
    636   rv = resolver.GetProxyForURL(
    637       GURL("http://request0"), &results[0], callback[0].callback(), &request[0],
    638       BoundNetLog());
    639   EXPECT_EQ(ERR_IO_PENDING, rv);
    640 
    641   // Wait for request 0 to finish.
    642   rv = callback[0].WaitForResult();
    643   EXPECT_EQ(0, rv);
    644   EXPECT_EQ("PROXY request0:80", results[0].ToPacString());
    645   ASSERT_EQ(1u, factory->resolvers().size());
    646   EXPECT_EQ(1, factory->resolvers()[0]->request_count());
    647 
    648   base::MessageLoop::current()->RunUntilIdle();
    649 
    650   // We now start 8 requests in parallel -- this will cause the maximum of
    651   // three threads to be provisioned (an additional two from what we already
    652   // have).
    653 
    654   for (int i = 1; i < kNumRequests; ++i) {
    655     rv = resolver.GetProxyForURL(
    656         GURL(base::StringPrintf("http://request%d", i)), &results[i],
    657         callback[i].callback(), &request[i], BoundNetLog());
    658     EXPECT_EQ(ERR_IO_PENDING, rv);
    659   }
    660 
    661   // We should now have a total of 3 threads, each with its own ProxyResolver
    662   // that will get initialized with the same data. (We check this later since
    663   // the assignment happens on the worker threads and may not have occurred
    664   // yet.)
    665   ASSERT_EQ(3u, factory->resolvers().size());
    666 
    667   // Cancel 3 of the 8 oustanding requests.
    668   resolver.CancelRequest(request[1]);
    669   resolver.CancelRequest(request[3]);
    670   resolver.CancelRequest(request[6]);
    671 
    672   // Wait for the remaining requests to complete.
    673   int kNonCancelledRequests[] = {2, 4, 5, 7, 8};
    674   for (size_t i = 0; i < arraysize(kNonCancelledRequests); ++i) {
    675     int request_index = kNonCancelledRequests[i];
    676     EXPECT_GE(callback[request_index].WaitForResult(), 0);
    677   }
    678 
    679   // Check that the cancelled requests never invoked their callback.
    680   EXPECT_FALSE(callback[1].have_result());
    681   EXPECT_FALSE(callback[3].have_result());
    682   EXPECT_FALSE(callback[6].have_result());
    683 
    684   // We call SetPacScript again, solely to stop the current worker threads.
    685   // (That way we can test to see the values observed by the synchronous
    686   // resolvers in a non-racy manner).
    687   TestCompletionCallback set_script_callback2;
    688   rv = resolver.SetPacScript(ProxyResolverScriptData::FromUTF8("xyz"),
    689                              set_script_callback2.callback());
    690   EXPECT_EQ(ERR_IO_PENDING, rv);
    691   EXPECT_EQ(OK, set_script_callback2.WaitForResult());
    692   ASSERT_EQ(4u, factory->resolvers().size());
    693 
    694   for (int i = 0; i < 3; ++i) {
    695     EXPECT_EQ(
    696         ASCIIToUTF16("pac script bytes"),
    697         factory->resolvers()[i]->last_script_data()->utf16()) << "i=" << i;
    698   }
    699 
    700   EXPECT_EQ(ASCIIToUTF16("xyz"),
    701             factory->resolvers()[3]->last_script_data()->utf16());
    702 
    703   // We don't know the exact ordering that requests ran on threads with,
    704   // but we do know the total count that should have reached the threads.
    705   // 8 total were submitted, and three were cancelled. Of the three that
    706   // were cancelled, one of them (request 1) was cancelled after it had
    707   // already been posted to the worker thread. So the resolvers will
    708   // have seen 6 total (and 1 from the run prior).
    709   ASSERT_EQ(4u, factory->resolvers().size());
    710   int total_count = 0;
    711   for (int i = 0; i < 3; ++i) {
    712     total_count += factory->resolvers()[i]->request_count();
    713   }
    714   EXPECT_EQ(7, total_count);
    715 }
    716 
    717 // Tests using two threads. The first request hangs the first thread. Checks
    718 // that other requests are able to complete while this first request remains
    719 // stalled.
    720 TEST(MultiThreadedProxyResolverTest, OneThreadBlocked) {
    721   const size_t kNumThreads = 2u;
    722   BlockableProxyResolverFactory* factory = new BlockableProxyResolverFactory;
    723   MultiThreadedProxyResolver resolver(factory, kNumThreads);
    724 
    725   int rv;
    726 
    727   EXPECT_TRUE(resolver.expects_pac_bytes());
    728 
    729   // Initialize the resolver.
    730   TestCompletionCallback set_script_callback;
    731   rv = resolver.SetPacScript(
    732       ProxyResolverScriptData::FromUTF8("pac script bytes"),
    733       set_script_callback.callback());
    734   EXPECT_EQ(ERR_IO_PENDING, rv);
    735   EXPECT_EQ(OK, set_script_callback.WaitForResult());
    736   // One thread has been provisioned (i.e. one ProxyResolver was created).
    737   ASSERT_EQ(1u, factory->resolvers().size());
    738   EXPECT_EQ(ASCIIToUTF16("pac script bytes"),
    739             factory->resolvers()[0]->last_script_data()->utf16());
    740 
    741   const int kNumRequests = 4;
    742   TestCompletionCallback callback[kNumRequests];
    743   ProxyInfo results[kNumRequests];
    744   ProxyResolver::RequestHandle request[kNumRequests];
    745 
    746   // Start a request that will block the first thread.
    747 
    748   factory->resolvers()[0]->Block();
    749 
    750   rv = resolver.GetProxyForURL(
    751       GURL("http://request0"), &results[0], callback[0].callback(), &request[0],
    752       BoundNetLog());
    753 
    754   EXPECT_EQ(ERR_IO_PENDING, rv);
    755   factory->resolvers()[0]->WaitUntilBlocked();
    756 
    757   // Start 3 more requests -- they should all be serviced by thread #2
    758   // since thread #1 is blocked.
    759 
    760   for (int i = 1; i < kNumRequests; ++i) {
    761     rv = resolver.GetProxyForURL(
    762         GURL(base::StringPrintf("http://request%d", i)),
    763         &results[i], callback[i].callback(), &request[i], BoundNetLog());
    764     EXPECT_EQ(ERR_IO_PENDING, rv);
    765   }
    766 
    767   // Wait for the three requests to complete (they should complete in FIFO
    768   // order).
    769   for (int i = 1; i < kNumRequests; ++i) {
    770     EXPECT_EQ(i - 1, callback[i].WaitForResult());
    771   }
    772 
    773   // Unblock the first thread.
    774   factory->resolvers()[0]->Unblock();
    775   EXPECT_EQ(0, callback[0].WaitForResult());
    776 
    777   // All in all, the first thread should have seen just 1 request. And the
    778   // second thread 3 requests.
    779   ASSERT_EQ(2u, factory->resolvers().size());
    780   EXPECT_EQ(1, factory->resolvers()[0]->request_count());
    781   EXPECT_EQ(3, factory->resolvers()[1]->request_count());
    782 }
    783 
    784 }  // namespace
    785 
    786 }  // namespace net
    787