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/test/test_suite.h"
11 #include "third_party/leveldatabase/env_chromium.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "third_party/leveldatabase/env_idb.h"
14 #include "third_party/leveldatabase/src/include/leveldb/db.h"
16 #define FPL FILE_PATH_LITERAL
20 using leveldb::IDBEnv
;
21 using leveldb::Options
;
22 using leveldb::ReadOptions
;
24 using leveldb::Status
;
25 using leveldb::WritableFile
;
26 using leveldb::WriteOptions
;
27 using leveldb_env::ChromiumEnv
;
28 using leveldb_env::MethodID
;
30 TEST(ErrorEncoding
, OnlyAMethod
) {
31 const MethodID in_method
= leveldb_env::kSequentialFileRead
;
32 const Status s
= MakeIOError("Somefile.txt", "message", in_method
);
34 base::File::Error error
= base::File::FILE_ERROR_MAX
;
35 EXPECT_EQ(leveldb_env::METHOD_ONLY
, ParseMethodAndError(s
, &method
, &error
));
36 EXPECT_EQ(in_method
, method
);
37 EXPECT_EQ(base::File::FILE_ERROR_MAX
, error
);
40 TEST(ErrorEncoding
, FileError
) {
41 const MethodID in_method
= leveldb_env::kWritableFileClose
;
42 const base::File::Error fe
= base::File::FILE_ERROR_INVALID_OPERATION
;
43 const Status s
= MakeIOError("Somefile.txt", "message", in_method
, fe
);
45 base::File::Error error
;
46 EXPECT_EQ(leveldb_env::METHOD_AND_PFE
,
47 ParseMethodAndError(s
, &method
, &error
));
48 EXPECT_EQ(in_method
, method
);
52 TEST(ErrorEncoding
, NoEncodedMessage
) {
53 Status s
= Status::IOError("Some message", "from leveldb itself");
54 MethodID method
= leveldb_env::kRandomAccessFileRead
;
55 base::File::Error error
= base::File::FILE_ERROR_MAX
;
56 EXPECT_EQ(leveldb_env::NONE
, ParseMethodAndError(s
, &method
, &error
));
57 EXPECT_EQ(leveldb_env::kRandomAccessFileRead
, method
);
58 EXPECT_EQ(base::File::FILE_ERROR_MAX
, error
);
62 class MyEnv
: public T
{
64 MyEnv() : directory_syncs_(0) {}
65 int directory_syncs() { return directory_syncs_
; }
68 virtual void DidSyncDir(const std::string
& fname
) {
70 leveldb_env::ChromiumEnv::DidSyncDir(fname
);
78 class ChromiumEnvMultiPlatformTests
: public ::testing::Test
{
82 typedef ::testing::Types
<ChromiumEnv
> ChromiumEnvMultiPlatformTestsTypes
;
83 TYPED_TEST_CASE(ChromiumEnvMultiPlatformTests
,
84 ChromiumEnvMultiPlatformTestsTypes
);
86 TYPED_TEST(ChromiumEnvMultiPlatformTests
, DirectorySyncing
) {
89 base::ScopedTempDir dir
;
90 ASSERT_TRUE(dir
.CreateUniqueTempDir());
91 base::FilePath dir_path
= dir
.path();
92 std::string some_data
= "some data";
93 Slice data
= some_data
;
95 std::string manifest_file_name
=
96 dir_path
.Append(FILE_PATH_LITERAL("MANIFEST-001")).AsUTF8Unsafe();
97 WritableFile
* manifest_file_ptr
;
98 Status s
= env
.NewWritableFile(manifest_file_name
, &manifest_file_ptr
);
100 scoped_ptr
<WritableFile
> manifest_file(manifest_file_ptr
);
101 manifest_file
->Append(data
);
102 EXPECT_EQ(0, env
.directory_syncs());
103 manifest_file
->Append(data
);
104 EXPECT_EQ(0, env
.directory_syncs());
106 std::string sst_file_name
=
107 dir_path
.Append(FILE_PATH_LITERAL("000003.sst")).AsUTF8Unsafe();
108 WritableFile
* sst_file_ptr
;
109 s
= env
.NewWritableFile(sst_file_name
, &sst_file_ptr
);
111 scoped_ptr
<WritableFile
> sst_file(sst_file_ptr
);
112 sst_file
->Append(data
);
113 EXPECT_EQ(0, env
.directory_syncs());
115 manifest_file
->Append(data
);
116 EXPECT_EQ(1, env
.directory_syncs());
117 manifest_file
->Append(data
);
118 EXPECT_EQ(1, env
.directory_syncs());
121 int CountFilesWithExtension(const base::FilePath
& dir
,
122 const base::FilePath::StringType
& extension
) {
123 int matching_files
= 0;
124 base::FileEnumerator
dir_reader(
125 dir
, false, base::FileEnumerator::FILES
);
126 for (base::FilePath fname
= dir_reader
.Next(); !fname
.empty();
127 fname
= dir_reader
.Next()) {
128 if (fname
.MatchesExtension(extension
))
131 return matching_files
;
134 bool GetFirstLDBFile(const base::FilePath
& dir
, base::FilePath
* ldb_file
) {
135 base::FileEnumerator
dir_reader(
136 dir
, false, base::FileEnumerator::FILES
);
137 for (base::FilePath fname
= dir_reader
.Next(); !fname
.empty();
138 fname
= dir_reader
.Next()) {
139 if (fname
.MatchesExtension(FPL(".ldb"))) {
147 TEST(ChromiumEnv
, BackupTables
) {
149 options
.create_if_missing
= true;
150 options
.env
= IDBEnv();
152 base::ScopedTempDir scoped_temp_dir
;
153 ASSERT_TRUE(scoped_temp_dir
.CreateUniqueTempDir());
154 base::FilePath dir
= scoped_temp_dir
.path();
157 Status status
= DB::Open(options
, dir
.AsUTF8Unsafe(), &db
);
158 EXPECT_TRUE(status
.ok()) << status
.ToString();
159 status
= db
->Put(WriteOptions(), "key", "value");
160 EXPECT_TRUE(status
.ok()) << status
.ToString();
163 db
->CompactRange(&a
, &z
);
164 int ldb_files
= CountFilesWithExtension(dir
, FPL(".ldb"));
165 int bak_files
= CountFilesWithExtension(dir
, FPL(".bak"));
166 EXPECT_GT(ldb_files
, 0);
167 EXPECT_EQ(ldb_files
, bak_files
);
168 base::FilePath ldb_file
;
169 EXPECT_TRUE(GetFirstLDBFile(dir
, &ldb_file
));
171 EXPECT_TRUE(base::DeleteFile(ldb_file
, false));
172 EXPECT_EQ(ldb_files
- 1, CountFilesWithExtension(dir
, FPL(".ldb")));
174 // The ldb file deleted above should be restored in Open.
175 status
= leveldb::DB::Open(options
, dir
.AsUTF8Unsafe(), &db
);
176 EXPECT_TRUE(status
.ok()) << status
.ToString();
178 status
= db
->Get(ReadOptions(), "key", &value
);
179 EXPECT_TRUE(status
.ok()) << status
.ToString();
180 EXPECT_EQ("value", value
);
183 // Ensure that deleting an ldb file also deletes its backup.
184 int orig_ldb_files
= CountFilesWithExtension(dir
, FPL(".ldb"));
185 EXPECT_GT(ldb_files
, 0);
186 EXPECT_EQ(ldb_files
, bak_files
);
187 EXPECT_TRUE(GetFirstLDBFile(dir
, &ldb_file
));
188 options
.env
->DeleteFile(ldb_file
.AsUTF8Unsafe());
189 ldb_files
= CountFilesWithExtension(dir
, FPL(".ldb"));
190 bak_files
= CountFilesWithExtension(dir
, FPL(".bak"));
191 EXPECT_EQ(orig_ldb_files
- 1, ldb_files
);
192 EXPECT_EQ(bak_files
, ldb_files
);
195 TEST(ChromiumEnv
, GetChildrenEmptyDir
) {
196 base::ScopedTempDir scoped_temp_dir
;
197 ASSERT_TRUE(scoped_temp_dir
.CreateUniqueTempDir());
198 base::FilePath dir
= scoped_temp_dir
.path();
201 std::vector
<std::string
> result
;
202 leveldb::Status status
= env
->GetChildren(dir
.AsUTF8Unsafe(), &result
);
203 EXPECT_TRUE(status
.ok());
204 EXPECT_EQ(0U, result
.size());
207 TEST(ChromiumEnv
, GetChildrenPriorResults
) {
208 base::ScopedTempDir scoped_temp_dir
;
209 ASSERT_TRUE(scoped_temp_dir
.CreateUniqueTempDir());
210 base::FilePath dir
= scoped_temp_dir
.path();
212 base::FilePath new_file_dir
= dir
.Append(FPL("tmp_file"));
213 FILE* f
= fopen(new_file_dir
.AsUTF8Unsafe().c_str(), "w");
215 fputs("Temp file contents", f
);
220 std::vector
<std::string
> result
;
221 leveldb::Status status
= env
->GetChildren(dir
.AsUTF8Unsafe(), &result
);
222 EXPECT_TRUE(status
.ok());
223 EXPECT_EQ(1U, result
.size());
225 // And a second time should also return one result
226 status
= env
->GetChildren(dir
.AsUTF8Unsafe(), &result
);
227 EXPECT_TRUE(status
.ok());
228 EXPECT_EQ(1U, result
.size());
231 int main(int argc
, char** argv
) { return base::TestSuite(argc
, argv
).Run(); }