| Index: net/base/host_resolver_unittest.cc
|
| ===================================================================
|
| --- net/base/host_resolver_unittest.cc (revision 18213)
|
| +++ net/base/host_resolver_unittest.cc (working copy)
|
| @@ -26,8 +26,118 @@
|
| using net::ScopedHostMapper;
|
| using net::WaitingHostMapper;
|
|
|
| +// TODO(eroman):
|
| +// - Test mixing async with sync (in particular how does sync update the
|
| +// cache while an async is already pending).
|
| +
|
| namespace {
|
|
|
| +// A variant of WaitingHostMapper that pushes each host mapped into a list.
|
| +// (and uses a manual-reset event rather than auto-reset).
|
| +class CapturingHostMapper : public net::HostMapper {
|
| + public:
|
| + CapturingHostMapper() : event_(true, false) {
|
| + }
|
| +
|
| + void Signal() {
|
| + event_.Signal();
|
| + }
|
| +
|
| + virtual std::string Map(const std::string& host) {
|
| + event_.Wait();
|
| + {
|
| + AutoLock l(lock_);
|
| + capture_list_.push_back(host);
|
| + }
|
| + return MapUsingPrevious(host);
|
| + }
|
| +
|
| + std::vector<std::string> GetCaptureList() const {
|
| + std::vector<std::string> copy;
|
| + {
|
| + AutoLock l(lock_);
|
| + copy = capture_list_;
|
| + }
|
| + return copy;
|
| + }
|
| +
|
| + private:
|
| + std::vector<std::string> capture_list_;
|
| + mutable Lock lock_;
|
| + base::WaitableEvent event_;
|
| +};
|
| +
|
| +// Helper that represents a single Resolve() result, used to inspect all the
|
| +// resolve results by forwarding them to Delegate.
|
| +class ResolveRequest {
|
| + public:
|
| + // Delegate interface, for notification when the ResolveRequest completes.
|
| + class Delegate {
|
| + public:
|
| + virtual ~Delegate() {}
|
| + virtual void OnCompleted(ResolveRequest* resolve) = 0;
|
| + };
|
| +
|
| + ResolveRequest(net::HostResolver* resolver,
|
| + const std::string& hostname,
|
| + int port,
|
| + Delegate* delegate)
|
| + : hostname_(hostname), port_(port), resolver_(resolver),
|
| + delegate_(delegate),
|
| + ALLOW_THIS_IN_INITIALIZER_LIST(
|
| + callback_(this, &ResolveRequest::OnLookupFinished)) {
|
| + // Start the request.
|
| + int err = resolver->Resolve(hostname, port, &addrlist_, &callback_, &req_);
|
| + EXPECT_EQ(net::ERR_IO_PENDING, err);
|
| + }
|
| +
|
| + void Cancel() {
|
| + resolver_->CancelRequest(req_);
|
| + }
|
| +
|
| + const std::string& hostname() const {
|
| + return hostname_;
|
| + }
|
| +
|
| + int port() const {
|
| + return port_;
|
| + }
|
| +
|
| + int result() const {
|
| + return result_;
|
| + }
|
| +
|
| + const net::AddressList& addrlist() const {
|
| + return addrlist_;
|
| + }
|
| +
|
| + net::HostResolver* resolver() const {
|
| + return resolver_;
|
| + }
|
| +
|
| + private:
|
| + void OnLookupFinished(int result) {
|
| + result_ = result;
|
| + delegate_->OnCompleted(this);
|
| + }
|
| +
|
| + // The request details.
|
| + std::string hostname_;
|
| + int port_;
|
| + net::HostResolver::Request* req_;
|
| +
|
| + // The result of the resolve.
|
| + int result_;
|
| + net::AddressList addrlist_;
|
| +
|
| + net::HostResolver* resolver_;
|
| +
|
| + Delegate* delegate_;
|
| + net::CompletionCallbackImpl<ResolveRequest> callback_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ResolveRequest);
|
| +};
|
| +
|
| class HostResolverTest : public testing::Test {
|
| public:
|
| HostResolverTest()
|
| @@ -58,7 +168,8 @@
|
| mapper->AddRule("just.testing", "192.168.1.42");
|
| ScopedHostMapper scoped_mapper(mapper.get());
|
|
|
| - int err = host_resolver.Resolve("just.testing", kPortnum, &adrlist, NULL);
|
| + int err = host_resolver.Resolve("just.testing", kPortnum, &adrlist, NULL,
|
| + NULL);
|
| EXPECT_EQ(net::OK, err);
|
|
|
| const struct addrinfo* ainfo = adrlist.head();
|
| @@ -81,7 +192,7 @@
|
| ScopedHostMapper scoped_mapper(mapper.get());
|
|
|
| int err = host_resolver.Resolve("just.testing", kPortnum, &adrlist,
|
| - &callback_);
|
| + &callback_, NULL);
|
| EXPECT_EQ(net::ERR_IO_PENDING, err);
|
|
|
| MessageLoop::current()->Run();
|
| @@ -109,7 +220,7 @@
|
| const int kPortnum = 80;
|
|
|
| int err = host_resolver.Resolve("just.testing", kPortnum, &adrlist,
|
| - &callback_);
|
| + &callback_, NULL);
|
| EXPECT_EQ(net::ERR_IO_PENDING, err);
|
|
|
| // Make sure we will exit the queue even when callback is not called.
|
| @@ -134,7 +245,7 @@
|
| net::HostResolver host_resolver;
|
| net::AddressList adrlist;
|
| const int kPortnum = 5555;
|
| - int err = host_resolver.Resolve("127.1.2.3", kPortnum, &adrlist, NULL);
|
| + int err = host_resolver.Resolve("127.1.2.3", kPortnum, &adrlist, NULL, NULL);
|
| EXPECT_EQ(net::OK, err);
|
|
|
| const struct addrinfo* ainfo = adrlist.head();
|
| @@ -157,7 +268,8 @@
|
| net::HostResolver host_resolver;
|
| net::AddressList adrlist;
|
| const int kPortnum = 5555;
|
| - int err = host_resolver.Resolve("2001:db8::1", kPortnum, &adrlist, NULL);
|
| + int err = host_resolver.Resolve("2001:db8::1", kPortnum, &adrlist, NULL,
|
| + NULL);
|
| // On computers without IPv6 support, getaddrinfo cannot convert IPv6
|
| // address literals to addresses (getaddrinfo returns EAI_NONAME). So this
|
| // test has to allow host_resolver.Resolve to fail.
|
| @@ -190,8 +302,320 @@
|
| net::HostResolver host_resolver;
|
| net::AddressList adrlist;
|
| const int kPortnum = 5555;
|
| - int err = host_resolver.Resolve("", kPortnum, &adrlist, NULL);
|
| + int err = host_resolver.Resolve("", kPortnum, &adrlist, NULL, NULL);
|
| EXPECT_EQ(net::ERR_NAME_NOT_RESOLVED, err);
|
| }
|
|
|
| +// Helper class used by HostResolverTest.DeDupeRequests. It receives request
|
| +// completion notifications for all the resolves, so it can tally up and
|
| +// determine when we are done.
|
| +class DeDupeRequestsVerifier : public ResolveRequest::Delegate {
|
| + public:
|
| + explicit DeDupeRequestsVerifier(CapturingHostMapper* mapper)
|
| + : count_a_(0), count_b_(0), mapper_(mapper) {}
|
| +
|
| + // The test does 5 resolves (which can complete in any order).
|
| + virtual void OnCompleted(ResolveRequest* resolve) {
|
| + // Tally up how many requests we have seen.
|
| + if (resolve->hostname() == "a") {
|
| + count_a_++;
|
| + } else if (resolve->hostname() == "b") {
|
| + count_b_++;
|
| + } else {
|
| + FAIL() << "Unexpected hostname: " << resolve->hostname();
|
| + }
|
| +
|
| + // Check that the port was set correctly.
|
| + EXPECT_EQ(resolve->port(), resolve->addrlist().GetPort());
|
| +
|
| + // Check whether all the requests have finished yet.
|
| + int total_completions = count_a_ + count_b_;
|
| + if (total_completions == 5) {
|
| + EXPECT_EQ(2, count_a_);
|
| + EXPECT_EQ(3, count_b_);
|
| +
|
| + // The mapper should have been called only twice -- once with "a", once
|
| + // with "b".
|
| + std::vector<std::string> capture_list = mapper_->GetCaptureList();
|
| + EXPECT_EQ(2U, capture_list.size());
|
| +
|
| + // End this test, we are done.
|
| + MessageLoop::current()->Quit();
|
| + }
|
| + }
|
| +
|
| + private:
|
| + int count_a_;
|
| + int count_b_;
|
| + CapturingHostMapper* mapper_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(DeDupeRequestsVerifier);
|
| +};
|
| +
|
| +TEST_F(HostResolverTest, DeDupeRequests) {
|
| + // Use a capturing mapper, since the verifier needs to know what calls
|
| + // reached Map(). Also, the capturing mapper is initially blocked.
|
| + scoped_refptr<CapturingHostMapper> mapper = new CapturingHostMapper();
|
| + ScopedHostMapper scoped_mapper(mapper.get());
|
| +
|
| + net::HostResolver host_resolver;
|
| +
|
| + // The class will receive callbacks for when each resolve completes. It
|
| + // checks that the right things happened.
|
| + DeDupeRequestsVerifier verifier(mapper.get());
|
| +
|
| + // Start 5 requests, duplicating hosts "a" and "b". Since the mapper is
|
| + // blocked, these should all pile up until we signal it.
|
| +
|
| + ResolveRequest req1(&host_resolver, "a", 80, &verifier);
|
| + ResolveRequest req2(&host_resolver, "b", 80, &verifier);
|
| + ResolveRequest req3(&host_resolver, "b", 81, &verifier);
|
| + ResolveRequest req4(&host_resolver, "a", 82, &verifier);
|
| + ResolveRequest req5(&host_resolver, "b", 83, &verifier);
|
| +
|
| + // Ready, Set, GO!!!
|
| + mapper->Signal();
|
| +
|
| + // |verifier| will send quit message once all the requests have finished.
|
| + MessageLoop::current()->Run();
|
| +}
|
| +
|
| +// Helper class used by HostResolverTest.CancelMultipleRequests.
|
| +class CancelMultipleRequestsVerifier : public ResolveRequest::Delegate {
|
| + public:
|
| + CancelMultipleRequestsVerifier() {}
|
| +
|
| + // The cancels kill all but one request.
|
| + virtual void OnCompleted(ResolveRequest* resolve) {
|
| + EXPECT_EQ("a", resolve->hostname());
|
| + EXPECT_EQ(82, resolve->port());
|
| +
|
| + // Check that the port was set correctly.
|
| + EXPECT_EQ(resolve->port(), resolve->addrlist().GetPort());
|
| +
|
| + // End this test, we are done.
|
| + MessageLoop::current()->Quit();
|
| + }
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(CancelMultipleRequestsVerifier);
|
| +};
|
| +
|
| +TEST_F(HostResolverTest, CancelMultipleRequests) {
|
| + // Use a capturing mapper, since the verifier needs to know what calls
|
| + // reached Map(). Also, the capturing mapper is initially blocked.
|
| + scoped_refptr<CapturingHostMapper> mapper = new CapturingHostMapper();
|
| + ScopedHostMapper scoped_mapper(mapper.get());
|
| +
|
| + net::HostResolver host_resolver;
|
| +
|
| + // The class will receive callbacks for when each resolve completes. It
|
| + // checks that the right things happened.
|
| + CancelMultipleRequestsVerifier verifier;
|
| +
|
| + // Start 5 requests, duplicating hosts "a" and "b". Since the mapper is
|
| + // blocked, these should all pile up until we signal it.
|
| +
|
| + ResolveRequest req1(&host_resolver, "a", 80, &verifier);
|
| + ResolveRequest req2(&host_resolver, "b", 80, &verifier);
|
| + ResolveRequest req3(&host_resolver, "b", 81, &verifier);
|
| + ResolveRequest req4(&host_resolver, "a", 82, &verifier);
|
| + ResolveRequest req5(&host_resolver, "b", 83, &verifier);
|
| +
|
| + // Cancel everything except request 4.
|
| + req1.Cancel();
|
| + req2.Cancel();
|
| + req3.Cancel();
|
| + req5.Cancel();
|
| +
|
| + // Ready, Set, GO!!!
|
| + mapper->Signal();
|
| +
|
| + // |verifier| will send quit message once all the requests have finished.
|
| + MessageLoop::current()->Run();
|
| +}
|
| +
|
| +// Helper class used by HostResolverTest.CancelWithinCallback.
|
| +class CancelWithinCallbackVerifier : public ResolveRequest::Delegate {
|
| + public:
|
| + CancelWithinCallbackVerifier()
|
| + : req_to_cancel1_(NULL), req_to_cancel2_(NULL), num_completions_(0) {
|
| + }
|
| +
|
| + virtual void OnCompleted(ResolveRequest* resolve) {
|
| + num_completions_++;
|
| +
|
| + // Port 80 is the first request that the callback will be invoked for.
|
| + // While we are executing within that callback, cancel the other requests
|
| + // in the job and start another request.
|
| + if (80 == resolve->port()) {
|
| + EXPECT_EQ("a", resolve->hostname());
|
| +
|
| + req_to_cancel1_->Cancel();
|
| + req_to_cancel2_->Cancel();
|
| +
|
| + // Start a request (so we can make sure the canceled requests don't
|
| + // complete before "finalrequest" finishes.
|
| + final_request_.reset(new ResolveRequest(
|
| + resolve->resolver(), "finalrequest", 70, this));
|
| +
|
| + } else if (83 == resolve->port()) {
|
| + EXPECT_EQ("a", resolve->hostname());
|
| + } else if (resolve->hostname() == "finalrequest") {
|
| + EXPECT_EQ(70, resolve->addrlist().GetPort());
|
| +
|
| + // End this test, we are done.
|
| + MessageLoop::current()->Quit();
|
| + } else {
|
| + FAIL() << "Unexpected completion: " << resolve->hostname() << ", "
|
| + << resolve->port();
|
| + }
|
| + }
|
| +
|
| + void SetRequestsToCancel(ResolveRequest* req_to_cancel1,
|
| + ResolveRequest* req_to_cancel2) {
|
| + req_to_cancel1_ = req_to_cancel1;
|
| + req_to_cancel2_ = req_to_cancel2;
|
| + }
|
| +
|
| + private:
|
| + scoped_ptr<ResolveRequest> final_request_;
|
| + ResolveRequest* req_to_cancel1_;
|
| + ResolveRequest* req_to_cancel2_;
|
| + int num_completions_;
|
| + DISALLOW_COPY_AND_ASSIGN(CancelWithinCallbackVerifier);
|
| +};
|
| +
|
| +TEST_F(HostResolverTest, CancelWithinCallback) {
|
| + // Use a capturing mapper, since the verifier needs to know what calls
|
| + // reached Map(). Also, the capturing mapper is initially blocked.
|
| + scoped_refptr<CapturingHostMapper> mapper = new CapturingHostMapper();
|
| + ScopedHostMapper scoped_mapper(mapper.get());
|
| +
|
| + net::HostResolver host_resolver;
|
| +
|
| + // The class will receive callbacks for when each resolve completes. It
|
| + // checks that the right things happened.
|
| + CancelWithinCallbackVerifier verifier;
|
| +
|
| + // Start 4 requests, duplicating hosts "a". Since the mapper is
|
| + // blocked, these should all pile up until we signal it.
|
| +
|
| + ResolveRequest req1(&host_resolver, "a", 80, &verifier);
|
| + ResolveRequest req2(&host_resolver, "a", 81, &verifier);
|
| + ResolveRequest req3(&host_resolver, "a", 82, &verifier);
|
| + ResolveRequest req4(&host_resolver, "a", 83, &verifier);
|
| +
|
| + // Once "a:80" completes, it will cancel "a:81" and "a:82".
|
| + verifier.SetRequestsToCancel(&req2, &req3);
|
| +
|
| + // Ready, Set, GO!!!
|
| + mapper->Signal();
|
| +
|
| + // |verifier| will send quit message once all the requests have finished.
|
| + MessageLoop::current()->Run();
|
| +}
|
| +
|
| +// Helper class used by HostResolverTest.DeleteWithinCallback.
|
| +class DeleteWithinCallbackVerifier : public ResolveRequest::Delegate {
|
| + public:
|
| + DeleteWithinCallbackVerifier() {}
|
| +
|
| + virtual void OnCompleted(ResolveRequest* resolve) {
|
| + EXPECT_EQ("a", resolve->hostname());
|
| + EXPECT_EQ(80, resolve->port());
|
| + delete resolve->resolver();
|
| +
|
| + // Quit after returning from OnCompleted (to give it a chance at
|
| + // incorrectly running the cancelled tasks).
|
| + MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
|
| + }
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(DeleteWithinCallbackVerifier);
|
| +};
|
| +
|
| +TEST_F(HostResolverTest, DeleteWithinCallback) {
|
| + // Use a capturing mapper, since the verifier needs to know what calls
|
| + // reached Map(). Also, the capturing mapper is initially blocked.
|
| + scoped_refptr<CapturingHostMapper> mapper = new CapturingHostMapper();
|
| + ScopedHostMapper scoped_mapper(mapper.get());
|
| +
|
| + // This should be deleted by DeleteWithinCallbackVerifier -- if it leaks
|
| + // then the test has failed.
|
| + net::HostResolver* host_resolver = new net::HostResolver;
|
| +
|
| + // The class will receive callbacks for when each resolve completes. It
|
| + // checks that the right things happened.
|
| + DeleteWithinCallbackVerifier verifier;
|
| +
|
| + // Start 4 requests, duplicating hosts "a". Since the mapper is
|
| + // blocked, these should all pile up until we signal it.
|
| +
|
| + ResolveRequest req1(host_resolver, "a", 80, &verifier);
|
| + ResolveRequest req2(host_resolver, "a", 81, &verifier);
|
| + ResolveRequest req3(host_resolver, "a", 82, &verifier);
|
| + ResolveRequest req4(host_resolver, "a", 83, &verifier);
|
| +
|
| + // Ready, Set, GO!!!
|
| + mapper->Signal();
|
| +
|
| + // |verifier| will send quit message once all the requests have finished.
|
| + MessageLoop::current()->Run();
|
| +}
|
| +
|
| +// Helper class used by HostResolverTest.StartWithinCallback.
|
| +class StartWithinCallbackVerifier : public ResolveRequest::Delegate {
|
| + public:
|
| + StartWithinCallbackVerifier() : num_requests_(0) {}
|
| +
|
| + virtual void OnCompleted(ResolveRequest* resolve) {
|
| + EXPECT_EQ("a", resolve->hostname());
|
| +
|
| + if (80 == resolve->port()) {
|
| + // On completing the first request, start another request for "a".
|
| + // Since caching is disabled, this will result in another async request.
|
| + final_request_.reset(new ResolveRequest(
|
| + resolve->resolver(), "a", 70, this));
|
| + }
|
| + if (++num_requests_ == 5) {
|
| + // Test is done.
|
| + MessageLoop::current()->Quit();
|
| + }
|
| + }
|
| +
|
| + private:
|
| + int num_requests_;
|
| + scoped_ptr<ResolveRequest> final_request_;
|
| + DISALLOW_COPY_AND_ASSIGN(StartWithinCallbackVerifier);
|
| +};
|
| +
|
| +TEST_F(HostResolverTest, StartWithinCallback) {
|
| + // Use a capturing mapper, since the verifier needs to know what calls
|
| + // reached Map(). Also, the capturing mapper is initially blocked.
|
| + scoped_refptr<CapturingHostMapper> mapper = new CapturingHostMapper();
|
| + ScopedHostMapper scoped_mapper(mapper.get());
|
| +
|
| + // Turn off caching for this host resolver.
|
| + net::HostResolver host_resolver(0, 0);
|
| +
|
| + // The class will receive callbacks for when each resolve completes. It
|
| + // checks that the right things happened.
|
| + StartWithinCallbackVerifier verifier;
|
| +
|
| + // Start 4 requests, duplicating hosts "a". Since the mapper is
|
| + // blocked, these should all pile up until we signal it.
|
| +
|
| + ResolveRequest req1(&host_resolver, "a", 80, &verifier);
|
| + ResolveRequest req2(&host_resolver, "a", 81, &verifier);
|
| + ResolveRequest req3(&host_resolver, "a", 82, &verifier);
|
| + ResolveRequest req4(&host_resolver, "a", 83, &verifier);
|
| +
|
| + // Ready, Set, GO!!!
|
| + mapper->Signal();
|
| +
|
| + // |verifier| will send quit message once all the requests have finished.
|
| + MessageLoop::current()->Run();
|
| +}
|
| +
|
| } // namespace
|
|
|