[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
bug#7868: [RFC] parallel-tests: avoid command-line length limit issue (w
From: |
Stefano Lattarini |
Subject: |
bug#7868: [RFC] parallel-tests: avoid command-line length limit issue (was: Re: bug#7868: splitting up test suites) |
Date: |
Thu, 20 Jan 2011 18:11:00 +0100 |
User-agent: |
KMail/1.13.3 (Linux/2.6.30-2-686; KDE/4.4.4; i686; ; ) |
On Thursday 20 January 2011, Stefano Lattarini wrote:
> Hello Ralf.
>
> On Wednesday 19 January 2011, Ralf Wildenhues wrote:
> > The testsuite is too large for MSYS.
> >
> Ouch.
>
> > We've finally reached the point where we have more than 1000
> > tests, $(TESTS) expands to 15k characters, and where 'make check' will
> > not work at all any more on MSYS, because it cannot spawn sh any more,
> > presumably in 'make check TESTS="..."'. (MSYS make doesn't export
> > macros to the environment of spawned processes even without .NOEXPORT,
> > presumably otherwise lots of Makefiles would be really unusable here.)
> > This also clears up the spurious failure of sed a few days ago.
> >
> > Here's a preliminary plan for multiple testsuites per Makefile.am.
> >
> Hmmm... while this feature might be worth having even indipendently
> from the issue at hand (but see below for small nits), I still think
> that in the long run it would be nicer to transparently work around
> such command-line length issues in the test driver, if possible. Do
> you think your patch "parallel-tests: avoid command-line length limit
> issue" (from commit v1.11-191-g24e3b4e) could be resurrected in some
> way?
>
OK, I've done my homework and come up with the attached patch.
It's not yet very well polished, and certainly needs more testsuite
exposure [1] on various systems before being "ok to apply", but it
seems quite promising to me.
[1] I'm posting it now anyway because I'm out of time for today.
Sorry.
Also, I'd appreciate if anyone could test it on MSYS (and Cygwin?),
since I don't have access to those systems.
Thanks,
Stefano
From f6f4dc5d2e6e3d174f696409fa5c07e207d377a4 Mon Sep 17 00:00:00 2001
From: Ralf Wildenhues <address@hidden>
Date: Tue, 7 Sep 2010 04:38:08 +0200
Subject: [PATCH] parallel-tests: avoid command-line length limit issue.
* automake.in (handle_tests): New argument $makefile, new
substitution %MAKEFILE%.
(generate_makefile): Adjust.
* lib/am/check.am [%?PARALLEL_TESTS%] (check-TESTS): Use a
temporary makefile to sanitize TEST_LOGS value passed to the
recursive $(MAKE) invocation, to avoid exceeding the command
line limit on w32 (MSYS). Extend comments.
* tests/parallel-tests-linewrap.test: New test.
* tests/parallel-tests-cleanup.test: Likewise.
* tests/parallel-tests-gnumakefile.test: Likewise.
* tests/parallel-tests-long-cmdline.test: Likewise.
* tests/Makefile.am (TESTS): Updated.
* NEWS: Update.
Report by Bob Friesenhahn.
---
ChangeLog | 19 +++++++
NEWS | 3 +
automake.in | 11 +++-
lib/Automake/tests/Makefile.in | 21 ++++++--
lib/am/check.am | 35 +++++++++++--
tests/Makefile.am | 3 +
tests/Makefile.in | 24 +++++++--
tests/parallel-tests-cleanup.test | 91 +++++++++++++++++++++++++++++++++
tests/parallel-tests-gnumakefile.test | 49 ++++++++++++++++++
tests/parallel-tests-linewrap.test | 63 +++++++++++++++++++++++
10 files changed, 301 insertions(+), 18 deletions(-)
create mode 100755 tests/parallel-tests-cleanup.test
create mode 100755 tests/parallel-tests-gnumakefile.test
create mode 100755 tests/parallel-tests-linewrap.test
diff --git a/ChangeLog b/ChangeLog
index 31ff009..4a0e7e1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2011-01-20 Stefano Lattarini <address@hidden>
+ Ralf Wildenhues <address@hidden>
+
+ parallel-tests: avoid command-line length limit issue.
+ * automake.in (handle_tests): New argument $makefile, new
+ substitution %MAKEFILE%.
+ (generate_makefile): Adjust.
+ * lib/am/check.am [%?PARALLEL_TESTS%] (check-TESTS): Use a
+ temporary makefile to sanitize TEST_LOGS value passed to the
+ recursive $(MAKE) invocation, to avoid exceeding the command
+ line limit on w32 (MSYS). Extend comments.
+ * tests/parallel-tests-linewrap.test: New test.
+ * tests/parallel-tests-cleanup.test: Likewise.
+ * tests/parallel-tests-gnumakefile.test: Likewise.
+ * tests/parallel-tests-long-cmdline.test: Likewise.
+ * tests/Makefile.am (TESTS): Updated.
+ * NEWS: Update.
+ Report by Bob Friesenhahn.
+
2011-01-19 Stefano Lattarini <address@hidden>
Ralf Wildenhues <address@hidden>
diff --git a/NEWS b/NEWS
index b5cb6e9..c5f28b5 100644
--- a/NEWS
+++ b/NEWS
@@ -22,6 +22,9 @@ Bugs fixed in 1.11.0a:
- The AM_COND_IF macro also works if the shell expression for the conditional
is no longer valid for the condition.
+ - The `parallel-tests' driver works around a problem with command-line
+ length limits with `make check' on w32 (MSYS).
+
* Long standing bugs:
- On Darwin 9, `pythondir' and `pyexecdir' pointed below `/Library/Python'
diff --git a/automake.in b/automake.in
index d56fbf7..bd9f453 100755
--- a/automake.in
+++ b/automake.in
@@ -4919,9 +4919,13 @@ sub handle_tests_dejagnu
}
+# handle_tests ($MAKEFILE)
+# ------------------------
# Handle TESTS variable and other checks.
-sub handle_tests
+sub handle_tests ($)
{
+ my ($makefile) = @_;
+
if (option 'dejagnu')
{
&handle_tests_dejagnu;
@@ -4940,7 +4944,8 @@ sub handle_tests
push (@check_tests, 'check-TESTS');
$output_rules .= &file_contents ('check', new Automake::Location,
COLOR => !! option 'color-tests',
- PARALLEL_TESTS => !! option
'parallel-tests');
+ PARALLEL_TESTS => !! option
'parallel-tests',
+ MAKEFILE => basename $makefile);
# Tests that are known programs should have $(EXEEXT) appended.
# For matching purposes, we need to adjust XFAIL_TESTS as well.
@@ -8220,7 +8225,7 @@ sub generate_makefile ($$)
handle_tags;
handle_minor_options;
# Must come after handle_programs so that %known_programs is up-to-date.
- handle_tests;
+ handle_tests ($makefile);
# This must come after most other rules.
handle_dist;
diff --git a/lib/Automake/tests/Makefile.in b/lib/Automake/tests/Makefile.in
index b4940db..d3846aa 100644
--- a/lib/Automake/tests/Makefile.in
+++ b/lib/Automake/tests/Makefile.in
@@ -403,11 +403,22 @@ $(TEST_SUITE_LOG): $(TEST_LOGS)
check-TESTS:
@list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
- @list='$(TEST_LOGS)'; \
- list=`for f in $$list; do \
- test .log = $$f || echo $$f; \
- done | tr '\012\015' ' '`; \
- $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$list"
+ @am__tmpdir=am-tmp$$$$; \
+ am__mkfile=$$am__tmpdir/Makefile; \
+ am__trap='rm -rf $$am__tmpdir; (exit $$st); exit $$st'; \
+ trap "st=129; $$am__trap" 1; trap "st=130; $$am__trap" 2; \
+ trap "st=141; $$am__trap" 13; trap "st=143; $$am__trap" 15; \
+ st=0; \
+ mkdir $$am__tmpdir \
+ && { echo "TEST_LOGS = \\"; \
+ list='$(TEST_LOGS)'; for f in $$list; do \
+ test .log = $$f || echo "$$f \\"; \
+ done; \
+ } | sed '$$s/ *\\$$//' > $$am__mkfile \
+ && sed '/^TEST_LOGS =/d' Makefile >> $$am__mkfile \
+ && $(MAKE) -f $$am__mkfile $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ || st=$$?; \
+ rm -rf $$am__tmpdir; exit $$st
.log.html:
@list='$(RST2HTML) $$RST2HTML rst2html rst2html.py'; \
diff --git a/lib/am/check.am b/lib/am/check.am
index 5728081..837f1b4 100644
--- a/lib/am/check.am
+++ b/lib/am/check.am
@@ -236,11 +236,36 @@ check-TESTS:
## cannot use `$?' to compute the set of lazily rerun tests, lest
## we rely on .PHONY to work portably.
@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
- @list='$(TEST_LOGS)'; \
- list=`for f in $$list; do \
- test .log = $$f || echo $$f; \
- done | tr '\012\015' ' '`; \
- $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$list"
+## We'll need a temporary file (see comments below for why), and the safer
+## way to create it portably is to use a temporary directory (as the mkdir
+## utility should be truly atomic everywhere).
+ @am__tmpdir=am-tmp$$$$; \
+ am__mkfile=$$am__tmpdir/Makefile; \
+ am__trap='rm -rf $$am__tmpdir; (exit $$st); exit $$st'; \
+ trap "st=129; $$am__trap" 1; trap "st=130; $$am__trap" 2; \
+ trap "st=141; $$am__trap" 13; trap "st=143; $$am__trap" 15; \
+ st=0; \
+ mkdir $$am__tmpdir \
+## Yes, this is hacky, but we cannot simply override the $(TEST_LOGS)
+## definition by appending to Makefile, since at that point it's original
+## value has been already used in a dependency declaration, i.e.
+## $(TEST_SUITE_LOG): $(TEST_LOGS)
+## (see above in this same *.am fragment).
+ && { echo "TEST_LOGS = \\"; \
+ list='$(TEST_LOGS)'; for f in $$list; do \
+## A bug in GNU make 3.80 can lead to bare `.log' occurrences.
+## Strip them out.
+ test .log = $$f || echo "$$f \\"; \
+ done; \
+ } | sed '$$s/ *\\$$//' > $$am__mkfile \
+ && sed '/^TEST_LOGS =/d' %MAKEFILE% >> $$am__mkfile \
+## It would have been nice to be able to use something like:
+## $(POST_PROCESSING_COMMAND) Makefile.in | $(MAKE) -f -
+## instead of a temporary file here, but unfortunately that doesn't
+## work with at least Solaris 10 dmake.
+ && $(MAKE) -f $$am__mkfile $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ || st=$$?; \
+ rm -rf $$am__tmpdir; exit $$st
AM_RECURSIVE_TARGETS += check
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 713dd92..f263764 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -567,6 +567,9 @@ parallel-tests7.test \
parallel-tests8.test \
parallel-tests9.test \
parallel-tests10.test \
+parallel-tests-cleanup.test \
+parallel-tests-gnumakefile.test \
+parallel-tests-linewrap.test \
parallel-tests-unreadable-log.test \
parse.test \
percent.test \
diff --git a/tests/Makefile.in b/tests/Makefile.in
index 45adb04..7491f05 100644
--- a/tests/Makefile.in
+++ b/tests/Makefile.in
@@ -834,6 +834,9 @@ parallel-tests7.test \
parallel-tests8.test \
parallel-tests9.test \
parallel-tests10.test \
+parallel-tests-cleanup.test \
+parallel-tests-gnumakefile.test \
+parallel-tests-linewrap.test \
parallel-tests-unreadable-log.test \
parse.test \
percent.test \
@@ -1222,11 +1225,22 @@ $(TEST_SUITE_LOG): $(TEST_LOGS)
check-TESTS:
@list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
- @list='$(TEST_LOGS)'; \
- list=`for f in $$list; do \
- test .log = $$f || echo $$f; \
- done | tr '\012\015' ' '`; \
- $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$list"
+ @am__tmpdir=am-tmp$$$$; \
+ am__mkfile=$$am__tmpdir/Makefile; \
+ am__trap='rm -rf $$am__tmpdir; (exit $$st); exit $$st'; \
+ trap "st=129; $$am__trap" 1; trap "st=130; $$am__trap" 2; \
+ trap "st=141; $$am__trap" 13; trap "st=143; $$am__trap" 15; \
+ st=0; \
+ mkdir $$am__tmpdir \
+ && { echo "TEST_LOGS = \\"; \
+ list='$(TEST_LOGS)'; for f in $$list; do \
+ test .log = $$f || echo "$$f \\"; \
+ done; \
+ } | sed '$$s/ *\\$$//' > $$am__mkfile \
+ && sed '/^TEST_LOGS =/d' Makefile >> $$am__mkfile \
+ && $(MAKE) -f $$am__mkfile $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ || st=$$?; \
+ rm -rf $$am__tmpdir; exit $$st
.log.html:
@list='$(RST2HTML) $$RST2HTML rst2html rst2html.py'; \
diff --git a/tests/parallel-tests-cleanup.test
b/tests/parallel-tests-cleanup.test
new file mode 100755
index 0000000..26e9d5c
--- /dev/null
+++ b/tests/parallel-tests-cleanup.test
@@ -0,0 +1,91 @@
+#! /bin/sh
+# Copyright (C) 2011 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 2, 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/>.
+
+# Check that the temporary files/directories used by the Makefile
+# post-processing code in the parallel-tests testsuite driver are
+# duly cleaned up on success, on failure, and when well-known signals
+# are received.
+
+parallel_tests=yes
+. ./defs || Exit 1
+
+set -e
+
+cat >> configure.in << 'END'
+AC_OUTPUT
+END
+
+cat > Makefile.am << 'END'
+TEST_EXTENSIONS = .sh
+TESTS = foo.sh
+SH_LOG_COMPILER = sh
+EXTRA_DIST = foo.sh
+END
+
+check_filelist ()
+{
+ expect_filelist=$1
+ got_filelist=`ls`
+ if test x"$expect_filelist" != x"$got_filelist"; then
+ # Display the differences in a more user-friendly way.
+ # Useful for debugging and failure analysis.
+ set +x # Don't be overly verbose.
+ for f in $expect_filelist; do echo $f; done > exp
+ for f in $got_filelist; do echo $f; done > got
+ set -x
+ diff exp got || :
+ return 1
+ else
+ return 0
+ fi
+}
+
+$ACLOCAL
+$AUTOMAKE -a
+$AUTOCONF
+
+./configure
+
+aborted=`(ls && echo foo.sh ) | sort`
+completed=`(echo "$aborted" && echo test-suite.log && echo foo.log) | sort`
+
+echo 'exit 0' > foo.sh
+$MAKE check
+check_filelist "$completed"
+$MAKE clean
+
+echo 'exit 1' > foo.sh
+$MAKE check && Exit 1
+check_filelist "$completed"
+$MAKE clean
+
+echo 'sleep 10' > foo.sh
+
+# Yes, all the "sleeps" below sucks, but here is better to play "dumb
+# and safer" than having stray I/O or leaving zombies around.
+for signum in 1 2 13 15; do
+ failed=false
+ $MAKE check &
+ kill -$signum $!
+ check_filelist "$aborted" || failed=:
+ sleep 12 # Wait for all the children to complete.
+ $failed && Exit 1
+ $MAKE clean
+done
+
+$MAKE distcheck
+
+:
diff --git a/tests/parallel-tests-gnumakefile.test
b/tests/parallel-tests-gnumakefile.test
new file mode 100755
index 0000000..60d6fd7
--- /dev/null
+++ b/tests/parallel-tests-gnumakefile.test
@@ -0,0 +1,49 @@
+#! /bin/sh
+# Copyright (C) 2011 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 2, 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/>.
+
+# Check that recursive make calls triggered by parallel-tests testsuite
+# driver work also if the makefile is named GNUmakefile.
+
+required=GNUmake
+parallel_tests=yes
+. ./defs || Exit 1
+set -e
+
+cat configure.in - > t << 'END'
+AC_OUTPUT
+END
+sed '/^AC_CONFIG_FILES/s|Makefile|GNUmakefile|' t > configure.in
+rm -f t
+
+cat > GNUmakefile.am <<'END'
+TESTS = foo.test
+END
+
+cat > foo.test <<'END'
+#! /bin/sh
+exit 0
+END
+chmod +x foo.test
+
+$ACLOCAL
+$AUTOCONF
+$AUTOMAKE -a
+
+./configure
+
+$MAKE check
+
+:
diff --git a/tests/parallel-tests-linewrap.test
b/tests/parallel-tests-linewrap.test
new file mode 100755
index 0000000..b3969f0
--- /dev/null
+++ b/tests/parallel-tests-linewrap.test
@@ -0,0 +1,63 @@
+#! /bin/sh
+# Copyright (C) 2011 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 2, 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/>.
+
+# Check that the definition of TEST_LOGS is not broken on multiple lines,
+# even if the list of tests, the list of test extensions, the test names
+# and the test extensions are all very long.
+# We need to be sure of this in order for the Makefile post-processing
+# code in the parallel-tests testsuite driver to work.
+
+parallel_tests=yes
+. ./defs || Exit 1
+
+set -e
+
+# Avoid forks if possible
+i=1
+if (i=$(($i+1)) && test $i -eq 2); then
+ incr_i() { i=$(($i+1)); }
+else
+ incr_i() { i=`expr $i + 1`; }
+fi
+
+cat >> configure.in << 'END'
+AC_OUTPUT
+END
+
+cat > Makefile.am << 'END'
+TEST_EXTENSIONS =
+TESTS =
+END
+
+lc_ext=a_very_very_very_long_test_extension_indeed_it_is_slightly_longer_than_81_characters
+uc_ext=A_VERY_VERY_VERY_LONG_TEST_EXTENSION_INDEED_IT_IS_SLIGHTLY_LONGER_THAN_81_CHARACTERS
+
+while test $i -lt 200; do
+ echo TEST_EXTENSIONS += .${lc_ext}_${i}
+ echo ${uc_ext}_${i}_LOG_COMPILER = sh
+ echo TESTS +=
wow-this-definitely-is-a-very-long-name-for-a-dummy-testcase.${lc_ext}_${i}
+ incr_i
+done >> Makefile.am
+
+$ACLOCAL
+$AUTOMAKE -a
+
+# For debugging.
+$FGREP 'TEST_LOGS' Makefile.in
+
+grep '^TEST_LOGS *=.*\\$' Makefile.in && Exit 1
+
+:
--
1.7.2.3