1# 2# Library code for git p4 tests 3# 4 5# p4 tests never use the top-level repo; always build/clone into 6# a subdirectory called "$git" 7TEST_NO_CREATE_REPO=NoThanks 8 9# Some operations require multiple attempts to be successful. Define 10# here the maximal retry timeout in seconds. 11RETRY_TIMEOUT=60 12 13# Sometimes p4d seems to hang. Terminate the p4d process automatically after 14# the defined timeout in seconds. 15P4D_TIMEOUT=300 16 17. ./test-lib.sh 18 19if ! test_have_prereq PYTHON 20then 21 skip_all='skipping git p4 tests; python not available' 22 test_done 23fi 24( p4 -h && p4d -h ) >/dev/null 2>&1 || { 25 skip_all='skipping git p4 tests; no p4 or p4d' 26 test_done 27} 28 29# On cygwin, the NT version of Perforce can be used. When giving 30# it paths, either on the command-line or in client specifications, 31# be sure to use the native windows form. 32# 33# Older versions of perforce were available compiled natively for 34# cygwin. Those do not accept native windows paths, so make sure 35# not to convert for them. 36native_path () { 37 path="$1" && 38 if test_have_prereq CYGWIN && ! p4 -V | grep -q CYGWIN 39 then 40 path=$(cygpath --windows "$path") 41 else 42 path=$(test-tool path-utils real_path "$path") 43 fi && 44 echo "$path" 45} 46 47# On Solaris the 'date +%s' function is not supported and therefore we 48# need this replacement. 49# Attention: This function is not safe again against time offset updates 50# at runtime (e.g. via NTP). The 'clock_gettime(CLOCK_MONOTONIC)' 51# function could fix that but it is not in Python until 3.3. 52time_in_seconds () { 53 (cd / && "$PYTHON_PATH" -c 'import time; print(int(time.time()))') 54} 55 56test_set_port P4DPORT 57 58P4PORT=localhost:$P4DPORT 59P4CLIENT=client 60P4USER=author 61P4EDITOR=true 62unset P4CHARSET 63export P4PORT P4CLIENT P4USER P4EDITOR P4CHARSET 64 65db="$TRASH_DIRECTORY/db" 66cli="$TRASH_DIRECTORY/cli" 67git="$TRASH_DIRECTORY/git" 68pidfile="$TRASH_DIRECTORY/p4d.pid" 69 70# Sometimes "prove" seems to hang on exit because p4d is still running 71cleanup () { 72 if test -f "$pidfile" 73 then 74 kill -9 $(cat "$pidfile") 2>/dev/null && exit 255 75 fi 76} 77 78# git p4 submit generates a temp file, which will 79# not get cleaned up if the submission fails. Don't 80# clutter up /tmp on the test machine. 81TMPDIR="$TRASH_DIRECTORY" 82export TMPDIR 83 84registered_stop_p4d_atexit_handler= 85start_p4d () { 86 # One of the test scripts stops and then re-starts p4d. 87 # Don't register and then run the same atexit handlers several times. 88 if test -z "$registered_stop_p4d_atexit_handler" 89 then 90 test_atexit 'kill_p4d; cleanup' 91 registered_stop_p4d_atexit_handler=AlreadyDone 92 fi 93 94 mkdir -p "$db" "$cli" "$git" && 95 rm -f "$pidfile" && 96 ( 97 cd "$db" && 98 { 99 p4d -q -p $P4DPORT "$@" & 100 echo $! >"$pidfile" 101 } 102 ) && 103 104 # This gives p4d a long time to start up, as it can be 105 # quite slow depending on the machine. Set this environment 106 # variable to something smaller to fail faster in, say, 107 # an automated test setup. If the p4d process dies, that 108 # will be caught with the "kill -0" check below. 109 i=${P4D_START_PATIENCE:-300} 110 pid=$(cat "$pidfile") 111 112 timeout=$(($(time_in_seconds) + $P4D_TIMEOUT)) 113 while true 114 do 115 if test $(time_in_seconds) -gt $timeout 116 then 117 kill -9 $pid 118 exit 1 119 fi 120 sleep 1 121 done & 122 watchdog_pid=$! 123 124 ready= 125 while test $i -gt 0 126 do 127 # succeed when p4 client commands start to work 128 if p4 info >/dev/null 2>&1 129 then 130 ready=true 131 break 132 fi 133 # fail if p4d died 134 kill -0 $pid 2>/dev/null || break 135 echo waiting for p4d to start 136 sleep 1 137 i=$(( $i - 1 )) 138 done 139 140 if test -z "$ready" 141 then 142 # p4d failed to start 143 return 1 144 fi 145 146 # build a p4 user so author@example.com has an entry 147 p4_add_user author 148 149 # build a client 150 client_view "//depot/... //client/..." && 151 152 return 0 153} 154 155p4_add_user () { 156 name=$1 && 157 p4 user -f -i <<-EOF 158 User: $name 159 Email: $name@example.com 160 FullName: Dr. $name 161 EOF 162} 163 164p4_add_job () { 165 p4 job -f -i <<-EOF 166 Job: $1 167 Status: open 168 User: dummy 169 Description: 170 EOF 171} 172 173retry_until_success () { 174 timeout=$(($(time_in_seconds) + $RETRY_TIMEOUT)) 175 until "$@" 2>/dev/null || test $(time_in_seconds) -gt $timeout 176 do 177 sleep 1 178 done 179} 180 181retry_until_fail () { 182 timeout=$(($(time_in_seconds) + $RETRY_TIMEOUT)) 183 until ! "$@" 2>/dev/null || test $(time_in_seconds) -gt $timeout 184 do 185 sleep 1 186 done 187} 188 189kill_p4d () { 190 pid=$(cat "$pidfile") 191 retry_until_fail kill $pid 192 retry_until_fail kill -9 $pid 193 # complain if it would not die 194 test_must_fail kill $pid >/dev/null 2>&1 && 195 rm -rf "$db" "$cli" "$pidfile" && 196 retry_until_fail kill -9 $watchdog_pid 197} 198 199cleanup_git () { 200 retry_until_success rm -r "$git" 201 test_must_fail test -d "$git" && 202 retry_until_success mkdir "$git" 203} 204 205marshal_dump () { 206 what=$1 && 207 line=${2:-1} && 208 cat >"$TRASH_DIRECTORY/marshal-dump.py" <<-EOF && 209 import marshal 210 import sys 211 instream = getattr(sys.stdin, 'buffer', sys.stdin) 212 for i in range($line): 213 d = marshal.load(instream) 214 print(d[b'$what'].decode('utf-8')) 215 EOF 216 "$PYTHON_PATH" "$TRASH_DIRECTORY/marshal-dump.py" 217} 218 219# 220# Construct a client with this list of View lines 221# 222client_view () { 223 ( 224 cat <<-EOF && 225 Client: $P4CLIENT 226 Description: $P4CLIENT 227 Root: $cli 228 AltRoots: $(native_path "$cli") 229 LineEnd: unix 230 View: 231 EOF 232 printf "\t%s\n" "$@" 233 ) | p4 client -i 234} 235 236is_cli_file_writeable () { 237 # cygwin version of p4 does not set read-only attr, 238 # will be marked 444 but -w is true 239 file="$1" && 240 if test_have_prereq CYGWIN && p4 -V | grep -q CYGWIN 241 then 242 stat=$(stat --format=%a "$file") && 243 test $stat = 644 244 else 245 test -w "$file" 246 fi 247}