]> git.ipfire.org Git - thirdparty/automake.git/commitdiff
coverage: possible infinite recursion in the test harness
authorStefano Lattarini <stefano.lattarini@gmail.com>
Wed, 10 Aug 2011 14:03:35 +0000 (16:03 +0200)
committerStefano Lattarini <stefano.lattarini@gmail.com>
Thu, 11 Aug 2011 09:22:03 +0000 (11:22 +0200)
Motivated by a regression in the 'test-protocols' branch.

* tests/parallel-tests-fork-bomb.test: New test, checking that
if $(TEST_SUITE_LOG) is in $(TEST_LOGS), we obtain a diagnosed
error rather than a make hang or a fork bomb.
* tests/Makefile.am (TESTS): Update.

ChangeLog
tests/Makefile.am
tests/Makefile.in
tests/parallel-tests-fork-bomb.test [new file with mode: 0755]

index e08b7c96d3674ff4dfee0fe7a3d42b3cb91d943b..2d7e5d6ea1b9244e26cbde1c59e243f3e5760f6a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2011-08-09  Stefano Lattarini  <stefano.lattarini@gmail.com>
+
+       coverage: possible infinite recursion in the test harness
+       Motivated by a regression in the 'test-protocols' branch.
+       * tests/parallel-tests-fork-bomb.test: New test, checking that
+       if $(TEST_SUITE_LOG) is in $(TEST_LOGS), we obtain a diagnosed
+       error rather than a make hang or a fork bomb.
+       * tests/Makefile.am (TESTS): Update.
+
 2011-08-09  Stefano Lattarini  <stefano.lattarini@gmail.com>
 
        test defs: yet more environment cleanup
index 82fb906063125acd1ce512b777d3c62b6b6ae548..833dc7a26a7bf134582284c5446fc7986050fa05 100644 (file)
@@ -733,6 +733,7 @@ parallel-tests-log-override-2.test \
 parallel-tests-log-override-recheck.test \
 parallel-tests-cmdline-override.test \
 parallel-tests-log-compiler-example.test \
+parallel-tests-fork-bomb.test \
 parse.test \
 percent.test \
 percent2.test \
index d6d418ced13cfde8deb1d4f599b29ba7608ac356..ede80e6eba241929bc793a37a39cc46977a163a0 100644 (file)
@@ -1006,6 +1006,7 @@ parallel-tests-log-override-2.test \
 parallel-tests-log-override-recheck.test \
 parallel-tests-cmdline-override.test \
 parallel-tests-log-compiler-example.test \
+parallel-tests-fork-bomb.test \
 parse.test \
 percent.test \
 percent2.test \
diff --git a/tests/parallel-tests-fork-bomb.test b/tests/parallel-tests-fork-bomb.test
new file mode 100755 (executable)
index 0000000..6a385d6
--- /dev/null
@@ -0,0 +1,142 @@
+#! /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 parallel-tests features:
+#  - If $(TEST_SUITE_LOG) is in $(TEST_LOGS), we get a diagnosed
+#    error, not a make hang or a system freeze.
+
+parallel_tests=yes
+. ./defs || Exit 1
+
+# The tricky part of this test is to avoid that make hangs or even
+# freezes the system in case infinite recursion (which is the bug we
+# are testing against) is encountered.  The following hacky makefile
+# should minimize the probability of that happening.
+cat > Makefile.am << 'END'
+TEST_LOG_COMPILER = true
+TESTS =
+
+errmsg = ::OOPS:: Recursion too deep
+
+if IS_GNU_MAKE
+
+ is_too_deep := $(shell test $(MAKELEVEL) -lt 10 && echo no)
+
+## Indenteation here required to avoid confusing Automake.
+ ifeq ($(is_too_deep),no)
+ else
+ $(error $(errmsg), $(MAKELEVEL) levels)
+ endif
+
+else !IS_GNU_MAKE
+
+# We use mkdir to detect the level of recursion, since it is easy
+# to use and assured to be portably atomical.  Also use an higher
+# number than with GNU make above, since the level used here can
+# be incremented by tow or more per recursion.
+recursion-not-too-deep:
+       @ok=no; \
+       for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 \
+                18 19 20 21 22 23 24 25 26 27 28 29; \
+       do \
+         echo " mkdir rec-$$i.d"; \
+         if mkdir rec-$$i.d; then \
+           ok=yes; break; \
+         else :; fi; \
+       done; \
+       test $$ok = yes || { echo '$(errmsg)' >&2; exit 1; }
+.PHONY: recursion-not-too-deep
+clean-local:
+       rmdir rec-[0-9].d
+
+targets = all check recheck $(TESTS) $(TEST_LOGS) $(TEST_SUITE_LOG)
+$(targets): recursion-not-too-deep
+
+# For BSD make.
+.BEGIN: recursion-not-too-deep
+
+endif !IS_GNU_MAKE
+END
+
+if using_gmake; then
+  cond=:
+else
+  cond=false
+fi
+
+cat >> configure.in << END
+AM_CONDITIONAL([IS_GNU_MAKE], [$cond])
+AC_OUTPUT
+END
+
+# Another helpful idiom to avoid hanging on capable systems.  The subshell
+# is needed since `ulimit' might be a special shell builtin.
+if (ulimit -t 8); then ulimit -t 8; fi
+
+$ACLOCAL
+$AUTOCONF
+$AUTOMAKE -a -Wno-portability
+
+./configure
+
+do_check ()
+{
+  st=0
+  log=$1; shift
+  env "$@" $MAKE -e check >output 2>&1 || st=$?
+  cat output
+  $FGREP '::OOPS::' output && Exit 1 # Possible infinite recursion.
+  # Check that at least we don't create a botched global log file.
+# FIXME: GNU make currently creates it!
+#  test ! -f "$log"
+    # Look for possible error messages about circular dependencies from
+    # either make or our own recipes.  At least one such a message must
+    # be present.
+    err_seen=no
+    for err_rx in \
+      'circular.* depend' \
+      'depend.* circular' \
+      'graph cycle' \
+      'infinite (loop|recursion)' \
+      'depend.* on itself' \
+    ; do
+      $EGREP -i "$err_rx" output | $FGREP "$log" || continue
+      err_seen=yes
+      break
+    done
+    test $err_seen = yes || Exit 1
+    # Some make implementations (e.g., NetBSD's), while smartly detecting
+    # the circular dependency early and diagnosing it, still exit with a
+    # successful exit status (yikes!).  Relax our checks not to fail in
+    # this case.
+    using_gmake && { test $st -gt 0 || Exit 1; }
+    :
+}
+
+: > test-suite.test
+do_check test-suite.log TESTS=test-suite.test
+rm -f *.log *.test
+
+: > 0.test
+: > 1.test
+: > 2.test
+: > 3.test
+: > foobar.test
+do_check foobar.log TEST_LOGS='0.log 1.log foobar.log 2.log 3.log' \
+                    TEST_SUITE_LOG=foobar.log
+rm -f *.log *.test
+
+: