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