Home | History | Annotate | Download | only in simple
      1 // Copyright (c) 2013 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 <algorithm>
      6 #include <functional>
      7 
      8 #include "base/files/scoped_temp_dir.h"
      9 #include "base/hash.h"
     10 #include "base/logging.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/pickle.h"
     13 #include "base/sha1.h"
     14 #include "base/strings/stringprintf.h"
     15 #include "base/task_runner.h"
     16 #include "base/threading/platform_thread.h"
     17 #include "base/time/time.h"
     18 #include "net/base/cache_type.h"
     19 #include "net/disk_cache/simple/simple_index.h"
     20 #include "net/disk_cache/simple/simple_index_delegate.h"
     21 #include "net/disk_cache/simple/simple_index_file.h"
     22 #include "net/disk_cache/simple/simple_test_util.h"
     23 #include "net/disk_cache/simple/simple_util.h"
     24 #include "testing/gtest/include/gtest/gtest.h"
     25 
     26 namespace disk_cache {
     27 namespace {
     28 
     29 const base::Time kTestLastUsedTime =
     30     base::Time::UnixEpoch() + base::TimeDelta::FromDays(20);
     31 const int kTestEntrySize = 789;
     32 
     33 }  // namespace
     34 
     35 
     36 class EntryMetadataTest  : public testing::Test {
     37  public:
     38   EntryMetadata NewEntryMetadataWithValues() {
     39     return EntryMetadata(kTestLastUsedTime, kTestEntrySize);
     40   }
     41 
     42   void CheckEntryMetadataValues(const EntryMetadata& entry_metadata) {
     43     EXPECT_LT(kTestLastUsedTime - base::TimeDelta::FromSeconds(2),
     44               entry_metadata.GetLastUsedTime());
     45     EXPECT_GT(kTestLastUsedTime + base::TimeDelta::FromSeconds(2),
     46               entry_metadata.GetLastUsedTime());
     47     EXPECT_EQ(kTestEntrySize, entry_metadata.GetEntrySize());
     48   }
     49 };
     50 
     51 class MockSimpleIndexFile : public SimpleIndexFile,
     52                             public base::SupportsWeakPtr<MockSimpleIndexFile> {
     53  public:
     54   MockSimpleIndexFile()
     55       : SimpleIndexFile(NULL, NULL, net::DISK_CACHE, base::FilePath()),
     56         load_result_(NULL),
     57         load_index_entries_calls_(0),
     58         disk_writes_(0) {}
     59 
     60   virtual void LoadIndexEntries(
     61       base::Time cache_last_modified,
     62       const base::Closure& callback,
     63       SimpleIndexLoadResult* out_load_result) OVERRIDE {
     64     load_callback_ = callback;
     65     load_result_ = out_load_result;
     66     ++load_index_entries_calls_;
     67   }
     68 
     69   virtual void WriteToDisk(const SimpleIndex::EntrySet& entry_set,
     70                            uint64 cache_size,
     71                            const base::TimeTicks& start,
     72                            bool app_on_background) OVERRIDE {
     73     disk_writes_++;
     74     disk_write_entry_set_ = entry_set;
     75   }
     76 
     77   void GetAndResetDiskWriteEntrySet(SimpleIndex::EntrySet* entry_set) {
     78     entry_set->swap(disk_write_entry_set_);
     79   }
     80 
     81   const base::Closure& load_callback() const { return load_callback_; }
     82   SimpleIndexLoadResult* load_result() const { return load_result_; }
     83   int load_index_entries_calls() const { return load_index_entries_calls_; }
     84   int disk_writes() const { return disk_writes_; }
     85 
     86  private:
     87   base::Closure load_callback_;
     88   SimpleIndexLoadResult* load_result_;
     89   int load_index_entries_calls_;
     90   int disk_writes_;
     91   SimpleIndex::EntrySet disk_write_entry_set_;
     92 };
     93 
     94 class SimpleIndexTest  : public testing::Test, public SimpleIndexDelegate {
     95  protected:
     96   SimpleIndexTest()
     97       : hashes_(base::Bind(&HashesInitializer)),
     98         doom_entries_calls_(0) {}
     99 
    100   static uint64 HashesInitializer(size_t hash_index) {
    101     return disk_cache::simple_util::GetEntryHashKey(
    102         base::StringPrintf("key%d", static_cast<int>(hash_index)));
    103   }
    104 
    105   virtual void SetUp() OVERRIDE {
    106     scoped_ptr<MockSimpleIndexFile> index_file(new MockSimpleIndexFile());
    107     index_file_ = index_file->AsWeakPtr();
    108     index_.reset(new SimpleIndex(NULL, this, net::DISK_CACHE,
    109                                  index_file.PassAs<SimpleIndexFile>()));
    110 
    111     index_->Initialize(base::Time());
    112   }
    113 
    114   void WaitForTimeChange() {
    115     const base::Time initial_time = base::Time::Now();
    116     do {
    117       base::PlatformThread::YieldCurrentThread();
    118     } while (base::Time::Now() -
    119              initial_time < base::TimeDelta::FromSeconds(1));
    120   }
    121 
    122   // From SimpleIndexDelegate:
    123   virtual void DoomEntries(std::vector<uint64>* entry_hashes,
    124                            const net::CompletionCallback& callback) OVERRIDE {
    125     std::for_each(entry_hashes->begin(), entry_hashes->end(),
    126                   std::bind1st(std::mem_fun(&SimpleIndex::Remove),
    127                                index_.get()));
    128     last_doom_entry_hashes_ = *entry_hashes;
    129     ++doom_entries_calls_;
    130   }
    131 
    132   // Redirect to allow single "friend" declaration in base class.
    133   bool GetEntryForTesting(uint64 key, EntryMetadata* metadata) {
    134     SimpleIndex::EntrySet::iterator it = index_->entries_set_.find(key);
    135     if (index_->entries_set_.end() == it)
    136       return false;
    137     *metadata = it->second;
    138     return true;
    139   }
    140 
    141   void InsertIntoIndexFileReturn(uint64 hash_key,
    142                                  base::Time last_used_time,
    143                                  int entry_size) {
    144     index_file_->load_result()->entries.insert(std::make_pair(
    145         hash_key, EntryMetadata(last_used_time, entry_size)));
    146   }
    147 
    148   void ReturnIndexFile() {
    149     index_file_->load_result()->did_load = true;
    150     index_file_->load_callback().Run();
    151   }
    152 
    153   // Non-const for timer manipulation.
    154   SimpleIndex* index() { return index_.get(); }
    155   const MockSimpleIndexFile* index_file() const { return index_file_.get(); }
    156 
    157   const std::vector<uint64>& last_doom_entry_hashes() const {
    158     return last_doom_entry_hashes_;
    159   }
    160   int doom_entries_calls() const { return doom_entries_calls_; }
    161 
    162 
    163   const simple_util::ImmutableArray<uint64, 16> hashes_;
    164   scoped_ptr<SimpleIndex> index_;
    165   base::WeakPtr<MockSimpleIndexFile> index_file_;
    166 
    167   std::vector<uint64> last_doom_entry_hashes_;
    168   int doom_entries_calls_;
    169 };
    170 
    171 TEST_F(EntryMetadataTest, Basics) {
    172   EntryMetadata entry_metadata;
    173   EXPECT_EQ(base::Time(), entry_metadata.GetLastUsedTime());
    174   EXPECT_EQ(0, entry_metadata.GetEntrySize());
    175 
    176   entry_metadata = NewEntryMetadataWithValues();
    177   CheckEntryMetadataValues(entry_metadata);
    178 
    179   const base::Time new_time = base::Time::Now();
    180   entry_metadata.SetLastUsedTime(new_time);
    181 
    182   EXPECT_LT(new_time - base::TimeDelta::FromSeconds(2),
    183             entry_metadata.GetLastUsedTime());
    184   EXPECT_GT(new_time + base::TimeDelta::FromSeconds(2),
    185             entry_metadata.GetLastUsedTime());
    186 }
    187 
    188 TEST_F(EntryMetadataTest, Serialize) {
    189   EntryMetadata entry_metadata = NewEntryMetadataWithValues();
    190 
    191   Pickle pickle;
    192   entry_metadata.Serialize(&pickle);
    193 
    194   PickleIterator it(pickle);
    195   EntryMetadata new_entry_metadata;
    196   new_entry_metadata.Deserialize(&it);
    197   CheckEntryMetadataValues(new_entry_metadata);
    198 }
    199 
    200 TEST_F(SimpleIndexTest, IndexSizeCorrectOnMerge) {
    201   typedef disk_cache::SimpleIndex::EntrySet EntrySet;
    202   index()->SetMaxSize(100);
    203   index()->Insert(hashes_.at<2>());
    204   index()->UpdateEntrySize(hashes_.at<2>(), 2);
    205   index()->Insert(hashes_.at<3>());
    206   index()->UpdateEntrySize(hashes_.at<3>(), 3);
    207   index()->Insert(hashes_.at<4>());
    208   index()->UpdateEntrySize(hashes_.at<4>(), 4);
    209   EXPECT_EQ(9U, index()->cache_size_);
    210   {
    211     scoped_ptr<SimpleIndexLoadResult> result(new SimpleIndexLoadResult());
    212     result->did_load = true;
    213     index()->MergeInitializingSet(result.Pass());
    214   }
    215   EXPECT_EQ(9U, index()->cache_size_);
    216   {
    217     scoped_ptr<SimpleIndexLoadResult> result(new SimpleIndexLoadResult());
    218     result->did_load = true;
    219     const uint64 new_hash_key = hashes_.at<11>();
    220     result->entries.insert(
    221         std::make_pair(new_hash_key, EntryMetadata(base::Time::Now(), 11)));
    222     const uint64 redundant_hash_key = hashes_.at<4>();
    223     result->entries.insert(std::make_pair(redundant_hash_key,
    224                                           EntryMetadata(base::Time::Now(), 4)));
    225     index()->MergeInitializingSet(result.Pass());
    226   }
    227   EXPECT_EQ(2U + 3U + 4U + 11U, index()->cache_size_);
    228 }
    229 
    230 // State of index changes as expected with an insert and a remove.
    231 TEST_F(SimpleIndexTest, BasicInsertRemove) {
    232   // Confirm blank state.
    233   EntryMetadata metadata;
    234   EXPECT_EQ(base::Time(), metadata.GetLastUsedTime());
    235   EXPECT_EQ(0, metadata.GetEntrySize());
    236 
    237   // Confirm state after insert.
    238   index()->Insert(hashes_.at<1>());
    239   ASSERT_TRUE(GetEntryForTesting(hashes_.at<1>(), &metadata));
    240   base::Time now(base::Time::Now());
    241   EXPECT_LT(now - base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
    242   EXPECT_GT(now + base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
    243   EXPECT_EQ(0, metadata.GetEntrySize());
    244 
    245   // Confirm state after remove.
    246   metadata = EntryMetadata();
    247   index()->Remove(hashes_.at<1>());
    248   EXPECT_FALSE(GetEntryForTesting(hashes_.at<1>(), &metadata));
    249   EXPECT_EQ(base::Time(), metadata.GetLastUsedTime());
    250   EXPECT_EQ(0, metadata.GetEntrySize());
    251 }
    252 
    253 TEST_F(SimpleIndexTest, Has) {
    254   // Confirm the base index has dispatched the request for index entries.
    255   EXPECT_TRUE(index_file_.get());
    256   EXPECT_EQ(1, index_file_->load_index_entries_calls());
    257 
    258   // Confirm "Has()" always returns true before the callback is called.
    259   const uint64 kHash1 = hashes_.at<1>();
    260   EXPECT_TRUE(index()->Has(kHash1));
    261   index()->Insert(kHash1);
    262   EXPECT_TRUE(index()->Has(kHash1));
    263   index()->Remove(kHash1);
    264   // TODO(rdsmith): Maybe return false on explicitly removed entries?
    265   EXPECT_TRUE(index()->Has(kHash1));
    266 
    267   ReturnIndexFile();
    268 
    269   // Confirm "Has() returns conditionally now.
    270   EXPECT_FALSE(index()->Has(kHash1));
    271   index()->Insert(kHash1);
    272   EXPECT_TRUE(index()->Has(kHash1));
    273   index()->Remove(kHash1);
    274 }
    275 
    276 TEST_F(SimpleIndexTest, UseIfExists) {
    277   // Confirm the base index has dispatched the request for index entries.
    278   EXPECT_TRUE(index_file_.get());
    279   EXPECT_EQ(1, index_file_->load_index_entries_calls());
    280 
    281   // Confirm "UseIfExists()" always returns true before the callback is called
    282   // and updates mod time if the entry was really there.
    283   const uint64 kHash1 = hashes_.at<1>();
    284   EntryMetadata metadata1, metadata2;
    285   EXPECT_TRUE(index()->UseIfExists(kHash1));
    286   EXPECT_FALSE(GetEntryForTesting(kHash1, &metadata1));
    287   index()->Insert(kHash1);
    288   EXPECT_TRUE(index()->UseIfExists(kHash1));
    289   EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata1));
    290   WaitForTimeChange();
    291   EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata2));
    292   EXPECT_EQ(metadata1.GetLastUsedTime(), metadata2.GetLastUsedTime());
    293   EXPECT_TRUE(index()->UseIfExists(kHash1));
    294   EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata2));
    295   EXPECT_LT(metadata1.GetLastUsedTime(), metadata2.GetLastUsedTime());
    296   index()->Remove(kHash1);
    297   EXPECT_TRUE(index()->UseIfExists(kHash1));
    298 
    299   ReturnIndexFile();
    300 
    301   // Confirm "UseIfExists() returns conditionally now
    302   EXPECT_FALSE(index()->UseIfExists(kHash1));
    303   EXPECT_FALSE(GetEntryForTesting(kHash1, &metadata1));
    304   index()->Insert(kHash1);
    305   EXPECT_TRUE(index()->UseIfExists(kHash1));
    306   EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata1));
    307   WaitForTimeChange();
    308   EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata2));
    309   EXPECT_EQ(metadata1.GetLastUsedTime(), metadata2.GetLastUsedTime());
    310   EXPECT_TRUE(index()->UseIfExists(kHash1));
    311   EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata2));
    312   EXPECT_LT(metadata1.GetLastUsedTime(), metadata2.GetLastUsedTime());
    313   index()->Remove(kHash1);
    314   EXPECT_FALSE(index()->UseIfExists(kHash1));
    315 }
    316 
    317 TEST_F(SimpleIndexTest, UpdateEntrySize) {
    318   base::Time now(base::Time::Now());
    319 
    320   index()->SetMaxSize(1000);
    321 
    322   const uint64 kHash1 = hashes_.at<1>();
    323   InsertIntoIndexFileReturn(kHash1, now - base::TimeDelta::FromDays(2), 475);
    324   ReturnIndexFile();
    325 
    326   EntryMetadata metadata;
    327   EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata));
    328   EXPECT_LT(
    329       now - base::TimeDelta::FromDays(2) - base::TimeDelta::FromSeconds(1),
    330       metadata.GetLastUsedTime());
    331   EXPECT_GT(
    332       now - base::TimeDelta::FromDays(2) + base::TimeDelta::FromSeconds(1),
    333       metadata.GetLastUsedTime());
    334   EXPECT_EQ(475, metadata.GetEntrySize());
    335 
    336   index()->UpdateEntrySize(kHash1, 600u);
    337   EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata));
    338   EXPECT_EQ(600, metadata.GetEntrySize());
    339   EXPECT_EQ(1, index()->GetEntryCount());
    340 }
    341 
    342 TEST_F(SimpleIndexTest, GetEntryCount) {
    343   EXPECT_EQ(0, index()->GetEntryCount());
    344   index()->Insert(hashes_.at<1>());
    345   EXPECT_EQ(1, index()->GetEntryCount());
    346   index()->Insert(hashes_.at<2>());
    347   EXPECT_EQ(2, index()->GetEntryCount());
    348   index()->Insert(hashes_.at<3>());
    349   EXPECT_EQ(3, index()->GetEntryCount());
    350   index()->Insert(hashes_.at<3>());
    351   EXPECT_EQ(3, index()->GetEntryCount());
    352   index()->Remove(hashes_.at<2>());
    353   EXPECT_EQ(2, index()->GetEntryCount());
    354   index()->Insert(hashes_.at<4>());
    355   EXPECT_EQ(3, index()->GetEntryCount());
    356   index()->Remove(hashes_.at<3>());
    357   EXPECT_EQ(2, index()->GetEntryCount());
    358   index()->Remove(hashes_.at<3>());
    359   EXPECT_EQ(2, index()->GetEntryCount());
    360   index()->Remove(hashes_.at<1>());
    361   EXPECT_EQ(1, index()->GetEntryCount());
    362   index()->Remove(hashes_.at<4>());
    363   EXPECT_EQ(0, index()->GetEntryCount());
    364 }
    365 
    366 // Confirm that we get the results we expect from a simple init.
    367 TEST_F(SimpleIndexTest, BasicInit) {
    368   base::Time now(base::Time::Now());
    369 
    370   InsertIntoIndexFileReturn(hashes_.at<1>(),
    371                             now - base::TimeDelta::FromDays(2),
    372                             10u);
    373   InsertIntoIndexFileReturn(hashes_.at<2>(),
    374                             now - base::TimeDelta::FromDays(3),
    375                             100u);
    376 
    377   ReturnIndexFile();
    378 
    379   EntryMetadata metadata;
    380   EXPECT_TRUE(GetEntryForTesting(hashes_.at<1>(), &metadata));
    381   EXPECT_LT(
    382       now - base::TimeDelta::FromDays(2) - base::TimeDelta::FromSeconds(1),
    383       metadata.GetLastUsedTime());
    384   EXPECT_GT(
    385       now - base::TimeDelta::FromDays(2) + base::TimeDelta::FromSeconds(1),
    386       metadata.GetLastUsedTime());
    387   EXPECT_EQ(10, metadata.GetEntrySize());
    388   EXPECT_TRUE(GetEntryForTesting(hashes_.at<2>(), &metadata));
    389   EXPECT_LT(
    390       now - base::TimeDelta::FromDays(3) - base::TimeDelta::FromSeconds(1),
    391       metadata.GetLastUsedTime());
    392   EXPECT_GT(
    393       now - base::TimeDelta::FromDays(3) + base::TimeDelta::FromSeconds(1),
    394       metadata.GetLastUsedTime());
    395   EXPECT_EQ(100, metadata.GetEntrySize());
    396 }
    397 
    398 // Remove something that's going to come in from the loaded index.
    399 TEST_F(SimpleIndexTest, RemoveBeforeInit) {
    400   const uint64 kHash1 = hashes_.at<1>();
    401   index()->Remove(kHash1);
    402 
    403   InsertIntoIndexFileReturn(kHash1,
    404                             base::Time::Now() - base::TimeDelta::FromDays(2),
    405                             10u);
    406   ReturnIndexFile();
    407 
    408   EXPECT_FALSE(index()->Has(kHash1));
    409 }
    410 
    411 // Insert something that's going to come in from the loaded index; correct
    412 // result?
    413 TEST_F(SimpleIndexTest, InsertBeforeInit) {
    414   const uint64 kHash1 = hashes_.at<1>();
    415   index()->Insert(kHash1);
    416 
    417   InsertIntoIndexFileReturn(kHash1,
    418                             base::Time::Now() - base::TimeDelta::FromDays(2),
    419                             10u);
    420   ReturnIndexFile();
    421 
    422   EntryMetadata metadata;
    423   EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata));
    424   base::Time now(base::Time::Now());
    425   EXPECT_LT(now - base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
    426   EXPECT_GT(now + base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
    427   EXPECT_EQ(0, metadata.GetEntrySize());
    428 }
    429 
    430 // Insert and Remove something that's going to come in from the loaded index.
    431 TEST_F(SimpleIndexTest, InsertRemoveBeforeInit) {
    432   const uint64 kHash1 = hashes_.at<1>();
    433   index()->Insert(kHash1);
    434   index()->Remove(kHash1);
    435 
    436   InsertIntoIndexFileReturn(kHash1,
    437                             base::Time::Now() - base::TimeDelta::FromDays(2),
    438                             10u);
    439   ReturnIndexFile();
    440 
    441   EXPECT_FALSE(index()->Has(kHash1));
    442 }
    443 
    444 // Insert and Remove something that's going to come in from the loaded index.
    445 TEST_F(SimpleIndexTest, RemoveInsertBeforeInit) {
    446   const uint64 kHash1 = hashes_.at<1>();
    447   index()->Remove(kHash1);
    448   index()->Insert(kHash1);
    449 
    450   InsertIntoIndexFileReturn(kHash1,
    451                             base::Time::Now() - base::TimeDelta::FromDays(2),
    452                             10u);
    453   ReturnIndexFile();
    454 
    455   EntryMetadata metadata;
    456   EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata));
    457   base::Time now(base::Time::Now());
    458   EXPECT_LT(now - base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
    459   EXPECT_GT(now + base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
    460   EXPECT_EQ(0, metadata.GetEntrySize());
    461 }
    462 
    463 // Do all above tests at once + a non-conflict to test for cross-key
    464 // interactions.
    465 TEST_F(SimpleIndexTest, AllInitConflicts) {
    466   base::Time now(base::Time::Now());
    467 
    468   index()->Remove(hashes_.at<1>());
    469   InsertIntoIndexFileReturn(hashes_.at<1>(),
    470                             now - base::TimeDelta::FromDays(2),
    471                             10u);
    472   index()->Insert(hashes_.at<2>());
    473   InsertIntoIndexFileReturn(hashes_.at<2>(),
    474                             now - base::TimeDelta::FromDays(3),
    475                             100u);
    476   index()->Insert(hashes_.at<3>());
    477   index()->Remove(hashes_.at<3>());
    478   InsertIntoIndexFileReturn(hashes_.at<3>(),
    479                             now - base::TimeDelta::FromDays(4),
    480                             1000u);
    481   index()->Remove(hashes_.at<4>());
    482   index()->Insert(hashes_.at<4>());
    483   InsertIntoIndexFileReturn(hashes_.at<4>(),
    484                             now - base::TimeDelta::FromDays(5),
    485                             10000u);
    486   InsertIntoIndexFileReturn(hashes_.at<5>(),
    487                             now - base::TimeDelta::FromDays(6),
    488                             100000u);
    489 
    490   ReturnIndexFile();
    491 
    492   EXPECT_FALSE(index()->Has(hashes_.at<1>()));
    493 
    494   EntryMetadata metadata;
    495   EXPECT_TRUE(GetEntryForTesting(hashes_.at<2>(), &metadata));
    496   EXPECT_LT(now - base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
    497   EXPECT_GT(now + base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
    498   EXPECT_EQ(0, metadata.GetEntrySize());
    499 
    500   EXPECT_FALSE(index()->Has(hashes_.at<3>()));
    501 
    502   EXPECT_TRUE(GetEntryForTesting(hashes_.at<4>(), &metadata));
    503   EXPECT_LT(now - base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
    504   EXPECT_GT(now + base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
    505   EXPECT_EQ(0, metadata.GetEntrySize());
    506 
    507   EXPECT_TRUE(GetEntryForTesting(hashes_.at<5>(), &metadata));
    508 
    509   EXPECT_GT(
    510       now - base::TimeDelta::FromDays(6) + base::TimeDelta::FromSeconds(1),
    511       metadata.GetLastUsedTime());
    512   EXPECT_LT(
    513       now - base::TimeDelta::FromDays(6) - base::TimeDelta::FromSeconds(1),
    514       metadata.GetLastUsedTime());
    515 
    516   EXPECT_EQ(100000, metadata.GetEntrySize());
    517 }
    518 
    519 TEST_F(SimpleIndexTest, BasicEviction) {
    520   base::Time now(base::Time::Now());
    521   index()->SetMaxSize(1000);
    522   InsertIntoIndexFileReturn(hashes_.at<1>(),
    523                             now - base::TimeDelta::FromDays(2),
    524                             475u);
    525   index()->Insert(hashes_.at<2>());
    526   index()->UpdateEntrySize(hashes_.at<2>(), 475);
    527   ReturnIndexFile();
    528 
    529   WaitForTimeChange();
    530 
    531   index()->Insert(hashes_.at<3>());
    532   // Confirm index is as expected: No eviction, everything there.
    533   EXPECT_EQ(3, index()->GetEntryCount());
    534   EXPECT_EQ(0, doom_entries_calls());
    535   EXPECT_TRUE(index()->Has(hashes_.at<1>()));
    536   EXPECT_TRUE(index()->Has(hashes_.at<2>()));
    537   EXPECT_TRUE(index()->Has(hashes_.at<3>()));
    538 
    539   // Trigger an eviction, and make sure the right things are tossed.
    540   // TODO(rdsmith): This is dependent on the innards of the implementation
    541   // as to at exactly what point we trigger eviction. Not sure how to fix
    542   // that.
    543   index()->UpdateEntrySize(hashes_.at<3>(), 475);
    544   EXPECT_EQ(1, doom_entries_calls());
    545   EXPECT_EQ(1, index()->GetEntryCount());
    546   EXPECT_FALSE(index()->Has(hashes_.at<1>()));
    547   EXPECT_FALSE(index()->Has(hashes_.at<2>()));
    548   EXPECT_TRUE(index()->Has(hashes_.at<3>()));
    549   ASSERT_EQ(2u, last_doom_entry_hashes().size());
    550 }
    551 
    552 // Confirm all the operations queue a disk write at some point in the
    553 // future.
    554 TEST_F(SimpleIndexTest, DiskWriteQueued) {
    555   index()->SetMaxSize(1000);
    556   ReturnIndexFile();
    557 
    558   EXPECT_FALSE(index()->write_to_disk_timer_.IsRunning());
    559 
    560   const uint64 kHash1 = hashes_.at<1>();
    561   index()->Insert(kHash1);
    562   EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
    563   index()->write_to_disk_timer_.Stop();
    564   EXPECT_FALSE(index()->write_to_disk_timer_.IsRunning());
    565 
    566   index()->UseIfExists(kHash1);
    567   EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
    568   index()->write_to_disk_timer_.Stop();
    569 
    570   index()->UpdateEntrySize(kHash1, 20);
    571   EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
    572   index()->write_to_disk_timer_.Stop();
    573 
    574   index()->Remove(kHash1);
    575   EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
    576   index()->write_to_disk_timer_.Stop();
    577 }
    578 
    579 TEST_F(SimpleIndexTest, DiskWriteExecuted) {
    580   index()->SetMaxSize(1000);
    581   ReturnIndexFile();
    582 
    583   EXPECT_FALSE(index()->write_to_disk_timer_.IsRunning());
    584 
    585   const uint64 kHash1 = hashes_.at<1>();
    586   index()->Insert(kHash1);
    587   index()->UpdateEntrySize(kHash1, 20);
    588   EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
    589   base::Closure user_task(index()->write_to_disk_timer_.user_task());
    590   index()->write_to_disk_timer_.Stop();
    591 
    592   EXPECT_EQ(0, index_file_->disk_writes());
    593   user_task.Run();
    594   EXPECT_EQ(1, index_file_->disk_writes());
    595   SimpleIndex::EntrySet entry_set;
    596   index_file_->GetAndResetDiskWriteEntrySet(&entry_set);
    597 
    598   uint64 hash_key = kHash1;
    599   base::Time now(base::Time::Now());
    600   ASSERT_EQ(1u, entry_set.size());
    601   EXPECT_EQ(hash_key, entry_set.begin()->first);
    602   const EntryMetadata& entry1(entry_set.begin()->second);
    603   EXPECT_LT(now - base::TimeDelta::FromMinutes(1), entry1.GetLastUsedTime());
    604   EXPECT_GT(now + base::TimeDelta::FromMinutes(1), entry1.GetLastUsedTime());
    605   EXPECT_EQ(20, entry1.GetEntrySize());
    606 }
    607 
    608 TEST_F(SimpleIndexTest, DiskWritePostponed) {
    609   index()->SetMaxSize(1000);
    610   ReturnIndexFile();
    611 
    612   EXPECT_FALSE(index()->write_to_disk_timer_.IsRunning());
    613 
    614   index()->Insert(hashes_.at<1>());
    615   index()->UpdateEntrySize(hashes_.at<1>(), 20);
    616   EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
    617   base::TimeTicks expected_trigger(
    618       index()->write_to_disk_timer_.desired_run_time());
    619 
    620   WaitForTimeChange();
    621   EXPECT_EQ(expected_trigger, index()->write_to_disk_timer_.desired_run_time());
    622   index()->Insert(hashes_.at<2>());
    623   index()->UpdateEntrySize(hashes_.at<2>(), 40);
    624   EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
    625   EXPECT_LT(expected_trigger, index()->write_to_disk_timer_.desired_run_time());
    626   index()->write_to_disk_timer_.Stop();
    627 }
    628 
    629 }  // namespace disk_cache
    630