FYI, I've just checked in the following for the 108/bdbstore module:
[I plan to do the same for qpidd later this week, but with the difference
 that it won't be turned on by default -- at least not in the beginning.]

        Instrument all tests so that they are run via valgrind (when possible):
        check for both errors and leaks.
        * configure.ac: Check for valgrind.
        * tests/Makefile.am (TESTS_ENVIRONMENT): Export VALGRIND.
        * tests/.vg-supp: New file, exempting known leaks on rawhide and
        Debian/unstable.  Leaks on the latter system all seem to originate
        in cppunit.  Some of the rawhide ones look suspicious.
        * tests/run-unit-tests: Use new "setup" file.
        Invoke DllPlugInTester via $vg (aka valgrind).
        Refer to the source directory using $pwd, since we're now running
        from a temporary subdirectory.
        * tests/system_test.sh: Remove traps. That is now done by "setup".
        [VERBOSE]: Print qpidd --version.
        Invoke qpidd via $vg.
        Add a kludgey "sleep 3", because it can take a while for libtool
        to start valgrind to start qpidd, in the background.
        Ideally, the python script would simply sleep-0.3-and-retry for
        a couple seconds, upon failure of the initial connection attempt.
        * tests/setup: New file.

With these changes, if you introduce a leak and run "make check", any test
that triggers that leak will fail with info from valgrind giving a clue to
where the leaked memory was allocated.  Of course, if the leak is in code
(e.g., a library) you have no control over, then you'll probably want to
ignore it -- but make a note to report/fix it upstream later.  In that
case, add the appropriate "suppression" to the tests/.vg-supp file.
Since this is valgrind, it also detects used-uninitialized errors,
double-free, and the like.  They too cause "make check" to fail.

One drawback with this sort of test is that it is very sensitive to the
environment (things like OS, libraries, C++ compiler version, etc.),
so if you run "make check" on RHEL N, or even straight FC 6, expect to
have to make some additions to the list of suppressions.

Index: configure.ac
===================================================================
--- configure.ac        (revision 678)
+++ configure.ac        (working copy)
@@ -124,6 +124,9 @@
   USE_APR=1
 fi

+# We use valgrind for the tests.  See if it's available.
+AC_CHECK_PROG([VALGRIND], [valgrind], [yes])
+
 AC_CONFIG_FILES([
   Makefile
   tests/Makefile
Index: tests/Makefile.am
===================================================================
--- tests/Makefile.am   (revision 678)
+++ tests/Makefile.am   (working copy)
@@ -28,6 +28,7 @@

 TESTS_ENVIRONMENT =                    \
   QPID_DIR=$(QPID_DIR)                 \
+  VALGRIND=$(VALGRIND)                 \
   abs_builddir='$(abs_builddir)'       \
   abs_srcdir='$(abs_srcdir)'

Index: tests/.vg-supp
===================================================================
--- tests/.vg-supp      (revision 0)
+++ tests/.vg-supp      (revision 0)
@@ -0,0 +1,2553 @@
+{
+   x14262_1
+   Memcheck:Leak
+   fun:_vgrZU_libstdcZpZpZa__Znwm
[2500+ lines of mangled stack signatures (what valgrind calls suppressions)]

Index: tests/run-unit-tests
===================================================================
--- tests/run-unit-tests        (revision 678)
+++ tests/run-unit-tests        (working copy)
@@ -1,8 +1,14 @@
 #!/bin/sh

-set -e
+. $srcdir/setup
+
+fail=0
+
 DB_HOME=dbdata
 mkdir -p $DB_HOME
 export DB_HOME
-strace -o k -ff DllPlugInTester -c -b .libs/*.so
+$vg DllPlugInTester -c -b $pwd/.libs/*.so 2> out || fail=1
 rm -rf $DB_HOME
+
+vg_check out || fail=1
+exit $fail
Index: tests/system_test.sh
===================================================================
--- tests/system_test.sh        (revision 678)
+++ tests/system_test.sh        (working copy)
@@ -17,21 +17,15 @@
 # specific language governing permissions and limitations
 # under the License.

+qpidd=$QPID_DIR/cpp/src/qpidd
+
 if test "$VERBOSE" = yes; then
   set -x
-  qpidd --version
+  $qpidd --version
 fi

-pid=0
-pwd=`pwd`
-t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$
-trap 's=$?;test $pid = 0||kill -SIGINT $pid;cd "$pwd" && rm -rf $t0 && exit 
$s' 0
-trap '(exit $?); exit $?' 1 2 13 15
+. $srcdir/setup

-framework_failure=0
-mkdir -p $tmp || framework_failure=1
-cd $tmp || framework_failure=1
-
 # Make sure $QPID_DIR contains what we need.
 xml_spec=$QPID_DIR/specs/amqp.0-8.xml
 test -f $xml_spec \
@@ -48,14 +42,16 @@

 fail=0

-qpidd=$QPID_DIR/cpp/src/qpidd
-
 for p in `seq 1 4`; do
-    $qpidd -s "$abs_builddir/../lib/.libs/libbdbstore.so" >> qpid.log & pid=$!
+    log=vg-log.$p
+    $vg $qpidd -s "$abs_builddir/../lib/.libs/libbdbstore.so" \
+       >> qpid.log 2> $log & pid=$!
+    sleep 3
     echo phase $p...
     python "$abs_srcdir/persistence.py" -s "$xml_spec" -p $p || fail=1
     kill -SIGINT $pid || { echo process already died; cat qpid.log ; fail=1; }
     wait $pid || fail=1
+    vg_check $log || fail=1
 done
 pid=0

Index: tests/setup
===================================================================
--- tests/setup (revision 0)
+++ tests/setup (revision 0)
@@ -0,0 +1,74 @@
+# -*- sh -*-
+
+test "$VERBOSE" = yes && set -x
+
+pwd=`pwd`
+t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$
+pid=0
+test -z "$TEST_DEBUG" &&
+trap 's=$?;test $pid = 0||kill -SIGINT $pid;cd "$pwd" && rm -rf $t0 && exit 
$s' 0
+test -z "$TEST_DEBUG" && trap '(exit $?); exit $?' 1 2 13 15
+
+framework_failure=0
+mkdir -p $tmp || framework_failure=1
+cd $tmp || framework_failure=1
+
+gen_supp=--gen-suppressions=all
+# This option makes valgrind significantly slower.
+full_leak_check=--leak-check=full
+
+vg_options="
+  --suppressions=$abs_srcdir/.vg-supp
+  --num-callers=25
+  --track-fds=yes
+  --demangle=no
+  $full_leak_check
+  $gen_supp
+  "
+# configure tests for the existence of valgrind.
+# If it's not available, then make $vg and vg_check no-ops.
+if test x$VALGRIND = x; then
+  vg=
+else
+  vg="libtool --mode=execute valgrind `echo $vg_options` --"
+fi
+
+vg_leak_check()
+{
+  local file=$1
+  local fail
+  # If we detect a leak, dump all output to stderr.
+  grep -E '^==[0-9]+== +definitely lost: [^0]' $file \
+      && { fail=1; cat $file 1>&2;
+           echo "found memory leaks (see log file, $file); see above" 1>&2; }
+  test "$fail" = ''
+}
+
+
+# Ensure 1) that there is an ERROR SUMMARY line, and
+# 2) that the number of errors is 0.
+# An offending line looks like this:
+# ==29302== ERROR SUMMARY: 4 errors from 2 contexts (suppressed: 16 from 5)
+vg_error_check()
+{
+  local file=$1
+  local fail
+  # If we detect a leak, dump all output to stderr.
+  grep -E '^==[0-9]+== ERROR SUMMARY:' $file > /dev/null \
+      || { fail=1; cat $file 1>&2;
+           echo "no valgrind ERROR SUMMARY line in $file" 1>&2; }
+  if test "$fail" = ''; then
+    grep -E '^==[0-9]+== ERROR SUMMARY: [^0] ' $file \
+      && { fail=1; cat $file 1>&2;
+          echo "valgrind reported errors in $file; see above" 1>&2; }
+  fi
+  test "$fail" = ''
+}
+
+vg_check()
+{
+  local file=$1
+  if test x$VALGRIND != x; then
+    vg_error_check $file && vg_leak_check $file
+  fi
+}

Reply via email to