
Confusingly, the 'git p4' tests used two cleanup functions: - 'kill_p4d' was run in the last test before 'test_done', and it not only killed 'p4d', but it killed the watchdog process, and cleaned up after 'p4d' as well by removing all directories used by the P4 daemon and client. This cleanup is not necessary right before 'test_done', because the whole trash directory is about to get removed anyway, but it is necessary in 't9801-git-p4-branch.sh', which uses 'kill_p4d' to stop 'p4d' before re-starting it in the middle of the test script. - 'cleanup' was run in the trap on EXIT, and it killed 'p4d', but, it didn't kill the watchdog process, and, contrarily to its name, didn't perform any cleanup whatsoever. Make it clearer what's going on by renaming and simplifying the cleanup functions, so in the end we'll have: - 'stop_p4d_and_watchdog' replaces 'cleanup' as it will try to live up to its name and stop both the 'p4d' and the watchdog processes, and as the sole function registered with 'test_atexit' it will be responsible for no leaving any stray processes behind after 'git p4' tests were finished or interrupted. - 'stop_and_cleanup_p4d' replaces 'kill_p4d' as it will stop 'p4d' (and the watchdog) and remove all directories used by the P4 daemon and cliean, so it can be used mid-script to stop and then re-start 'p4d'. Note that while 'cleanup' sent a single SIGKILL to 'p4d', 'kill_p4d' was quite brutal, as it first sent SIGTERM to the daemon repeatedly, either until its pid disappeared or until a given timeout was up, and then it sent SIGKILL repeatedly, for good measure. This is overkill (pardon the pun): a single SIGKILL should be able to take down any process in a sensible state, and if a process were to somehow end up stuck in the dreaded uninterruptible sleep state then even repeated SIGKILLs won't bring immediate help. So ditch all the repeated SIGTERM/SIGKILL parts, and use a single SIGKILL to stop 'p4d', and make sure that there are no races between asynchron signal delivery and subsequent restart of 'p4d' by waiting for it to die. With this change the 'retry_until_fail' helper has no callers left, remove it. Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
232 lines
4.9 KiB
Bash
232 lines
4.9 KiB
Bash
#
|
|
# Library code for git p4 tests
|
|
#
|
|
|
|
# p4 tests never use the top-level repo; always build/clone into
|
|
# a subdirectory called "$git"
|
|
TEST_NO_CREATE_REPO=NoThanks
|
|
|
|
# Some operations require multiple attempts to be successful. Define
|
|
# here the maximal retry timeout in seconds.
|
|
RETRY_TIMEOUT=60
|
|
|
|
# Sometimes p4d seems to hang. Terminate the p4d process automatically after
|
|
# the defined timeout in seconds.
|
|
P4D_TIMEOUT=300
|
|
|
|
. ./test-lib.sh
|
|
|
|
if ! test_have_prereq PYTHON
|
|
then
|
|
skip_all='skipping git p4 tests; python not available'
|
|
test_done
|
|
fi
|
|
( p4 -h && p4d -h ) >/dev/null 2>&1 || {
|
|
skip_all='skipping git p4 tests; no p4 or p4d'
|
|
test_done
|
|
}
|
|
|
|
# On cygwin, the NT version of Perforce can be used. When giving
|
|
# it paths, either on the command-line or in client specifications,
|
|
# be sure to use the native windows form.
|
|
#
|
|
# Older versions of perforce were available compiled natively for
|
|
# cygwin. Those do not accept native windows paths, so make sure
|
|
# not to convert for them.
|
|
native_path () {
|
|
path="$1" &&
|
|
if test_have_prereq CYGWIN && ! p4 -V | grep -q CYGWIN
|
|
then
|
|
path=$(cygpath --windows "$path")
|
|
else
|
|
path=$(test-tool path-utils real_path "$path")
|
|
fi &&
|
|
echo "$path"
|
|
}
|
|
|
|
# On Solaris the 'date +%s' function is not supported and therefore we
|
|
# need this replacement.
|
|
# Attention: This function is not safe again against time offset updates
|
|
# at runtime (e.g. via NTP). The 'clock_gettime(CLOCK_MONOTONIC)'
|
|
# function could fix that but it is not in Python until 3.3.
|
|
time_in_seconds () {
|
|
(cd / && "$PYTHON_PATH" -c 'import time; print(int(time.time()))')
|
|
}
|
|
|
|
test_set_port P4DPORT
|
|
|
|
P4PORT=localhost:$P4DPORT
|
|
P4CLIENT=client
|
|
P4USER=author
|
|
P4EDITOR=true
|
|
unset P4CHARSET
|
|
export P4PORT P4CLIENT P4USER P4EDITOR P4CHARSET
|
|
|
|
db="$TRASH_DIRECTORY/db"
|
|
cli="$TRASH_DIRECTORY/cli"
|
|
git="$TRASH_DIRECTORY/git"
|
|
pidfile="$TRASH_DIRECTORY/p4d.pid"
|
|
|
|
stop_p4d_and_watchdog () {
|
|
kill -9 $p4d_pid $watchdog_pid
|
|
}
|
|
|
|
# git p4 submit generates a temp file, which will
|
|
# not get cleaned up if the submission fails. Don't
|
|
# clutter up /tmp on the test machine.
|
|
TMPDIR="$TRASH_DIRECTORY"
|
|
export TMPDIR
|
|
|
|
registered_stop_p4d_atexit_handler=
|
|
start_p4d () {
|
|
# One of the test scripts stops and then re-starts p4d.
|
|
# Don't register and then run the same atexit handlers several times.
|
|
if test -z "$registered_stop_p4d_atexit_handler"
|
|
then
|
|
test_atexit 'stop_p4d_and_watchdog'
|
|
registered_stop_p4d_atexit_handler=AlreadyDone
|
|
fi
|
|
|
|
mkdir -p "$db" "$cli" "$git" &&
|
|
rm -f "$pidfile" &&
|
|
(
|
|
cd "$db" &&
|
|
{
|
|
p4d -q -p $P4DPORT "$@" &
|
|
echo $! >"$pidfile"
|
|
}
|
|
) &&
|
|
p4d_pid=$(cat "$pidfile")
|
|
|
|
# This gives p4d a long time to start up, as it can be
|
|
# quite slow depending on the machine. Set this environment
|
|
# variable to something smaller to fail faster in, say,
|
|
# an automated test setup. If the p4d process dies, that
|
|
# will be caught with the "kill -0" check below.
|
|
i=${P4D_START_PATIENCE:-300}
|
|
|
|
timeout=$(($(time_in_seconds) + $P4D_TIMEOUT))
|
|
while true
|
|
do
|
|
if test $(time_in_seconds) -gt $timeout
|
|
then
|
|
kill -9 $p4d_pid
|
|
exit 1
|
|
fi
|
|
sleep 1
|
|
done &
|
|
watchdog_pid=$!
|
|
|
|
ready=
|
|
while test $i -gt 0
|
|
do
|
|
# succeed when p4 client commands start to work
|
|
if p4 info >/dev/null 2>&1
|
|
then
|
|
ready=true
|
|
break
|
|
fi
|
|
# fail if p4d died
|
|
kill -0 $p4d_pid 2>/dev/null || break
|
|
echo waiting for p4d to start
|
|
sleep 1
|
|
i=$(( $i - 1 ))
|
|
done
|
|
|
|
if test -z "$ready"
|
|
then
|
|
# p4d failed to start
|
|
return 1
|
|
fi
|
|
|
|
# build a p4 user so author@example.com has an entry
|
|
p4_add_user author
|
|
|
|
# build a client
|
|
client_view "//depot/... //client/..." &&
|
|
|
|
return 0
|
|
}
|
|
|
|
p4_add_user () {
|
|
name=$1 &&
|
|
p4 user -f -i <<-EOF
|
|
User: $name
|
|
Email: $name@example.com
|
|
FullName: Dr. $name
|
|
EOF
|
|
}
|
|
|
|
p4_add_job () {
|
|
p4 job -f -i <<-EOF
|
|
Job: $1
|
|
Status: open
|
|
User: dummy
|
|
Description:
|
|
EOF
|
|
}
|
|
|
|
retry_until_success () {
|
|
timeout=$(($(time_in_seconds) + $RETRY_TIMEOUT))
|
|
until "$@" 2>/dev/null || test $(time_in_seconds) -gt $timeout
|
|
do
|
|
sleep 1
|
|
done
|
|
}
|
|
|
|
stop_and_cleanup_p4d () {
|
|
kill -9 $p4d_pid $watchdog_pid
|
|
wait $p4d_pid
|
|
rm -rf "$db" "$cli" "$pidfile"
|
|
}
|
|
|
|
cleanup_git () {
|
|
retry_until_success rm -r "$git"
|
|
test_must_fail test -d "$git" &&
|
|
retry_until_success mkdir "$git"
|
|
}
|
|
|
|
marshal_dump () {
|
|
what=$1 &&
|
|
line=${2:-1} &&
|
|
cat >"$TRASH_DIRECTORY/marshal-dump.py" <<-EOF &&
|
|
import marshal
|
|
import sys
|
|
instream = getattr(sys.stdin, 'buffer', sys.stdin)
|
|
for i in range($line):
|
|
d = marshal.load(instream)
|
|
print(d[b'$what'].decode('utf-8'))
|
|
EOF
|
|
"$PYTHON_PATH" "$TRASH_DIRECTORY/marshal-dump.py"
|
|
}
|
|
|
|
#
|
|
# Construct a client with this list of View lines
|
|
#
|
|
client_view () {
|
|
(
|
|
cat <<-EOF &&
|
|
Client: $P4CLIENT
|
|
Description: $P4CLIENT
|
|
Root: $cli
|
|
AltRoots: $(native_path "$cli")
|
|
LineEnd: unix
|
|
View:
|
|
EOF
|
|
printf "\t%s\n" "$@"
|
|
) | p4 client -i
|
|
}
|
|
|
|
is_cli_file_writeable () {
|
|
# cygwin version of p4 does not set read-only attr,
|
|
# will be marked 444 but -w is true
|
|
file="$1" &&
|
|
if test_have_prereq CYGWIN && p4 -V | grep -q CYGWIN
|
|
then
|
|
stat=$(stat --format=%a "$file") &&
|
|
test $stat = 644
|
|
else
|
|
test -w "$file"
|
|
fi
|
|
}
|