env_basic_test.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  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 <algorithm>
  7. #include <memory>
  8. #include <string>
  9. #include <vector>
  10. #include "env/mock_env.h"
  11. #include "file/file_util.h"
  12. #include "rocksdb/convenience.h"
  13. #include "rocksdb/env.h"
  14. #include "rocksdb/env_encryption.h"
  15. #include "test_util/testharness.h"
  16. namespace ROCKSDB_NAMESPACE {
  17. namespace {
  18. using CreateEnvFunc = Env*();
  19. // These functions are used to create the various environments under which this
  20. // test can execute. These functions are used to allow the test cases to be
  21. // created without the Env being initialized, thereby eliminating a potential
  22. // static initialization fiasco/race condition when attempting to get a
  23. // custom/configured env prior to main being invoked.
  24. static Env* GetDefaultEnv() { return Env::Default(); }
  25. static Env* GetMockEnv() {
  26. static std::unique_ptr<Env> mock_env(MockEnv::Create(Env::Default()));
  27. return mock_env.get();
  28. }
  29. static Env* NewTestEncryptedEnv(Env* base, const std::string& provider_id) {
  30. ConfigOptions config_opts;
  31. config_opts.invoke_prepare_options = false;
  32. std::shared_ptr<EncryptionProvider> provider;
  33. EXPECT_OK(EncryptionProvider::CreateFromString(config_opts, provider_id,
  34. &provider));
  35. return NewEncryptedEnv(base, provider);
  36. }
  37. static Env* GetCtrEncryptedEnv() {
  38. static std::unique_ptr<Env> ctr_encrypt_env(
  39. NewTestEncryptedEnv(Env::Default(), "CTR://test"));
  40. return ctr_encrypt_env.get();
  41. }
  42. static Env* GetMemoryEnv() {
  43. static std::unique_ptr<Env> mem_env(NewMemEnv(Env::Default()));
  44. return mem_env.get();
  45. }
  46. static Env* GetTestEnv() {
  47. static std::shared_ptr<Env> env_guard;
  48. static Env* custom_env = nullptr;
  49. if (custom_env == nullptr) {
  50. const char* env_uri = getenv("TEST_ENV_URI");
  51. if (env_uri != nullptr) {
  52. EXPECT_OK(Env::CreateFromUri(ConfigOptions(), env_uri, /*fs_uri=*/"",
  53. &custom_env, &env_guard));
  54. }
  55. }
  56. EXPECT_NE(custom_env, nullptr);
  57. return custom_env;
  58. }
  59. static Env* GetTestFS() {
  60. static std::shared_ptr<Env> fs_env_guard;
  61. static Env* fs_env = nullptr;
  62. if (fs_env == nullptr) {
  63. const char* fs_uri = getenv("TEST_FS_URI");
  64. if (fs_uri != nullptr) {
  65. EXPECT_OK(Env::CreateFromUri(ConfigOptions(), /*env_uri=*/"", fs_uri,
  66. &fs_env, &fs_env_guard));
  67. }
  68. }
  69. EXPECT_NE(fs_env, nullptr);
  70. return fs_env;
  71. }
  72. } // namespace
  73. class EnvBasicTestWithParam
  74. : public testing::Test,
  75. public ::testing::WithParamInterface<CreateEnvFunc*> {
  76. public:
  77. Env* env_;
  78. const EnvOptions soptions_;
  79. std::string test_dir_;
  80. EnvBasicTestWithParam() : env_(GetParam()()) {
  81. test_dir_ = test::PerThreadDBPath(env_, "env_basic_test");
  82. }
  83. void SetUp() override { ASSERT_OK(env_->CreateDirIfMissing(test_dir_)); }
  84. void TearDown() override { ASSERT_OK(DestroyDir(env_, test_dir_)); }
  85. };
  86. class EnvMoreTestWithParam : public EnvBasicTestWithParam {};
  87. INSTANTIATE_TEST_CASE_P(EnvDefault, EnvBasicTestWithParam,
  88. ::testing::Values(&GetDefaultEnv));
  89. INSTANTIATE_TEST_CASE_P(EnvDefault, EnvMoreTestWithParam,
  90. ::testing::Values(&GetDefaultEnv));
  91. INSTANTIATE_TEST_CASE_P(MockEnv, EnvBasicTestWithParam,
  92. ::testing::Values(&GetMockEnv));
  93. // next statements run env test against default encryption code.
  94. INSTANTIATE_TEST_CASE_P(EncryptedEnv, EnvBasicTestWithParam,
  95. ::testing::Values(&GetCtrEncryptedEnv));
  96. INSTANTIATE_TEST_CASE_P(EncryptedEnv, EnvMoreTestWithParam,
  97. ::testing::Values(&GetCtrEncryptedEnv));
  98. INSTANTIATE_TEST_CASE_P(MemEnv, EnvBasicTestWithParam,
  99. ::testing::Values(&GetMemoryEnv));
  100. namespace {
  101. // Returns a vector of 0 or 1 Env*, depending whether an Env is registered for
  102. // TEST_ENV_URI.
  103. //
  104. // The purpose of returning an empty vector (instead of nullptr) is that gtest
  105. // ValuesIn() will skip running tests when given an empty collection.
  106. std::vector<CreateEnvFunc*> GetCustomEnvs() {
  107. std::vector<CreateEnvFunc*> res;
  108. const char* uri = getenv("TEST_ENV_URI");
  109. if (uri != nullptr) {
  110. res.push_back(&GetTestEnv);
  111. }
  112. uri = getenv("TEST_FS_URI");
  113. if (uri != nullptr) {
  114. res.push_back(&GetTestFS);
  115. }
  116. return res;
  117. }
  118. } // anonymous namespace
  119. INSTANTIATE_TEST_CASE_P(CustomEnv, EnvBasicTestWithParam,
  120. ::testing::ValuesIn(GetCustomEnvs()));
  121. INSTANTIATE_TEST_CASE_P(CustomEnv, EnvMoreTestWithParam,
  122. ::testing::ValuesIn(GetCustomEnvs()));
  123. TEST_P(EnvBasicTestWithParam, Basics) {
  124. uint64_t file_size;
  125. std::unique_ptr<WritableFile> writable_file;
  126. std::vector<std::string> children;
  127. // Check that the directory is empty.
  128. ASSERT_EQ(Status::NotFound(), env_->FileExists(test_dir_ + "/non_existent"));
  129. ASSERT_TRUE(!env_->GetFileSize(test_dir_ + "/non_existent", &file_size).ok());
  130. ASSERT_OK(env_->GetChildren(test_dir_, &children));
  131. ASSERT_EQ(0U, children.size());
  132. // Create a file.
  133. ASSERT_OK(env_->NewWritableFile(test_dir_ + "/f", &writable_file, soptions_));
  134. ASSERT_OK(writable_file->Close());
  135. writable_file.reset();
  136. // Check that the file exists.
  137. ASSERT_OK(env_->FileExists(test_dir_ + "/f"));
  138. ASSERT_OK(env_->GetFileSize(test_dir_ + "/f", &file_size));
  139. ASSERT_EQ(0U, file_size);
  140. ASSERT_OK(env_->GetChildren(test_dir_, &children));
  141. ASSERT_EQ(1U, children.size());
  142. ASSERT_EQ("f", children[0]);
  143. ASSERT_OK(env_->DeleteFile(test_dir_ + "/f"));
  144. // Write to the file.
  145. ASSERT_OK(
  146. env_->NewWritableFile(test_dir_ + "/f1", &writable_file, soptions_));
  147. ASSERT_OK(writable_file->Append("abc"));
  148. ASSERT_OK(writable_file->Close());
  149. writable_file.reset();
  150. ASSERT_OK(
  151. env_->NewWritableFile(test_dir_ + "/f2", &writable_file, soptions_));
  152. ASSERT_OK(writable_file->Close());
  153. writable_file.reset();
  154. // Check for expected size.
  155. ASSERT_OK(env_->GetFileSize(test_dir_ + "/f1", &file_size));
  156. ASSERT_EQ(3U, file_size);
  157. // Check that renaming works.
  158. ASSERT_TRUE(
  159. !env_->RenameFile(test_dir_ + "/non_existent", test_dir_ + "/g").ok());
  160. ASSERT_OK(env_->RenameFile(test_dir_ + "/f1", test_dir_ + "/g"));
  161. ASSERT_EQ(Status::NotFound(), env_->FileExists(test_dir_ + "/f1"));
  162. ASSERT_OK(env_->FileExists(test_dir_ + "/g"));
  163. ASSERT_OK(env_->GetFileSize(test_dir_ + "/g", &file_size));
  164. ASSERT_EQ(3U, file_size);
  165. // Check that renaming overwriting works
  166. ASSERT_OK(env_->RenameFile(test_dir_ + "/f2", test_dir_ + "/g"));
  167. ASSERT_OK(env_->GetFileSize(test_dir_ + "/g", &file_size));
  168. ASSERT_EQ(0U, file_size);
  169. // Check that opening non-existent file fails.
  170. std::unique_ptr<SequentialFile> seq_file;
  171. std::unique_ptr<RandomAccessFile> rand_file;
  172. ASSERT_TRUE(!env_->NewSequentialFile(test_dir_ + "/non_existent", &seq_file,
  173. soptions_)
  174. .ok());
  175. ASSERT_TRUE(!seq_file);
  176. ASSERT_NOK(env_->NewRandomAccessFile(test_dir_ + "/non_existent", &rand_file,
  177. soptions_));
  178. ASSERT_TRUE(!rand_file);
  179. // Check that deleting works.
  180. ASSERT_NOK(env_->DeleteFile(test_dir_ + "/non_existent"));
  181. ASSERT_OK(env_->DeleteFile(test_dir_ + "/g"));
  182. ASSERT_EQ(Status::NotFound(), env_->FileExists(test_dir_ + "/g"));
  183. ASSERT_OK(env_->GetChildren(test_dir_, &children));
  184. ASSERT_EQ(0U, children.size());
  185. Status s = env_->GetChildren(test_dir_ + "/non_existent", &children);
  186. ASSERT_TRUE(s.IsNotFound());
  187. }
  188. TEST_P(EnvBasicTestWithParam, ReadWrite) {
  189. std::unique_ptr<WritableFile> writable_file;
  190. std::unique_ptr<SequentialFile> seq_file;
  191. std::unique_ptr<RandomAccessFile> rand_file;
  192. Slice result;
  193. char scratch[100];
  194. ASSERT_OK(env_->NewWritableFile(test_dir_ + "/f", &writable_file, soptions_));
  195. ASSERT_OK(writable_file->Append("hello "));
  196. ASSERT_OK(writable_file->Append("world"));
  197. ASSERT_OK(writable_file->Close());
  198. writable_file.reset();
  199. // Read sequentially.
  200. ASSERT_OK(env_->NewSequentialFile(test_dir_ + "/f", &seq_file, soptions_));
  201. ASSERT_OK(seq_file->Read(5, &result, scratch)); // Read "hello".
  202. ASSERT_EQ(0, result.compare("hello"));
  203. ASSERT_OK(seq_file->Skip(1));
  204. ASSERT_OK(seq_file->Read(1000, &result, scratch)); // Read "world".
  205. ASSERT_EQ(0, result.compare("world"));
  206. ASSERT_OK(seq_file->Read(1000, &result, scratch)); // Try reading past EOF.
  207. ASSERT_EQ(0U, result.size());
  208. ASSERT_OK(seq_file->Skip(100)); // Try to skip past end of file.
  209. ASSERT_OK(seq_file->Read(1000, &result, scratch));
  210. ASSERT_EQ(0U, result.size());
  211. // Random reads.
  212. ASSERT_OK(env_->NewRandomAccessFile(test_dir_ + "/f", &rand_file, soptions_));
  213. ASSERT_OK(rand_file->Read(6, 5, &result, scratch)); // Read "world".
  214. ASSERT_EQ(0, result.compare("world"));
  215. ASSERT_OK(rand_file->Read(0, 5, &result, scratch)); // Read "hello".
  216. ASSERT_EQ(0, result.compare("hello"));
  217. ASSERT_OK(rand_file->Read(10, 100, &result, scratch)); // Read "d".
  218. ASSERT_EQ(0, result.compare("d"));
  219. // Too high offset.
  220. ASSERT_TRUE(rand_file->Read(1000, 5, &result, scratch).ok());
  221. }
  222. TEST_P(EnvBasicTestWithParam, Misc) {
  223. std::unique_ptr<WritableFile> writable_file;
  224. ASSERT_OK(env_->NewWritableFile(test_dir_ + "/b", &writable_file, soptions_));
  225. // These are no-ops, but we test they return success.
  226. ASSERT_OK(writable_file->Sync());
  227. ASSERT_OK(writable_file->Flush());
  228. ASSERT_OK(writable_file->Close());
  229. writable_file.reset();
  230. }
  231. TEST_P(EnvBasicTestWithParam, LargeWrite) {
  232. const size_t kWriteSize = 300 * 1024;
  233. char* scratch = new char[kWriteSize * 2];
  234. std::string write_data;
  235. for (size_t i = 0; i < kWriteSize; ++i) {
  236. write_data.append(1, static_cast<char>(i));
  237. }
  238. std::unique_ptr<WritableFile> writable_file;
  239. ASSERT_OK(env_->NewWritableFile(test_dir_ + "/f", &writable_file, soptions_));
  240. ASSERT_OK(writable_file->Append("foo"));
  241. ASSERT_OK(writable_file->Append(write_data));
  242. ASSERT_OK(writable_file->Close());
  243. writable_file.reset();
  244. std::unique_ptr<SequentialFile> seq_file;
  245. Slice result;
  246. ASSERT_OK(env_->NewSequentialFile(test_dir_ + "/f", &seq_file, soptions_));
  247. ASSERT_OK(seq_file->Read(3, &result, scratch)); // Read "foo".
  248. ASSERT_EQ(0, result.compare("foo"));
  249. size_t read = 0;
  250. std::string read_data;
  251. while (read < kWriteSize) {
  252. ASSERT_OK(seq_file->Read(kWriteSize - read, &result, scratch));
  253. read_data.append(result.data(), result.size());
  254. read += result.size();
  255. }
  256. ASSERT_TRUE(write_data == read_data);
  257. delete[] scratch;
  258. }
  259. TEST_P(EnvMoreTestWithParam, GetModTime) {
  260. ASSERT_OK(env_->CreateDirIfMissing(test_dir_ + "/dir1"));
  261. uint64_t mtime1 = 0x0;
  262. ASSERT_OK(env_->GetFileModificationTime(test_dir_ + "/dir1", &mtime1));
  263. }
  264. TEST_P(EnvMoreTestWithParam, MakeDir) {
  265. ASSERT_OK(env_->CreateDir(test_dir_ + "/j"));
  266. ASSERT_OK(env_->FileExists(test_dir_ + "/j"));
  267. std::vector<std::string> children;
  268. ASSERT_OK(env_->GetChildren(test_dir_, &children));
  269. ASSERT_EQ(1U, children.size());
  270. // fail because file already exists
  271. ASSERT_TRUE(!env_->CreateDir(test_dir_ + "/j").ok());
  272. ASSERT_OK(env_->CreateDirIfMissing(test_dir_ + "/j"));
  273. ASSERT_OK(env_->DeleteDir(test_dir_ + "/j"));
  274. ASSERT_EQ(Status::NotFound(), env_->FileExists(test_dir_ + "/j"));
  275. }
  276. TEST_P(EnvMoreTestWithParam, GetChildren) {
  277. // empty folder returns empty vector
  278. std::vector<std::string> children;
  279. std::vector<Env::FileAttributes> childAttr;
  280. ASSERT_OK(env_->CreateDirIfMissing(test_dir_));
  281. ASSERT_OK(env_->GetChildren(test_dir_, &children));
  282. ASSERT_OK(env_->FileExists(test_dir_));
  283. ASSERT_OK(env_->GetChildrenFileAttributes(test_dir_, &childAttr));
  284. ASSERT_EQ(0U, children.size());
  285. ASSERT_EQ(0U, childAttr.size());
  286. // folder with contents returns relative path to test dir
  287. ASSERT_OK(env_->CreateDirIfMissing(test_dir_ + "/niu"));
  288. ASSERT_OK(env_->CreateDirIfMissing(test_dir_ + "/you"));
  289. ASSERT_OK(env_->CreateDirIfMissing(test_dir_ + "/guo"));
  290. ASSERT_OK(env_->GetChildren(test_dir_, &children));
  291. ASSERT_OK(env_->GetChildrenFileAttributes(test_dir_, &childAttr));
  292. ASSERT_EQ(3U, children.size());
  293. ASSERT_EQ(3U, childAttr.size());
  294. for (const auto& each : children) {
  295. env_->DeleteDir(test_dir_ + "/" + each).PermitUncheckedError();
  296. } // necessary for default POSIX env
  297. // non-exist directory returns IOError
  298. ASSERT_OK(env_->DeleteDir(test_dir_));
  299. ASSERT_NOK(env_->FileExists(test_dir_));
  300. ASSERT_NOK(env_->GetChildren(test_dir_, &children));
  301. ASSERT_NOK(env_->GetChildrenFileAttributes(test_dir_, &childAttr));
  302. // if dir is a file, returns IOError
  303. ASSERT_OK(env_->CreateDir(test_dir_));
  304. std::unique_ptr<WritableFile> writable_file;
  305. ASSERT_OK(
  306. env_->NewWritableFile(test_dir_ + "/file", &writable_file, soptions_));
  307. ASSERT_OK(writable_file->Close());
  308. writable_file.reset();
  309. ASSERT_NOK(env_->GetChildren(test_dir_ + "/file", &children));
  310. ASSERT_EQ(0U, children.size());
  311. }
  312. TEST_P(EnvMoreTestWithParam, GetChildrenIgnoresDotAndDotDot) {
  313. auto* env = Env::Default();
  314. ASSERT_OK(env->CreateDirIfMissing(test_dir_));
  315. // Create a single file
  316. std::string path = test_dir_;
  317. const EnvOptions soptions;
  318. #ifdef OS_WIN
  319. path.append("\\test_file");
  320. #else
  321. path.append("/test_file");
  322. #endif
  323. std::string data("test data");
  324. std::unique_ptr<WritableFile> file;
  325. ASSERT_OK(env->NewWritableFile(path, &file, soptions));
  326. ASSERT_OK(file->Append("test data"));
  327. // get the children
  328. std::vector<std::string> result;
  329. ASSERT_OK(env->GetChildren(test_dir_, &result));
  330. // expect only one file named `test_data`, i.e. no `.` or `..` names
  331. ASSERT_EQ(result.size(), 1);
  332. ASSERT_EQ(result.at(0), "test_file");
  333. }
  334. } // namespace ROCKSDB_NAMESPACE
  335. int main(int argc, char** argv) {
  336. ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
  337. ::testing::InitGoogleTest(&argc, argv);
  338. return RUN_ALL_TESTS();
  339. }