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:
commit
8a61097cde
@ -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
|
||||
|
18
t/README
18
t/README
@ -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
|
||||
--------------
|
||||
|
@ -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
2
t/valgrind/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/bin/
|
||||
/templates
|
123
t/valgrind/analyze.sh
Executable file
123
t/valgrind/analyze.sh
Executable 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
45
t/valgrind/default.supp
Normal 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
22
t/valgrind/valgrind.sh
Executable 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" "$@"
|
Loading…
Reference in New Issue
Block a user