Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(221)

Side by Side Diff: net/proxy/multi_threaded_proxy_resolver_unittest.cc

Issue 2822043: Add the capability to run multiple proxy PAC scripts in parallel.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Re-upload after revert Created 10 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/proxy/multi_threaded_proxy_resolver.cc ('k') | net/proxy/proxy_resolver.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/proxy/multi_threaded_proxy_resolver.h"
6
7 #include "base/stl_util-inl.h"
5 #include "base/string_util.h" 8 #include "base/string_util.h"
6 #include "base/waitable_event.h" 9 #include "base/waitable_event.h"
7 #include "googleurl/src/gurl.h" 10 #include "googleurl/src/gurl.h"
8 #include "net/base/net_log.h" 11 #include "net/base/net_log.h"
9 #include "net/base/net_log_unittest.h" 12 #include "net/base/net_log_unittest.h"
10 #include "net/base/net_errors.h" 13 #include "net/base/net_errors.h"
11 #include "net/base/test_completion_callback.h" 14 #include "net/base/test_completion_callback.h"
12 #include "net/proxy/proxy_info.h" 15 #include "net/proxy/proxy_info.h"
13 #include "net/proxy/single_threaded_proxy_resolver.h"
14 #include "testing/gtest/include/gtest/gtest.h" 16 #include "testing/gtest/include/gtest/gtest.h"
15 17
16 namespace net { 18 namespace net {
19
17 namespace { 20 namespace {
18 21
19 // A synchronous mock ProxyResolver implementation, which can be used in 22 // A synchronous mock ProxyResolver implementation, which can be used in
20 // conjunction with SingleThreadedProxyResolver. 23 // conjunction with MultiThreadedProxyResolver.
21 // - returns a single-item proxy list with the query's host. 24 // - returns a single-item proxy list with the query's host.
22 class MockProxyResolver : public ProxyResolver { 25 class MockProxyResolver : public ProxyResolver {
23 public: 26 public:
24 MockProxyResolver() 27 MockProxyResolver()
25 : ProxyResolver(true /*expects_pac_bytes*/), 28 : ProxyResolver(true /*expects_pac_bytes*/),
26 wrong_loop_(MessageLoop::current()), 29 wrong_loop_(MessageLoop::current()),
27 request_count_(0), 30 request_count_(0),
28 purge_count_(0), 31 purge_count_(0),
29 resolve_latency_ms_(0) {} 32 resolve_latency_ms_(0) {}
30 33
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
62 last_pac_script_ = text; 65 last_pac_script_ = text;
63 return OK; 66 return OK;
64 } 67 }
65 68
66 virtual void PurgeMemory() { 69 virtual void PurgeMemory() {
67 CheckIsOnWorkerThread(); 70 CheckIsOnWorkerThread();
68 ++purge_count_; 71 ++purge_count_;
69 } 72 }
70 73
71 int purge_count() const { return purge_count_; } 74 int purge_count() const { return purge_count_; }
75 int request_count() const { return request_count_; }
72 76
73 const string16& last_pac_script() const { return last_pac_script_; } 77 const string16& last_pac_script() const { return last_pac_script_; }
74 78
75 void SetResolveLatency(int latency_ms) { 79 void SetResolveLatency(int latency_ms) {
76 resolve_latency_ms_ = latency_ms; 80 resolve_latency_ms_ = latency_ms;
77 } 81 }
78 82
79 private: 83 private:
80 void CheckIsOnWorkerThread() { 84 void CheckIsOnWorkerThread() {
81 // We should be running on the worker thread -- while we don't know the 85 // We should be running on the worker thread -- while we don't know the
82 // message loop of SingleThreadedProxyResolver's worker thread, we do 86 // message loop of MultiThreadedProxyResolver's worker thread, we do
83 // know that it is going to be distinct from the loop running the 87 // know that it is going to be distinct from the loop running the
84 // test, so at least make sure it isn't the main loop. 88 // test, so at least make sure it isn't the main loop.
85 EXPECT_NE(MessageLoop::current(), wrong_loop_); 89 EXPECT_NE(MessageLoop::current(), wrong_loop_);
86 } 90 }
87 91
88 MessageLoop* wrong_loop_; 92 MessageLoop* wrong_loop_;
89 int request_count_; 93 int request_count_;
90 int purge_count_; 94 int purge_count_;
91 string16 last_pac_script_; 95 string16 last_pac_script_;
92 int resolve_latency_ms_; 96 int resolve_latency_ms_;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
134 return MockProxyResolver::GetProxyForURL( 138 return MockProxyResolver::GetProxyForURL(
135 query_url, results, callback, request, net_log); 139 query_url, results, callback, request, net_log);
136 } 140 }
137 141
138 private: 142 private:
139 bool should_block_; 143 bool should_block_;
140 base::WaitableEvent unblocked_; 144 base::WaitableEvent unblocked_;
141 base::WaitableEvent blocked_; 145 base::WaitableEvent blocked_;
142 }; 146 };
143 147
144 TEST(SingleThreadedProxyResolverTest, Basic) { 148 // ForwardingProxyResolver forwards all requests to |impl|.
145 MockProxyResolver* mock = new MockProxyResolver; 149 class ForwardingProxyResolver : public ProxyResolver {
146 SingleThreadedProxyResolver resolver(mock); 150 public:
151 explicit ForwardingProxyResolver(ProxyResolver* impl)
152 : ProxyResolver(impl->expects_pac_bytes()),
153 impl_(impl) {}
154
155 virtual int GetProxyForURL(const GURL& query_url,
156 ProxyInfo* results,
157 CompletionCallback* callback,
158 RequestHandle* request,
159 const BoundNetLog& net_log) {
160 return impl_->GetProxyForURL(
161 query_url, results, callback, request, net_log);
162 }
163
164 virtual void CancelRequest(RequestHandle request) {
165 impl_->CancelRequest(request);
166 }
167
168 virtual int SetPacScript(const GURL& pac_url,
169 const string16& script,
170 CompletionCallback* callback) {
171 if (impl_->expects_pac_bytes())
172 return impl_->SetPacScriptByData(script, callback);
173 else
174 return impl_->SetPacScriptByUrl(pac_url, callback);
175 }
176
177 virtual void PurgeMemory() {
178 impl_->PurgeMemory();
179 }
180
181 private:
182 ProxyResolver* impl_;
183 };
184
185 // This factory returns ProxyResolvers that forward all requests to
186 // |resolver|.
187 class ForwardingProxyResolverFactory : public ProxyResolverFactory {
188 public:
189 explicit ForwardingProxyResolverFactory(ProxyResolver* resolver)
190 : ProxyResolverFactory(resolver->expects_pac_bytes()),
191 resolver_(resolver) {}
192
193 virtual ProxyResolver* CreateProxyResolver() {
194 return new ForwardingProxyResolver(resolver_);
195 }
196
197 private:
198 ProxyResolver* resolver_;
199 };
200
201 // This factory returns new instances of BlockableProxyResolver.
202 class BlockableProxyResolverFactory : public ProxyResolverFactory {
203 public:
204 BlockableProxyResolverFactory() : ProxyResolverFactory(true) {}
205
206 ~BlockableProxyResolverFactory() {
207 STLDeleteElements(&resolvers_);
208 }
209
210 virtual ProxyResolver* CreateProxyResolver() {
211 BlockableProxyResolver* resolver = new BlockableProxyResolver;
212 resolvers_.push_back(resolver);
213 return new ForwardingProxyResolver(resolver);
214 }
215
216 std::vector<BlockableProxyResolver*> resolvers() {
217 return resolvers_;
218 }
219
220 private:
221 std::vector<BlockableProxyResolver*> resolvers_;
222 };
223
224 TEST(MultiThreadedProxyResolverTest, SingleThread_Basic) {
225 const size_t kNumThreads = 1u;
226 scoped_ptr<MockProxyResolver> mock(new MockProxyResolver);
227 MultiThreadedProxyResolver resolver(
228 new ForwardingProxyResolverFactory(mock.get()), kNumThreads);
147 229
148 int rv; 230 int rv;
149 231
150 EXPECT_TRUE(resolver.expects_pac_bytes()); 232 EXPECT_TRUE(resolver.expects_pac_bytes());
151 233
152 // Call SetPacScriptByData() -- verify that it reaches the synchronous 234 // Call SetPacScriptByData() -- verify that it reaches the synchronous
153 // resolver. 235 // resolver.
154 TestCompletionCallback set_script_callback; 236 TestCompletionCallback set_script_callback;
155 rv = resolver.SetPacScriptByData(ASCIIToUTF16("pac script bytes"), 237 rv = resolver.SetPacScriptByData(ASCIIToUTF16("pac script bytes"),
156 &set_script_callback); 238 &set_script_callback);
157 EXPECT_EQ(ERR_IO_PENDING, rv); 239 EXPECT_EQ(ERR_IO_PENDING, rv);
158 EXPECT_EQ(OK, set_script_callback.WaitForResult()); 240 EXPECT_EQ(OK, set_script_callback.WaitForResult());
159 EXPECT_EQ(ASCIIToUTF16("pac script bytes"), mock->last_pac_script()); 241 EXPECT_EQ(ASCIIToUTF16("pac script bytes"), mock->last_pac_script());
160 242
161 // Start request 0. 243 // Start request 0.
162 TestCompletionCallback callback0; 244 TestCompletionCallback callback0;
163 CapturingBoundNetLog log0(CapturingNetLog::kUnbounded); 245 CapturingBoundNetLog log0(CapturingNetLog::kUnbounded);
164 ProxyInfo results0; 246 ProxyInfo results0;
165 rv = resolver.GetProxyForURL( 247 rv = resolver.GetProxyForURL(
166 GURL("http://request0"), &results0, &callback0, NULL, log0.bound()); 248 GURL("http://request0"), &results0, &callback0, NULL, log0.bound());
167 EXPECT_EQ(ERR_IO_PENDING, rv); 249 EXPECT_EQ(ERR_IO_PENDING, rv);
168 250
169 // Wait for request 0 to finish. 251 // Wait for request 0 to finish.
170 rv = callback0.WaitForResult(); 252 rv = callback0.WaitForResult();
171 EXPECT_EQ(0, rv); 253 EXPECT_EQ(0, rv);
172 EXPECT_EQ("PROXY request0:80", results0.ToPacString()); 254 EXPECT_EQ("PROXY request0:80", results0.ToPacString());
173 255
174 // The mock proxy resolver should have written 1 log entry. And 256 // The mock proxy resolver should have written 1 log entry. And
175 // on completion, this should have been copied into |log0|. 257 // on completion, this should have been copied into |log0|.
176 EXPECT_EQ(1u, log0.entries().size()); 258 // We also have 1 log entry that was emitted by the
259 // MultiThreadedProxyResolver.
260 ASSERT_EQ(2u, log0.entries().size());
261 EXPECT_EQ(NetLog::TYPE_SUBMITTED_TO_RESOLVER_THREAD,
262 log0.entries()[0].type);
177 263
178 // Start 3 more requests (request1 to request3). 264 // Start 3 more requests (request1 to request3).
179 265
180 TestCompletionCallback callback1; 266 TestCompletionCallback callback1;
181 ProxyInfo results1; 267 ProxyInfo results1;
182 rv = resolver.GetProxyForURL( 268 rv = resolver.GetProxyForURL(
183 GURL("http://request1"), &results1, &callback1, NULL, BoundNetLog()); 269 GURL("http://request1"), &results1, &callback1, NULL, BoundNetLog());
184 EXPECT_EQ(ERR_IO_PENDING, rv); 270 EXPECT_EQ(ERR_IO_PENDING, rv);
185 271
186 TestCompletionCallback callback2; 272 TestCompletionCallback callback2;
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
218 // we queue up a dummy request after the PurgeMemory() call and wait until it 304 // we queue up a dummy request after the PurgeMemory() call and wait until it
219 // finishes to ensure PurgeMemory() has had a chance to run. 305 // finishes to ensure PurgeMemory() has had a chance to run.
220 TestCompletionCallback dummy_callback; 306 TestCompletionCallback dummy_callback;
221 rv = resolver.SetPacScriptByData(ASCIIToUTF16("dummy"), &dummy_callback); 307 rv = resolver.SetPacScriptByData(ASCIIToUTF16("dummy"), &dummy_callback);
222 EXPECT_EQ(OK, dummy_callback.WaitForResult()); 308 EXPECT_EQ(OK, dummy_callback.WaitForResult());
223 EXPECT_EQ(1, mock->purge_count()); 309 EXPECT_EQ(1, mock->purge_count());
224 } 310 }
225 311
226 // Tests that the NetLog is updated to include the time the request was waiting 312 // Tests that the NetLog is updated to include the time the request was waiting
227 // to be scheduled to a thread. 313 // to be scheduled to a thread.
228 TEST(SingleThreadedProxyResolverTest, UpdatesNetLogWithThreadWait) { 314 TEST(MultiThreadedProxyResolverTest,
229 BlockableProxyResolver* mock = new BlockableProxyResolver; 315 SingleThread_UpdatesNetLogWithThreadWait) {
230 SingleThreadedProxyResolver resolver(mock); 316 const size_t kNumThreads = 1u;
317 scoped_ptr<BlockableProxyResolver> mock(new BlockableProxyResolver);
318 MultiThreadedProxyResolver resolver(
319 new ForwardingProxyResolverFactory(mock.get()), kNumThreads);
231 320
232 int rv; 321 int rv;
233 322
323 // Initialize the resolver.
324 TestCompletionCallback init_callback;
325 rv = resolver.SetPacScriptByData(ASCIIToUTF16("foo"), &init_callback);
326 EXPECT_EQ(OK, init_callback.WaitForResult());
327
234 // Block the proxy resolver, so no request can complete. 328 // Block the proxy resolver, so no request can complete.
235 mock->Block(); 329 mock->Block();
236 330
237 // Start request 0. 331 // Start request 0.
238 ProxyResolver::RequestHandle request0; 332 ProxyResolver::RequestHandle request0;
239 TestCompletionCallback callback0; 333 TestCompletionCallback callback0;
240 ProxyInfo results0; 334 ProxyInfo results0;
241 CapturingBoundNetLog log0(CapturingNetLog::kUnbounded); 335 CapturingBoundNetLog log0(CapturingNetLog::kUnbounded);
242 rv = resolver.GetProxyForURL( 336 rv = resolver.GetProxyForURL(
243 GURL("http://request0"), &results0, &callback0, &request0, log0.bound()); 337 GURL("http://request0"), &results0, &callback0, &request0, log0.bound());
(...skipping 14 matching lines...) Expand all
258 CapturingBoundNetLog log2(CapturingNetLog::kUnbounded); 352 CapturingBoundNetLog log2(CapturingNetLog::kUnbounded);
259 rv = resolver.GetProxyForURL( 353 rv = resolver.GetProxyForURL(
260 GURL("http://request2"), &results2, &callback2, &request2, log2.bound()); 354 GURL("http://request2"), &results2, &callback2, &request2, log2.bound());
261 EXPECT_EQ(ERR_IO_PENDING, rv); 355 EXPECT_EQ(ERR_IO_PENDING, rv);
262 356
263 // Unblock the worker thread so the requests can continue running. 357 // Unblock the worker thread so the requests can continue running.
264 mock->WaitUntilBlocked(); 358 mock->WaitUntilBlocked();
265 mock->Unblock(); 359 mock->Unblock();
266 360
267 // Check that request 0 completed as expected. 361 // Check that request 0 completed as expected.
268 // The NetLog only has 1 entry (that came from the mock proxy resolver.) 362 // The NetLog has 1 entry that came from the MultiThreadedProxyResolver, and
363 // 1 entry from the mock proxy resolver.
269 EXPECT_EQ(0, callback0.WaitForResult()); 364 EXPECT_EQ(0, callback0.WaitForResult());
270 EXPECT_EQ("PROXY request0:80", results0.ToPacString()); 365 EXPECT_EQ("PROXY request0:80", results0.ToPacString());
271 ASSERT_EQ(1u, log0.entries().size()); 366 ASSERT_EQ(2u, log0.entries().size());
367 EXPECT_EQ(NetLog::TYPE_SUBMITTED_TO_RESOLVER_THREAD,
368 log0.entries()[0].type);
272 369
273 // Check that request 1 completed as expected. 370 // Check that request 1 completed as expected.
274 EXPECT_EQ(1, callback1.WaitForResult()); 371 EXPECT_EQ(1, callback1.WaitForResult());
275 EXPECT_EQ("PROXY request1:80", results1.ToPacString()); 372 EXPECT_EQ("PROXY request1:80", results1.ToPacString());
276 ASSERT_EQ(3u, log1.entries().size()); 373 ASSERT_EQ(4u, log1.entries().size());
277 EXPECT_TRUE(LogContainsBeginEvent( 374 EXPECT_TRUE(LogContainsBeginEvent(
278 log1.entries(), 0, 375 log1.entries(), 0,
279 NetLog::TYPE_WAITING_FOR_SINGLE_PROXY_RESOLVER_THREAD)); 376 NetLog::TYPE_WAITING_FOR_PROXY_RESOLVER_THREAD));
280 EXPECT_TRUE(LogContainsEndEvent( 377 EXPECT_TRUE(LogContainsEndEvent(
281 log1.entries(), 1, 378 log1.entries(), 1,
282 NetLog::TYPE_WAITING_FOR_SINGLE_PROXY_RESOLVER_THREAD)); 379 NetLog::TYPE_WAITING_FOR_PROXY_RESOLVER_THREAD));
283 380
284 // Check that request 2 completed as expected. 381 // Check that request 2 completed as expected.
285 EXPECT_EQ(2, callback2.WaitForResult()); 382 EXPECT_EQ(2, callback2.WaitForResult());
286 EXPECT_EQ("PROXY request2:80", results2.ToPacString()); 383 EXPECT_EQ("PROXY request2:80", results2.ToPacString());
287 ASSERT_EQ(3u, log2.entries().size()); 384 ASSERT_EQ(4u, log2.entries().size());
288 EXPECT_TRUE(LogContainsBeginEvent( 385 EXPECT_TRUE(LogContainsBeginEvent(
289 log2.entries(), 0, 386 log2.entries(), 0,
290 NetLog::TYPE_WAITING_FOR_SINGLE_PROXY_RESOLVER_THREAD)); 387 NetLog::TYPE_WAITING_FOR_PROXY_RESOLVER_THREAD));
291 EXPECT_TRUE(LogContainsEndEvent( 388 EXPECT_TRUE(LogContainsEndEvent(
292 log2.entries(), 1, 389 log2.entries(), 1,
293 NetLog::TYPE_WAITING_FOR_SINGLE_PROXY_RESOLVER_THREAD)); 390 NetLog::TYPE_WAITING_FOR_PROXY_RESOLVER_THREAD));
294 } 391 }
295 392
296 // Cancel a request which is in progress, and then cancel a request which 393 // Cancel a request which is in progress, and then cancel a request which
297 // is pending. 394 // is pending.
298 TEST(SingleThreadedProxyResolverTest, CancelRequest) { 395 TEST(MultiThreadedProxyResolverTest, SingleThread_CancelRequest) {
299 BlockableProxyResolver* mock = new BlockableProxyResolver; 396 const size_t kNumThreads = 1u;
300 SingleThreadedProxyResolver resolver(mock); 397 scoped_ptr<BlockableProxyResolver> mock(new BlockableProxyResolver);
398 MultiThreadedProxyResolver resolver(
399 new ForwardingProxyResolverFactory(mock.get()),
400 kNumThreads);
301 401
302 int rv; 402 int rv;
303 403
404 // Initialize the resolver.
405 TestCompletionCallback init_callback;
406 rv = resolver.SetPacScriptByData(ASCIIToUTF16("foo"), &init_callback);
407 EXPECT_EQ(OK, init_callback.WaitForResult());
408
304 // Block the proxy resolver, so no request can complete. 409 // Block the proxy resolver, so no request can complete.
305 mock->Block(); 410 mock->Block();
306 411
307 // Start request 0. 412 // Start request 0.
308 ProxyResolver::RequestHandle request0; 413 ProxyResolver::RequestHandle request0;
309 TestCompletionCallback callback0; 414 TestCompletionCallback callback0;
310 ProxyInfo results0; 415 ProxyInfo results0;
311 rv = resolver.GetProxyForURL( 416 rv = resolver.GetProxyForURL(
312 GURL("http://request0"), &results0, &callback0, &request0, BoundNetLog()); 417 GURL("http://request0"), &results0, &callback0, &request0, BoundNetLog());
313 EXPECT_EQ(ERR_IO_PENDING, rv); 418 EXPECT_EQ(ERR_IO_PENDING, rv);
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
354 // the request count is 2 and not 3 here. 459 // the request count is 2 and not 3 here.
355 EXPECT_EQ(2, rv); 460 EXPECT_EQ(2, rv);
356 EXPECT_EQ("PROXY request3:80", results3.ToPacString()); 461 EXPECT_EQ("PROXY request3:80", results3.ToPacString());
357 462
358 // Requests 0 and 2 which were cancelled, hence their completion callbacks 463 // Requests 0 and 2 which were cancelled, hence their completion callbacks
359 // were never summoned. 464 // were never summoned.
360 EXPECT_FALSE(callback0.have_result()); 465 EXPECT_FALSE(callback0.have_result());
361 EXPECT_FALSE(callback2.have_result()); 466 EXPECT_FALSE(callback2.have_result());
362 } 467 }
363 468
364 // Test that deleting SingleThreadedProxyResolver while requests are 469 // Test that deleting MultiThreadedProxyResolver while requests are
365 // outstanding cancels them (and doesn't leak anything). 470 // outstanding cancels them (and doesn't leak anything).
366 TEST(SingleThreadedProxyResolverTest, CancelRequestByDeleting) { 471 TEST(MultiThreadedProxyResolverTest, SingleThread_CancelRequestByDeleting) {
367 BlockableProxyResolver* mock = new BlockableProxyResolver; 472 const size_t kNumThreads = 1u;
368 scoped_ptr<SingleThreadedProxyResolver> resolver( 473 scoped_ptr<BlockableProxyResolver> mock(new BlockableProxyResolver);
369 new SingleThreadedProxyResolver(mock)); 474 scoped_ptr<MultiThreadedProxyResolver> resolver(
475 new MultiThreadedProxyResolver(
476 new ForwardingProxyResolverFactory(mock.get()), kNumThreads));
370 477
371 int rv; 478 int rv;
372 479
480 // Initialize the resolver.
481 TestCompletionCallback init_callback;
482 rv = resolver->SetPacScriptByData(ASCIIToUTF16("foo"), &init_callback);
483 EXPECT_EQ(OK, init_callback.WaitForResult());
484
373 // Block the proxy resolver, so no request can complete. 485 // Block the proxy resolver, so no request can complete.
374 mock->Block(); 486 mock->Block();
375 487
376 // Start 3 requests. 488 // Start 3 requests.
377 489
378 TestCompletionCallback callback0; 490 TestCompletionCallback callback0;
379 ProxyInfo results0; 491 ProxyInfo results0;
380 rv = resolver->GetProxyForURL( 492 rv = resolver->GetProxyForURL(
381 GURL("http://request0"), &results0, &callback0, NULL, BoundNetLog()); 493 GURL("http://request0"), &results0, &callback0, NULL, BoundNetLog());
382 EXPECT_EQ(ERR_IO_PENDING, rv); 494 EXPECT_EQ(ERR_IO_PENDING, rv);
383 495
384 TestCompletionCallback callback1; 496 TestCompletionCallback callback1;
385 ProxyInfo results1; 497 ProxyInfo results1;
386 rv = resolver->GetProxyForURL( 498 rv = resolver->GetProxyForURL(
387 GURL("http://request1"), &results1, &callback1, NULL, BoundNetLog()); 499 GURL("http://request1"), &results1, &callback1, NULL, BoundNetLog());
388 EXPECT_EQ(ERR_IO_PENDING, rv); 500 EXPECT_EQ(ERR_IO_PENDING, rv);
389 501
390 TestCompletionCallback callback2; 502 TestCompletionCallback callback2;
391 ProxyInfo results2; 503 ProxyInfo results2;
392 rv = resolver->GetProxyForURL( 504 rv = resolver->GetProxyForURL(
393 GURL("http://request2"), &results2, &callback2, NULL, BoundNetLog()); 505 GURL("http://request2"), &results2, &callback2, NULL, BoundNetLog());
394 EXPECT_EQ(ERR_IO_PENDING, rv); 506 EXPECT_EQ(ERR_IO_PENDING, rv);
395 507
396 // Wait until request 0 reaches the worker thread. 508 // Wait until request 0 reaches the worker thread.
397 mock->WaitUntilBlocked(); 509 mock->WaitUntilBlocked();
398 510
399 // Add some latency, to improve the chance that when 511 // Add some latency, to improve the chance that when
400 // SingleThreadedProxyResolver is deleted below we are still running inside 512 // MultiThreadedProxyResolver is deleted below we are still running inside
401 // of the worker thread. The test will pass regardless, so this race doesn't 513 // of the worker thread. The test will pass regardless, so this race doesn't
402 // cause flakiness. However the destruction during execution is a more 514 // cause flakiness. However the destruction during execution is a more
403 // interesting case to test. 515 // interesting case to test.
404 mock->SetResolveLatency(100); 516 mock->SetResolveLatency(100);
405 517
406 // Unblock the worker thread and delete the underlying 518 // Unblock the worker thread and delete the underlying
407 // SingleThreadedProxyResolver immediately. 519 // MultiThreadedProxyResolver immediately.
408 mock->Unblock(); 520 mock->Unblock();
409 resolver.reset(); 521 resolver.reset();
410 522
411 // Give any posted tasks a chance to run (in case there is badness). 523 // Give any posted tasks a chance to run (in case there is badness).
412 MessageLoop::current()->RunAllPending(); 524 MessageLoop::current()->RunAllPending();
413 525
414 // Check that none of the outstanding requests were completed. 526 // Check that none of the outstanding requests were completed.
415 EXPECT_FALSE(callback0.have_result()); 527 EXPECT_FALSE(callback0.have_result());
416 EXPECT_FALSE(callback1.have_result()); 528 EXPECT_FALSE(callback1.have_result());
417 EXPECT_FALSE(callback2.have_result()); 529 EXPECT_FALSE(callback2.have_result());
418 } 530 }
419 531
420 // Cancel an outstanding call to SetPacScriptByData(). 532 // Cancel an outstanding call to SetPacScriptByData().
421 TEST(SingleThreadedProxyResolverTest, CancelSetPacScript) { 533 TEST(MultiThreadedProxyResolverTest, SingleThread_CancelSetPacScript) {
422 BlockableProxyResolver* mock = new BlockableProxyResolver; 534 const size_t kNumThreads = 1u;
423 SingleThreadedProxyResolver resolver(mock); 535 scoped_ptr<BlockableProxyResolver> mock(new BlockableProxyResolver);
536 MultiThreadedProxyResolver resolver(
537 new ForwardingProxyResolverFactory(mock.get()), kNumThreads);
424 538
425 int rv; 539 int rv;
426 540
427 // Block the proxy resolver, so no request can complete.
428 mock->Block();
429
430 // Start request 0.
431 ProxyResolver::RequestHandle request0;
432 TestCompletionCallback callback0;
433 ProxyInfo results0;
434 rv = resolver.GetProxyForURL(
435 GURL("http://request0"), &results0, &callback0, &request0, BoundNetLog());
436 EXPECT_EQ(ERR_IO_PENDING, rv);
437
438 // Wait until requests 0 reaches the worker thread.
439 mock->WaitUntilBlocked();
440
441 TestCompletionCallback set_pac_script_callback; 541 TestCompletionCallback set_pac_script_callback;
442 rv = resolver.SetPacScriptByData(ASCIIToUTF16("data"), 542 rv = resolver.SetPacScriptByData(ASCIIToUTF16("data"),
443 &set_pac_script_callback); 543 &set_pac_script_callback);
444 EXPECT_EQ(ERR_IO_PENDING, rv); 544 EXPECT_EQ(ERR_IO_PENDING, rv);
445 545
446 // Cancel the SetPacScriptByData request (it can't have finished yet, 546 // Cancel the SetPacScriptByData request.
447 // since the single-thread is currently blocked).
448 resolver.CancelSetPacScript(); 547 resolver.CancelSetPacScript();
449 548
450 // Start 1 more request. 549 // Start another SetPacScript request
451 550 TestCompletionCallback set_pac_script_callback2;
452 TestCompletionCallback callback1; 551 rv = resolver.SetPacScriptByData(ASCIIToUTF16("data2"),
453 ProxyInfo results1; 552 &set_pac_script_callback2);
553 EXPECT_EQ(ERR_IO_PENDING, rv);
554
555 // Wait for the initialization to complete.
556
557 rv = set_pac_script_callback2.WaitForResult();
558 EXPECT_EQ(0, rv);
559 EXPECT_EQ(ASCIIToUTF16("data2"), mock->last_pac_script());
560
561 // The first SetPacScript callback should never have been completed.
562 EXPECT_FALSE(set_pac_script_callback.have_result());
563 }
564
565 // Tests setting the PAC script once, lazily creating new threads, and
566 // cancelling requests.
567 TEST(MultiThreadedProxyResolverTest, ThreeThreads_Basic) {
568 const size_t kNumThreads = 3u;
569 BlockableProxyResolverFactory* factory = new BlockableProxyResolverFactory;
570 MultiThreadedProxyResolver resolver(factory, kNumThreads);
571
572 int rv;
573
574 EXPECT_TRUE(resolver.expects_pac_bytes());
575
576 // Call SetPacScriptByData() -- verify that it reaches the synchronous
577 // resolver.
578 TestCompletionCallback set_script_callback;
579 rv = resolver.SetPacScriptByData(ASCIIToUTF16("pac script bytes"),
580 &set_script_callback);
581 EXPECT_EQ(ERR_IO_PENDING, rv);
582 EXPECT_EQ(OK, set_script_callback.WaitForResult());
583 // One thread has been provisioned (i.e. one ProxyResolver was created).
584 ASSERT_EQ(1u, factory->resolvers().size());
585 EXPECT_EQ(ASCIIToUTF16("pac script bytes"),
586 factory->resolvers()[0]->last_pac_script());
587
588 const int kNumRequests = 9;
589 TestCompletionCallback callback[kNumRequests];
590 ProxyInfo results[kNumRequests];
591 ProxyResolver::RequestHandle request[kNumRequests];
592
593 // Start request 0 -- this should run on thread 0 as there is nothing else
594 // going on right now.
454 rv = resolver.GetProxyForURL( 595 rv = resolver.GetProxyForURL(
455 GURL("http://request1"), &results1, &callback1, NULL, BoundNetLog()); 596 GURL("http://request0"), &results[0], &callback[0], &request[0],
456 EXPECT_EQ(ERR_IO_PENDING, rv); 597 BoundNetLog());
457 598 EXPECT_EQ(ERR_IO_PENDING, rv);
458 // Unblock the worker thread so the requests can continue running. 599
459 mock->Unblock(); 600 // Wait for request 0 to finish.
460 601 rv = callback[0].WaitForResult();
461 // Wait for requests 0 and 1 to finish.
462
463 rv = callback0.WaitForResult();
464 EXPECT_EQ(0, rv); 602 EXPECT_EQ(0, rv);
465 EXPECT_EQ("PROXY request0:80", results0.ToPacString()); 603 EXPECT_EQ("PROXY request0:80", results[0].ToPacString());
466 604 ASSERT_EQ(1u, factory->resolvers().size());
467 rv = callback1.WaitForResult(); 605 EXPECT_EQ(1, factory->resolvers()[0]->request_count());
468 EXPECT_EQ(1, rv); 606
469 EXPECT_EQ("PROXY request1:80", results1.ToPacString()); 607 MessageLoop::current()->RunAllPending();
470 608
471 // The SetPacScript callback should never have been completed. 609 // We now start 8 requests in parallel -- this will cause the maximum of
472 EXPECT_FALSE(set_pac_script_callback.have_result()); 610 // three threads to be provisioned (an additional two from what we already
611 // have).
612
613 for (int i = 1; i < kNumRequests; ++i) {
614 rv = resolver.GetProxyForURL(
615 GURL(StringPrintf("http://request%d", i)), &results[i], &callback[i],
616 &request[i], BoundNetLog());
617 EXPECT_EQ(ERR_IO_PENDING, rv);
618 }
619
620 // We should now have a total of 3 threads, each with its own ProxyResolver
621 // that will get initialized with the same data. (We check this later since
622 // the assignment happens on the worker threads and may not have occurred
623 // yet.)
624 ASSERT_EQ(3u, factory->resolvers().size());
625
626 // Cancel 3 of the 8 oustanding requests.
627 resolver.CancelRequest(request[1]);
628 resolver.CancelRequest(request[3]);
629 resolver.CancelRequest(request[6]);
630
631 // Wait for the remaining requests to complete.
632 int kNonCancelledRequests[] = {2, 4, 5, 7, 8};
633 for (size_t i = 0; i < arraysize(kNonCancelledRequests); ++i) {
634 int request_index = kNonCancelledRequests[i];
635 EXPECT_GE(callback[request_index].WaitForResult(), 0);
636 }
637
638 // Check that the cancelled requests never invoked their callback.
639 EXPECT_FALSE(callback[1].have_result());
640 EXPECT_FALSE(callback[3].have_result());
641 EXPECT_FALSE(callback[6].have_result());
642
643 // We call SetPacScript again, solely to stop the current worker threads.
644 // (That way we can test to see the values observed by the synchronous
645 // resolvers in a non-racy manner).
646 TestCompletionCallback set_script_callback2;
647 rv = resolver.SetPacScriptByData(ASCIIToUTF16("xyz"), &set_script_callback2);
648 EXPECT_EQ(ERR_IO_PENDING, rv);
649 EXPECT_EQ(OK, set_script_callback2.WaitForResult());
650 ASSERT_EQ(4u, factory->resolvers().size());
651
652 for (int i = 0; i < 3; ++i) {
653 EXPECT_EQ(ASCIIToUTF16("pac script bytes"),
654 factory->resolvers()[i]->last_pac_script()) << "i=" << i;
655 }
656
657 EXPECT_EQ(ASCIIToUTF16("xyz"),
658 factory->resolvers()[3]->last_pac_script());
659
660 // We don't know the exact ordering that requests ran on threads with,
661 // but we do know the total count that should have reached the threads.
662 // 8 total were submitted, and three were cancelled. Of the three that
663 // were cancelled, one of them (request 1) was cancelled after it had
664 // already been posted to the worker thread. So the resolvers will
665 // have seen 6 total (and 1 from the run prior).
666 ASSERT_EQ(4u, factory->resolvers().size());
667 int total_count = 0;
668 for (int i = 0; i < 3; ++i) {
669 total_count += factory->resolvers()[i]->request_count();
670 }
671 EXPECT_EQ(7, total_count);
672 }
673
674 // Tests using two threads. The first request hangs the first thread. Checks
675 // that other requests are able to complete while this first request remains
676 // stalled.
677 TEST(MultiThreadedProxyResolverTest, OneThreadBlocked) {
678 const size_t kNumThreads = 2u;
679 BlockableProxyResolverFactory* factory = new BlockableProxyResolverFactory;
680 MultiThreadedProxyResolver resolver(factory, kNumThreads);
681
682 int rv;
683
684 EXPECT_TRUE(resolver.expects_pac_bytes());
685
686 // Initialize the resolver.
687 TestCompletionCallback set_script_callback;
688 rv = resolver.SetPacScriptByData(ASCIIToUTF16("pac script bytes"),
689 &set_script_callback);
690 EXPECT_EQ(ERR_IO_PENDING, rv);
691 EXPECT_EQ(OK, set_script_callback.WaitForResult());
692 // One thread has been provisioned (i.e. one ProxyResolver was created).
693 ASSERT_EQ(1u, factory->resolvers().size());
694 EXPECT_EQ(ASCIIToUTF16("pac script bytes"),
695 factory->resolvers()[0]->last_pac_script());
696
697 const int kNumRequests = 4;
698 TestCompletionCallback callback[kNumRequests];
699 ProxyInfo results[kNumRequests];
700 ProxyResolver::RequestHandle request[kNumRequests];
701
702 // Start a request that will block the first thread.
703
704 factory->resolvers()[0]->Block();
705
706 rv = resolver.GetProxyForURL(
707 GURL("http://request0"), &results[0], &callback[0], &request[0],
708 BoundNetLog());
709
710 EXPECT_EQ(ERR_IO_PENDING, rv);
711 factory->resolvers()[0]->WaitUntilBlocked();
712
713 // Start 3 more requests -- they should all be serviced by thread #2
714 // since thread #1 is blocked.
715
716 for (int i = 1; i < kNumRequests; ++i) {
717 rv = resolver.GetProxyForURL(
718 GURL(StringPrintf("http://request%d", i)),
719 &results[i], &callback[i], &request[i], BoundNetLog());
720 EXPECT_EQ(ERR_IO_PENDING, rv);
721 }
722
723 // Wait for the three requests to complete (they should complete in FIFO
724 // order).
725 for (int i = 1; i < kNumRequests; ++i) {
726 EXPECT_EQ(i - 1, callback[i].WaitForResult());
727 }
728
729 // Unblock the first thread.
730 factory->resolvers()[0]->Unblock();
731 EXPECT_EQ(0, callback[0].WaitForResult());
732
733 // All in all, the first thread should have seen just 1 request. And the
734 // second thread 3 requests.
735 ASSERT_EQ(2u, factory->resolvers().size());
736 EXPECT_EQ(1, factory->resolvers()[0]->request_count());
737 EXPECT_EQ(3, factory->resolvers()[1]->request_count());
473 } 738 }
474 739
475 } // namespace 740 } // namespace
741
476 } // namespace net 742 } // namespace net
OLDNEW
« no previous file with comments | « net/proxy/multi_threaded_proxy_resolver.cc ('k') | net/proxy/proxy_resolver.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698