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

Side by Side Diff: net/base/host_resolver_unittest.cc

Issue 149511: Refactorings surrounding HostResolver:... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Merge in socks5_client_socket_unittest.cc Created 11 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/base/host_resolver_proc.cc ('k') | net/base/mock_host_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
(Empty)
1 // Copyright (c) 2006-2008 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/base/host_resolver.h"
6
7 #if defined(OS_WIN)
8 #include <ws2tcpip.h>
9 #include <wspiapi.h>
10 #elif defined(OS_POSIX)
11 #include <netdb.h>
12 #endif
13
14 #include <string>
15
16 #include "base/compiler_specific.h"
17 #include "base/message_loop.h"
18 #include "base/ref_counted.h"
19 #include "net/base/address_list.h"
20 #include "net/base/completion_callback.h"
21 #include "net/base/host_resolver_unittest.h"
22 #include "net/base/net_errors.h"
23 #include "net/base/test_completion_callback.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 using net::RuleBasedHostMapper;
27 using net::ScopedHostMapper;
28 using net::WaitingHostMapper;
29
30 // TODO(eroman):
31 // - Test mixing async with sync (in particular how does sync update the
32 // cache while an async is already pending).
33
34 namespace {
35
36 // A variant of WaitingHostMapper that pushes each host mapped into a list.
37 // (and uses a manual-reset event rather than auto-reset).
38 class CapturingHostMapper : public net::HostMapper {
39 public:
40 CapturingHostMapper() : event_(true, false) {
41 }
42
43 void Signal() {
44 event_.Signal();
45 }
46
47 virtual std::string Map(const std::string& host) {
48 event_.Wait();
49 {
50 AutoLock l(lock_);
51 capture_list_.push_back(host);
52 }
53 return MapUsingPrevious(host);
54 }
55
56 std::vector<std::string> GetCaptureList() const {
57 std::vector<std::string> copy;
58 {
59 AutoLock l(lock_);
60 copy = capture_list_;
61 }
62 return copy;
63 }
64
65 private:
66 std::vector<std::string> capture_list_;
67 mutable Lock lock_;
68 base::WaitableEvent event_;
69 };
70
71 // Helper that represents a single Resolve() result, used to inspect all the
72 // resolve results by forwarding them to Delegate.
73 class ResolveRequest {
74 public:
75 // Delegate interface, for notification when the ResolveRequest completes.
76 class Delegate {
77 public:
78 virtual ~Delegate() {}
79 virtual void OnCompleted(ResolveRequest* resolve) = 0;
80 };
81
82 ResolveRequest(net::HostResolver* resolver,
83 const std::string& hostname,
84 int port,
85 Delegate* delegate)
86 : info_(hostname, port), resolver_(resolver), delegate_(delegate),
87 ALLOW_THIS_IN_INITIALIZER_LIST(
88 callback_(this, &ResolveRequest::OnLookupFinished)) {
89 // Start the request.
90 int err = resolver->Resolve(info_, &addrlist_, &callback_, &req_);
91 EXPECT_EQ(net::ERR_IO_PENDING, err);
92 }
93
94 ResolveRequest(net::HostResolver* resolver,
95 const net::HostResolver::RequestInfo& info,
96 Delegate* delegate)
97 : info_(info), resolver_(resolver), delegate_(delegate),
98 ALLOW_THIS_IN_INITIALIZER_LIST(
99 callback_(this, &ResolveRequest::OnLookupFinished)) {
100 // Start the request.
101 int err = resolver->Resolve(info, &addrlist_, &callback_, &req_);
102 EXPECT_EQ(net::ERR_IO_PENDING, err);
103 }
104
105 void Cancel() {
106 resolver_->CancelRequest(req_);
107 }
108
109 const std::string& hostname() const {
110 return info_.hostname();
111 }
112
113 int port() const {
114 return info_.port();
115 }
116
117 int result() const {
118 return result_;
119 }
120
121 const net::AddressList& addrlist() const {
122 return addrlist_;
123 }
124
125 net::HostResolver* resolver() const {
126 return resolver_;
127 }
128
129 private:
130 void OnLookupFinished(int result) {
131 result_ = result;
132 delegate_->OnCompleted(this);
133 }
134
135 // The request details.
136 net::HostResolver::RequestInfo info_;
137 net::HostResolver::Request* req_;
138
139 // The result of the resolve.
140 int result_;
141 net::AddressList addrlist_;
142
143 // We don't use a scoped_refptr, to simplify deleting shared resolver in
144 // DeleteWithinCallback test.
145 net::HostResolver* resolver_;
146
147 Delegate* delegate_;
148 net::CompletionCallbackImpl<ResolveRequest> callback_;
149
150 DISALLOW_COPY_AND_ASSIGN(ResolveRequest);
151 };
152
153 class HostResolverTest : public testing::Test {
154 public:
155 HostResolverTest()
156 : callback_called_(false),
157 ALLOW_THIS_IN_INITIALIZER_LIST(
158 callback_(this, &HostResolverTest::OnLookupFinished)) {
159 }
160
161 protected:
162 bool callback_called_;
163 int callback_result_;
164 net::CompletionCallbackImpl<HostResolverTest> callback_;
165
166 private:
167 void OnLookupFinished(int result) {
168 callback_called_ = true;
169 callback_result_ = result;
170 MessageLoop::current()->Quit();
171 }
172 };
173
174 TEST_F(HostResolverTest, SynchronousLookup) {
175 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
176 net::AddressList adrlist;
177 const int kPortnum = 80;
178
179 scoped_refptr<RuleBasedHostMapper> mapper = new RuleBasedHostMapper();
180 mapper->AddRule("just.testing", "192.168.1.42");
181 ScopedHostMapper scoped_mapper(mapper.get());
182
183 net::HostResolver::RequestInfo info("just.testing", kPortnum);
184 int err = host_resolver->Resolve(info, &adrlist, NULL, NULL);
185 EXPECT_EQ(net::OK, err);
186
187 const struct addrinfo* ainfo = adrlist.head();
188 EXPECT_EQ(static_cast<addrinfo*>(NULL), ainfo->ai_next);
189 EXPECT_EQ(sizeof(struct sockaddr_in), ainfo->ai_addrlen);
190
191 const struct sockaddr* sa = ainfo->ai_addr;
192 const struct sockaddr_in* sa_in = (const struct sockaddr_in*) sa;
193 EXPECT_TRUE(htons(kPortnum) == sa_in->sin_port);
194 EXPECT_TRUE(htonl(0xc0a8012a) == sa_in->sin_addr.s_addr);
195 }
196
197 TEST_F(HostResolverTest, AsynchronousLookup) {
198 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
199 net::AddressList adrlist;
200 const int kPortnum = 80;
201
202 scoped_refptr<RuleBasedHostMapper> mapper = new RuleBasedHostMapper();
203 mapper->AddRule("just.testing", "192.168.1.42");
204 ScopedHostMapper scoped_mapper(mapper.get());
205
206 net::HostResolver::RequestInfo info("just.testing", kPortnum);
207 int err = host_resolver->Resolve(info, &adrlist, &callback_, NULL);
208 EXPECT_EQ(net::ERR_IO_PENDING, err);
209
210 MessageLoop::current()->Run();
211
212 ASSERT_TRUE(callback_called_);
213 ASSERT_EQ(net::OK, callback_result_);
214
215 const struct addrinfo* ainfo = adrlist.head();
216 EXPECT_EQ(static_cast<addrinfo*>(NULL), ainfo->ai_next);
217 EXPECT_EQ(sizeof(struct sockaddr_in), ainfo->ai_addrlen);
218
219 const struct sockaddr* sa = ainfo->ai_addr;
220 const struct sockaddr_in* sa_in = (const struct sockaddr_in*) sa;
221 EXPECT_TRUE(htons(kPortnum) == sa_in->sin_port);
222 EXPECT_TRUE(htonl(0xc0a8012a) == sa_in->sin_addr.s_addr);
223 }
224
225 TEST_F(HostResolverTest, CanceledAsynchronousLookup) {
226 scoped_refptr<WaitingHostMapper> mapper = new WaitingHostMapper();
227 ScopedHostMapper scoped_mapper(mapper.get());
228
229 {
230 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
231 net::AddressList adrlist;
232 const int kPortnum = 80;
233
234 net::HostResolver::RequestInfo info("just.testing", kPortnum);
235 int err = host_resolver->Resolve(info, &adrlist, &callback_, NULL);
236 EXPECT_EQ(net::ERR_IO_PENDING, err);
237
238 // Make sure we will exit the queue even when callback is not called.
239 MessageLoop::current()->PostDelayedTask(FROM_HERE,
240 new MessageLoop::QuitTask(),
241 1000);
242 MessageLoop::current()->Run();
243 }
244
245 mapper->Signal();
246
247 EXPECT_FALSE(callback_called_);
248 }
249
250 TEST_F(HostResolverTest, NumericIPv4Address) {
251 // Stevens says dotted quads with AI_UNSPEC resolve to a single sockaddr_in.
252
253 scoped_refptr<RuleBasedHostMapper> mapper = new RuleBasedHostMapper();
254 mapper->AllowDirectLookup("*");
255 ScopedHostMapper scoped_mapper(mapper.get());
256
257 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
258 net::AddressList adrlist;
259 const int kPortnum = 5555;
260 net::HostResolver::RequestInfo info("127.1.2.3", kPortnum);
261 int err = host_resolver->Resolve(info, &adrlist, NULL, NULL);
262 EXPECT_EQ(net::OK, err);
263
264 const struct addrinfo* ainfo = adrlist.head();
265 EXPECT_EQ(static_cast<addrinfo*>(NULL), ainfo->ai_next);
266 EXPECT_EQ(sizeof(struct sockaddr_in), ainfo->ai_addrlen);
267
268 const struct sockaddr* sa = ainfo->ai_addr;
269 const struct sockaddr_in* sa_in = (const struct sockaddr_in*) sa;
270 EXPECT_TRUE(htons(kPortnum) == sa_in->sin_port);
271 EXPECT_TRUE(htonl(0x7f010203) == sa_in->sin_addr.s_addr);
272 }
273
274 TEST_F(HostResolverTest, NumericIPv6Address) {
275 scoped_refptr<RuleBasedHostMapper> mapper = new RuleBasedHostMapper();
276 mapper->AllowDirectLookup("*");
277 ScopedHostMapper scoped_mapper(mapper.get());
278
279 // Resolve a plain IPv6 address. Don't worry about [brackets], because
280 // the caller should have removed them.
281 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
282 net::AddressList adrlist;
283 const int kPortnum = 5555;
284 net::HostResolver::RequestInfo info("2001:db8::1", kPortnum);
285 int err = host_resolver->Resolve(info, &adrlist, NULL, NULL);
286 // On computers without IPv6 support, getaddrinfo cannot convert IPv6
287 // address literals to addresses (getaddrinfo returns EAI_NONAME). So this
288 // test has to allow host_resolver->Resolve to fail.
289 if (err == net::ERR_NAME_NOT_RESOLVED)
290 return;
291 EXPECT_EQ(net::OK, err);
292
293 const struct addrinfo* ainfo = adrlist.head();
294 EXPECT_EQ(static_cast<addrinfo*>(NULL), ainfo->ai_next);
295 EXPECT_EQ(sizeof(struct sockaddr_in6), ainfo->ai_addrlen);
296
297 const struct sockaddr* sa = ainfo->ai_addr;
298 const struct sockaddr_in6* sa_in6 = (const struct sockaddr_in6*) sa;
299 EXPECT_TRUE(htons(kPortnum) == sa_in6->sin6_port);
300
301 const uint8 expect_addr[] = {
302 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00,
303 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
304 };
305 for (int i = 0; i < 16; i++) {
306 EXPECT_EQ(expect_addr[i], sa_in6->sin6_addr.s6_addr[i]);
307 }
308 }
309
310 TEST_F(HostResolverTest, EmptyHost) {
311 scoped_refptr<RuleBasedHostMapper> mapper = new RuleBasedHostMapper();
312 mapper->AllowDirectLookup("*");
313 ScopedHostMapper scoped_mapper(mapper.get());
314
315 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
316 net::AddressList adrlist;
317 const int kPortnum = 5555;
318 net::HostResolver::RequestInfo info("", kPortnum);
319 int err = host_resolver->Resolve(info, &adrlist, NULL, NULL);
320 EXPECT_EQ(net::ERR_NAME_NOT_RESOLVED, err);
321 }
322
323 // Helper class used by HostResolverTest.DeDupeRequests. It receives request
324 // completion notifications for all the resolves, so it can tally up and
325 // determine when we are done.
326 class DeDupeRequestsVerifier : public ResolveRequest::Delegate {
327 public:
328 explicit DeDupeRequestsVerifier(CapturingHostMapper* mapper)
329 : count_a_(0), count_b_(0), mapper_(mapper) {}
330
331 // The test does 5 resolves (which can complete in any order).
332 virtual void OnCompleted(ResolveRequest* resolve) {
333 // Tally up how many requests we have seen.
334 if (resolve->hostname() == "a") {
335 count_a_++;
336 } else if (resolve->hostname() == "b") {
337 count_b_++;
338 } else {
339 FAIL() << "Unexpected hostname: " << resolve->hostname();
340 }
341
342 // Check that the port was set correctly.
343 EXPECT_EQ(resolve->port(), resolve->addrlist().GetPort());
344
345 // Check whether all the requests have finished yet.
346 int total_completions = count_a_ + count_b_;
347 if (total_completions == 5) {
348 EXPECT_EQ(2, count_a_);
349 EXPECT_EQ(3, count_b_);
350
351 // The mapper should have been called only twice -- once with "a", once
352 // with "b".
353 std::vector<std::string> capture_list = mapper_->GetCaptureList();
354 EXPECT_EQ(2U, capture_list.size());
355
356 // End this test, we are done.
357 MessageLoop::current()->Quit();
358 }
359 }
360
361 private:
362 int count_a_;
363 int count_b_;
364 CapturingHostMapper* mapper_;
365
366 DISALLOW_COPY_AND_ASSIGN(DeDupeRequestsVerifier);
367 };
368
369 TEST_F(HostResolverTest, DeDupeRequests) {
370 // Use a capturing mapper, since the verifier needs to know what calls
371 // reached Map(). Also, the capturing mapper is initially blocked.
372 scoped_refptr<CapturingHostMapper> mapper = new CapturingHostMapper();
373 ScopedHostMapper scoped_mapper(mapper.get());
374
375 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
376
377 // The class will receive callbacks for when each resolve completes. It
378 // checks that the right things happened.
379 DeDupeRequestsVerifier verifier(mapper.get());
380
381 // Start 5 requests, duplicating hosts "a" and "b". Since the mapper is
382 // blocked, these should all pile up until we signal it.
383
384 ResolveRequest req1(host_resolver, "a", 80, &verifier);
385 ResolveRequest req2(host_resolver, "b", 80, &verifier);
386 ResolveRequest req3(host_resolver, "b", 81, &verifier);
387 ResolveRequest req4(host_resolver, "a", 82, &verifier);
388 ResolveRequest req5(host_resolver, "b", 83, &verifier);
389
390 // Ready, Set, GO!!!
391 mapper->Signal();
392
393 // |verifier| will send quit message once all the requests have finished.
394 MessageLoop::current()->Run();
395 }
396
397 // Helper class used by HostResolverTest.CancelMultipleRequests.
398 class CancelMultipleRequestsVerifier : public ResolveRequest::Delegate {
399 public:
400 CancelMultipleRequestsVerifier() {}
401
402 // The cancels kill all but one request.
403 virtual void OnCompleted(ResolveRequest* resolve) {
404 EXPECT_EQ("a", resolve->hostname());
405 EXPECT_EQ(82, resolve->port());
406
407 // Check that the port was set correctly.
408 EXPECT_EQ(resolve->port(), resolve->addrlist().GetPort());
409
410 // End this test, we are done.
411 MessageLoop::current()->Quit();
412 }
413
414 private:
415 DISALLOW_COPY_AND_ASSIGN(CancelMultipleRequestsVerifier);
416 };
417
418 TEST_F(HostResolverTest, CancelMultipleRequests) {
419 // Use a capturing mapper, since the verifier needs to know what calls
420 // reached Map(). Also, the capturing mapper is initially blocked.
421 scoped_refptr<CapturingHostMapper> mapper = new CapturingHostMapper();
422 ScopedHostMapper scoped_mapper(mapper.get());
423
424 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
425
426 // The class will receive callbacks for when each resolve completes. It
427 // checks that the right things happened.
428 CancelMultipleRequestsVerifier verifier;
429
430 // Start 5 requests, duplicating hosts "a" and "b". Since the mapper is
431 // blocked, these should all pile up until we signal it.
432
433 ResolveRequest req1(host_resolver, "a", 80, &verifier);
434 ResolveRequest req2(host_resolver, "b", 80, &verifier);
435 ResolveRequest req3(host_resolver, "b", 81, &verifier);
436 ResolveRequest req4(host_resolver, "a", 82, &verifier);
437 ResolveRequest req5(host_resolver, "b", 83, &verifier);
438
439 // Cancel everything except request 4.
440 req1.Cancel();
441 req2.Cancel();
442 req3.Cancel();
443 req5.Cancel();
444
445 // Ready, Set, GO!!!
446 mapper->Signal();
447
448 // |verifier| will send quit message once all the requests have finished.
449 MessageLoop::current()->Run();
450 }
451
452 // Helper class used by HostResolverTest.CancelWithinCallback.
453 class CancelWithinCallbackVerifier : public ResolveRequest::Delegate {
454 public:
455 CancelWithinCallbackVerifier()
456 : req_to_cancel1_(NULL), req_to_cancel2_(NULL), num_completions_(0) {
457 }
458
459 virtual void OnCompleted(ResolveRequest* resolve) {
460 num_completions_++;
461
462 // Port 80 is the first request that the callback will be invoked for.
463 // While we are executing within that callback, cancel the other requests
464 // in the job and start another request.
465 if (80 == resolve->port()) {
466 EXPECT_EQ("a", resolve->hostname());
467
468 req_to_cancel1_->Cancel();
469 req_to_cancel2_->Cancel();
470
471 // Start a request (so we can make sure the canceled requests don't
472 // complete before "finalrequest" finishes.
473 final_request_.reset(new ResolveRequest(
474 resolve->resolver(), "finalrequest", 70, this));
475
476 } else if (83 == resolve->port()) {
477 EXPECT_EQ("a", resolve->hostname());
478 } else if (resolve->hostname() == "finalrequest") {
479 EXPECT_EQ(70, resolve->addrlist().GetPort());
480
481 // End this test, we are done.
482 MessageLoop::current()->Quit();
483 } else {
484 FAIL() << "Unexpected completion: " << resolve->hostname() << ", "
485 << resolve->port();
486 }
487 }
488
489 void SetRequestsToCancel(ResolveRequest* req_to_cancel1,
490 ResolveRequest* req_to_cancel2) {
491 req_to_cancel1_ = req_to_cancel1;
492 req_to_cancel2_ = req_to_cancel2;
493 }
494
495 private:
496 scoped_ptr<ResolveRequest> final_request_;
497 ResolveRequest* req_to_cancel1_;
498 ResolveRequest* req_to_cancel2_;
499 int num_completions_;
500 DISALLOW_COPY_AND_ASSIGN(CancelWithinCallbackVerifier);
501 };
502
503 TEST_F(HostResolverTest, CancelWithinCallback) {
504 // Use a capturing mapper, since the verifier needs to know what calls
505 // reached Map(). Also, the capturing mapper is initially blocked.
506 scoped_refptr<CapturingHostMapper> mapper = new CapturingHostMapper();
507 ScopedHostMapper scoped_mapper(mapper.get());
508
509 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
510
511 // The class will receive callbacks for when each resolve completes. It
512 // checks that the right things happened.
513 CancelWithinCallbackVerifier verifier;
514
515 // Start 4 requests, duplicating hosts "a". Since the mapper is
516 // blocked, these should all pile up until we signal it.
517
518 ResolveRequest req1(host_resolver, "a", 80, &verifier);
519 ResolveRequest req2(host_resolver, "a", 81, &verifier);
520 ResolveRequest req3(host_resolver, "a", 82, &verifier);
521 ResolveRequest req4(host_resolver, "a", 83, &verifier);
522
523 // Once "a:80" completes, it will cancel "a:81" and "a:82".
524 verifier.SetRequestsToCancel(&req2, &req3);
525
526 // Ready, Set, GO!!!
527 mapper->Signal();
528
529 // |verifier| will send quit message once all the requests have finished.
530 MessageLoop::current()->Run();
531 }
532
533 // Helper class used by HostResolverTest.DeleteWithinCallback.
534 class DeleteWithinCallbackVerifier : public ResolveRequest::Delegate {
535 public:
536 // |host_resolver| is the resolver that the the resolve requests were started
537 // with.
538 DeleteWithinCallbackVerifier(net::HostResolver* host_resolver)
539 : host_resolver_(host_resolver) {}
540
541 virtual void OnCompleted(ResolveRequest* resolve) {
542 EXPECT_EQ("a", resolve->hostname());
543 EXPECT_EQ(80, resolve->port());
544
545 // Release the last reference to the host resolver that started the
546 // requests.
547 host_resolver_ = NULL;
548
549 // Quit after returning from OnCompleted (to give it a chance at
550 // incorrectly running the cancelled tasks).
551 MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
552 }
553
554 private:
555 scoped_refptr<net::HostResolver> host_resolver_;
556 DISALLOW_COPY_AND_ASSIGN(DeleteWithinCallbackVerifier);
557 };
558
559 TEST_F(HostResolverTest, DeleteWithinCallback) {
560 // Use a capturing mapper, since the verifier needs to know what calls
561 // reached Map(). Also, the capturing mapper is initially blocked.
562 scoped_refptr<CapturingHostMapper> mapper = new CapturingHostMapper();
563 ScopedHostMapper scoped_mapper(mapper.get());
564
565 // The class will receive callbacks for when each resolve completes. It
566 // checks that the right things happened. Note that the verifier holds the
567 // only reference to |host_resolver|, so it can delete it within callback.
568 net::HostResolver* host_resolver = new net::HostResolver;
569 DeleteWithinCallbackVerifier verifier(host_resolver);
570
571 // Start 4 requests, duplicating hosts "a". Since the mapper is
572 // blocked, these should all pile up until we signal it.
573
574 ResolveRequest req1(host_resolver, "a", 80, &verifier);
575 ResolveRequest req2(host_resolver, "a", 81, &verifier);
576 ResolveRequest req3(host_resolver, "a", 82, &verifier);
577 ResolveRequest req4(host_resolver, "a", 83, &verifier);
578
579 // Ready, Set, GO!!!
580 mapper->Signal();
581
582 // |verifier| will send quit message once all the requests have finished.
583 MessageLoop::current()->Run();
584 }
585
586 // Helper class used by HostResolverTest.StartWithinCallback.
587 class StartWithinCallbackVerifier : public ResolveRequest::Delegate {
588 public:
589 StartWithinCallbackVerifier() : num_requests_(0) {}
590
591 virtual void OnCompleted(ResolveRequest* resolve) {
592 EXPECT_EQ("a", resolve->hostname());
593
594 if (80 == resolve->port()) {
595 // On completing the first request, start another request for "a".
596 // Since caching is disabled, this will result in another async request.
597 final_request_.reset(new ResolveRequest(
598 resolve->resolver(), "a", 70, this));
599 }
600 if (++num_requests_ == 5) {
601 // Test is done.
602 MessageLoop::current()->Quit();
603 }
604 }
605
606 private:
607 int num_requests_;
608 scoped_ptr<ResolveRequest> final_request_;
609 DISALLOW_COPY_AND_ASSIGN(StartWithinCallbackVerifier);
610 };
611
612 TEST_F(HostResolverTest, StartWithinCallback) {
613 // Use a capturing mapper, since the verifier needs to know what calls
614 // reached Map(). Also, the capturing mapper is initially blocked.
615 scoped_refptr<CapturingHostMapper> mapper = new CapturingHostMapper();
616 ScopedHostMapper scoped_mapper(mapper.get());
617
618 // Turn off caching for this host resolver.
619 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver(0, 0));
620
621 // The class will receive callbacks for when each resolve completes. It
622 // checks that the right things happened.
623 StartWithinCallbackVerifier verifier;
624
625 // Start 4 requests, duplicating hosts "a". Since the mapper is
626 // blocked, these should all pile up until we signal it.
627
628 ResolveRequest req1(host_resolver, "a", 80, &verifier);
629 ResolveRequest req2(host_resolver, "a", 81, &verifier);
630 ResolveRequest req3(host_resolver, "a", 82, &verifier);
631 ResolveRequest req4(host_resolver, "a", 83, &verifier);
632
633 // Ready, Set, GO!!!
634 mapper->Signal();
635
636 // |verifier| will send quit message once all the requests have finished.
637 MessageLoop::current()->Run();
638 }
639
640 // Helper class used by HostResolverTest.BypassCache.
641 class BypassCacheVerifier : public ResolveRequest::Delegate {
642 public:
643 BypassCacheVerifier() {}
644
645 virtual void OnCompleted(ResolveRequest* resolve) {
646 EXPECT_EQ("a", resolve->hostname());
647 net::HostResolver* resolver = resolve->resolver();
648
649 if (80 == resolve->port()) {
650 // On completing the first request, start another request for "a".
651 // Since caching is enabled, this should complete synchronously.
652
653 // Note that |junk_callback| shouldn't be used since we are going to
654 // complete synchronously. We can't specify NULL though since that would
655 // mean synchronous mode so we give it a value of 1.
656 net::CompletionCallback* junk_callback =
657 reinterpret_cast<net::CompletionCallback*> (1);
658 net::AddressList addrlist;
659
660 net::HostResolver::RequestInfo info("a", 70);
661 int error = resolver->Resolve(info, &addrlist, junk_callback, NULL);
662 EXPECT_EQ(net::OK, error);
663
664 // Ok good. Now make sure that if we ask to bypass the cache, it can no
665 // longer service the request synchronously.
666 info = net::HostResolver::RequestInfo("a", 71);
667 info.set_allow_cached_response(false);
668 final_request_.reset(new ResolveRequest(resolver, info, this));
669 } else if (71 == resolve->port()) {
670 // Test is done.
671 MessageLoop::current()->Quit();
672 } else {
673 FAIL() << "Unexpected port number";
674 }
675 }
676
677 private:
678 scoped_ptr<ResolveRequest> final_request_;
679 DISALLOW_COPY_AND_ASSIGN(BypassCacheVerifier);
680 };
681
682 TEST_F(HostResolverTest, BypassCache) {
683 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
684
685 // The class will receive callbacks for when each resolve completes. It
686 // checks that the right things happened.
687 BypassCacheVerifier verifier;
688
689 // Start a request.
690 ResolveRequest req1(host_resolver, "a", 80, &verifier);
691
692 // |verifier| will send quit message once all the requests have finished.
693 MessageLoop::current()->Run();
694 }
695
696 bool operator==(const net::HostResolver::RequestInfo& a,
697 const net::HostResolver::RequestInfo& b) {
698 return a.hostname() == b.hostname() &&
699 a.port() == b.port() &&
700 a.allow_cached_response() == b.allow_cached_response() &&
701 a.is_speculative() == b.is_speculative() &&
702 a.referrer() == b.referrer();
703 }
704
705 // Observer that just makes note of how it was called. The test code can then
706 // inspect to make sure it was called with the right parameters.
707 class CapturingObserver : public net::HostResolver::Observer {
708 public:
709 // DnsResolutionObserver methods:
710 virtual void OnStartResolution(int id,
711 const net::HostResolver::RequestInfo& info) {
712 start_log.push_back(StartOrCancelEntry(id, info));
713 }
714
715 virtual void OnFinishResolutionWithStatus(
716 int id,
717 bool was_resolved,
718 const net::HostResolver::RequestInfo& info) {
719 finish_log.push_back(FinishEntry(id, was_resolved, info));
720 }
721
722 virtual void OnCancelResolution(int id,
723 const net::HostResolver::RequestInfo& info) {
724 cancel_log.push_back(StartOrCancelEntry(id, info));
725 }
726
727 // Tuple (id, info).
728 struct StartOrCancelEntry {
729 StartOrCancelEntry(int id, const net::HostResolver::RequestInfo& info)
730 : id(id), info(info) {}
731
732 bool operator==(const StartOrCancelEntry& other) const {
733 return id == other.id && info == other.info;
734 }
735
736 int id;
737 net::HostResolver::RequestInfo info;
738 };
739
740 // Tuple (id, was_resolved, info).
741 struct FinishEntry {
742 FinishEntry(int id, bool was_resolved,
743 const net::HostResolver::RequestInfo& info)
744 : id(id), was_resolved(was_resolved), info(info) {}
745
746 bool operator==(const FinishEntry& other) const {
747 return id == other.id &&
748 was_resolved == other.was_resolved &&
749 info == other.info;
750 }
751
752 int id;
753 bool was_resolved;
754 net::HostResolver::RequestInfo info;
755 };
756
757 std::vector<StartOrCancelEntry> start_log;
758 std::vector<FinishEntry> finish_log;
759 std::vector<StartOrCancelEntry> cancel_log;
760 };
761
762 // Test that registering, unregistering, and notifying of observers works.
763 // Does not test the cancellation notification since all resolves are
764 // synchronous.
765 TEST_F(HostResolverTest, Observers) {
766 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
767
768 CapturingObserver observer;
769
770 host_resolver->AddObserver(&observer);
771
772 net::AddressList addrlist;
773
774 // Resolve "host1".
775 net::HostResolver::RequestInfo info1("host1", 70);
776 int rv = host_resolver->Resolve(info1, &addrlist, NULL, NULL);
777 EXPECT_EQ(net::OK, rv);
778
779 EXPECT_EQ(1U, observer.start_log.size());
780 EXPECT_EQ(1U, observer.finish_log.size());
781 EXPECT_EQ(0U, observer.cancel_log.size());
782 EXPECT_TRUE(observer.start_log[0] ==
783 CapturingObserver::StartOrCancelEntry(0, info1));
784 EXPECT_TRUE(observer.finish_log[0] ==
785 CapturingObserver::FinishEntry(0, true, info1));
786
787 // Resolve "host1" again -- this time it will be served from cache, but it
788 // should still notify of completion.
789 TestCompletionCallback callback;
790 rv = host_resolver->Resolve(info1, &addrlist, &callback, NULL);
791 ASSERT_EQ(net::OK, rv); // Should complete synchronously.
792
793 EXPECT_EQ(2U, observer.start_log.size());
794 EXPECT_EQ(2U, observer.finish_log.size());
795 EXPECT_EQ(0U, observer.cancel_log.size());
796 EXPECT_TRUE(observer.start_log[1] ==
797 CapturingObserver::StartOrCancelEntry(1, info1));
798 EXPECT_TRUE(observer.finish_log[1] ==
799 CapturingObserver::FinishEntry(1, true, info1));
800
801 // Resolve "host2", setting referrer to "http://foobar.com"
802 net::HostResolver::RequestInfo info2("host2", 70);
803 info2.set_referrer(GURL("http://foobar.com"));
804 rv = host_resolver->Resolve(info2, &addrlist, NULL, NULL);
805 EXPECT_EQ(net::OK, rv);
806
807 EXPECT_EQ(3U, observer.start_log.size());
808 EXPECT_EQ(3U, observer.finish_log.size());
809 EXPECT_EQ(0U, observer.cancel_log.size());
810 EXPECT_TRUE(observer.start_log[2] ==
811 CapturingObserver::StartOrCancelEntry(2, info2));
812 EXPECT_TRUE(observer.finish_log[2] ==
813 CapturingObserver::FinishEntry(2, true, info2));
814
815 // Unregister the observer.
816 host_resolver->RemoveObserver(&observer);
817
818 // Resolve "host3"
819 net::HostResolver::RequestInfo info3("host3", 70);
820 host_resolver->Resolve(info3, &addrlist, NULL, NULL);
821
822 // No effect this time, since observer was removed.
823 EXPECT_EQ(3U, observer.start_log.size());
824 EXPECT_EQ(3U, observer.finish_log.size());
825 EXPECT_EQ(0U, observer.cancel_log.size());
826 }
827
828 // Tests that observers are sent OnCancelResolution() whenever a request is
829 // cancelled. There are two ways to cancel a request:
830 // (1) Delete the HostResolver while job is outstanding.
831 // (2) Call HostResolver::CancelRequest() while a request is outstanding.
832 TEST_F(HostResolverTest, CancellationObserver) {
833 CapturingObserver observer;
834 {
835 // Create a host resolver and attach an observer.
836 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
837 host_resolver->AddObserver(&observer);
838
839 TestCompletionCallback callback;
840
841 EXPECT_EQ(0U, observer.start_log.size());
842 EXPECT_EQ(0U, observer.finish_log.size());
843 EXPECT_EQ(0U, observer.cancel_log.size());
844
845 // Start an async resolve for (host1:70).
846 net::HostResolver::RequestInfo info1("host1", 70);
847 net::HostResolver::Request* req = NULL;
848 net::AddressList addrlist;
849 int rv = host_resolver->Resolve(info1, &addrlist, &callback, &req);
850 EXPECT_EQ(net::ERR_IO_PENDING, rv);
851 EXPECT_TRUE(NULL != req);
852
853 EXPECT_EQ(1U, observer.start_log.size());
854 EXPECT_EQ(0U, observer.finish_log.size());
855 EXPECT_EQ(0U, observer.cancel_log.size());
856
857 EXPECT_TRUE(observer.start_log[0] ==
858 CapturingObserver::StartOrCancelEntry(0, info1));
859
860 // Cancel the request (host mapper is blocked so it cant be finished yet).
861 host_resolver->CancelRequest(req);
862
863 EXPECT_EQ(1U, observer.start_log.size());
864 EXPECT_EQ(0U, observer.finish_log.size());
865 EXPECT_EQ(1U, observer.cancel_log.size());
866
867 EXPECT_TRUE(observer.cancel_log[0] ==
868 CapturingObserver::StartOrCancelEntry(0, info1));
869
870 // Start an async request for (host2:60)
871 net::HostResolver::RequestInfo info2("host2", 60);
872 rv = host_resolver->Resolve(info2, &addrlist, &callback, NULL);
873 EXPECT_EQ(net::ERR_IO_PENDING, rv);
874 EXPECT_TRUE(NULL != req);
875
876 EXPECT_EQ(2U, observer.start_log.size());
877 EXPECT_EQ(0U, observer.finish_log.size());
878 EXPECT_EQ(1U, observer.cancel_log.size());
879
880 EXPECT_TRUE(observer.start_log[1] ==
881 CapturingObserver::StartOrCancelEntry(1, info2));
882
883 // Upon exiting this scope, HostResolver is destroyed, so all requests are
884 // implicitly cancelled.
885 }
886
887 // Check that destroying the HostResolver sent a notification for
888 // cancellation of host2:60 request.
889
890 EXPECT_EQ(2U, observer.start_log.size());
891 EXPECT_EQ(0U, observer.finish_log.size());
892 EXPECT_EQ(2U, observer.cancel_log.size());
893
894 net::HostResolver::RequestInfo info("host2", 60);
895 EXPECT_TRUE(observer.cancel_log[1] ==
896 CapturingObserver::StartOrCancelEntry(1, info));
897 }
898
899 } // namespace
OLDNEW
« no previous file with comments | « net/base/host_resolver_proc.cc ('k') | net/base/mock_host_resolver.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698