From 5aca977be87cdf5a0642eb3ed036293a2b3aee56 Mon Sep 17 00:00:00 2001 From: Andrew Kryczka Date: Fri, 3 Jun 2016 18:44:22 -0700 Subject: [PATCH] env_basic_test library for testing new Envs [pluggable Env part 3] Summary: - Provide env_test as a static library. We will build it for future releases so internal Envs can use env_test by linking against this library. - Add tests for CustomEnv, which is configurable via ENV_TEST_URI environment variable. It uses the URI-based Env lookup (depends on D58449). - Refactor env_basic_test cases to use a unique/configurable directory for test files. Test Plan: built a test binary against librocksdb_env_test.a. It registered the default Env with URI prefix "a://". - verify runs all CustomEnv tests when URI with correct prefix is provided ``` $ ENV_TEST_URI="a://ok" ./tmp --gtest_filter="CustomEnv/*" ... [ PASSED ] 12 tests. ``` - verify runs no CustomEnv tests when URI with non-matching prefix is provided ``` $ ENV_TEST_URI="b://ok" ./tmp --gtest_filter="CustomEnv/*" ... [ PASSED ] 0 tests. ``` Reviewers: ldemailly, IslamAbdelRahman, lightmark, sdong Reviewed By: sdong Subscribers: andrewkr, dhruba, leveldb Differential Revision: https://reviews.facebook.net/D58485 --- Makefile | 11 +++- util/env_basic_test.cc | 121 ++++++++++++++++++++++++++++------------- 2 files changed, 92 insertions(+), 40 deletions(-) diff --git a/Makefile b/Makefile index 582824038..401c06416 100644 --- a/Makefile +++ b/Makefile @@ -394,6 +394,9 @@ TOOLS = \ rocksdb_dump \ rocksdb_undump +TEST_LIBS = \ + librocksdb_env_basic_test.a + # TODO: add back forward_iterator_bench, after making it build in all environemnts. BENCHMARKS = db_bench table_reader_bench cache_bench memtablerep_bench @@ -462,7 +465,7 @@ endif # PLATFORM_SHARED_EXT analyze tools tools_lib -all: $(LIBRARY) $(BENCHMARKS) tools tools_lib $(TESTS) +all: $(LIBRARY) $(BENCHMARKS) tools tools_lib test_libs $(TESTS) static_lib: $(LIBRARY) @@ -472,6 +475,8 @@ tools: $(TOOLS) tools_lib: $(TOOLS_LIBRARY) +test_libs: $(TEST_LIBS) + dbg: $(LIBRARY) $(BENCHMARKS) tools $(TESTS) # creates static library and programs @@ -805,6 +810,10 @@ $(TOOLS_LIBRARY): $(BENCH_SOURCES:.cc=.o) $(TOOL_SOURCES:.cc=.o) $(LIB_SOURCES:. $(AM_V_AR)rm -f $@ $(AM_V_at)$(AR) $(ARFLAGS) $@ $^ +librocksdb_env_basic_test.a: util/env_basic_test.o $(LIBOBJECTS) $(TESTHARNESS) + $(AM_V_AR)rm -f $@ + $(AM_V_at)$(AR) $(ARFLAGS) $@ $^ + db_bench: tools/db_bench.o $(BENCHTOOLOBJECTS) $(AM_LINK) diff --git a/util/env_basic_test.cc b/util/env_basic_test.cc index 0ff4c2ade..734723134 100644 --- a/util/env_basic_test.cc +++ b/util/env_basic_test.cc @@ -7,6 +7,7 @@ #include #include "rocksdb/env.h" +#include "rocksdb/utilities/env_registry.h" #include "util/mock_env.h" #include "util/testharness.h" @@ -17,18 +18,61 @@ class EnvBasicTestWithParam : public testing::Test, public: Env* env_; const EnvOptions soptions_; + std::string test_dir_; - EnvBasicTestWithParam() { env_ = GetParam(); } + EnvBasicTestWithParam() { + env_ = GetParam(); + test_dir_ = test::TmpDir(env_) + "/env_basic_test"; + } + + void SetUp() { + env_->CreateDirIfMissing(test_dir_); + std::vector files; + env_->GetChildren(test_dir_, &files); + for (const auto& file : files) { + env_->DeleteFile(test_dir_ + "/" + file); + } + } }; static std::unique_ptr mock_env(new MockEnv(Env::Default())); -INSTANTIATE_TEST_CASE_P( - MockEnv, EnvBasicTestWithParam, - ::testing::Values(mock_env.get())); +INSTANTIATE_TEST_CASE_P(MockEnv, EnvBasicTestWithParam, + ::testing::Values(mock_env.get())); #ifndef ROCKSDB_LITE static std::unique_ptr mem_env(NewMemEnv(Env::Default())); INSTANTIATE_TEST_CASE_P(MemEnv, EnvBasicTestWithParam, ::testing::Values(mem_env.get())); + +namespace { + +// Returns a vector of 0 or 1 Env*, depending whether an Env is registered for +// TEST_ENV_URI. +// +// The purpose of returning an empty vector (instead of nullptr) is that gtest +// ValuesIn() will skip running tests when given an empty collection. +std::vector GetCustomEnvs() { + static Env* custom_env; + static std::unique_ptr custom_env_guard; + static bool init = false; + if (!init) { + init = true; + const char* uri = getenv("TEST_ENV_URI"); + if (uri != nullptr) { + custom_env = NewEnvFromUri(uri, &custom_env_guard); + } + } + + std::vector res; + if (custom_env != nullptr) { + res.emplace_back(custom_env); + } + return res; +} + +} // anonymous namespace + +INSTANTIATE_TEST_CASE_P(CustomEnv, EnvBasicTestWithParam, + ::testing::ValuesIn(GetCustomEnvs())); #endif // ROCKSDB_LITE TEST_P(EnvBasicTestWithParam, Basics) { @@ -36,60 +80,60 @@ TEST_P(EnvBasicTestWithParam, Basics) { unique_ptr writable_file; std::vector children; - ASSERT_OK(env_->CreateDir("/dir")); - // Check that the directory is empty. - ASSERT_EQ(Status::NotFound(), env_->FileExists("/dir/non_existent")); - ASSERT_TRUE(!env_->GetFileSize("/dir/non_existent", &file_size).ok()); - ASSERT_OK(env_->GetChildren("/dir", &children)); + ASSERT_EQ(Status::NotFound(), env_->FileExists(test_dir_ + "/non_existent")); + ASSERT_TRUE(!env_->GetFileSize(test_dir_ + "/non_existent", &file_size).ok()); + ASSERT_OK(env_->GetChildren(test_dir_, &children)); ASSERT_EQ(0U, children.size()); // Create a file. - ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file, soptions_)); + ASSERT_OK(env_->NewWritableFile(test_dir_ + "/f", &writable_file, soptions_)); writable_file.reset(); // Check that the file exists. - ASSERT_OK(env_->FileExists("/dir/f")); - ASSERT_OK(env_->GetFileSize("/dir/f", &file_size)); + ASSERT_OK(env_->FileExists(test_dir_ + "/f")); + ASSERT_OK(env_->GetFileSize(test_dir_ + "/f", &file_size)); ASSERT_EQ(0U, file_size); - ASSERT_OK(env_->GetChildren("/dir", &children)); + ASSERT_OK(env_->GetChildren(test_dir_, &children)); ASSERT_EQ(1U, children.size()); ASSERT_EQ("f", children[0]); // Write to the file. - ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file, soptions_)); + ASSERT_OK(env_->NewWritableFile(test_dir_ + "/f", &writable_file, soptions_)); ASSERT_OK(writable_file->Append("abc")); writable_file.reset(); // Check for expected size. - ASSERT_OK(env_->GetFileSize("/dir/f", &file_size)); + ASSERT_OK(env_->GetFileSize(test_dir_ + "/f", &file_size)); ASSERT_EQ(3U, file_size); // Check that renaming works. - ASSERT_TRUE(!env_->RenameFile("/dir/non_existent", "/dir/g").ok()); - ASSERT_OK(env_->RenameFile("/dir/f", "/dir/g")); - ASSERT_EQ(Status::NotFound(), env_->FileExists("/dir/f")); - ASSERT_OK(env_->FileExists("/dir/g")); - ASSERT_OK(env_->GetFileSize("/dir/g", &file_size)); + ASSERT_TRUE(!env_->RenameFile(test_dir_ + "/non_existent", "/g").ok()); + ASSERT_OK(env_->RenameFile(test_dir_ + "/f", test_dir_ + "/g")); + ASSERT_EQ(Status::NotFound(), env_->FileExists(test_dir_ + "/f")); + ASSERT_OK(env_->FileExists(test_dir_ + "/g")); + ASSERT_OK(env_->GetFileSize(test_dir_ + "/g", &file_size)); ASSERT_EQ(3U, file_size); // Check that opening non-existent file fails. unique_ptr seq_file; unique_ptr rand_file; - ASSERT_TRUE(!env_->NewSequentialFile("/dir/non_existent", &seq_file, - soptions_).ok()); + ASSERT_TRUE(!env_->NewSequentialFile(test_dir_ + "/non_existent", &seq_file, + soptions_) + .ok()); ASSERT_TRUE(!seq_file); - ASSERT_TRUE(!env_->NewRandomAccessFile("/dir/non_existent", &rand_file, - soptions_).ok()); + ASSERT_TRUE(!env_->NewRandomAccessFile(test_dir_ + "/non_existent", + &rand_file, soptions_) + .ok()); ASSERT_TRUE(!rand_file); // Check that deleting works. - ASSERT_TRUE(!env_->DeleteFile("/dir/non_existent").ok()); - ASSERT_OK(env_->DeleteFile("/dir/g")); - ASSERT_EQ(Status::NotFound(), env_->FileExists("/dir/g")); - ASSERT_OK(env_->GetChildren("/dir", &children)); + ASSERT_TRUE(!env_->DeleteFile(test_dir_ + "/non_existent").ok()); + ASSERT_OK(env_->DeleteFile(test_dir_ + "/g")); + ASSERT_EQ(Status::NotFound(), env_->FileExists(test_dir_ + "/g")); + ASSERT_OK(env_->GetChildren(test_dir_, &children)); ASSERT_EQ(0U, children.size()); - ASSERT_OK(env_->DeleteDir("/dir")); + ASSERT_OK(env_->DeleteDir(test_dir_)); } TEST_P(EnvBasicTestWithParam, ReadWrite) { @@ -99,15 +143,13 @@ TEST_P(EnvBasicTestWithParam, ReadWrite) { Slice result; char scratch[100]; - ASSERT_OK(env_->CreateDir("/dir")); - - ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file, soptions_)); + ASSERT_OK(env_->NewWritableFile(test_dir_ + "/f", &writable_file, soptions_)); ASSERT_OK(writable_file->Append("hello ")); ASSERT_OK(writable_file->Append("world")); writable_file.reset(); // Read sequentially. - ASSERT_OK(env_->NewSequentialFile("/dir/f", &seq_file, soptions_)); + ASSERT_OK(env_->NewSequentialFile(test_dir_ + "/f", &seq_file, soptions_)); ASSERT_OK(seq_file->Read(5, &result, scratch)); // Read "hello". ASSERT_EQ(0, result.compare("hello")); ASSERT_OK(seq_file->Skip(1)); @@ -120,7 +162,7 @@ TEST_P(EnvBasicTestWithParam, ReadWrite) { ASSERT_EQ(0U, result.size()); // Random reads. - ASSERT_OK(env_->NewRandomAccessFile("/dir/f", &rand_file, soptions_)); + ASSERT_OK(env_->NewRandomAccessFile(test_dir_ + "/f", &rand_file, soptions_)); ASSERT_OK(rand_file->Read(6, 5, &result, scratch)); // Read "world". ASSERT_EQ(0, result.compare("world")); ASSERT_OK(rand_file->Read(0, 5, &result, scratch)); // Read "hello". @@ -135,8 +177,9 @@ TEST_P(EnvBasicTestWithParam, ReadWrite) { TEST_P(EnvBasicTestWithParam, Locks) { FileLock* lock; - // These are no-ops, but we test they return success. - ASSERT_OK(env_->LockFile("some file", &lock)); + // only test they return success. + // TODO(andrewkr): verify functionality + ASSERT_OK(env_->LockFile(test_dir_ + "lock_file", &lock)); ASSERT_OK(env_->UnlockFile(lock)); } @@ -146,7 +189,7 @@ TEST_P(EnvBasicTestWithParam, Misc) { ASSERT_TRUE(!test_dir.empty()); unique_ptr writable_file; - ASSERT_OK(env_->NewWritableFile("/a/b", &writable_file, soptions_)); + ASSERT_OK(env_->NewWritableFile(test_dir_ + "/b", &writable_file, soptions_)); // These are no-ops, but we test they return success. ASSERT_OK(writable_file->Sync()); @@ -165,14 +208,14 @@ TEST_P(EnvBasicTestWithParam, LargeWrite) { } unique_ptr writable_file; - ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file, soptions_)); + ASSERT_OK(env_->NewWritableFile(test_dir_ + "/f", &writable_file, soptions_)); ASSERT_OK(writable_file->Append("foo")); ASSERT_OK(writable_file->Append(write_data)); writable_file.reset(); unique_ptr seq_file; Slice result; - ASSERT_OK(env_->NewSequentialFile("/dir/f", &seq_file, soptions_)); + ASSERT_OK(env_->NewSequentialFile(test_dir_ + "/f", &seq_file, soptions_)); ASSERT_OK(seq_file->Read(3, &result, scratch)); // Read "foo". ASSERT_EQ(0, result.compare("foo"));