summaryrefslogtreecommitdiff
path: root/chromium/net/dns/host_resolver_impl_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/dns/host_resolver_impl_unittest.cc')
-rw-r--r--chromium/net/dns/host_resolver_impl_unittest.cc543
1 files changed, 479 insertions, 64 deletions
diff --git a/chromium/net/dns/host_resolver_impl_unittest.cc b/chromium/net/dns/host_resolver_impl_unittest.cc
index f6b7f690675..c314f80c24d 100644
--- a/chromium/net/dns/host_resolver_impl_unittest.cc
+++ b/chromium/net/dns/host_resolver_impl_unittest.cc
@@ -12,6 +12,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_vector.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/condition_variable.h"
@@ -197,10 +198,12 @@ class Request {
};
Request(const HostResolver::RequestInfo& info,
+ RequestPriority priority,
size_t index,
HostResolver* resolver,
Handler* handler)
: info_(info),
+ priority_(priority),
index_(index),
resolver_(resolver),
handler_(handler),
@@ -213,8 +216,12 @@ class Request {
DCHECK(!handle_);
list_ = AddressList();
result_ = resolver_->Resolve(
- info_, &list_, base::Bind(&Request::OnComplete, base::Unretained(this)),
- &handle_, BoundNetLog());
+ info_,
+ priority_,
+ &list_,
+ base::Bind(&Request::OnComplete, base::Unretained(this)),
+ &handle_,
+ BoundNetLog());
if (!list_.empty())
EXPECT_EQ(OK, result_);
return result_;
@@ -291,6 +298,7 @@ class Request {
}
HostResolver::RequestInfo info_;
+ RequestPriority priority_;
size_t index_;
HostResolver* resolver_;
Handler* handler_;
@@ -413,14 +421,29 @@ class HostResolverImplTest : public testing::Test {
HostResolverImplTest() : proc_(new MockHostResolverProc()) {}
+ void CreateResolver() {
+ CreateResolverWithLimitsAndParams(DefaultLimits(),
+ DefaultParams(proc_.get()));
+ }
+
+ // This HostResolverImpl will only allow 1 outstanding resolve at a time and
+ // perform no retries.
+ void CreateSerialResolver() {
+ HostResolverImpl::ProcTaskParams params = DefaultParams(proc_.get());
+ params.max_retry_attempts = 0u;
+ PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, 1);
+ CreateResolverWithLimitsAndParams(limits, params);
+ }
+
protected:
// A Request::Handler which is a proxy to the HostResolverImplTest fixture.
struct Handler : public Request::Handler {
virtual ~Handler() {}
// Proxy functions so that classes derived from Handler can access them.
- Request* CreateRequest(const HostResolver::RequestInfo& info) {
- return test->CreateRequest(info);
+ Request* CreateRequest(const HostResolver::RequestInfo& info,
+ RequestPriority priority) {
+ return test->CreateRequest(info, priority);
}
Request* CreateRequest(const std::string& hostname, int port) {
return test->CreateRequest(hostname, port);
@@ -435,31 +458,30 @@ class HostResolverImplTest : public testing::Test {
HostResolverImplTest* test;
};
- void CreateResolver() {
- resolver_.reset(new HostResolverImpl(HostCache::CreateDefaultCache(),
- DefaultLimits(),
- DefaultParams(proc_.get()),
- NULL));
+ // testing::Test implementation:
+ virtual void SetUp() OVERRIDE {
+ CreateResolver();
}
- // This HostResolverImpl will only allow 1 outstanding resolve at a time and
- // perform no retries.
- void CreateSerialResolver() {
- HostResolverImpl::ProcTaskParams params = DefaultParams(proc_.get());
- params.max_retry_attempts = 0u;
- PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, 1);
- resolver_.reset(new HostResolverImpl(
- HostCache::CreateDefaultCache(),
- limits,
- params,
- NULL));
+ virtual void TearDown() OVERRIDE {
+ if (resolver_.get())
+ EXPECT_EQ(0u, resolver_->num_running_dispatcher_jobs_for_tests());
+ EXPECT_FALSE(proc_->HasBlockedRequests());
+ }
+
+ virtual void CreateResolverWithLimitsAndParams(
+ const PrioritizedDispatcher::Limits& limits,
+ const HostResolverImpl::ProcTaskParams& params) {
+ resolver_.reset(new HostResolverImpl(HostCache::CreateDefaultCache(),
+ limits, params, NULL));
}
// The Request will not be made until a call to |Resolve()|, and the Job will
// not start until released by |proc_->SignalXXX|.
- Request* CreateRequest(const HostResolver::RequestInfo& info) {
- Request* req = new Request(info, requests_.size(), resolver_.get(),
- handler_.get());
+ Request* CreateRequest(const HostResolver::RequestInfo& info,
+ RequestPriority priority) {
+ Request* req = new Request(
+ info, priority, requests_.size(), resolver_.get(), handler_.get());
requests_.push_back(req);
return req;
}
@@ -469,9 +491,8 @@ class HostResolverImplTest : public testing::Test {
RequestPriority priority,
AddressFamily family) {
HostResolver::RequestInfo info(HostPortPair(hostname, port));
- info.set_priority(priority);
info.set_address_family(family);
- return CreateRequest(info);
+ return CreateRequest(info, priority);
}
Request* CreateRequest(const std::string& hostname,
@@ -488,25 +509,15 @@ class HostResolverImplTest : public testing::Test {
return CreateRequest(hostname, kDefaultPort);
}
- virtual void SetUp() OVERRIDE {
- CreateResolver();
- }
-
- virtual void TearDown() OVERRIDE {
- if (resolver_.get())
- EXPECT_EQ(0u, resolver_->num_running_jobs_for_tests());
- EXPECT_FALSE(proc_->HasBlockedRequests());
- }
-
void set_handler(Handler* handler) {
handler_.reset(handler);
handler_->test = this;
}
// Friendship is not inherited, so use proxies to access those.
- size_t num_running_jobs() const {
+ size_t num_running_dispatcher_jobs() const {
DCHECK(resolver_.get());
- return resolver_->num_running_jobs_for_tests();
+ return resolver_->num_running_dispatcher_jobs_for_tests();
}
void set_fallback_to_proctask(bool fallback_to_proctask) {
@@ -514,6 +525,10 @@ class HostResolverImplTest : public testing::Test {
resolver_->fallback_to_proctask_ = fallback_to_proctask;
}
+ static unsigned maximum_dns_failures() {
+ return HostResolverImpl::kMaximumDnsFailures;
+ }
+
scoped_refptr<MockHostResolverProc> proc_;
scoped_ptr<HostResolverImpl> resolver_;
ScopedVector<Request> requests_;
@@ -817,7 +832,8 @@ TEST_F(HostResolverImplTest, BypassCache) {
// longer service the request synchronously.
HostResolver::RequestInfo info(HostPortPair(hostname, 71));
info.set_allow_cached_response(false);
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest(info)->Resolve());
+ EXPECT_EQ(ERR_IO_PENDING,
+ CreateRequest(info, DEFAULT_PRIORITY)->Resolve());
} else if (71 == req->info().port()) {
// Test is done.
base::MessageLoop::current()->Quit();
@@ -889,7 +905,7 @@ TEST_F(HostResolverImplTest, ObeyPoolConstraintsAfterIPAddressChange) {
EXPECT_EQ(ERR_NETWORK_CHANGED, requests_[0]->WaitForResult());
- EXPECT_EQ(1u, num_running_jobs());
+ EXPECT_EQ(1u, num_running_dispatcher_jobs());
EXPECT_FALSE(requests_[1]->completed());
EXPECT_FALSE(requests_[2]->completed());
@@ -1189,14 +1205,15 @@ TEST_F(HostResolverImplTest, ResolveFromCache) {
HostResolver::RequestInfo info(HostPortPair("just.testing", 80));
// First hit will miss the cache.
- EXPECT_EQ(ERR_DNS_CACHE_MISS, CreateRequest(info)->ResolveFromCache());
+ EXPECT_EQ(ERR_DNS_CACHE_MISS,
+ CreateRequest(info, DEFAULT_PRIORITY)->ResolveFromCache());
// This time, we fetch normally.
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest(info)->Resolve());
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest(info, DEFAULT_PRIORITY)->Resolve());
EXPECT_EQ(OK, requests_[1]->WaitForResult());
// Now we should be able to fetch from the cache.
- EXPECT_EQ(OK, CreateRequest(info)->ResolveFromCache());
+ EXPECT_EQ(OK, CreateRequest(info, DEFAULT_PRIORITY)->ResolveFromCache());
EXPECT_TRUE(requests_[2]->HasOneAddress("192.168.1.42", 80));
}
@@ -1228,7 +1245,7 @@ TEST_F(HostResolverImplTest, MultipleAttempts) {
// Resolve "host1".
HostResolver::RequestInfo info(HostPortPair("host1", 70));
- Request* req = CreateRequest(info);
+ Request* req = CreateRequest(info, DEFAULT_PRIORITY);
EXPECT_EQ(ERR_IO_PENDING, req->Resolve());
// Resolve returns -4 to indicate that 3rd attempt has resolved the host.
@@ -1255,36 +1272,70 @@ DnsConfig CreateValidDnsConfig() {
// Specialized fixture for tests of DnsTask.
class HostResolverImplDnsTest : public HostResolverImplTest {
+ public:
+ HostResolverImplDnsTest() : dns_client_(NULL) {}
+
protected:
+ // testing::Test implementation:
virtual void SetUp() OVERRIDE {
- AddDnsRule("nx", dns_protocol::kTypeA, MockDnsClientRule::FAIL);
- AddDnsRule("nx", dns_protocol::kTypeAAAA, MockDnsClientRule::FAIL);
- AddDnsRule("ok", dns_protocol::kTypeA, MockDnsClientRule::OK);
- AddDnsRule("ok", dns_protocol::kTypeAAAA, MockDnsClientRule::OK);
- AddDnsRule("4ok", dns_protocol::kTypeA, MockDnsClientRule::OK);
- AddDnsRule("4ok", dns_protocol::kTypeAAAA, MockDnsClientRule::EMPTY);
- AddDnsRule("6ok", dns_protocol::kTypeA, MockDnsClientRule::EMPTY);
- AddDnsRule("6ok", dns_protocol::kTypeAAAA, MockDnsClientRule::OK);
- AddDnsRule("4nx", dns_protocol::kTypeA, MockDnsClientRule::OK);
- AddDnsRule("4nx", dns_protocol::kTypeAAAA, MockDnsClientRule::FAIL);
+ AddDnsRule("nx", dns_protocol::kTypeA, MockDnsClientRule::FAIL, false);
+ AddDnsRule("nx", dns_protocol::kTypeAAAA, MockDnsClientRule::FAIL, false);
+ AddDnsRule("ok", dns_protocol::kTypeA, MockDnsClientRule::OK, false);
+ AddDnsRule("ok", dns_protocol::kTypeAAAA, MockDnsClientRule::OK, false);
+ AddDnsRule("4ok", dns_protocol::kTypeA, MockDnsClientRule::OK, false);
+ AddDnsRule("4ok", dns_protocol::kTypeAAAA, MockDnsClientRule::EMPTY, false);
+ AddDnsRule("6ok", dns_protocol::kTypeA, MockDnsClientRule::EMPTY, false);
+ AddDnsRule("6ok", dns_protocol::kTypeAAAA, MockDnsClientRule::OK, false);
+ AddDnsRule("4nx", dns_protocol::kTypeA, MockDnsClientRule::OK, false);
+ AddDnsRule("4nx", dns_protocol::kTypeAAAA, MockDnsClientRule::FAIL, false);
+ AddDnsRule("empty", dns_protocol::kTypeA, MockDnsClientRule::EMPTY, false);
+ AddDnsRule("empty", dns_protocol::kTypeAAAA, MockDnsClientRule::EMPTY,
+ false);
+
+ AddDnsRule("slow_nx", dns_protocol::kTypeA, MockDnsClientRule::FAIL, true);
+ AddDnsRule("slow_nx", dns_protocol::kTypeAAAA, MockDnsClientRule::FAIL,
+ true);
+
+ AddDnsRule("4slow_ok", dns_protocol::kTypeA, MockDnsClientRule::OK, true);
+ AddDnsRule("4slow_ok", dns_protocol::kTypeAAAA, MockDnsClientRule::OK,
+ false);
+ AddDnsRule("6slow_ok", dns_protocol::kTypeA, MockDnsClientRule::OK, false);
+ AddDnsRule("6slow_ok", dns_protocol::kTypeAAAA, MockDnsClientRule::OK,
+ true);
+ AddDnsRule("4slow_4ok", dns_protocol::kTypeA, MockDnsClientRule::OK, true);
+ AddDnsRule("4slow_4ok", dns_protocol::kTypeAAAA, MockDnsClientRule::EMPTY,
+ false);
+ AddDnsRule("4slow_4timeout", dns_protocol::kTypeA,
+ MockDnsClientRule::TIMEOUT, true);
+ AddDnsRule("4slow_4timeout", dns_protocol::kTypeAAAA, MockDnsClientRule::OK,
+ false);
+ AddDnsRule("4slow_6timeout", dns_protocol::kTypeA,
+ MockDnsClientRule::OK, true);
+ AddDnsRule("4slow_6timeout", dns_protocol::kTypeAAAA,
+ MockDnsClientRule::TIMEOUT, false);
CreateResolver();
}
- void CreateResolver() {
+ // HostResolverImplTest implementation:
+ virtual void CreateResolverWithLimitsAndParams(
+ const PrioritizedDispatcher::Limits& limits,
+ const HostResolverImpl::ProcTaskParams& params) OVERRIDE {
resolver_.reset(new HostResolverImpl(HostCache::CreateDefaultCache(),
- DefaultLimits(),
- DefaultParams(proc_.get()),
+ limits,
+ params,
NULL));
// Disable IPv6 support probing.
resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
- resolver_->SetDnsClient(CreateMockDnsClient(DnsConfig(), dns_rules_));
+ dns_client_ = new MockDnsClient(DnsConfig(), dns_rules_);
+ resolver_->SetDnsClient(scoped_ptr<DnsClient>(dns_client_));
}
// Adds a rule to |dns_rules_|. Must be followed by |CreateResolver| to apply.
void AddDnsRule(const std::string& prefix,
uint16 qtype,
- MockDnsClientRule::Result result) {
- dns_rules_.push_back(MockDnsClientRule(prefix, qtype, result));
+ MockDnsClientRule::Result result,
+ bool delay) {
+ dns_rules_.push_back(MockDnsClientRule(prefix, qtype, result, delay));
}
void ChangeDnsConfig(const DnsConfig& config) {
@@ -1294,6 +1345,8 @@ class HostResolverImplDnsTest : public HostResolverImplTest {
}
MockDnsClientRuleList dns_rules_;
+ // Owned by |resolver_|.
+ MockDnsClient* dns_client_;
};
// TODO(szym): Test AbortAllInProgressJobs due to DnsConfig change.
@@ -1361,7 +1414,8 @@ TEST_F(HostResolverImplDnsTest, NoFallbackToProcTask) {
// Simulate the case when the preference or policy has disabled the DNS client
// causing AbortDnsTasks.
- resolver_->SetDnsClient(CreateMockDnsClient(DnsConfig(), dns_rules_));
+ resolver_->SetDnsClient(
+ scoped_ptr<DnsClient>(new MockDnsClient(DnsConfig(), dns_rules_)));
ChangeDnsConfig(CreateValidDnsConfig());
// First request is resolved by MockDnsClient, others should fail due to
@@ -1509,6 +1563,24 @@ TEST_F(HostResolverImplDnsTest, BypassDnsTask) {
EXPECT_EQ(OK, requests_[i]->WaitForResult()) << i;
}
+TEST_F(HostResolverImplDnsTest, SystemOnlyBypassesDnsTask) {
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ proc_->AddRuleForAllFamilies(std::string(), std::string());
+
+ HostResolver::RequestInfo info_bypass(HostPortPair("ok", 80));
+ info_bypass.set_host_resolver_flags(HOST_RESOLVER_SYSTEM_ONLY);
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest(info_bypass, MEDIUM)->Resolve());
+
+ HostResolver::RequestInfo info(HostPortPair("ok", 80));
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest(info, MEDIUM)->Resolve());
+
+ proc_->SignalMultiple(requests_.size());
+
+ EXPECT_EQ(ERR_NAME_NOT_RESOLVED, requests_[0]->WaitForResult());
+ EXPECT_EQ(OK, requests_[1]->WaitForResult());
+}
+
TEST_F(HostResolverImplDnsTest, DisableDnsClientOnPersistentFailure) {
ChangeDnsConfig(CreateValidDnsConfig());
@@ -1520,7 +1592,7 @@ TEST_F(HostResolverImplDnsTest, DisableDnsClientOnPersistentFailure) {
EXPECT_EQ(ERR_IO_PENDING, req->Resolve());
EXPECT_EQ(OK, req->WaitForResult());
- for (unsigned i = 0; i < 20; ++i) {
+ for (unsigned i = 0; i < maximum_dns_failures(); ++i) {
// Use custom names to require separate Jobs.
std::string hostname = base::StringPrintf("nx_%u", i);
// Ensure fallback to ProcTask succeeds.
@@ -1585,7 +1657,8 @@ TEST_F(HostResolverImplDnsTest, DualFamilyLocalhost) {
DefaultLimits(),
DefaultParams(proc.get()),
NULL));
- resolver_->SetDnsClient(CreateMockDnsClient(DnsConfig(), dns_rules_));
+ resolver_->SetDnsClient(
+ scoped_ptr<DnsClient>(new MockDnsClient(DnsConfig(), dns_rules_)));
resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV4);
// Get the expected output.
@@ -1609,7 +1682,7 @@ TEST_F(HostResolverImplDnsTest, DualFamilyLocalhost) {
// Try without DnsClient.
ChangeDnsConfig(DnsConfig());
- Request* req = CreateRequest(info);
+ Request* req = CreateRequest(info, DEFAULT_PRIORITY);
// It is resolved via getaddrinfo, so expect asynchronous result.
EXPECT_EQ(ERR_IO_PENDING, req->Resolve());
EXPECT_EQ(OK, req->WaitForResult());
@@ -1630,7 +1703,7 @@ TEST_F(HostResolverImplDnsTest, DualFamilyLocalhost) {
config.hosts = hosts;
ChangeDnsConfig(config);
- req = CreateRequest(info);
+ req = CreateRequest(info, DEFAULT_PRIORITY);
// Expect synchronous resolution from DnsHosts.
EXPECT_EQ(OK, req->Resolve());
@@ -1638,4 +1711,346 @@ TEST_F(HostResolverImplDnsTest, DualFamilyLocalhost) {
EXPECT_EQ(saw_ipv6, req->HasAddress("::1", 80));
}
+// Cancel a request with a single DNS transaction active.
+TEST_F(HostResolverImplDnsTest, CancelWithOneTransactionActive) {
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV4);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok", 80)->Resolve());
+ EXPECT_EQ(1u, num_running_dispatcher_jobs());
+ requests_[0]->Cancel();
+
+ // Dispatcher state checked in TearDown.
+}
+
+// Cancel a request with a single DNS transaction active and another pending.
+TEST_F(HostResolverImplDnsTest, CancelWithOneTransactionActiveOnePending) {
+ CreateSerialResolver();
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok", 80)->Resolve());
+ EXPECT_EQ(1u, num_running_dispatcher_jobs());
+ requests_[0]->Cancel();
+
+ // Dispatcher state checked in TearDown.
+}
+
+// Cancel a request with two DNS transactions active.
+TEST_F(HostResolverImplDnsTest, CancelWithTwoTransactionsActive) {
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok", 80)->Resolve());
+ EXPECT_EQ(2u, num_running_dispatcher_jobs());
+ requests_[0]->Cancel();
+
+ // Dispatcher state checked in TearDown.
+}
+
+// Delete a resolver with some active requests and some queued requests.
+TEST_F(HostResolverImplDnsTest, DeleteWithActiveTransactions) {
+ // At most 10 Jobs active at once.
+ CreateResolverWithLimitsAndParams(
+ PrioritizedDispatcher::Limits(NUM_PRIORITIES, 10u),
+ DefaultParams(proc_.get()));
+
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ // First active job is an IPv4 request.
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok", 80, MEDIUM,
+ ADDRESS_FAMILY_IPV4)->Resolve());
+
+ // Add 10 more DNS lookups for different hostnames. First 4 should have two
+ // active jobs, next one has a single active job, and one pending. Others
+ // should all be queued.
+ for (int i = 0; i < 10; ++i) {
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest(
+ base::StringPrintf("ok%i", i))->Resolve());
+ }
+ EXPECT_EQ(10u, num_running_dispatcher_jobs());
+
+ resolver_.reset();
+}
+
+// Cancel a request with only the IPv6 transaction active.
+TEST_F(HostResolverImplDnsTest, CancelWithIPv6TransactionActive) {
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("6slow_ok", 80)->Resolve());
+ EXPECT_EQ(2u, num_running_dispatcher_jobs());
+
+ // The IPv4 request should complete, the IPv6 request is still pending.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1u, num_running_dispatcher_jobs());
+ requests_[0]->Cancel();
+
+ // Dispatcher state checked in TearDown.
+}
+
+// Cancel a request with only the IPv4 transaction pending.
+TEST_F(HostResolverImplDnsTest, CancelWithIPv4TransactionPending) {
+ set_fallback_to_proctask(false);
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("4slow_ok", 80)->Resolve());
+ EXPECT_EQ(2u, num_running_dispatcher_jobs());
+
+ // The IPv6 request should complete, the IPv4 request is still pending.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1u, num_running_dispatcher_jobs());
+
+ requests_[0]->Cancel();
+}
+
+// Test cases where AAAA completes first.
+TEST_F(HostResolverImplDnsTest, AAAACompletesFirst) {
+ set_fallback_to_proctask(false);
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("4slow_ok", 80)->Resolve());
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("4slow_4ok", 80)->Resolve());
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("4slow_4timeout", 80)->Resolve());
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("4slow_6timeout", 80)->Resolve());
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(requests_[0]->completed());
+ EXPECT_FALSE(requests_[1]->completed());
+ EXPECT_FALSE(requests_[2]->completed());
+ // The IPv6 of the third request should have failed and resulted in cancelling
+ // the IPv4 request.
+ EXPECT_TRUE(requests_[3]->completed());
+ EXPECT_EQ(ERR_DNS_TIMED_OUT, requests_[3]->result());
+ EXPECT_EQ(3u, num_running_dispatcher_jobs());
+
+ dns_client_->CompleteDelayedTransactions();
+ EXPECT_TRUE(requests_[0]->completed());
+ EXPECT_EQ(OK, requests_[0]->result());
+ EXPECT_EQ(2u, requests_[0]->NumberOfAddresses());
+ EXPECT_TRUE(requests_[0]->HasAddress("127.0.0.1", 80));
+ EXPECT_TRUE(requests_[0]->HasAddress("::1", 80));
+
+ EXPECT_TRUE(requests_[1]->completed());
+ EXPECT_EQ(OK, requests_[1]->result());
+ EXPECT_EQ(1u, requests_[1]->NumberOfAddresses());
+ EXPECT_TRUE(requests_[1]->HasAddress("127.0.0.1", 80));
+
+ EXPECT_TRUE(requests_[2]->completed());
+ EXPECT_EQ(ERR_DNS_TIMED_OUT, requests_[2]->result());
+}
+
+// Test the case where only a single transaction slot is available.
+TEST_F(HostResolverImplDnsTest, SerialResolver) {
+ CreateSerialResolver();
+ set_fallback_to_proctask(false);
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok", 80)->Resolve());
+ EXPECT_EQ(1u, num_running_dispatcher_jobs());
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(requests_[0]->completed());
+ EXPECT_EQ(OK, requests_[0]->result());
+ EXPECT_EQ(2u, requests_[0]->NumberOfAddresses());
+ EXPECT_TRUE(requests_[0]->HasAddress("127.0.0.1", 80));
+ EXPECT_TRUE(requests_[0]->HasAddress("::1", 80));
+}
+
+// Test the case where the AAAA query is started when another transaction
+// completes.
+TEST_F(HostResolverImplDnsTest, AAAAStartsAfterOtherJobFinishes) {
+ CreateResolverWithLimitsAndParams(
+ PrioritizedDispatcher::Limits(NUM_PRIORITIES, 2),
+ DefaultParams(proc_.get()));
+ set_fallback_to_proctask(false);
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok", 80, MEDIUM,
+ ADDRESS_FAMILY_IPV4)->Resolve());
+ EXPECT_EQ(ERR_IO_PENDING,
+ CreateRequest("4slow_ok", 80, MEDIUM)->Resolve());
+ // An IPv4 request should have been started pending for each job.
+ EXPECT_EQ(2u, num_running_dispatcher_jobs());
+
+ // Request 0's IPv4 request should complete, starting Request 1's IPv6
+ // request, which should also complete.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1u, num_running_dispatcher_jobs());
+ EXPECT_TRUE(requests_[0]->completed());
+ EXPECT_FALSE(requests_[1]->completed());
+
+ dns_client_->CompleteDelayedTransactions();
+ EXPECT_TRUE(requests_[1]->completed());
+ EXPECT_EQ(OK, requests_[1]->result());
+ EXPECT_EQ(2u, requests_[1]->NumberOfAddresses());
+ EXPECT_TRUE(requests_[1]->HasAddress("127.0.0.1", 80));
+ EXPECT_TRUE(requests_[1]->HasAddress("::1", 80));
+}
+
+// Tests the case that a Job with a single transaction receives an empty address
+// list, triggering fallback to ProcTask.
+TEST_F(HostResolverImplDnsTest, IPv4EmptyFallback) {
+ ChangeDnsConfig(CreateValidDnsConfig());
+ proc_->AddRuleForAllFamilies("empty_fallback", "192.168.0.1");
+ proc_->SignalMultiple(1u);
+ EXPECT_EQ(ERR_IO_PENDING,
+ CreateRequest("empty_fallback", 80, MEDIUM,
+ ADDRESS_FAMILY_IPV4)->Resolve());
+ EXPECT_EQ(OK, requests_[0]->WaitForResult());
+ EXPECT_TRUE(requests_[0]->HasOneAddress("192.168.0.1", 80));
+}
+
+// Tests the case that a Job with two transactions receives two empty address
+// lists, triggering fallback to ProcTask.
+TEST_F(HostResolverImplDnsTest, UnspecEmptyFallback) {
+ ChangeDnsConfig(CreateValidDnsConfig());
+ proc_->AddRuleForAllFamilies("empty_fallback", "192.168.0.1");
+ proc_->SignalMultiple(1u);
+ EXPECT_EQ(ERR_IO_PENDING,
+ CreateRequest("empty_fallback", 80, MEDIUM,
+ ADDRESS_FAMILY_UNSPECIFIED)->Resolve());
+ EXPECT_EQ(OK, requests_[0]->WaitForResult());
+ EXPECT_TRUE(requests_[0]->HasOneAddress("192.168.0.1", 80));
+}
+
+// Tests getting a new invalid DnsConfig while there are active DnsTasks.
+TEST_F(HostResolverImplDnsTest, InvalidDnsConfigWithPendingRequests) {
+ // At most 3 jobs active at once. This number is important, since we want to
+ // make sure that aborting the first HostResolverImpl::Job does not trigger
+ // another DnsTransaction on the second Job when it releases its second
+ // prioritized dispatcher slot.
+ CreateResolverWithLimitsAndParams(
+ PrioritizedDispatcher::Limits(NUM_PRIORITIES, 3u),
+ DefaultParams(proc_.get()));
+
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ proc_->AddRuleForAllFamilies("slow_nx1", "192.168.0.1");
+ proc_->AddRuleForAllFamilies("slow_nx2", "192.168.0.2");
+ proc_->AddRuleForAllFamilies("ok", "192.168.0.3");
+
+ // First active job gets two slots.
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("slow_nx1")->Resolve());
+ // Next job gets one slot, and waits on another.
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("slow_nx2")->Resolve());
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok")->Resolve());
+
+ EXPECT_EQ(3u, num_running_dispatcher_jobs());
+
+ // Clear DNS config. Two in-progress jobs should be aborted, and the next one
+ // should use a ProcTask.
+ ChangeDnsConfig(DnsConfig());
+ EXPECT_EQ(ERR_NETWORK_CHANGED, requests_[0]->WaitForResult());
+ EXPECT_EQ(ERR_NETWORK_CHANGED, requests_[1]->WaitForResult());
+
+ // Finish up the third job. Should bypass the DnsClient, and get its results
+ // from MockHostResolverProc.
+ EXPECT_FALSE(requests_[2]->completed());
+ proc_->SignalMultiple(1u);
+ EXPECT_EQ(OK, requests_[2]->WaitForResult());
+ EXPECT_TRUE(requests_[2]->HasOneAddress("192.168.0.3", 80));
+}
+
+// Tests the case that DnsClient is automatically disabled due to failures
+// while there are active DnsTasks.
+TEST_F(HostResolverImplDnsTest,
+ AutomaticallyDisableDnsClientWithPendingRequests) {
+ // Trying different limits is important for this test: Different limits
+ // result in different behavior when aborting in-progress DnsTasks. Having
+ // a DnsTask that has one job active and one in the queue when another job
+ // occupying two slots has its DnsTask aborted is the case most likely to run
+ // into problems.
+ for (size_t limit = 1u; limit < 6u; ++limit) {
+ CreateResolverWithLimitsAndParams(
+ PrioritizedDispatcher::Limits(NUM_PRIORITIES, limit),
+ DefaultParams(proc_.get()));
+
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ // Queue up enough failures to disable DnsTasks. These will all fall back
+ // to ProcTasks, and succeed there.
+ for (unsigned i = 0u; i < maximum_dns_failures(); ++i) {
+ std::string host = base::StringPrintf("nx%u", i);
+ proc_->AddRuleForAllFamilies(host, "192.168.0.1");
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest(host)->Resolve());
+ }
+
+ // These requests should all bypass DnsTasks, due to the above failures,
+ // so should end up using ProcTasks.
+ proc_->AddRuleForAllFamilies("slow_ok1", "192.168.0.2");
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("slow_ok1")->Resolve());
+ proc_->AddRuleForAllFamilies("slow_ok2", "192.168.0.3");
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("slow_ok2")->Resolve());
+ proc_->AddRuleForAllFamilies("slow_ok3", "192.168.0.4");
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("slow_ok3")->Resolve());
+ proc_->SignalMultiple(maximum_dns_failures() + 3);
+
+ for (size_t i = 0u; i < maximum_dns_failures(); ++i) {
+ EXPECT_EQ(OK, requests_[i]->WaitForResult());
+ EXPECT_TRUE(requests_[i]->HasOneAddress("192.168.0.1", 80));
+ }
+
+ EXPECT_EQ(OK, requests_[maximum_dns_failures()]->WaitForResult());
+ EXPECT_TRUE(requests_[maximum_dns_failures()]->HasOneAddress(
+ "192.168.0.2", 80));
+ EXPECT_EQ(OK, requests_[maximum_dns_failures() + 1]->WaitForResult());
+ EXPECT_TRUE(requests_[maximum_dns_failures() + 1]->HasOneAddress(
+ "192.168.0.3", 80));
+ EXPECT_EQ(OK, requests_[maximum_dns_failures() + 2]->WaitForResult());
+ EXPECT_TRUE(requests_[maximum_dns_failures() + 2]->HasOneAddress(
+ "192.168.0.4", 80));
+ requests_.clear();
+ }
+}
+
+// Tests a call to SetDnsClient while there are active DnsTasks.
+TEST_F(HostResolverImplDnsTest, ManuallyDisableDnsClientWithPendingRequests) {
+ // At most 3 jobs active at once. This number is important, since we want to
+ // make sure that aborting the first HostResolverImpl::Job does not trigger
+ // another DnsTransaction on the second Job when it releases its second
+ // prioritized dispatcher slot.
+ CreateResolverWithLimitsAndParams(
+ PrioritizedDispatcher::Limits(NUM_PRIORITIES, 3u),
+ DefaultParams(proc_.get()));
+
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ proc_->AddRuleForAllFamilies("slow_ok1", "192.168.0.1");
+ proc_->AddRuleForAllFamilies("slow_ok2", "192.168.0.2");
+ proc_->AddRuleForAllFamilies("ok", "192.168.0.3");
+
+ // First active job gets two slots.
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("slow_ok1")->Resolve());
+ // Next job gets one slot, and waits on another.
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("slow_ok2")->Resolve());
+ // Next one is queued.
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok")->Resolve());
+
+ EXPECT_EQ(3u, num_running_dispatcher_jobs());
+
+ // Clear DnsClient. The two in-progress jobs should fall back to a ProcTask,
+ // and the next one should be started with a ProcTask.
+ resolver_->SetDnsClient(scoped_ptr<DnsClient>());
+
+ // All three in-progress requests should now be running a ProcTask.
+ EXPECT_EQ(3u, num_running_dispatcher_jobs());
+ proc_->SignalMultiple(3u);
+
+ EXPECT_EQ(OK, requests_[0]->WaitForResult());
+ EXPECT_TRUE(requests_[0]->HasOneAddress("192.168.0.1", 80));
+ EXPECT_EQ(OK, requests_[1]->WaitForResult());
+ EXPECT_TRUE(requests_[1]->HasOneAddress("192.168.0.2", 80));
+ EXPECT_EQ(OK, requests_[2]->WaitForResult());
+ EXPECT_TRUE(requests_[2]->HasOneAddress("192.168.0.3", 80));
+}
+
} // namespace net