Home | History | Annotate | Download | only in dns
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "net/dns/host_cache.h"
      6 
      7 #include "base/format_macros.h"
      8 #include "base/stl_util.h"
      9 #include "base/strings/string_util.h"
     10 #include "base/strings/stringprintf.h"
     11 #include "net/base/net_errors.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 
     14 namespace net {
     15 
     16 namespace {
     17 
     18 const int kMaxCacheEntries = 10;
     19 
     20 // Builds a key for |hostname|, defaulting the address family to unspecified.
     21 HostCache::Key Key(const std::string& hostname) {
     22   return HostCache::Key(hostname, ADDRESS_FAMILY_UNSPECIFIED, 0);
     23 }
     24 
     25 }  // namespace
     26 
     27 TEST(HostCacheTest, Basic) {
     28   const base::TimeDelta kTTL = base::TimeDelta::FromSeconds(10);
     29 
     30   HostCache cache(kMaxCacheEntries);
     31 
     32   // Start at t=0.
     33   base::TimeTicks now;
     34 
     35   HostCache::Key key1 = Key("foobar.com");
     36   HostCache::Key key2 = Key("foobar2.com");
     37   HostCache::Entry entry = HostCache::Entry(OK, AddressList());
     38 
     39   EXPECT_EQ(0U, cache.size());
     40 
     41   // Add an entry for "foobar.com" at t=0.
     42   EXPECT_FALSE(cache.Lookup(key1, now));
     43   cache.Set(key1, entry, now, kTTL);
     44   EXPECT_TRUE(cache.Lookup(key1, now));
     45   EXPECT_TRUE(cache.Lookup(key1, now)->error == entry.error);
     46 
     47   EXPECT_EQ(1U, cache.size());
     48 
     49   // Advance to t=5.
     50   now += base::TimeDelta::FromSeconds(5);
     51 
     52   // Add an entry for "foobar2.com" at t=5.
     53   EXPECT_FALSE(cache.Lookup(key2, now));
     54   cache.Set(key2, entry, now, kTTL);
     55   EXPECT_TRUE(cache.Lookup(key2, now));
     56   EXPECT_EQ(2U, cache.size());
     57 
     58   // Advance to t=9
     59   now += base::TimeDelta::FromSeconds(4);
     60 
     61   // Verify that the entries we added are still retrievable, and usable.
     62   EXPECT_TRUE(cache.Lookup(key1, now));
     63   EXPECT_TRUE(cache.Lookup(key2, now));
     64   EXPECT_NE(cache.Lookup(key1, now), cache.Lookup(key2, now));
     65 
     66   // Advance to t=10; key is now expired.
     67   now += base::TimeDelta::FromSeconds(1);
     68 
     69   EXPECT_FALSE(cache.Lookup(key1, now));
     70   EXPECT_TRUE(cache.Lookup(key2, now));
     71 
     72   // Update key1, so it is no longer expired.
     73   cache.Set(key1, entry, now, kTTL);
     74   EXPECT_TRUE(cache.Lookup(key1, now));
     75   EXPECT_EQ(2U, cache.size());
     76 
     77   // Both entries should still be retrievable and usable.
     78   EXPECT_TRUE(cache.Lookup(key1, now));
     79   EXPECT_TRUE(cache.Lookup(key2, now));
     80 
     81   // Advance to t=20; both entries are now expired.
     82   now += base::TimeDelta::FromSeconds(10);
     83 
     84   EXPECT_FALSE(cache.Lookup(key1, now));
     85   EXPECT_FALSE(cache.Lookup(key2, now));
     86 }
     87 
     88 // Try caching entries for a failed resolve attempt -- since we set the TTL of
     89 // such entries to 0 it won't store, but it will kick out the previous result.
     90 TEST(HostCacheTest, NoCacheZeroTTL) {
     91   const base::TimeDelta kSuccessEntryTTL = base::TimeDelta::FromSeconds(10);
     92   const base::TimeDelta kFailureEntryTTL = base::TimeDelta::FromSeconds(0);
     93 
     94   HostCache cache(kMaxCacheEntries);
     95 
     96   // Set t=0.
     97   base::TimeTicks now;
     98 
     99   HostCache::Key key1 = Key("foobar.com");
    100   HostCache::Key key2 = Key("foobar2.com");
    101   HostCache::Entry entry = HostCache::Entry(OK, AddressList());
    102 
    103   EXPECT_FALSE(cache.Lookup(key1, now));
    104   cache.Set(key1, entry, now, kFailureEntryTTL);
    105   EXPECT_EQ(1U, cache.size());
    106 
    107   // We disallow use of negative entries.
    108   EXPECT_FALSE(cache.Lookup(key1, now));
    109 
    110   // Now overwrite with a valid entry, and then overwrite with negative entry
    111   // again -- the valid entry should be kicked out.
    112   cache.Set(key1, entry, now, kSuccessEntryTTL);
    113   EXPECT_TRUE(cache.Lookup(key1, now));
    114   cache.Set(key1, entry, now, kFailureEntryTTL);
    115   EXPECT_FALSE(cache.Lookup(key1, now));
    116 }
    117 
    118 // Try caching entries for a failed resolves for 10 seconds.
    119 TEST(HostCacheTest, CacheNegativeEntry) {
    120   const base::TimeDelta kFailureEntryTTL = base::TimeDelta::FromSeconds(10);
    121 
    122   HostCache cache(kMaxCacheEntries);
    123 
    124   // Start at t=0.
    125   base::TimeTicks now;
    126 
    127   HostCache::Key key1 = Key("foobar.com");
    128   HostCache::Key key2 = Key("foobar2.com");
    129   HostCache::Entry entry = HostCache::Entry(OK, AddressList());
    130 
    131   EXPECT_EQ(0U, cache.size());
    132 
    133   // Add an entry for "foobar.com" at t=0.
    134   EXPECT_FALSE(cache.Lookup(key1, now));
    135   cache.Set(key1, entry, now, kFailureEntryTTL);
    136   EXPECT_TRUE(cache.Lookup(key1, now));
    137   EXPECT_EQ(1U, cache.size());
    138 
    139   // Advance to t=5.
    140   now += base::TimeDelta::FromSeconds(5);
    141 
    142   // Add an entry for "foobar2.com" at t=5.
    143   EXPECT_FALSE(cache.Lookup(key2, now));
    144   cache.Set(key2, entry, now, kFailureEntryTTL);
    145   EXPECT_TRUE(cache.Lookup(key2, now));
    146   EXPECT_EQ(2U, cache.size());
    147 
    148   // Advance to t=9
    149   now += base::TimeDelta::FromSeconds(4);
    150 
    151   // Verify that the entries we added are still retrievable, and usable.
    152   EXPECT_TRUE(cache.Lookup(key1, now));
    153   EXPECT_TRUE(cache.Lookup(key2, now));
    154 
    155   // Advance to t=10; key1 is now expired.
    156   now += base::TimeDelta::FromSeconds(1);
    157 
    158   EXPECT_FALSE(cache.Lookup(key1, now));
    159   EXPECT_TRUE(cache.Lookup(key2, now));
    160 
    161   // Update key1, so it is no longer expired.
    162   cache.Set(key1, entry, now, kFailureEntryTTL);
    163   // Re-uses existing entry storage.
    164   EXPECT_TRUE(cache.Lookup(key1, now));
    165   EXPECT_EQ(2U, cache.size());
    166 
    167   // Both entries should still be retrievable and usable.
    168   EXPECT_TRUE(cache.Lookup(key1, now));
    169   EXPECT_TRUE(cache.Lookup(key2, now));
    170 
    171   // Advance to t=20; both entries are now expired.
    172   now += base::TimeDelta::FromSeconds(10);
    173 
    174   EXPECT_FALSE(cache.Lookup(key1, now));
    175   EXPECT_FALSE(cache.Lookup(key2, now));
    176 }
    177 
    178 // Tests that the same hostname can be duplicated in the cache, so long as
    179 // the address family differs.
    180 TEST(HostCacheTest, AddressFamilyIsPartOfKey) {
    181   const base::TimeDelta kSuccessEntryTTL = base::TimeDelta::FromSeconds(10);
    182 
    183   HostCache cache(kMaxCacheEntries);
    184 
    185   // t=0.
    186   base::TimeTicks now;
    187 
    188   HostCache::Key key1("foobar.com", ADDRESS_FAMILY_UNSPECIFIED, 0);
    189   HostCache::Key key2("foobar.com", ADDRESS_FAMILY_IPV4, 0);
    190   HostCache::Entry entry = HostCache::Entry(OK, AddressList());
    191 
    192   EXPECT_EQ(0U, cache.size());
    193 
    194   // Add an entry for ("foobar.com", UNSPECIFIED) at t=0.
    195   EXPECT_FALSE(cache.Lookup(key1, now));
    196   cache.Set(key1, entry, now, kSuccessEntryTTL);
    197   EXPECT_TRUE(cache.Lookup(key1, now));
    198   EXPECT_EQ(1U, cache.size());
    199 
    200   // Add an entry for ("foobar.com", IPV4_ONLY) at t=0.
    201   EXPECT_FALSE(cache.Lookup(key2, now));
    202   cache.Set(key2, entry, now, kSuccessEntryTTL);
    203   EXPECT_TRUE(cache.Lookup(key2, now));
    204   EXPECT_EQ(2U, cache.size());
    205 
    206   // Even though the hostnames were the same, we should have two unique
    207   // entries (because the address families differ).
    208   EXPECT_NE(cache.Lookup(key1, now), cache.Lookup(key2, now));
    209 }
    210 
    211 // Tests that the same hostname can be duplicated in the cache, so long as
    212 // the HostResolverFlags differ.
    213 TEST(HostCacheTest, HostResolverFlagsArePartOfKey) {
    214   const base::TimeDelta kTTL = base::TimeDelta::FromSeconds(10);
    215 
    216   HostCache cache(kMaxCacheEntries);
    217 
    218   // t=0.
    219   base::TimeTicks now;
    220 
    221   HostCache::Key key1("foobar.com", ADDRESS_FAMILY_IPV4, 0);
    222   HostCache::Key key2("foobar.com", ADDRESS_FAMILY_IPV4,
    223                       HOST_RESOLVER_CANONNAME);
    224   HostCache::Key key3("foobar.com", ADDRESS_FAMILY_IPV4,
    225                       HOST_RESOLVER_LOOPBACK_ONLY);
    226   HostCache::Entry entry = HostCache::Entry(OK, AddressList());
    227 
    228   EXPECT_EQ(0U, cache.size());
    229 
    230   // Add an entry for ("foobar.com", IPV4, NONE) at t=0.
    231   EXPECT_FALSE(cache.Lookup(key1, now));
    232   cache.Set(key1, entry, now, kTTL);
    233   EXPECT_TRUE(cache.Lookup(key1, now));
    234   EXPECT_EQ(1U, cache.size());
    235 
    236   // Add an entry for ("foobar.com", IPV4, CANONNAME) at t=0.
    237   EXPECT_FALSE(cache.Lookup(key2, now));
    238   cache.Set(key2, entry, now, kTTL);
    239   EXPECT_TRUE(cache.Lookup(key2, now));
    240   EXPECT_EQ(2U, cache.size());
    241 
    242   // Add an entry for ("foobar.com", IPV4, LOOPBACK_ONLY) at t=0.
    243   EXPECT_FALSE(cache.Lookup(key3, now));
    244   cache.Set(key3, entry, now, kTTL);
    245   EXPECT_TRUE(cache.Lookup(key3, now));
    246   EXPECT_EQ(3U, cache.size());
    247 
    248   // Even though the hostnames were the same, we should have two unique
    249   // entries (because the HostResolverFlags differ).
    250   EXPECT_NE(cache.Lookup(key1, now), cache.Lookup(key2, now));
    251   EXPECT_NE(cache.Lookup(key1, now), cache.Lookup(key3, now));
    252   EXPECT_NE(cache.Lookup(key2, now), cache.Lookup(key3, now));
    253 }
    254 
    255 TEST(HostCacheTest, NoCache) {
    256   // Disable caching.
    257   const base::TimeDelta kTTL = base::TimeDelta::FromSeconds(10);
    258 
    259   HostCache cache(0);
    260   EXPECT_TRUE(cache.caching_is_disabled());
    261 
    262   // Set t=0.
    263   base::TimeTicks now;
    264 
    265   HostCache::Entry entry = HostCache::Entry(OK, AddressList());
    266 
    267   // Lookup and Set should have no effect.
    268   EXPECT_FALSE(cache.Lookup(Key("foobar.com"),now));
    269   cache.Set(Key("foobar.com"), entry, now, kTTL);
    270   EXPECT_FALSE(cache.Lookup(Key("foobar.com"), now));
    271 
    272   EXPECT_EQ(0U, cache.size());
    273 }
    274 
    275 TEST(HostCacheTest, Clear) {
    276   const base::TimeDelta kTTL = base::TimeDelta::FromSeconds(10);
    277 
    278   HostCache cache(kMaxCacheEntries);
    279 
    280   // Set t=0.
    281   base::TimeTicks now;
    282 
    283   HostCache::Entry entry = HostCache::Entry(OK, AddressList());
    284 
    285   EXPECT_EQ(0u, cache.size());
    286 
    287   // Add three entries.
    288   cache.Set(Key("foobar1.com"), entry, now, kTTL);
    289   cache.Set(Key("foobar2.com"), entry, now, kTTL);
    290   cache.Set(Key("foobar3.com"), entry, now, kTTL);
    291 
    292   EXPECT_EQ(3u, cache.size());
    293 
    294   cache.clear();
    295 
    296   EXPECT_EQ(0u, cache.size());
    297 }
    298 
    299 // Tests the less than and equal operators for HostCache::Key work.
    300 TEST(HostCacheTest, KeyComparators) {
    301   struct {
    302     // Inputs.
    303     HostCache::Key key1;
    304     HostCache::Key key2;
    305 
    306     // Expectation.
    307     //   -1 means key1 is less than key2
    308     //    0 means key1 equals key2
    309     //    1 means key1 is greater than key2
    310     int expected_comparison;
    311   } tests[] = {
    312     {
    313       HostCache::Key("host1", ADDRESS_FAMILY_UNSPECIFIED, 0),
    314       HostCache::Key("host1", ADDRESS_FAMILY_UNSPECIFIED, 0),
    315       0
    316     },
    317     {
    318       HostCache::Key("host1", ADDRESS_FAMILY_IPV4, 0),
    319       HostCache::Key("host1", ADDRESS_FAMILY_UNSPECIFIED, 0),
    320       1
    321     },
    322     {
    323       HostCache::Key("host1", ADDRESS_FAMILY_UNSPECIFIED, 0),
    324       HostCache::Key("host1", ADDRESS_FAMILY_IPV4, 0),
    325       -1
    326     },
    327     {
    328       HostCache::Key("host1", ADDRESS_FAMILY_UNSPECIFIED, 0),
    329       HostCache::Key("host2", ADDRESS_FAMILY_UNSPECIFIED, 0),
    330       -1
    331     },
    332     {
    333       HostCache::Key("host1", ADDRESS_FAMILY_IPV4, 0),
    334       HostCache::Key("host2", ADDRESS_FAMILY_UNSPECIFIED, 0),
    335       1
    336     },
    337     {
    338       HostCache::Key("host1", ADDRESS_FAMILY_UNSPECIFIED, 0),
    339       HostCache::Key("host2", ADDRESS_FAMILY_IPV4, 0),
    340       -1
    341     },
    342     {
    343       HostCache::Key("host1", ADDRESS_FAMILY_UNSPECIFIED, 0),
    344       HostCache::Key("host1", ADDRESS_FAMILY_UNSPECIFIED,
    345                      HOST_RESOLVER_CANONNAME),
    346       -1
    347     },
    348     {
    349       HostCache::Key("host1", ADDRESS_FAMILY_UNSPECIFIED,
    350                      HOST_RESOLVER_CANONNAME),
    351       HostCache::Key("host1", ADDRESS_FAMILY_UNSPECIFIED, 0),
    352       1
    353     },
    354     {
    355       HostCache::Key("host1", ADDRESS_FAMILY_UNSPECIFIED,
    356                      HOST_RESOLVER_CANONNAME),
    357       HostCache::Key("host2", ADDRESS_FAMILY_UNSPECIFIED,
    358                      HOST_RESOLVER_CANONNAME),
    359       -1
    360     },
    361   };
    362 
    363   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    364     SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i));
    365 
    366     const HostCache::Key& key1 = tests[i].key1;
    367     const HostCache::Key& key2 = tests[i].key2;
    368 
    369     switch (tests[i].expected_comparison) {
    370       case -1:
    371         EXPECT_TRUE(key1 < key2);
    372         EXPECT_FALSE(key2 < key1);
    373         break;
    374       case 0:
    375         EXPECT_FALSE(key1 < key2);
    376         EXPECT_FALSE(key2 < key1);
    377         break;
    378       case 1:
    379         EXPECT_FALSE(key1 < key2);
    380         EXPECT_TRUE(key2 < key1);
    381         break;
    382       default:
    383         FAIL() << "Invalid expectation. Can be only -1, 0, 1";
    384     }
    385   }
    386 }
    387 
    388 }  // namespace net
    389