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.h"
7 #include "base/files/file_enumerator.h"
8 #include "base/files/file_path.h"
9 #include "base/files/scoped_temp_dir.h"
10 #include "base/test/test_suite.h"
11 #include "env_chromium_stdio.h"
13 #include "env_chromium_win.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "third_party/leveldatabase/env_idb.h"
17 #include "third_party/leveldatabase/src/include/leveldb/db.h"
19 using namespace leveldb_env;
20 using namespace leveldb;
22 #define FPL FILE_PATH_LITERAL
24 TEST(ErrorEncoding, OnlyAMethod) {
25 const MethodID in_method = kSequentialFileRead;
26 const Status s = MakeIOError("Somefile.txt", "message", in_method);
29 EXPECT_EQ(METHOD_ONLY,
30 ParseMethodAndError(s.ToString().c_str(), &method, &error));
31 EXPECT_EQ(in_method, method);
32 EXPECT_EQ(-75, error);
35 TEST(ErrorEncoding, FileError) {
36 const MethodID in_method = kWritableFileClose;
37 const base::File::Error fe = base::File::FILE_ERROR_INVALID_OPERATION;
38 const Status s = MakeIOError("Somefile.txt", "message", in_method, fe);
41 EXPECT_EQ(METHOD_AND_PFE,
42 ParseMethodAndError(s.ToString().c_str(), &method, &error));
43 EXPECT_EQ(in_method, method);
47 TEST(ErrorEncoding, Errno) {
48 const MethodID in_method = kWritableFileFlush;
49 const int some_errno = ENOENT;
51 MakeIOError("Somefile.txt", "message", in_method, some_errno);
54 EXPECT_EQ(METHOD_AND_ERRNO,
55 ParseMethodAndError(s.ToString().c_str(), &method, &error));
56 EXPECT_EQ(in_method, method);
57 EXPECT_EQ(some_errno, error);
61 TEST(ErrorEncoding, ErrnoWin32) {
62 const MethodID in_method = kWritableFileFlush;
63 const DWORD some_errno = ERROR_FILE_NOT_FOUND;
65 MakeIOErrorWin("Somefile.txt", "message", in_method, some_errno);
68 EXPECT_EQ(METHOD_AND_ERRNO,
69 ParseMethodAndError(s.ToString().c_str(), &method, &error));
70 EXPECT_EQ(in_method, method);
71 EXPECT_EQ(some_errno, error);
75 TEST(ErrorEncoding, NoEncodedMessage) {
76 Status s = Status::IOError("Some message", "from leveldb itself");
77 MethodID method = kRandomAccessFileRead;
79 EXPECT_EQ(NONE, ParseMethodAndError(s.ToString().c_str(), &method, &error));
80 EXPECT_EQ(kRandomAccessFileRead, method);
85 class MyEnv : public T {
87 MyEnv() : directory_syncs_(0) {}
88 int directory_syncs() { return directory_syncs_; }
91 virtual void DidSyncDir(const std::string& fname) {
93 ChromiumEnv::DidSyncDir(fname);
100 template <typename T>
101 class ChromiumEnvMultiPlatformTests : public ::testing::Test {
106 typedef ::testing::Types<ChromiumEnvStdio, ChromiumEnvWin> ChromiumEnvMultiPlatformTestsTypes;
108 typedef ::testing::Types<ChromiumEnvStdio> ChromiumEnvMultiPlatformTestsTypes;
110 TYPED_TEST_CASE(ChromiumEnvMultiPlatformTests, ChromiumEnvMultiPlatformTestsTypes);
112 TYPED_TEST(ChromiumEnvMultiPlatformTests, DirectorySyncing) {
113 MyEnv<TypeParam> env;
115 base::ScopedTempDir dir;
116 ASSERT_TRUE(dir.CreateUniqueTempDir());
117 base::FilePath dir_path = dir.path();
118 std::string some_data = "some data";
119 Slice data = some_data;
121 std::string manifest_file_name =
122 FilePathToString(dir_path.Append(FILE_PATH_LITERAL("MANIFEST-001")));
123 WritableFile* manifest_file_ptr;
124 Status s = env.NewWritableFile(manifest_file_name, &manifest_file_ptr);
126 scoped_ptr<WritableFile> manifest_file(manifest_file_ptr);
127 manifest_file->Append(data);
128 EXPECT_EQ(0, env.directory_syncs());
129 manifest_file->Append(data);
130 EXPECT_EQ(0, env.directory_syncs());
132 std::string sst_file_name =
133 FilePathToString(dir_path.Append(FILE_PATH_LITERAL("000003.sst")));
134 WritableFile* sst_file_ptr;
135 s = env.NewWritableFile(sst_file_name, &sst_file_ptr);
137 scoped_ptr<WritableFile> sst_file(sst_file_ptr);
138 sst_file->Append(data);
139 EXPECT_EQ(0, env.directory_syncs());
141 manifest_file->Append(data);
142 EXPECT_EQ(1, env.directory_syncs());
143 manifest_file->Append(data);
144 EXPECT_EQ(1, env.directory_syncs());
147 int CountFilesWithExtension(const base::FilePath& dir,
148 const base::FilePath::StringType& extension) {
149 int matching_files = 0;
150 base::FileEnumerator dir_reader(
151 dir, false, base::FileEnumerator::FILES);
152 for (base::FilePath fname = dir_reader.Next(); !fname.empty();
153 fname = dir_reader.Next()) {
154 if (fname.MatchesExtension(extension))
157 return matching_files;
160 bool GetFirstLDBFile(const base::FilePath& dir, base::FilePath* ldb_file) {
161 base::FileEnumerator dir_reader(
162 dir, false, base::FileEnumerator::FILES);
163 for (base::FilePath fname = dir_reader.Next(); !fname.empty();
164 fname = dir_reader.Next()) {
165 if (fname.MatchesExtension(FPL(".ldb"))) {
173 TEST(ChromiumEnv, BackupTables) {
175 options.create_if_missing = true;
176 options.env = IDBEnv();
178 base::ScopedTempDir scoped_temp_dir;
179 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
180 base::FilePath dir = scoped_temp_dir.path();
183 Status status = DB::Open(options, dir.AsUTF8Unsafe(), &db);
184 EXPECT_TRUE(status.ok()) << status.ToString();
185 status = db->Put(WriteOptions(), "key", "value");
186 EXPECT_TRUE(status.ok()) << status.ToString();
189 db->CompactRange(&a, &z);
190 int ldb_files = CountFilesWithExtension(dir, FPL(".ldb"));
191 int bak_files = CountFilesWithExtension(dir, FPL(".bak"));
192 EXPECT_GT(ldb_files, 0);
193 EXPECT_EQ(ldb_files, bak_files);
194 base::FilePath ldb_file;
195 EXPECT_TRUE(GetFirstLDBFile(dir, &ldb_file));
197 EXPECT_TRUE(base::DeleteFile(ldb_file, false));
198 EXPECT_EQ(ldb_files - 1, CountFilesWithExtension(dir, FPL(".ldb")));
200 // The ldb file deleted above should be restored in Open.
201 status = leveldb::DB::Open(options, dir.AsUTF8Unsafe(), &db);
202 EXPECT_TRUE(status.ok()) << status.ToString();
204 status = db->Get(ReadOptions(), "key", &value);
205 EXPECT_TRUE(status.ok()) << status.ToString();
206 EXPECT_EQ("value", value);
209 // Ensure that deleting an ldb file also deletes its backup.
210 int orig_ldb_files = CountFilesWithExtension(dir, FPL(".ldb"));
211 EXPECT_GT(ldb_files, 0);
212 EXPECT_EQ(ldb_files, bak_files);
213 EXPECT_TRUE(GetFirstLDBFile(dir, &ldb_file));
214 options.env->DeleteFile(ldb_file.AsUTF8Unsafe());
215 ldb_files = CountFilesWithExtension(dir, FPL(".ldb"));
216 bak_files = CountFilesWithExtension(dir, FPL(".bak"));
217 EXPECT_EQ(orig_ldb_files - 1, ldb_files);
218 EXPECT_EQ(bak_files, ldb_files);
221 TEST(ChromiumEnv, GetChildrenEmptyDir) {
222 base::ScopedTempDir scoped_temp_dir;
223 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
224 base::FilePath dir = scoped_temp_dir.path();
227 std::vector<std::string> result;
228 leveldb::Status status = env->GetChildren(dir.AsUTF8Unsafe(), &result);
229 EXPECT_TRUE(status.ok());
230 EXPECT_EQ(0U, result.size());
233 TEST(ChromiumEnv, GetChildrenPriorResults) {
234 base::ScopedTempDir scoped_temp_dir;
235 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
236 base::FilePath dir = scoped_temp_dir.path();
238 base::FilePath new_file_dir = dir.Append(FPL("tmp_file"));
239 FILE* f = fopen(new_file_dir.AsUTF8Unsafe().c_str(), "w");
241 fputs("Temp file contents", f);
246 std::vector<std::string> result;
247 leveldb::Status status = env->GetChildren(dir.AsUTF8Unsafe(), &result);
248 EXPECT_TRUE(status.ok());
249 EXPECT_EQ(1U, result.size());
251 // And a second time should also return one result
252 status = env->GetChildren(dir.AsUTF8Unsafe(), &result);
253 EXPECT_TRUE(status.ok());
254 EXPECT_EQ(1U, result.size());
257 int main(int argc, char** argv) { return base::TestSuite(argc, argv).Run(); }