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/file_util.h"
6 #include "base/files/file_enumerator.h"
7 #include "base/files/file_path.h"
8 #include "base/files/scoped_temp_dir.h"
9 #include "base/test/test_suite.h"
10 #include "env_chromium.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "third_party/leveldatabase/env_idb.h"
13 #include "third_party/leveldatabase/src/include/leveldb/db.h"
15 using namespace leveldb_env
;
16 using namespace leveldb
;
18 #define FPL FILE_PATH_LITERAL
20 TEST(ErrorEncoding
, OnlyAMethod
) {
21 const MethodID in_method
= kSequentialFileRead
;
22 const Status s
= MakeIOError("Somefile.txt", "message", in_method
);
25 EXPECT_EQ(METHOD_ONLY
,
26 ParseMethodAndError(s
.ToString().c_str(), &method
, &error
));
27 EXPECT_EQ(in_method
, method
);
28 EXPECT_EQ(-75, error
);
31 TEST(ErrorEncoding
, PlatformFileError
) {
32 const MethodID in_method
= kWritableFileClose
;
33 const base::PlatformFileError pfe
=
34 base::PLATFORM_FILE_ERROR_INVALID_OPERATION
;
35 const Status s
= MakeIOError("Somefile.txt", "message", in_method
, pfe
);
38 EXPECT_EQ(METHOD_AND_PFE
,
39 ParseMethodAndError(s
.ToString().c_str(), &method
, &error
));
40 EXPECT_EQ(in_method
, method
);
41 EXPECT_EQ(pfe
, error
);
44 TEST(ErrorEncoding
, Errno
) {
45 const MethodID in_method
= kWritableFileFlush
;
46 const int some_errno
= ENOENT
;
48 MakeIOError("Somefile.txt", "message", in_method
, some_errno
);
51 EXPECT_EQ(METHOD_AND_ERRNO
,
52 ParseMethodAndError(s
.ToString().c_str(), &method
, &error
));
53 EXPECT_EQ(in_method
, method
);
54 EXPECT_EQ(some_errno
, error
);
57 TEST(ErrorEncoding
, NoEncodedMessage
) {
58 Status s
= Status::IOError("Some message", "from leveldb itself");
59 MethodID method
= kRandomAccessFileRead
;
61 EXPECT_EQ(NONE
, ParseMethodAndError(s
.ToString().c_str(), &method
, &error
));
62 EXPECT_EQ(kRandomAccessFileRead
, method
);
66 class MyEnv
: public ChromiumEnv
{
68 MyEnv() : directory_syncs_(0) {}
69 int directory_syncs() { return directory_syncs_
; }
72 virtual void DidSyncDir(const std::string
& fname
) {
74 ChromiumEnv::DidSyncDir(fname
);
81 TEST(ChromiumEnv
, DirectorySyncing
) {
83 base::ScopedTempDir dir
;
84 dir
.CreateUniqueTempDir();
85 base::FilePath dir_path
= dir
.path();
86 std::string some_data
= "some data";
87 Slice data
= some_data
;
89 std::string manifest_file_name
=
90 FilePathToString(dir_path
.Append(FILE_PATH_LITERAL("MANIFEST-001")));
91 WritableFile
* manifest_file_ptr
;
92 Status s
= env
.NewWritableFile(manifest_file_name
, &manifest_file_ptr
);
94 scoped_ptr
<WritableFile
> manifest_file(manifest_file_ptr
);
95 manifest_file
->Append(data
);
96 EXPECT_EQ(0, env
.directory_syncs());
97 manifest_file
->Append(data
);
98 EXPECT_EQ(0, env
.directory_syncs());
100 std::string sst_file_name
=
101 FilePathToString(dir_path
.Append(FILE_PATH_LITERAL("000003.sst")));
102 WritableFile
* sst_file_ptr
;
103 s
= env
.NewWritableFile(sst_file_name
, &sst_file_ptr
);
105 scoped_ptr
<WritableFile
> sst_file(sst_file_ptr
);
106 sst_file
->Append(data
);
107 EXPECT_EQ(0, env
.directory_syncs());
109 manifest_file
->Append(data
);
110 EXPECT_EQ(1, env
.directory_syncs());
111 manifest_file
->Append(data
);
112 EXPECT_EQ(1, env
.directory_syncs());
115 int CountFilesWithExtension(const base::FilePath
& dir
,
116 const base::FilePath::StringType
& extension
) {
117 int matching_files
= 0;
118 base::FileEnumerator
dir_reader(
119 dir
, false, base::FileEnumerator::FILES
);
120 for (base::FilePath fname
= dir_reader
.Next(); !fname
.empty();
121 fname
= dir_reader
.Next()) {
122 if (fname
.MatchesExtension(extension
))
125 return matching_files
;
128 bool GetFirstLDBFile(const base::FilePath
& dir
, base::FilePath
* ldb_file
) {
129 base::FileEnumerator
dir_reader(
130 dir
, false, base::FileEnumerator::FILES
);
131 for (base::FilePath fname
= dir_reader
.Next(); !fname
.empty();
132 fname
= dir_reader
.Next()) {
133 if (fname
.MatchesExtension(FPL(".ldb"))) {
141 TEST(ChromiumEnv
, BackupTables
) {
143 options
.create_if_missing
= true;
144 options
.env
= IDBEnv();
146 base::ScopedTempDir scoped_temp_dir
;
147 scoped_temp_dir
.CreateUniqueTempDir();
148 base::FilePath dir
= scoped_temp_dir
.path();
151 Status status
= DB::Open(options
, dir
.AsUTF8Unsafe(), &db
);
152 EXPECT_TRUE(status
.ok()) << status
.ToString();
153 status
= db
->Put(WriteOptions(), "key", "value");
154 EXPECT_TRUE(status
.ok()) << status
.ToString();
157 db
->CompactRange(&a
, &z
);
158 int ldb_files
= CountFilesWithExtension(dir
, FPL(".ldb"));
159 int bak_files
= CountFilesWithExtension(dir
, FPL(".bak"));
160 EXPECT_GT(ldb_files
, 0);
161 EXPECT_EQ(ldb_files
, bak_files
);
162 base::FilePath ldb_file
;
163 EXPECT_TRUE(GetFirstLDBFile(dir
, &ldb_file
));
165 EXPECT_TRUE(base::DeleteFile(ldb_file
, false));
166 EXPECT_EQ(ldb_files
- 1, CountFilesWithExtension(dir
, FPL(".ldb")));
168 // The ldb file deleted above should be restored in Open.
169 status
= leveldb::DB::Open(options
, dir
.AsUTF8Unsafe(), &db
);
170 EXPECT_TRUE(status
.ok()) << status
.ToString();
172 status
= db
->Get(ReadOptions(), "key", &value
);
173 EXPECT_TRUE(status
.ok()) << status
.ToString();
174 EXPECT_EQ("value", value
);
177 // Ensure that deleting an ldb file also deletes its backup.
178 int orig_ldb_files
= CountFilesWithExtension(dir
, FPL(".ldb"));
179 int orig_bak_files
= CountFilesWithExtension(dir
, FPL(".bak"));
180 EXPECT_GT(ldb_files
, 0);
181 EXPECT_EQ(ldb_files
, bak_files
);
182 EXPECT_TRUE(GetFirstLDBFile(dir
, &ldb_file
));
183 options
.env
->DeleteFile(ldb_file
.AsUTF8Unsafe());
184 ldb_files
= CountFilesWithExtension(dir
, FPL(".ldb"));
185 bak_files
= CountFilesWithExtension(dir
, FPL(".bak"));
186 EXPECT_EQ(orig_ldb_files
- 1, ldb_files
);
187 EXPECT_EQ(bak_files
, ldb_files
);
190 TEST(ChromiumEnv
, GetChildrenEmptyDir
) {
191 base::ScopedTempDir scoped_temp_dir
;
192 scoped_temp_dir
.CreateUniqueTempDir();
193 base::FilePath dir
= scoped_temp_dir
.path();
196 std::vector
<std::string
> result
;
197 leveldb::Status status
= env
->GetChildren(dir
.AsUTF8Unsafe(), &result
);
198 EXPECT_TRUE(status
.ok());
199 EXPECT_EQ(0, result
.size());
202 TEST(ChromiumEnv
, GetChildrenPriorResults
) {
203 base::ScopedTempDir scoped_temp_dir
;
204 scoped_temp_dir
.CreateUniqueTempDir();
205 base::FilePath dir
= scoped_temp_dir
.path();
207 base::FilePath new_file_dir
= dir
.Append(FPL("tmp_file"));
208 FILE* f
= fopen(new_file_dir
.AsUTF8Unsafe().c_str(), "w");
210 fputs("Temp file contents", f
);
215 std::vector
<std::string
> result
;
216 leveldb::Status status
= env
->GetChildren(dir
.AsUTF8Unsafe(), &result
);
217 EXPECT_TRUE(status
.ok());
218 EXPECT_EQ(1, result
.size());
220 // And a second time should also return one result
221 status
= env
->GetChildren(dir
.AsUTF8Unsafe(), &result
);
222 EXPECT_TRUE(status
.ok());
223 EXPECT_EQ(1, result
.size());
226 int main(int argc
, char** argv
) { return base::TestSuite(argc
, argv
).Run(); }