Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2010 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/base/host_cache.h"
      6 
      7 #include "base/format_macros.h"
      8 #include "base/stl_util-inl.h"
      9 #include "base/string_util.h"
     10 #include "base/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 const int kMaxCacheEntries = 10;
     18 
     19 const base::TimeDelta kSuccessEntryTTL = base::TimeDelta::FromSeconds(10);
     20 const base::TimeDelta kFailureEntryTTL = base::TimeDelta::FromSeconds(0);
     21 
     22 // Builds a key for |hostname|, defaulting the address family to unspecified.
     23 HostCache::Key Key(const std::string& hostname) {
     24   return HostCache::Key(hostname, ADDRESS_FAMILY_UNSPECIFIED, 0);
     25 }
     26 
     27 }  // namespace
     28 
     29 TEST(HostCacheTest, Basic) {
     30   HostCache cache(kMaxCacheEntries, kSuccessEntryTTL, kFailureEntryTTL);
     31 
     32   // Start at t=0.
     33   base::TimeTicks now;
     34 
     35   const HostCache::Entry* entry1 = NULL;  // Entry for foobar.com.
     36   const HostCache::Entry* entry2 = NULL;  // Entry for foobar2.com.
     37 
     38   EXPECT_EQ(0U, cache.size());
     39 
     40   // Add an entry for "foobar.com" at t=0.
     41   EXPECT_TRUE(cache.Lookup(Key("foobar.com"), base::TimeTicks()) == NULL);
     42   cache.Set(Key("foobar.com"), OK, AddressList(), now);
     43   entry1 = cache.Lookup(Key("foobar.com"), base::TimeTicks());
     44   EXPECT_FALSE(entry1 == NULL);
     45   EXPECT_EQ(1U, cache.size());
     46 
     47   // Advance to t=5.
     48   now += base::TimeDelta::FromSeconds(5);
     49 
     50   // Add an entry for "foobar2.com" at t=5.
     51   EXPECT_TRUE(cache.Lookup(Key("foobar2.com"), base::TimeTicks()) == NULL);
     52   cache.Set(Key("foobar2.com"), OK, AddressList(), now);
     53   entry2 = cache.Lookup(Key("foobar2.com"), base::TimeTicks());
     54   EXPECT_FALSE(NULL == entry1);
     55   EXPECT_EQ(2U, cache.size());
     56 
     57   // Advance to t=9
     58   now += base::TimeDelta::FromSeconds(4);
     59 
     60   // Verify that the entries we added are still retrievable, and usable.
     61   EXPECT_EQ(entry1, cache.Lookup(Key("foobar.com"), now));
     62   EXPECT_EQ(entry2, cache.Lookup(Key("foobar2.com"), now));
     63 
     64   // Advance to t=10; entry1 is now expired.
     65   now += base::TimeDelta::FromSeconds(1);
     66 
     67   EXPECT_TRUE(cache.Lookup(Key("foobar.com"), now) == NULL);
     68   EXPECT_EQ(entry2, cache.Lookup(Key("foobar2.com"), now));
     69 
     70   // Update entry1, so it is no longer expired.
     71   cache.Set(Key("foobar.com"), OK, AddressList(), now);
     72   // Re-uses existing entry storage.
     73   EXPECT_EQ(entry1, cache.Lookup(Key("foobar.com"), now));
     74   EXPECT_EQ(2U, cache.size());
     75 
     76   // Both entries should still be retrievable and usable.
     77   EXPECT_EQ(entry1, cache.Lookup(Key("foobar.com"), now));
     78   EXPECT_EQ(entry2, cache.Lookup(Key("foobar2.com"), now));
     79 
     80   // Advance to t=20; both entries are now expired.
     81   now += base::TimeDelta::FromSeconds(10);
     82 
     83   EXPECT_TRUE(cache.Lookup(Key("foobar.com"), now) == NULL);
     84   EXPECT_TRUE(cache.Lookup(Key("foobar2.com"), now) == NULL);
     85 }
     86 
     87 // Try caching entries for a failed resolve attempt -- since we set
     88 // the TTL of such entries to 0 it won't work.
     89 TEST(HostCacheTest, NoCacheNegative) {
     90   HostCache cache(kMaxCacheEntries, kSuccessEntryTTL, kFailureEntryTTL);
     91 
     92   // Set t=0.
     93   base::TimeTicks now;
     94 
     95   EXPECT_TRUE(cache.Lookup(Key("foobar.com"), base::TimeTicks()) == NULL);
     96   cache.Set(Key("foobar.com"), ERR_NAME_NOT_RESOLVED, AddressList(), now);
     97   EXPECT_EQ(1U, cache.size());
     98 
     99   // We disallow use of negative entries.
    100   EXPECT_TRUE(cache.Lookup(Key("foobar.com"), now) == NULL);
    101 
    102   // Now overwrite with a valid entry, and then overwrite with negative entry
    103   // again -- the valid entry should be kicked out.
    104   cache.Set(Key("foobar.com"), OK, AddressList(), now);
    105   EXPECT_FALSE(cache.Lookup(Key("foobar.com"), now) == NULL);
    106   cache.Set(Key("foobar.com"), ERR_NAME_NOT_RESOLVED, AddressList(), now);
    107   EXPECT_TRUE(cache.Lookup(Key("foobar.com"), now) == NULL);
    108 }
    109 
    110 // Try caching entries for a failed resolves for 10 seconds.
    111 TEST(HostCacheTest, CacheNegativeEntry) {
    112   HostCache cache(kMaxCacheEntries,
    113                   base::TimeDelta::FromSeconds(0), // success entry TTL.
    114                   base::TimeDelta::FromSeconds(10)); // failure entry TTL.
    115 
    116   // Start at t=0.
    117   base::TimeTicks now;
    118 
    119   const HostCache::Entry* entry1 = NULL;  // Entry for foobar.com.
    120   const HostCache::Entry* entry2 = NULL;  // Entry for foobar2.com.
    121 
    122   EXPECT_EQ(0U, cache.size());
    123 
    124   // Add an entry for "foobar.com" at t=0.
    125   EXPECT_TRUE(cache.Lookup(Key("foobar.com"), base::TimeTicks()) == NULL);
    126   cache.Set(Key("foobar.com"), ERR_NAME_NOT_RESOLVED, AddressList(), now);
    127   entry1 = cache.Lookup(Key("foobar.com"), base::TimeTicks());
    128   EXPECT_FALSE(entry1 == NULL);
    129   EXPECT_EQ(1U, cache.size());
    130 
    131   // Advance to t=5.
    132   now += base::TimeDelta::FromSeconds(5);
    133 
    134   // Add an entry for "foobar2.com" at t=5.
    135   EXPECT_TRUE(cache.Lookup(Key("foobar2.com"), base::TimeTicks()) == NULL);
    136   cache.Set(Key("foobar2.com"), ERR_NAME_NOT_RESOLVED, AddressList(), now);
    137   entry2 = cache.Lookup(Key("foobar2.com"), base::TimeTicks());
    138   EXPECT_FALSE(NULL == entry1);
    139   EXPECT_EQ(2U, cache.size());
    140 
    141   // Advance to t=9
    142   now += base::TimeDelta::FromSeconds(4);
    143 
    144   // Verify that the entries we added are still retrievable, and usable.
    145   EXPECT_EQ(entry1, cache.Lookup(Key("foobar.com"), now));
    146   EXPECT_EQ(entry2, cache.Lookup(Key("foobar2.com"), now));
    147 
    148   // Advance to t=10; entry1 is now expired.
    149   now += base::TimeDelta::FromSeconds(1);
    150 
    151   EXPECT_TRUE(cache.Lookup(Key("foobar.com"), now) == NULL);
    152   EXPECT_EQ(entry2, cache.Lookup(Key("foobar2.com"), now));
    153 
    154   // Update entry1, so it is no longer expired.
    155   cache.Set(Key("foobar.com"), ERR_NAME_NOT_RESOLVED, AddressList(), now);
    156   // Re-uses existing entry storage.
    157   EXPECT_EQ(entry1, cache.Lookup(Key("foobar.com"), now));
    158   EXPECT_EQ(2U, cache.size());
    159 
    160   // Both entries should still be retrievable and usable.
    161   EXPECT_EQ(entry1, cache.Lookup(Key("foobar.com"), now));
    162   EXPECT_EQ(entry2, cache.Lookup(Key("foobar2.com"), now));
    163 
    164   // Advance to t=20; both entries are now expired.
    165   now += base::TimeDelta::FromSeconds(10);
    166 
    167   EXPECT_TRUE(cache.Lookup(Key("foobar.com"), now) == NULL);
    168   EXPECT_TRUE(cache.Lookup(Key("foobar2.com"), now) == NULL);
    169 }
    170 
    171 TEST(HostCacheTest, Compact) {
    172   // Initial entries limit is big enough to accomadate everything we add.
    173   HostCache cache(kMaxCacheEntries, kSuccessEntryTTL, kFailureEntryTTL);
    174 
    175   EXPECT_EQ(0U, cache.size());
    176 
    177   // t=10
    178   base::TimeTicks now = base::TimeTicks() + base::TimeDelta::FromSeconds(10);
    179 
    180   // Add five valid entries at t=10.
    181   for (int i = 0; i < 5; ++i) {
    182     std::string hostname = base::StringPrintf("valid%d", i);
    183     cache.Set(Key(hostname), OK, AddressList(), now);
    184   }
    185   EXPECT_EQ(5U, cache.size());
    186 
    187   // Add 3 expired entries at t=0.
    188   for (int i = 0; i < 3; ++i) {
    189     std::string hostname = base::StringPrintf("expired%d", i);
    190     base::TimeTicks t = now - base::TimeDelta::FromSeconds(10);
    191     cache.Set(Key(hostname), OK, AddressList(), t);
    192   }
    193   EXPECT_EQ(8U, cache.size());
    194 
    195   // Add 2 negative entries at t=10
    196   for (int i = 0; i < 2; ++i) {
    197     std::string hostname = base::StringPrintf("negative%d", i);
    198     cache.Set(Key(hostname), ERR_NAME_NOT_RESOLVED, AddressList(), now);
    199   }
    200   EXPECT_EQ(10U, cache.size());
    201 
    202   EXPECT_TRUE(ContainsKey(cache.entries_, Key("valid0")));
    203   EXPECT_TRUE(ContainsKey(cache.entries_, Key("valid1")));
    204   EXPECT_TRUE(ContainsKey(cache.entries_, Key("valid2")));
    205   EXPECT_TRUE(ContainsKey(cache.entries_, Key("valid3")));
    206   EXPECT_TRUE(ContainsKey(cache.entries_, Key("valid4")));
    207   EXPECT_TRUE(ContainsKey(cache.entries_, Key("expired0")));
    208   EXPECT_TRUE(ContainsKey(cache.entries_, Key("expired1")));
    209   EXPECT_TRUE(ContainsKey(cache.entries_, Key("expired2")));
    210   EXPECT_TRUE(ContainsKey(cache.entries_, Key("negative0")));
    211   EXPECT_TRUE(ContainsKey(cache.entries_, Key("negative1")));
    212 
    213   // Shrink the max constraints bound and compact. We expect the "negative"
    214   // and "expired" entries to have been dropped.
    215   cache.max_entries_ = 5;
    216   cache.Compact(now, NULL);
    217   EXPECT_EQ(5U, cache.entries_.size());
    218 
    219   EXPECT_TRUE(ContainsKey(cache.entries_, Key("valid0")));
    220   EXPECT_TRUE(ContainsKey(cache.entries_, Key("valid1")));
    221   EXPECT_TRUE(ContainsKey(cache.entries_, Key("valid2")));
    222   EXPECT_TRUE(ContainsKey(cache.entries_, Key("valid3")));
    223   EXPECT_TRUE(ContainsKey(cache.entries_, Key("valid4")));
    224   EXPECT_FALSE(ContainsKey(cache.entries_, Key("expired0")));
    225   EXPECT_FALSE(ContainsKey(cache.entries_, Key("expired1")));
    226   EXPECT_FALSE(ContainsKey(cache.entries_, Key("expired2")));
    227   EXPECT_FALSE(ContainsKey(cache.entries_, Key("negative0")));
    228   EXPECT_FALSE(ContainsKey(cache.entries_, Key("negative1")));
    229 
    230   // Shrink further -- this time the compact will start dropping valid entries
    231   // to make space.
    232   cache.max_entries_ = 3;
    233   cache.Compact(now, NULL);
    234   EXPECT_EQ(3U, cache.size());
    235 }
    236 
    237 // Add entries while the cache is at capacity, causing evictions.
    238 TEST(HostCacheTest, SetWithCompact) {
    239   HostCache cache(3, kSuccessEntryTTL, kFailureEntryTTL);
    240 
    241   // t=10
    242   base::TimeTicks now = base::TimeTicks() + kSuccessEntryTTL;
    243 
    244   cache.Set(Key("host1"), OK, AddressList(), now);
    245   cache.Set(Key("host2"), OK, AddressList(), now);
    246   cache.Set(Key("expired"), OK, AddressList(), now - kSuccessEntryTTL);
    247 
    248   EXPECT_EQ(3U, cache.size());
    249 
    250   // Should all be retrievable except "expired".
    251   EXPECT_FALSE(NULL == cache.Lookup(Key("host1"), now));
    252   EXPECT_FALSE(NULL == cache.Lookup(Key("host2"), now));
    253   EXPECT_TRUE(NULL == cache.Lookup(Key("expired"), now));
    254 
    255   // Adding the fourth entry will cause "expired" to be evicted.
    256   cache.Set(Key("host3"), OK, AddressList(), now);
    257   EXPECT_EQ(3U, cache.size());
    258   EXPECT_TRUE(cache.Lookup(Key("expired"), now) == NULL);
    259   EXPECT_FALSE(cache.Lookup(Key("host1"), now) == NULL);
    260   EXPECT_FALSE(cache.Lookup(Key("host2"), now) == NULL);
    261   EXPECT_FALSE(cache.Lookup(Key("host3"), now) == NULL);
    262 
    263   // Add two more entries. Something should be evicted, however "host5"
    264   // should definitely be in there (since it was last inserted).
    265   cache.Set(Key("host4"), OK, AddressList(), now);
    266   EXPECT_EQ(3U, cache.size());
    267   cache.Set(Key("host5"), OK, AddressList(), now);
    268   EXPECT_EQ(3U, cache.size());
    269   EXPECT_FALSE(cache.Lookup(Key("host5"), now) == NULL);
    270 }
    271 
    272 // Tests that the same hostname can be duplicated in the cache, so long as
    273 // the address family differs.
    274 TEST(HostCacheTest, AddressFamilyIsPartOfKey) {
    275   HostCache cache(kMaxCacheEntries, kSuccessEntryTTL, kFailureEntryTTL);
    276 
    277   // t=0.
    278   base::TimeTicks now;
    279 
    280   HostCache::Key key1("foobar.com", ADDRESS_FAMILY_UNSPECIFIED, 0);
    281   HostCache::Key key2("foobar.com", ADDRESS_FAMILY_IPV4, 0);
    282 
    283   const HostCache::Entry* entry1 = NULL;  // Entry for key1
    284   const HostCache::Entry* entry2 = NULL;  // Entry for key2
    285 
    286   EXPECT_EQ(0U, cache.size());
    287 
    288   // Add an entry for ("foobar.com", UNSPECIFIED) at t=0.
    289   EXPECT_TRUE(cache.Lookup(key1, base::TimeTicks()) == NULL);
    290   cache.Set(key1, OK, AddressList(), now);
    291   entry1 = cache.Lookup(key1, base::TimeTicks());
    292   EXPECT_FALSE(entry1 == NULL);
    293   EXPECT_EQ(1U, cache.size());
    294 
    295   // Add an entry for ("foobar.com", IPV4_ONLY) at t=0.
    296   EXPECT_TRUE(cache.Lookup(key2, base::TimeTicks()) == NULL);
    297   cache.Set(key2, OK, AddressList(), now);
    298   entry2 = cache.Lookup(key2, base::TimeTicks());
    299   EXPECT_FALSE(entry2 == NULL);
    300   EXPECT_EQ(2U, cache.size());
    301 
    302   // Even though the hostnames were the same, we should have two unique
    303   // entries (because the address families differ).
    304   EXPECT_NE(entry1, entry2);
    305 }
    306 
    307 // Tests that the same hostname can be duplicated in the cache, so long as
    308 // the HostResolverFlags differ.
    309 TEST(HostCacheTest, HostResolverFlagsArePartOfKey) {
    310   HostCache cache(kMaxCacheEntries, kSuccessEntryTTL, kFailureEntryTTL);
    311 
    312   // t=0.
    313   base::TimeTicks now;
    314 
    315   HostCache::Key key1("foobar.com", ADDRESS_FAMILY_IPV4, 0);
    316   HostCache::Key key2("foobar.com", ADDRESS_FAMILY_IPV4,
    317                       HOST_RESOLVER_CANONNAME);
    318   HostCache::Key key3("foobar.com", ADDRESS_FAMILY_IPV4,
    319                       HOST_RESOLVER_LOOPBACK_ONLY);
    320 
    321   const HostCache::Entry* entry1 = NULL;  // Entry for key1
    322   const HostCache::Entry* entry2 = NULL;  // Entry for key2
    323   const HostCache::Entry* entry3 = NULL;  // Entry for key3
    324 
    325   EXPECT_EQ(0U, cache.size());
    326 
    327   // Add an entry for ("foobar.com", IPV4, NONE) at t=0.
    328   EXPECT_TRUE(cache.Lookup(key1, base::TimeTicks()) == NULL);
    329   cache.Set(key1, OK, AddressList(), now);
    330   entry1 = cache.Lookup(key1, base::TimeTicks());
    331   EXPECT_FALSE(entry1 == NULL);
    332   EXPECT_EQ(1U, cache.size());
    333 
    334   // Add an entry for ("foobar.com", IPV4, CANONNAME) at t=0.
    335   EXPECT_TRUE(cache.Lookup(key2, base::TimeTicks()) == NULL);
    336   cache.Set(key2, OK, AddressList(), now);
    337   entry2 = cache.Lookup(key2, base::TimeTicks());
    338   EXPECT_FALSE(entry2 == NULL);
    339   EXPECT_EQ(2U, cache.size());
    340 
    341   // Add an entry for ("foobar.com", IPV4, LOOPBACK_ONLY) at t=0.
    342   EXPECT_TRUE(cache.Lookup(key3, base::TimeTicks()) == NULL);
    343   cache.Set(key3, OK, AddressList(), now);
    344   entry3 = cache.Lookup(key3, base::TimeTicks());
    345   EXPECT_FALSE(entry3 == NULL);
    346   EXPECT_EQ(3U, cache.size());
    347 
    348   // Even though the hostnames were the same, we should have two unique
    349   // entries (because the HostResolverFlags differ).
    350   EXPECT_NE(entry1, entry2);
    351   EXPECT_NE(entry1, entry3);
    352   EXPECT_NE(entry2, entry3);
    353 }
    354 
    355 TEST(HostCacheTest, NoCache) {
    356   // Disable caching.
    357   HostCache cache(0, kSuccessEntryTTL, kFailureEntryTTL);
    358   EXPECT_TRUE(cache.caching_is_disabled());
    359 
    360   // Set t=0.
    361   base::TimeTicks now;
    362 
    363   // Lookup and Set should have no effect.
    364   EXPECT_TRUE(cache.Lookup(Key("foobar.com"), base::TimeTicks()) == NULL);
    365   cache.Set(Key("foobar.com"), OK, AddressList(), now);
    366   EXPECT_TRUE(cache.Lookup(Key("foobar.com"), base::TimeTicks()) == NULL);
    367 
    368   EXPECT_EQ(0U, cache.size());
    369 }
    370 
    371 TEST(HostCacheTest, Clear) {
    372   HostCache cache(kMaxCacheEntries, kSuccessEntryTTL, kFailureEntryTTL);
    373 
    374   // Set t=0.
    375   base::TimeTicks now;
    376 
    377   EXPECT_EQ(0u, cache.size());
    378 
    379   // Add three entries.
    380   cache.Set(Key("foobar1.com"), OK, AddressList(), now);
    381   cache.Set(Key("foobar2.com"), OK, AddressList(), now);
    382   cache.Set(Key("foobar3.com"), OK, AddressList(), now);
    383 
    384   EXPECT_EQ(3u, cache.size());
    385 
    386   cache.clear();
    387 
    388   EXPECT_EQ(0u, cache.size());
    389 }
    390 
    391 // Tests the less than and equal operators for HostCache::Key work.
    392 TEST(HostCacheTest, KeyComparators) {
    393   struct {
    394     // Inputs.
    395     HostCache::Key key1;
    396     HostCache::Key key2;
    397 
    398     // Expectation.
    399     //   -1 means key1 is less than key2
    400     //    0 means key1 equals key2
    401     //    1 means key1 is greater than key2
    402     int expected_comparison;
    403   } tests[] = {
    404     {
    405       HostCache::Key("host1", ADDRESS_FAMILY_UNSPECIFIED, 0),
    406       HostCache::Key("host1", ADDRESS_FAMILY_UNSPECIFIED, 0),
    407       0
    408     },
    409     {
    410       HostCache::Key("host1", ADDRESS_FAMILY_IPV4, 0),
    411       HostCache::Key("host1", ADDRESS_FAMILY_UNSPECIFIED, 0),
    412       1
    413     },
    414     {
    415       HostCache::Key("host1", ADDRESS_FAMILY_UNSPECIFIED, 0),
    416       HostCache::Key("host1", ADDRESS_FAMILY_IPV4, 0),
    417       -1
    418     },
    419     {
    420       HostCache::Key("host1", ADDRESS_FAMILY_UNSPECIFIED, 0),
    421       HostCache::Key("host2", ADDRESS_FAMILY_UNSPECIFIED, 0),
    422       -1
    423     },
    424     {
    425       HostCache::Key("host1", ADDRESS_FAMILY_IPV4, 0),
    426       HostCache::Key("host2", ADDRESS_FAMILY_UNSPECIFIED, 0),
    427       1
    428     },
    429     {
    430       HostCache::Key("host1", ADDRESS_FAMILY_UNSPECIFIED, 0),
    431       HostCache::Key("host2", ADDRESS_FAMILY_IPV4, 0),
    432       -1
    433     },
    434         {
    435       HostCache::Key("host1", ADDRESS_FAMILY_UNSPECIFIED, 0),
    436       HostCache::Key("host1", ADDRESS_FAMILY_UNSPECIFIED,
    437                      HOST_RESOLVER_CANONNAME),
    438       -1
    439     },
    440     {
    441       HostCache::Key("host1", ADDRESS_FAMILY_UNSPECIFIED,
    442                      HOST_RESOLVER_CANONNAME),
    443       HostCache::Key("host1", ADDRESS_FAMILY_UNSPECIFIED, 0),
    444       1
    445     },
    446     {
    447       HostCache::Key("host1", ADDRESS_FAMILY_UNSPECIFIED,
    448                      HOST_RESOLVER_CANONNAME),
    449       HostCache::Key("host2", ADDRESS_FAMILY_UNSPECIFIED,
    450                      HOST_RESOLVER_CANONNAME),
    451       -1
    452     },
    453   };
    454 
    455   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    456     SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i));
    457 
    458     const HostCache::Key& key1 = tests[i].key1;
    459     const HostCache::Key& key2 = tests[i].key2;
    460 
    461     switch (tests[i].expected_comparison) {
    462       case -1:
    463         EXPECT_TRUE(key1 < key2);
    464         EXPECT_FALSE(key2 < key1);
    465         EXPECT_FALSE(key2 == key1);
    466         break;
    467       case 0:
    468         EXPECT_FALSE(key1 < key2);
    469         EXPECT_FALSE(key2 < key1);
    470         EXPECT_TRUE(key2 == key1);
    471         break;
    472       case 1:
    473         EXPECT_FALSE(key1 < key2);
    474         EXPECT_TRUE(key2 < key1);
    475         EXPECT_FALSE(key2 == key1);
    476         break;
    477       default:
    478         FAIL() << "Invalid expectation. Can be only -1, 0, 1";
    479     }
    480   }
    481 }
    482 
    483 }  // namespace net
    484