diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
commit | 09911bf300f1a419907a9412154760efd0b7abc3 (patch) | |
tree | f131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/net/dns_master_unittest.cc | |
parent | 586acc5fe142f498261f52c66862fa417c3d52d2 (diff) | |
download | chromium_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.cc | 451 |
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 |