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

Side by Side Diff: net/proxy/single_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/single_threaded_proxy_resolver.cc ('k') | net/proxy/sync_host_resolver_bridge.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) 2009 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 "base/string_util.h"
6 #include "base/waitable_event.h"
7 #include "googleurl/src/gurl.h"
8 #include "net/base/net_log.h"
9 #include "net/base/net_log_unittest.h"
10 #include "net/base/net_errors.h"
11 #include "net/base/test_completion_callback.h"
12 #include "net/proxy/proxy_info.h"
13 #include "net/proxy/single_threaded_proxy_resolver.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace net {
17 namespace {
18
19 // A synchronous mock ProxyResolver implementation, which can be used in
20 // conjunction with SingleThreadedProxyResolver.
21 // - returns a single-item proxy list with the query's host.
22 class MockProxyResolver : public ProxyResolver {
23 public:
24 MockProxyResolver()
25 : ProxyResolver(true /*expects_pac_bytes*/),
26 wrong_loop_(MessageLoop::current()),
27 request_count_(0),
28 purge_count_(0),
29 resolve_latency_ms_(0) {}
30
31 // ProxyResolver implementation:
32 virtual int GetProxyForURL(const GURL& query_url,
33 ProxyInfo* results,
34 CompletionCallback* callback,
35 RequestHandle* request,
36 const BoundNetLog& net_log) {
37 if (resolve_latency_ms_)
38 PlatformThread::Sleep(resolve_latency_ms_);
39
40 CheckIsOnWorkerThread();
41
42 EXPECT_TRUE(callback == NULL);
43 EXPECT_TRUE(request == NULL);
44
45 // Write something into |net_log| (doesn't really have any meaning.)
46 net_log.BeginEvent(NetLog::TYPE_PROXY_RESOLVER_V8_DNS_RESOLVE, NULL);
47
48 results->UseNamedProxy(query_url.host());
49
50 // Return a success code which represents the request's order.
51 return request_count_++;
52 }
53
54 virtual void CancelRequest(RequestHandle request) {
55 NOTREACHED();
56 }
57
58 virtual int SetPacScript(const GURL& pac_url,
59 const string16& text,
60 CompletionCallback* callback) {
61 CheckIsOnWorkerThread();
62 last_pac_script_ = text;
63 return OK;
64 }
65
66 virtual void PurgeMemory() {
67 CheckIsOnWorkerThread();
68 ++purge_count_;
69 }
70
71 int purge_count() const { return purge_count_; }
72
73 const string16& last_pac_script() const { return last_pac_script_; }
74
75 void SetResolveLatency(int latency_ms) {
76 resolve_latency_ms_ = latency_ms;
77 }
78
79 private:
80 void CheckIsOnWorkerThread() {
81 // We should be running on the worker thread -- while we don't know the
82 // message loop of SingleThreadedProxyResolver's worker thread, we do
83 // 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.
85 EXPECT_NE(MessageLoop::current(), wrong_loop_);
86 }
87
88 MessageLoop* wrong_loop_;
89 int request_count_;
90 int purge_count_;
91 string16 last_pac_script_;
92 int resolve_latency_ms_;
93 };
94
95
96 // A mock synchronous ProxyResolver which can be set to block upon reaching
97 // GetProxyForURL().
98 // TODO(eroman): WaitUntilBlocked() *must* be called before calling Unblock(),
99 // otherwise there will be a race on |should_block_| since it is
100 // read without any synchronization.
101 class BlockableProxyResolver : public MockProxyResolver {
102 public:
103 BlockableProxyResolver()
104 : should_block_(false),
105 unblocked_(true, true),
106 blocked_(true, false) {
107 }
108
109 void Block() {
110 should_block_ = true;
111 unblocked_.Reset();
112 }
113
114 void Unblock() {
115 should_block_ = false;
116 blocked_.Reset();
117 unblocked_.Signal();
118 }
119
120 void WaitUntilBlocked() {
121 blocked_.Wait();
122 }
123
124 virtual int GetProxyForURL(const GURL& query_url,
125 ProxyInfo* results,
126 CompletionCallback* callback,
127 RequestHandle* request,
128 const BoundNetLog& net_log) {
129 if (should_block_) {
130 blocked_.Signal();
131 unblocked_.Wait();
132 }
133
134 return MockProxyResolver::GetProxyForURL(
135 query_url, results, callback, request, net_log);
136 }
137
138 private:
139 bool should_block_;
140 base::WaitableEvent unblocked_;
141 base::WaitableEvent blocked_;
142 };
143
144 TEST(SingleThreadedProxyResolverTest, Basic) {
145 MockProxyResolver* mock = new MockProxyResolver;
146 SingleThreadedProxyResolver resolver(mock);
147
148 int rv;
149
150 EXPECT_TRUE(resolver.expects_pac_bytes());
151
152 // Call SetPacScriptByData() -- verify that it reaches the synchronous
153 // resolver.
154 TestCompletionCallback set_script_callback;
155 rv = resolver.SetPacScriptByData(ASCIIToUTF16("pac script bytes"),
156 &set_script_callback);
157 EXPECT_EQ(ERR_IO_PENDING, rv);
158 EXPECT_EQ(OK, set_script_callback.WaitForResult());
159 EXPECT_EQ(ASCIIToUTF16("pac script bytes"), mock->last_pac_script());
160
161 // Start request 0.
162 TestCompletionCallback callback0;
163 CapturingBoundNetLog log0(CapturingNetLog::kUnbounded);
164 ProxyInfo results0;
165 rv = resolver.GetProxyForURL(
166 GURL("http://request0"), &results0, &callback0, NULL, log0.bound());
167 EXPECT_EQ(ERR_IO_PENDING, rv);
168
169 // Wait for request 0 to finish.
170 rv = callback0.WaitForResult();
171 EXPECT_EQ(0, rv);
172 EXPECT_EQ("PROXY request0:80", results0.ToPacString());
173
174 // The mock proxy resolver should have written 1 log entry. And
175 // on completion, this should have been copied into |log0|.
176 EXPECT_EQ(1u, log0.entries().size());
177
178 // Start 3 more requests (request1 to request3).
179
180 TestCompletionCallback callback1;
181 ProxyInfo results1;
182 rv = resolver.GetProxyForURL(
183 GURL("http://request1"), &results1, &callback1, NULL, BoundNetLog());
184 EXPECT_EQ(ERR_IO_PENDING, rv);
185
186 TestCompletionCallback callback2;
187 ProxyInfo results2;
188 rv = resolver.GetProxyForURL(
189 GURL("http://request2"), &results2, &callback2, NULL, BoundNetLog());
190 EXPECT_EQ(ERR_IO_PENDING, rv);
191
192 TestCompletionCallback callback3;
193 ProxyInfo results3;
194 rv = resolver.GetProxyForURL(
195 GURL("http://request3"), &results3, &callback3, NULL, BoundNetLog());
196 EXPECT_EQ(ERR_IO_PENDING, rv);
197
198 // Wait for the requests to finish (they must finish in the order they were
199 // started, which is what we check for from their magic return value)
200
201 rv = callback1.WaitForResult();
202 EXPECT_EQ(1, rv);
203 EXPECT_EQ("PROXY request1:80", results1.ToPacString());
204
205 rv = callback2.WaitForResult();
206 EXPECT_EQ(2, rv);
207 EXPECT_EQ("PROXY request2:80", results2.ToPacString());
208
209 rv = callback3.WaitForResult();
210 EXPECT_EQ(3, rv);
211 EXPECT_EQ("PROXY request3:80", results3.ToPacString());
212
213 // Ensure that PurgeMemory() reaches the wrapped resolver and happens on the
214 // right thread.
215 EXPECT_EQ(0, mock->purge_count());
216 resolver.PurgeMemory();
217 // There is no way to get a callback directly when PurgeMemory() completes, so
218 // 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.
220 TestCompletionCallback dummy_callback;
221 rv = resolver.SetPacScriptByData(ASCIIToUTF16("dummy"), &dummy_callback);
222 EXPECT_EQ(OK, dummy_callback.WaitForResult());
223 EXPECT_EQ(1, mock->purge_count());
224 }
225
226 // Tests that the NetLog is updated to include the time the request was waiting
227 // to be scheduled to a thread.
228 TEST(SingleThreadedProxyResolverTest, UpdatesNetLogWithThreadWait) {
229 BlockableProxyResolver* mock = new BlockableProxyResolver;
230 SingleThreadedProxyResolver resolver(mock);
231
232 int rv;
233
234 // Block the proxy resolver, so no request can complete.
235 mock->Block();
236
237 // Start request 0.
238 ProxyResolver::RequestHandle request0;
239 TestCompletionCallback callback0;
240 ProxyInfo results0;
241 CapturingBoundNetLog log0(CapturingNetLog::kUnbounded);
242 rv = resolver.GetProxyForURL(
243 GURL("http://request0"), &results0, &callback0, &request0, log0.bound());
244 EXPECT_EQ(ERR_IO_PENDING, rv);
245
246 // Start 2 more requests (request1 and request2).
247
248 TestCompletionCallback callback1;
249 ProxyInfo results1;
250 CapturingBoundNetLog log1(CapturingNetLog::kUnbounded);
251 rv = resolver.GetProxyForURL(
252 GURL("http://request1"), &results1, &callback1, NULL, log1.bound());
253 EXPECT_EQ(ERR_IO_PENDING, rv);
254
255 ProxyResolver::RequestHandle request2;
256 TestCompletionCallback callback2;
257 ProxyInfo results2;
258 CapturingBoundNetLog log2(CapturingNetLog::kUnbounded);
259 rv = resolver.GetProxyForURL(
260 GURL("http://request2"), &results2, &callback2, &request2, log2.bound());
261 EXPECT_EQ(ERR_IO_PENDING, rv);
262
263 // Unblock the worker thread so the requests can continue running.
264 mock->WaitUntilBlocked();
265 mock->Unblock();
266
267 // Check that request 0 completed as expected.
268 // The NetLog only has 1 entry (that came from the mock proxy resolver.)
269 EXPECT_EQ(0, callback0.WaitForResult());
270 EXPECT_EQ("PROXY request0:80", results0.ToPacString());
271 ASSERT_EQ(1u, log0.entries().size());
272
273 // Check that request 1 completed as expected.
274 EXPECT_EQ(1, callback1.WaitForResult());
275 EXPECT_EQ("PROXY request1:80", results1.ToPacString());
276 ASSERT_EQ(3u, log1.entries().size());
277 EXPECT_TRUE(LogContainsBeginEvent(
278 log1.entries(), 0,
279 NetLog::TYPE_WAITING_FOR_SINGLE_PROXY_RESOLVER_THREAD));
280 EXPECT_TRUE(LogContainsEndEvent(
281 log1.entries(), 1,
282 NetLog::TYPE_WAITING_FOR_SINGLE_PROXY_RESOLVER_THREAD));
283
284 // Check that request 2 completed as expected.
285 EXPECT_EQ(2, callback2.WaitForResult());
286 EXPECT_EQ("PROXY request2:80", results2.ToPacString());
287 ASSERT_EQ(3u, log2.entries().size());
288 EXPECT_TRUE(LogContainsBeginEvent(
289 log2.entries(), 0,
290 NetLog::TYPE_WAITING_FOR_SINGLE_PROXY_RESOLVER_THREAD));
291 EXPECT_TRUE(LogContainsEndEvent(
292 log2.entries(), 1,
293 NetLog::TYPE_WAITING_FOR_SINGLE_PROXY_RESOLVER_THREAD));
294 }
295
296 // Cancel a request which is in progress, and then cancel a request which
297 // is pending.
298 TEST(SingleThreadedProxyResolverTest, CancelRequest) {
299 BlockableProxyResolver* mock = new BlockableProxyResolver;
300 SingleThreadedProxyResolver resolver(mock);
301
302 int rv;
303
304 // Block the proxy resolver, so no request can complete.
305 mock->Block();
306
307 // Start request 0.
308 ProxyResolver::RequestHandle request0;
309 TestCompletionCallback callback0;
310 ProxyInfo results0;
311 rv = resolver.GetProxyForURL(
312 GURL("http://request0"), &results0, &callback0, &request0, BoundNetLog());
313 EXPECT_EQ(ERR_IO_PENDING, rv);
314
315 // Wait until requests 0 reaches the worker thread.
316 mock->WaitUntilBlocked();
317
318 // Start 3 more requests (request1 : request3).
319
320 TestCompletionCallback callback1;
321 ProxyInfo results1;
322 rv = resolver.GetProxyForURL(
323 GURL("http://request1"), &results1, &callback1, NULL, BoundNetLog());
324 EXPECT_EQ(ERR_IO_PENDING, rv);
325
326 ProxyResolver::RequestHandle request2;
327 TestCompletionCallback callback2;
328 ProxyInfo results2;
329 rv = resolver.GetProxyForURL(
330 GURL("http://request2"), &results2, &callback2, &request2, BoundNetLog());
331 EXPECT_EQ(ERR_IO_PENDING, rv);
332
333 TestCompletionCallback callback3;
334 ProxyInfo results3;
335 rv = resolver.GetProxyForURL(
336 GURL("http://request3"), &results3, &callback3, NULL, BoundNetLog());
337 EXPECT_EQ(ERR_IO_PENDING, rv);
338
339 // Cancel request0 (inprogress) and request2 (pending).
340 resolver.CancelRequest(request0);
341 resolver.CancelRequest(request2);
342
343 // Unblock the worker thread so the requests can continue running.
344 mock->Unblock();
345
346 // Wait for requests 1 and 3 to finish.
347
348 rv = callback1.WaitForResult();
349 EXPECT_EQ(1, rv);
350 EXPECT_EQ("PROXY request1:80", results1.ToPacString());
351
352 rv = callback3.WaitForResult();
353 // Note that since request2 was cancelled before reaching the resolver,
354 // the request count is 2 and not 3 here.
355 EXPECT_EQ(2, rv);
356 EXPECT_EQ("PROXY request3:80", results3.ToPacString());
357
358 // Requests 0 and 2 which were cancelled, hence their completion callbacks
359 // were never summoned.
360 EXPECT_FALSE(callback0.have_result());
361 EXPECT_FALSE(callback2.have_result());
362 }
363
364 // Test that deleting SingleThreadedProxyResolver while requests are
365 // outstanding cancels them (and doesn't leak anything).
366 TEST(SingleThreadedProxyResolverTest, CancelRequestByDeleting) {
367 BlockableProxyResolver* mock = new BlockableProxyResolver;
368 scoped_ptr<SingleThreadedProxyResolver> resolver(
369 new SingleThreadedProxyResolver(mock));
370
371 int rv;
372
373 // Block the proxy resolver, so no request can complete.
374 mock->Block();
375
376 // Start 3 requests.
377
378 TestCompletionCallback callback0;
379 ProxyInfo results0;
380 rv = resolver->GetProxyForURL(
381 GURL("http://request0"), &results0, &callback0, NULL, BoundNetLog());
382 EXPECT_EQ(ERR_IO_PENDING, rv);
383
384 TestCompletionCallback callback1;
385 ProxyInfo results1;
386 rv = resolver->GetProxyForURL(
387 GURL("http://request1"), &results1, &callback1, NULL, BoundNetLog());
388 EXPECT_EQ(ERR_IO_PENDING, rv);
389
390 TestCompletionCallback callback2;
391 ProxyInfo results2;
392 rv = resolver->GetProxyForURL(
393 GURL("http://request2"), &results2, &callback2, NULL, BoundNetLog());
394 EXPECT_EQ(ERR_IO_PENDING, rv);
395
396 // Wait until request 0 reaches the worker thread.
397 mock->WaitUntilBlocked();
398
399 // Add some latency, to improve the chance that when
400 // SingleThreadedProxyResolver is deleted below we are still running inside
401 // 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
403 // interesting case to test.
404 mock->SetResolveLatency(100);
405
406 // Unblock the worker thread and delete the underlying
407 // SingleThreadedProxyResolver immediately.
408 mock->Unblock();
409 resolver.reset();
410
411 // Give any posted tasks a chance to run (in case there is badness).
412 MessageLoop::current()->RunAllPending();
413
414 // Check that none of the outstanding requests were completed.
415 EXPECT_FALSE(callback0.have_result());
416 EXPECT_FALSE(callback1.have_result());
417 EXPECT_FALSE(callback2.have_result());
418 }
419
420 // Cancel an outstanding call to SetPacScriptByData().
421 TEST(SingleThreadedProxyResolverTest, CancelSetPacScript) {
422 BlockableProxyResolver* mock = new BlockableProxyResolver;
423 SingleThreadedProxyResolver resolver(mock);
424
425 int rv;
426
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;
442 rv = resolver.SetPacScriptByData(ASCIIToUTF16("data"),
443 &set_pac_script_callback);
444 EXPECT_EQ(ERR_IO_PENDING, rv);
445
446 // Cancel the SetPacScriptByData request (it can't have finished yet,
447 // since the single-thread is currently blocked).
448 resolver.CancelSetPacScript();
449
450 // Start 1 more request.
451
452 TestCompletionCallback callback1;
453 ProxyInfo results1;
454 rv = resolver.GetProxyForURL(
455 GURL("http://request1"), &results1, &callback1, NULL, BoundNetLog());
456 EXPECT_EQ(ERR_IO_PENDING, rv);
457
458 // Unblock the worker thread so the requests can continue running.
459 mock->Unblock();
460
461 // Wait for requests 0 and 1 to finish.
462
463 rv = callback0.WaitForResult();
464 EXPECT_EQ(0, rv);
465 EXPECT_EQ("PROXY request0:80", results0.ToPacString());
466
467 rv = callback1.WaitForResult();
468 EXPECT_EQ(1, rv);
469 EXPECT_EQ("PROXY request1:80", results1.ToPacString());
470
471 // The SetPacScript callback should never have been completed.
472 EXPECT_FALSE(set_pac_script_callback.have_result());
473 }
474
475 } // namespace
476 } // namespace net
OLDNEW
« no previous file with comments | « net/proxy/single_threaded_proxy_resolver.cc ('k') | net/proxy/sync_host_resolver_bridge.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698