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