1// Copyright 2014 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 <algorithm>
6#include <functional>
7#include <limits>
8#include <string>
9#include <vector>
10
11#include "base/files/file.h"
12#include "base/files/file_path.h"
13#include "base/files/file_util.h"
14#include "base/files/scoped_temp_dir.h"
15#include "base/stl_util.h"
16#include "content/browser/fileapi/sandbox_database_test_helper.h"
17#include "storage/browser/fileapi/sandbox_origin_database.h"
18#include "storage/common/fileapi/file_system_util.h"
19#include "testing/gtest/include/gtest/gtest.h"
20#include "third_party/leveldatabase/src/db/filename.h"
21#include "third_party/leveldatabase/src/include/leveldb/db.h"
22
23using storage::SandboxOriginDatabase;
24
25namespace content {
26
27namespace {
28const base::FilePath::CharType kFileSystemDirName[] =
29    FILE_PATH_LITERAL("File System");
30const base::FilePath::CharType kOriginDatabaseName[] =
31    FILE_PATH_LITERAL("Origins");
32}  // namespace
33
34TEST(SandboxOriginDatabaseTest, BasicTest) {
35  base::ScopedTempDir dir;
36  ASSERT_TRUE(dir.CreateUniqueTempDir());
37  const base::FilePath kFSDir = dir.path().Append(kFileSystemDirName);
38  EXPECT_FALSE(base::PathExists(kFSDir));
39  EXPECT_TRUE(base::CreateDirectory(kFSDir));
40
41  SandboxOriginDatabase database(kFSDir, NULL);
42  std::string origin("origin");
43
44  EXPECT_FALSE(database.HasOriginPath(origin));
45  // Double-check to make sure that had no side effects.
46  EXPECT_FALSE(database.HasOriginPath(origin));
47
48  base::FilePath path0;
49  base::FilePath path1;
50
51  // Empty strings aren't valid origins.
52  EXPECT_FALSE(database.GetPathForOrigin(std::string(), &path0));
53
54  EXPECT_TRUE(database.GetPathForOrigin(origin, &path0));
55  EXPECT_TRUE(database.HasOriginPath(origin));
56  EXPECT_TRUE(database.GetPathForOrigin(origin, &path1));
57  EXPECT_FALSE(path0.empty());
58  EXPECT_FALSE(path1.empty());
59  EXPECT_EQ(path0, path1);
60
61  EXPECT_TRUE(base::PathExists(kFSDir.Append(kOriginDatabaseName)));
62}
63
64TEST(SandboxOriginDatabaseTest, TwoPathTest) {
65  base::ScopedTempDir dir;
66  ASSERT_TRUE(dir.CreateUniqueTempDir());
67  const base::FilePath kFSDir = dir.path().Append(kFileSystemDirName);
68  EXPECT_FALSE(base::PathExists(kFSDir));
69  EXPECT_TRUE(base::CreateDirectory(kFSDir));
70
71  SandboxOriginDatabase database(kFSDir, NULL);
72  std::string origin0("origin0");
73  std::string origin1("origin1");
74
75  EXPECT_FALSE(database.HasOriginPath(origin0));
76  EXPECT_FALSE(database.HasOriginPath(origin1));
77
78  base::FilePath path0;
79  base::FilePath path1;
80  EXPECT_TRUE(database.GetPathForOrigin(origin0, &path0));
81  EXPECT_TRUE(database.HasOriginPath(origin0));
82  EXPECT_FALSE(database.HasOriginPath(origin1));
83  EXPECT_TRUE(database.GetPathForOrigin(origin1, &path1));
84  EXPECT_TRUE(database.HasOriginPath(origin1));
85  EXPECT_FALSE(path0.empty());
86  EXPECT_FALSE(path1.empty());
87  EXPECT_NE(path0, path1);
88
89  EXPECT_TRUE(base::PathExists(kFSDir.Append(kOriginDatabaseName)));
90}
91
92TEST(SandboxOriginDatabaseTest, DropDatabaseTest) {
93  base::ScopedTempDir dir;
94  ASSERT_TRUE(dir.CreateUniqueTempDir());
95  const base::FilePath kFSDir = dir.path().Append(kFileSystemDirName);
96  EXPECT_FALSE(base::PathExists(kFSDir));
97  EXPECT_TRUE(base::CreateDirectory(kFSDir));
98
99  SandboxOriginDatabase database(kFSDir, NULL);
100  std::string origin("origin");
101
102  EXPECT_FALSE(database.HasOriginPath(origin));
103
104  base::FilePath path0;
105  EXPECT_TRUE(database.GetPathForOrigin(origin, &path0));
106  EXPECT_TRUE(database.HasOriginPath(origin));
107  EXPECT_FALSE(path0.empty());
108
109  EXPECT_TRUE(base::PathExists(kFSDir.Append(kOriginDatabaseName)));
110
111  database.DropDatabase();
112
113  base::FilePath path1;
114  EXPECT_TRUE(database.HasOriginPath(origin));
115  EXPECT_TRUE(database.GetPathForOrigin(origin, &path1));
116  EXPECT_FALSE(path1.empty());
117  EXPECT_EQ(path0, path1);
118}
119
120TEST(SandboxOriginDatabaseTest, DeleteOriginTest) {
121  base::ScopedTempDir dir;
122  ASSERT_TRUE(dir.CreateUniqueTempDir());
123  const base::FilePath kFSDir = dir.path().Append(kFileSystemDirName);
124  EXPECT_FALSE(base::PathExists(kFSDir));
125  EXPECT_TRUE(base::CreateDirectory(kFSDir));
126
127  SandboxOriginDatabase database(kFSDir, NULL);
128  std::string origin("origin");
129
130  EXPECT_FALSE(database.HasOriginPath(origin));
131  EXPECT_TRUE(database.RemovePathForOrigin(origin));
132
133  base::FilePath path0;
134  EXPECT_TRUE(database.GetPathForOrigin(origin, &path0));
135  EXPECT_TRUE(database.HasOriginPath(origin));
136  EXPECT_FALSE(path0.empty());
137
138  EXPECT_TRUE(database.RemovePathForOrigin(origin));
139  EXPECT_FALSE(database.HasOriginPath(origin));
140
141  base::FilePath path1;
142  EXPECT_TRUE(database.GetPathForOrigin(origin, &path1));
143  EXPECT_FALSE(path1.empty());
144  EXPECT_NE(path0, path1);
145}
146
147TEST(SandboxOriginDatabaseTest, ListOriginsTest) {
148  base::ScopedTempDir dir;
149  ASSERT_TRUE(dir.CreateUniqueTempDir());
150  const base::FilePath kFSDir = dir.path().Append(kFileSystemDirName);
151  EXPECT_FALSE(base::PathExists(kFSDir));
152  EXPECT_TRUE(base::CreateDirectory(kFSDir));
153
154  std::vector<SandboxOriginDatabase::OriginRecord> origins;
155
156  SandboxOriginDatabase database(kFSDir, NULL);
157  EXPECT_TRUE(database.ListAllOrigins(&origins));
158  EXPECT_TRUE(origins.empty());
159  origins.clear();
160
161  std::string origin0("origin0");
162  std::string origin1("origin1");
163
164  EXPECT_FALSE(database.HasOriginPath(origin0));
165  EXPECT_FALSE(database.HasOriginPath(origin1));
166
167  base::FilePath path0;
168  base::FilePath path1;
169  EXPECT_TRUE(database.GetPathForOrigin(origin0, &path0));
170  EXPECT_TRUE(database.ListAllOrigins(&origins));
171  EXPECT_EQ(origins.size(), 1UL);
172  EXPECT_EQ(origins[0].origin, origin0);
173  EXPECT_EQ(origins[0].path, path0);
174  origins.clear();
175  EXPECT_TRUE(database.GetPathForOrigin(origin1, &path1));
176  EXPECT_TRUE(database.ListAllOrigins(&origins));
177  EXPECT_EQ(origins.size(), 2UL);
178  if (origins[0].origin == origin0) {
179    EXPECT_EQ(origins[0].path, path0);
180    EXPECT_EQ(origins[1].origin, origin1);
181    EXPECT_EQ(origins[1].path, path1);
182  } else {
183    EXPECT_EQ(origins[0].origin, origin1);
184    EXPECT_EQ(origins[0].path, path1);
185    EXPECT_EQ(origins[1].origin, origin0);
186    EXPECT_EQ(origins[1].path, path0);
187  }
188}
189
190TEST(SandboxOriginDatabaseTest, DatabaseRecoveryTest) {
191  // Checks if SandboxOriginDatabase properly handles database corruption.
192  // In this test, we'll register some origins to the origin database, then
193  // corrupt database and its log file.
194  // After repairing, the origin database should be consistent even when some
195  // entries lost.
196
197  base::ScopedTempDir dir;
198  ASSERT_TRUE(dir.CreateUniqueTempDir());
199  const base::FilePath kFSDir = dir.path().Append(kFileSystemDirName);
200  const base::FilePath kDBDir = kFSDir.Append(kOriginDatabaseName);
201  EXPECT_FALSE(base::PathExists(kFSDir));
202  EXPECT_TRUE(base::CreateDirectory(kFSDir));
203
204  const std::string kOrigins[] = {
205    "foo.example.com",
206    "bar.example.com",
207    "baz.example.com",
208    "hoge.example.com",
209    "fuga.example.com",
210  };
211
212  scoped_ptr<SandboxOriginDatabase> database(
213      new SandboxOriginDatabase(kFSDir, NULL));
214  for (size_t i = 0; i < arraysize(kOrigins); ++i) {
215    base::FilePath path;
216    EXPECT_FALSE(database->HasOriginPath(kOrigins[i]));
217    EXPECT_TRUE(database->GetPathForOrigin(kOrigins[i], &path));
218    EXPECT_FALSE(path.empty());
219    EXPECT_TRUE(database->GetPathForOrigin(kOrigins[i], &path));
220
221    if (i != 1)
222      EXPECT_TRUE(base::CreateDirectory(kFSDir.Append(path)));
223  }
224  database.reset();
225
226  const base::FilePath kGarbageDir = kFSDir.AppendASCII("foo");
227  const base::FilePath kGarbageFile = kGarbageDir.AppendASCII("bar");
228  EXPECT_TRUE(base::CreateDirectory(kGarbageDir));
229  base::File file(kGarbageFile,
230                  base::File::FLAG_CREATE | base::File::FLAG_WRITE);
231  EXPECT_TRUE(file.IsValid());
232  file.Close();
233
234  // Corrupt database itself and last log entry to drop last 1 database
235  // operation.  The database should detect the corruption and should recover
236  // its consistency after recovery.
237  CorruptDatabase(kDBDir, leveldb::kDescriptorFile,
238                  0, std::numeric_limits<size_t>::max());
239  CorruptDatabase(kDBDir, leveldb::kLogFile, -1, 1);
240
241  base::FilePath path;
242  database.reset(new SandboxOriginDatabase(kFSDir, NULL));
243  std::vector<SandboxOriginDatabase::OriginRecord> origins_in_db;
244  EXPECT_TRUE(database->ListAllOrigins(&origins_in_db));
245
246  // Expect all but last added origin will be repaired back, and kOrigins[1]
247  // should be dropped due to absence of backing directory.
248  EXPECT_EQ(arraysize(kOrigins) - 2, origins_in_db.size());
249
250  const std::string kOrigin("piyo.example.org");
251  EXPECT_FALSE(database->HasOriginPath(kOrigin));
252  EXPECT_TRUE(database->GetPathForOrigin(kOrigin, &path));
253  EXPECT_FALSE(path.empty());
254  EXPECT_TRUE(database->HasOriginPath(kOrigin));
255
256  EXPECT_FALSE(base::PathExists(kGarbageFile));
257  EXPECT_FALSE(base::PathExists(kGarbageDir));
258}
259
260TEST(SandboxOriginDatabaseTest, DatabaseRecoveryForMissingDBFileTest) {
261  const leveldb::FileType kLevelDBFileTypes[] = {
262    leveldb::kLogFile,
263    leveldb::kDBLockFile,
264    leveldb::kTableFile,
265    leveldb::kDescriptorFile,
266    leveldb::kCurrentFile,
267    leveldb::kTempFile,
268    leveldb::kInfoLogFile,
269  };
270
271  for (size_t i = 0; i < arraysize(kLevelDBFileTypes); ++i) {
272    base::ScopedTempDir dir;
273    ASSERT_TRUE(dir.CreateUniqueTempDir());
274    const base::FilePath kFSDir = dir.path().Append(kFileSystemDirName);
275    const base::FilePath kDBDir = kFSDir.Append(kOriginDatabaseName);
276    EXPECT_FALSE(base::PathExists(kFSDir));
277    EXPECT_TRUE(base::CreateDirectory(kFSDir));
278
279    const std::string kOrigin = "foo.example.com";
280    base::FilePath path;
281
282    scoped_ptr<SandboxOriginDatabase> database(
283        new SandboxOriginDatabase(kFSDir, NULL));
284    EXPECT_FALSE(database->HasOriginPath(kOrigin));
285    EXPECT_TRUE(database->GetPathForOrigin(kOrigin, &path));
286    EXPECT_FALSE(path.empty());
287    EXPECT_TRUE(database->GetPathForOrigin(kOrigin, &path));
288    EXPECT_TRUE(base::CreateDirectory(kFSDir.Append(path)));
289    database.reset();
290
291    DeleteDatabaseFile(kDBDir, kLevelDBFileTypes[i]);
292
293    database.reset(new SandboxOriginDatabase(kFSDir, NULL));
294    std::vector<SandboxOriginDatabase::OriginRecord> origins_in_db;
295    EXPECT_TRUE(database->ListAllOrigins(&origins_in_db));
296
297    const std::string kOrigin2("piyo.example.org");
298    EXPECT_FALSE(database->HasOriginPath(kOrigin2));
299    EXPECT_TRUE(database->GetPathForOrigin(kOrigin2, &path));
300    EXPECT_FALSE(path.empty());
301    EXPECT_TRUE(database->HasOriginPath(kOrigin2));
302  }
303}
304
305}  // namespace content
306