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();

Reply via email to