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/file_util.h" 6 #include "base/files/scoped_temp_dir.h" 7 #include "base/hash.h" 8 #include "base/logging.h" 9 #include "base/memory/scoped_ptr.h" 10 #include "base/message_loop/message_loop_proxy.h" 11 #include "base/pickle.h" 12 #include "base/run_loop.h" 13 #include "base/strings/stringprintf.h" 14 #include "base/time/time.h" 15 #include "net/disk_cache/simple/simple_entry_format.h" 16 #include "net/disk_cache/simple/simple_index.h" 17 #include "net/disk_cache/simple/simple_index_file.h" 18 #include "net/disk_cache/simple/simple_util.h" 19 #include "testing/gtest/include/gtest/gtest.h" 20 21 using base::Time; 22 using disk_cache::SimpleIndexFile; 23 using disk_cache::SimpleIndex; 24 25 namespace disk_cache { 26 27 TEST(IndexMetadataTest, Basics) { 28 SimpleIndexFile::IndexMetadata index_metadata; 29 30 EXPECT_EQ(disk_cache::kSimpleIndexMagicNumber, index_metadata.magic_number_); 31 EXPECT_EQ(disk_cache::kSimpleVersion, index_metadata.version_); 32 EXPECT_EQ(0U, index_metadata.GetNumberOfEntries()); 33 EXPECT_EQ(0U, index_metadata.cache_size_); 34 35 EXPECT_TRUE(index_metadata.CheckIndexMetadata()); 36 } 37 38 TEST(IndexMetadataTest, Serialize) { 39 SimpleIndexFile::IndexMetadata index_metadata(123, 456); 40 Pickle pickle; 41 index_metadata.Serialize(&pickle); 42 PickleIterator it(pickle); 43 SimpleIndexFile::IndexMetadata new_index_metadata; 44 new_index_metadata.Deserialize(&it); 45 46 EXPECT_EQ(new_index_metadata.magic_number_, index_metadata.magic_number_); 47 EXPECT_EQ(new_index_metadata.version_, index_metadata.version_); 48 EXPECT_EQ(new_index_metadata.GetNumberOfEntries(), 49 index_metadata.GetNumberOfEntries()); 50 EXPECT_EQ(new_index_metadata.cache_size_, index_metadata.cache_size_); 51 52 EXPECT_TRUE(new_index_metadata.CheckIndexMetadata()); 53 } 54 55 // This friend derived class is able to reexport its ancestors private methods 56 // as public, for use in tests. 57 class WrappedSimpleIndexFile : public SimpleIndexFile { 58 public: 59 using SimpleIndexFile::Deserialize; 60 using SimpleIndexFile::IsIndexFileStale; 61 using SimpleIndexFile::Serialize; 62 63 explicit WrappedSimpleIndexFile(const base::FilePath& index_file_directory) 64 : SimpleIndexFile(base::MessageLoopProxy::current().get(), 65 base::MessageLoopProxy::current().get(), 66 index_file_directory) {} 67 virtual ~WrappedSimpleIndexFile() { 68 } 69 70 const base::FilePath& GetIndexFilePath() const { 71 return index_file_; 72 } 73 }; 74 75 class SimpleIndexFileTest : public testing::Test { 76 public: 77 bool CompareTwoEntryMetadata(const EntryMetadata& a, const EntryMetadata& b) { 78 return a.last_used_time_ == b.last_used_time_ && 79 a.entry_size_ == b.entry_size_; 80 } 81 82 protected: 83 SimpleIndexFileTest() : callback_called_(false) {} 84 85 base::Closure GetCallback() { 86 return base::Bind(&SimpleIndexFileTest::LoadIndexEntriesCallback, 87 base::Unretained(this)); 88 } 89 90 bool callback_called() { return callback_called_; } 91 92 private: 93 void LoadIndexEntriesCallback() { 94 EXPECT_FALSE(callback_called_); 95 callback_called_ = true; 96 } 97 98 bool callback_called_; 99 }; 100 101 TEST_F(SimpleIndexFileTest, Serialize) { 102 SimpleIndex::EntrySet entries; 103 static const uint64 kHashes[] = { 11, 22, 33 }; 104 static const size_t kNumHashes = arraysize(kHashes); 105 EntryMetadata metadata_entries[kNumHashes]; 106 107 SimpleIndexFile::IndexMetadata index_metadata(static_cast<uint64>(kNumHashes), 108 456); 109 for (size_t i = 0; i < kNumHashes; ++i) { 110 uint64 hash = kHashes[i]; 111 metadata_entries[i] = 112 EntryMetadata(Time::FromInternalValue(hash), hash); 113 SimpleIndex::InsertInEntrySet(hash, metadata_entries[i], &entries); 114 } 115 116 scoped_ptr<Pickle> pickle = WrappedSimpleIndexFile::Serialize( 117 index_metadata, entries); 118 EXPECT_TRUE(pickle.get() != NULL); 119 120 SimpleIndexLoadResult deserialize_result; 121 WrappedSimpleIndexFile::Deserialize(static_cast<const char*>(pickle->data()), 122 pickle->size(), 123 &deserialize_result); 124 EXPECT_TRUE(deserialize_result.did_load); 125 const SimpleIndex::EntrySet& new_entries = deserialize_result.entries; 126 EXPECT_EQ(entries.size(), new_entries.size()); 127 128 for (size_t i = 0; i < kNumHashes; ++i) { 129 SimpleIndex::EntrySet::const_iterator it = new_entries.find(kHashes[i]); 130 EXPECT_TRUE(new_entries.end() != it); 131 EXPECT_TRUE(CompareTwoEntryMetadata(it->second, metadata_entries[i])); 132 } 133 } 134 135 TEST_F(SimpleIndexFileTest, IsIndexFileStale) { 136 base::ScopedTempDir cache_dir; 137 ASSERT_TRUE(cache_dir.CreateUniqueTempDir()); 138 base::Time cache_mtime; 139 const base::FilePath cache_path = cache_dir.path(); 140 141 ASSERT_TRUE(simple_util::GetMTime(cache_path, &cache_mtime)); 142 WrappedSimpleIndexFile simple_index_file(cache_path); 143 const base::FilePath& index_path = simple_index_file.GetIndexFilePath(); 144 EXPECT_TRUE(WrappedSimpleIndexFile::IsIndexFileStale(cache_mtime, 145 index_path)); 146 const std::string kDummyData = "nothing to be seen here"; 147 EXPECT_EQ(static_cast<int>(kDummyData.size()), 148 file_util::WriteFile(index_path, 149 kDummyData.data(), 150 kDummyData.size())); 151 ASSERT_TRUE(simple_util::GetMTime(cache_path, &cache_mtime)); 152 EXPECT_FALSE(WrappedSimpleIndexFile::IsIndexFileStale(cache_mtime, 153 index_path)); 154 155 const base::Time past_time = base::Time::Now() - 156 base::TimeDelta::FromSeconds(10); 157 EXPECT_TRUE(file_util::TouchFile(index_path, past_time, past_time)); 158 EXPECT_TRUE(file_util::TouchFile(cache_path, past_time, past_time)); 159 ASSERT_TRUE(simple_util::GetMTime(cache_path, &cache_mtime)); 160 EXPECT_FALSE(WrappedSimpleIndexFile::IsIndexFileStale(cache_mtime, 161 index_path)); 162 const base::Time even_older = 163 past_time - base::TimeDelta::FromSeconds(10); 164 EXPECT_TRUE(file_util::TouchFile(index_path, even_older, even_older)); 165 EXPECT_TRUE(WrappedSimpleIndexFile::IsIndexFileStale(cache_mtime, 166 index_path)); 167 168 } 169 170 TEST_F(SimpleIndexFileTest, WriteThenLoadIndex) { 171 base::ScopedTempDir cache_dir; 172 ASSERT_TRUE(cache_dir.CreateUniqueTempDir()); 173 174 SimpleIndex::EntrySet entries; 175 static const uint64 kHashes[] = { 11, 22, 33 }; 176 static const size_t kNumHashes = arraysize(kHashes); 177 EntryMetadata metadata_entries[kNumHashes]; 178 for (size_t i = 0; i < kNumHashes; ++i) { 179 uint64 hash = kHashes[i]; 180 metadata_entries[i] = 181 EntryMetadata(Time::FromInternalValue(hash), hash); 182 SimpleIndex::InsertInEntrySet(hash, metadata_entries[i], &entries); 183 } 184 185 const uint64 kCacheSize = 456U; 186 { 187 WrappedSimpleIndexFile simple_index_file(cache_dir.path()); 188 simple_index_file.WriteToDisk(entries, kCacheSize, 189 base::TimeTicks(), false); 190 base::RunLoop().RunUntilIdle(); 191 EXPECT_TRUE(base::PathExists(simple_index_file.GetIndexFilePath())); 192 } 193 194 WrappedSimpleIndexFile simple_index_file(cache_dir.path()); 195 base::Time fake_cache_mtime; 196 ASSERT_TRUE(simple_util::GetMTime(simple_index_file.GetIndexFilePath(), 197 &fake_cache_mtime)); 198 SimpleIndexLoadResult load_index_result; 199 simple_index_file.LoadIndexEntries(fake_cache_mtime, 200 GetCallback(), 201 &load_index_result); 202 base::RunLoop().RunUntilIdle(); 203 204 EXPECT_TRUE(base::PathExists(simple_index_file.GetIndexFilePath())); 205 ASSERT_TRUE(callback_called()); 206 EXPECT_TRUE(load_index_result.did_load); 207 EXPECT_FALSE(load_index_result.flush_required); 208 209 EXPECT_EQ(kNumHashes, load_index_result.entries.size()); 210 for (size_t i = 0; i < kNumHashes; ++i) 211 EXPECT_EQ(1U, load_index_result.entries.count(kHashes[i])); 212 } 213 214 TEST_F(SimpleIndexFileTest, LoadCorruptIndex) { 215 base::ScopedTempDir cache_dir; 216 ASSERT_TRUE(cache_dir.CreateUniqueTempDir()); 217 218 WrappedSimpleIndexFile simple_index_file(cache_dir.path()); 219 const base::FilePath& index_path = simple_index_file.GetIndexFilePath(); 220 const std::string kDummyData = "nothing to be seen here"; 221 EXPECT_EQ(static_cast<int>(kDummyData.size()), 222 file_util::WriteFile(index_path, 223 kDummyData.data(), 224 kDummyData.size())); 225 base::Time fake_cache_mtime; 226 ASSERT_TRUE(simple_util::GetMTime(simple_index_file.GetIndexFilePath(), 227 &fake_cache_mtime)); 228 EXPECT_FALSE(WrappedSimpleIndexFile::IsIndexFileStale(fake_cache_mtime, 229 index_path)); 230 231 SimpleIndexLoadResult load_index_result; 232 simple_index_file.LoadIndexEntries(fake_cache_mtime, 233 GetCallback(), 234 &load_index_result); 235 base::RunLoop().RunUntilIdle(); 236 237 EXPECT_FALSE(base::PathExists(index_path)); 238 ASSERT_TRUE(callback_called()); 239 EXPECT_TRUE(load_index_result.did_load); 240 EXPECT_TRUE(load_index_result.flush_required); 241 } 242 243 } // namespace disk_cache 244