]>
git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/env/env_basic_test.cc
1 // Copyright (c) 2011 The LevelDB 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. See the AUTHORS file for names of contributors.
5 // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
12 #include "env/mock_env.h"
13 #include "rocksdb/convenience.h"
14 #include "rocksdb/env.h"
15 #include "rocksdb/env_encryption.h"
16 #include "test_util/testharness.h"
18 namespace ROCKSDB_NAMESPACE
{
20 // Normalizes trivial differences across Envs such that these test cases can
22 class NormalizingEnvWrapper
: public EnvWrapper
{
24 std::unique_ptr
<Env
> base_
;
27 explicit NormalizingEnvWrapper(std::unique_ptr
<Env
>&& base
)
28 : EnvWrapper(base
.get()), base_(std::move(base
)) {}
29 explicit NormalizingEnvWrapper(Env
* base
) : EnvWrapper(base
) {}
31 // Removes . and .. from directory listing
32 Status
GetChildren(const std::string
& dir
,
33 std::vector
<std::string
>* result
) override
{
34 Status status
= EnvWrapper::GetChildren(dir
, result
);
36 result
->erase(std::remove_if(result
->begin(), result
->end(),
37 [](const std::string
& s
) {
38 return s
== "." || s
== "..";
45 // Removes . and .. from directory listing
46 Status
GetChildrenFileAttributes(
47 const std::string
& dir
, std::vector
<FileAttributes
>* result
) override
{
48 Status status
= EnvWrapper::GetChildrenFileAttributes(dir
, result
);
50 result
->erase(std::remove_if(result
->begin(), result
->end(),
51 [](const FileAttributes
& fa
) {
52 return fa
.name
== "." || fa
.name
== "..";
60 class EnvBasicTestWithParam
: public testing::Test
,
61 public ::testing::WithParamInterface
<Env
*> {
64 const EnvOptions soptions_
;
65 std::string test_dir_
;
67 EnvBasicTestWithParam() : env_(GetParam()) {
68 test_dir_
= test::PerThreadDBPath(env_
, "env_basic_test");
71 void SetUp() override
{
72 env_
->CreateDirIfMissing(test_dir_
).PermitUncheckedError();
75 void TearDown() override
{
76 std::vector
<std::string
> files
;
77 env_
->GetChildren(test_dir_
, &files
).PermitUncheckedError();
78 for (const auto& file
: files
) {
79 // don't know whether it's file or directory, try both. The tests must
80 // only create files or empty directories, so one must succeed, else the
81 // directory's corrupted.
82 Status s
= env_
->DeleteFile(test_dir_
+ "/" + file
);
84 ASSERT_OK(env_
->DeleteDir(test_dir_
+ "/" + file
));
90 class EnvMoreTestWithParam
: public EnvBasicTestWithParam
{};
92 static std::unique_ptr
<Env
> def_env(new NormalizingEnvWrapper(Env::Default()));
93 INSTANTIATE_TEST_CASE_P(EnvDefault
, EnvBasicTestWithParam
,
94 ::testing::Values(def_env
.get()));
95 INSTANTIATE_TEST_CASE_P(EnvDefault
, EnvMoreTestWithParam
,
96 ::testing::Values(def_env
.get()));
98 static std::unique_ptr
<Env
> mock_env(new MockEnv(Env::Default()));
99 INSTANTIATE_TEST_CASE_P(MockEnv
, EnvBasicTestWithParam
,
100 ::testing::Values(mock_env
.get()));
103 static Env
* NewTestEncryptedEnv(Env
* base
, const std::string
& provider_id
) {
104 std::shared_ptr
<EncryptionProvider
> provider
;
105 EXPECT_OK(EncryptionProvider::CreateFromString(ConfigOptions(), provider_id
,
107 std::unique_ptr
<Env
> encrypted(NewEncryptedEnv(base
, provider
));
108 return new NormalizingEnvWrapper(std::move(encrypted
));
111 // next statements run env test against default encryption code.
112 static std::unique_ptr
<Env
> ctr_encrypt_env(NewTestEncryptedEnv(Env::Default(),
114 INSTANTIATE_TEST_CASE_P(EncryptedEnv
, EnvBasicTestWithParam
,
115 ::testing::Values(ctr_encrypt_env
.get()));
116 INSTANTIATE_TEST_CASE_P(EncryptedEnv
, EnvMoreTestWithParam
,
117 ::testing::Values(ctr_encrypt_env
.get()));
118 #endif // ROCKSDB_LITE
121 static std::unique_ptr
<Env
> mem_env(NewMemEnv(Env::Default()));
122 INSTANTIATE_TEST_CASE_P(MemEnv
, EnvBasicTestWithParam
,
123 ::testing::Values(mem_env
.get()));
127 // Returns a vector of 0 or 1 Env*, depending whether an Env is registered for
130 // The purpose of returning an empty vector (instead of nullptr) is that gtest
131 // ValuesIn() will skip running tests when given an empty collection.
132 std::vector
<Env
*> GetCustomEnvs() {
133 static Env
* custom_env
;
134 static bool init
= false;
137 const char* uri
= getenv("TEST_ENV_URI");
138 if (uri
!= nullptr) {
139 Env::LoadEnv(uri
, &custom_env
);
143 std::vector
<Env
*> res
;
144 if (custom_env
!= nullptr) {
145 res
.emplace_back(custom_env
);
150 } // anonymous namespace
152 INSTANTIATE_TEST_CASE_P(CustomEnv
, EnvBasicTestWithParam
,
153 ::testing::ValuesIn(GetCustomEnvs()));
155 INSTANTIATE_TEST_CASE_P(CustomEnv
, EnvMoreTestWithParam
,
156 ::testing::ValuesIn(GetCustomEnvs()));
158 #endif // ROCKSDB_LITE
160 TEST_P(EnvBasicTestWithParam
, Basics
) {
162 std::unique_ptr
<WritableFile
> writable_file
;
163 std::vector
<std::string
> children
;
165 // Check that the directory is empty.
166 ASSERT_EQ(Status::NotFound(), env_
->FileExists(test_dir_
+ "/non_existent"));
167 ASSERT_TRUE(!env_
->GetFileSize(test_dir_
+ "/non_existent", &file_size
).ok());
168 ASSERT_OK(env_
->GetChildren(test_dir_
, &children
));
169 ASSERT_EQ(0U, children
.size());
172 ASSERT_OK(env_
->NewWritableFile(test_dir_
+ "/f", &writable_file
, soptions_
));
173 ASSERT_OK(writable_file
->Close());
174 writable_file
.reset();
176 // Check that the file exists.
177 ASSERT_OK(env_
->FileExists(test_dir_
+ "/f"));
178 ASSERT_OK(env_
->GetFileSize(test_dir_
+ "/f", &file_size
));
179 ASSERT_EQ(0U, file_size
);
180 ASSERT_OK(env_
->GetChildren(test_dir_
, &children
));
181 ASSERT_EQ(1U, children
.size());
182 ASSERT_EQ("f", children
[0]);
183 ASSERT_OK(env_
->DeleteFile(test_dir_
+ "/f"));
185 // Write to the file.
187 env_
->NewWritableFile(test_dir_
+ "/f1", &writable_file
, soptions_
));
188 ASSERT_OK(writable_file
->Append("abc"));
189 ASSERT_OK(writable_file
->Close());
190 writable_file
.reset();
192 env_
->NewWritableFile(test_dir_
+ "/f2", &writable_file
, soptions_
));
193 ASSERT_OK(writable_file
->Close());
194 writable_file
.reset();
196 // Check for expected size.
197 ASSERT_OK(env_
->GetFileSize(test_dir_
+ "/f1", &file_size
));
198 ASSERT_EQ(3U, file_size
);
200 // Check that renaming works.
202 !env_
->RenameFile(test_dir_
+ "/non_existent", test_dir_
+ "/g").ok());
203 ASSERT_OK(env_
->RenameFile(test_dir_
+ "/f1", test_dir_
+ "/g"));
204 ASSERT_EQ(Status::NotFound(), env_
->FileExists(test_dir_
+ "/f1"));
205 ASSERT_OK(env_
->FileExists(test_dir_
+ "/g"));
206 ASSERT_OK(env_
->GetFileSize(test_dir_
+ "/g", &file_size
));
207 ASSERT_EQ(3U, file_size
);
209 // Check that renaming overwriting works
210 ASSERT_OK(env_
->RenameFile(test_dir_
+ "/f2", test_dir_
+ "/g"));
211 ASSERT_OK(env_
->GetFileSize(test_dir_
+ "/g", &file_size
));
212 ASSERT_EQ(0U, file_size
);
214 // Check that opening non-existent file fails.
215 std::unique_ptr
<SequentialFile
> seq_file
;
216 std::unique_ptr
<RandomAccessFile
> rand_file
;
217 ASSERT_TRUE(!env_
->NewSequentialFile(test_dir_
+ "/non_existent", &seq_file
,
220 ASSERT_TRUE(!seq_file
);
221 ASSERT_NOK(env_
->NewRandomAccessFile(test_dir_
+ "/non_existent", &rand_file
,
223 ASSERT_TRUE(!rand_file
);
225 // Check that deleting works.
226 ASSERT_NOK(env_
->DeleteFile(test_dir_
+ "/non_existent"));
227 ASSERT_OK(env_
->DeleteFile(test_dir_
+ "/g"));
228 ASSERT_EQ(Status::NotFound(), env_
->FileExists(test_dir_
+ "/g"));
229 ASSERT_OK(env_
->GetChildren(test_dir_
, &children
));
230 ASSERT_EQ(0U, children
.size());
231 Status s
= env_
->GetChildren(test_dir_
+ "/non_existent", &children
);
232 ASSERT_TRUE(s
.IsNotFound());
235 TEST_P(EnvBasicTestWithParam
, ReadWrite
) {
236 std::unique_ptr
<WritableFile
> writable_file
;
237 std::unique_ptr
<SequentialFile
> seq_file
;
238 std::unique_ptr
<RandomAccessFile
> rand_file
;
242 ASSERT_OK(env_
->NewWritableFile(test_dir_
+ "/f", &writable_file
, soptions_
));
243 ASSERT_OK(writable_file
->Append("hello "));
244 ASSERT_OK(writable_file
->Append("world"));
245 ASSERT_OK(writable_file
->Close());
246 writable_file
.reset();
248 // Read sequentially.
249 ASSERT_OK(env_
->NewSequentialFile(test_dir_
+ "/f", &seq_file
, soptions_
));
250 ASSERT_OK(seq_file
->Read(5, &result
, scratch
)); // Read "hello".
251 ASSERT_EQ(0, result
.compare("hello"));
252 ASSERT_OK(seq_file
->Skip(1));
253 ASSERT_OK(seq_file
->Read(1000, &result
, scratch
)); // Read "world".
254 ASSERT_EQ(0, result
.compare("world"));
255 ASSERT_OK(seq_file
->Read(1000, &result
, scratch
)); // Try reading past EOF.
256 ASSERT_EQ(0U, result
.size());
257 ASSERT_OK(seq_file
->Skip(100)); // Try to skip past end of file.
258 ASSERT_OK(seq_file
->Read(1000, &result
, scratch
));
259 ASSERT_EQ(0U, result
.size());
262 ASSERT_OK(env_
->NewRandomAccessFile(test_dir_
+ "/f", &rand_file
, soptions_
));
263 ASSERT_OK(rand_file
->Read(6, 5, &result
, scratch
)); // Read "world".
264 ASSERT_EQ(0, result
.compare("world"));
265 ASSERT_OK(rand_file
->Read(0, 5, &result
, scratch
)); // Read "hello".
266 ASSERT_EQ(0, result
.compare("hello"));
267 ASSERT_OK(rand_file
->Read(10, 100, &result
, scratch
)); // Read "d".
268 ASSERT_EQ(0, result
.compare("d"));
271 ASSERT_TRUE(rand_file
->Read(1000, 5, &result
, scratch
).ok());
274 TEST_P(EnvBasicTestWithParam
, Misc
) {
275 std::unique_ptr
<WritableFile
> writable_file
;
276 ASSERT_OK(env_
->NewWritableFile(test_dir_
+ "/b", &writable_file
, soptions_
));
278 // These are no-ops, but we test they return success.
279 ASSERT_OK(writable_file
->Sync());
280 ASSERT_OK(writable_file
->Flush());
281 ASSERT_OK(writable_file
->Close());
282 writable_file
.reset();
285 TEST_P(EnvBasicTestWithParam
, LargeWrite
) {
286 const size_t kWriteSize
= 300 * 1024;
287 char* scratch
= new char[kWriteSize
* 2];
289 std::string write_data
;
290 for (size_t i
= 0; i
< kWriteSize
; ++i
) {
291 write_data
.append(1, static_cast<char>(i
));
294 std::unique_ptr
<WritableFile
> writable_file
;
295 ASSERT_OK(env_
->NewWritableFile(test_dir_
+ "/f", &writable_file
, soptions_
));
296 ASSERT_OK(writable_file
->Append("foo"));
297 ASSERT_OK(writable_file
->Append(write_data
));
298 ASSERT_OK(writable_file
->Close());
299 writable_file
.reset();
301 std::unique_ptr
<SequentialFile
> seq_file
;
303 ASSERT_OK(env_
->NewSequentialFile(test_dir_
+ "/f", &seq_file
, soptions_
));
304 ASSERT_OK(seq_file
->Read(3, &result
, scratch
)); // Read "foo".
305 ASSERT_EQ(0, result
.compare("foo"));
308 std::string read_data
;
309 while (read
< kWriteSize
) {
310 ASSERT_OK(seq_file
->Read(kWriteSize
- read
, &result
, scratch
));
311 read_data
.append(result
.data(), result
.size());
312 read
+= result
.size();
314 ASSERT_TRUE(write_data
== read_data
);
318 TEST_P(EnvMoreTestWithParam
, GetModTime
) {
319 ASSERT_OK(env_
->CreateDirIfMissing(test_dir_
+ "/dir1"));
320 uint64_t mtime1
= 0x0;
321 ASSERT_OK(env_
->GetFileModificationTime(test_dir_
+ "/dir1", &mtime1
));
324 TEST_P(EnvMoreTestWithParam
, MakeDir
) {
325 ASSERT_OK(env_
->CreateDir(test_dir_
+ "/j"));
326 ASSERT_OK(env_
->FileExists(test_dir_
+ "/j"));
327 std::vector
<std::string
> children
;
328 env_
->GetChildren(test_dir_
, &children
);
329 ASSERT_EQ(1U, children
.size());
330 // fail because file already exists
331 ASSERT_TRUE(!env_
->CreateDir(test_dir_
+ "/j").ok());
332 ASSERT_OK(env_
->CreateDirIfMissing(test_dir_
+ "/j"));
333 ASSERT_OK(env_
->DeleteDir(test_dir_
+ "/j"));
334 ASSERT_EQ(Status::NotFound(), env_
->FileExists(test_dir_
+ "/j"));
337 TEST_P(EnvMoreTestWithParam
, GetChildren
) {
338 // empty folder returns empty vector
339 std::vector
<std::string
> children
;
340 std::vector
<Env::FileAttributes
> childAttr
;
341 ASSERT_OK(env_
->CreateDirIfMissing(test_dir_
));
342 ASSERT_OK(env_
->GetChildren(test_dir_
, &children
));
343 ASSERT_OK(env_
->FileExists(test_dir_
));
344 ASSERT_OK(env_
->GetChildrenFileAttributes(test_dir_
, &childAttr
));
345 ASSERT_EQ(0U, children
.size());
346 ASSERT_EQ(0U, childAttr
.size());
348 // folder with contents returns relative path to test dir
349 ASSERT_OK(env_
->CreateDirIfMissing(test_dir_
+ "/niu"));
350 ASSERT_OK(env_
->CreateDirIfMissing(test_dir_
+ "/you"));
351 ASSERT_OK(env_
->CreateDirIfMissing(test_dir_
+ "/guo"));
352 ASSERT_OK(env_
->GetChildren(test_dir_
, &children
));
353 ASSERT_OK(env_
->GetChildrenFileAttributes(test_dir_
, &childAttr
));
354 ASSERT_EQ(3U, children
.size());
355 ASSERT_EQ(3U, childAttr
.size());
356 for (auto each
: children
) {
357 env_
->DeleteDir(test_dir_
+ "/" + each
).PermitUncheckedError();
358 } // necessary for default POSIX env
360 // non-exist directory returns IOError
361 ASSERT_OK(env_
->DeleteDir(test_dir_
));
362 ASSERT_NOK(env_
->FileExists(test_dir_
));
363 ASSERT_NOK(env_
->GetChildren(test_dir_
, &children
));
364 ASSERT_NOK(env_
->GetChildrenFileAttributes(test_dir_
, &childAttr
));
366 // if dir is a file, returns IOError
367 ASSERT_OK(env_
->CreateDir(test_dir_
));
368 std::unique_ptr
<WritableFile
> writable_file
;
370 env_
->NewWritableFile(test_dir_
+ "/file", &writable_file
, soptions_
));
371 ASSERT_OK(writable_file
->Close());
372 writable_file
.reset();
373 ASSERT_NOK(env_
->GetChildren(test_dir_
+ "/file", &children
));
374 ASSERT_EQ(0U, children
.size());
377 } // namespace ROCKSDB_NAMESPACE
378 int main(int argc
, char** argv
) {
379 ::testing::InitGoogleTest(&argc
, argv
);
380 return RUN_ALL_TESTS();