sapling/tests/test-patchpython.py
Jun Wu ab49fe9698 patchpython: new extension to patch buggy Python modules
Summary:
As discussed, we want to make sure we have a good SocketServer for Python 2.6,
which is unsupported by PSF but still being widely used by our users.

This diff adds a new extension that tries to fix buggy Python standard modules,
namely the SocketServer. It fixes a critical race condition for Python 2.6
(https://bugs.python.org/issue21491) and the zombie process issue for both
Python 2.6 and 2.7 (https://bugs.python.org/issue11109).

A simple test is added to check zombie processes are no more.

Test Plan:
Run the newly added test, `test-patchpython.py` with both Python 2.6 and 2.7.
Comment out the `import patchpython` line in the test and make sure it fails
on Python 2.6 and 2.7 with `AssertionError: zombie process detected`.

Reviewers: #mercurial, ttung, mjpieters

Reviewed By: mjpieters

Subscribers: simonfar, durham, mjpieters

Differential Revision: https://phabricator.intern.facebook.com/D3384909

Signature: t1:3384909:1465319491:0ba64b496186712651b7ee6bd502d1e2ccac57d1
2016-06-03 11:11:30 +01:00

65 lines
1.7 KiB
Python

import errno
import os
import signal
import socket
import sys
import time
try:
import SocketServer
except ImportError:
# Python 3
import socketserver as SocketServer
try:
import patchpython
except ImportError:
# This happens if run-tests.py is run from the "tests" directory
# instead of the root of the project.
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
import patchpython
def testnozombies():
class reportpidhandler(SocketServer.StreamRequestHandler):
def handle(self):
self.wfile.write('%s' % (os.getpid(),))
class server(SocketServer.ForkingMixIn, SocketServer.UnixStreamServer):
pass
socketpath = 'testsocket'
pid = os.fork()
if pid > 0:
# client
waittime = 0
while not os.path.exists(socketpath):
time.sleep(0.1)
waittime += 0.1
if waittime > 5:
assert False, 'server timed out'
try:
pids = []
for i in xrange(5):
s = socket.socket(socket.AF_UNIX)
s.connect(socketpath)
buf = s.recv(1024)
s.close()
pids.append(int(buf))
# give the server some time to do cleanup
time.sleep(0.5)
for p in pids:
try:
os.kill(p, 0)
assert False, 'zombie process detected'
except OSError as ex:
if ex.errno != errno.ESRCH:
raise
finally:
os.kill(pid, signal.SIGTERM) # stop server
else:
# server
s = server(socketpath, reportpidhandler)
s.serve_forever(poll_interval=0.1)
testnozombies()