]>
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/env.h"
14 #include "test_util/testharness.h"
16 namespace ROCKSDB_NAMESPACE
{
18 // Normalizes trivial differences across Envs such that these test cases can
20 class NormalizingEnvWrapper
: public EnvWrapper
{
22 explicit NormalizingEnvWrapper(Env
* base
) : EnvWrapper(base
) {}
24 // Removes . and .. from directory listing
25 Status
GetChildren(const std::string
& dir
,
26 std::vector
<std::string
>* result
) override
{
27 Status status
= EnvWrapper::GetChildren(dir
, result
);
29 result
->erase(std::remove_if(result
->begin(), result
->end(),
30 [](const std::string
& s
) {
31 return s
== "." || s
== "..";
38 // Removes . and .. from directory listing
39 Status
GetChildrenFileAttributes(
40 const std::string
& dir
, std::vector
<FileAttributes
>* result
) override
{
41 Status status
= EnvWrapper::GetChildrenFileAttributes(dir
, result
);
43 result
->erase(std::remove_if(result
->begin(), result
->end(),
44 [](const FileAttributes
& fa
) {
45 return fa
.name
== "." || fa
.name
== "..";
53 class EnvBasicTestWithParam
: public testing::Test
,
54 public ::testing::WithParamInterface
<Env
*> {
57 const EnvOptions soptions_
;
58 std::string test_dir_
;
60 EnvBasicTestWithParam() : env_(GetParam()) {
61 test_dir_
= test::PerThreadDBPath(env_
, "env_basic_test");
64 void SetUp() override
{ env_
->CreateDirIfMissing(test_dir_
); }
66 void TearDown() override
{
67 std::vector
<std::string
> files
;
68 env_
->GetChildren(test_dir_
, &files
);
69 for (const auto& file
: files
) {
70 // don't know whether it's file or directory, try both. The tests must
71 // only create files or empty directories, so one must succeed, else the
72 // directory's corrupted.
73 Status s
= env_
->DeleteFile(test_dir_
+ "/" + file
);
75 ASSERT_OK(env_
->DeleteDir(test_dir_
+ "/" + file
));
81 class EnvMoreTestWithParam
: public EnvBasicTestWithParam
{};
83 static std::unique_ptr
<Env
> def_env(new NormalizingEnvWrapper(Env::Default()));
84 INSTANTIATE_TEST_CASE_P(EnvDefault
, EnvBasicTestWithParam
,
85 ::testing::Values(def_env
.get()));
86 INSTANTIATE_TEST_CASE_P(EnvDefault
, EnvMoreTestWithParam
,
87 ::testing::Values(def_env
.get()));
89 static std::unique_ptr
<Env
> mock_env(new MockEnv(Env::Default()));
90 INSTANTIATE_TEST_CASE_P(MockEnv
, EnvBasicTestWithParam
,
91 ::testing::Values(mock_env
.get()));
93 static std::unique_ptr
<Env
> mem_env(NewMemEnv(Env::Default()));
94 INSTANTIATE_TEST_CASE_P(MemEnv
, EnvBasicTestWithParam
,
95 ::testing::Values(mem_env
.get()));
99 // Returns a vector of 0 or 1 Env*, depending whether an Env is registered for
102 // The purpose of returning an empty vector (instead of nullptr) is that gtest
103 // ValuesIn() will skip running tests when given an empty collection.
104 std::vector
<Env
*> GetCustomEnvs() {
105 static Env
* custom_env
;
106 static bool init
= false;
109 const char* uri
= getenv("TEST_ENV_URI");
110 if (uri
!= nullptr) {
111 Env::LoadEnv(uri
, &custom_env
);
115 std::vector
<Env
*> res
;
116 if (custom_env
!= nullptr) {
117 res
.emplace_back(custom_env
);
122 } // anonymous namespace
124 INSTANTIATE_TEST_CASE_P(CustomEnv
, EnvBasicTestWithParam
,
125 ::testing::ValuesIn(GetCustomEnvs()));
127 INSTANTIATE_TEST_CASE_P(CustomEnv
, EnvMoreTestWithParam
,
128 ::testing::ValuesIn(GetCustomEnvs()));
130 #endif // ROCKSDB_LITE
132 TEST_P(EnvBasicTestWithParam
, Basics
) {
134 std::unique_ptr
<WritableFile
> writable_file
;
135 std::vector
<std::string
> children
;
137 // Check that the directory is empty.
138 ASSERT_EQ(Status::NotFound(), env_
->FileExists(test_dir_
+ "/non_existent"));
139 ASSERT_TRUE(!env_
->GetFileSize(test_dir_
+ "/non_existent", &file_size
).ok());
140 ASSERT_OK(env_
->GetChildren(test_dir_
, &children
));
141 ASSERT_EQ(0U, children
.size());
144 ASSERT_OK(env_
->NewWritableFile(test_dir_
+ "/f", &writable_file
, soptions_
));
145 ASSERT_OK(writable_file
->Close());
146 writable_file
.reset();
148 // Check that the file exists.
149 ASSERT_OK(env_
->FileExists(test_dir_
+ "/f"));
150 ASSERT_OK(env_
->GetFileSize(test_dir_
+ "/f", &file_size
));
151 ASSERT_EQ(0U, file_size
);
152 ASSERT_OK(env_
->GetChildren(test_dir_
, &children
));
153 ASSERT_EQ(1U, children
.size());
154 ASSERT_EQ("f", children
[0]);
155 ASSERT_OK(env_
->DeleteFile(test_dir_
+ "/f"));
157 // Write to the file.
159 env_
->NewWritableFile(test_dir_
+ "/f1", &writable_file
, soptions_
));
160 ASSERT_OK(writable_file
->Append("abc"));
161 ASSERT_OK(writable_file
->Close());
162 writable_file
.reset();
164 env_
->NewWritableFile(test_dir_
+ "/f2", &writable_file
, soptions_
));
165 ASSERT_OK(writable_file
->Close());
166 writable_file
.reset();
168 // Check for expected size.
169 ASSERT_OK(env_
->GetFileSize(test_dir_
+ "/f1", &file_size
));
170 ASSERT_EQ(3U, file_size
);
172 // Check that renaming works.
174 !env_
->RenameFile(test_dir_
+ "/non_existent", test_dir_
+ "/g").ok());
175 ASSERT_OK(env_
->RenameFile(test_dir_
+ "/f1", test_dir_
+ "/g"));
176 ASSERT_EQ(Status::NotFound(), env_
->FileExists(test_dir_
+ "/f1"));
177 ASSERT_OK(env_
->FileExists(test_dir_
+ "/g"));
178 ASSERT_OK(env_
->GetFileSize(test_dir_
+ "/g", &file_size
));
179 ASSERT_EQ(3U, file_size
);
181 // Check that renaming overwriting works
182 ASSERT_OK(env_
->RenameFile(test_dir_
+ "/f2", test_dir_
+ "/g"));
183 ASSERT_OK(env_
->GetFileSize(test_dir_
+ "/g", &file_size
));
184 ASSERT_EQ(0U, file_size
);
186 // Check that opening non-existent file fails.
187 std::unique_ptr
<SequentialFile
> seq_file
;
188 std::unique_ptr
<RandomAccessFile
> rand_file
;
189 ASSERT_TRUE(!env_
->NewSequentialFile(test_dir_
+ "/non_existent", &seq_file
,
192 ASSERT_TRUE(!seq_file
);
193 ASSERT_TRUE(!env_
->NewRandomAccessFile(test_dir_
+ "/non_existent",
194 &rand_file
, soptions_
)
196 ASSERT_TRUE(!rand_file
);
198 // Check that deleting works.
199 ASSERT_TRUE(!env_
->DeleteFile(test_dir_
+ "/non_existent").ok());
200 ASSERT_OK(env_
->DeleteFile(test_dir_
+ "/g"));
201 ASSERT_EQ(Status::NotFound(), env_
->FileExists(test_dir_
+ "/g"));
202 ASSERT_OK(env_
->GetChildren(test_dir_
, &children
));
203 ASSERT_EQ(0U, children
.size());
205 env_
->GetChildren(test_dir_
+ "/non_existent", &children
).IsNotFound());
208 TEST_P(EnvBasicTestWithParam
, ReadWrite
) {
209 std::unique_ptr
<WritableFile
> writable_file
;
210 std::unique_ptr
<SequentialFile
> seq_file
;
211 std::unique_ptr
<RandomAccessFile
> rand_file
;
215 ASSERT_OK(env_
->NewWritableFile(test_dir_
+ "/f", &writable_file
, soptions_
));
216 ASSERT_OK(writable_file
->Append("hello "));
217 ASSERT_OK(writable_file
->Append("world"));
218 ASSERT_OK(writable_file
->Close());
219 writable_file
.reset();
221 // Read sequentially.
222 ASSERT_OK(env_
->NewSequentialFile(test_dir_
+ "/f", &seq_file
, soptions_
));
223 ASSERT_OK(seq_file
->Read(5, &result
, scratch
)); // Read "hello".
224 ASSERT_EQ(0, result
.compare("hello"));
225 ASSERT_OK(seq_file
->Skip(1));
226 ASSERT_OK(seq_file
->Read(1000, &result
, scratch
)); // Read "world".
227 ASSERT_EQ(0, result
.compare("world"));
228 ASSERT_OK(seq_file
->Read(1000, &result
, scratch
)); // Try reading past EOF.
229 ASSERT_EQ(0U, result
.size());
230 ASSERT_OK(seq_file
->Skip(100)); // Try to skip past end of file.
231 ASSERT_OK(seq_file
->Read(1000, &result
, scratch
));
232 ASSERT_EQ(0U, result
.size());
235 ASSERT_OK(env_
->NewRandomAccessFile(test_dir_
+ "/f", &rand_file
, soptions_
));
236 ASSERT_OK(rand_file
->Read(6, 5, &result
, scratch
)); // Read "world".
237 ASSERT_EQ(0, result
.compare("world"));
238 ASSERT_OK(rand_file
->Read(0, 5, &result
, scratch
)); // Read "hello".
239 ASSERT_EQ(0, result
.compare("hello"));
240 ASSERT_OK(rand_file
->Read(10, 100, &result
, scratch
)); // Read "d".
241 ASSERT_EQ(0, result
.compare("d"));
244 ASSERT_TRUE(rand_file
->Read(1000, 5, &result
, scratch
).ok());
247 TEST_P(EnvBasicTestWithParam
, Misc
) {
248 std::unique_ptr
<WritableFile
> writable_file
;
249 ASSERT_OK(env_
->NewWritableFile(test_dir_
+ "/b", &writable_file
, soptions_
));
251 // These are no-ops, but we test they return success.
252 ASSERT_OK(writable_file
->Sync());
253 ASSERT_OK(writable_file
->Flush());
254 ASSERT_OK(writable_file
->Close());
255 writable_file
.reset();
258 TEST_P(EnvBasicTestWithParam
, LargeWrite
) {
259 const size_t kWriteSize
= 300 * 1024;
260 char* scratch
= new char[kWriteSize
* 2];
262 std::string write_data
;
263 for (size_t i
= 0; i
< kWriteSize
; ++i
) {
264 write_data
.append(1, static_cast<char>(i
));
267 std::unique_ptr
<WritableFile
> writable_file
;
268 ASSERT_OK(env_
->NewWritableFile(test_dir_
+ "/f", &writable_file
, soptions_
));
269 ASSERT_OK(writable_file
->Append("foo"));
270 ASSERT_OK(writable_file
->Append(write_data
));
271 ASSERT_OK(writable_file
->Close());
272 writable_file
.reset();
274 std::unique_ptr
<SequentialFile
> seq_file
;
276 ASSERT_OK(env_
->NewSequentialFile(test_dir_
+ "/f", &seq_file
, soptions_
));
277 ASSERT_OK(seq_file
->Read(3, &result
, scratch
)); // Read "foo".
278 ASSERT_EQ(0, result
.compare("foo"));
281 std::string read_data
;
282 while (read
< kWriteSize
) {
283 ASSERT_OK(seq_file
->Read(kWriteSize
- read
, &result
, scratch
));
284 read_data
.append(result
.data(), result
.size());
285 read
+= result
.size();
287 ASSERT_TRUE(write_data
== read_data
);
291 TEST_P(EnvMoreTestWithParam
, GetModTime
) {
292 ASSERT_OK(env_
->CreateDirIfMissing(test_dir_
+ "/dir1"));
293 uint64_t mtime1
= 0x0;
294 ASSERT_OK(env_
->GetFileModificationTime(test_dir_
+ "/dir1", &mtime1
));
297 TEST_P(EnvMoreTestWithParam
, MakeDir
) {
298 ASSERT_OK(env_
->CreateDir(test_dir_
+ "/j"));
299 ASSERT_OK(env_
->FileExists(test_dir_
+ "/j"));
300 std::vector
<std::string
> children
;
301 env_
->GetChildren(test_dir_
, &children
);
302 ASSERT_EQ(1U, children
.size());
303 // fail because file already exists
304 ASSERT_TRUE(!env_
->CreateDir(test_dir_
+ "/j").ok());
305 ASSERT_OK(env_
->CreateDirIfMissing(test_dir_
+ "/j"));
306 ASSERT_OK(env_
->DeleteDir(test_dir_
+ "/j"));
307 ASSERT_EQ(Status::NotFound(), env_
->FileExists(test_dir_
+ "/j"));
310 TEST_P(EnvMoreTestWithParam
, GetChildren
) {
311 // empty folder returns empty vector
312 std::vector
<std::string
> children
;
313 std::vector
<Env::FileAttributes
> childAttr
;
314 ASSERT_OK(env_
->CreateDirIfMissing(test_dir_
));
315 ASSERT_OK(env_
->GetChildren(test_dir_
, &children
));
316 ASSERT_OK(env_
->FileExists(test_dir_
));
317 ASSERT_OK(env_
->GetChildrenFileAttributes(test_dir_
, &childAttr
));
318 ASSERT_EQ(0U, children
.size());
319 ASSERT_EQ(0U, childAttr
.size());
321 // folder with contents returns relative path to test dir
322 ASSERT_OK(env_
->CreateDirIfMissing(test_dir_
+ "/niu"));
323 ASSERT_OK(env_
->CreateDirIfMissing(test_dir_
+ "/you"));
324 ASSERT_OK(env_
->CreateDirIfMissing(test_dir_
+ "/guo"));
325 ASSERT_OK(env_
->GetChildren(test_dir_
, &children
));
326 ASSERT_OK(env_
->GetChildrenFileAttributes(test_dir_
, &childAttr
));
327 ASSERT_EQ(3U, children
.size());
328 ASSERT_EQ(3U, childAttr
.size());
329 for (auto each
: children
) {
330 env_
->DeleteDir(test_dir_
+ "/" + each
);
331 } // necessary for default POSIX env
333 // non-exist directory returns IOError
334 ASSERT_OK(env_
->DeleteDir(test_dir_
));
335 ASSERT_TRUE(!env_
->FileExists(test_dir_
).ok());
336 ASSERT_TRUE(!env_
->GetChildren(test_dir_
, &children
).ok());
337 ASSERT_TRUE(!env_
->GetChildrenFileAttributes(test_dir_
, &childAttr
).ok());
339 // if dir is a file, returns IOError
340 ASSERT_OK(env_
->CreateDir(test_dir_
));
341 std::unique_ptr
<WritableFile
> writable_file
;
343 env_
->NewWritableFile(test_dir_
+ "/file", &writable_file
, soptions_
));
344 ASSERT_OK(writable_file
->Close());
345 writable_file
.reset();
346 ASSERT_TRUE(!env_
->GetChildren(test_dir_
+ "/file", &children
).ok());
347 ASSERT_EQ(0U, children
.size());
350 } // namespace ROCKSDB_NAMESPACE
351 int main(int argc
, char** argv
) {
352 ::testing::InitGoogleTest(&argc
, argv
);
353 return RUN_ALL_TESTS();