env_basic_test.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  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.
  4. //
  5. // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
  6. #include <memory>
  7. #include <string>
  8. #include <vector>
  9. #include <algorithm>
  10. #include "env/mock_env.h"
  11. #include "rocksdb/env.h"
  12. #include "test_util/testharness.h"
  13. namespace ROCKSDB_NAMESPACE {
  14. // Normalizes trivial differences across Envs such that these test cases can
  15. // run on all Envs.
  16. class NormalizingEnvWrapper : public EnvWrapper {
  17. public:
  18. explicit NormalizingEnvWrapper(Env* base) : EnvWrapper(base) {}
  19. // Removes . and .. from directory listing
  20. Status GetChildren(const std::string& dir,
  21. std::vector<std::string>* result) override {
  22. Status status = EnvWrapper::GetChildren(dir, result);
  23. if (status.ok()) {
  24. result->erase(std::remove_if(result->begin(), result->end(),
  25. [](const std::string& s) {
  26. return s == "." || s == "..";
  27. }),
  28. result->end());
  29. }
  30. return status;
  31. }
  32. // Removes . and .. from directory listing
  33. Status GetChildrenFileAttributes(
  34. const std::string& dir, std::vector<FileAttributes>* result) override {
  35. Status status = EnvWrapper::GetChildrenFileAttributes(dir, result);
  36. if (status.ok()) {
  37. result->erase(std::remove_if(result->begin(), result->end(),
  38. [](const FileAttributes& fa) {
  39. return fa.name == "." || fa.name == "..";
  40. }),
  41. result->end());
  42. }
  43. return status;
  44. }
  45. };
  46. class EnvBasicTestWithParam : public testing::Test,
  47. public ::testing::WithParamInterface<Env*> {
  48. public:
  49. Env* env_;
  50. const EnvOptions soptions_;
  51. std::string test_dir_;
  52. EnvBasicTestWithParam() : env_(GetParam()) {
  53. test_dir_ = test::PerThreadDBPath(env_, "env_basic_test");
  54. }
  55. void SetUp() override { env_->CreateDirIfMissing(test_dir_); }
  56. void TearDown() override {
  57. std::vector<std::string> files;
  58. env_->GetChildren(test_dir_, &files);
  59. for (const auto& file : files) {
  60. // don't know whether it's file or directory, try both. The tests must
  61. // only create files or empty directories, so one must succeed, else the
  62. // directory's corrupted.
  63. Status s = env_->DeleteFile(test_dir_ + "/" + file);
  64. if (!s.ok()) {
  65. ASSERT_OK(env_->DeleteDir(test_dir_ + "/" + file));
  66. }
  67. }
  68. }
  69. };
  70. class EnvMoreTestWithParam : public EnvBasicTestWithParam {};
  71. static std::unique_ptr<Env> def_env(new NormalizingEnvWrapper(Env::Default()));
  72. INSTANTIATE_TEST_CASE_P(EnvDefault, EnvBasicTestWithParam,
  73. ::testing::Values(def_env.get()));
  74. INSTANTIATE_TEST_CASE_P(EnvDefault, EnvMoreTestWithParam,
  75. ::testing::Values(def_env.get()));
  76. static std::unique_ptr<Env> mock_env(new MockEnv(Env::Default()));
  77. INSTANTIATE_TEST_CASE_P(MockEnv, EnvBasicTestWithParam,
  78. ::testing::Values(mock_env.get()));
  79. #ifndef ROCKSDB_LITE
  80. static std::unique_ptr<Env> mem_env(NewMemEnv(Env::Default()));
  81. INSTANTIATE_TEST_CASE_P(MemEnv, EnvBasicTestWithParam,
  82. ::testing::Values(mem_env.get()));
  83. namespace {
  84. // Returns a vector of 0 or 1 Env*, depending whether an Env is registered for
  85. // TEST_ENV_URI.
  86. //
  87. // The purpose of returning an empty vector (instead of nullptr) is that gtest
  88. // ValuesIn() will skip running tests when given an empty collection.
  89. std::vector<Env*> GetCustomEnvs() {
  90. static Env* custom_env;
  91. static bool init = false;
  92. if (!init) {
  93. init = true;
  94. const char* uri = getenv("TEST_ENV_URI");
  95. if (uri != nullptr) {
  96. Env::LoadEnv(uri, &custom_env);
  97. }
  98. }
  99. std::vector<Env*> res;
  100. if (custom_env != nullptr) {
  101. res.emplace_back(custom_env);
  102. }
  103. return res;
  104. }
  105. } // anonymous namespace
  106. INSTANTIATE_TEST_CASE_P(CustomEnv, EnvBasicTestWithParam,
  107. ::testing::ValuesIn(GetCustomEnvs()));
  108. INSTANTIATE_TEST_CASE_P(CustomEnv, EnvMoreTestWithParam,
  109. ::testing::ValuesIn(GetCustomEnvs()));
  110. #endif // ROCKSDB_LITE
  111. TEST_P(EnvBasicTestWithParam, Basics) {
  112. uint64_t file_size;
  113. std::unique_ptr<WritableFile> writable_file;
  114. std::vector<std::string> children;
  115. // Check that the directory is empty.
  116. ASSERT_EQ(Status::NotFound(), env_->FileExists(test_dir_ + "/non_existent"));
  117. ASSERT_TRUE(!env_->GetFileSize(test_dir_ + "/non_existent", &file_size).ok());
  118. ASSERT_OK(env_->GetChildren(test_dir_, &children));
  119. ASSERT_EQ(0U, children.size());
  120. // Create a file.
  121. ASSERT_OK(env_->NewWritableFile(test_dir_ + "/f", &writable_file, soptions_));
  122. ASSERT_OK(writable_file->Close());
  123. writable_file.reset();
  124. // Check that the file exists.
  125. ASSERT_OK(env_->FileExists(test_dir_ + "/f"));
  126. ASSERT_OK(env_->GetFileSize(test_dir_ + "/f", &file_size));
  127. ASSERT_EQ(0U, file_size);
  128. ASSERT_OK(env_->GetChildren(test_dir_, &children));
  129. ASSERT_EQ(1U, children.size());
  130. ASSERT_EQ("f", children[0]);
  131. ASSERT_OK(env_->DeleteFile(test_dir_ + "/f"));
  132. // Write to the file.
  133. ASSERT_OK(
  134. env_->NewWritableFile(test_dir_ + "/f1", &writable_file, soptions_));
  135. ASSERT_OK(writable_file->Append("abc"));
  136. ASSERT_OK(writable_file->Close());
  137. writable_file.reset();
  138. ASSERT_OK(
  139. env_->NewWritableFile(test_dir_ + "/f2", &writable_file, soptions_));
  140. ASSERT_OK(writable_file->Close());
  141. writable_file.reset();
  142. // Check for expected size.
  143. ASSERT_OK(env_->GetFileSize(test_dir_ + "/f1", &file_size));
  144. ASSERT_EQ(3U, file_size);
  145. // Check that renaming works.
  146. ASSERT_TRUE(
  147. !env_->RenameFile(test_dir_ + "/non_existent", test_dir_ + "/g").ok());
  148. ASSERT_OK(env_->RenameFile(test_dir_ + "/f1", test_dir_ + "/g"));
  149. ASSERT_EQ(Status::NotFound(), env_->FileExists(test_dir_ + "/f1"));
  150. ASSERT_OK(env_->FileExists(test_dir_ + "/g"));
  151. ASSERT_OK(env_->GetFileSize(test_dir_ + "/g", &file_size));
  152. ASSERT_EQ(3U, file_size);
  153. // Check that renaming overwriting works
  154. ASSERT_OK(env_->RenameFile(test_dir_ + "/f2", test_dir_ + "/g"));
  155. ASSERT_OK(env_->GetFileSize(test_dir_ + "/g", &file_size));
  156. ASSERT_EQ(0U, file_size);
  157. // Check that opening non-existent file fails.
  158. std::unique_ptr<SequentialFile> seq_file;
  159. std::unique_ptr<RandomAccessFile> rand_file;
  160. ASSERT_TRUE(!env_->NewSequentialFile(test_dir_ + "/non_existent", &seq_file,
  161. soptions_)
  162. .ok());
  163. ASSERT_TRUE(!seq_file);
  164. ASSERT_TRUE(!env_->NewRandomAccessFile(test_dir_ + "/non_existent",
  165. &rand_file, soptions_)
  166. .ok());
  167. ASSERT_TRUE(!rand_file);
  168. // Check that deleting works.
  169. ASSERT_TRUE(!env_->DeleteFile(test_dir_ + "/non_existent").ok());
  170. ASSERT_OK(env_->DeleteFile(test_dir_ + "/g"));
  171. ASSERT_EQ(Status::NotFound(), env_->FileExists(test_dir_ + "/g"));
  172. ASSERT_OK(env_->GetChildren(test_dir_, &children));
  173. ASSERT_EQ(0U, children.size());
  174. ASSERT_TRUE(
  175. env_->GetChildren(test_dir_ + "/non_existent", &children).IsNotFound());
  176. }
  177. TEST_P(EnvBasicTestWithParam, ReadWrite) {
  178. std::unique_ptr<WritableFile> writable_file;
  179. std::unique_ptr<SequentialFile> seq_file;
  180. std::unique_ptr<RandomAccessFile> rand_file;
  181. Slice result;
  182. char scratch[100];
  183. ASSERT_OK(env_->NewWritableFile(test_dir_ + "/f", &writable_file, soptions_));
  184. ASSERT_OK(writable_file->Append("hello "));
  185. ASSERT_OK(writable_file->Append("world"));
  186. ASSERT_OK(writable_file->Close());
  187. writable_file.reset();
  188. // Read sequentially.
  189. ASSERT_OK(env_->NewSequentialFile(test_dir_ + "/f", &seq_file, soptions_));
  190. ASSERT_OK(seq_file->Read(5, &result, scratch)); // Read "hello".
  191. ASSERT_EQ(0, result.compare("hello"));
  192. ASSERT_OK(seq_file->Skip(1));
  193. ASSERT_OK(seq_file->Read(1000, &result, scratch)); // Read "world".
  194. ASSERT_EQ(0, result.compare("world"));
  195. ASSERT_OK(seq_file->Read(1000, &result, scratch)); // Try reading past EOF.
  196. ASSERT_EQ(0U, result.size());
  197. ASSERT_OK(seq_file->Skip(100)); // Try to skip past end of file.
  198. ASSERT_OK(seq_file->Read(1000, &result, scratch));
  199. ASSERT_EQ(0U, result.size());
  200. // Random reads.
  201. ASSERT_OK(env_->NewRandomAccessFile(test_dir_ + "/f", &rand_file, soptions_));
  202. ASSERT_OK(rand_file->Read(6, 5, &result, scratch)); // Read "world".
  203. ASSERT_EQ(0, result.compare("world"));
  204. ASSERT_OK(rand_file->Read(0, 5, &result, scratch)); // Read "hello".
  205. ASSERT_EQ(0, result.compare("hello"));
  206. ASSERT_OK(rand_file->Read(10, 100, &result, scratch)); // Read "d".
  207. ASSERT_EQ(0, result.compare("d"));
  208. // Too high offset.
  209. ASSERT_TRUE(rand_file->Read(1000, 5, &result, scratch).ok());
  210. }
  211. TEST_P(EnvBasicTestWithParam, Misc) {
  212. std::unique_ptr<WritableFile> writable_file;
  213. ASSERT_OK(env_->NewWritableFile(test_dir_ + "/b", &writable_file, soptions_));
  214. // These are no-ops, but we test they return success.
  215. ASSERT_OK(writable_file->Sync());
  216. ASSERT_OK(writable_file->Flush());
  217. ASSERT_OK(writable_file->Close());
  218. writable_file.reset();
  219. }
  220. TEST_P(EnvBasicTestWithParam, LargeWrite) {
  221. const size_t kWriteSize = 300 * 1024;
  222. char* scratch = new char[kWriteSize * 2];
  223. std::string write_data;
  224. for (size_t i = 0; i < kWriteSize; ++i) {
  225. write_data.append(1, static_cast<char>(i));
  226. }
  227. std::unique_ptr<WritableFile> writable_file;
  228. ASSERT_OK(env_->NewWritableFile(test_dir_ + "/f", &writable_file, soptions_));
  229. ASSERT_OK(writable_file->Append("foo"));
  230. ASSERT_OK(writable_file->Append(write_data));
  231. ASSERT_OK(writable_file->Close());
  232. writable_file.reset();
  233. std::unique_ptr<SequentialFile> seq_file;
  234. Slice result;
  235. ASSERT_OK(env_->NewSequentialFile(test_dir_ + "/f", &seq_file, soptions_));
  236. ASSERT_OK(seq_file->Read(3, &result, scratch)); // Read "foo".
  237. ASSERT_EQ(0, result.compare("foo"));
  238. size_t read = 0;
  239. std::string read_data;
  240. while (read < kWriteSize) {
  241. ASSERT_OK(seq_file->Read(kWriteSize - read, &result, scratch));
  242. read_data.append(result.data(), result.size());
  243. read += result.size();
  244. }
  245. ASSERT_TRUE(write_data == read_data);
  246. delete [] scratch;
  247. }
  248. TEST_P(EnvMoreTestWithParam, GetModTime) {
  249. ASSERT_OK(env_->CreateDirIfMissing(test_dir_ + "/dir1"));
  250. uint64_t mtime1 = 0x0;
  251. ASSERT_OK(env_->GetFileModificationTime(test_dir_ + "/dir1", &mtime1));
  252. }
  253. TEST_P(EnvMoreTestWithParam, MakeDir) {
  254. ASSERT_OK(env_->CreateDir(test_dir_ + "/j"));
  255. ASSERT_OK(env_->FileExists(test_dir_ + "/j"));
  256. std::vector<std::string> children;
  257. env_->GetChildren(test_dir_, &children);
  258. ASSERT_EQ(1U, children.size());
  259. // fail because file already exists
  260. ASSERT_TRUE(!env_->CreateDir(test_dir_ + "/j").ok());
  261. ASSERT_OK(env_->CreateDirIfMissing(test_dir_ + "/j"));
  262. ASSERT_OK(env_->DeleteDir(test_dir_ + "/j"));
  263. ASSERT_EQ(Status::NotFound(), env_->FileExists(test_dir_ + "/j"));
  264. }
  265. TEST_P(EnvMoreTestWithParam, GetChildren) {
  266. // empty folder returns empty vector
  267. std::vector<std::string> children;
  268. std::vector<Env::FileAttributes> childAttr;
  269. ASSERT_OK(env_->CreateDirIfMissing(test_dir_));
  270. ASSERT_OK(env_->GetChildren(test_dir_, &children));
  271. ASSERT_OK(env_->FileExists(test_dir_));
  272. ASSERT_OK(env_->GetChildrenFileAttributes(test_dir_, &childAttr));
  273. ASSERT_EQ(0U, children.size());
  274. ASSERT_EQ(0U, childAttr.size());
  275. // folder with contents returns relative path to test dir
  276. ASSERT_OK(env_->CreateDirIfMissing(test_dir_ + "/niu"));
  277. ASSERT_OK(env_->CreateDirIfMissing(test_dir_ + "/you"));
  278. ASSERT_OK(env_->CreateDirIfMissing(test_dir_ + "/guo"));
  279. ASSERT_OK(env_->GetChildren(test_dir_, &children));
  280. ASSERT_OK(env_->GetChildrenFileAttributes(test_dir_, &childAttr));
  281. ASSERT_EQ(3U, children.size());
  282. ASSERT_EQ(3U, childAttr.size());
  283. for (auto each : children) {
  284. env_->DeleteDir(test_dir_ + "/" + each);
  285. } // necessary for default POSIX env
  286. // non-exist directory returns IOError
  287. ASSERT_OK(env_->DeleteDir(test_dir_));
  288. ASSERT_TRUE(!env_->FileExists(test_dir_).ok());
  289. ASSERT_TRUE(!env_->GetChildren(test_dir_, &children).ok());
  290. ASSERT_TRUE(!env_->GetChildrenFileAttributes(test_dir_, &childAttr).ok());
  291. // if dir is a file, returns IOError
  292. ASSERT_OK(env_->CreateDir(test_dir_));
  293. std::unique_ptr<WritableFile> writable_file;
  294. ASSERT_OK(
  295. env_->NewWritableFile(test_dir_ + "/file", &writable_file, soptions_));
  296. ASSERT_OK(writable_file->Close());
  297. writable_file.reset();
  298. ASSERT_TRUE(!env_->GetChildren(test_dir_ + "/file", &children).ok());
  299. ASSERT_EQ(0U, children.size());
  300. }
  301. } // namespace ROCKSDB_NAMESPACE
  302. int main(int argc, char** argv) {
  303. ::testing::InitGoogleTest(&argc, argv);
  304. return RUN_ALL_TESTS();
  305. }