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
;
92 Status s
= env
.NewWritableFile(manifest_file_name
, &manifest_file
);
94 manifest_file
->Append(data
);
95 EXPECT_EQ(0, env
.directory_syncs());
96 manifest_file
->Append(data
);
97 EXPECT_EQ(0, env
.directory_syncs());
99 std::string sst_file_name
=
100 FilePathToString(dir_path
.Append(FILE_PATH_LITERAL("000003.sst")));
101 WritableFile
* sst_file
;
102 s
= env
.NewWritableFile(sst_file_name
, &sst_file
);
104 sst_file
->Append(data
);
105 EXPECT_EQ(0, env
.directory_syncs());
107 manifest_file
->Append(data
);
108 EXPECT_EQ(1, env
.directory_syncs());
109 manifest_file
->Append(data
);
110 EXPECT_EQ(1, env
.directory_syncs());
113 int CountFilesWithExtension(const base::FilePath
& dir
,
114 const base::FilePath::StringType
& extension
) {
115 int matching_files
= 0;
116 base::FileEnumerator
dir_reader(
117 dir
, false, base::FileEnumerator::FILES
);
118 for (base::FilePath fname
= dir_reader
.Next(); !fname
.empty();
119 fname
= dir_reader
.Next()) {
120 if (fname
.MatchesExtension(extension
))
123 return matching_files
;
126 bool GetFirstLDBFile(const base::FilePath
& dir
, base::FilePath
* ldb_file
) {
127 base::FileEnumerator
dir_reader(
128 dir
, false, base::FileEnumerator::FILES
);
129 for (base::FilePath fname
= dir_reader
.Next(); !fname
.empty();
130 fname
= dir_reader
.Next()) {
131 if (fname
.MatchesExtension(FPL(".ldb"))) {
139 TEST(ChromiumEnv
, BackupTables
) {
141 options
.create_if_missing
= true;
142 options
.env
= IDBEnv();
144 base::ScopedTempDir scoped_temp_dir
;
145 scoped_temp_dir
.CreateUniqueTempDir();
146 base::FilePath dir
= scoped_temp_dir
.path();
149 Status status
= DB::Open(options
, dir
.AsUTF8Unsafe(), &db
);
150 EXPECT_TRUE(status
.ok()) << status
.ToString();
151 status
= db
->Put(WriteOptions(), "key", "value");
152 EXPECT_TRUE(status
.ok()) << status
.ToString();
155 db
->CompactRange(&a
, &z
);
156 int ldb_files
= CountFilesWithExtension(dir
, FPL(".ldb"));
157 int bak_files
= CountFilesWithExtension(dir
, FPL(".bak"));
158 EXPECT_GT(ldb_files
, 0);
159 EXPECT_EQ(ldb_files
, bak_files
);
160 base::FilePath ldb_file
;
161 EXPECT_TRUE(GetFirstLDBFile(dir
, &ldb_file
));
162 EXPECT_TRUE(base::DeleteFile(ldb_file
, false));
163 EXPECT_EQ(ldb_files
- 1, CountFilesWithExtension(dir
, FPL(".ldb")));
166 // The ldb file deleted above should be restored in Open.
167 status
= leveldb::DB::Open(options
, dir
.AsUTF8Unsafe(), &db
);
168 EXPECT_TRUE(status
.ok()) << status
.ToString();
170 status
= db
->Get(ReadOptions(), "key", &value
);
171 EXPECT_TRUE(status
.ok()) << status
.ToString();
172 EXPECT_EQ("value", value
);
175 // Ensure that deleting an ldb file also deletes its backup.
176 int orig_ldb_files
= CountFilesWithExtension(dir
, FPL(".ldb"));
177 int orig_bak_files
= CountFilesWithExtension(dir
, FPL(".bak"));
178 EXPECT_GT(ldb_files
, 0);
179 EXPECT_EQ(ldb_files
, bak_files
);
180 EXPECT_TRUE(GetFirstLDBFile(dir
, &ldb_file
));
181 options
.env
->DeleteFile(ldb_file
.AsUTF8Unsafe());
182 ldb_files
= CountFilesWithExtension(dir
, FPL(".ldb"));
183 bak_files
= CountFilesWithExtension(dir
, FPL(".bak"));
184 EXPECT_EQ(orig_ldb_files
- 1, ldb_files
);
185 EXPECT_EQ(bak_files
, ldb_files
);
188 int main(int argc
, char** argv
) { return base::TestSuite(argc
, argv
).Run(); }