# HG changeset patch # User Matt Harbison # Date 1426977771 14400 # Node ID 88e61e45026dcecc8b5e69235ea792ee7a65f2e0 # Parent 524dbc8ffeac21bd40d6505c93c3f6bc9926a108 tests: import killdaemons.py from Mercurial 1cfded2fa1a9 This contains updated functionality to kill the server process on Windows, which is needed to run the test-*server.t tests. This version requires the pids to be passed as an argument instead of via $DAEMON_PIDS. diff --git a/tests/killdaemons.py b/tests/killdaemons.py --- a/tests/killdaemons.py +++ b/tests/killdaemons.py @@ -1,25 +1,91 @@ #!/usr/bin/env python -import os, time, errno, signal +import os, sys, time, errno, signal + +if os.name =='nt': + import ctypes + + def _check(ret, expectederr=None): + if ret == 0: + winerrno = ctypes.GetLastError() + if winerrno == expectederr: + return True + raise ctypes.WinError(winerrno) -# Kill off any leftover daemon processes -try: - fp = open(os.environ['DAEMON_PIDS']) - for line in fp: + def kill(pid, logfn, tryhard=True): + logfn('# Killing daemon process %d' % pid) + PROCESS_TERMINATE = 1 + PROCESS_QUERY_INFORMATION = 0x400 + SYNCHRONIZE = 0x00100000 + WAIT_OBJECT_0 = 0 + WAIT_TIMEOUT = 258 + handle = ctypes.windll.kernel32.OpenProcess( + PROCESS_TERMINATE|SYNCHRONIZE|PROCESS_QUERY_INFORMATION, + False, pid) + if handle == 0: + _check(0, 87) # err 87 when process not found + return # process not found, already finished try: - pid = int(line) - except ValueError: - continue + r = ctypes.windll.kernel32.WaitForSingleObject(handle, 100) + if r == WAIT_OBJECT_0: + pass # terminated, but process handle still available + elif r == WAIT_TIMEOUT: + _check(ctypes.windll.kernel32.TerminateProcess(handle, -1)) + else: + _check(r) + + # TODO?: forcefully kill when timeout + # and ?shorter waiting time? when tryhard==True + r = ctypes.windll.kernel32.WaitForSingleObject(handle, 100) + # timeout = 100 ms + if r == WAIT_OBJECT_0: + pass # process is terminated + elif r == WAIT_TIMEOUT: + logfn('# Daemon process %d is stuck') + else: + _check(r) # any error + except: #re-raises + ctypes.windll.kernel32.CloseHandle(handle) # no _check, keep error + raise + _check(ctypes.windll.kernel32.CloseHandle(handle)) + +else: + def kill(pid, logfn, tryhard=True): try: os.kill(pid, 0) + logfn('# Killing daemon process %d' % pid) os.kill(pid, signal.SIGTERM) - for i in range(10): - time.sleep(0.05) + if tryhard: + for i in range(10): + time.sleep(0.05) + os.kill(pid, 0) + else: + time.sleep(0.1) os.kill(pid, 0) + logfn('# Daemon process %d is stuck - really killing it' % pid) os.kill(pid, signal.SIGKILL) except OSError, err: if err.errno != errno.ESRCH: raise - fp.close() -except IOError: - pass + +def killdaemons(pidfile, tryhard=True, remove=False, logfn=None): + if not logfn: + logfn = lambda s: s + # Kill off any leftover daemon processes + try: + fp = open(pidfile) + for line in fp: + try: + pid = int(line) + except ValueError: + continue + kill(pid, logfn, tryhard) + fp.close() + if remove: + os.unlink(pidfile) + except IOError: + pass + +if __name__ == '__main__': + path, = sys.argv[1:] + killdaemons(path) diff --git a/tests/test-simple4server-bundle2.t b/tests/test-simple4server-bundle2.t --- a/tests/test-simple4server-bundle2.t +++ b/tests/test-simple4server-bundle2.t @@ -140,7 +140,7 @@ $ echo '[__temporary__]' >> server/.hg/hgrc $ echo 'advertiseobsolete=False' >> server/.hg/hgrc - $ $TESTDIR/killdaemons.py + $ $TESTDIR/killdaemons.py $DAEMON_PIDS $ hg serve -R server -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log $ cat hg.pid >> $DAEMON_PIDS @@ -154,7 +154,7 @@ lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2-exp=HG2Y%0Ab2x%253Achangegroup%3D01%2C02%0Ab2x%253Alistkeys%0Ab2x%253Aobsmarkers%3DV0%2CV1%0Ab2x%253Apushkey%0Ab2x%253Aremote-changegroup%3Dhttp%2Chttps%0Adigests%3Dmd5%2Csha1%2Csha512 unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 (no-eol) $ echo 'advertiseobsolete=True' >> server/.hg/hgrc - $ $TESTDIR/killdaemons.py + $ $TESTDIR/killdaemons.py $DAEMON_PIDS $ hg serve -R server -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log $ cat hg.pid >> $DAEMON_PIDS diff --git a/tests/test-simple4server.t b/tests/test-simple4server.t --- a/tests/test-simple4server.t +++ b/tests/test-simple4server.t @@ -141,7 +141,7 @@ $ echo '[__temporary__]' >> server/.hg/hgrc $ echo 'advertiseobsolete=False' >> server/.hg/hgrc - $ $TESTDIR/killdaemons.py + $ $TESTDIR/killdaemons.py $DAEMON_PIDS $ hg serve -R server -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log $ cat hg.pid >> $DAEMON_PIDS @@ -155,7 +155,7 @@ lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 (no-eol) $ echo 'advertiseobsolete=True' >> server/.hg/hgrc - $ $TESTDIR/killdaemons.py + $ $TESTDIR/killdaemons.py $DAEMON_PIDS $ hg serve -R server -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log $ cat hg.pid >> $DAEMON_PIDS