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