You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by ti...@apache.org on 2016/10/12 17:46:38 UTC

[1/5] mesos git commit: Added a parallel gtest runner.

Repository: mesos
Updated Branches:
  refs/heads/master b2beef37f -> 1fdea7dec


Added a parallel gtest runner.

Adds a driver capable of running different GoogleTest test cases in
parallel. We will add the driver to the build setup in later commits.

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


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

Branch: refs/heads/master
Commit: 5ccacf5e6b977b190f29e34099dd361b7a95fff8
Parents: b2beef3
Author: Benjamin Bannier <be...@mesosphere.io>
Authored: Wed Oct 12 16:57:13 2016 +0200
Committer: Till Toenshoff <to...@me.com>
Committed: Wed Oct 12 16:57:13 2016 +0200

----------------------------------------------------------------------
 support/mesos-gtest-runner.py | 274 +++++++++++++++++++++++++++++++++++++
 1 file changed, 274 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/5ccacf5e/support/mesos-gtest-runner.py
----------------------------------------------------------------------
diff --git a/support/mesos-gtest-runner.py b/support/mesos-gtest-runner.py
new file mode 100755
index 0000000..6c1cf54
--- /dev/null
+++ b/support/mesos-gtest-runner.py
@@ -0,0 +1,274 @@
+#!/usr/bin/env python
+#
+# 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.
+
+
+"""
+Parallel test runner for GoogleTest programs.
+
+This script allows one to execute GoogleTest tests in parallel.
+GoogleTest programs come with built-in support for running in parallel.
+Here tests can automatically be partitioned across a number of test
+program invocations ("shards"). This script provides a convenient
+wrapper around that functionality and stream-lined output.
+"""
+
+
+from __future__ import print_function
+
+import multiprocessing
+import optparse
+import os
+import signal
+import subprocess
+import sys
+
+
+DEFAULT_NUM_JOBS = int(multiprocessing.cpu_count() * 1.5)
+
+
+class Bcolors:
+    """
+    A collection of tty output modifiers.
+
+    To switch the output of a string, prefix it with the desired
+    modifier, and terminate it with 'ENDC'.
+    """
+
+    HEADER = '\033[95m' if sys.stdout.isatty() else ''
+    OKBLUE = '\033[94m' if sys.stdout.isatty() else ''
+    OKGREEN = '\033[92m' if sys.stdout.isatty() else ''
+    WARNING = '\033[93m' if sys.stdout.isatty() else ''
+    FAIL = '\033[91m'if sys.stdout.isatty() else ''
+    ENDC = '\033[0m' if sys.stdout.isatty() else ''
+    BOLD = '\033[1m' if sys.stdout.isatty() else ''
+    UNDERLINE = '\033[4m' if sys.stdout.isatty() else ''
+
+    @staticmethod
+    def colorize(string, *color_codes):
+        """Decorate a string with a number of color codes."""
+        colors = ''.join(color_codes)
+        return '{begin}{string}{end}'.format(
+            begin=colors if sys.stdout.isatty() else '',
+            string=string,
+            end=Bcolors.ENDC if sys.stdout.isatty() else '')
+
+
+def run_test(opts):
+    """
+    Perform an actual run of the test executable.
+
+    Expects a list of parameters giving the number of the current
+    shard, the total number of shards, and the executable to run.
+    """
+    shard, nshards, executable = opts
+
+    signal.signal(signal.SIGINT, signal.SIG_IGN)
+
+    env = os.environ.copy()
+    env['GTEST_TOTAL_SHARDS'] = str(nshards)
+    env['GTEST_SHARD_INDEX'] = str(shard)
+
+    try:
+        output = subprocess.check_output(
+            executable.split(),
+            stderr=subprocess.STDOUT,
+            env=env,
+            universal_newlines=True)
+        print(Bcolors.colorize('.', Bcolors.OKGREEN), end='')
+        sys.stdout.flush()
+        return True, output
+    except subprocess.CalledProcessError as ex:
+        print(Bcolors.colorize('.', Bcolors.FAIL), end='')
+        sys.stdout.flush()
+        return False, ex.output
+
+
+def parse_arguments():
+    """Return the executable to work on, and a list of options."""
+    parser = optparse.OptionParser(
+        usage='Usage: %prog [options] <test> [-- <test_options>]')
+
+    parser.add_option(
+        '-j', '--jobs', type='int',
+        default=DEFAULT_NUM_JOBS,
+        help='number of parallel jobs to spawn. DEFAULT: {default_}'
+        .format(default_=DEFAULT_NUM_JOBS))
+
+    parser.add_option(
+        '-s', '--sequential', type='string',
+        default='',
+        help='gtest filter for tests to run sequentially')
+
+    parser.add_option(
+        '-v', '--verbosity', type='int',
+        default=1,
+        help='output verbosity:'
+        ' 0 only shows summarized information,'
+        ' 1 also shows full logs of failed shards, and anything'
+        ' >1 shows all output. DEFAULT: 1')
+
+    (options, executable) = parser.parse_args()
+
+    if not executable:
+        parser.print_usage()
+        sys.exit(1)
+
+    if not os.path.isfile(executable[0]):
+        print(
+            Bcolors.colorize(
+                "ERROR: File '{file}' does not exists"
+                .format(file=executable[0]), Bcolors.FAIL),
+            file=sys.stderr)
+        sys.exit(1)
+
+    if not os.access(executable[0], os.X_OK):
+        print(
+            Bcolors.colorize(
+                "ERROR: File '{file}' is not executable"
+                .format(file=executable[0]), Bcolors.FAIL),
+            file=sys.stderr)
+        sys.exit(1)
+
+    if options.sequential and options.sequential.count(':-'):
+        print(
+            Bcolors.colorize(
+                "ERROR: Cannot use negative filters in "
+                "'sequential' parameter: '{filter}'"
+                .format(filter=options.sequential), Bcolors.FAIL),
+            file=sys.stderr)
+        sys.exit(1)
+
+    if options.sequential and os.environ.get('GTEST_FILTER') and \
+            os.environ['GTEST_FILTER'].count(':-'):
+        print(
+            Bcolors.colorize(
+                "ERROR: Cannot specify both 'sequential' ""option "
+                "and environment variable 'GTEST_FILTER' "
+                "containing negative filters",
+                Bcolors.FAIL),
+            file=sys.stderr)
+        sys.exit(1)
+
+    if os.environ.get('GTEST_FILTER'):
+        options.parallel = '{env_filter}:-{sequential_filter}'\
+                         .format(env_filter=os.environ['GTEST_FILTER'],
+                                 sequential_filter=options.sequential)
+    else:
+        options.parallel = '*:-{sequential_filter}'\
+                         .format(sequential_filter=options.sequential)
+
+    return executable, options
+
+
+if __name__ == '__main__':
+    EXECUTABLE, OPTIONS = parse_arguments()
+
+    def options_gen(executable, filter_, jobs):
+        """Generator for options for a certain shard.
+
+        Here we set up GoogleTest specific flags, and generate
+        distinct shard indices.
+        """
+        opts = range(jobs)
+
+        # If we run in a terminal, enable colored test output. We
+        # still allow users to disable this themselves via extra args.
+        if sys.stdout.isatty():
+            args = executable[1:]
+            executable = '{exe} --gtest_color=yes {args}'\
+                         .format(exe=executable[0], args=args if args else '')
+
+        if filter_:
+            executable = '{exe} --gtest_filter={filter}'\
+                         .format(exe=executable, filter=filter_)
+
+        for opt in opts:
+            yield opt, jobs, executable
+
+    try:
+        RESULTS = []
+
+        POOL = multiprocessing.Pool(processes=OPTIONS.jobs)
+
+        # Run parallel tests.
+        #
+        # Multiprocessing's `map` cannot properly handle `KeyboardInterrupt` in
+        # some python versions. Use `map_async` with an explicit timeout
+        # instead. See http://stackoverflow.com/a/1408476.
+        RESULTS.extend(
+            POOL.map_async(
+                run_test,
+                options_gen(
+                    EXECUTABLE, OPTIONS.parallel, OPTIONS.jobs)).get(
+                        timeout=sys.maxint))
+
+        # Now run sequential tests.
+        if OPTIONS.sequential:
+            RESULTS.extend(
+                POOL.map_async(
+                    run_test,
+                    options_gen(
+                        EXECUTABLE, OPTIONS.sequential, 1)).get(
+                            timeout=sys.maxint))
+
+        # Count the number of failed shards and print results from
+        # failed shards.
+        #
+        # NOTE: The `RESULTS` array stores the result for each
+        # `run_test` invocation returning a tuple (success, output).
+        NFAILED = len([success for success, __ in RESULTS if not success])
+
+        # TODO(bbannier): Introduce a verbosity which prints results
+        # as they arrive; this likely requires some output parsing to
+        # ensure results from different tests do not interleave.
+        for result in RESULTS:
+            if not result[0]:
+                if OPTIONS.verbosity > 0:
+                    print(result[1], file=sys.stderr)
+            else:
+                if OPTIONS.verbosity > 1:
+                    print(result[1], file=sys.stdout)
+
+        if NFAILED > 0:
+            print(Bcolors.colorize('\n[FAIL]', Bcolors.FAIL, Bcolors.BOLD),
+                  file=sys.stderr)
+        else:
+            print(Bcolors.colorize('\n[PASS]', Bcolors.OKGREEN, Bcolors.BOLD))
+
+        sys.exit(NFAILED)
+
+    except KeyboardInterrupt:
+        # Force a newline after intermediate test reports.
+        print()
+
+        print('Caught KeyboardInterrupt, terminating workers')
+
+        POOL.terminate()
+        POOL.join()
+
+        sys.exit(1)
+
+    except OSError as ex:
+        print(Bcolors.colorize(
+            '\nERROR: {ex}'.format(ex=ex),
+            Bcolors.FAIL, Bcolors.BOLD))
+
+        POOL.terminate()
+        POOL.join()
+
+        sys.exit(1)


[5/5] mesos git commit: Permitted specifying custom test driver in stout.

Posted by ti...@apache.org.
Permitted specifying custom test driver in stout.

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


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

Branch: refs/heads/master
Commit: 1fdea7dec36244d852f1fdb9436f74aabd9f8bb7
Parents: 105cc65
Author: Benjamin Bannier <be...@mesosphere.io>
Authored: Wed Oct 12 18:58:54 2016 +0200
Committer: Till Toenshoff <to...@me.com>
Committed: Wed Oct 12 18:58:54 2016 +0200

----------------------------------------------------------------------
 3rdparty/stout/Makefile.am  | 2 +-
 3rdparty/stout/configure.ac | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/1fdea7de/3rdparty/stout/Makefile.am
----------------------------------------------------------------------
diff --git a/3rdparty/stout/Makefile.am b/3rdparty/stout/Makefile.am
index fda069d..e70d301 100644
--- a/3rdparty/stout/Makefile.am
+++ b/3rdparty/stout/Makefile.am
@@ -188,7 +188,7 @@ BUILT_SOURCES = $(BUNDLED_DEPS)
 # See the following discussion for the workaround:
 # http://lists.gnu.org/archive/html/automake/2013-01/msg00051.html
 check-local: tests
-	./stout-tests
+	$(TEST_DRIVER) ./stout-tests
 
 tests: $(BUNDLED_DEPS)
 	$(MAKE) $(AM_MAKEFLAGS) stout-tests

http://git-wip-us.apache.org/repos/asf/mesos/blob/1fdea7de/3rdparty/stout/configure.ac
----------------------------------------------------------------------
diff --git a/3rdparty/stout/configure.ac b/3rdparty/stout/configure.ac
index 527188a..cbb0fdb 100644
--- a/3rdparty/stout/configure.ac
+++ b/3rdparty/stout/configure.ac
@@ -156,8 +156,9 @@ AC_ARG_WITH([svn],
 
 
 ###############################################################################
-# Miscellaneous flags/library/tool checks
+# Miscellaneous flags/library/tool checks.
 ###############################################################################
+AC_ARG_VAR([TEST_DRIVER], [executable and arguments of a test driver])
 
 # Check for pthreads (uses m4/ax_pthread.m4).
 AX_PTHREAD([], [AC_MSG_ERROR([failed to find pthreads])])


[4/5] mesos git commit: Permitted specifying custom test driver in libprocess.

Posted by ti...@apache.org.
Permitted specifying custom test driver in libprocess.

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


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

Branch: refs/heads/master
Commit: 105cc65242755c0e24e81d001dcbfdfa7ea352d5
Parents: 8b61157
Author: Benjamin Bannier <be...@mesosphere.io>
Authored: Wed Oct 12 18:58:48 2016 +0200
Committer: Till Toenshoff <to...@me.com>
Committed: Wed Oct 12 18:58:48 2016 +0200

----------------------------------------------------------------------
 3rdparty/libprocess/Makefile.am  | 2 +-
 3rdparty/libprocess/configure.ac | 6 ++++++
 2 files changed, 7 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/105cc652/3rdparty/libprocess/Makefile.am
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/Makefile.am b/3rdparty/libprocess/Makefile.am
index 020b0e1..f91155b 100644
--- a/3rdparty/libprocess/Makefile.am
+++ b/3rdparty/libprocess/Makefile.am
@@ -304,7 +304,7 @@ BUILT_SOURCES = $(BUNDLED_DEPS)
 # See the following discussion for the workaround:
 # http://lists.gnu.org/archive/html/automake/2013-01/msg00051.html
 check-local: tests
-	./libprocess-tests
+	$(TEST_DRIVER) ./libprocess-tests
 
 tests: all $(BUNDLED_DEPS)
 	$(MAKE) $(AM_MAKEFLAGS) libprocess-tests benchmarks

http://git-wip-us.apache.org/repos/asf/mesos/blob/105cc652/3rdparty/libprocess/configure.ac
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/configure.ac b/3rdparty/libprocess/configure.ac
index f3033e3..1644035 100644
--- a/3rdparty/libprocess/configure.ac
+++ b/3rdparty/libprocess/configure.ac
@@ -213,6 +213,12 @@ AC_ARG_WITH([svn],
 
 
 ###############################################################################
+# Miscellaneous flags/library/tool checks.
+###############################################################################
+AC_ARG_VAR([TEST_DRIVER], [executable and arguments of a test driver])
+
+
+###############################################################################
 # Compiler checks.
 ###############################################################################
 


[3/5] mesos git commit: Enable Mesos test runner.

Posted by ti...@apache.org.
Enable Mesos test runner.

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


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

Branch: refs/heads/master
Commit: 8b611570bec9936a72917d19ed90dc6a87d16632
Parents: d996d78
Author: Benjamin Bannier <be...@mesosphere.io>
Authored: Wed Oct 12 18:58:42 2016 +0200
Committer: Till Toenshoff <to...@me.com>
Committed: Wed Oct 12 18:58:42 2016 +0200

----------------------------------------------------------------------
 src/Makefile.am | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/8b611570/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index fd01e1d..3bcc0f2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2346,7 +2346,7 @@ uninstall-hook:
 # See the following discussion for the workaround:
 # http://lists.gnu.org/archive/html/automake/2013-01/msg00051.html
 check-local: tests
-	./mesos-tests
+	$(TEST_DRIVER) ./mesos-tests
 
 if INSTALL_TESTS
 # If we enabled test installation, we can run the tests from the


[2/5] mesos git commit: Added configure option for Mesos test runner.

Posted by ti...@apache.org.
Added configure option for Mesos test runner.

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


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

Branch: refs/heads/master
Commit: d996d78c4010c4d8319c102a5dfaf7f71b9c198a
Parents: 5ccacf5
Author: Benjamin Bannier <be...@mesosphere.io>
Authored: Wed Oct 12 18:58:32 2016 +0200
Committer: Till Toenshoff <to...@me.com>
Committed: Wed Oct 12 18:58:32 2016 +0200

----------------------------------------------------------------------
 configure.ac | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/d996d78c/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index 034bb91..015255e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -253,6 +253,9 @@ AC_ARG_ENABLE([zlib],
                            will be far less responsive; not recommended]),
             [enable_zlib=no], [enable_zlib=yes])
 
+AC_ARG_ENABLE([parallel_test_execution],
+              AS_HELP_STRING([--enable-parallel-test-execution],
+                             [execute tests in parallel where possible]))
 
 ###############################################################################
 # Optional packages.
@@ -544,7 +547,7 @@ esac
 
 
 ###############################################################################
-# Miscellaneous flags/library/tool checks
+# Miscellaneous flags/library/tool checks.
 ###############################################################################
 
 AC_ARG_VAR([JAVA_HOME], [location of Java Development Kit (JDK)])
@@ -559,6 +562,8 @@ AC_ARG_VAR([PROTOBUF_JAR], [full path to protobuf jar on prefixed builds])
 
 AC_ARG_VAR([PYTHON], [which Python interpreter to use])
 
+AC_ARG_VAR([TEST_DRIVER], [executable and arguments of a test driver])
+
 # Check for pthreads (uses m4/ax_pthread.m4).
 AX_PTHREAD([], [AC_MSG_ERROR([failed to find pthreads])])
 
@@ -605,6 +610,17 @@ AM_CONDITIONAL([INSTALL_TESTS], [test x"$enable_tests_install" = "xyes"])
 AS_IF([test x"$enable_tests_install" = "xyes"],
       [AC_DEFINE([MESOS_INSTALL_TESTS], [1])])
 
+# If we use our own test runner to parallelize gtests we can run
+# everything but ROOT tests in parallel.
+# We here set up `TEST_DRIVER` to contain an unexpanded automake
+# variable name; this allows us to reuse the test runner to run bundled
+# 3rdparty checks. The special quoting ensures that this containing a
+# space is not expanded by autoconf.
+# TODO(bbannier): Make this more readible by using autoconf/m4 magic.
+AS_IF([test "x$enable_parallel_test_execution" = "xyes"],
+      [AC_SUBST([TEST_DRIVER],
+       '${abs_top_srcdir}/support/mesos-gtest-runner.py'[' --sequential='*ROOT_*'']]))
+
 # Check for libunwind, and link it in if present.
 if test "x$OS_NAME" = "xfreebsd"; then
   AC_CHECK_LIB(execinfo, backtrace, LIBS="$LIBS -lexecinfo")