summaryrefslogtreecommitdiffstats
path: root/chrome/browser/net/dns_master_unittest.cc
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
commit09911bf300f1a419907a9412154760efd0b7abc3 (patch)
treef131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/net/dns_master_unittest.cc
parent586acc5fe142f498261f52c66862fa417c3d52d2 (diff)
downloadchromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/net/dns_master_unittest.cc')
-rw-r--r--chrome/browser/net/dns_master_unittest.cc451
1 files changed, 451 insertions, 0 deletions
diff --git a/chrome/browser/net/dns_master_unittest.cc b/chrome/browser/net/dns_master_unittest.cc
new file mode 100644
index 0000000..804af04
--- /dev/null
+++ b/chrome/browser/net/dns_master_unittest.cc
@@ -0,0 +1,451 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Multi-threaded tests of DnsMaster and DnsPrefetch slave functionality.
+
+#include <time.h>
+#include <ws2tcpip.h>
+#include <Wspiapi.h> // Needed for win2k compatibility
+
+#include <algorithm>
+#include <map>
+#include <sstream>
+#include <string>
+
+#include "base/spin_wait.h"
+#include "chrome/browser/net/dns_global.h"
+#include "chrome/browser/net/dns_host_info.h"
+#include "chrome/browser/net/dns_slave.h"
+#include "net/base/winsock_init.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+
+namespace {
+
+class DnsMasterTest : public testing::Test {
+};
+
+typedef chrome_browser_net::DnsMaster DnsMaster;
+typedef chrome_browser_net::DnsPrefetcherInit DnsPrefetcherInit;
+typedef chrome_browser_net::DnsHostInfo DnsHostInfo;
+typedef chrome_browser_net::NameList NameList;
+
+
+//------------------------------------------------------------------------------
+// Provide network function stubs to run tests offline (and avoid the variance
+// of real DNS lookups.
+//------------------------------------------------------------------------------
+
+static void __stdcall fake_free_addr_info(struct addrinfo* ai) {
+ // Kill off the dummy results.
+ EXPECT_TRUE(NULL != ai);
+ delete ai;
+}
+
+static int __stdcall fake_get_addr_info(const char* nodename,
+ const char* servname,
+ const struct addrinfo* hints,
+ struct addrinfo** result) {
+ static Lock lock;
+ int duration;
+ bool was_found;
+ std::string hostname(nodename);
+ // Dummy up *some* return results to pass along.
+ *result = new addrinfo;
+ EXPECT_TRUE(NULL != *result);
+ {
+ AutoLock autolock(lock);
+
+ static bool initialized = false;
+ typedef std::map<std::string, int> Latency;
+ static Latency latency;
+ static std::map<std::string, bool> found;
+ if (!initialized) {
+ initialized = true;
+ // List all known hostnames
+ latency["www.google.com"] = 50;
+ latency["gmail.google.com.com"] = 70;
+ latency["mail.google.com"] = 44;
+ latency["gmail.com"] = 63;
+
+ for (Latency::iterator it = latency.begin(); latency.end() != it; it++) {
+ found[it->first] = true;
+ }
+ } // End static initialization
+
+ was_found = found[hostname];
+
+ if (latency.end() != latency.find(hostname)) {
+ duration = latency[hostname];
+ } else {
+ duration = 500;
+ }
+ // Change latency to simulate cache warming (next latency will be short).
+ latency[hostname] = 1;
+ } // Release lock.
+
+ Sleep(duration);
+
+ return was_found ? 0 : WSAHOST_NOT_FOUND;
+}
+
+static void SetupNetworkInfrastructure() {
+ bool kUseFakeNetwork = true;
+ if (kUseFakeNetwork)
+ chrome_browser_net::SetAddrinfoCallbacks(fake_get_addr_info,
+ fake_free_addr_info);
+}
+
+//------------------------------------------------------------------------------
+// Provide a function to create unique (nonexistant) domains at *every* call.
+//------------------------------------------------------------------------------
+static std::string GetNonexistantDomain() {
+ static std::string postfix = ".google.com";
+ static std::string prefix = "www.";
+ static std::string mid = "datecount";
+
+ static int counter = 0; // Make sure its unique.
+ time_t number = time(NULL);
+ std::ostringstream result;
+ result << prefix << number << mid << ++counter << postfix;
+ return result.str();
+}
+
+//------------------------------------------------------------------------------
+// Use a blocking function to contrast results we get via async services.
+//------------------------------------------------------------------------------
+TimeDelta BlockingDnsLookup(const std::string& hostname) {
+ char* port = "80"; // I may need to get the real port
+ struct addrinfo* result = NULL;
+ Time start = Time::Now();
+
+ // Use the same underlying methods as dns_prefetch_slave does
+ chrome_browser_net::get_getaddrinfo()(hostname.c_str(), port,
+ NULL, &result);
+
+ TimeDelta duration = Time::Now() - start;
+
+ if (result) {
+ chrome_browser_net::get_freeaddrinfo()(result);
+ result = NULL;
+ }
+
+ return duration;
+}
+
+//------------------------------------------------------------------------------
+
+// First test to be sure the OS is caching lookups, which is the whole premise
+// of DNS prefetching.
+TEST(DnsMasterTest, OsCachesLookupsTest) {
+ SetupNetworkInfrastructure();
+ WinsockInit ws_init;
+
+ for (int i = 0; i < 5; i++) {
+ std::string badname;
+ badname = GetNonexistantDomain();
+ TimeDelta duration = BlockingDnsLookup(badname);
+ TimeDelta cached_duration = BlockingDnsLookup(badname);
+ EXPECT_TRUE(duration > cached_duration);
+ }
+}
+
+TEST(DnsMasterTest, StartupShutdownTest) {
+ DnsMaster testing_master(TimeDelta::FromMilliseconds(5000));
+
+ // With no threads, we should have no problem doing a shutdown.
+ EXPECT_TRUE(testing_master.ShutdownSlaves());
+}
+
+TEST(DnsMasterTest, BenefitLookupTest) {
+ SetupNetworkInfrastructure();
+ WinsockInit ws_init;
+ DnsPrefetcherInit dns_init(NULL); // Creates global service .
+ DnsMaster testing_master(TimeDelta::FromMilliseconds(5000));
+
+ std::string goog("www.google.com"),
+ goog2("gmail.google.com.com"),
+ goog3("mail.google.com"),
+ goog4("gmail.com");
+ DnsHostInfo goog_info, goog2_info, goog3_info, goog4_info;
+
+ // Simulate getting similar names from a network observer
+ goog_info.SetHostname(goog);
+ goog2_info.SetHostname(goog2);
+ goog3_info.SetHostname(goog3);
+ goog4_info.SetHostname(goog4);
+
+ goog_info.SetStartedState();
+ goog2_info.SetStartedState();
+ goog3_info.SetStartedState();
+ goog4_info.SetStartedState();
+
+ goog_info.SetFinishedState(true);
+ goog2_info.SetFinishedState(true);
+ goog3_info.SetFinishedState(true);
+ goog4_info.SetFinishedState(true);
+
+ NameList names;
+ names.insert(names.end(), goog);
+ names.insert(names.end(), goog2);
+ names.insert(names.end(), goog3);
+ names.insert(names.end(), goog4);
+
+ // First only cause a minimal set of threads to start up.
+ // Currently we actually start 4 threads when we get called with an array
+ testing_master.ResolveList(names);
+
+ // Wait for some resoultion for each google.
+ SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <=
+ testing_master.GetResolutionDuration(goog).InMilliseconds());
+ SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <=
+ testing_master.GetResolutionDuration(goog2).InMilliseconds());
+ SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <=
+ testing_master.GetResolutionDuration(goog3).InMilliseconds());
+ SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <=
+ testing_master.GetResolutionDuration(goog4).InMilliseconds());
+
+ EXPECT_EQ(std::min(names.size(),
+ 4u /* chrome_browser_net::DnsMaster::kSlaveCountMin */ ),
+ testing_master.running_slave_count());
+
+ EXPECT_TRUE(testing_master.WasFound(goog));
+ EXPECT_TRUE(testing_master.WasFound(goog2));
+ EXPECT_TRUE(testing_master.WasFound(goog3));
+ EXPECT_TRUE(testing_master.WasFound(goog4));
+
+ // With the mock DNS, each of these should have taken some time, and hence
+ // shown a benefit (i.e., prefetch cost more than network access time).
+
+ // Simulate actual navigation, and acrue the benefit for "helping" the DNS
+ // part of the navigation.
+ EXPECT_TRUE(testing_master.AcruePrefetchBenefits(&goog_info));
+ EXPECT_TRUE(testing_master.AcruePrefetchBenefits(&goog2_info));
+ EXPECT_TRUE(testing_master.AcruePrefetchBenefits(&goog3_info));
+ EXPECT_TRUE(testing_master.AcruePrefetchBenefits(&goog4_info));
+
+ // Benefits can ONLY be reported once (for the first navigation).
+ EXPECT_FALSE(testing_master.AcruePrefetchBenefits(&goog_info));
+ EXPECT_FALSE(testing_master.AcruePrefetchBenefits(&goog2_info));
+ EXPECT_FALSE(testing_master.AcruePrefetchBenefits(&goog3_info));
+ EXPECT_FALSE(testing_master.AcruePrefetchBenefits(&goog4_info));
+
+ // Ensure a clean shutdown.
+ EXPECT_TRUE(testing_master.ShutdownSlaves());
+}
+
+TEST(DnsMasterTest, DISABLED_SingleSlaveLookupTest) {
+ SetupNetworkInfrastructure();
+ WinsockInit ws_init;
+ DnsPrefetcherInit dns_init(NULL); // Creates global service.
+ DnsMaster testing_master(TimeDelta::FromMilliseconds(5000));
+
+ std::string goog("www.google.com"),
+ goog2("gmail.google.com.com"),
+ goog3("mail.google.com"),
+ goog4("gmail.com");
+ std::string bad1(GetNonexistantDomain()),
+ bad2(GetNonexistantDomain());
+
+ // Warm up local OS cache.
+ BlockingDnsLookup(goog);
+
+ NameList names;
+ names.insert(names.end(), goog);
+ names.insert(names.end(), bad1);
+ names.insert(names.end(), bad2);
+
+ // First only cause a single thread to start up
+ testing_master.ResolveList(names);
+
+ // Wait for some resoultion for google.
+ SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <=
+ testing_master.GetResolutionDuration(goog).InMilliseconds());
+
+ EXPECT_TRUE(testing_master.WasFound(goog));
+ EXPECT_FALSE(testing_master.WasFound(bad1));
+ EXPECT_FALSE(testing_master.WasFound(bad2));
+ // Verify the reason it is not found is that it is still being proceessed.
+ // Negative time mean no resolution yet.
+ EXPECT_GT(0, testing_master.GetResolutionDuration(bad2).InMilliseconds());
+
+ // Spin long enough that we *do* find the resolution of bad2.
+ SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <=
+ testing_master.GetResolutionDuration(bad2).InMilliseconds());
+
+ // Verify both fictitious names are resolved by now.
+ // Typical random name takes about 20-30 ms
+ EXPECT_LT(0, testing_master.GetResolutionDuration(bad1).InMilliseconds());
+ EXPECT_LT(0, testing_master.GetResolutionDuration(bad2).InMilliseconds());
+ EXPECT_FALSE(testing_master.WasFound(bad1));
+ EXPECT_FALSE(testing_master.WasFound(bad2));
+
+ EXPECT_EQ(1, testing_master.running_slave_count());
+
+ // With just one thread (doing nothing now), ensure a clean shutdown.
+ EXPECT_TRUE(testing_master.ShutdownSlaves());
+}
+
+TEST(DnsMasterTest, DISABLED_MultiThreadedLookupTest) {
+ SetupNetworkInfrastructure();
+ WinsockInit ws_init;
+ DnsMaster testing_master(TimeDelta::FromSeconds(30));
+ DnsPrefetcherInit dns_init(NULL);
+
+ std::string goog("www.google.com"),
+ goog2("gmail.google.com.com"),
+ goog3("mail.google.com"),
+ goog4("gmail.com");
+ std::string bad1(GetNonexistantDomain()),
+ bad2(GetNonexistantDomain());
+
+ NameList names;
+ names.insert(names.end(), goog);
+ names.insert(names.end(), goog3);
+ names.insert(names.end(), bad1);
+ names.insert(names.end(), goog2);
+ names.insert(names.end(), bad2);
+ names.insert(names.end(), goog4);
+ names.insert(names.end(), goog);
+
+ // Warm up the *OS* cache for all the goog domains.
+ BlockingDnsLookup(goog);
+ BlockingDnsLookup(goog2);
+ BlockingDnsLookup(goog3);
+ BlockingDnsLookup(goog4);
+
+ // Get all 8 threads running by calling many times before queue is handled.
+ for (int i = 0; i < 10; i++) {
+ testing_master.ResolveList(names);
+ }
+
+ Sleep(10); // Allow time for async DNS to get answers.
+
+ EXPECT_TRUE(testing_master.WasFound(goog));
+ EXPECT_TRUE(testing_master.WasFound(goog3));
+ EXPECT_TRUE(testing_master.WasFound(goog2));
+ EXPECT_TRUE(testing_master.WasFound(goog4));
+ EXPECT_FALSE(testing_master.WasFound(bad1));
+ EXPECT_FALSE(testing_master.WasFound(bad2));
+
+ EXPECT_EQ(8, testing_master.running_slave_count());
+
+ EXPECT_TRUE(testing_master.ShutdownSlaves());
+}
+
+TEST(DnsMasterTest, DISABLED_MultiThreadedSpeedupTest) {
+ SetupNetworkInfrastructure();
+ WinsockInit ws_init;
+ DnsMaster testing_master(TimeDelta::FromSeconds(30));
+ DnsPrefetcherInit dns_init(NULL);
+
+ std::string goog("www.google.com"),
+ goog2("gmail.google.com.com"),
+ goog3("mail.google.com"),
+ goog4("gmail.com");
+ std::string bad1(GetNonexistantDomain()),
+ bad2(GetNonexistantDomain()),
+ bad3(GetNonexistantDomain()),
+ bad4(GetNonexistantDomain());
+
+ NameList names;
+ names.insert(names.end(), goog);
+ names.insert(names.end(), bad1);
+ names.insert(names.end(), bad2);
+ names.insert(names.end(), goog3);
+ names.insert(names.end(), goog2);
+ names.insert(names.end(), bad3);
+ names.insert(names.end(), bad4);
+ names.insert(names.end(), goog4);
+
+ // First cause a lookup using a single thread.
+ testing_master.ResolveList(names);
+
+ // Wait for some resoultion for google.
+ SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <=
+ testing_master.GetResolutionDuration(goog).InMilliseconds());
+
+ EXPECT_TRUE(testing_master.WasFound(goog));
+ EXPECT_FALSE(testing_master.WasFound(bad1));
+ EXPECT_FALSE(testing_master.WasFound(bad2));
+ // ...and due to delay in geting resolution of bad names, the single slave
+ // thread won't have time to finish the list.
+ EXPECT_FALSE(testing_master.WasFound(goog3));
+ EXPECT_FALSE(testing_master.WasFound(goog2));
+ EXPECT_FALSE(testing_master.WasFound(goog4));
+
+ EXPECT_EQ(1, testing_master.running_slave_count());
+
+ // Get all 8 threads running by calling many times before queue is handled.
+ names.clear();
+ for (int i = 0; i < 10; i++)
+ testing_master.Resolve(GetNonexistantDomain());
+
+ // Wait long enough for all the goog's to be resolved.
+ // They should all take about the same time, and run in parallel.
+ SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <=
+ testing_master.GetResolutionDuration(goog2).InMilliseconds());
+ SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <=
+ testing_master.GetResolutionDuration(goog3).InMilliseconds());
+ SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <=
+ testing_master.GetResolutionDuration(goog4).InMilliseconds());
+
+ EXPECT_TRUE(testing_master.WasFound(goog3));
+ EXPECT_TRUE(testing_master.WasFound(goog2));
+ EXPECT_TRUE(testing_master.WasFound(goog4));
+
+ EXPECT_FALSE(testing_master.WasFound(bad1));
+ EXPECT_FALSE(testing_master.WasFound(bad2)); // Perhaps not even decided.
+
+ // Queue durations should be distinct from when 1 slave was working.
+ EXPECT_GT(testing_master.GetQueueDuration(goog3).InMilliseconds(),
+ testing_master.GetQueueDuration(goog).InMilliseconds());
+ EXPECT_GT(testing_master.GetQueueDuration(goog4).InMilliseconds(),
+ testing_master.GetQueueDuration(goog).InMilliseconds());
+
+ // Give bad names a chance to be determined as unresolved.
+ SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <=
+ testing_master.GetResolutionDuration(bad1).InMilliseconds());
+ SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 <=
+ testing_master.GetResolutionDuration(bad2).InMilliseconds());
+
+
+ // Well known names should resolve faster than bad names.
+ EXPECT_GE(testing_master.GetResolutionDuration(bad1).InMilliseconds(),
+ testing_master.GetResolutionDuration(goog).InMilliseconds());
+
+ EXPECT_GE(testing_master.GetResolutionDuration(bad2).InMilliseconds(),
+ testing_master.GetResolutionDuration(goog4).InMilliseconds());
+
+ EXPECT_EQ(8, testing_master.running_slave_count());
+
+ EXPECT_TRUE(testing_master.ShutdownSlaves());
+}
+
+} // namespace