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   index()->SetMaxSize(100);
    202   index()->Insert(hashes_.at<2>());
    203   index()->UpdateEntrySize(hashes_.at<2>(), 2);
    204   index()->Insert(hashes_.at<3>());
    205   index()->UpdateEntrySize(hashes_.at<3>(), 3);
    206   index()->Insert(hashes_.at<4>());
    207   index()->UpdateEntrySize(hashes_.at<4>(), 4);
    208   EXPECT_EQ(9U, index()->cache_size_);
    209   {
    210     scoped_ptr<SimpleIndexLoadResult> result(new SimpleIndexLoadResult());
    211     result->did_load = true;
    212     index()->MergeInitializingSet(result.Pass());
    213   }
    214   EXPECT_EQ(9U, index()->cache_size_);
    215   {
    216     scoped_ptr<SimpleIndexLoadResult> result(new SimpleIndexLoadResult());
    217     result->did_load = true;
    218     const uint64 new_hash_key = hashes_.at<11>();
    219     result->entries.insert(
    220         std::make_pair(new_hash_key, EntryMetadata(base::Time::Now(), 11)));
    221     const uint64 redundant_hash_key = hashes_.at<4>();
    222     result->entries.insert(std::make_pair(redundant_hash_key,
    223                                           EntryMetadata(base::Time::Now(), 4)));
    224     index()->MergeInitializingSet(result.Pass());
    225   }
    226   EXPECT_EQ(2U + 3U + 4U + 11U, index()->cache_size_);
    227 }
    228 
    229 // State of index changes as expected with an insert and a remove.
    230 TEST_F(SimpleIndexTest, BasicInsertRemove) {
    231   // Confirm blank state.
    232   EntryMetadata metadata;
    233   EXPECT_EQ(base::Time(), metadata.GetLastUsedTime());
    234   EXPECT_EQ(0, metadata.GetEntrySize());
    235 
    236   // Confirm state after insert.
    237   index()->Insert(hashes_.at<1>());
    238   ASSERT_TRUE(GetEntryForTesting(hashes_.at<1>(), &metadata));
    239   base::Time now(base::Time::Now());
    240   EXPECT_LT(now - base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
    241   EXPECT_GT(now + base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
    242   EXPECT_EQ(0, metadata.GetEntrySize());
    243 
    244   // Confirm state after remove.
    245   metadata = EntryMetadata();
    246   index()->Remove(hashes_.at<1>());
    247   EXPECT_FALSE(GetEntryForTesting(hashes_.at<1>(), &metadata));
    248   EXPECT_EQ(base::Time(), metadata.GetLastUsedTime());
    249   EXPECT_EQ(0, metadata.GetEntrySize());
    250 }
    251 
    252 TEST_F(SimpleIndexTest, Has) {
    253   // Confirm the base index has dispatched the request for index entries.
    254   EXPECT_TRUE(index_file_.get());
    255   EXPECT_EQ(1, index_file_->load_index_entries_calls());
    256 
    257   // Confirm "Has()" always returns true before the callback is called.
    258   const uint64 kHash1 = hashes_.at<1>();
    259   EXPECT_TRUE(index()->Has(kHash1));
    260   index()->Insert(kHash1);
    261   EXPECT_TRUE(index()->Has(kHash1));
    262   index()->Remove(kHash1);
    263   // TODO(rdsmith): Maybe return false on explicitly removed entries?
    264   EXPECT_TRUE(index()->Has(kHash1));
    265 
    266   ReturnIndexFile();
    267 
    268   // Confirm "Has() returns conditionally now.
    269   EXPECT_FALSE(index()->Has(kHash1));
    270   index()->Insert(kHash1);
    271   EXPECT_TRUE(index()->Has(kHash1));
    272   index()->Remove(kHash1);
    273 }
    274 
    275 TEST_F(SimpleIndexTest, UseIfExists) {
    276   // Confirm the base index has dispatched the request for index entries.
    277   EXPECT_TRUE(index_file_.get());
    278   EXPECT_EQ(1, index_file_->load_index_entries_calls());
    279 
    280   // Confirm "UseIfExists()" always returns true before the callback is called
    281   // and updates mod time if the entry was really there.
    282   const uint64 kHash1 = hashes_.at<1>();
    283   EntryMetadata metadata1, metadata2;
    284   EXPECT_TRUE(index()->UseIfExists(kHash1));
    285   EXPECT_FALSE(GetEntryForTesting(kHash1, &metadata1));
    286   index()->Insert(kHash1);
    287   EXPECT_TRUE(index()->UseIfExists(kHash1));
    288   EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata1));
    289   WaitForTimeChange();
    290   EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata2));
    291   EXPECT_EQ(metadata1.GetLastUsedTime(), metadata2.GetLastUsedTime());
    292   EXPECT_TRUE(index()->UseIfExists(kHash1));
    293   EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata2));
    294   EXPECT_LT(metadata1.GetLastUsedTime(), metadata2.GetLastUsedTime());
    295   index()->Remove(kHash1);
    296   EXPECT_TRUE(index()->UseIfExists(kHash1));
    297 
    298   ReturnIndexFile();
    299 
    300   // Confirm "UseIfExists() returns conditionally now
    301   EXPECT_FALSE(index()->UseIfExists(kHash1));
    302   EXPECT_FALSE(GetEntryForTesting(kHash1, &metadata1));
    303   index()->Insert(kHash1);
    304   EXPECT_TRUE(index()->UseIfExists(kHash1));
    305   EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata1));
    306   WaitForTimeChange();
    307   EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata2));
    308   EXPECT_EQ(metadata1.GetLastUsedTime(), metadata2.GetLastUsedTime());
    309   EXPECT_TRUE(index()->UseIfExists(kHash1));
    310   EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata2));
    311   EXPECT_LT(metadata1.GetLastUsedTime(), metadata2.GetLastUsedTime());
    312   index()->Remove(kHash1);
    313   EXPECT_FALSE(index()->UseIfExists(kHash1));
    314 }
    315 
    316 TEST_F(SimpleIndexTest, UpdateEntrySize) {
    317   base::Time now(base::Time::Now());
    318 
    319   index()->SetMaxSize(1000);
    320 
    321   const uint64 kHash1 = hashes_.at<1>();
    322   InsertIntoIndexFileReturn(kHash1, now - base::TimeDelta::FromDays(2), 475);
    323   ReturnIndexFile();
    324 
    325   EntryMetadata metadata;
    326   EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata));
    327   EXPECT_LT(
    328       now - base::TimeDelta::FromDays(2) - base::TimeDelta::FromSeconds(1),
    329       metadata.GetLastUsedTime());
    330   EXPECT_GT(
    331       now - base::TimeDelta::FromDays(2) + base::TimeDelta::FromSeconds(1),
    332       metadata.GetLastUsedTime());
    333   EXPECT_EQ(475, metadata.GetEntrySize());
    334 
    335   index()->UpdateEntrySize(kHash1, 600u);
    336   EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata));
    337   EXPECT_EQ(600, metadata.GetEntrySize());
    338   EXPECT_EQ(1, index()->GetEntryCount());
    339 }
    340 
    341 TEST_F(SimpleIndexTest, GetEntryCount) {
    342   EXPECT_EQ(0, index()->GetEntryCount());
    343   index()->Insert(hashes_.at<1>());
    344   EXPECT_EQ(1, index()->GetEntryCount());
    345   index()->Insert(hashes_.at<2>());
    346   EXPECT_EQ(2, index()->GetEntryCount());
    347   index()->Insert(hashes_.at<3>());
    348   EXPECT_EQ(3, index()->GetEntryCount());
    349   index()->Insert(hashes_.at<3>());
    350   EXPECT_EQ(3, index()->GetEntryCount());
    351   index()->Remove(hashes_.at<2>());
    352   EXPECT_EQ(2, index()->GetEntryCount());
    353   index()->Insert(hashes_.at<4>());
    354   EXPECT_EQ(3, index()->GetEntryCount());
    355   index()->Remove(hashes_.at<3>());
    356   EXPECT_EQ(2, index()->GetEntryCount());
    357   index()->Remove(hashes_.at<3>());
    358   EXPECT_EQ(2, index()->GetEntryCount());
    359   index()->Remove(hashes_.at<1>());
    360   EXPECT_EQ(1, index()->GetEntryCount());
    361   index()->Remove(hashes_.at<4>());
    362   EXPECT_EQ(0, index()->GetEntryCount());
    363 }
    364 
    365 // Confirm that we get the results we expect from a simple init.
    366 TEST_F(SimpleIndexTest, BasicInit) {
    367   base::Time now(base::Time::Now());
    368 
    369   InsertIntoIndexFileReturn(hashes_.at<1>(),
    370                             now - base::TimeDelta::FromDays(2),
    371                             10u);
    372   InsertIntoIndexFileReturn(hashes_.at<2>(),
    373                             now - base::TimeDelta::FromDays(3),
    374                             100u);
    375 
    376   ReturnIndexFile();
    377 
    378   EntryMetadata metadata;
    379   EXPECT_TRUE(GetEntryForTesting(hashes_.at<1>(), &metadata));
    380   EXPECT_LT(
    381       now - base::TimeDelta::FromDays(2) - base::TimeDelta::FromSeconds(1),
    382       metadata.GetLastUsedTime());
    383   EXPECT_GT(
    384       now - base::TimeDelta::FromDays(2) + base::TimeDelta::FromSeconds(1),
    385       metadata.GetLastUsedTime());
    386   EXPECT_EQ(10, metadata.GetEntrySize());
    387   EXPECT_TRUE(GetEntryForTesting(hashes_.at<2>(), &metadata));
    388   EXPECT_LT(
    389       now - base::TimeDelta::FromDays(3) - base::TimeDelta::FromSeconds(1),
    390       metadata.GetLastUsedTime());
    391   EXPECT_GT(
    392       now - base::TimeDelta::FromDays(3) + base::TimeDelta::FromSeconds(1),
    393       metadata.GetLastUsedTime());
    394   EXPECT_EQ(100, metadata.GetEntrySize());
    395 }
    396 
    397 // Remove something that's going to come in from the loaded index.
    398 TEST_F(SimpleIndexTest, RemoveBeforeInit) {
    399   const uint64 kHash1 = hashes_.at<1>();
    400   index()->Remove(kHash1);
    401 
    402   InsertIntoIndexFileReturn(kHash1,
    403                             base::Time::Now() - base::TimeDelta::FromDays(2),
    404                             10u);
    405   ReturnIndexFile();
    406 
    407   EXPECT_FALSE(index()->Has(kHash1));
    408 }
    409 
    410 // Insert something that's going to come in from the loaded index; correct
    411 // result?
    412 TEST_F(SimpleIndexTest, InsertBeforeInit) {
    413   const uint64 kHash1 = hashes_.at<1>();
    414   index()->Insert(kHash1);
    415 
    416   InsertIntoIndexFileReturn(kHash1,
    417                             base::Time::Now() - base::TimeDelta::FromDays(2),
    418                             10u);
    419   ReturnIndexFile();
    420 
    421   EntryMetadata metadata;
    422   EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata));
    423   base::Time now(base::Time::Now());
    424   EXPECT_LT(now - base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
    425   EXPECT_GT(now + base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
    426   EXPECT_EQ(0, metadata.GetEntrySize());
    427 }
    428 
    429 // Insert and Remove something that's going to come in from the loaded index.
    430 TEST_F(SimpleIndexTest, InsertRemoveBeforeInit) {
    431   const uint64 kHash1 = hashes_.at<1>();
    432   index()->Insert(kHash1);
    433   index()->Remove(kHash1);
    434 
    435   InsertIntoIndexFileReturn(kHash1,
    436                             base::Time::Now() - base::TimeDelta::FromDays(2),
    437                             10u);
    438   ReturnIndexFile();
    439 
    440   EXPECT_FALSE(index()->Has(kHash1));
    441 }
    442 
    443 // Insert and Remove something that's going to come in from the loaded index.
    444 TEST_F(SimpleIndexTest, RemoveInsertBeforeInit) {
    445   const uint64 kHash1 = hashes_.at<1>();
    446   index()->Remove(kHash1);
    447   index()->Insert(kHash1);
    448 
    449   InsertIntoIndexFileReturn(kHash1,
    450                             base::Time::Now() - base::TimeDelta::FromDays(2),
    451                             10u);
    452   ReturnIndexFile();
    453 
    454   EntryMetadata metadata;
    455   EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata));
    456   base::Time now(base::Time::Now());
    457   EXPECT_LT(now - base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
    458   EXPECT_GT(now + base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
    459   EXPECT_EQ(0, metadata.GetEntrySize());
    460 }
    461 
    462 // Do all above tests at once + a non-conflict to test for cross-key
    463 // interactions.
    464 TEST_F(SimpleIndexTest, AllInitConflicts) {
    465   base::Time now(base::Time::Now());
    466 
    467   index()->Remove(hashes_.at<1>());
    468   InsertIntoIndexFileReturn(hashes_.at<1>(),
    469                             now - base::TimeDelta::FromDays(2),
    470                             10u);
    471   index()->Insert(hashes_.at<2>());
    472   InsertIntoIndexFileReturn(hashes_.at<2>(),
    473                             now - base::TimeDelta::FromDays(3),
    474                             100u);
    475   index()->Insert(hashes_.at<3>());
    476   index()->Remove(hashes_.at<3>());
    477   InsertIntoIndexFileReturn(hashes_.at<3>(),
    478                             now - base::TimeDelta::FromDays(4),
    479                             1000u);
    480   index()->Remove(hashes_.at<4>());
    481   index()->Insert(hashes_.at<4>());
    482   InsertIntoIndexFileReturn(hashes_.at<4>(),
    483                             now - base::TimeDelta::FromDays(5),
    484                             10000u);
    485   InsertIntoIndexFileReturn(hashes_.at<5>(),
    486                             now - base::TimeDelta::FromDays(6),
    487                             100000u);
    488 
    489   ReturnIndexFile();
    490 
    491   EXPECT_FALSE(index()->Has(hashes_.at<1>()));
    492 
    493   EntryMetadata metadata;
    494   EXPECT_TRUE(GetEntryForTesting(hashes_.at<2>(), &metadata));
    495   EXPECT_LT(now - base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
    496   EXPECT_GT(now + base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
    497   EXPECT_EQ(0, metadata.GetEntrySize());
    498 
    499   EXPECT_FALSE(index()->Has(hashes_.at<3>()));
    500 
    501   EXPECT_TRUE(GetEntryForTesting(hashes_.at<4>(), &metadata));
    502   EXPECT_LT(now - base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
    503   EXPECT_GT(now + base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
    504   EXPECT_EQ(0, metadata.GetEntrySize());
    505 
    506   EXPECT_TRUE(GetEntryForTesting(hashes_.at<5>(), &metadata));
    507 
    508   EXPECT_GT(
    509       now - base::TimeDelta::FromDays(6) + base::TimeDelta::FromSeconds(1),
    510       metadata.GetLastUsedTime());
    511   EXPECT_LT(
    512       now - base::TimeDelta::FromDays(6) - base::TimeDelta::FromSeconds(1),
    513       metadata.GetLastUsedTime());
    514 
    515   EXPECT_EQ(100000, metadata.GetEntrySize());
    516 }
    517 
    518 TEST_F(SimpleIndexTest, BasicEviction) {
    519   base::Time now(base::Time::Now());
    520   index()->SetMaxSize(1000);
    521   InsertIntoIndexFileReturn(hashes_.at<1>(),
    522                             now - base::TimeDelta::FromDays(2),
    523                             475u);
    524   index()->Insert(hashes_.at<2>());
    525   index()->UpdateEntrySize(hashes_.at<2>(), 475);
    526   ReturnIndexFile();
    527 
    528   WaitForTimeChange();
    529 
    530   index()->Insert(hashes_.at<3>());
    531   // Confirm index is as expected: No eviction, everything there.
    532   EXPECT_EQ(3, index()->GetEntryCount());
    533   EXPECT_EQ(0, doom_entries_calls());
    534   EXPECT_TRUE(index()->Has(hashes_.at<1>()));
    535   EXPECT_TRUE(index()->Has(hashes_.at<2>()));
    536   EXPECT_TRUE(index()->Has(hashes_.at<3>()));
    537 
    538   // Trigger an eviction, and make sure the right things are tossed.
    539   // TODO(rdsmith): This is dependent on the innards of the implementation
    540   // as to at exactly what point we trigger eviction. Not sure how to fix
    541   // that.
    542   index()->UpdateEntrySize(hashes_.at<3>(), 475);
    543   EXPECT_EQ(1, doom_entries_calls());
    544   EXPECT_EQ(1, index()->GetEntryCount());
    545   EXPECT_FALSE(index()->Has(hashes_.at<1>()));
    546   EXPECT_FALSE(index()->Has(hashes_.at<2>()));
    547   EXPECT_TRUE(index()->Has(hashes_.at<3>()));
    548   ASSERT_EQ(2u, last_doom_entry_hashes().size());
    549 }
    550 
    551 // Confirm all the operations queue a disk write at some point in the
    552 // future.
    553 TEST_F(SimpleIndexTest, DiskWriteQueued) {
    554   index()->SetMaxSize(1000);
    555   ReturnIndexFile();
    556 
    557   EXPECT_FALSE(index()->write_to_disk_timer_.IsRunning());
    558 
    559   const uint64 kHash1 = hashes_.at<1>();
    560   index()->Insert(kHash1);
    561   EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
    562   index()->write_to_disk_timer_.Stop();
    563   EXPECT_FALSE(index()->write_to_disk_timer_.IsRunning());
    564 
    565   index()->UseIfExists(kHash1);
    566   EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
    567   index()->write_to_disk_timer_.Stop();
    568 
    569   index()->UpdateEntrySize(kHash1, 20);
    570   EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
    571   index()->write_to_disk_timer_.Stop();
    572 
    573   index()->Remove(kHash1);
    574   EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
    575   index()->write_to_disk_timer_.Stop();
    576 }
    577 
    578 TEST_F(SimpleIndexTest, DiskWriteExecuted) {
    579   index()->SetMaxSize(1000);
    580   ReturnIndexFile();
    581 
    582   EXPECT_FALSE(index()->write_to_disk_timer_.IsRunning());
    583 
    584   const uint64 kHash1 = hashes_.at<1>();
    585   index()->Insert(kHash1);
    586   index()->UpdateEntrySize(kHash1, 20);
    587   EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
    588   base::Closure user_task(index()->write_to_disk_timer_.user_task());
    589   index()->write_to_disk_timer_.Stop();
    590 
    591   EXPECT_EQ(0, index_file_->disk_writes());
    592   user_task.Run();
    593   EXPECT_EQ(1, index_file_->disk_writes());
    594   SimpleIndex::EntrySet entry_set;
    595   index_file_->GetAndResetDiskWriteEntrySet(&entry_set);
    596 
    597   uint64 hash_key = kHash1;
    598   base::Time now(base::Time::Now());
    599   ASSERT_EQ(1u, entry_set.size());
    600   EXPECT_EQ(hash_key, entry_set.begin()->first);
    601   const EntryMetadata& entry1(entry_set.begin()->second);
    602   EXPECT_LT(now - base::TimeDelta::FromMinutes(1), entry1.GetLastUsedTime());
    603   EXPECT_GT(now + base::TimeDelta::FromMinutes(1), entry1.GetLastUsedTime());
    604   EXPECT_EQ(20, entry1.GetEntrySize());
    605 }
    606 
    607 TEST_F(SimpleIndexTest, DiskWritePostponed) {
    608   index()->SetMaxSize(1000);
    609   ReturnIndexFile();
    610 
    611   EXPECT_FALSE(index()->write_to_disk_timer_.IsRunning());
    612 
    613   index()->Insert(hashes_.at<1>());
    614   index()->UpdateEntrySize(hashes_.at<1>(), 20);
    615   EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
    616   base::TimeTicks expected_trigger(
    617       index()->write_to_disk_timer_.desired_run_time());
    618 
    619   WaitForTimeChange();
    620   EXPECT_EQ(expected_trigger, index()->write_to_disk_timer_.desired_run_time());
    621   index()->Insert(hashes_.at<2>());
    622   index()->UpdateEntrySize(hashes_.at<2>(), 40);
    623   EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
    624   EXPECT_LT(expected_trigger, index()->write_to_disk_timer_.desired_run_time());
    625   index()->write_to_disk_timer_.Stop();
    626 }
    627 
    628 }  // namespace disk_cache
    629