Repository: mesos
Updated Branches:
  refs/heads/master 7a6dda708 -> 6cca8c807


Enable mesos tests installation.

This patch enables the installation mesos-tests and its dependencies
and helper tool. The goal is to allow operators to build a separate
test package that can be run at deployment time to verify that Mesos
works in the deployment environment.

Since the build directory is searched first, to run it on a host
that has a build tree, you need to specify a non-existent tree:

~ $ $PREFIX/libexec/mesos/tests/mesos-tests --build_dir=/none

\- Add --enable-tests-install
\- Fix mesos-tests gmock dependencies
\- Optionally install tests, helpers and test modules
\- Add utility helpers to find various test resources

Review: https://reviews.apache.org/r/40553/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/6cca8c80
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/6cca8c80
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/6cca8c80

Branch: refs/heads/master
Commit: 6cca8c8071e4b863d951a1631141f861c47826d1
Parents: 7a6dda7
Author: James Peach <[email protected]>
Authored: Mon Feb 8 11:28:07 2016 +0100
Committer: Till Toenshoff <[email protected]>
Committed: Mon Feb 8 19:22:13 2016 +0100

----------------------------------------------------------------------
 Makefile.am                                     |   8 ++
 configure.ac                                    |  11 ++
 src/Makefile.am                                 | 111 ++++++++++++----
 src/examples/test_framework.cpp                 |   4 +-
 src/tests/balloon_framework_test.sh             |   9 +-
 src/tests/containerizer/launch_tests.cpp        |   3 +-
 src/tests/containerizer/memory_test_helper.cpp  |   5 +-
 .../containerizer/mesos_containerizer_tests.cpp |   4 +-
 src/tests/containerizer/ns_tests.cpp            |   3 +-
 src/tests/containerizer/port_mapping_tests.cpp  |   2 +-
 src/tests/environment.cpp                       |   8 +-
 src/tests/event_call_framework_test.sh          |   5 +-
 src/tests/fetcher_tests.cpp                     |  30 ++---
 src/tests/health_check_tests.cpp                |   2 +-
 src/tests/mesos.cpp                             |   2 +-
 src/tests/module.cpp                            |  83 ++----------
 src/tests/module_tests.cpp                      |  41 ++----
 src/tests/no_executor_framework_test.sh         |   5 +-
 src/tests/oversubscription_tests.cpp            |   3 +-
 src/tests/persistent_volume_framework_test.sh   |   6 +-
 src/tests/script.cpp                            |  22 +++-
 src/tests/slave_tests.cpp                       |  10 +-
 src/tests/test_framework_test.sh                |   6 +-
 src/tests/utils.cpp                             | 127 +++++++++++++++++++
 src/tests/utils.hpp                             |  42 ++++++
 25 files changed, 372 insertions(+), 180 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/Makefile.am
----------------------------------------------------------------------
diff --git a/Makefile.am b/Makefile.am
index fbd4e5a..2b43854 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -27,6 +27,9 @@ PHONY_TARGETS =
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = mesos.pc
 
+# Directories to optionally install test binaries and libraries.
+testlibexecdir = $(pkglibexecdir)/tests
+
 # Since we generate several files in src/ with config.status, make
 # sure they're regenerated before we recurse into the src directory.
 all-recursive: src/python/setup.py                     \
@@ -92,5 +95,10 @@ distclean-local:
        -rm -f ./3rdparty/libprocess/report.xml
        -rm -f ./src/report.xml
 
+if INSTALL_TESTS
+dist_testlibexec_SCRIPTS =                             \
+  support/atexit.sh                                    \
+  support/colors.sh
+endif
 
 .PHONY: $(PHONY_TARGETS)

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index cb39c7f..b9a9906 100644
--- a/configure.ac
+++ b/configure.ac
@@ -241,6 +241,12 @@ AC_ARG_ENABLE([python-dependency-install],
                               downloaded or installed]),
               [without_python_deps=yes], [])
 
+AC_ARG_ENABLE([tests-install],
+              AS_HELP_STRING([--enable-tests-install],
+                             [build and install tests and their helper tools
+                              default: no]),
+              [], [enable_tests_install=no])
+
 AC_ARG_WITH([network-isolator],
             AS_HELP_STRING([--with-network-isolator],
                            [builds the network isolator]),
@@ -316,6 +322,8 @@ AM_CONDITIONAL([OS_FREEBSD], [test "x$OS_NAME" = 
"xfreebsd"])
 AC_PROG_CXX([g++])
 AC_PROG_CC([gcc])
 
+AC_PROG_LN_S
+
 AX_COMPILER_VERSION
 AX_COMPILER_VENDOR
 
@@ -324,6 +332,9 @@ AX_COMPILER_VENDOR
 AM_CONDITIONAL([DEBUG], [test x"$enable_debug" = "xyes"])
 AM_CONDITIONAL([OPTIMIZE], [test x"$enable_optimize" = "xyes"])
 
+AM_CONDITIONAL([INSTALL_TESTS], [test x"$enable_tests_install" = "xyes"])
+AS_IF([test x"$enable_tests_install" = "xyes"],
+      [AC_DEFINE([MESOS_INSTALL_TESTS], [1])])
 
 debug_flags="-g1"
 if test "x$enable_debug" = "xyes"; then

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index 22f5131..5813ab2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -47,6 +47,12 @@ PICOJSON = 
$(LIBPROCESS)/3rdparty/picojson-$(PICOJSON_VERSION)
 pkglibexecdir = $(libexecdir)/$(PACKAGE)
 pkgsysconfdir = $(sysconfdir)/$(PACKAGE)
 
+# Directories to optionally install test binaries and libraries.
+testlibexecdir = $(pkglibexecdir)/tests
+
+# Directory where Mesos modules are installed.
+pkgmoduledir = $(pkglibdir)/modules
+
 if WITH_BUNDLED_PROTOBUF
 # Protocol buffer compiler.
 PROTOC = ../$(PROTOBUF)/src/protoc
@@ -58,6 +64,7 @@ PROTOCFLAGS = -I$(top_srcdir)/include -I$(srcdir)
 
 # Initialize variables here so we can use += operator everywhere else.
 lib_LTLIBRARIES =
+pkgmodule_LTLIBRARIES =
 noinst_LTLIBRARIES =
 sbin_PROGRAMS =
 bin_PROGRAMS =
@@ -94,6 +101,7 @@ MESOS_CPPFLAGS += -Wall -Werror
 MESOS_CPPFLAGS += -DLIBDIR=\"$(libdir)\"
 MESOS_CPPFLAGS += -DPKGLIBEXECDIR=\"$(pkglibexecdir)\"
 MESOS_CPPFLAGS += -DPKGDATADIR=\"$(pkgdatadir)\"
+MESOS_CPPFLAGS += -DPKGMODULEDIR=\"$(pkgmoduledir)\"
 MESOS_CPPFLAGS += -I$(top_srcdir)/include
 MESOS_CPPFLAGS += -I$(top_srcdir)/$(LIBPROCESS)/include
 MESOS_CPPFLAGS += -I$(top_srcdir)/$(STOUT)/include
@@ -1658,10 +1666,11 @@ endif
 check_PROGRAMS += memory-test-helper
 memory_test_helper_SOURCES =                                   \
   tests/flags.cpp                                              \
+  tests/utils.cpp                                              \
   tests/containerizer/memory_test_helper_main.cpp              \
   tests/containerizer/memory_test_helper.cpp
 memory_test_helper_CPPFLAGS = $(mesos_tests_CPPFLAGS)
-memory_test_helper_LDADD = libmesos.la $(LDADD)
+memory_test_helper_LDADD = $(mesos_tests_LDADD)
 
 check_PROGRAMS += active-user-test-helper
 active_user_test_helper_SOURCES = tests/active_user_test_helper.cpp
@@ -1674,7 +1683,7 @@ check_PROGRAMS += mesos-tests
 MESOS_MODULE_LDFLAGS = -release $(PACKAGE_VERSION) -shared
 
 # Library containing the logrotate container logger.
-lib_LTLIBRARIES += liblogrotate_container_logger.la
+pkgmodule_LTLIBRARIES += liblogrotate_container_logger.la
 liblogrotate_container_logger_la_SOURCES =                     \
   slave/container_loggers/logrotate.hpp                                \
   slave/container_loggers/lib_logrotate.hpp                    \
@@ -1683,33 +1692,48 @@ liblogrotate_container_logger_la_CPPFLAGS = 
$(MESOS_CPPFLAGS)
 liblogrotate_container_logger_la_LDFLAGS = $(MESOS_MODULE_LDFLAGS)
 
 # Library containing the fixed resource estimator.
-lib_LTLIBRARIES += libfixed_resource_estimator.la
+pkgmodule_LTLIBRARIES += libfixed_resource_estimator.la
 libfixed_resource_estimator_la_SOURCES = slave/resource_estimators/fixed.cpp
 libfixed_resource_estimator_la_CPPFLAGS = $(MESOS_CPPFLAGS)
 libfixed_resource_estimator_la_LDFLAGS = $(MESOS_MODULE_LDFLAGS)
 
 # Library containing the load qos controller.
-lib_LTLIBRARIES += libload_qos_controller.la
+pkgmodule_LTLIBRARIES += libload_qos_controller.la
 libload_qos_controller_la_SOURCES = slave/qos_controllers/load.hpp
 libload_qos_controller_la_SOURCES += slave/qos_controllers/load.cpp
 libload_qos_controller_la_CPPFLAGS = $(MESOS_CPPFLAGS)
 libload_qos_controller_la_LDFLAGS = $(MESOS_MODULE_LDFLAGS)
 
-# We need to build the test module libraries for running the test suite but
-# don't need to install them.  The 'noinst_' prefix ensures that these 
libraries
-# will not be installed.  However, it also skips building the shared libraries.
-# The workaround is to use '-rpath /nowhere' to force libtool to build the
-# shared library.
-MESOS_TEST_MODULE_LDFLAGS = $(MESOS_MODULE_LDFLAGS) -rpath /nowhere
+MESOS_TEST_MODULE_LDFLAGS = $(MESOS_MODULE_LDFLAGS)
+
+# Even if we are not installing the test suite, we still need to build
+# the test module libraries as shared libraries for running the test suite.
+# When we use the 'noinst_' prefix to ensure these libraries are not
+# installed, automake skips building the shared libraries. The workaround is
+# to use '-rpath /nowhere' to force libtool to always build shared libraries.
+if !INSTALL_TESTS
+MESOS_TEST_MODULE_LDFLAGS += -rpath /nowhere
+endif
+
+MESOS_TEST_MODULES =           \
+  libexamplemodule.la          \
+  libtestallocator.la          \
+  libtestanonymous.la          \
+  libtestauthentication.la     \
+  libtestauthorizer.la         \
+  libtestcontainer_logger.la   \
+  libtesthook.la               \
+  libtesthttpauthenticator.la  \
+  libtestisolator.la           \
+  libtestqos_controller.la     \
+  libtestresource_estimator.la
 
 # Library containing an example module.
-noinst_LTLIBRARIES += libexamplemodule.la
 libexamplemodule_la_SOURCES = examples/example_module_impl.cpp
 libexamplemodule_la_CPPFLAGS = $(MESOS_CPPFLAGS)
 libexamplemodule_la_LDFLAGS = $(MESOS_TEST_MODULE_LDFLAGS)
 
 # Library containing the test anonymous modules.
-noinst_LTLIBRARIES += libtestanonymous.la
 libtestanonymous_la_SOURCES = examples/test_anonymous_module.cpp
 libtestanonymous_la_CPPFLAGS = $(MESOS_CPPFLAGS)
 libtestanonymous_la_LDFLAGS = $(MESOS_TEST_MODULE_LDFLAGS)
@@ -1717,63 +1741,59 @@ libtestanonymous_la_LDFLAGS = 
$(MESOS_TEST_MODULE_LDFLAGS)
 # Library containing the test CRAM-MD5 authentication modules.
 # TODO(tillt): Add cyrus-sasl2 dependency while removing it from libmesos.
 # TODO(tillt): Enable optional building of this module library.
-# TODO(tillt): Make this module library installable. See MESOS-1940.
-noinst_LTLIBRARIES += libtestauthentication.la
 libtestauthentication_la_SOURCES = examples/test_authentication_modules.cpp
 libtestauthentication_la_CPPFLAGS = $(MESOS_CPPFLAGS)
 libtestauthentication_la_LDFLAGS = $(MESOS_TEST_MODULE_LDFLAGS)
 
 # Library containing the test authorizer module.
-noinst_LTLIBRARIES += libtestauthorizer.la
 libtestauthorizer_la_SOURCES = examples/test_authorizer_module.cpp
 libtestauthorizer_la_CPPFLAGS = $(MESOS_CPPFLAGS)
 libtestauthorizer_la_LDFLAGS = $(MESOS_TEST_MODULE_LDFLAGS)
 
 # Library containing the test http authenticator module.
-noinst_LTLIBRARIES += libtesthttpauthenticator.la
 libtesthttpauthenticator_la_SOURCES = 
examples/test_http_authenticator_module.cpp
 libtesthttpauthenticator_la_CPPFLAGS = $(MESOS_CPPFLAGS)
 libtesthttpauthenticator_la_LDFLAGS = $(MESOS_TEST_MODULE_LDFLAGS)
 
 # Library containing the test DRF allocator module.
-noinst_LTLIBRARIES += libtestallocator.la
 libtestallocator_la_SOURCES = examples/test_allocator_module.cpp
 libtestallocator_la_CPPFLAGS = $(MESOS_CPPFLAGS)
 libtestallocator_la_LDFLAGS = $(MESOS_TEST_MODULE_LDFLAGS)
 
 # Library containing example test sandbox container logger module.
-noinst_LTLIBRARIES += libtestcontainer_logger.la
 libtestcontainer_logger_la_SOURCES =           \
   examples/test_container_logger_module.cpp
 libtestcontainer_logger_la_CPPFLAGS = $(MESOS_CPPFLAGS)
 libtestcontainer_logger_la_LDFLAGS = $(MESOS_TEST_MODULE_LDFLAGS)
 
 # Library containing test Hook module.
-noinst_LTLIBRARIES += libtesthook.la
 libtesthook_la_SOURCES = examples/test_hook_module.cpp
 libtesthook_la_CPPFLAGS = $(MESOS_CPPFLAGS)
 libtesthook_la_LDFLAGS = $(MESOS_TEST_MODULE_LDFLAGS)
 
 # Library containing test CPU and memory isolator modules.
-noinst_LTLIBRARIES += libtestisolator.la
 libtestisolator_la_SOURCES = examples/test_isolator_module.cpp
 libtestisolator_la_CPPFLAGS = $(MESOS_CPPFLAGS)
 libtestisolator_la_LDFLAGS = $(MESOS_TEST_MODULE_LDFLAGS)
 
 # Library containing example test noop resource estimator module.
-noinst_LTLIBRARIES += libtestresource_estimator.la
 libtestresource_estimator_la_SOURCES =         \
   examples/test_resource_estimator_module.cpp
 libtestresource_estimator_la_CPPFLAGS = $(MESOS_CPPFLAGS)
 libtestresource_estimator_la_LDFLAGS = $(MESOS_TEST_MODULE_LDFLAGS)
 
 # Library containing example test noop qos controller module.
-noinst_LTLIBRARIES += libtestqos_controller.la
 libtestqos_controller_la_SOURCES =             \
   examples/test_qos_controller_module.cpp
 libtestqos_controller_la_CPPFLAGS = $(MESOS_CPPFLAGS)
 libtestqos_controller_la_LDFLAGS = $(MESOS_TEST_MODULE_LDFLAGS)
 
+if INSTALL_TESTS
+pkgmodule_LTLIBRARIES += $(MESOS_TEST_MODULES)
+else
+noinst_LTLIBRARIES += $(MESOS_TEST_MODULES)
+endif
+
 mesos_tests_SOURCES =                                          \
   slave/qos_controllers/load.cpp                               \
   tests/anonymous_tests.cpp                                    \
@@ -1869,6 +1889,8 @@ mesos_tests_CPPFLAGS += -DSOURCE_DIR=\"$(abs_top_srcdir)\"
 mesos_tests_CPPFLAGS += -DBUILD_DIR=\"$(abs_top_builddir)\"
 mesos_tests_CPPFLAGS += -I../$(GTEST)/include
 mesos_tests_CPPFLAGS += -I../$(GMOCK)/include
+mesos_tests_CPPFLAGS += -DTESTLIBEXECDIR=\"$(testlibexecdir)\"
+mesos_tests_CPPFLAGS += -DSBINDIR=\"$(sbindir)\"
 
 mesos_tests_LDADD = ../$(LIBPROCESS)/3rdparty/libgmock.la libmesos.la $(LDADD)
 
@@ -1876,7 +1898,10 @@ if !OS_FREEBSD
   mesos_tests_LDADD += -ldl # FreeBSD includes dynamic lib utils in libc.
 endif
 
-mesos_tests_DEPENDENCIES = # Initialized to allow += below.
+mesos_tests_DEPENDENCIES =                                     \
+  ../$(LIBPROCESS)/3rdparty/libgmock.la                        \
+  libmesos.la                                                  \
+  $(MESOS_TEST_MODULES)
 
 if OS_LINUX
 mesos_tests_SOURCES +=                                         \
@@ -1954,6 +1979,39 @@ dist_check_SCRIPTS +=                                    
        \
   tests/python_framework_test.sh                               \
   tests/test_framework_test.sh
 
+../$(LIBPROCESS)/3rdparty/libgmock.la:
+       @cd ../$(LIBPROCESS)/3rdparty && $(MAKE) $(AM_MAKEFLAGS) libgmock.la
+
+if INSTALL_TESTS
+testlibexec_PROGRAMS = $(check_PROGRAMS)
+dist_testlibexec_SCRIPTS =                     \
+  tests/balloon_framework_test.sh              \
+  tests/event_call_framework_test.sh           \
+  tests/java_exception_test.sh                 \
+  tests/java_framework_test.sh                 \
+  tests/java_log_test.sh                       \
+  tests/no_executor_framework_test.sh          \
+  tests/persistent_volume_framework_test.sh    \
+  tests/python_framework_test.sh               \
+  tests/test_framework_test.sh
+
+endif
+
+# Install compatibility symlinks for modules that used to be in $(LIBDIR)
+# but are now in $(PKGMODULEDIR). We use install-data-hook because it
+# runs late in the install process after the target directories have
+# been created.
+install-data-hook:
+       cd $(DESTDIR)/$(libdir) &&                              \
+       for name in libfixed_resource_estimator                 \
+           libload_qos_controller                              \
+           liblogrotate_container_logger; do                   \
+               for lib in `cd $(DESTDIR)/$(pkgmoduledir) && ls $${name}*`; do \
+                 rm -f $$lib;                                  \
+                 $(LN_S) $(pkgmoduledir)/$$lib $$lib;          \
+               done;                                           \
+       done
+
 # We use a check-local target for now to avoid the parallel test
 # runner that ships with newer versions of autotools.
 # See the following discussion for the workaround:
@@ -1961,6 +2019,13 @@ dist_check_SCRIPTS +=                                    
        \
 check-local: tests
        ./mesos-tests
 
+if INSTALL_TESTS
+# If we enabled test installation, we can run the tests from the
+# installation tree.
+installcheck-local:
+       $(testlibexecdir)/mesos-tests --build_dir=/nowhere --source_dir=/nowhere
+endif
+
 clean-local: clean-java clean-python
 
 tests: all $(check_PROGRAMS) mesos-tests

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/src/examples/test_framework.cpp
----------------------------------------------------------------------
diff --git a/src/examples/test_framework.cpp b/src/examples/test_framework.cpp
index ff7b005..c9695c4 100644
--- a/src/examples/test_framework.cpp
+++ b/src/examples/test_framework.cpp
@@ -194,9 +194,9 @@ int main(int argc, char** argv)
 {
   // Find this executable's directory to locate executor.
   string uri;
-  Option<string> value = os::getenv("MESOS_BUILD_DIR");
+  Option<string> value = os::getenv("MESOS_HELPER_DIR");
   if (value.isSome()) {
-    uri = path::join(value.get(), "src", "test-executor");
+    uri = path::join(value.get(), "test-executor");
   } else {
     uri = path::join(
         os::realpath(Path(argv[0]).dirname()).get(),

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/src/tests/balloon_framework_test.sh
----------------------------------------------------------------------
diff --git a/src/tests/balloon_framework_test.sh 
b/src/tests/balloon_framework_test.sh
index 25a19cf..ae32753 100755
--- a/src/tests/balloon_framework_test.sh
+++ b/src/tests/balloon_framework_test.sh
@@ -5,6 +5,8 @@
 
 source ${MESOS_SOURCE_DIR}/support/colors.sh
 source ${MESOS_SOURCE_DIR}/support/atexit.sh
+source ${MESOS_HELPER_DIR}/colors.sh
+source ${MESOS_HELPER_DIR}/atexit.sh
 
 EXISTING_MEMORY_HIERARCHY=$(cat /proc/mounts | grep memory | cut -f 2 -d ' ')
 if [[ -n ${EXISTING_MEMORY_HIERARCHY} ]]; then
@@ -60,14 +62,15 @@ function cleanup() {
 atexit cleanup
 
 export LD_LIBRARY_PATH=${MESOS_BUILD_DIR}/src/.libs
-MASTER=${MESOS_BUILD_DIR}/src/mesos-master
-SLAVE=${MESOS_BUILD_DIR}/src/mesos-slave
-BALLOON_FRAMEWORK=${MESOS_BUILD_DIR}/src/balloon-framework
+MASTER=${MESOS_SBIN_DIR}/mesos-master
+SLAVE=${MESOS_SBIN_DIR}/mesos-slave
+BALLOON_FRAMEWORK=${MESOS_HELPER_DIR}/balloon-framework
 
 # The mesos binaries expect MESOS_ prefixed environment variables
 # to correspond to flags, so we unset these here.
 unset MESOS_BUILD_DIR
 unset MESOS_SOURCE_DIR
+unset MESOS_HELPER_DIR
 #unset MESOS_LAUNCHER_DIR # leave this so we can find mesos-fetcher.
 unset MESOS_VERBOSE
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/src/tests/containerizer/launch_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/launch_tests.cpp 
b/src/tests/containerizer/launch_tests.cpp
index fd84c13..e0f934c 100644
--- a/src/tests/containerizer/launch_tests.cpp
+++ b/src/tests/containerizer/launch_tests.cpp
@@ -34,6 +34,7 @@
 #include "slave/containerizer/mesos/launch.hpp"
 
 #include "tests/flags.hpp"
+#include "tests/utils.hpp"
 
 #include "tests/containerizer/rootfs.hpp"
 
@@ -72,7 +73,7 @@ public:
     argv[1] = slave::MesosContainerizerLaunch::NAME;
 
     Try<Subprocess> s = subprocess(
-        path::join(tests::flags.build_dir, "src", "mesos-containerizer"),
+        path::join(getLauncherDir(), "mesos-containerizer"),
         argv,
         Subprocess::PATH("/dev/null"),
         Subprocess::FD(STDOUT_FILENO),

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/src/tests/containerizer/memory_test_helper.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/memory_test_helper.cpp 
b/src/tests/containerizer/memory_test_helper.cpp
index 4a3de2e..92579a2 100644
--- a/src/tests/containerizer/memory_test_helper.cpp
+++ b/src/tests/containerizer/memory_test_helper.cpp
@@ -36,6 +36,7 @@
 #include <stout/try.hpp>
 
 #include "tests/flags.hpp"
+#include "tests/utils.hpp"
 
 #include "tests/containerizer/memory_test_helper.hpp"
 
@@ -196,9 +197,7 @@ Try<Nothing> MemoryTestHelper::spawn()
   argv.push_back(MemoryTestHelperMain::NAME);
 
   Try<Subprocess> process = subprocess(
-      path::join(flags.build_dir,
-                 "src",
-                 "memory-test-helper"),
+      getTestHelperPath("memory-test-helper"),
       argv,
       Subprocess::PIPE(),
       Subprocess::PIPE(),

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/src/tests/containerizer/mesos_containerizer_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/mesos_containerizer_tests.cpp 
b/src/tests/containerizer/mesos_containerizer_tests.cpp
index a45ed1b..15f0f93 100644
--- a/src/tests/containerizer/mesos_containerizer_tests.cpp
+++ b/src/tests/containerizer/mesos_containerizer_tests.cpp
@@ -108,7 +108,7 @@ public:
     }
 
     slave::Flags flags;
-    flags.launcher_dir = path::join(tests::flags.build_dir, "src");
+    flags.launcher_dir = getLauncherDir();
 
     Try<Launcher*> launcher = PosixLauncher::create(flags);
     if (launcher.isError()) {
@@ -401,7 +401,7 @@ TEST_F(MesosContainerizerExecuteTest, IoRedirection)
   string directory = os::getcwd(); // We're inside a temporary sandbox.
 
   slave::Flags flags;
-  flags.launcher_dir = path::join(tests::flags.build_dir, "src");
+  flags.launcher_dir = getLauncherDir();
 
   Fetcher fetcher;
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/src/tests/containerizer/ns_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/ns_tests.cpp 
b/src/tests/containerizer/ns_tests.cpp
index 603e54b..4bf45e9 100644
--- a/src/tests/containerizer/ns_tests.cpp
+++ b/src/tests/containerizer/ns_tests.cpp
@@ -39,6 +39,7 @@
 #include "linux/ns.hpp"
 
 #include "tests/flags.hpp"
+#include "tests/utils.hpp"
 
 #include "tests/containerizer/setns_test_helper.hpp"
 
@@ -85,7 +86,7 @@ TEST(NsTest, ROOT_setns)
   argv.push_back(SetnsTestHelper::NAME);
 
   Try<Subprocess> s = subprocess(
-      path::join(tests::flags.build_dir, "src", "setns-test-helper"),
+      getTestHelperPath("setns-test-helper"),
       argv,
       Subprocess::FD(STDIN_FILENO),
       Subprocess::FD(STDOUT_FILENO),

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/src/tests/containerizer/port_mapping_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/port_mapping_tests.cpp 
b/src/tests/containerizer/port_mapping_tests.cpp
index e346c75..3e02835 100644
--- a/src/tests/containerizer/port_mapping_tests.cpp
+++ b/src/tests/containerizer/port_mapping_tests.cpp
@@ -278,7 +278,7 @@ protected:
   {
     slave::Flags flags;
 
-    flags.launcher_dir = path::join(tests::flags.build_dir, "src");
+    flags.launcher_dir = getLauncherDir();
 
     flags.resources = strings::join(";", vector<string>({
         containerCPU,

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/src/tests/environment.cpp
----------------------------------------------------------------------
diff --git a/src/tests/environment.cpp b/src/tests/environment.cpp
index e112270..6cd295f 100644
--- a/src/tests/environment.cpp
+++ b/src/tests/environment.cpp
@@ -58,6 +58,7 @@
 
 #include "tests/environment.hpp"
 #include "tests/flags.hpp"
+#include "tests/utils.hpp"
 
 #ifdef WITH_NETWORK_ISOLATOR
 using namespace routing;
@@ -681,12 +682,7 @@ void Environment::SetUp()
   // TODO(tillt): Adapt library towards JNI specific name once libmesos
   // has been split.
   if (os::getenv("MESOS_NATIVE_JAVA_LIBRARY").isNone()) {
-    string path = path::join(tests::flags.build_dir, "src", ".libs");
-#ifdef __APPLE__
-    path = path::join(path, "libmesos-" VERSION ".dylib");
-#else
-    path = path::join(path, "libmesos-" VERSION ".so");
-#endif
+    string path = getLibMesosPath();
     os::setenv("MESOS_NATIVE_JAVA_LIBRARY", path);
   }
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/src/tests/event_call_framework_test.sh
----------------------------------------------------------------------
diff --git a/src/tests/event_call_framework_test.sh 
b/src/tests/event_call_framework_test.sh
index 9d12115..cddb520 100755
--- a/src/tests/event_call_framework_test.sh
+++ b/src/tests/event_call_framework_test.sh
@@ -14,7 +14,10 @@ test $? != 0 && \
   echo "Failed to find MESOS_BUILD_DIR in environment" && \
   exit 1
 
+source ${MESOS_SOURCE_DIR}/support/colors.sh
 source ${MESOS_SOURCE_DIR}/support/atexit.sh
+source ${MESOS_HELPER_DIR}/colors.sh
+source ${MESOS_HELPER_DIR}/atexit.sh
 
 MESOS_WORK_DIR=`mktemp -d -t mesos-XXXXXX`
 
@@ -37,4 +40,4 @@ export MESOS_LAUNCHER="posix"
 export MESOS_AUTHENTICATE=false
 
 # Check that the C++ low level scheduler executes without crashing (returns 0).
-exec ${MESOS_BUILD_DIR}/src/event-call-framework --master=local
+exec ${MESOS_HELPER_DIR}/event-call-framework --master=local

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/src/tests/fetcher_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/fetcher_tests.cpp b/src/tests/fetcher_tests.cpp
index 1831d89..fb47706 100644
--- a/src/tests/fetcher_tests.cpp
+++ b/src/tests/fetcher_tests.cpp
@@ -81,7 +81,7 @@ TEST_F(FetcherTest, FileURI)
   EXPECT_FALSE(os::exists(localFile));
 
   slave::Flags flags;
-  flags.launcher_dir = path::join(tests::flags.build_dir, "src");
+  flags.launcher_dir = getLauncherDir();
 
   ContainerID containerId;
   containerId.set_value(UUID::random().toString());
@@ -115,7 +115,7 @@ TEST_F(FetcherTest, InvalidUser)
   EXPECT_FALSE(os::exists(localFile));
 
   slave::Flags flags;
-  flags.launcher_dir = path::join(tests::flags.build_dir, "src");
+  flags.launcher_dir = getLauncherDir();
   flags.frameworks_home = "/tmp/frameworks";
 
   ContainerID containerId;
@@ -151,7 +151,7 @@ TEST_F(FetcherTest, NonExistingFile)
   string testFile = path::join(fromDir, "nonExistingFile");
 
   slave::Flags flags;
-  flags.launcher_dir = path::join(tests::flags.build_dir, "src");
+  flags.launcher_dir = getLauncherDir();
   flags.frameworks_home = "/tmp/frameworks";
 
   ContainerID containerId;
@@ -177,7 +177,7 @@ TEST_F(FetcherTest, NonExistingFile)
 TEST_F(FetcherTest, MalformedURI)
 {
   slave::Flags flags;
-  flags.launcher_dir = path::join(tests::flags.build_dir, "src");
+  flags.launcher_dir = getLauncherDir();
   flags.frameworks_home = "/tmp/frameworks";
 
   ContainerID containerId;
@@ -210,7 +210,7 @@ TEST_F(FetcherTest, AbsoluteFilePath)
   EXPECT_FALSE(os::exists(localFile));
 
   slave::Flags flags;
-  flags.launcher_dir = path::join(tests::flags.build_dir, "src");
+  flags.launcher_dir = getLauncherDir();
 
   ContainerID containerId;
   containerId.set_value(UUID::random().toString());
@@ -241,7 +241,7 @@ TEST_F(FetcherTest, RelativeFilePath)
   EXPECT_FALSE(os::exists(localFile));
 
   slave::Flags flags;
-  flags.launcher_dir = path::join(tests::flags.build_dir, "src");
+  flags.launcher_dir = getLauncherDir();
 
   ContainerID containerId;
   containerId.set_value(UUID::random().toString());
@@ -321,7 +321,7 @@ TEST_F(FetcherTest, OSNetUriTest)
   EXPECT_FALSE(os::exists(localFile));
 
   slave::Flags flags;
-  flags.launcher_dir = path::join(tests::flags.build_dir, "src");
+  flags.launcher_dir = getLauncherDir();
   flags.frameworks_home = "/tmp/frameworks";
 
   ContainerID containerId;
@@ -366,7 +366,7 @@ TEST_F(FetcherTest, OSNetUriSpaceTest)
   EXPECT_FALSE(os::exists(localFile));
 
   slave::Flags flags;
-  flags.launcher_dir = path::join(tests::flags.build_dir, "src");
+  flags.launcher_dir = getLauncherDir();
   flags.frameworks_home = "/tmp/frameworks";
 
   ContainerID containerId;
@@ -405,7 +405,7 @@ TEST_F(FetcherTest, FileLocalhostURI)
   EXPECT_FALSE(os::exists(localFile));
 
   slave::Flags flags;
-  flags.launcher_dir = path::join(tests::flags.build_dir, "src");
+  flags.launcher_dir = getLauncherDir();
 
   ContainerID containerId;
   containerId.set_value(UUID::random().toString());
@@ -442,7 +442,7 @@ TEST_F(FetcherTest, NoExtractNotExecutable)
   uri->set_extract(false);
 
   slave::Flags flags;
-  flags.launcher_dir = path::join(tests::flags.build_dir, "src");
+  flags.launcher_dir = getLauncherDir();
 
   Fetcher fetcher;
   SlaveID slaveId;
@@ -481,7 +481,7 @@ TEST_F(FetcherTest, NoExtractExecutable)
   uri->set_extract(false);
 
   slave::Flags flags;
-  flags.launcher_dir = path::join(tests::flags.build_dir, "src");
+  flags.launcher_dir = getLauncherDir();
 
   Fetcher fetcher;
   SlaveID slaveId;
@@ -532,7 +532,7 @@ TEST_F(FetcherTest, ExtractNotExecutable)
   uri->set_extract(true);
 
   slave::Flags flags;
-  flags.launcher_dir = path::join(tests::flags.build_dir, "src");
+  flags.launcher_dir = getLauncherDir();
 
   Fetcher fetcher;
   SlaveID slaveId;
@@ -583,7 +583,7 @@ TEST_F(FetcherTest, ExtractTar)
   uri->set_extract(true);
 
   slave::Flags flags;
-  flags.launcher_dir = path::join(tests::flags.build_dir, "src");
+  flags.launcher_dir = getLauncherDir();
 
   Fetcher fetcher;
   SlaveID slaveId;
@@ -621,7 +621,7 @@ TEST_F(FetcherTest, ExtractGzipFile)
   uri->set_extract(true);
 
   slave::Flags flags;
-  flags.launcher_dir = path::join(tests::flags.build_dir, "src");
+  flags.launcher_dir = getLauncherDir();
 
   Fetcher fetcher;
   SlaveID slaveId;
@@ -704,7 +704,7 @@ TEST_F(FetcherTest, HdfsURI)
   EXPECT_FALSE(os::exists(localFile));
 
   slave::Flags flags;
-  flags.launcher_dir = path::join(tests::flags.build_dir, "src");
+  flags.launcher_dir = getLauncherDir();
   flags.hadoop_home = hadoopPath;
 
   ContainerID containerId;

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/src/tests/health_check_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/health_check_tests.cpp b/src/tests/health_check_tests.cpp
index 65e8fe2..59ef319 100644
--- a/src/tests/health_check_tests.cpp
+++ b/src/tests/health_check_tests.cpp
@@ -120,7 +120,7 @@ public:
     // We need to set the correct directory to launch health check process
     // instead of the default for tests.
     variable->set_name("MESOS_LAUNCHER_DIR");
-    variable->set_value(path::join(tests::flags.build_dir, "src"));
+    variable->set_value(getLauncherDir());
 
     task.mutable_command()->CopyFrom(command);
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/src/tests/mesos.cpp
----------------------------------------------------------------------
diff --git a/src/tests/mesos.cpp b/src/tests/mesos.cpp
index 8fe28ae..e0f641c 100644
--- a/src/tests/mesos.cpp
+++ b/src/tests/mesos.cpp
@@ -153,7 +153,7 @@ slave::Flags MesosTest::CreateSlaveFlags()
   flags.work_dir = directory.get();
   flags.fetcher_cache_dir = path::join(directory.get(), "fetch");
 
-  flags.launcher_dir = path::join(tests::flags.build_dir, "src");
+  flags.launcher_dir = getLauncherDir();
 
   // Create a default credential file.
   const string& path = path::join(directory.get(), "credential");

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/src/tests/module.cpp
----------------------------------------------------------------------
diff --git a/src/tests/module.cpp b/src/tests/module.cpp
index 246f3a4..8cc305c 100644
--- a/src/tests/module.cpp
+++ b/src/tests/module.cpp
@@ -55,15 +55,9 @@ static void addIsolatorModules(Modules* modules)
 {
   CHECK_NOTNULL(modules);
 
-  const string libraryPath = path::join(
-      tests::flags.build_dir,
-      "src",
-      ".libs",
-      os::libraries::expandName("testisolator"));
-
   // Now add our test CPU and Memory isolator modules.
   Modules::Library* library = modules->add_libraries();
-  library->set_file(libraryPath);
+  library->set_file(getModulePath("testisolator"));
 
   // To add a new module from this library, create a new ModuleID enum
   // and tie it with a module name.
@@ -77,15 +71,9 @@ static void addAuthenticationModules(Modules* modules)
 {
   CHECK_NOTNULL(modules);
 
-  const string libraryPath = path::join(
-      tests::flags.build_dir,
-      "src",
-      ".libs",
-      os::libraries::expandName("testauthentication"));
-
   // Now add our test authentication modules.
   Modules::Library* library = modules->add_libraries();
-  library->set_file(libraryPath);
+  library->set_file(getModulePath("testauthentication"));
 
   // To add a new module from this library, create a new ModuleID enum
   // and tie it with a module name.
@@ -103,18 +91,9 @@ static void addContainerLoggerModules(Modules* modules)
 {
   CHECK_NOTNULL(modules);
 
-  const string libraryDirectory = path::join(
-      tests::flags.build_dir,
-      "src",
-      ".libs");
-
-  const string sandboxLoggerPath = path::join(
-      libraryDirectory,
-      os::libraries::expandName("testcontainer_logger"));
-
   // Add our test container logger module.
   Modules::Library* library = modules->add_libraries();
-  library->set_file(sandboxLoggerPath);
+  library->set_file(getModulePath("testcontainer_logger"));
 
   // To add a new module from this library, create a new ModuleID enum
   // and tie it with a module name.
@@ -122,13 +101,9 @@ static void addContainerLoggerModules(Modules* modules)
             TestSandboxContainerLogger,
             "org_apache_mesos_TestSandboxContainerLogger");
 
-  const string logrotateLoggerPath = path::join(
-      libraryDirectory,
-      os::libraries::expandName("logrotate_container_logger"));
-
   // Add the second container logger module.
   library = modules->add_libraries();
-  library->set_file(logrotateLoggerPath);
+  library->set_file(getModulePath("logrotate_container_logger"));
 
   addModule(library,
             LogrotateContainerLogger,
@@ -138,7 +113,7 @@ static void addContainerLoggerModules(Modules* modules)
   Modules::Library::Module* module = library->mutable_modules(0);
   mesos::Parameter* moduleParameter = module->add_parameters();
   moduleParameter->set_key("launcher_dir");
-  moduleParameter->set_value(path::join(tests::flags.build_dir, "src"));
+  moduleParameter->set_value(getLauncherDir());
 
   // Set the size and number of log files to keep.
   moduleParameter = module->add_parameters();
@@ -157,15 +132,9 @@ static void addHookModules(Modules* modules)
 {
   CHECK_NOTNULL(modules);
 
-  const string libraryPath = path::join(
-      tests::flags.build_dir,
-      "src",
-      ".libs",
-      os::libraries::expandName("testhook"));
-
   // Now add our test hook module.
   Modules::Library* library = modules->add_libraries();
-  library->set_file(libraryPath);
+  library->set_file(getModulePath("testhook"));
 
   // To add a new module from this library, create a new ModuleID enum
   // and tie it with a module name.
@@ -177,15 +146,9 @@ static void addAnonymousModules(Modules* modules)
 {
   CHECK_NOTNULL(modules);
 
-  const string libraryPath = path::join(
-      tests::flags.build_dir,
-      "src",
-      ".libs",
-      os::libraries::expandName("testanonymous"));
-
   // Now add our test anonymous module.
   Modules::Library* library = modules->add_libraries();
-  library->set_file(libraryPath);
+  library->set_file(getModulePath("testanonymous"));
 
   // To add a new module from this library, create a new ModuleID enum
   // and tie it with a module name.
@@ -199,15 +162,9 @@ static void addAllocatorModules(Modules* modules)
 {
   CHECK_NOTNULL(modules);
 
-  const string libraryPath = path::join(
-      tests::flags.build_dir,
-      "src",
-      ".libs",
-      os::libraries::expandName("testallocator"));
-
   // Now add our allocator module.
   Modules::Library* library = modules->add_libraries();
-  library->set_file(libraryPath);
+  library->set_file(getModulePath("testallocator"));
 
   // To add a new module from this library, create a new ModuleID enum
   // and tie it with a module name.
@@ -220,15 +177,9 @@ static void addResourceEstimatorModules(Modules* modules)
 {
   CHECK_NOTNULL(modules);
 
-  const string libraryPath = path::join(
-      tests::flags.build_dir,
-      "src",
-      ".libs",
-      os::libraries::expandName("testresource_estimator"));
-
   // Now add our resource_estimator module.
   Modules::Library* library = modules->add_libraries();
-  library->set_file(libraryPath);
+  library->set_file(getModulePath("testresource_estimator"));
 
   // To add a new module from this library, create a new ModuleID enum
   // and tie it with a module name.
@@ -243,15 +194,9 @@ static void addAuthorizerModules(Modules* modules)
 {
   CHECK_NOTNULL(modules);
 
-  const string libraryPath = path::join(
-      tests::flags.build_dir,
-      "src",
-      ".libs",
-      os::libraries::expandName("testauthorizer"));
-
   // Now add our test authorizer module.
   Modules::Library* library = modules->add_libraries();
-  library->set_file(libraryPath);
+  library->set_file(getModulePath("testauthorizer"));
 
   // To add a new module from this library, create a new ModuleID enum
   // and tie it with a module name.
@@ -264,15 +209,9 @@ static void addHttpAuthenticatorModules(Modules* modules)
 {
   CHECK_NOTNULL(modules);
 
-  const string libraryPath = path::join(
-      tests::flags.build_dir,
-      "src",
-      ".libs",
-      os::libraries::expandName("testhttpauthenticator"));
-
   // Now add our test HTTP authenticator module.
   Modules::Library* library = modules->add_libraries();
-  library->set_file(libraryPath);
+  library->set_file(getModulePath("testhttpauthenticator"));
 
   // To add a new module from this library, create a new ModuleID enum
   // and tie it with a module name.

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/src/tests/module_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/module_tests.cpp b/src/tests/module_tests.cpp
index 7b3e98b..121d653 100644
--- a/src/tests/module_tests.cpp
+++ b/src/tests/module_tests.cpp
@@ -55,10 +55,8 @@ protected:
   // per-test teardown.
   static void SetUpTestCase()
   {
-    libraryDirectory = path::join(tests::flags.build_dir, "src", ".libs");
-
-    EXPECT_SOME(dynamicLibrary.open(path::join(libraryDirectory,
-        os::libraries::expandName(DEFAULT_MODULE_LIBRARY_NAME))));
+    EXPECT_SOME(dynamicLibrary.open(
+        getModulePath(DEFAULT_MODULE_LIBRARY_NAME)));
 
     Try<void*> symbol = dynamicLibrary.loadSymbol(DEFAULT_MODULE_NAME);
     EXPECT_SOME(symbol);
@@ -78,9 +76,7 @@ protected:
     : module(None())
   {
     Modules::Library* library = defaultModules.add_libraries();
-    library->set_file(path::join(
-        libraryDirectory,
-        os::libraries::expandName(DEFAULT_MODULE_LIBRARY_NAME)));
+    library->set_file(getModulePath(DEFAULT_MODULE_LIBRARY_NAME));
     library->add_modules()->set_name(DEFAULT_MODULE_NAME);
   }
 
@@ -109,24 +105,20 @@ protected:
 
   static DynamicLibrary dynamicLibrary;
   static ModuleBase* moduleBase;
-  static string libraryDirectory;
 };
 
 
 DynamicLibrary ModuleTest::dynamicLibrary;
 ModuleBase* ModuleTest::moduleBase = NULL;
-string ModuleTest::libraryDirectory;
 
 
 Modules getModules(
-    const string& libraryDirectory,
     const string& libraryName,
     const string& moduleName)
 {
   Modules modules;
   Modules::Library* library = modules.add_libraries();
-  library->set_file(
-      path::join(libraryDirectory, os::libraries::expandName(libraryName)));
+  library->set_file(getModulePath(libraryName));
   Modules::Library::Module* module = library->add_modules();
   module->set_name(moduleName);
   return modules;
@@ -134,13 +126,12 @@ Modules getModules(
 
 
 Modules getModules(
-    const string& libraryDirectory,
     const string& libraryName,
     const string& moduleName,
     const string& parameterKey,
     const string& parameterValue)
 {
-  Modules modules = getModules(libraryDirectory, libraryName, moduleName);
+  Modules modules = getModules(libraryName, moduleName);
   Modules::Library* library = modules.mutable_libraries(0);
   Modules::Library::Module* module = library->mutable_modules(0);
   Parameter* parameter = module->add_parameters();
@@ -151,14 +142,12 @@ Modules getModules(
 
 
 Try<Modules> getModulesFromJson(
-    const string& libraryDirectory,
     const string& libraryName,
     const string& moduleName,
     const string& parameterKey,
     const string& parameterValue)
 {
-  string libraryFile =
-    path::join(libraryDirectory, os::libraries::expandName(libraryName));
+  string libraryFile = getModulePath(libraryName);
 
   string jsonString =
     "{\n"
@@ -209,7 +198,6 @@ TEST_F(ModuleTest, ExampleModuleLoadTest)
 TEST_F(ModuleTest, ParameterWithoutValue)
 {
   Modules modules = getModules(
-      libraryDirectory,
       DEFAULT_MODULE_LIBRARY_NAME,
       DEFAULT_MODULE_NAME,
       "operation",
@@ -225,7 +213,6 @@ TEST_F(ModuleTest, ParameterWithoutValue)
 TEST_F(ModuleTest, ParameterWithInvalidValue)
 {
   Modules modules = getModules(
-      libraryDirectory,
       DEFAULT_MODULE_LIBRARY_NAME,
       DEFAULT_MODULE_NAME,
       "operation",
@@ -241,7 +228,6 @@ TEST_F(ModuleTest, ParameterWithInvalidValue)
 TEST_F(ModuleTest, ParameterWithoutKey)
 {
   Modules modules = getModules(
-      libraryDirectory,
       DEFAULT_MODULE_LIBRARY_NAME,
       DEFAULT_MODULE_NAME,
       "",
@@ -260,7 +246,6 @@ TEST_F(ModuleTest, ParameterWithoutKey)
 TEST_F(ModuleTest, ParameterWithInvalidKey)
 {
   Modules modules = getModules(
-      libraryDirectory,
       DEFAULT_MODULE_LIBRARY_NAME,
       DEFAULT_MODULE_NAME,
       "X",
@@ -279,7 +264,6 @@ TEST_F(ModuleTest, ParameterWithInvalidKey)
 TEST_F(ModuleTest, ValidParameters)
 {
   Modules modules = getModules(
-      libraryDirectory,
       DEFAULT_MODULE_LIBRARY_NAME,
       DEFAULT_MODULE_NAME,
       "operation",
@@ -297,7 +281,6 @@ TEST_F(ModuleTest, ValidParameters)
 TEST_F(ModuleTest, OverrideJson)
 {
   Modules modules = getModules(
-      libraryDirectory,
       DEFAULT_MODULE_LIBRARY_NAME,
       DEFAULT_MODULE_NAME,
       "operation",
@@ -325,7 +308,6 @@ TEST_F(ModuleTest, OverrideJson)
 TEST_F(ModuleTest, JsonParseTest)
 {
   Try<Modules> modules = getModulesFromJson(
-      libraryDirectory,
       DEFAULT_MODULE_LIBRARY_NAME,
       DEFAULT_MODULE_NAME,
       "operation",
@@ -398,8 +380,7 @@ TEST_F(ModuleTest, LibraryNameWithoutExtension)
   Modules modules;
   Modules::Library* library = modules.add_libraries();
   library->set_name(DEFAULT_MODULE_LIBRARY_NAME);
-  library->set_file(path::join(libraryDirectory,
-      os::libraries::expandName(DEFAULT_MODULE_LIBRARY_NAME)));
+  library->set_file(getModulePath(DEFAULT_MODULE_LIBRARY_NAME));
   Modules::Library::Module* module = library->add_modules();
   module->set_name(DEFAULT_MODULE_NAME);
 
@@ -411,7 +392,6 @@ TEST_F(ModuleTest, LibraryNameWithoutExtension)
 TEST_F(ModuleTest, EmptyLibraryFilename)
 {
   Modules modules = getModules(
-      libraryDirectory,
       "",
       "org_apache_mesos_TestModule");
   EXPECT_ERROR(ModuleManager::load(modules));
@@ -421,7 +401,7 @@ TEST_F(ModuleTest, EmptyLibraryFilename)
 // Test that module library loading fails when module name is empty.
 TEST_F(ModuleTest, EmptyModuleName)
 {
-  Modules modules = getModules(libraryDirectory, "examplemodule", "");
+  Modules modules = getModules("examplemodule", "");
   EXPECT_ERROR(ModuleManager::load(modules));
 }
 
@@ -430,7 +410,6 @@ TEST_F(ModuleTest, EmptyModuleName)
 TEST_F(ModuleTest, UnknownLibraryTest)
 {
   Modules modules = getModules(
-      libraryDirectory,
       "unknown",
       "org_apache_mesos_TestModule");
   EXPECT_ERROR(ModuleManager::load(modules));
@@ -441,7 +420,7 @@ TEST_F(ModuleTest, UnknownLibraryTest)
 // the commandline.
 TEST_F(ModuleTest, UnknownModuleTest)
 {
-  Modules modules = getModules(libraryDirectory, "examplemodule", "unknown");
+  Modules modules = getModules("examplemodule", "unknown");
   EXPECT_ERROR(ModuleManager::load(modules));
 }
 
@@ -460,7 +439,7 @@ TEST_F(ModuleTest, NonModuleLibrary)
 {
   // Trying to load libmesos.so (libmesos.dylib on OS X) as a module
   // library should fail.
-  Modules modules = getModules(libraryDirectory, "mesos", DEFAULT_MODULE_NAME);
+  Modules modules = getModules("mesos", DEFAULT_MODULE_NAME);
   EXPECT_ERROR(ModuleManager::load(modules));
 }
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/src/tests/no_executor_framework_test.sh
----------------------------------------------------------------------
diff --git a/src/tests/no_executor_framework_test.sh 
b/src/tests/no_executor_framework_test.sh
index aebdc8c..4fa154e 100755
--- a/src/tests/no_executor_framework_test.sh
+++ b/src/tests/no_executor_framework_test.sh
@@ -14,7 +14,10 @@ test $? != 0 && \
   echo "Failed to find MESOS_BUILD_DIR in environment" && \
   exit 1
 
+source ${MESOS_SOURCE_DIR}/support/colors.sh
 source ${MESOS_SOURCE_DIR}/support/atexit.sh
+source ${MESOS_HELPER_DIR}/colors.sh
+source ${MESOS_HELPER_DIR}/atexit.sh
 
 MESOS_WORK_DIR=`mktemp -d -t mesos-XXXXXX`
 
@@ -34,4 +37,4 @@ export MESOS_ISOLATION="filesystem/posix,posix/cpu,posix/mem"
 export MESOS_LAUNCHER="posix"
 
 # Check that the C++ test framework executes without crashing (returns 0).
-exec ${MESOS_BUILD_DIR}/src/no-executor-framework --master=local --num_tasks=5
+exec ${MESOS_HELPER_DIR}/no-executor-framework --master=local --num_tasks=5

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/src/tests/oversubscription_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/oversubscription_tests.cpp 
b/src/tests/oversubscription_tests.cpp
index c857c2b..d4ae819 100644
--- a/src/tests/oversubscription_tests.cpp
+++ b/src/tests/oversubscription_tests.cpp
@@ -103,8 +103,7 @@ protected:
 
   void loadFixedResourceEstimatorModule(const string& resources)
   {
-    string libraryPath = path::join(tests::flags.build_dir, "src", ".libs",
-        os::libraries::expandName("fixed_resource_estimator"));
+    string libraryPath = getModulePath("fixed_resource_estimator");
 
     Modules::Library* library = modules.add_libraries();
     library->set_name("fixed_resource_estimator");

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/src/tests/persistent_volume_framework_test.sh
----------------------------------------------------------------------
diff --git a/src/tests/persistent_volume_framework_test.sh 
b/src/tests/persistent_volume_framework_test.sh
index 84f0284..074cdcb 100755
--- a/src/tests/persistent_volume_framework_test.sh
+++ b/src/tests/persistent_volume_framework_test.sh
@@ -14,7 +14,11 @@ test $? != 0 && \
   echo "Failed to find MESOS_BUILD_DIR in environment" && \
   exit 1
 
+
+source ${MESOS_SOURCE_DIR}/support/colors.sh
 source ${MESOS_SOURCE_DIR}/support/atexit.sh
+source ${MESOS_HELPER_DIR}/colors.sh
+source ${MESOS_HELPER_DIR}/atexit.sh
 
 MESOS_WORK_DIR=`mktemp -d -t mesos-XXXXXX`
 
@@ -31,4 +35,4 @@ export MESOS_ISOLATION="filesystem/posix,posix/cpu,posix/mem"
 export MESOS_LAUNCHER="posix"
 
 # Check that the framework executes without crashing (returns 0).
-exec ${MESOS_BUILD_DIR}/src/persistent-volume-framework --master=local
+exec ${MESOS_HELPER_DIR}/persistent-volume-framework --master=local

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/src/tests/script.cpp
----------------------------------------------------------------------
diff --git a/src/tests/script.cpp b/src/tests/script.cpp
index ee44fef..36ddf40 100644
--- a/src/tests/script.cpp
+++ b/src/tests/script.cpp
@@ -36,6 +36,7 @@
 #include "tests/flags.hpp"
 #include "tests/mesos.hpp"
 #include "tests/script.hpp"
+#include "tests/utils.hpp"
 
 using std::string;
 
@@ -56,11 +57,11 @@ void execute(const string& script)
   }
 
   // Determine the path for the script.
-  Result<string> path =
-    os::realpath(path::join(flags.source_dir, "src", "tests", script));
+  Result<string> path = os::realpath(getTestScriptPath(script));
 
   if (!path.isSome()) {
-    FAIL() << "Failed to locate script: "
+    FAIL() << "Failed to locate script "
+           << script << ": "
            << (path.isError() ? path.error() : "No such file or directory");
   }
 
@@ -100,11 +101,18 @@ void execute(const string& script)
       }
     }
 
-    // Set up the environment for executing the script.
-    os::setenv("MESOS_SOURCE_DIR", flags.source_dir);
+    // Set up the environment for executing the script. We might be running 
from
+    // the Mesos source tree or from an installed version of the tests. In the
+    // latter case, all of the variables below are swizzled to point to the
+    // installed locations, except MESOS_SOURCE_DIR. Scripts that make use of
+    // MESOS_SOURCE_DIR are expected to gracefully degrade if the Mesos source
+    // is no longer present.
     os::setenv("MESOS_BUILD_DIR", flags.build_dir);
-    os::setenv("MESOS_WEBUI_DIR", path::join(flags.source_dir, "src", 
"webui"));
-    os::setenv("MESOS_LAUNCHER_DIR", path::join(flags.build_dir, "src"));
+    os::setenv("MESOS_HELPER_DIR", getTestHelperDir());
+    os::setenv("MESOS_LAUNCHER_DIR", getLauncherDir());
+    os::setenv("MESOS_SBIN_DIR", getSbinDir());
+    os::setenv("MESOS_SOURCE_DIR", flags.source_dir);
+    os::setenv("MESOS_WEBUI_DIR", getWebUIDir());
 
     // Enable replicated log based registry.
     os::setenv("MESOS_REGISTRY", "replicated_log");

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/src/tests/slave_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/slave_tests.cpp b/src/tests/slave_tests.cpp
index b2b1fd4..2a34d54 100644
--- a/src/tests/slave_tests.cpp
+++ b/src/tests/slave_tests.cpp
@@ -36,6 +36,7 @@
 
 #include <stout/option.hpp>
 #include <stout/os.hpp>
+#include <stout/path.hpp>
 #include <stout/try.hpp>
 
 #include "common/build.hpp"
@@ -58,6 +59,7 @@
 #include "tests/flags.hpp"
 #include "tests/limiter.hpp"
 #include "tests/mesos.hpp"
+#include "tests/utils.hpp"
 
 using namespace mesos::internal::slave;
 
@@ -399,7 +401,7 @@ TEST_F(SlaveTest, CommandExecutorWithOverride)
   ASSERT_SOME(file);
 
   string executorCommand =
-    path::join(tests::flags.build_dir, "src", "mesos-executor") +
+    path::join(getLauncherDir(), "mesos-executor") +
     " --override -- /bin/sh -c 'echo hello world >" + file.get() + "'";
 
   // Expect two status updates, one for once the mesos-executor says
@@ -757,8 +759,7 @@ TEST_F(SlaveTest, ROOT_RunTaskWithCommandInfoWithoutUser)
   CHECK_SOME(user) << "Failed to get current user name"
                    << (user.isError() ? ": " + user.error() : "");
 
-  const string helper =
-      path::join(tests::flags.build_dir, "src", "active-user-test-helper");
+  const string helper = getTestHelperPath("active-user-test-helper");
 
   // Command executor will run as user running test.
   CommandInfo command;
@@ -835,8 +836,7 @@ TEST_F(SlaveTest, 
DISABLED_ROOT_RunTaskWithCommandInfoWithUser)
 
   Future<TaskStatus> statusRunning;
   Future<TaskStatus> statusFinished;
-  const string helper =
-      path::join(tests::flags.build_dir, "src", "active-user-test-helper");
+  const string helper = getTestHelperPath("active-user-test-helper");
 
   Future<vector<Offer>> offers;
   EXPECT_CALL(sched, resourceOffers(&driver, _))

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/src/tests/test_framework_test.sh
----------------------------------------------------------------------
diff --git a/src/tests/test_framework_test.sh b/src/tests/test_framework_test.sh
index 409e809..617ca52 100755
--- a/src/tests/test_framework_test.sh
+++ b/src/tests/test_framework_test.sh
@@ -14,7 +14,11 @@ test $? != 0 && \
   echo "Failed to find MESOS_BUILD_DIR in environment" && \
   exit 1
 
+
+source ${MESOS_SOURCE_DIR}/support/colors.sh
 source ${MESOS_SOURCE_DIR}/support/atexit.sh
+source ${MESOS_HELPER_DIR}/colors.sh
+source ${MESOS_HELPER_DIR}/atexit.sh
 
 MESOS_WORK_DIR=`mktemp -d -t mesos-XXXXXX`
 
@@ -34,4 +38,4 @@ export MESOS_ISOLATION="filesystem/posix,posix/cpu,posix/mem"
 export MESOS_LAUNCHER="posix"
 
 # Check that the C++ test framework executes without crashing (returns 0).
-exec ${MESOS_BUILD_DIR}/src/test-framework --master=local
+exec ${MESOS_HELPER_DIR}/test-framework --master=local

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/src/tests/utils.cpp
----------------------------------------------------------------------
diff --git a/src/tests/utils.cpp b/src/tests/utils.cpp
index 22bf3a8..cc5259a 100644
--- a/src/tests/utils.cpp
+++ b/src/tests/utils.cpp
@@ -29,10 +29,18 @@
 #include "tests/flags.hpp"
 #include "tests/utils.hpp"
 
+using std::string;
+
 namespace mesos {
 namespace internal {
 namespace tests {
 
+#if MESOS_INSTALL_TESTS
+const bool searchInstallationDirectory = true;
+#else
+const bool searchInstallationDirectory = false;
+#endif
+
 JSON::Object Metrics()
 {
   process::UPID upid("metrics", process::address());
@@ -49,6 +57,125 @@ JSON::Object Metrics()
   return parse.get();
 }
 
+string getModulePath(const string& name)
+{
+  string path = path::join(
+      tests::flags.build_dir,
+      "src",
+      ".libs");
+
+  if (!os::exists(path) && searchInstallationDirectory) {
+    path = PKGMODULEDIR;
+  }
+
+  return path::join(path, os::libraries::expandName(name));
+}
+
+string getLibMesosPath()
+{
+  string path = path::join(
+      tests::flags.build_dir,
+      "src",
+      ".libs",
+      os::libraries::expandName("mesos-" VERSION));
+
+  if (!os::exists(path) && searchInstallationDirectory) {
+    path = path::join(
+        LIBDIR,
+        os::libraries::expandName("mesos-" VERSION));
+  }
+
+  return path;
+}
+
+string getLauncherDir()
+{
+  string path = path::join(
+      tests::flags.build_dir,
+      "src");
+
+  if (!os::exists(path) && searchInstallationDirectory) {
+    path = PKGLIBEXECDIR;
+  }
+
+  return path;
+}
+
+string getTestHelperPath(const string& name)
+{
+  string path = path::join(
+      tests::flags.build_dir,
+      "src",
+      name);
+
+  if (!os::exists(path) && searchInstallationDirectory) {
+    path = path::join(
+        TESTLIBEXECDIR,
+        name);
+  }
+
+  return path;
+}
+
+string getTestHelperDir()
+{
+  string path = path::join(
+      tests::flags.build_dir,
+      "src");
+
+  if (!os::exists(path) && searchInstallationDirectory) {
+      return TESTLIBEXECDIR;
+  }
+
+  return path;
+}
+
+string getTestScriptPath(const string& script)
+{
+  string path = path::join(
+      flags.source_dir,
+      "src",
+      "tests",
+      script);
+
+  if (!os::exists(path) && searchInstallationDirectory) {
+    path = path::join(
+        TESTLIBEXECDIR,
+        script);
+  }
+
+  return path;
+}
+
+string getSbinDir()
+{
+  string path = path::join(
+      tests::flags.build_dir,
+      "src");
+
+  if (!os::exists(path) && searchInstallationDirectory) {
+      return SBINDIR;
+  }
+
+  return path;
+}
+
+string getWebUIDir()
+{
+  string path = path::join(
+      flags.source_dir,
+      "src",
+      "webui");
+
+  if (!os::exists(path) && searchInstallationDirectory) {
+    path = path::join(
+        PKGDATADIR,
+        "webui");
+  }
+
+  return path;
+}
+
 } // namespace tests {
 } // namespace internal {
 } // namespace mesos {

http://git-wip-us.apache.org/repos/asf/mesos/blob/6cca8c80/src/tests/utils.hpp
----------------------------------------------------------------------
diff --git a/src/tests/utils.hpp b/src/tests/utils.hpp
index a6cca47..140ebaa 100644
--- a/src/tests/utils.hpp
+++ b/src/tests/utils.hpp
@@ -27,6 +27,48 @@ namespace tests {
 // TODO(vinod): Move this into a libprocess utility header.
 JSON::Object Metrics();
 
+// Path finding utilities.
+//
+// Various tests need to access paths to load files or libraries. Normally,
+// these paths are located within the build directory, often in the .libs
+// directories generated by Automake. However, if the Mesos tests were built
+// with --enable-tests-install, we may be running the tests from an installed
+// version of the test suite. In this case, we should always find paths in the
+// installation tree and never the build directory. If the build directory is
+// still present, you can force these helpers to ignore it by passing the
+// --build_dir=/none option to the test suite.
+//
+// The path helpers below all check for a build directory path, then fall back
+// to an installation path only if --enable-tests-install was specified at
+// configuration time.
+
+// Get the path to a named Mesos module.
+std::string getModulePath(const std::string& name);
+
+// Get the path to libmesos-$(VERSION).so
+std::string getLibMesosPath();
+
+// Get the launcher directory for mesos-executor, mesos-containerizer, etc.
+std::string getLauncherDir();
+
+// Get the path to a named test helper.
+std::string getTestHelperPath(const std::string& name);
+
+// Get the path to a named test script. In the Mesos source tree,
+// these live in $MESOS_SOURCE_DIR/src/tests. In a tests install
+// they live in $TESTLIBEXECDIR.
+std::string getTestScriptPath(const std::string& name);
+
+// Get the path to the directory where test helpers are installed.
+std::string getTestHelperDir();
+
+// Get the path to the directory where executables that require super-
+// user privileges are installed.
+std::string getSbinDir();
+
+// Get the path to the directory of the webui files/assets.
+std::string getWebUIDir();
+
 } // namespace tests {
 } // namespace internal {
 } // namespace mesos {

Reply via email to