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 "storage/browser/fileapi/sandbox_directory_database.h"
6
7#include <math.h>
8#include <limits>
9
10#include "base/files/file.h"
11#include "base/files/file_util.h"
12#include "base/files/scoped_temp_dir.h"
13#include "base/memory/scoped_ptr.h"
14#include "base/strings/string_number_conversions.h"
15#include "base/strings/string_util.h"
16#include "content/browser/fileapi/sandbox_database_test_helper.h"
17#include "storage/common/fileapi/file_system_util.h"
18#include "testing/gtest/include/gtest/gtest.h"
19#include "third_party/leveldatabase/src/include/leveldb/db.h"
20
21#define FPL(x) FILE_PATH_LITERAL(x)
22
23using storage::FilePathToString;
24using storage::SandboxDirectoryDatabase;
25
26namespace content {
27
28namespace {
29const base::FilePath::CharType kDirectoryDatabaseName[] = FPL("Paths");
30}
31
32class SandboxDirectoryDatabaseTest : public testing::Test {
33 public:
34  typedef SandboxDirectoryDatabase::FileId FileId;
35  typedef SandboxDirectoryDatabase::FileInfo FileInfo;
36
37  SandboxDirectoryDatabaseTest() {
38    EXPECT_TRUE(base_.CreateUniqueTempDir());
39    InitDatabase();
40  }
41
42  SandboxDirectoryDatabase* db() {
43    return db_.get();
44  }
45
46  void InitDatabase() {
47    // Call CloseDatabase() to avoid having multiple database instances for
48    // single directory at once.
49    CloseDatabase();
50    db_.reset(new SandboxDirectoryDatabase(path(), NULL));
51  }
52
53  void CloseDatabase() {
54    db_.reset();
55  }
56
57  base::File::Error AddFileInfo(
58      FileId parent_id, const base::FilePath::StringType& name) {
59    FileId file_id;
60    FileInfo info;
61    info.parent_id = parent_id;
62    info.name = name;
63    return db_->AddFileInfo(info, &file_id);
64  }
65
66  void CreateDirectory(FileId parent_id,
67                       const base::FilePath::StringType& name,
68                       FileId* file_id_out) {
69    FileInfo info;
70    info.parent_id = parent_id;
71    info.name = name;
72    ASSERT_EQ(base::File::FILE_OK, db_->AddFileInfo(info, file_id_out));
73  }
74
75  void CreateFile(FileId parent_id,
76                  const base::FilePath::StringType& name,
77                  const base::FilePath::StringType& data_path,
78                  FileId* file_id_out) {
79    FileId file_id;
80
81    FileInfo info;
82    info.parent_id = parent_id;
83    info.name = name;
84    info.data_path = base::FilePath(data_path).NormalizePathSeparators();
85    ASSERT_EQ(base::File::FILE_OK, db_->AddFileInfo(info, &file_id));
86
87    base::FilePath local_path = path().Append(data_path);
88    if (!base::DirectoryExists(local_path.DirName()))
89      ASSERT_TRUE(base::CreateDirectory(local_path.DirName()));
90
91    base::File file(local_path,
92                    base::File::FLAG_CREATE | base::File::FLAG_WRITE);
93    ASSERT_TRUE(file.IsValid());
94    ASSERT_TRUE(file.created());
95
96    if (file_id_out)
97      *file_id_out = file_id;
98  }
99
100  void ClearDatabaseAndDirectory() {
101    db_.reset();
102    ASSERT_TRUE(base::DeleteFile(path(), true /* recursive */));
103    ASSERT_TRUE(base::CreateDirectory(path()));
104    db_.reset(new SandboxDirectoryDatabase(path(), NULL));
105  }
106
107  bool RepairDatabase() {
108    return db()->RepairDatabase(
109        FilePathToString(path().Append(kDirectoryDatabaseName)));
110  }
111
112  const base::FilePath& path() {
113    return base_.path();
114  }
115
116  // Makes link from |parent_id| to |child_id| with |name|.
117  void MakeHierarchyLink(FileId parent_id,
118                         FileId child_id,
119                         const base::FilePath::StringType& name) {
120    ASSERT_TRUE(db()->db_->Put(
121        leveldb::WriteOptions(),
122        "CHILD_OF:" + base::Int64ToString(parent_id) + ":" +
123        FilePathToString(base::FilePath(name)),
124        base::Int64ToString(child_id)).ok());
125  }
126
127  // Deletes link from parent of |file_id| to |file_id|.
128  void DeleteHierarchyLink(FileId file_id) {
129    FileInfo file_info;
130    ASSERT_TRUE(db()->GetFileInfo(file_id, &file_info));
131    ASSERT_TRUE(db()->db_->Delete(
132        leveldb::WriteOptions(),
133        "CHILD_OF:" + base::Int64ToString(file_info.parent_id) + ":" +
134        FilePathToString(base::FilePath(file_info.name))).ok());
135  }
136
137 protected:
138  // Common temp base for nondestructive uses.
139  base::ScopedTempDir base_;
140  scoped_ptr<SandboxDirectoryDatabase> db_;
141
142 private:
143  DISALLOW_COPY_AND_ASSIGN(SandboxDirectoryDatabaseTest);
144};
145
146TEST_F(SandboxDirectoryDatabaseTest, TestMissingFileGetInfo) {
147  FileId file_id = 888;
148  FileInfo info;
149  EXPECT_FALSE(db()->GetFileInfo(file_id, &info));
150}
151
152TEST_F(SandboxDirectoryDatabaseTest, TestGetRootFileInfoBeforeCreate) {
153  FileId file_id = 0;
154  FileInfo info;
155  EXPECT_TRUE(db()->GetFileInfo(file_id, &info));
156  EXPECT_EQ(0, info.parent_id);
157  EXPECT_TRUE(info.name.empty());
158  EXPECT_TRUE(info.data_path.empty());
159}
160
161TEST_F(SandboxDirectoryDatabaseTest, TestMissingParentAddFileInfo) {
162  FileId parent_id = 7;
163  EXPECT_EQ(base::File::FILE_ERROR_NOT_A_DIRECTORY,
164            AddFileInfo(parent_id, FILE_PATH_LITERAL("foo")));
165}
166
167TEST_F(SandboxDirectoryDatabaseTest, TestAddNameClash) {
168  FileInfo info;
169  FileId file_id;
170  info.parent_id = 0;
171  info.name = FILE_PATH_LITERAL("dir 0");
172  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id));
173
174  // Check for name clash in the root directory.
175  base::FilePath::StringType name = info.name;
176  EXPECT_EQ(base::File::FILE_ERROR_EXISTS, AddFileInfo(0, name));
177  name = FILE_PATH_LITERAL("dir 1");
178  EXPECT_EQ(base::File::FILE_OK, AddFileInfo(0, name));
179
180  name = FILE_PATH_LITERAL("subdir 0");
181  EXPECT_EQ(base::File::FILE_OK, AddFileInfo(file_id, name));
182
183  // Check for name clash in a subdirectory.
184  EXPECT_EQ(base::File::FILE_ERROR_EXISTS, AddFileInfo(file_id, name));
185  name = FILE_PATH_LITERAL("subdir 1");
186  EXPECT_EQ(base::File::FILE_OK, AddFileInfo(file_id, name));
187}
188
189TEST_F(SandboxDirectoryDatabaseTest, TestRenameNoMoveNameClash) {
190  FileInfo info;
191  FileId file_id0;
192  base::FilePath::StringType name0 = FILE_PATH_LITERAL("foo");
193  base::FilePath::StringType name1 = FILE_PATH_LITERAL("bar");
194  base::FilePath::StringType name2 = FILE_PATH_LITERAL("bas");
195  info.parent_id = 0;
196  info.name = name0;
197  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id0));
198  EXPECT_EQ(base::File::FILE_OK, AddFileInfo(0, name1));
199  info.name = name1;
200  EXPECT_FALSE(db()->UpdateFileInfo(file_id0, info));
201  info.name = name2;
202  EXPECT_TRUE(db()->UpdateFileInfo(file_id0, info));
203}
204
205TEST_F(SandboxDirectoryDatabaseTest, TestMoveSameNameNameClash) {
206  FileInfo info;
207  FileId file_id0;
208  FileId file_id1;
209  base::FilePath::StringType name0 = FILE_PATH_LITERAL("foo");
210  base::FilePath::StringType name1 = FILE_PATH_LITERAL("bar");
211  info.parent_id = 0;
212  info.name = name0;
213  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id0));
214  info.parent_id = file_id0;
215  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id1));
216  info.parent_id = 0;
217  EXPECT_FALSE(db()->UpdateFileInfo(file_id1, info));
218  info.name = name1;
219  EXPECT_TRUE(db()->UpdateFileInfo(file_id1, info));
220}
221
222TEST_F(SandboxDirectoryDatabaseTest, TestMoveRenameNameClash) {
223  FileInfo info;
224  FileId file_id0;
225  FileId file_id1;
226  base::FilePath::StringType name0 = FILE_PATH_LITERAL("foo");
227  base::FilePath::StringType name1 = FILE_PATH_LITERAL("bar");
228  base::FilePath::StringType name2 = FILE_PATH_LITERAL("bas");
229  info.parent_id = 0;
230  info.name = name0;
231  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id0));
232  info.parent_id = file_id0;
233  info.name = name1;
234  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id1));
235  info.parent_id = 0;
236  info.name = name0;
237  EXPECT_FALSE(db()->UpdateFileInfo(file_id1, info));
238  info.name = name1;
239  EXPECT_TRUE(db()->UpdateFileInfo(file_id1, info));
240  // Also test a successful move+rename.
241  info.parent_id = file_id0;
242  info.name = name2;
243  EXPECT_TRUE(db()->UpdateFileInfo(file_id1, info));
244}
245
246TEST_F(SandboxDirectoryDatabaseTest, TestRemoveWithChildren) {
247  FileInfo info;
248  FileId file_id0;
249  FileId file_id1;
250  info.parent_id = 0;
251  info.name = FILE_PATH_LITERAL("foo");
252  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id0));
253  info.parent_id = file_id0;
254  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id1));
255  EXPECT_FALSE(db()->RemoveFileInfo(file_id0));
256  EXPECT_TRUE(db()->RemoveFileInfo(file_id1));
257  EXPECT_TRUE(db()->RemoveFileInfo(file_id0));
258}
259
260TEST_F(SandboxDirectoryDatabaseTest, TestGetChildWithName) {
261  FileInfo info;
262  FileId file_id0;
263  FileId file_id1;
264  base::FilePath::StringType name0 = FILE_PATH_LITERAL("foo");
265  base::FilePath::StringType name1 = FILE_PATH_LITERAL("bar");
266  info.parent_id = 0;
267  info.name = name0;
268  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id0));
269  info.parent_id = file_id0;
270  info.name = name1;
271  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id1));
272  EXPECT_NE(file_id0, file_id1);
273
274  FileId check_file_id;
275  EXPECT_FALSE(db()->GetChildWithName(0, name1, &check_file_id));
276  EXPECT_TRUE(db()->GetChildWithName(0, name0, &check_file_id));
277  EXPECT_EQ(file_id0, check_file_id);
278  EXPECT_FALSE(db()->GetChildWithName(file_id0, name0, &check_file_id));
279  EXPECT_TRUE(db()->GetChildWithName(file_id0, name1, &check_file_id));
280  EXPECT_EQ(file_id1, check_file_id);
281}
282
283TEST_F(SandboxDirectoryDatabaseTest, TestGetFileWithPath) {
284  FileInfo info;
285  FileId file_id0;
286  FileId file_id1;
287  FileId file_id2;
288  base::FilePath::StringType name0 = FILE_PATH_LITERAL("foo");
289  base::FilePath::StringType name1 = FILE_PATH_LITERAL("bar");
290  base::FilePath::StringType name2 = FILE_PATH_LITERAL("dog");
291
292  info.parent_id = 0;
293  info.name = name0;
294  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id0));
295  info.parent_id = file_id0;
296  info.name = name1;
297  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id1));
298  EXPECT_NE(file_id0, file_id1);
299  info.parent_id = file_id1;
300  info.name = name2;
301  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id2));
302  EXPECT_NE(file_id0, file_id2);
303  EXPECT_NE(file_id1, file_id2);
304
305  FileId check_file_id;
306  base::FilePath path = base::FilePath(name0);
307  EXPECT_TRUE(db()->GetFileWithPath(path, &check_file_id));
308  EXPECT_EQ(file_id0, check_file_id);
309
310  path = path.Append(name1);
311  EXPECT_TRUE(db()->GetFileWithPath(path, &check_file_id));
312  EXPECT_EQ(file_id1, check_file_id);
313
314  path = path.Append(name2);
315  EXPECT_TRUE(db()->GetFileWithPath(path, &check_file_id));
316  EXPECT_EQ(file_id2, check_file_id);
317}
318
319TEST_F(SandboxDirectoryDatabaseTest, TestListChildren) {
320  // No children in the root.
321  std::vector<FileId> children;
322  EXPECT_TRUE(db()->ListChildren(0, &children));
323  EXPECT_TRUE(children.empty());
324
325  // One child in the root.
326  FileId file_id0;
327  FileInfo info;
328  info.parent_id = 0;
329  info.name = FILE_PATH_LITERAL("foo");
330  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id0));
331  EXPECT_TRUE(db()->ListChildren(0, &children));
332  EXPECT_EQ(children.size(), 1UL);
333  EXPECT_EQ(children[0], file_id0);
334
335  // Two children in the root.
336  FileId file_id1;
337  info.name = FILE_PATH_LITERAL("bar");
338  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id1));
339  EXPECT_TRUE(db()->ListChildren(0, &children));
340  EXPECT_EQ(2UL, children.size());
341  if (children[0] == file_id0) {
342    EXPECT_EQ(children[1], file_id1);
343  } else {
344    EXPECT_EQ(children[1], file_id0);
345    EXPECT_EQ(children[0], file_id1);
346  }
347
348  // No children in a subdirectory.
349  EXPECT_TRUE(db()->ListChildren(file_id0, &children));
350  EXPECT_TRUE(children.empty());
351
352  // One child in a subdirectory.
353  info.parent_id = file_id0;
354  info.name = FILE_PATH_LITERAL("foo");
355  FileId file_id2;
356  FileId file_id3;
357  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id2));
358  EXPECT_TRUE(db()->ListChildren(file_id0, &children));
359  EXPECT_EQ(1UL, children.size());
360  EXPECT_EQ(children[0], file_id2);
361
362  // Two children in a subdirectory.
363  info.name = FILE_PATH_LITERAL("bar");
364  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info, &file_id3));
365  EXPECT_TRUE(db()->ListChildren(file_id0, &children));
366  EXPECT_EQ(2UL, children.size());
367  if (children[0] == file_id2) {
368    EXPECT_EQ(children[1], file_id3);
369  } else {
370    EXPECT_EQ(children[1], file_id2);
371    EXPECT_EQ(children[0], file_id3);
372  }
373}
374
375TEST_F(SandboxDirectoryDatabaseTest, TestUpdateModificationTime) {
376  FileInfo info0;
377  FileId file_id;
378  info0.parent_id = 0;
379  info0.name = FILE_PATH_LITERAL("name");
380  info0.data_path = base::FilePath(FILE_PATH_LITERAL("fake path"));
381  info0.modification_time = base::Time::Now();
382  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info0, &file_id));
383  FileInfo info1;
384  EXPECT_TRUE(db()->GetFileInfo(file_id, &info1));
385  EXPECT_EQ(info0.name, info1.name);
386  EXPECT_EQ(info0.parent_id, info1.parent_id);
387  EXPECT_EQ(info0.data_path, info1.data_path);
388  EXPECT_EQ(
389      floor(info0.modification_time.ToDoubleT()),
390      info1.modification_time.ToDoubleT());
391
392  EXPECT_TRUE(db()->UpdateModificationTime(file_id, base::Time::UnixEpoch()));
393  EXPECT_TRUE(db()->GetFileInfo(file_id, &info1));
394  EXPECT_EQ(info0.name, info1.name);
395  EXPECT_EQ(info0.parent_id, info1.parent_id);
396  EXPECT_EQ(info0.data_path, info1.data_path);
397  EXPECT_NE(info0.modification_time, info1.modification_time);
398  EXPECT_EQ(
399      info1.modification_time.ToDoubleT(),
400      floor(base::Time::UnixEpoch().ToDoubleT()));
401
402  EXPECT_FALSE(db()->UpdateModificationTime(999, base::Time::UnixEpoch()));
403}
404
405TEST_F(SandboxDirectoryDatabaseTest, TestSimpleFileOperations) {
406  FileId file_id = 888;
407  FileInfo info0;
408  EXPECT_FALSE(db()->GetFileInfo(file_id, &info0));
409  info0.parent_id = 0;
410  info0.data_path = base::FilePath(FILE_PATH_LITERAL("foo"));
411  info0.name = FILE_PATH_LITERAL("file name");
412  info0.modification_time = base::Time::Now();
413  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info0, &file_id));
414  FileInfo info1;
415  EXPECT_TRUE(db()->GetFileInfo(file_id, &info1));
416  EXPECT_EQ(info0.parent_id, info1.parent_id);
417  EXPECT_EQ(info0.data_path, info1.data_path);
418  EXPECT_EQ(info0.name, info1.name);
419  EXPECT_EQ(
420      floor(info0.modification_time.ToDoubleT()),
421      info1.modification_time.ToDoubleT());
422}
423
424TEST_F(SandboxDirectoryDatabaseTest, TestOverwritingMoveFileSrcDirectory) {
425  FileId directory_id;
426  FileInfo info0;
427  info0.parent_id = 0;
428  info0.name = FILE_PATH_LITERAL("directory");
429  info0.modification_time = base::Time::Now();
430  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info0, &directory_id));
431
432  FileId file_id;
433  FileInfo info1;
434  info1.parent_id = 0;
435  info1.data_path = base::FilePath(FILE_PATH_LITERAL("bar"));
436  info1.name = FILE_PATH_LITERAL("file");
437  info1.modification_time = base::Time::UnixEpoch();
438  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info1, &file_id));
439
440  EXPECT_FALSE(db()->OverwritingMoveFile(directory_id, file_id));
441}
442
443TEST_F(SandboxDirectoryDatabaseTest, TestOverwritingMoveFileDestDirectory) {
444  FileId file_id;
445  FileInfo info0;
446  info0.parent_id = 0;
447  info0.name = FILE_PATH_LITERAL("file");
448  info0.data_path = base::FilePath(FILE_PATH_LITERAL("bar"));
449  info0.modification_time = base::Time::Now();
450  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info0, &file_id));
451
452  FileId directory_id;
453  FileInfo info1;
454  info1.parent_id = 0;
455  info1.name = FILE_PATH_LITERAL("directory");
456  info1.modification_time = base::Time::UnixEpoch();
457  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info1, &directory_id));
458
459  EXPECT_FALSE(db()->OverwritingMoveFile(file_id, directory_id));
460}
461
462TEST_F(SandboxDirectoryDatabaseTest, TestOverwritingMoveFileSuccess) {
463  FileId file_id0;
464  FileInfo info0;
465  info0.parent_id = 0;
466  info0.data_path = base::FilePath(FILE_PATH_LITERAL("foo"));
467  info0.name = FILE_PATH_LITERAL("file name 0");
468  info0.modification_time = base::Time::Now();
469  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info0, &file_id0));
470
471  FileInfo dir_info;
472  FileId dir_id;
473  dir_info.parent_id = 0;
474  dir_info.name = FILE_PATH_LITERAL("directory name");
475  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(dir_info, &dir_id));
476
477  FileId file_id1;
478  FileInfo info1;
479  info1.parent_id = dir_id;
480  info1.data_path = base::FilePath(FILE_PATH_LITERAL("bar"));
481  info1.name = FILE_PATH_LITERAL("file name 1");
482  info1.modification_time = base::Time::UnixEpoch();
483  EXPECT_EQ(base::File::FILE_OK, db()->AddFileInfo(info1, &file_id1));
484
485  EXPECT_TRUE(db()->OverwritingMoveFile(file_id0, file_id1));
486
487  FileInfo check_info;
488  FileId check_id;
489
490  EXPECT_FALSE(db()->GetFileWithPath(base::FilePath(info0.name), &check_id));
491  EXPECT_TRUE(db()->GetFileWithPath(
492      base::FilePath(dir_info.name).Append(info1.name), &check_id));
493  EXPECT_TRUE(db()->GetFileInfo(check_id, &check_info));
494
495  EXPECT_EQ(info0.data_path, check_info.data_path);
496}
497
498TEST_F(SandboxDirectoryDatabaseTest, TestGetNextInteger) {
499  int64 next = -1;
500  EXPECT_TRUE(db()->GetNextInteger(&next));
501  EXPECT_EQ(0, next);
502  EXPECT_TRUE(db()->GetNextInteger(&next));
503  EXPECT_EQ(1, next);
504  InitDatabase();
505  EXPECT_TRUE(db()->GetNextInteger(&next));
506  EXPECT_EQ(2, next);
507  EXPECT_TRUE(db()->GetNextInteger(&next));
508  EXPECT_EQ(3, next);
509  InitDatabase();
510  EXPECT_TRUE(db()->GetNextInteger(&next));
511  EXPECT_EQ(4, next);
512}
513
514TEST_F(SandboxDirectoryDatabaseTest, TestConsistencyCheck_Empty) {
515  EXPECT_TRUE(db()->IsFileSystemConsistent());
516
517  int64 next = -1;
518  EXPECT_TRUE(db()->GetNextInteger(&next));
519  EXPECT_EQ(0, next);
520  EXPECT_TRUE(db()->IsFileSystemConsistent());
521}
522
523TEST_F(SandboxDirectoryDatabaseTest, TestConsistencyCheck_Consistent) {
524  FileId dir_id;
525  CreateFile(0, FPL("foo"), FPL("hoge"), NULL);
526  CreateDirectory(0, FPL("bar"), &dir_id);
527  CreateFile(dir_id, FPL("baz"), FPL("fuga"), NULL);
528  CreateFile(dir_id, FPL("fizz"), FPL("buzz"), NULL);
529
530  EXPECT_TRUE(db()->IsFileSystemConsistent());
531}
532
533TEST_F(SandboxDirectoryDatabaseTest,
534       TestConsistencyCheck_BackingMultiEntry) {
535  const base::FilePath::CharType kBackingFileName[] = FPL("the celeb");
536  CreateFile(0, FPL("foo"), kBackingFileName, NULL);
537
538  EXPECT_TRUE(db()->IsFileSystemConsistent());
539  ASSERT_TRUE(base::DeleteFile(path().Append(kBackingFileName), false));
540  CreateFile(0, FPL("bar"), kBackingFileName, NULL);
541  EXPECT_FALSE(db()->IsFileSystemConsistent());
542}
543
544TEST_F(SandboxDirectoryDatabaseTest, TestConsistencyCheck_FileLost) {
545  const base::FilePath::CharType kBackingFileName[] = FPL("hoge");
546  CreateFile(0, FPL("foo"), kBackingFileName, NULL);
547
548  EXPECT_TRUE(db()->IsFileSystemConsistent());
549  ASSERT_TRUE(base::DeleteFile(path().Append(kBackingFileName), false));
550  EXPECT_TRUE(db()->IsFileSystemConsistent());
551}
552
553TEST_F(SandboxDirectoryDatabaseTest, TestConsistencyCheck_OrphanFile) {
554  CreateFile(0, FPL("foo"), FPL("hoge"), NULL);
555
556  EXPECT_TRUE(db()->IsFileSystemConsistent());
557
558  base::File file(path().Append(FPL("Orphan File")),
559                  base::File::FLAG_CREATE | base::File::FLAG_WRITE);
560  ASSERT_TRUE(file.IsValid());
561  ASSERT_TRUE(file.created());
562  file.Close();
563
564  EXPECT_TRUE(db()->IsFileSystemConsistent());
565}
566
567TEST_F(SandboxDirectoryDatabaseTest, TestConsistencyCheck_RootLoop) {
568  EXPECT_TRUE(db()->IsFileSystemConsistent());
569  MakeHierarchyLink(0, 0, base::FilePath::StringType());
570  EXPECT_FALSE(db()->IsFileSystemConsistent());
571}
572
573TEST_F(SandboxDirectoryDatabaseTest, TestConsistencyCheck_DirectoryLoop) {
574  FileId dir1_id;
575  FileId dir2_id;
576  base::FilePath::StringType dir1_name = FPL("foo");
577  CreateDirectory(0, dir1_name, &dir1_id);
578  CreateDirectory(dir1_id, FPL("bar"), &dir2_id);
579
580  EXPECT_TRUE(db()->IsFileSystemConsistent());
581  MakeHierarchyLink(dir2_id, dir1_id, dir1_name);
582  EXPECT_FALSE(db()->IsFileSystemConsistent());
583}
584
585TEST_F(SandboxDirectoryDatabaseTest, TestConsistencyCheck_NameMismatch) {
586  FileId dir_id;
587  FileId file_id;
588  CreateDirectory(0, FPL("foo"), &dir_id);
589  CreateFile(dir_id, FPL("bar"), FPL("hoge/fuga/piyo"), &file_id);
590
591  EXPECT_TRUE(db()->IsFileSystemConsistent());
592  DeleteHierarchyLink(file_id);
593  MakeHierarchyLink(dir_id, file_id, FPL("baz"));
594  EXPECT_FALSE(db()->IsFileSystemConsistent());
595}
596
597TEST_F(SandboxDirectoryDatabaseTest, TestConsistencyCheck_WreckedEntries) {
598  FileId dir1_id;
599  FileId dir2_id;
600  CreateDirectory(0, FPL("foo"), &dir1_id);
601  CreateDirectory(dir1_id, FPL("bar"), &dir2_id);
602  CreateFile(dir2_id, FPL("baz"), FPL("fizz/buzz"), NULL);
603
604  EXPECT_TRUE(db()->IsFileSystemConsistent());
605  DeleteHierarchyLink(dir2_id);  // Delete link from |dir1_id| to |dir2_id|.
606  EXPECT_FALSE(db()->IsFileSystemConsistent());
607}
608
609TEST_F(SandboxDirectoryDatabaseTest, TestRepairDatabase_Success) {
610  base::FilePath::StringType kFileName = FPL("bar");
611
612  FileId file_id_prev;
613  CreateFile(0, FPL("foo"), FPL("hoge"), NULL);
614  CreateFile(0, kFileName, FPL("fuga"), &file_id_prev);
615
616  const base::FilePath kDatabaseDirectory =
617      path().Append(kDirectoryDatabaseName);
618  CloseDatabase();
619  CorruptDatabase(kDatabaseDirectory, leveldb::kDescriptorFile,
620                  0, std::numeric_limits<size_t>::max());
621  InitDatabase();
622  EXPECT_FALSE(db()->IsFileSystemConsistent());
623
624  FileId file_id;
625  EXPECT_TRUE(db()->GetChildWithName(0, kFileName, &file_id));
626  EXPECT_EQ(file_id_prev, file_id);
627
628  EXPECT_TRUE(db()->IsFileSystemConsistent());
629}
630
631TEST_F(SandboxDirectoryDatabaseTest, TestRepairDatabase_Failure) {
632  base::FilePath::StringType kFileName = FPL("bar");
633
634  CreateFile(0, FPL("foo"), FPL("hoge"), NULL);
635  CreateFile(0, kFileName, FPL("fuga"), NULL);
636
637  const base::FilePath kDatabaseDirectory =
638      path().Append(kDirectoryDatabaseName);
639  CloseDatabase();
640  CorruptDatabase(kDatabaseDirectory, leveldb::kDescriptorFile,
641                  0, std::numeric_limits<size_t>::max());
642  CorruptDatabase(kDatabaseDirectory, leveldb::kLogFile,
643                  -1, 1);
644  InitDatabase();
645  EXPECT_FALSE(db()->IsFileSystemConsistent());
646
647  FileId file_id;
648  EXPECT_FALSE(db()->GetChildWithName(0, kFileName, &file_id));
649  EXPECT_TRUE(db()->IsFileSystemConsistent());
650}
651
652TEST_F(SandboxDirectoryDatabaseTest, TestRepairDatabase_MissingManifest) {
653  base::FilePath::StringType kFileName = FPL("bar");
654
655  FileId file_id_prev;
656  CreateFile(0, FPL("foo"), FPL("hoge"), NULL);
657  CreateFile(0, kFileName, FPL("fuga"), &file_id_prev);
658
659  const base::FilePath kDatabaseDirectory =
660      path().Append(kDirectoryDatabaseName);
661  CloseDatabase();
662
663  DeleteDatabaseFile(kDatabaseDirectory, leveldb::kDescriptorFile);
664
665  InitDatabase();
666  EXPECT_FALSE(db()->IsFileSystemConsistent());
667
668  FileId file_id;
669  EXPECT_TRUE(db()->GetChildWithName(0, kFileName, &file_id));
670  EXPECT_EQ(file_id_prev, file_id);
671
672  EXPECT_TRUE(db()->IsFileSystemConsistent());
673}
674
675}  // namespace content
676