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

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

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

Powered by Google App Engine
This is Rietveld 408576698