Repository: mesos Updated Branches: refs/heads/master 50583f15f -> a1400f79e
Added test filters to stout tests. This commit moves the test-name-based filtering done in the Mesos tests into a stout test header. The test filters search each test name for substrings and disables tests under certain circumstances. This move comes with a single new filter: a SymlinkFilter. On Windows, the creation of symlinks requires special privileges similar to `ROOT_` tests in Mesos. Prior to this commit, we would need to manually filter out specific tests when building Mesos in a non-privileged CI (such as the ASF infrastructure). Review: https://reviews.apache.org/r/57824/ Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/113da435 Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/113da435 Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/113da435 Branch: refs/heads/master Commit: 113da435b12f826b14c807d7d666676e01d58d14 Parents: 50583f1 Author: John Kordich <[email protected]> Authored: Mon Apr 10 18:31:08 2017 -0700 Committer: Joseph Wu <[email protected]> Committed: Tue Apr 11 14:32:01 2017 -0700 ---------------------------------------------------------------------- 3rdparty/stout/include/Makefile.am | 1 + .../stout/include/stout/tests/environment.hpp | 193 +++++++++++++++++++ 3rdparty/stout/tests/main.cpp | 9 + 3rdparty/stout/tests/os/filesystem_tests.cpp | 4 +- 3rdparty/stout/tests/os/rmdir_tests.cpp | 8 +- 3rdparty/stout/tests/os_tests.cpp | 6 +- 6 files changed, 212 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/113da435/3rdparty/stout/include/Makefile.am ---------------------------------------------------------------------- diff --git a/3rdparty/stout/include/Makefile.am b/3rdparty/stout/include/Makefile.am index abe3dcf..e3f4b41 100644 --- a/3rdparty/stout/include/Makefile.am +++ b/3rdparty/stout/include/Makefile.am @@ -24,6 +24,7 @@ nobase_include_HEADERS = \ stout/duration.hpp \ stout/dynamiclibrary.hpp \ stout/elf.hpp \ + stout/environment.hpp \ stout/error.hpp \ stout/errorbase.hpp \ stout/exit.hpp \ http://git-wip-us.apache.org/repos/asf/mesos/blob/113da435/3rdparty/stout/include/stout/tests/environment.hpp ---------------------------------------------------------------------- diff --git a/3rdparty/stout/include/stout/tests/environment.hpp b/3rdparty/stout/include/stout/tests/environment.hpp new file mode 100644 index 0000000..61dfe0d --- /dev/null +++ b/3rdparty/stout/include/stout/tests/environment.hpp @@ -0,0 +1,193 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __STOUT_TESTS_ENVIRONMENT_HPP__ +#define __STOUT_TESTS_ENVIRONMENT_HPP__ + +#ifndef __WINDOWS__ +#include <sys/wait.h> + +#include <unistd.h> +#endif // __WINDOWS__ + +#include <string> +#include <vector> + +#include <gtest/gtest.h> + +#include <stout/check.hpp> +#include <stout/error.hpp> +#include <stout/fs.hpp> +#include <stout/option.hpp> +#include <stout/os.hpp> +#include <stout/path.hpp> +#include <stout/strings.hpp> +#include <stout/try.hpp> + +#include <stout/os/temp.hpp> +#include <stout/os/touch.hpp> + +using std::string; +using std::vector; + +namespace stout { +namespace internal { +namespace tests { + +class TestFilter +{ +public: + TestFilter() {} + virtual ~TestFilter() {} + + // Returns true iff the test should be disabled. + virtual bool disable(const ::testing::TestInfo* test) const = 0; + + // Returns whether the test name or parameterization matches the pattern. + static bool matches(const ::testing::TestInfo* test, const string& pattern) + { + if (strings::contains(test->test_case_name(), pattern) || + strings::contains(test->name(), pattern)) { + return true; + } else if (test->type_param() != nullptr && + strings::contains(test->type_param(), pattern)) { + return true; + } + + return false; + } +}; + +// Attempt to create a symlink. If not possible, disable all unit tests +// that rely on the creation of symlinks. +class SymlinkFilter : public TestFilter +{ +public: + SymlinkFilter() + { + const Try<string> temp_path = os::mkdtemp(); + CHECK_SOME(temp_path); + + const string file = path::join(temp_path.get(), "file"); + const string link = path::join(temp_path.get(), "link"); + + CHECK_SOME(os::touch(file)); + + Try<Nothing> symlinkCheck = fs::symlink(file, link); + canCreateSymlinks = !symlinkCheck.isError(); + + if (!canCreateSymlinks) { + std::cerr + << "-------------------------------------------------------------\n" + << "Not able to create Symlinks, so no symlink tests will be run\n" + << "-------------------------------------------------------------" + << std::endl; + } + } + + bool disable(const ::testing::TestInfo* test) const + { + return matches(test, "SYMLINK_") && !canCreateSymlinks; + } + +private: + bool canCreateSymlinks; +}; + + +// Return list of disabled tests based on test name based filters. +static vector<string> disabled( + const ::testing::UnitTest* unitTest, + const vector<std::shared_ptr<TestFilter>>& filters) +{ + vector<string> disabled; + + for (int i = 0; i < unitTest->total_test_case_count(); i++) { + const ::testing::TestCase* testCase = unitTest->GetTestCase(i); + for (int j = 0; j < testCase->total_test_count(); j++) { + const ::testing::TestInfo* test = testCase->GetTestInfo(j); + + foreach (const std::shared_ptr<TestFilter>& filter, filters) { + if (filter->disable(test)) { + disabled.push_back( + test->test_case_name() + string(".") + test->name()); + break; + } + } + } + } + + return disabled; +} + +// Used to set up and manage the test environment. +class Environment : public ::testing::Environment { +public: + // We use the constructor to setup specific tests by updating the + // gtest filter. We do this so that we can selectively run tests that + // require root or specific OS support (e.g., cgroups). Note that this + // should not effect any other filters that have been put in place + // either on the command line or via an environment variable. + // NOTE: This should be done before invoking `RUN_ALL_TESTS`. + Environment(vector<std::shared_ptr<TestFilter>> filters) + { + // First we split the current filter into enabled and disabled tests + // (which are separated by a '-'). + const string& filter = ::testing::GTEST_FLAG(filter); + + // An empty filter indicates no tests should be run. + if (filter.empty()) { + return; + } + + filters.push_back(std::shared_ptr<TestFilter>(new SymlinkFilter())); + + string enabled; + string disabled; + + size_t dash = filter.find('-'); + if (dash != string::npos) { + enabled = filter.substr(0, dash); + disabled = filter.substr(dash + 1); + } else { + enabled = filter; + } + + // Use universal filter if not specified. + if (enabled.empty()) { + enabled = "*"; + } + + // Ensure disabled tests end with ":" separator before we add more. + if (!disabled.empty() && !strings::endsWith(disabled, ":")) { + disabled += ":"; + } + + // Construct the filter string to handle system or platform specific tests. + ::testing::UnitTest* unitTest = ::testing::UnitTest::GetInstance(); + + disabled += strings::join(":", tests::disabled(unitTest, filters)); + + // Now update the gtest flag. + ::testing::GTEST_FLAG(filter) = enabled + "-" + disabled; + } +}; + +} // namespace tests { +} // namespace internal { +} // namespace stout { + +#endif // __STOUT_TESTS_ENVIRONMENT_HPP__ http://git-wip-us.apache.org/repos/asf/mesos/blob/113da435/3rdparty/stout/tests/main.cpp ---------------------------------------------------------------------- diff --git a/3rdparty/stout/tests/main.cpp b/3rdparty/stout/tests/main.cpp index f41b29c..fbbe839 100644 --- a/3rdparty/stout/tests/main.cpp +++ b/3rdparty/stout/tests/main.cpp @@ -20,6 +20,11 @@ #include <stout/os/socket.hpp> // For `wsa_*` on Windows. +#include <stout/tests/environment.hpp> + +using stout::internal::tests::Environment; +using stout::internal::tests::TestFilter; + #ifdef __WINDOWS__ // A no-op parameter validator. We use this to prevent the Windows @@ -61,6 +66,10 @@ int main(int argc, char** argv) _set_invalid_parameter_handler(noop_invalid_parameter_handler); #endif // __WINDOWS__ + vector<std::shared_ptr<TestFilter>> filters; + Environment* environment = new Environment(filters); + testing::AddGlobalTestEnvironment(environment); + const int test_results = RUN_ALL_TESTS(); // Prefer to return the error code from the test run over the error code http://git-wip-us.apache.org/repos/asf/mesos/blob/113da435/3rdparty/stout/tests/os/filesystem_tests.cpp ---------------------------------------------------------------------- diff --git a/3rdparty/stout/tests/os/filesystem_tests.cpp b/3rdparty/stout/tests/os/filesystem_tests.cpp index e445daf..ee5a1a1 100644 --- a/3rdparty/stout/tests/os/filesystem_tests.cpp +++ b/3rdparty/stout/tests/os/filesystem_tests.cpp @@ -179,7 +179,7 @@ TEST_F(FsTest, Touch) } -TEST_F(FsTest, Symlink) +TEST_F(FsTest, SYMLINK_Symlink) { const string temp_path = os::getcwd(); const string link = path::join(temp_path, "sym.link"); @@ -198,7 +198,7 @@ TEST_F(FsTest, Symlink) } -TEST_F(FsTest, Rm) +TEST_F(FsTest, SYMLINK_Rm) { const string tmpdir = os::getcwd(); http://git-wip-us.apache.org/repos/asf/mesos/blob/113da435/3rdparty/stout/tests/os/rmdir_tests.cpp ---------------------------------------------------------------------- diff --git a/3rdparty/stout/tests/os/rmdir_tests.cpp b/3rdparty/stout/tests/os/rmdir_tests.cpp index ed43b44..0fcc2d1 100644 --- a/3rdparty/stout/tests/os/rmdir_tests.cpp +++ b/3rdparty/stout/tests/os/rmdir_tests.cpp @@ -285,7 +285,7 @@ TEST_F(RmdirTest, RemoveDirectoryWithDeviceFile) // MESOS-5881. // This test verifies that `rmdir` can remove a directory with a // symlink that has no target. -TEST_F_TEMP_DISABLED_ON_WINDOWS(RmdirTest, RemoveDirectoryNoTargetSymbolicLink) +TEST_F_TEMP_DISABLED_ON_WINDOWS(RmdirTest, SYMLINK_RmDirNoTargetSymbolicLink) { const string newDirectory = path::join(os::getcwd(), "newDirectory"); ASSERT_SOME(os::mkdir(newDirectory)); @@ -301,7 +301,7 @@ TEST_F_TEMP_DISABLED_ON_WINDOWS(RmdirTest, RemoveDirectoryNoTargetSymbolicLink) // This test verifies that `rmdir` can remove a directory with a // "hanging" symlink whose target has been deleted. -TEST_F(RmdirTest, RemoveDirectoryHangingSymlink) +TEST_F(RmdirTest, SYMLINK_RemoveDirectoryHangingSymlink) { const string newDirectory = path::join(os::getcwd(), "newDirectory"); ASSERT_SOME(os::mkdir(newDirectory)); @@ -321,7 +321,7 @@ TEST_F(RmdirTest, RemoveDirectoryHangingSymlink) // This test verifies that `rmdir` will only remove the symbolic link and not // the target directory. -TEST_F(RmdirTest, RemoveDirectoryWithSymbolicLinkTargetDirectory) +TEST_F(RmdirTest, SYMLINK_RemoveDirectoryWithSymbolicLinkTargetDirectory) { const string newDirectory = path::join(os::getcwd(), "newDirectory"); ASSERT_SOME(os::mkdir(newDirectory)); @@ -344,7 +344,7 @@ TEST_F(RmdirTest, RemoveDirectoryWithSymbolicLinkTargetDirectory) // This test verifies that `rmdir` will only remove the symbolic link and not // the target file. -TEST_F(RmdirTest, RemoveDirectoryWithSymbolicLinkTargetFile) +TEST_F(RmdirTest, SYMLINK_RemoveDirectoryWithSymbolicLinkTargetFile) { const string newDirectory = path::join(os::getcwd(), "newDirectory"); ASSERT_SOME(os::mkdir(newDirectory)); http://git-wip-us.apache.org/repos/asf/mesos/blob/113da435/3rdparty/stout/tests/os_tests.cpp ---------------------------------------------------------------------- diff --git a/3rdparty/stout/tests/os_tests.cpp b/3rdparty/stout/tests/os_tests.cpp index 8b95314..7f785b0 100644 --- a/3rdparty/stout/tests/os_tests.cpp +++ b/3rdparty/stout/tests/os_tests.cpp @@ -212,7 +212,7 @@ TEST_F(OsTest, Nonblock) // Tests all four combinations of following a link or not and of a file // or a link as argument. Also tests that an error is returned for a // non-existing file. -TEST_F_TEMP_DISABLED_ON_WINDOWS(OsTest, Size) +TEST_F_TEMP_DISABLED_ON_WINDOWS(OsTest, SYMLINK_Size) { const string file = path::join(os::getcwd(), UUID::random().toString()); @@ -754,7 +754,7 @@ TEST_F(OsTest, User) } -TEST_F(OsTest, Chown) +TEST_F(OsTest, SYMLINK_Chown) { using os::stat::DO_NOT_FOLLOW_SYMLINK; @@ -979,7 +979,7 @@ TEST_F(OsTest, Mknod) // TODO(hausdorff): Look into enabling this test on Windows. Currently it is // not possible to create a symlink on Windows unless the target exists. See // MESOS-5881. -TEST_F_TEMP_DISABLED_ON_WINDOWS(OsTest, Realpath) +TEST_F_TEMP_DISABLED_ON_WINDOWS(OsTest, SYMLINK_Realpath) { // Create a file. const Try<string> _testFile = os::mktemp();
