push: propagate remote and refspec with --recurse-submodules
[gitweb.git] / t / lib-git-p4.sh
index 7061dce7e5de2f67e60fe6c42c40519f29cad4a1..54fd5a6ca02757f77004d0f8babfcc6d616162c0 100644 (file)
@@ -6,9 +6,18 @@
 # 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
+if ! test_have_prereq PYTHON
+then
        skip_all='skipping git p4 tests; python not available'
        test_done
 fi
@@ -17,6 +26,33 @@ fi
        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-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()))')
+}
+
 # Try to pick a unique port: guess a large number, then hope
 # no more than one of each test is running.
 #
@@ -28,20 +64,40 @@ P4DPORT=$((10669 + ($testid - $git_p4_test_start)))
 
 P4PORT=localhost:$P4DPORT
 P4CLIENT=client
-P4EDITOR=:
-export P4PORT P4CLIENT P4EDITOR
+P4USER=author
+P4EDITOR=true
+unset P4CHARSET
+export P4PORT P4CLIENT P4USER P4EDITOR P4CHARSET
 
 db="$TRASH_DIRECTORY/db"
-cli=$(test-path-utils real_path "$TRASH_DIRECTORY/cli")
+cli="$TRASH_DIRECTORY/cli"
 git="$TRASH_DIRECTORY/git"
 pidfile="$TRASH_DIRECTORY/p4d.pid"
 
-start_p4d() {
+# Sometimes "prove" seems to hang on exit because p4d is still running
+cleanup () {
+       if test -f "$pidfile"
+       then
+               kill -9 $(cat "$pidfile") 2>/dev/null && exit 255
+       fi
+}
+trap cleanup EXIT
+
+# 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
+
+start_p4d () {
        mkdir -p "$db" "$cli" "$git" &&
        rm -f "$pidfile" &&
        (
-               p4d -q -r "$db" -p $P4DPORT &
-               echo $! >"$pidfile"
+               cd "$db" &&
+               {
+                       p4d -q -p $P4DPORT "$@" &
+                       echo $! >"$pidfile"
+               }
        ) &&
 
        # This gives p4d a long time to start up, as it can be
@@ -51,6 +107,19 @@ start_p4d() {
        # will be caught with the "kill -0" check below.
        i=${P4D_START_PATIENCE:-300}
        pid=$(cat "$pidfile")
+
+       timeout=$(($(time_in_seconds) + $P4D_TIMEOUT))
+       while true
+       do
+               if test $(time_in_seconds) -gt $timeout
+               then
+                       kill -9 $pid
+                       exit 1
+               fi
+               sleep 1
+       done &
+       watchdog_pid=$!
+
        ready=
        while test $i -gt 0
        do
@@ -73,46 +142,75 @@ start_p4d() {
                return 1
        fi
 
+       # build a p4 user so author@example.com has an entry
+       p4_add_user author
+
        # build a client
-       (
-               cd "$cli" &&
-               p4 client -i <<-EOF
-               Client: client
-               Description: client
-               Root: $cli
-               View: //depot/... //client/...
-               EOF
-       )
+       client_view "//depot/... //client/..." &&
+
        return 0
 }
 
-kill_p4d() {
-       pid=$(cat "$pidfile")
-       # it had better exist for the first kill
-       kill $pid &&
-       for i in 1 2 3 4 5 ; do
-               kill $pid >/dev/null 2>&1 || break
+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
+}
+
+retry_until_fail () {
+       timeout=$(($(time_in_seconds) + $RETRY_TIMEOUT))
+       until ! "$@" 2>/dev/null || test $(time_in_seconds) -gt $timeout
+       do
                sleep 1
-       done &&
+       done
+}
+
+kill_p4d () {
+       pid=$(cat "$pidfile")
+       retry_until_fail kill $pid
+       retry_until_fail kill -9 $pid
        # complain if it would not die
        test_must_fail kill $pid >/dev/null 2>&1 &&
-       rm -rf "$db" "$cli" "$pidfile"
+       rm -rf "$db" "$cli" "$pidfile" &&
+       retry_until_fail kill -9 $watchdog_pid
 }
 
-cleanup_git() {
-       rm -rf "$git" &&
-       mkdir "$git"
+cleanup_git () {
+       retry_until_success rm -r "$git"
+       test_must_fail test -d "$git" &&
+       retry_until_success mkdir "$git"
 }
 
-marshal_dump() {
+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(sys.stdin)
-       print d['$what']
+           d = marshal.load(instream)
+       print(d[b'$what'].decode('utf-8'))
        EOF
        "$PYTHON_PATH" "$TRASH_DIRECTORY/marshal-dump.py"
 }
@@ -120,16 +218,29 @@ marshal_dump() {
 #
 # Construct a client with this list of View lines
 #
-client_view() {
+client_view () {
        (
                cat <<-EOF &&
-               Client: client
-               Description: client
+               Client: $P4CLIENT
+               Description: $P4CLIENT
                Root: $cli
+               AltRoots: $(native_path "$cli")
+               LineEnd: unix
                View:
                EOF
-               for arg ; do
-                       printf "\t$arg\n"
-               done
+               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
+}