tests/killdaemons.py
author Augie Fackler <augie@google.com>
Tue, 30 Jun 2015 19:19:17 -0400
changeset 25708 d3d32643c060
parent 25473 123c99034cb6
child 28942 05cb9c6f310e
permissions -rwxr-xr-x
wireproto: correctly escape batched args and responses (issue4739) This issue appears to be as old as wireproto batching itself: I can reproduce the failure as far back as 08ef6b5f3715 trivially by rebasing the test changes in this patch, which was back in the 1.9 era. I didn't test before that change, because prior to that the testfile has a different name and I'm lazy. Note that the test thought it was checking this case, but it actually wasn't: it put a literal ; in the arg and response for its greet command, but the mangle/unmangle step defined in the test meant that instead of "Fo, =;o" going over the wire, "Gp-!><p" went instead, which doesn't contain any special characters (those being [.=;]) and thus not exercising the escaping. The test has been updated to use pre-unmangled special characters, so the request is now "Fo+<:o", which mangles to "Gp,=;p". I have confirmed that the test fails without the adjustment to the escaping rules in wireproto.py. No existing clients of RPC batching were depending on the old behavior in any way. The only *actual* users of batchable RPCs in core were: 1) largefiles, wherein it batches up many statlfile calls. It sends hexlified hashes over the wire and gets a 0, 1, or 2 back as a response. No risk of special characters. 2) setdiscovery, which was using heads() and known(), both of which communicate via hexlified nodes. Again, no risk of special characters. Since the escaping functionality has been completely broken since it was introduced, we know that it has no users. As such, we can change the escaping mechanism without having to worry about backwards compatibility issues. For the curious, this was detected by chance: it happens that the lz4-compressed text of a test file for remotefilelog compressed to something containing a ;, which then caused the failure when I moved remotefilelog to using batching for file content fetching.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
7344
58fd3c718ca4 tests: add killdaemons helper script
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     1
#!/usr/bin/env python
58fd3c718ca4 tests: add killdaemons helper script
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     2
17466
d5a3bda6e170 killdaemons: take file argument explicitely
Patrick Mezard <patrick@mezard.eu>
parents: 17465
diff changeset
     3
import os, sys, time, errno, signal
7344
58fd3c718ca4 tests: add killdaemons helper script
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     4
17465
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
     5
if os.name =='nt':
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
     6
    import ctypes
20493
b5f43dbf64ca tests: kill for windows in killdaemons.py checks return values
Simon Heimberg <simohe@besonet.ch>
parents: 17466
diff changeset
     7
b5f43dbf64ca tests: kill for windows in killdaemons.py checks return values
Simon Heimberg <simohe@besonet.ch>
parents: 17466
diff changeset
     8
    def _check(ret, expectederr=None):
b5f43dbf64ca tests: kill for windows in killdaemons.py checks return values
Simon Heimberg <simohe@besonet.ch>
parents: 17466
diff changeset
     9
        if ret == 0:
b5f43dbf64ca tests: kill for windows in killdaemons.py checks return values
Simon Heimberg <simohe@besonet.ch>
parents: 17466
diff changeset
    10
            winerrno = ctypes.GetLastError()
b5f43dbf64ca tests: kill for windows in killdaemons.py checks return values
Simon Heimberg <simohe@besonet.ch>
parents: 17466
diff changeset
    11
            if winerrno == expectederr:
b5f43dbf64ca tests: kill for windows in killdaemons.py checks return values
Simon Heimberg <simohe@besonet.ch>
parents: 17466
diff changeset
    12
                return True
b5f43dbf64ca tests: kill for windows in killdaemons.py checks return values
Simon Heimberg <simohe@besonet.ch>
parents: 17466
diff changeset
    13
            raise ctypes.WinError(winerrno)
b5f43dbf64ca tests: kill for windows in killdaemons.py checks return values
Simon Heimberg <simohe@besonet.ch>
parents: 17466
diff changeset
    14
17465
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
    15
    def kill(pid, logfn, tryhard=True):
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
    16
        logfn('# Killing daemon process %d' % pid)
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
    17
        PROCESS_TERMINATE = 1
20496
acbd19b9fbe1 tests: killdaemons.py for windows distinguishes access violation and terminated
Simon Heimberg <simohe@besonet.ch>
parents: 20495
diff changeset
    18
        PROCESS_QUERY_INFORMATION = 0x400
20698
1147563faf62 killdaemons: drop superfluous L suffix from constant
Augie Fackler <raf@durin42.com>
parents: 20496
diff changeset
    19
        SYNCHRONIZE = 0x00100000
20494
ea3adeac5248 tests: killdaemons.py for windows waits for killed process to terminate
Simon Heimberg <simohe@besonet.ch>
parents: 20493
diff changeset
    20
        WAIT_OBJECT_0 = 0
ea3adeac5248 tests: killdaemons.py for windows waits for killed process to terminate
Simon Heimberg <simohe@besonet.ch>
parents: 20493
diff changeset
    21
        WAIT_TIMEOUT = 258
17465
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
    22
        handle = ctypes.windll.kernel32.OpenProcess(
20496
acbd19b9fbe1 tests: killdaemons.py for windows distinguishes access violation and terminated
Simon Heimberg <simohe@besonet.ch>
parents: 20495
diff changeset
    23
                PROCESS_TERMINATE|SYNCHRONIZE|PROCESS_QUERY_INFORMATION,
acbd19b9fbe1 tests: killdaemons.py for windows distinguishes access violation and terminated
Simon Heimberg <simohe@besonet.ch>
parents: 20495
diff changeset
    24
                False, pid)
20493
b5f43dbf64ca tests: kill for windows in killdaemons.py checks return values
Simon Heimberg <simohe@besonet.ch>
parents: 17466
diff changeset
    25
        if handle == 0:
20495
0cf1c8c452d3 tests: killdaemons.py for checks reason when getting no process handle
Simon Heimberg <simohe@besonet.ch>
parents: 20494
diff changeset
    26
            _check(0, 87) # err 87 when process not found
20493
b5f43dbf64ca tests: kill for windows in killdaemons.py checks return values
Simon Heimberg <simohe@besonet.ch>
parents: 17466
diff changeset
    27
            return # process not found, already finished
b5f43dbf64ca tests: kill for windows in killdaemons.py checks return values
Simon Heimberg <simohe@besonet.ch>
parents: 17466
diff changeset
    28
        try:
20496
acbd19b9fbe1 tests: killdaemons.py for windows distinguishes access violation and terminated
Simon Heimberg <simohe@besonet.ch>
parents: 20495
diff changeset
    29
            r = ctypes.windll.kernel32.WaitForSingleObject(handle, 100)
acbd19b9fbe1 tests: killdaemons.py for windows distinguishes access violation and terminated
Simon Heimberg <simohe@besonet.ch>
parents: 20495
diff changeset
    30
            if r == WAIT_OBJECT_0:
acbd19b9fbe1 tests: killdaemons.py for windows distinguishes access violation and terminated
Simon Heimberg <simohe@besonet.ch>
parents: 20495
diff changeset
    31
                pass # terminated, but process handle still available
acbd19b9fbe1 tests: killdaemons.py for windows distinguishes access violation and terminated
Simon Heimberg <simohe@besonet.ch>
parents: 20495
diff changeset
    32
            elif r == WAIT_TIMEOUT:
acbd19b9fbe1 tests: killdaemons.py for windows distinguishes access violation and terminated
Simon Heimberg <simohe@besonet.ch>
parents: 20495
diff changeset
    33
                _check(ctypes.windll.kernel32.TerminateProcess(handle, -1))
acbd19b9fbe1 tests: killdaemons.py for windows distinguishes access violation and terminated
Simon Heimberg <simohe@besonet.ch>
parents: 20495
diff changeset
    34
            else:
acbd19b9fbe1 tests: killdaemons.py for windows distinguishes access violation and terminated
Simon Heimberg <simohe@besonet.ch>
parents: 20495
diff changeset
    35
                _check(r)
20494
ea3adeac5248 tests: killdaemons.py for windows waits for killed process to terminate
Simon Heimberg <simohe@besonet.ch>
parents: 20493
diff changeset
    36
ea3adeac5248 tests: killdaemons.py for windows waits for killed process to terminate
Simon Heimberg <simohe@besonet.ch>
parents: 20493
diff changeset
    37
            # TODO?: forcefully kill when timeout
ea3adeac5248 tests: killdaemons.py for windows waits for killed process to terminate
Simon Heimberg <simohe@besonet.ch>
parents: 20493
diff changeset
    38
            #        and ?shorter waiting time? when tryhard==True
ea3adeac5248 tests: killdaemons.py for windows waits for killed process to terminate
Simon Heimberg <simohe@besonet.ch>
parents: 20493
diff changeset
    39
            r = ctypes.windll.kernel32.WaitForSingleObject(handle, 100)
ea3adeac5248 tests: killdaemons.py for windows waits for killed process to terminate
Simon Heimberg <simohe@besonet.ch>
parents: 20493
diff changeset
    40
                                                       # timeout = 100 ms
ea3adeac5248 tests: killdaemons.py for windows waits for killed process to terminate
Simon Heimberg <simohe@besonet.ch>
parents: 20493
diff changeset
    41
            if r == WAIT_OBJECT_0:
ea3adeac5248 tests: killdaemons.py for windows waits for killed process to terminate
Simon Heimberg <simohe@besonet.ch>
parents: 20493
diff changeset
    42
                pass # process is terminated
ea3adeac5248 tests: killdaemons.py for windows waits for killed process to terminate
Simon Heimberg <simohe@besonet.ch>
parents: 20493
diff changeset
    43
            elif r == WAIT_TIMEOUT:
ea3adeac5248 tests: killdaemons.py for windows waits for killed process to terminate
Simon Heimberg <simohe@besonet.ch>
parents: 20493
diff changeset
    44
                logfn('# Daemon process %d is stuck')
ea3adeac5248 tests: killdaemons.py for windows waits for killed process to terminate
Simon Heimberg <simohe@besonet.ch>
parents: 20493
diff changeset
    45
            else:
21194
476069509e72 killdaemons: correct typo of _check() function caught by pyflakes
Yuya Nishihara <yuya@tcha.org>
parents: 20698
diff changeset
    46
                _check(r) # any error
20493
b5f43dbf64ca tests: kill for windows in killdaemons.py checks return values
Simon Heimberg <simohe@besonet.ch>
parents: 17466
diff changeset
    47
        except: #re-raises
b5f43dbf64ca tests: kill for windows in killdaemons.py checks return values
Simon Heimberg <simohe@besonet.ch>
parents: 17466
diff changeset
    48
            ctypes.windll.kernel32.CloseHandle(handle) # no _check, keep error
b5f43dbf64ca tests: kill for windows in killdaemons.py checks return values
Simon Heimberg <simohe@besonet.ch>
parents: 17466
diff changeset
    49
            raise
b5f43dbf64ca tests: kill for windows in killdaemons.py checks return values
Simon Heimberg <simohe@besonet.ch>
parents: 17466
diff changeset
    50
        _check(ctypes.windll.kernel32.CloseHandle(handle))
b5f43dbf64ca tests: kill for windows in killdaemons.py checks return values
Simon Heimberg <simohe@besonet.ch>
parents: 17466
diff changeset
    51
17465
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
    52
else:
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
    53
    def kill(pid, logfn, tryhard=True):
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
    54
        try:
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
    55
            os.kill(pid, 0)
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
    56
            logfn('# Killing daemon process %d' % pid)
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
    57
            os.kill(pid, signal.SIGTERM)
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
    58
            if tryhard:
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
    59
                for i in range(10):
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
    60
                    time.sleep(0.05)
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
    61
                    os.kill(pid, 0)
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
    62
            else:
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
    63
                time.sleep(0.1)
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
    64
                os.kill(pid, 0)
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
    65
            logfn('# Daemon process %d is stuck - really killing it' % pid)
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
    66
            os.kill(pid, signal.SIGKILL)
25031
0adc22a0b6b3 python3: update killdaemons and run-tests print and exception syntax
Augie Fackler <augie@google.com>
parents: 21194
diff changeset
    67
        except OSError as err:
17465
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
    68
            if err.errno != errno.ESRCH:
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
    69
                raise
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
    70
17464
eddfb9a550d0 run-tests: do not duplicate killdaemons() code
Patrick Mezard <patrick@mezard.eu>
parents: 10905
diff changeset
    71
def killdaemons(pidfile, tryhard=True, remove=False, logfn=None):
eddfb9a550d0 run-tests: do not duplicate killdaemons() code
Patrick Mezard <patrick@mezard.eu>
parents: 10905
diff changeset
    72
    if not logfn:
eddfb9a550d0 run-tests: do not duplicate killdaemons() code
Patrick Mezard <patrick@mezard.eu>
parents: 10905
diff changeset
    73
        logfn = lambda s: s
eddfb9a550d0 run-tests: do not duplicate killdaemons() code
Patrick Mezard <patrick@mezard.eu>
parents: 10905
diff changeset
    74
    # Kill off any leftover daemon processes
eddfb9a550d0 run-tests: do not duplicate killdaemons() code
Patrick Mezard <patrick@mezard.eu>
parents: 10905
diff changeset
    75
    try:
eddfb9a550d0 run-tests: do not duplicate killdaemons() code
Patrick Mezard <patrick@mezard.eu>
parents: 10905
diff changeset
    76
        fp = open(pidfile)
eddfb9a550d0 run-tests: do not duplicate killdaemons() code
Patrick Mezard <patrick@mezard.eu>
parents: 10905
diff changeset
    77
        for line in fp:
eddfb9a550d0 run-tests: do not duplicate killdaemons() code
Patrick Mezard <patrick@mezard.eu>
parents: 10905
diff changeset
    78
            try:
eddfb9a550d0 run-tests: do not duplicate killdaemons() code
Patrick Mezard <patrick@mezard.eu>
parents: 10905
diff changeset
    79
                pid = int(line)
eddfb9a550d0 run-tests: do not duplicate killdaemons() code
Patrick Mezard <patrick@mezard.eu>
parents: 10905
diff changeset
    80
            except ValueError:
eddfb9a550d0 run-tests: do not duplicate killdaemons() code
Patrick Mezard <patrick@mezard.eu>
parents: 10905
diff changeset
    81
                continue
17465
2d4a096e213c killdaemons: add windows implementation
Patrick Mezard <patrick@mezard.eu>
parents: 17464
diff changeset
    82
            kill(pid, logfn, tryhard)
17464
eddfb9a550d0 run-tests: do not duplicate killdaemons() code
Patrick Mezard <patrick@mezard.eu>
parents: 10905
diff changeset
    83
        fp.close()
eddfb9a550d0 run-tests: do not duplicate killdaemons() code
Patrick Mezard <patrick@mezard.eu>
parents: 10905
diff changeset
    84
        if remove:
eddfb9a550d0 run-tests: do not duplicate killdaemons() code
Patrick Mezard <patrick@mezard.eu>
parents: 10905
diff changeset
    85
            os.unlink(pidfile)
eddfb9a550d0 run-tests: do not duplicate killdaemons() code
Patrick Mezard <patrick@mezard.eu>
parents: 10905
diff changeset
    86
    except IOError:
eddfb9a550d0 run-tests: do not duplicate killdaemons() code
Patrick Mezard <patrick@mezard.eu>
parents: 10905
diff changeset
    87
        pass
eddfb9a550d0 run-tests: do not duplicate killdaemons() code
Patrick Mezard <patrick@mezard.eu>
parents: 10905
diff changeset
    88
eddfb9a550d0 run-tests: do not duplicate killdaemons() code
Patrick Mezard <patrick@mezard.eu>
parents: 10905
diff changeset
    89
if __name__ == '__main__':
25473
123c99034cb6 tests: make killdaemons.py use DAEMON_PIDS by default
Matt Mackall <mpm@selenic.com>
parents: 25031
diff changeset
    90
    if len(sys.argv) > 1:
123c99034cb6 tests: make killdaemons.py use DAEMON_PIDS by default
Matt Mackall <mpm@selenic.com>
parents: 25031
diff changeset
    91
        path, = sys.argv[1:]
123c99034cb6 tests: make killdaemons.py use DAEMON_PIDS by default
Matt Mackall <mpm@selenic.com>
parents: 25031
diff changeset
    92
    else:
123c99034cb6 tests: make killdaemons.py use DAEMON_PIDS by default
Matt Mackall <mpm@selenic.com>
parents: 25031
diff changeset
    93
        path = os.environ["DAEMON_PIDS"]
123c99034cb6 tests: make killdaemons.py use DAEMON_PIDS by default
Matt Mackall <mpm@selenic.com>
parents: 25031
diff changeset
    94
17466
d5a3bda6e170 killdaemons: take file argument explicitely
Patrick Mezard <patrick@mezard.eu>
parents: 17465
diff changeset
    95
    killdaemons(path)