Home | History | Annotate | Download | only in simple
      1 // Copyright (c) 2011 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/file.h"
      6 #include "base/files/file_util.h"
      7 #include "base/files/scoped_temp_dir.h"
      8 #include "base/hash.h"
      9 #include "base/logging.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/pickle.h"
     12 #include "base/run_loop.h"
     13 #include "base/strings/stringprintf.h"
     14 #include "base/thread_task_runner_handle.h"
     15 #include "base/threading/thread.h"
     16 #include "base/time/time.h"
     17 #include "net/base/cache_type.h"
     18 #include "net/base/test_completion_callback.h"
     19 #include "net/disk_cache/disk_cache_test_util.h"
     20 #include "net/disk_cache/simple/simple_backend_impl.h"
     21 #include "net/disk_cache/simple/simple_backend_version.h"
     22 #include "net/disk_cache/simple/simple_entry_format.h"
     23 #include "net/disk_cache/simple/simple_index.h"
     24 #include "net/disk_cache/simple/simple_index_file.h"
     25 #include "net/disk_cache/simple/simple_util.h"
     26 #include "net/disk_cache/simple/simple_version_upgrade.h"
     27 #include "testing/gtest/include/gtest/gtest.h"
     28 
     29 using base::Time;
     30 using disk_cache::SimpleIndexFile;
     31 using disk_cache::SimpleIndex;
     32 
     33 namespace disk_cache {
     34 
     35 // The Simple Cache backend requires a few guarantees from the filesystem like
     36 // atomic renaming of recently open files. Those guarantees are not provided in
     37 // general on Windows.
     38 #if defined(OS_POSIX)
     39 
     40 TEST(IndexMetadataTest, Basics) {
     41   SimpleIndexFile::IndexMetadata index_metadata;
     42 
     43   EXPECT_EQ(disk_cache::kSimpleIndexMagicNumber, index_metadata.magic_number_);
     44   EXPECT_EQ(disk_cache::kSimpleVersion, index_metadata.version_);
     45   EXPECT_EQ(0U, index_metadata.GetNumberOfEntries());
     46   EXPECT_EQ(0U, index_metadata.cache_size_);
     47 
     48   EXPECT_TRUE(index_metadata.CheckIndexMetadata());
     49 }
     50 
     51 TEST(IndexMetadataTest, Serialize) {
     52   SimpleIndexFile::IndexMetadata index_metadata(123, 456);
     53   Pickle pickle;
     54   index_metadata.Serialize(&pickle);
     55   PickleIterator it(pickle);
     56   SimpleIndexFile::IndexMetadata new_index_metadata;
     57   new_index_metadata.Deserialize(&it);
     58 
     59   EXPECT_EQ(new_index_metadata.magic_number_, index_metadata.magic_number_);
     60   EXPECT_EQ(new_index_metadata.version_, index_metadata.version_);
     61   EXPECT_EQ(new_index_metadata.GetNumberOfEntries(),
     62             index_metadata.GetNumberOfEntries());
     63   EXPECT_EQ(new_index_metadata.cache_size_, index_metadata.cache_size_);
     64 
     65   EXPECT_TRUE(new_index_metadata.CheckIndexMetadata());
     66 }
     67 
     68 // This friend derived class is able to reexport its ancestors private methods
     69 // as public, for use in tests.
     70 class WrappedSimpleIndexFile : public SimpleIndexFile {
     71  public:
     72   using SimpleIndexFile::Deserialize;
     73   using SimpleIndexFile::LegacyIsIndexFileStale;
     74   using SimpleIndexFile::Serialize;
     75   using SimpleIndexFile::SerializeFinalData;
     76 
     77   explicit WrappedSimpleIndexFile(const base::FilePath& index_file_directory)
     78       : SimpleIndexFile(base::ThreadTaskRunnerHandle::Get(),
     79                         base::ThreadTaskRunnerHandle::Get(),
     80                         net::DISK_CACHE,
     81                         index_file_directory) {}
     82   virtual ~WrappedSimpleIndexFile() {
     83   }
     84 
     85   const base::FilePath& GetIndexFilePath() const {
     86     return index_file_;
     87   }
     88 
     89   bool CreateIndexFileDirectory() const {
     90     return base::CreateDirectory(index_file_.DirName());
     91   }
     92 };
     93 
     94 class SimpleIndexFileTest : public testing::Test {
     95  public:
     96   bool CompareTwoEntryMetadata(const EntryMetadata& a, const EntryMetadata& b) {
     97     return
     98         a.last_used_time_seconds_since_epoch_ ==
     99             b.last_used_time_seconds_since_epoch_ &&
    100         a.entry_size_ == b.entry_size_;
    101   }
    102 
    103  protected:
    104   SimpleIndexFileTest() : callback_called_(false) {}
    105 
    106   base::Closure GetCallback() {
    107     return base::Bind(&SimpleIndexFileTest::LoadIndexEntriesCallback,
    108                       base::Unretained(this));
    109   }
    110 
    111   bool callback_called() { return callback_called_; }
    112 
    113  private:
    114   void LoadIndexEntriesCallback() {
    115     EXPECT_FALSE(callback_called_);
    116     callback_called_ = true;
    117   }
    118 
    119   bool callback_called_;
    120 };
    121 
    122 TEST_F(SimpleIndexFileTest, Serialize) {
    123   SimpleIndex::EntrySet entries;
    124   static const uint64 kHashes[] = { 11, 22, 33 };
    125   static const size_t kNumHashes = arraysize(kHashes);
    126   EntryMetadata metadata_entries[kNumHashes];
    127 
    128   SimpleIndexFile::IndexMetadata index_metadata(static_cast<uint64>(kNumHashes),
    129                                                 456);
    130   for (size_t i = 0; i < kNumHashes; ++i) {
    131     uint64 hash = kHashes[i];
    132     metadata_entries[i] = EntryMetadata(Time(), hash);
    133     SimpleIndex::InsertInEntrySet(hash, metadata_entries[i], &entries);
    134   }
    135 
    136   scoped_ptr<Pickle> pickle = WrappedSimpleIndexFile::Serialize(
    137       index_metadata, entries);
    138   EXPECT_TRUE(pickle.get() != NULL);
    139   base::Time now = base::Time::Now();
    140   EXPECT_TRUE(WrappedSimpleIndexFile::SerializeFinalData(now, pickle.get()));
    141   base::Time when_index_last_saw_cache;
    142   SimpleIndexLoadResult deserialize_result;
    143   WrappedSimpleIndexFile::Deserialize(static_cast<const char*>(pickle->data()),
    144                                       pickle->size(),
    145                                       &when_index_last_saw_cache,
    146                                       &deserialize_result);
    147   EXPECT_TRUE(deserialize_result.did_load);
    148   EXPECT_EQ(now, when_index_last_saw_cache);
    149   const SimpleIndex::EntrySet& new_entries = deserialize_result.entries;
    150   EXPECT_EQ(entries.size(), new_entries.size());
    151 
    152   for (size_t i = 0; i < kNumHashes; ++i) {
    153     SimpleIndex::EntrySet::const_iterator it = new_entries.find(kHashes[i]);
    154     EXPECT_TRUE(new_entries.end() != it);
    155     EXPECT_TRUE(CompareTwoEntryMetadata(it->second, metadata_entries[i]));
    156   }
    157 }
    158 
    159 TEST_F(SimpleIndexFileTest, LegacyIsIndexFileStale) {
    160   base::ScopedTempDir cache_dir;
    161   ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
    162   base::Time cache_mtime;
    163   const base::FilePath cache_path = cache_dir.path();
    164 
    165   ASSERT_TRUE(simple_util::GetMTime(cache_path, &cache_mtime));
    166   WrappedSimpleIndexFile simple_index_file(cache_path);
    167   ASSERT_TRUE(simple_index_file.CreateIndexFileDirectory());
    168   const base::FilePath& index_path = simple_index_file.GetIndexFilePath();
    169   EXPECT_TRUE(
    170       WrappedSimpleIndexFile::LegacyIsIndexFileStale(cache_mtime, index_path));
    171   const std::string kDummyData = "nothing to be seen here";
    172   EXPECT_EQ(static_cast<int>(kDummyData.size()),
    173             base::WriteFile(index_path,
    174                             kDummyData.data(), kDummyData.size()));
    175   ASSERT_TRUE(simple_util::GetMTime(cache_path, &cache_mtime));
    176   EXPECT_FALSE(
    177       WrappedSimpleIndexFile::LegacyIsIndexFileStale(cache_mtime, index_path));
    178 
    179   const base::Time past_time = base::Time::Now() -
    180       base::TimeDelta::FromSeconds(10);
    181   EXPECT_TRUE(base::TouchFile(index_path, past_time, past_time));
    182   EXPECT_TRUE(base::TouchFile(cache_path, past_time, past_time));
    183   ASSERT_TRUE(simple_util::GetMTime(cache_path, &cache_mtime));
    184   EXPECT_FALSE(
    185       WrappedSimpleIndexFile::LegacyIsIndexFileStale(cache_mtime, index_path));
    186   const base::Time even_older = past_time - base::TimeDelta::FromSeconds(10);
    187   EXPECT_TRUE(base::TouchFile(index_path, even_older, even_older));
    188   EXPECT_TRUE(
    189       WrappedSimpleIndexFile::LegacyIsIndexFileStale(cache_mtime, index_path));
    190 }
    191 
    192 // This test is flaky, see http://crbug.com/255775.
    193 TEST_F(SimpleIndexFileTest, DISABLED_WriteThenLoadIndex) {
    194   base::ScopedTempDir cache_dir;
    195   ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
    196 
    197   SimpleIndex::EntrySet entries;
    198   static const uint64 kHashes[] = { 11, 22, 33 };
    199   static const size_t kNumHashes = arraysize(kHashes);
    200   EntryMetadata metadata_entries[kNumHashes];
    201   for (size_t i = 0; i < kNumHashes; ++i) {
    202     uint64 hash = kHashes[i];
    203     metadata_entries[i] = EntryMetadata(Time(), hash);
    204     SimpleIndex::InsertInEntrySet(hash, metadata_entries[i], &entries);
    205   }
    206 
    207   const uint64 kCacheSize = 456U;
    208   {
    209     WrappedSimpleIndexFile simple_index_file(cache_dir.path());
    210     simple_index_file.WriteToDisk(entries, kCacheSize,
    211                                   base::TimeTicks(), false);
    212     base::RunLoop().RunUntilIdle();
    213     EXPECT_TRUE(base::PathExists(simple_index_file.GetIndexFilePath()));
    214   }
    215 
    216   WrappedSimpleIndexFile simple_index_file(cache_dir.path());
    217   base::Time fake_cache_mtime;
    218   ASSERT_TRUE(simple_util::GetMTime(simple_index_file.GetIndexFilePath(),
    219                                     &fake_cache_mtime));
    220   SimpleIndexLoadResult load_index_result;
    221   simple_index_file.LoadIndexEntries(fake_cache_mtime,
    222                                      GetCallback(),
    223                                      &load_index_result);
    224   base::RunLoop().RunUntilIdle();
    225 
    226   EXPECT_TRUE(base::PathExists(simple_index_file.GetIndexFilePath()));
    227   ASSERT_TRUE(callback_called());
    228   EXPECT_TRUE(load_index_result.did_load);
    229   EXPECT_FALSE(load_index_result.flush_required);
    230 
    231   EXPECT_EQ(kNumHashes, load_index_result.entries.size());
    232   for (size_t i = 0; i < kNumHashes; ++i)
    233     EXPECT_EQ(1U, load_index_result.entries.count(kHashes[i]));
    234 }
    235 
    236 TEST_F(SimpleIndexFileTest, LoadCorruptIndex) {
    237   base::ScopedTempDir cache_dir;
    238   ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
    239 
    240   WrappedSimpleIndexFile simple_index_file(cache_dir.path());
    241   ASSERT_TRUE(simple_index_file.CreateIndexFileDirectory());
    242   const base::FilePath& index_path = simple_index_file.GetIndexFilePath();
    243   const std::string kDummyData = "nothing to be seen here";
    244   EXPECT_EQ(
    245       implicit_cast<int>(kDummyData.size()),
    246       base::WriteFile(index_path, kDummyData.data(), kDummyData.size()));
    247   base::Time fake_cache_mtime;
    248   ASSERT_TRUE(simple_util::GetMTime(simple_index_file.GetIndexFilePath(),
    249                                     &fake_cache_mtime));
    250   EXPECT_FALSE(WrappedSimpleIndexFile::LegacyIsIndexFileStale(fake_cache_mtime,
    251                                                               index_path));
    252 
    253   SimpleIndexLoadResult load_index_result;
    254   simple_index_file.LoadIndexEntries(fake_cache_mtime,
    255                                      GetCallback(),
    256                                      &load_index_result);
    257   base::RunLoop().RunUntilIdle();
    258 
    259   EXPECT_FALSE(base::PathExists(index_path));
    260   ASSERT_TRUE(callback_called());
    261   EXPECT_TRUE(load_index_result.did_load);
    262   EXPECT_TRUE(load_index_result.flush_required);
    263 }
    264 
    265 // Tests that after an upgrade the backend has the index file put in place.
    266 TEST_F(SimpleIndexFileTest, SimpleCacheUpgrade) {
    267   base::ScopedTempDir cache_dir;
    268   ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
    269   const base::FilePath cache_path = cache_dir.path();
    270 
    271   // Write an old fake index file.
    272   base::File file(cache_path.AppendASCII("index"),
    273                   base::File::FLAG_CREATE | base::File::FLAG_WRITE);
    274   ASSERT_TRUE(file.IsValid());
    275   disk_cache::FakeIndexData file_contents;
    276   file_contents.initial_magic_number = disk_cache::kSimpleInitialMagicNumber;
    277   file_contents.version = 5;
    278   int bytes_written = file.Write(0, reinterpret_cast<char*>(&file_contents),
    279                                  sizeof(file_contents));
    280   ASSERT_EQ((int)sizeof(file_contents), bytes_written);
    281   file.Close();
    282 
    283   // Write the index file. The format is incorrect, but for transitioning from
    284   // v5 it does not matter.
    285   const std::string index_file_contents("incorrectly serialized data");
    286   const base::FilePath old_index_file =
    287       cache_path.AppendASCII("the-real-index");
    288   ASSERT_EQ(implicit_cast<int>(index_file_contents.size()),
    289             base::WriteFile(old_index_file,
    290                             index_file_contents.data(),
    291                             index_file_contents.size()));
    292 
    293   // Upgrade the cache.
    294   ASSERT_TRUE(disk_cache::UpgradeSimpleCacheOnDisk(cache_path));
    295 
    296   // Create the backend and initiate index flush by destroying the backend.
    297   base::Thread cache_thread("CacheThread");
    298   ASSERT_TRUE(cache_thread.StartWithOptions(
    299       base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
    300   disk_cache::SimpleBackendImpl* simple_cache =
    301       new disk_cache::SimpleBackendImpl(cache_path,
    302                                         0,
    303                                         net::DISK_CACHE,
    304                                         cache_thread.message_loop_proxy().get(),
    305                                         NULL);
    306   net::TestCompletionCallback cb;
    307   int rv = simple_cache->Init(cb.callback());
    308   EXPECT_EQ(net::OK, cb.GetResult(rv));
    309   rv = simple_cache->index()->ExecuteWhenReady(cb.callback());
    310   EXPECT_EQ(net::OK, cb.GetResult(rv));
    311   delete simple_cache;
    312 
    313   // The backend flushes the index on destruction and does so on the cache
    314   // thread, wait for the flushing to finish by posting a callback to the cache
    315   // thread after that.
    316   MessageLoopHelper helper;
    317   CallbackTest cb_shutdown(&helper, false);
    318   cache_thread.message_loop_proxy()->PostTask(
    319       FROM_HERE,
    320       base::Bind(&CallbackTest::Run, base::Unretained(&cb_shutdown), net::OK));
    321   helper.WaitUntilCacheIoFinished(1);
    322 
    323   // Verify that the index file exists.
    324   const base::FilePath& index_file_path =
    325       cache_path.AppendASCII("index-dir").AppendASCII("the-real-index");
    326   EXPECT_TRUE(base::PathExists(index_file_path));
    327 
    328   // Verify that the version of the index file is correct.
    329   std::string contents;
    330   EXPECT_TRUE(base::ReadFileToString(index_file_path, &contents));
    331   base::Time when_index_last_saw_cache;
    332   SimpleIndexLoadResult deserialize_result;
    333   WrappedSimpleIndexFile::Deserialize(contents.data(),
    334                                       contents.size(),
    335                                       &when_index_last_saw_cache,
    336                                       &deserialize_result);
    337   EXPECT_TRUE(deserialize_result.did_load);
    338 }
    339 
    340 #endif  // defined(OS_POSIX)
    341 
    342 }  // namespace disk_cache
    343