summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authordarin@google.com <darin@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-09-24 06:31:34 +0000
committerdarin@google.com <darin@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-09-24 06:31:34 +0000
commit025517044b4be3ab45efc2f383e5a7b830aa7281 (patch)
treeb43566625f0702e8fa44590a7a82b3c41b56b5cc /net
parent8943d1c09b155984790847a849e816ffe695a91a (diff)
downloadchromium_src-025517044b4be3ab45efc2f383e5a7b830aa7281.zip
chromium_src-025517044b4be3ab45efc2f383e5a7b830aa7281.tar.gz
chromium_src-025517044b4be3ab45efc2f383e5a7b830aa7281.tar.bz2
Add support for mock DNS queries. This allows us to eliminate
flaky DNS queries from the unit tests. Note: some unit tests still connect to www.google.com. My plan is to resolve those in a subsequent CL. R=wtc BUG=2635 Review URL: http://codereview.chromium.org/4022 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@2545 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/base/host_resolver.cc24
-rw-r--r--net/base/host_resolver.h24
-rw-r--r--net/base/host_resolver_unittest.h86
-rw-r--r--net/base/run_all_unittests.cc6
-rw-r--r--net/base/tcp_client_socket_unittest.cc9
-rw-r--r--net/http/http_network_layer_unittest.cc9
6 files changed, 155 insertions, 3 deletions
diff --git a/net/base/host_resolver.cc b/net/base/host_resolver.cc
index ab706b3..d3b054f 100644
--- a/net/base/host_resolver.cc
+++ b/net/base/host_resolver.cc
@@ -26,8 +26,15 @@ namespace net {
//-----------------------------------------------------------------------------
-static int ResolveAddrInfo(const std::string& host, const std::string& port,
- struct addrinfo** results) {
+static HostMapper* host_mapper;
+
+HostMapper* SetHostMapper(HostMapper* value) {
+ std::swap(host_mapper, value);
+ return value;
+}
+
+static int HostResolverProc(
+ const std::string& host, const std::string& port, struct addrinfo** out) {
struct addrinfo hints = {0};
hints.ai_family = PF_UNSPEC;
hints.ai_flags = AI_ADDRCONFIG;
@@ -35,10 +42,21 @@ static int ResolveAddrInfo(const std::string& host, const std::string& port,
// Restrict result set to only this socket type to avoid duplicates.
hints.ai_socktype = SOCK_STREAM;
- int err = getaddrinfo(host.c_str(), port.c_str(), &hints, results);
+ int err = getaddrinfo(host.c_str(), port.c_str(), &hints, out);
return err ? ERR_NAME_NOT_RESOLVED : OK;
}
+static int ResolveAddrInfo(
+ const std::string& host, const std::string& port, struct addrinfo** out) {
+ int rv;
+ if (host_mapper) {
+ rv = HostResolverProc(host_mapper->Map(host), port, out);
+ } else {
+ rv = HostResolverProc(host, port, out);
+ }
+ return rv;
+}
+
//-----------------------------------------------------------------------------
class HostResolver::Request :
diff --git a/net/base/host_resolver.h b/net/base/host_resolver.h
index 5364d17..1f649f8 100644
--- a/net/base/host_resolver.h
+++ b/net/base/host_resolver.h
@@ -55,6 +55,30 @@ class HostResolver {
DISALLOW_COPY_AND_ASSIGN(HostResolver);
};
+// A helper class used in unit tests to alter hostname mappings. See
+// SetHostMapper for details.
+class HostMapper {
+ public:
+ virtual ~HostMapper() {}
+ virtual std::string Map(const std::string& host) = 0;
+};
+
+#ifdef UNIT_TEST
+// This function is designed to allow unit tests to override the behavior of
+// HostResolver. For example, a HostMapper instance can force all hostnames
+// to map to a fixed IP address such as 127.0.0.1.
+//
+// The previously set HostMapper (or NULL if there was none) is returned.
+//
+// NOTE: This function is not thread-safe, so take care to only call this
+// function while there are no outstanding HostResolver instances.
+//
+// NOTE: In most cases, you should use ScopedHostMapper instead, which is
+// defined in host_resolver_unittest.h
+//
+HostMapper* SetHostMapper(HostMapper* host_mapper);
+#endif
+
} // namespace net
#endif // NET_BASE_HOST_RESOLVER_H_
diff --git a/net/base/host_resolver_unittest.h b/net/base/host_resolver_unittest.h
new file mode 100644
index 0000000..c7ecea81
--- /dev/null
+++ b/net/base/host_resolver_unittest.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines ScopedHostMapper, which is a helper class for writing
+// tests that use HostResolver either directly or indirectly.
+//
+// In most cases, it is important that unit tests avoid making actual DNS
+// queries since the resulting tests can be flaky, especially if the network is
+// unreliable for some reason. To simplify writing tests that avoid making
+// actual DNS queries, the following helper class may be used:
+//
+// ScopedHostMapper scoped_host_mapper;
+// scoped_host_mapper.AddRule("foo.com", "1.2.3.4");
+// scoped_host_mapper.AddRule("bar.com", "2.3.4.5");
+// ...
+//
+// The above rules define a static mapping from hostnames to IP address
+// literals. The first parameter to AddRule specifies a host pattern to match
+// against, and the second parameter indicates what value should be used to
+// replace the given hostname. So, the following is also supported:
+//
+// scoped_host_mapper.AddRule("*.com", "127.0.0.1");
+//
+// If there are multiple ScopedHostMappers on the stack, then the last one
+// allocated will be used. However, if it does not provide a matching rule,
+// then it will delegate to the previously allocated ScopedHostMapper.
+// Finally, if no HostMapper matches a given hostname, then the hostname will
+// be unmodified.
+
+#ifndef NET_BASE_HOST_RESOLVER_UNITTEST_H_
+#define NET_BASE_HOST_RESOLVER_UNITTEST_H_
+
+#ifdef UNIT_TEST
+
+#include <list>
+
+#include "base/string_util.h"
+#include "net/base/host_resolver.h"
+#include "net/base/net_errors.h"
+
+namespace net {
+
+// This class sets the HostResolverProc for a particular scope.
+class ScopedHostMapper : public HostMapper {
+ public:
+ ScopedHostMapper() {
+ previous_host_mapper_ = SetHostMapper(this);
+ }
+
+ ~ScopedHostMapper() {
+ SetHostMapper(previous_host_mapper_);
+ }
+
+ // Any hostname matching the given pattern will be replaced with the given
+ // replacement value. Usually, replacement should be an IP address literal.
+ void AddRule(const char* host_pattern, const char* replacement) {
+ rules_.push_back(Rule(host_pattern, replacement));
+ }
+
+ private:
+ std::string Map(const std::string& host) {
+ RuleList::const_iterator r;
+ for (r = rules_.begin(); r != rules_.end(); ++r) {
+ if (MatchPattern(host, r->host_pattern))
+ return r->replacement;
+ }
+ return previous_host_mapper_ ? previous_host_mapper_->Map(host) : host;
+ }
+
+ struct Rule {
+ std::string host_pattern;
+ std::string replacement;
+ Rule(const char* h, const char* r) : host_pattern(h), replacement(r) {}
+ };
+ typedef std::list<Rule> RuleList;
+
+ HostMapper* previous_host_mapper_;
+ RuleList rules_;
+};
+
+} // namespace net
+
+#endif // UNIT_TEST
+
+#endif // NET_BASE_HOST_RESOLVER_UNITTEST_H_
diff --git a/net/base/run_all_unittests.cc b/net/base/run_all_unittests.cc
index f5c1419b..de79e68 100644
--- a/net/base/run_all_unittests.cc
+++ b/net/base/run_all_unittests.cc
@@ -29,10 +29,15 @@
#include "base/message_loop.h"
#include "base/test_suite.h"
+#include "net/base/host_resolver_unittest.h"
class NetTestSuite : public TestSuite {
public:
NetTestSuite(int argc, char** argv) : TestSuite(argc, argv) {
+ // In case any attempts are made to resolve host names, force them all to
+ // be mapped to localhost. This prevents DNS queries from being sent in
+ // the process of running these unit tests.
+ host_mapper_.AddRule("*", "127.0.0.1");
}
virtual void Initialize() {
@@ -51,6 +56,7 @@ class NetTestSuite : public TestSuite {
private:
scoped_ptr<MessageLoop> message_loop_;
+ net::ScopedHostMapper host_mapper_;
};
int main(int argc, char** argv) {
diff --git a/net/base/tcp_client_socket_unittest.cc b/net/base/tcp_client_socket_unittest.cc
index 062a9b9..34c0940 100644
--- a/net/base/tcp_client_socket_unittest.cc
+++ b/net/base/tcp_client_socket_unittest.cc
@@ -5,12 +5,21 @@
#include "base/platform_test.h"
#include "net/base/address_list.h"
#include "net/base/host_resolver.h"
+#include "net/base/host_resolver_unittest.h"
#include "net/base/net_errors.h"
#include "net/base/tcp_client_socket.h"
#include "net/base/test_completion_callback.h"
#include "testing/gtest/include/gtest/gtest.h"
class TCPClientSocketTest : public PlatformTest {
+ public:
+ TCPClientSocketTest() {
+ // TODO(darin): kill this exception once we have a way to test out the
+ // TCPClientSocket class using loopback connections.
+ host_mapper_.AddRule("www.google.com", "www.google.com");
+ }
+ private:
+ net::ScopedHostMapper host_mapper_;
};
diff --git a/net/http/http_network_layer_unittest.cc b/net/http/http_network_layer_unittest.cc
index ab59edc..316c91d 100644
--- a/net/http/http_network_layer_unittest.cc
+++ b/net/http/http_network_layer_unittest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "net/base/host_resolver_unittest.h"
#include "net/http/http_network_layer.h"
#include "net/http/http_transaction_unittest.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -9,6 +10,14 @@
namespace {
class HttpNetworkLayerTest : public testing::Test {
+ public:
+ HttpNetworkLayerTest() {
+ // TODO(darin): kill this exception once we have a way to test out the
+ // HttpNetworkLayer class using loopback connections.
+ host_mapper_.AddRule("www.google.com", "www.google.com");
+ }
+ private:
+ net::ScopedHostMapper host_mapper_;
};
} // namespace