automake-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Parallel test execution: new option `parallel-tests': [1/4]


From: Ralf Wildenhues
Subject: Parallel test execution: new option `parallel-tests': [1/4]
Date: Sun, 12 Oct 2008 22:34:02 +0200
User-agent: Mutt/1.5.18 (2008-05-17)

Parallel test execution: new option `parallel-tests'.

2008-07-05  Akim Demaille <address@hidden>
            Jim Meyering <address@hidden>
            Benoit Sigoure <address@hidden>
            Ralf Wildenhues <address@hidden>

    * automake.in (handle_tests): Set new conditional PARALLEL_TESTS
    when reading check.am.  Handle option `parallel-tests' and all
    its new semantics.  Define macros TEST_SUFFIXES, TEST_SUITE_LOG,
    TEST_SUITE_HTML, TEST_LOGS, TEST_LOGS_TMP, suffix rules if
    applicable, and per-target rules for other tests.  Add all log
    files to %clean_files at the `MOSTLY_CLEAN' level.
    * lib/Automake/Options.pm (_process_option_list): Accept
    `parallel-tests'.
    * lib/am/check.am [!PARALLEL_TESTS] (check-TESTS): Move existing
    testsuite driver under this new conditional.
    [PARALLEL_TESTS]
    (am__rst_title, am__rst_section, am__text_box am__sh_e_setup)
    (am__check_pre, am__check_post): New internal macros.
    ($(TEST_SUITE_LOG), check-TESTS, .log.html, check-html): New
    rules.
    * lib/am/check2.am: New file.
    * lib/am/Makefile.am (dist_am_DATA): Add check2.am.
    * tests/Makefile.am (AUTOMAKE_OPTIONS): Use `parallel-tests'.
    (clean-local): Renamed from distclean-local.
    * tests/defs.in: Drop VERBOSE handling, not needed here any more.

diff --git a/automake.in b/automake.in
index 99f6400..b4e0312 100755
--- a/automake.in
+++ b/automake.in
@@ -4738,13 +4738,95 @@ sub handle_tests
     {
       push (@check_tests, 'check-TESTS');
       $output_rules .= &file_contents ('check', new Automake::Location,
-                                      COLOR => !! option 'color-tests');
+                                      COLOR => !! option 'color-tests',
+                                      PARALLEL_TESTS => !! option 
'parallel-tests');
 
       # Tests that are known programs should have $(EXEEXT) appended.
       # For matching purposes, we need to adjust XFAIL_TESTS as well.
       append_exeext { exists $known_programs{$_[0]} } 'TESTS';
       append_exeext { exists $known_programs{$_[0]} } 'XFAIL_TESTS'
        if (var ('XFAIL_TESTS'));
+
+      if (option 'parallel-tests')
+        {
+         define_variable ('TEST_SUITE_LOG', 'test-suite.log', INTERNAL);
+         define_variable ('TEST_SUITE_HTML', '$(TEST_SUITE_LOG:.log=.html)', 
INTERNAL);
+         my $suff = '.test';
+         my $at_exeext = '';
+         if (exists $configure_vars{'EXEEXT'})
+           {
+             $at_exeext = subst ('EXEEXT');
+             $suff = $at_exeext  . ' ' . $suff;
+           }
+         define_variable ('TEST_SUFFIXES', $suff, INTERNAL);
+         # FIXME: this mishandles conditions.
+         my @test_suffixes = (var 'TEST_SUFFIXES')->value_as_list_recursive;
+         if (exists $configure_vars{'EXEEXT'})
+           {
+             unshift (@test_suffixes, $at_exeext)
+               unless $test_suffixes[0] eq $at_exeext;
+           }
+         unshift (@test_suffixes, '');
+
+         transform_variable_recursively
+           ('TESTS', 'TEST_LOGS', 'am__testlogs', 1, INTERNAL,
+             sub {
+               my ($subvar, $val, $cond, $full_cond) = @_;
+               my $obj = $val;
+               return $obj
+                 if $val =~ /address@hidden@$/;
+               $obj =~ s/\$\(EXEEXT\)$//o;
+               foreach my $test_suffix (@test_suffixes)
+                 {
+                   next
+                     if $test_suffix eq $at_exeext || $test_suffix eq '';
+                   return substr ($obj, 0, length ($obj) - length 
($test_suffix)) . '.log'
+                     if substr ($obj, - length ($test_suffix)) eq $test_suffix;
+                 }
+               $obj .= '.log';
+               $output_rules .= file_contents ('check2', new 
Automake::Location,
+                                               GENERIC => 0,
+                                               OBJ => $obj,
+                                               SOURCE => $val,
+                                               EXT => '');
+               return $obj;
+             });
+
+         my $nhelper=1;
+         my $prev = 'TESTS';
+         my $post = '';
+         my $last_suffix = $test_suffixes[$#test_suffixes];
+         my $cur = '';
+         foreach my $test_suffix (@test_suffixes)
+           {
+             if ($test_suffix eq $last_suffix)
+               {
+                 $cur = 'TEST_LOGS';
+               }
+             else
+               {
+                 $cur = 'am__test_logs' . $nhelper;
+               }
+             define_variable ($cur,
+               '$(' . $prev . ':' . $test_suffix . $post . '=.log)', INTERNAL);
+             $post = '.log';
+             $prev = $cur;
+             $nhelper++;
+             $output_rules .= file_contents ('check2', new Automake::Location,
+                                             GENERIC => 1,
+                                             OBJ => '',
+                                             SOURCE => '$<',
+                                             EXT => $test_suffix)
+               if $test_suffix ne $at_exeext && $test_suffix ne '';
+           }
+
+         define_variable ('TEST_LOGS_TMP', '$(TEST_LOGS:.log=.log-t)', 
INTERNAL);
+
+         $clean_files{'$(TEST_LOGS_TMP)'} = MOSTLY_CLEAN;
+         $clean_files{'$(TEST_LOGS)'} = MOSTLY_CLEAN;
+         $clean_files{'$(TEST_SUITE_LOG)'} = MOSTLY_CLEAN;
+         $clean_files{'$(TEST_SUITE_HTML)'} = MOSTLY_CLEAN;
+       }
     }
 }
 
diff --git a/lib/Automake/Options.pm b/lib/Automake/Options.pm
index 1705981..df08e05 100644
--- a/lib/Automake/Options.pm
+++ b/lib/Automake/Options.pm
@@ -266,7 +266,7 @@ sub _process_option_list (\%$@)
             || $_ eq 'subdir-objects' || $_ eq 'nostdinc'
             || $_ eq 'no-exeext' || $_ eq 'no-define'
             || $_ eq 'std-options'
-            || $_ eq 'color-tests'
+            || $_ eq 'color-tests' || $_ eq 'parallel-tests'
             || $_ eq 'cygnus' || $_ eq 'no-dependencies')
        {
          # Explicitly recognize these.
diff --git a/lib/am/Makefile.am b/lib/am/Makefile.am
index f6fdafa..1ab2f31 100644
--- a/lib/am/Makefile.am
+++ b/lib/am/Makefile.am
@@ -2,7 +2,7 @@
 
 ## Makefile for Automake lib/am.
 
-## Copyright (C) 1995, 1996, 1997, 1998, 1999, 2001, 2003, 2004
+## Copyright (C) 1995, 1996, 1997, 1998, 1999, 2001, 2003, 2004, 2008
 ## Free Software Foundation, Inc.
 
 ## This program is free software; you can redistribute it and/or modify
@@ -23,6 +23,7 @@ amdir = $(pkgvdatadir)/am
 dist_am_DATA = \
 ansi2knr.am \
 check.am \
+check2.am \
 clean-hdr.am \
 clean.am \
 compile.am \
diff --git a/lib/am/check.am b/lib/am/check.am
index ca400fe..129f2d1 100644
--- a/lib/am/check.am
+++ b/lib/am/check.am
@@ -38,6 +38,219 @@ endif !%?COLOR%
 
 .PHONY: check-TESTS
 
+if %?PARALLEL_TESTS%
+
+include inst-vars.am
+
+## New parallel test driver.
+##
+## This provides special support for "unit tests", that is to
+## say, tests that (once run) no longer need to be re-compiled and
+## re-run at each "make check", unless their sources changed.  To
+## enable unit-test supports, define LAZY_TEST_SUITE.  In such a
+## setting, that heavily relies on correct dependencies, its users may
+## prefer to define EXTRA_PROGRAMS instead of check_PROGRAMS, because
+## it allows intertwined compilation and execution of the tests.
+## Sometimes this helps catching errors earlier (you don't have to
+## wait for all the tests to be compiled).
+##
+## Define TEST_SUITE_LOG to be the name of the global log to create.
+## Define TEST_LOGS to the set of logs to include in it.  It defaults
+## to $(TESTS), with `.test' and address@hidden@' removed, and `'.log'
+## appended.
+##
+## In addition to the magic "exit 77 means SKIP" feature (which was
+## imported from automake), there is a magic "exit 99 means FAIL" feature
+## which is useful if you need to issue a hard error no matter whether the
+## test is XFAIL or not.  You can disable this feature by setting the
+## variable DISABLE_HARD_ERRORS to `yes'.
+
+# Restructured Text title and section.
+am__rst_title   = sed 's/.*/   &   /;h;s/./=/g;p;x;p;g;p;s/.*//'
+am__rst_section = sed 'p;s/./=/g;p;g'
+
+# Put stdin (possibly several lines separated by ".  ") in a box.
+am__text_box = sed 's/\.  /\n/g' | sed '/^$$/d' |              \
+$(AWK) '{ if (final) final = final "\n" $$0; else final = $$0; }\
+max < length($$0) { max = length($$0); }                       \
+END {                                                          \
+  for (i = 0; i < max; ++i) line = line "=";                   \
+  print line; print final; print line;                         \
+}'
+
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL).  This contradicts POSIX.  Work around the problem
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+
+# To be inserted before the command running the test.  Creates the
+# directory for the log if needed.  Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log, and passes
+# TESTS_ENVIRONMENT.  Save and restore TERM around use of
+# TESTS_ENVIRONMENT, in case that unsets it.
+am__check_pre =                                                \
+$(am__sh_e_setup);                                     \
+$(am__vpath_adj_setup) $(am__vpath_adj)                        \
+srcdir=$(srcdir); export srcdir;                       \
+rm -f address@hidden;                                          \
+trap 'st=$$?; rm -f '\''$(abs_builddir)/address@hidden'\''; (exit $$st); exit 
$$st' \
+  1 2 13 15;                                           \
+am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;           \
+test "x$$am__odir" = x. || $(MKDIR_P) "$$am__odir" || exit $$?;        \
+if test -f "./$$f"; then dir=./;                       \
+elif test -f "$$f"; then dir=;                         \
+else dir="$(srcdir)/"; fi;                             \
+tst=$$dir$$f; log='$@'; __SAVED_TERM=$$TERM;           \
+$(TESTS_ENVIRONMENT)
+
+# To be appended to the command running the test.  Handle the stdout
+# and stderr redirection, and catch the exit status.
+am__check_post =                                       \
+>address@hidden 2>&1;                                          \
+estatus=$$?;                                           \
+TERM=$$__SAVED_TERM; export TERM;                      \
+$(am__tty_colors);                                     \
+xfailed=PASS;                                          \
+for xfail in : $(XFAIL_TESTS); do                      \
+  case $$f in                                          \
+    $$xfail | $(srcdir)/$$xfail) xfailed=XFAIL; break; \
+  esac;                                                        \
+done;                                                  \
+case $$estatus:$$xfailed in                            \
+    0:XFAIL) col=$$red; res=XPASS;;                    \
+    0:*)     col=$$grn; res=PASS ;;                    \
+    77:*)    col=$$blu; res=SKIP ;;                    \
+    99:*)    col=$$red; res=FAIL ;;                    \
+    *:XFAIL) col=$$lgn; res=XFAIL;;                    \
+    *:*)     col=$$red; res=FAIL ;;                    \
+esac;                                                  \
+echo "$${col}$$res$${std}: $$f";                       \
+echo "$$res: $$f (exit: $$estatus)" |                  \
+  $(am__rst_section) >$@;                              \
+cat address@hidden >>$@;                                               \
+rm -f address@hidden;                                          \
+if test -z '$(DISABLE_HARD_ERRORS)'                    \
+   && test $$estatus -eq 99; then                      \
+  exit $$estatus; else :;                              \
+fi
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+       @$(am__sh_e_setup);                                             \
+       list='$(TEST_LOGS)';                                            \
+       results=`for f in $$list; do                                    \
+                  read line < $$f && echo "$$line" || echo FAIL;       \
+                done`;                                                 \
+       all=`echo "$$results" | wc -l | sed -e 's/^[     ]*//'`;        \
+       fail=`echo "$$results" | grep -c '^FAIL'`;                      \
+       pass=`echo "$$results" | grep -c '^PASS'`;                      \
+       skip=`echo "$$results" | grep -c '^SKIP'`;                      \
+       xfail=`echo "$$results" | grep -c '^XFAIL'`;                    \
+       xpass=`echo "$$results" | grep -c '^XPASS'`;                    \
+       failures=`expr $$fail + $$xpass`;                               \
+       all=`expr $$all - $$skip`;                                      \
+       if test "$$all" -eq 1; then tests=test; All=;                   \
+       else tests=tests; All="All "; fi;                               \
+       case fail=$$fail:xpass=$$xpass:xfail=$$xfail in                 \
+         fail=0:xpass=0:xfail=0)                                       \
+           msg="$$All$$all $$tests passed.  ";                         \
+           exit=true;;                                                 \
+         fail=0:xpass=0:xfail=*)                                       \
+           msg="$$All$$all $$tests behaved as expected";               \
+           if test "$$xfail" -eq 1; then xfailures=failure;            \
+           else xfailures=failures; fi;                                \
+           msg="$$msg ($$xfail expected $$xfailures).  ";              \
+           exit=true;;                                                 \
+         fail=*:xpass=0:xfail=*)                                       \
+           msg="$$fail of $$all $$tests failed.  ";                    \
+           exit=false;;                                                \
+         fail=*:xpass=*:xfail=*)                                       \
+           msg="$$failures of $$all $$tests did not behave as expected"; \
+           if test "$$xpass" -eq 1; then xpasses=pass;                 \
+           else xpasses=passes; fi;                                    \
+           msg="$$msg ($$xpass unexpected $$xpasses).  ";              \
+           exit=false;;                                                \
+         *)                                                            \
+           echo >&2 "incorrect case"; exit 4;;                         \
+       esac;                                                           \
+       if test "$$skip" -ne 0; then                                    \
+         if test "$$skip" -eq 1; then                                  \
+           msg="$$msg($$skip test was not run).  ";                    \
+         else                                                          \
+           msg="$$msg($$skip tests were not run).  ";                  \
+         fi;                                                           \
+       fi;                                                             \
+       if test "$$failures" -ne 0; then                                \
+         {                                                             \
+           echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" |     \
+             $(am__rst_title);                                         \
+           echo "$$msg";                                               \
+           echo;                                                       \
+           echo ".. contents:: :depth: 2";                             \
+           echo;                                                       \
+           for f in $$list; do                                         \
+             read line < $$f;                                          \
+             case $$line in                                            \
+               SKIP:*|PASS:*|XFAIL:*);;                                \
+               *) echo; cat $$f;;                                      \
+             esac;                                                     \
+           done;                                                       \
+         } >$(TEST_SUITE_LOG).tmp;                                     \
+         mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG);                   \
+         msg="$${msg}See $(subdir)/$(TEST_SUITE_LOG).  ";              \
+         if test -n "$(PACKAGE_BUGREPORT)"; then                       \
+           msg="$${msg}Please report to $(PACKAGE_BUGREPORT).  ";      \
+         fi;                                                           \
+       fi;                                                             \
+       $(am__tty_colors);                                              \
+       if $$exit; then                                                 \
+         echo $(ECHO_N) "$$grn$(ECHO_C)";                              \
+        else                                                           \
+         echo $(ECHO_N) "$$red$(ECHO_C)";                              \
+       fi;                                                             \
+       echo "$$msg" | $(am__text_box);                                 \
+       echo $(ECHO_N) "$$std$(ECHO_C)";                                \
+       test x"$$VERBOSE" = x || $$exit || cat $(TEST_SUITE_LOG);       \
+       $$exit
+
+# Run all the tests.
+check-TESTS:
+       @if test -z '$(LAZY_TEST_SUITE)'                                \
+           && test -n "$(TEST_SUITE_LOG)$(TEST_LOGS)"; then            \
+         rm -f $(TEST_SUITE_LOG) $(TEST_LOGS); \
+       fi
+       @$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG)
+
+
+## -------------- ##
+## Produce HTML.  ##
+## -------------- ##
+
+.log.html:
+       @list='$(RST2HTML) $$RST2HTML rst2html rst2html.py';            \
+       for r2h in $$list; do                                           \
+         if ($$r2h --version) >/dev/null 2>&1; then                    \
+           R2H=$$r2h;                                                  \
+         fi;                                                           \
+       done;                                                           \
+       if test -z "$$R2H"; then                                        \
+         echo >&2 "cannot find rst2html, cannot create $@";            \
+         exit 2;                                                       \
+       fi;                                                             \
+       $$R2H $< >address@hidden
+       @mv address@hidden $@
+
+# Be sure to run check-TESTS first, and then to convert the result.
+# Beware of concurrent executions.  And expect check-TESTS to fail.
+check-html:
+       @if $(MAKE) $(AM_MAKEFLAGS) check-TESTS; then :; else   \
+         rv=$$?;                                               \
+         $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_HTML);           \
+         exit $$rv;                                            \
+       fi
+.PHONY: check-html
+
+else !%?PARALLEL_TESTS%
+
 check-TESTS: $(TESTS)
        @failed=0; all=0; xfail=0; xpass=0; skip=0; \
        srcdir=$(srcdir); export srcdir; \
@@ -138,3 +351,5 @@ check-TESTS: $(TESTS)
          echo "$$dashes$$std"; \
          test "$$failed" -eq 0; \
        else :; fi
+
+endif !%?PARALLEL_TESTS%
diff --git a/lib/am/check2.am b/lib/am/check2.am
new file mode 100644
index 0000000..58ca9e6
--- /dev/null
+++ b/lib/am/check2.am
@@ -0,0 +1,20 @@
+## automake - create Makefile.in from Makefile.am
+## Copyright (C) 2008 Free Software Foundation, Inc.
+
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3, or (at your option)
+## any later version.
+
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+
+## You should have received a copy of the GNU General Public License
+## along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+## From a test file to a log file.
+?GENERIC?%EXT%.log:
+?!GENERIC?%OBJ%: %SOURCE%
+       @p='%SOURCE%'; $(am__check_pre) "$$tst" $(am__check_post)
diff --git a/tests/.gitignore b/tests/.gitignore
index f1c3bff..a6827fd 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -2,3 +2,5 @@ aclocal-*
 automake-*
 defs
 *.dir
+*.log
+*.log-t
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 32cefa5..9cc6dbe 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,4 +1,5 @@
 ## Process this file with automake to create Makefile.in
+AUTOMAKE_OPTIONS = parallel-tests
 
 XFAIL_TESTS =                                  \
 all.test                                       \
@@ -670,7 +671,7 @@ EXTRA_DIST = ChangeLog-old $(TESTS)
 # Each test case depends on defs, aclocal, and automake.
 check_SCRIPTS = defs aclocal-$(APIVERSION) automake-$(APIVERSION)
 
-distclean-local: check-clean-local
+clean-local: check-clean-local
 
 check-clean-local:
        -chmod -R u+rwx *.dir
diff --git a/tests/defs.in b/tests/defs.in
index fb4e0e0..063ce58 100644
--- a/tests/defs.in
+++ b/tests/defs.in
@@ -40,9 +40,7 @@ test -f ./defs || {
    exit 1
 }
 
-# If srcdir is not set, then we are not running from `make check', be verbose.
 if test -z "$srcdir"; then
-   VERBOSE=x
    # compute $srcdir.
    srcdir=`echo "$0" | sed -e 's,/[^\\/]*$,,'`
    test "$srcdir" = $0 && srcdir=.
@@ -56,12 +54,6 @@ test -f "$srcdir/defs.in" || {
 
 me=`echo "$0" | sed -e 's,.*[\\/],,;s/\.test$//'`
 
-# See how redirections should work.  User can set VERBOSE to see all
-# output.
-test -z "$VERBOSE" && {
-   exec > /dev/null 2>&1
-}
-
 # Make sure we override the user shell.
 SHELL='@SHELL@'
 export SHELL
@@ -402,10 +394,7 @@ AUTOMAKE_fails ()
   AUTOMAKE_run 1 ${1+"$@"}
 }
 
-# Turn on shell traces when VERBOSE is set.
-if test -n "$VERBOSE"; then
-  set -x
-else
-  :
-fi
+# Turn on shell traces.
+set -x
+
 pwd




reply via email to

[Prev in Thread] Current Thread [Next in Thread]