1 // Copyright (c) 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.
5 #include "base/files/file.h"
6 #include "base/files/file_enumerator.h"
7 #include "base/files/file_path.h"
8 #include "base/files/file_util.h"
9 #include "base/files/scoped_temp_dir.h"
10 #include "base/lazy_instance.h"
11 #include "base/test/test_suite.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "third_party/leveldatabase/env_chromium.h"
14 #include "third_party/leveldatabase/src/include/leveldb/db.h"
16 #define FPL FILE_PATH_LITERAL
20 using leveldb::Options
;
21 using leveldb::ReadOptions
;
23 using leveldb::Status
;
24 using leveldb::WritableFile
;
25 using leveldb::WriteOptions
;
26 using leveldb_env::ChromiumEnv
;
27 using leveldb_env::MethodID
;
29 TEST(ErrorEncoding
, OnlyAMethod
) {
30 const MethodID in_method
= leveldb_env::kSequentialFileRead
;
31 const Status s
= MakeIOError("Somefile.txt", "message", in_method
);
33 base::File::Error error
= base::File::FILE_ERROR_MAX
;
34 EXPECT_EQ(leveldb_env::METHOD_ONLY
, ParseMethodAndError(s
, &method
, &error
));
35 EXPECT_EQ(in_method
, method
);
36 EXPECT_EQ(base::File::FILE_ERROR_MAX
, error
);
39 TEST(ErrorEncoding
, FileError
) {
40 const MethodID in_method
= leveldb_env::kWritableFileClose
;
41 const base::File::Error fe
= base::File::FILE_ERROR_INVALID_OPERATION
;
42 const Status s
= MakeIOError("Somefile.txt", "message", in_method
, fe
);
44 base::File::Error error
;
45 EXPECT_EQ(leveldb_env::METHOD_AND_BFE
,
46 ParseMethodAndError(s
, &method
, &error
));
47 EXPECT_EQ(in_method
, method
);
51 TEST(ErrorEncoding
, NoEncodedMessage
) {
52 Status s
= Status::IOError("Some message", "from leveldb itself");
53 MethodID method
= leveldb_env::kRandomAccessFileRead
;
54 base::File::Error error
= base::File::FILE_ERROR_MAX
;
55 EXPECT_EQ(leveldb_env::NONE
, ParseMethodAndError(s
, &method
, &error
));
56 EXPECT_EQ(leveldb_env::kRandomAccessFileRead
, method
);
57 EXPECT_EQ(base::File::FILE_ERROR_MAX
, error
);
61 class ChromiumEnvMultiPlatformTests
: public ::testing::Test
{
65 typedef ::testing::Types
<ChromiumEnv
> ChromiumEnvMultiPlatformTestsTypes
;
66 TYPED_TEST_CASE(ChromiumEnvMultiPlatformTests
,
67 ChromiumEnvMultiPlatformTestsTypes
);
69 int CountFilesWithExtension(const base::FilePath
& dir
,
70 const base::FilePath::StringType
& extension
) {
71 int matching_files
= 0;
72 base::FileEnumerator
dir_reader(
73 dir
, false, base::FileEnumerator::FILES
);
74 for (base::FilePath fname
= dir_reader
.Next(); !fname
.empty();
75 fname
= dir_reader
.Next()) {
76 if (fname
.MatchesExtension(extension
))
79 return matching_files
;
82 bool GetFirstLDBFile(const base::FilePath
& dir
, base::FilePath
* ldb_file
) {
83 base::FileEnumerator
dir_reader(
84 dir
, false, base::FileEnumerator::FILES
);
85 for (base::FilePath fname
= dir_reader
.Next(); !fname
.empty();
86 fname
= dir_reader
.Next()) {
87 if (fname
.MatchesExtension(FPL(".ldb"))) {
95 class BackupEnv
: public ChromiumEnv
{
97 BackupEnv() : ChromiumEnv("BackupEnv", true /* backup tables */) {}
100 base::LazyInstance
<BackupEnv
>::Leaky backup_env
= LAZY_INSTANCE_INITIALIZER
;
102 TEST(ChromiumEnv
, BackupTables
) {
104 options
.create_if_missing
= true;
105 options
.env
= backup_env
.Pointer();
107 base::ScopedTempDir scoped_temp_dir
;
108 ASSERT_TRUE(scoped_temp_dir
.CreateUniqueTempDir());
109 base::FilePath dir
= scoped_temp_dir
.path();
112 Status status
= DB::Open(options
, dir
.AsUTF8Unsafe(), &db
);
113 EXPECT_TRUE(status
.ok()) << status
.ToString();
114 status
= db
->Put(WriteOptions(), "key", "value");
115 EXPECT_TRUE(status
.ok()) << status
.ToString();
118 db
->CompactRange(&a
, &z
);
119 int ldb_files
= CountFilesWithExtension(dir
, FPL(".ldb"));
120 int bak_files
= CountFilesWithExtension(dir
, FPL(".bak"));
121 EXPECT_GT(ldb_files
, 0);
122 EXPECT_EQ(ldb_files
, bak_files
);
123 base::FilePath ldb_file
;
124 EXPECT_TRUE(GetFirstLDBFile(dir
, &ldb_file
));
126 EXPECT_TRUE(base::DeleteFile(ldb_file
, false));
127 EXPECT_EQ(ldb_files
- 1, CountFilesWithExtension(dir
, FPL(".ldb")));
129 // The ldb file deleted above should be restored in Open.
130 status
= leveldb::DB::Open(options
, dir
.AsUTF8Unsafe(), &db
);
131 EXPECT_TRUE(status
.ok()) << status
.ToString();
133 status
= db
->Get(ReadOptions(), "key", &value
);
134 EXPECT_TRUE(status
.ok()) << status
.ToString();
135 EXPECT_EQ("value", value
);
138 // Ensure that deleting an ldb file also deletes its backup.
139 int orig_ldb_files
= CountFilesWithExtension(dir
, FPL(".ldb"));
140 EXPECT_GT(ldb_files
, 0);
141 EXPECT_EQ(ldb_files
, bak_files
);
142 EXPECT_TRUE(GetFirstLDBFile(dir
, &ldb_file
));
143 options
.env
->DeleteFile(ldb_file
.AsUTF8Unsafe());
144 ldb_files
= CountFilesWithExtension(dir
, FPL(".ldb"));
145 bak_files
= CountFilesWithExtension(dir
, FPL(".bak"));
146 EXPECT_EQ(orig_ldb_files
- 1, ldb_files
);
147 EXPECT_EQ(bak_files
, ldb_files
);
150 TEST(ChromiumEnv
, GetChildrenEmptyDir
) {
151 base::ScopedTempDir scoped_temp_dir
;
152 ASSERT_TRUE(scoped_temp_dir
.CreateUniqueTempDir());
153 base::FilePath dir
= scoped_temp_dir
.path();
155 Env
* env
= Env::Default();
156 std::vector
<std::string
> result
;
157 leveldb::Status status
= env
->GetChildren(dir
.AsUTF8Unsafe(), &result
);
158 EXPECT_TRUE(status
.ok());
159 EXPECT_EQ(0U, result
.size());
162 TEST(ChromiumEnv
, GetChildrenPriorResults
) {
163 base::ScopedTempDir scoped_temp_dir
;
164 ASSERT_TRUE(scoped_temp_dir
.CreateUniqueTempDir());
165 base::FilePath dir
= scoped_temp_dir
.path();
167 base::FilePath new_file_dir
= dir
.Append(FPL("tmp_file"));
168 FILE* f
= fopen(new_file_dir
.AsUTF8Unsafe().c_str(), "w");
170 fputs("Temp file contents", f
);
174 Env
* env
= Env::Default();
175 std::vector
<std::string
> result
;
176 leveldb::Status status
= env
->GetChildren(dir
.AsUTF8Unsafe(), &result
);
177 EXPECT_TRUE(status
.ok());
178 EXPECT_EQ(1U, result
.size());
180 // And a second time should also return one result
181 status
= env
->GetChildren(dir
.AsUTF8Unsafe(), &result
);
182 EXPECT_TRUE(status
.ok());
183 EXPECT_EQ(1U, result
.size());
186 int main(int argc
, char** argv
) { return base::TestSuite(argc
, argv
).Run(); }