Merge branch 'js/valgrind'

* js/valgrind:
  valgrind: do not require valgrind 3.4.0 or newer
  test-lib: avoid assuming that templates/ are in the GIT_EXEC_PATH
  Tests: let --valgrind imply --verbose and --tee
  Add a script to coalesce the valgrind outputs
  t/Makefile: provide a 'valgrind' target
  test-lib.sh: optionally output to test-results/$TEST.out, too
  Valgrind support: check for more than just programming errors
  valgrind: ignore ldso and more libz errors
  Add valgrind support in test scripts
This commit is contained in:
Junio C Hamano 2009-03-05 15:41:18 -08:00
commit 8a61097cde
7 changed files with 301 additions and 5 deletions

View File

@ -38,4 +38,7 @@ full-svn-test:
$(MAKE) $(TSVN) GIT_SVN_NO_OPTIMIZE_COMMITS=1 LC_ALL=C
$(MAKE) $(TSVN) GIT_SVN_NO_OPTIMIZE_COMMITS=0 LC_ALL=en_US.UTF-8
.PHONY: pre-clean $(T) aggregate-results clean
valgrind:
GIT_TEST_OPTS=--valgrind $(MAKE)
.PHONY: pre-clean $(T) aggregate-results clean valgrind

View File

@ -39,7 +39,8 @@ this:
* passed all 3 test(s)
You can pass --verbose (or -v), --debug (or -d), and --immediate
(or -i) command line argument to the test.
(or -i) command line argument to the test, or by setting GIT_TEST_OPTS
appropriately before running "make".
--verbose::
This makes the test more verbose. Specifically, the
@ -58,6 +59,21 @@ You can pass --verbose (or -v), --debug (or -d), and --immediate
This causes additional long-running tests to be run (where
available), for more exhaustive testing.
--valgrind::
Execute all Git binaries with valgrind and exit with status
126 on errors (just like regular tests, this will only stop
the test script when running under -i). Valgrind errors
go to stderr, so you might want to pass the -v option, too.
Since it makes no sense to run the tests with --valgrind and
not see any output, this option implies --verbose. For
convenience, it also implies --tee.
--tee::
In addition to printing the test output to the terminal,
write it to files named 't/test-results/$TEST_NAME.out'.
As the names depend on the tests' file names, it is safe to
run the tests with this option in parallel.
Skipping Tests
--------------

View File

@ -3,6 +3,22 @@
# Copyright (c) 2005 Junio C Hamano
#
# if --tee was passed, write the output not only to the terminal, but
# additionally to the file test-results/$BASENAME.out, too.
case "$GIT_TEST_TEE_STARTED, $* " in
done,*)
# do not redirect again
;;
*' --tee '*|*' --va'*)
mkdir -p test-results
BASE=test-results/$(basename "$0" .sh)
(GIT_TEST_TEE_STARTED=done ${SHELL-sh} "$0" "$@" 2>&1;
echo $? > $BASE.exit) | tee $BASE.out
test "$(cat $BASE.exit)" = 0
exit
;;
esac
# Keep the original TERM for say_color
ORIGINAL_TERM=$TERM
@ -94,6 +110,10 @@ do
--no-python)
# noop now...
shift ;;
--va|--val|--valg|--valgr|--valgri|--valgrin|--valgrind)
valgrind=t; verbose=t; shift ;;
--tee)
shift ;; # was handled already
*)
break ;;
esac
@ -434,7 +454,7 @@ test_create_repo () {
repo="$1"
mkdir -p "$repo"
cd "$repo" || error "Cannot setup test environment"
"$GIT_EXEC_PATH/git" init "--template=$GIT_EXEC_PATH/templates/blt/" >&3 2>&4 ||
"$GIT_EXEC_PATH/git" init "--template=$owd/../templates/blt/" >&3 2>&4 ||
error "cannot run git init -- have you built things yet?"
mv .git/hooks .git/hooks-disabled
cd "$owd"
@ -492,8 +512,73 @@ test_done () {
# Test the binaries we have just built. The tests are kept in
# t/ subdirectory and are run in 'trash directory' subdirectory.
TEST_DIRECTORY=$(pwd)
if test -z "$valgrind"
then
PATH=$TEST_DIRECTORY/..:$PATH
GIT_EXEC_PATH=$(pwd)/..
GIT_EXEC_PATH=$TEST_DIRECTORY/..
else
make_symlink () {
test -h "$2" &&
test "$1" = "$(readlink "$2")" || {
# be super paranoid
if mkdir "$2".lock
then
rm -f "$2" &&
ln -s "$1" "$2" &&
rm -r "$2".lock
else
while test -d "$2".lock
do
say "Waiting for lock on $2."
sleep 1
done
fi
}
}
make_valgrind_symlink () {
# handle only executables
test -x "$1" || return
base=$(basename "$1")
symlink_target=$TEST_DIRECTORY/../$base
# do not override scripts
if test -x "$symlink_target" &&
test ! -d "$symlink_target" &&
test "#!" != "$(head -c 2 < "$symlink_target")"
then
symlink_target=../valgrind.sh
fi
case "$base" in
*.sh|*.perl)
symlink_target=../unprocessed-script
esac
# create the link, or replace it if it is out of date
make_symlink "$symlink_target" "$GIT_VALGRIND/bin/$base" || exit
}
# override all git executables in TEST_DIRECTORY/..
GIT_VALGRIND=$TEST_DIRECTORY/valgrind
mkdir -p "$GIT_VALGRIND"/bin
for file in $TEST_DIRECTORY/../git* $TEST_DIRECTORY/../test-*
do
make_valgrind_symlink $file
done
OLDIFS=$IFS
IFS=:
for path in $PATH
do
ls "$path"/git-* 2> /dev/null |
while read file
do
make_valgrind_symlink "$file"
done
done
IFS=$OLDIFS
PATH=$GIT_VALGRIND/bin:$PATH
GIT_EXEC_PATH=$GIT_VALGRIND/bin
export GIT_VALGRIND
fi
GIT_TEMPLATE_DIR=$(pwd)/../templates/blt
unset GIT_CONFIG
GIT_CONFIG_NOSYSTEM=1

2
t/valgrind/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/bin/
/templates

123
t/valgrind/analyze.sh Executable file
View File

@ -0,0 +1,123 @@
#!/bin/sh
out_prefix=$(dirname "$0")/../test-results/valgrind.out
output=
count=0
total_count=0
missing_message=
new_line='
'
# start outputting the current valgrind error in $out_prefix.++$count,
# and the test case which failed in the corresponding .message file
start_output () {
test -z "$output" || return
# progress
total_count=$(($total_count+1))
test -t 2 && printf "\rFound %d errors" $total_count >&2
count=$(($count+1))
output=$out_prefix.$count
: > $output
echo "*** $1 ***" > $output.message
}
finish_output () {
test ! -z "$output" || return
output=
# if a test case has more than one valgrind error, we need to
# copy the last .message file to the previous errors
test -z "$missing_message" || {
while test $missing_message -lt $count
do
cp $out_prefix.$count.message \
$out_prefix.$missing_message.message
missing_message=$(($missing_message+1))
done
missing_message=
}
}
# group the valgrind errors by backtrace
output_all () {
last_line=
j=0
i=1
while test $i -le $count
do
# output <number> <backtrace-in-one-line>
echo "$i $(tr '\n' ' ' < $out_prefix.$i)"
i=$(($i+1))
done |
sort -t ' ' -k 2 | # order by <backtrace-in-one-line>
while read number line
do
# find duplicates, do not output backtrace twice
if test "$line" != "$last_line"
then
last_line=$line
j=$(($j+1))
printf "\nValgrind error $j:\n\n"
cat $out_prefix.$number
printf "\nfound in:\n"
fi
# print the test case where this came from
printf "\n"
cat $out_prefix.$number.message
done
}
handle_one () {
OLDIFS=$IFS
IFS="$new_line"
while read line
do
case "$line" in
# backtrace, possibly a new one
==[0-9]*)
# Does the current valgrind error have a message yet?
case "$output" in
*.message)
test -z "$missing_message" &&
missing_message=$count
output=
esac
start_output $(basename $1)
echo "$line" |
sed 's/==[0-9]*==/==valgrind==/' >> $output
;;
# end of backtrace
'}')
test -z "$output" || {
echo "$line" >> $output
test $output = ${output%.message} &&
output=$output.message
}
;;
# end of test case
'')
finish_output
;;
# normal line; if $output is set, print the line
*)
test -z "$output" || echo "$line" >> $output
;;
esac
done < $1
IFS=$OLDIFS
# just to be safe
finish_output
}
for test_script in "$(dirname "$0")"/../test-results/*.out
do
handle_one $test_script
done
output_all

45
t/valgrind/default.supp Normal file
View File

@ -0,0 +1,45 @@
{
ignore-zlib-errors-cond
Memcheck:Cond
obj:*libz.so*
}
{
ignore-zlib-errors-value8
Memcheck:Value8
obj:*libz.so*
}
{
ignore-zlib-errors-value4
Memcheck:Value4
obj:*libz.so*
}
{
ignore-ldso-cond
Memcheck:Cond
obj:*ld-*.so
}
{
ignore-ldso-addr8
Memcheck:Addr8
obj:*ld-*.so
}
{
ignore-ldso-addr4
Memcheck:Addr4
obj:*ld-*.so
}
{
writing-data-from-zlib-triggers-even-more-errors
Memcheck:Param
write(buf)
obj:/lib/ld-*.so
fun:write_in_full
fun:write_buffer
fun:write_loose_object
}

22
t/valgrind/valgrind.sh Executable file
View File

@ -0,0 +1,22 @@
#!/bin/sh
base=$(basename "$0")
TRACK_ORIGINS=
VALGRIND_VERSION=$(valgrind --version)
VALGRIND_MAJOR=$(expr "$VALGRIND_VERSION" : '[^0-9]*\([0-9]*\)')
VALGRIND_MINOR=$(expr "$VALGRIND_VERSION" : '[^0-9]*[0-9]*\.\([0-9]*\)')
test 3 -gt "$VALGRIND_MAJOR" ||
test 3 -eq "$VALGRIND_MAJOR" -a 4 -gt "$VALGRIND_MINOR" ||
TRACK_ORIGINS=--track-origins=yes
exec valgrind -q --error-exitcode=126 \
--leak-check=no \
--suppressions="$GIT_VALGRIND/default.supp" \
--gen-suppressions=all \
$TRACK_ORIGINS \
--log-fd=4 \
--input-fd=4 \
$GIT_VALGRIND_OPTIONS \
"$GIT_VALGRIND"/../../"$base" "$@"