1// Copyright 2013 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 "net/disk_cache/simple/simple_version_upgrade.h"
6
7#include "base/basictypes.h"
8#include "base/files/file_path.h"
9#include "base/files/file_util.h"
10#include "base/files/scoped_temp_dir.h"
11#include "base/format_macros.h"
12#include "base/strings/stringprintf.h"
13#include "net/base/net_errors.h"
14#include "net/disk_cache/simple/simple_backend_version.h"
15#include "net/disk_cache/simple/simple_entry_format_history.h"
16#include "testing/gtest/include/gtest/gtest.h"
17
18// The migration process relies on ability to rename newly created files, which
19// could be problematic on Windows XP.
20#if defined(OS_POSIX)
21
22namespace {
23
24// Same as |disk_cache::kSimpleInitialMagicNumber|.
25const uint64 kSimpleInitialMagicNumber = GG_UINT64_C(0xfcfb6d1ba7725c30);
26
27// The "fake index" file that cache backends use to distinguish whether the
28// cache belongs to one backend or another.
29const char kFakeIndexFileName[] = "index";
30
31// Same as |SimpleIndexFile::kIndexFileName|.
32const char kIndexFileName[] = "the-real-index";
33
34bool WriteFakeIndexFileV5(const base::FilePath& cache_path) {
35  disk_cache::FakeIndexData data;
36  data.version = 5;
37  data.initial_magic_number = kSimpleInitialMagicNumber;
38  data.unused_must_be_zero1 = 0;
39  data.unused_must_be_zero2 = 0;
40  const base::FilePath file_name = cache_path.AppendASCII("index");
41  return sizeof(data) ==
42         base::WriteFile(
43             file_name, reinterpret_cast<const char*>(&data), sizeof(data));
44}
45
46TEST(SimpleVersionUpgradeTest, FailsToMigrateBackwards) {
47  base::ScopedTempDir cache_dir;
48  ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
49  const base::FilePath cache_path = cache_dir.path();
50
51  disk_cache::FakeIndexData data;
52  data.version = 100500;
53  data.initial_magic_number = kSimpleInitialMagicNumber;
54  data.unused_must_be_zero1 = 0;
55  data.unused_must_be_zero2 = 0;
56  const base::FilePath file_name = cache_path.AppendASCII(kFakeIndexFileName);
57  ASSERT_EQ(implicit_cast<int>(sizeof(data)),
58            base::WriteFile(
59                file_name, reinterpret_cast<const char*>(&data), sizeof(data)));
60  EXPECT_FALSE(disk_cache::UpgradeSimpleCacheOnDisk(cache_dir.path()));
61}
62
63TEST(SimpleVersionUpgradeTest, FakeIndexVersionGetsUpdated) {
64  base::ScopedTempDir cache_dir;
65  ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
66  const base::FilePath cache_path = cache_dir.path();
67
68  WriteFakeIndexFileV5(cache_path);
69  const std::string file_contents("incorrectly serialized data");
70  const base::FilePath index_file = cache_path.AppendASCII(kIndexFileName);
71  ASSERT_EQ(implicit_cast<int>(file_contents.size()),
72            base::WriteFile(
73                index_file, file_contents.data(), file_contents.size()));
74
75  // Upgrade.
76  ASSERT_TRUE(disk_cache::UpgradeSimpleCacheOnDisk(cache_path));
77
78  // Check that the version in the fake index file is updated.
79  std::string new_fake_index_contents;
80  ASSERT_TRUE(base::ReadFileToString(cache_path.AppendASCII(kFakeIndexFileName),
81                                     &new_fake_index_contents));
82  const disk_cache::FakeIndexData* fake_index_header;
83  EXPECT_EQ(sizeof(*fake_index_header), new_fake_index_contents.size());
84  fake_index_header = reinterpret_cast<const disk_cache::FakeIndexData*>(
85      new_fake_index_contents.data());
86  EXPECT_EQ(disk_cache::kSimpleVersion, fake_index_header->version);
87  EXPECT_EQ(kSimpleInitialMagicNumber, fake_index_header->initial_magic_number);
88}
89
90TEST(SimpleVersionUpgradeTest, UpgradeV5V6IndexMustDisappear) {
91  base::ScopedTempDir cache_dir;
92  ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
93  const base::FilePath cache_path = cache_dir.path();
94
95  WriteFakeIndexFileV5(cache_path);
96  const std::string file_contents("incorrectly serialized data");
97  const base::FilePath index_file = cache_path.AppendASCII(kIndexFileName);
98  ASSERT_EQ(implicit_cast<int>(file_contents.size()),
99            base::WriteFile(
100                index_file, file_contents.data(), file_contents.size()));
101
102  // Create a few entry-like files.
103  const uint64 kEntries = 5;
104  for (uint64 entry_hash = 0; entry_hash < kEntries; ++entry_hash) {
105    for (int index = 0; index < 3; ++index) {
106      std::string file_name =
107          base::StringPrintf("%016" PRIx64 "_%1d", entry_hash, index);
108      std::string entry_contents =
109          file_contents +
110          base::StringPrintf(" %" PRIx64, implicit_cast<uint64>(entry_hash));
111      ASSERT_EQ(implicit_cast<int>(entry_contents.size()),
112                base::WriteFile(cache_path.AppendASCII(file_name),
113                                     entry_contents.data(),
114                                     entry_contents.size()));
115    }
116  }
117
118  // Upgrade.
119  ASSERT_TRUE(disk_cache::UpgradeIndexV5V6(cache_path));
120
121  // Check that the old index disappeared but the files remain unchanged.
122  EXPECT_FALSE(base::PathExists(index_file));
123  for (uint64 entry_hash = 0; entry_hash < kEntries; ++entry_hash) {
124    for (int index = 0; index < 3; ++index) {
125      std::string file_name =
126          base::StringPrintf("%016" PRIx64 "_%1d", entry_hash, index);
127      std::string expected_contents =
128          file_contents +
129          base::StringPrintf(" %" PRIx64, implicit_cast<uint64>(entry_hash));
130      std::string real_contents;
131      EXPECT_TRUE(base::ReadFileToString(cache_path.AppendASCII(file_name),
132                                         &real_contents));
133      EXPECT_EQ(expected_contents, real_contents);
134    }
135  }
136}
137
138}  // namespace
139
140#endif  // defined(OS_POSIX)
141