Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / net / disk_cache / simple / simple_index_file_unittest.cc
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