Upstream version 5.34.92.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/file_util.h"
6 #include "base/files/file.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/message_loop/message_loop_proxy.h"
12 #include "base/pickle.h"
13 #include "base/run_loop.h"
14 #include "base/strings/stringprintf.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::MessageLoopProxy::current().get(),
79                         base::MessageLoopProxy::current().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             file_util::WriteFile(index_path,
174                                  kDummyData.data(),
175                                  kDummyData.size()));
176   ASSERT_TRUE(simple_util::GetMTime(cache_path, &cache_mtime));
177   EXPECT_FALSE(
178       WrappedSimpleIndexFile::LegacyIsIndexFileStale(cache_mtime, index_path));
179
180   const base::Time past_time = base::Time::Now() -
181       base::TimeDelta::FromSeconds(10);
182   EXPECT_TRUE(base::TouchFile(index_path, past_time, past_time));
183   EXPECT_TRUE(base::TouchFile(cache_path, past_time, past_time));
184   ASSERT_TRUE(simple_util::GetMTime(cache_path, &cache_mtime));
185   EXPECT_FALSE(
186       WrappedSimpleIndexFile::LegacyIsIndexFileStale(cache_mtime, index_path));
187   const base::Time even_older = past_time - base::TimeDelta::FromSeconds(10);
188   EXPECT_TRUE(base::TouchFile(index_path, even_older, even_older));
189   EXPECT_TRUE(
190       WrappedSimpleIndexFile::LegacyIsIndexFileStale(cache_mtime, index_path));
191 }
192
193 // This test is flaky, see http://crbug.com/255775.
194 TEST_F(SimpleIndexFileTest, DISABLED_WriteThenLoadIndex) {
195   base::ScopedTempDir cache_dir;
196   ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
197
198   SimpleIndex::EntrySet entries;
199   static const uint64 kHashes[] = { 11, 22, 33 };
200   static const size_t kNumHashes = arraysize(kHashes);
201   EntryMetadata metadata_entries[kNumHashes];
202   for (size_t i = 0; i < kNumHashes; ++i) {
203     uint64 hash = kHashes[i];
204     metadata_entries[i] = EntryMetadata(Time(), hash);
205     SimpleIndex::InsertInEntrySet(hash, metadata_entries[i], &entries);
206   }
207
208   const uint64 kCacheSize = 456U;
209   {
210     WrappedSimpleIndexFile simple_index_file(cache_dir.path());
211     simple_index_file.WriteToDisk(entries, kCacheSize,
212                                   base::TimeTicks(), false);
213     base::RunLoop().RunUntilIdle();
214     EXPECT_TRUE(base::PathExists(simple_index_file.GetIndexFilePath()));
215   }
216
217   WrappedSimpleIndexFile simple_index_file(cache_dir.path());
218   base::Time fake_cache_mtime;
219   ASSERT_TRUE(simple_util::GetMTime(simple_index_file.GetIndexFilePath(),
220                                     &fake_cache_mtime));
221   SimpleIndexLoadResult load_index_result;
222   simple_index_file.LoadIndexEntries(fake_cache_mtime,
223                                      GetCallback(),
224                                      &load_index_result);
225   base::RunLoop().RunUntilIdle();
226
227   EXPECT_TRUE(base::PathExists(simple_index_file.GetIndexFilePath()));
228   ASSERT_TRUE(callback_called());
229   EXPECT_TRUE(load_index_result.did_load);
230   EXPECT_FALSE(load_index_result.flush_required);
231
232   EXPECT_EQ(kNumHashes, load_index_result.entries.size());
233   for (size_t i = 0; i < kNumHashes; ++i)
234     EXPECT_EQ(1U, load_index_result.entries.count(kHashes[i]));
235 }
236
237 TEST_F(SimpleIndexFileTest, LoadCorruptIndex) {
238   base::ScopedTempDir cache_dir;
239   ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
240
241   WrappedSimpleIndexFile simple_index_file(cache_dir.path());
242   ASSERT_TRUE(simple_index_file.CreateIndexFileDirectory());
243   const base::FilePath& index_path = simple_index_file.GetIndexFilePath();
244   const std::string kDummyData = "nothing to be seen here";
245   EXPECT_EQ(
246       implicit_cast<int>(kDummyData.size()),
247       file_util::WriteFile(index_path, kDummyData.data(), kDummyData.size()));
248   base::Time fake_cache_mtime;
249   ASSERT_TRUE(simple_util::GetMTime(simple_index_file.GetIndexFilePath(),
250                                     &fake_cache_mtime));
251   EXPECT_FALSE(WrappedSimpleIndexFile::LegacyIsIndexFileStale(fake_cache_mtime,
252                                                               index_path));
253
254   SimpleIndexLoadResult load_index_result;
255   simple_index_file.LoadIndexEntries(fake_cache_mtime,
256                                      GetCallback(),
257                                      &load_index_result);
258   base::RunLoop().RunUntilIdle();
259
260   EXPECT_FALSE(base::PathExists(index_path));
261   ASSERT_TRUE(callback_called());
262   EXPECT_TRUE(load_index_result.did_load);
263   EXPECT_TRUE(load_index_result.flush_required);
264 }
265
266 // Tests that after an upgrade the backend has the index file put in place.
267 TEST_F(SimpleIndexFileTest, SimpleCacheUpgrade) {
268   base::ScopedTempDir cache_dir;
269   ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
270   const base::FilePath cache_path = cache_dir.path();
271
272   // Write an old fake index file.
273   base::File file(cache_path.AppendASCII("index"),
274                   base::File::FLAG_CREATE | base::File::FLAG_WRITE);
275   ASSERT_TRUE(file.IsValid());
276   disk_cache::FakeIndexData file_contents;
277   file_contents.initial_magic_number = disk_cache::kSimpleInitialMagicNumber;
278   file_contents.version = 5;
279   int bytes_written = file.Write(0, reinterpret_cast<char*>(&file_contents),
280                                  sizeof(file_contents));
281   ASSERT_EQ((int)sizeof(file_contents), bytes_written);
282   file.Close();
283
284   // Write the index file. The format is incorrect, but for transitioning from
285   // v5 it does not matter.
286   const std::string index_file_contents("incorrectly serialized data");
287   const base::FilePath old_index_file =
288       cache_path.AppendASCII("the-real-index");
289   ASSERT_EQ(implicit_cast<int>(index_file_contents.size()),
290             file_util::WriteFile(old_index_file,
291                                  index_file_contents.data(),
292                                  index_file_contents.size()));
293
294   // Upgrade the cache.
295   ASSERT_TRUE(disk_cache::UpgradeSimpleCacheOnDisk(cache_path));
296
297   // Create the backend and initiate index flush by destroying the backend.
298   base::Thread cache_thread("CacheThread");
299   ASSERT_TRUE(cache_thread.StartWithOptions(
300       base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
301   disk_cache::SimpleBackendImpl* simple_cache =
302       new disk_cache::SimpleBackendImpl(cache_path,
303                                         0,
304                                         net::DISK_CACHE,
305                                         cache_thread.message_loop_proxy().get(),
306                                         NULL);
307   net::TestCompletionCallback cb;
308   int rv = simple_cache->Init(cb.callback());
309   EXPECT_EQ(net::OK, cb.GetResult(rv));
310   rv = simple_cache->index()->ExecuteWhenReady(cb.callback());
311   EXPECT_EQ(net::OK, cb.GetResult(rv));
312   delete simple_cache;
313
314   // The backend flushes the index on destruction and does so on the cache
315   // thread, wait for the flushing to finish by posting a callback to the cache
316   // thread after that.
317   MessageLoopHelper helper;
318   CallbackTest cb_shutdown(&helper, false);
319   cache_thread.message_loop_proxy()->PostTask(
320       FROM_HERE,
321       base::Bind(&CallbackTest::Run, base::Unretained(&cb_shutdown), net::OK));
322   helper.WaitUntilCacheIoFinished(1);
323
324   // Verify that the index file exists.
325   const base::FilePath& index_file_path =
326       cache_path.AppendASCII("index-dir").AppendASCII("the-real-index");
327   EXPECT_TRUE(base::PathExists(index_file_path));
328
329   // Verify that the version of the index file is correct.
330   std::string contents;
331   EXPECT_TRUE(base::ReadFileToString(index_file_path, &contents));
332   base::Time when_index_last_saw_cache;
333   SimpleIndexLoadResult deserialize_result;
334   WrappedSimpleIndexFile::Deserialize(contents.data(),
335                                       contents.size(),
336                                       &when_index_last_saw_cache,
337                                       &deserialize_result);
338   EXPECT_TRUE(deserialize_result.did_load);
339 }
340
341 #endif  // defined(OS_POSIX)
342
343 }  // namespace disk_cache