mirror of https://github.com/python/cpython
Michael fixed the race conditions and removed the sleeps.
This is his SF patch 569697. I renamed main() to test_main() again so that this is run as part of the standard test suite.
This commit is contained in:
parent
4837fa3a54
commit
83ccb4e011
|
@ -37,6 +37,42 @@ class SocketUDPTest(unittest.TestCase):
|
||||||
self.serv = None
|
self.serv = None
|
||||||
|
|
||||||
class ThreadableTest:
|
class ThreadableTest:
|
||||||
|
"""Threadable Test class
|
||||||
|
|
||||||
|
The ThreadableTest class makes it easy to create a threaded
|
||||||
|
client/server pair from an existing unit test. To create a
|
||||||
|
new threaded class from an existing unit test, use multiple
|
||||||
|
inheritance:
|
||||||
|
|
||||||
|
class NewClass (OldClass, ThreadableTest):
|
||||||
|
pass
|
||||||
|
|
||||||
|
This class defines two new fixture functions with obvious
|
||||||
|
purposes for overriding:
|
||||||
|
|
||||||
|
clientSetUp ()
|
||||||
|
clientTearDown ()
|
||||||
|
|
||||||
|
Any new test functions within the class must then define
|
||||||
|
tests in pairs, where the test name is preceeded with a
|
||||||
|
'_' to indicate the client portion of the test. Ex:
|
||||||
|
|
||||||
|
def testFoo(self):
|
||||||
|
# Server portion
|
||||||
|
|
||||||
|
def _testFoo(self):
|
||||||
|
# Client portion
|
||||||
|
|
||||||
|
Any exceptions raised by the clients during their tests
|
||||||
|
are caught and transferred to the main thread to alert
|
||||||
|
the testing framework.
|
||||||
|
|
||||||
|
Note, the server setup function cannot call any blocking
|
||||||
|
functions that rely on the client thread during setup,
|
||||||
|
unless serverExplicityReady() is called just before
|
||||||
|
the blocking call (such as in setting up a client/server
|
||||||
|
connection and performing the accept() in setUp().
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# Swap the true setup function
|
# Swap the true setup function
|
||||||
|
@ -45,8 +81,16 @@ class ThreadableTest:
|
||||||
self.setUp = self._setUp
|
self.setUp = self._setUp
|
||||||
self.tearDown = self._tearDown
|
self.tearDown = self._tearDown
|
||||||
|
|
||||||
|
def serverExplicitReady(self):
|
||||||
|
"""This method allows the server to explicitly indicate that
|
||||||
|
it wants the client thread to proceed. This is useful if the
|
||||||
|
server is about to execute a blocking routine that is
|
||||||
|
dependent upon the client thread during its setup routine."""
|
||||||
|
self.server_ready.set()
|
||||||
|
|
||||||
def _setUp(self):
|
def _setUp(self):
|
||||||
self.ready = threading.Event()
|
self.server_ready = threading.Event()
|
||||||
|
self.client_ready = threading.Event()
|
||||||
self.done = threading.Event()
|
self.done = threading.Event()
|
||||||
self.queue = Queue.Queue(1)
|
self.queue = Queue.Queue(1)
|
||||||
|
|
||||||
|
@ -59,7 +103,9 @@ class ThreadableTest:
|
||||||
self.clientRun, (test_method,))
|
self.clientRun, (test_method,))
|
||||||
|
|
||||||
self.__setUp()
|
self.__setUp()
|
||||||
self.ready.wait()
|
if not self.server_ready.isSet():
|
||||||
|
self.server_ready.set()
|
||||||
|
self.client_ready.wait()
|
||||||
|
|
||||||
def _tearDown(self):
|
def _tearDown(self):
|
||||||
self.__tearDown()
|
self.__tearDown()
|
||||||
|
@ -70,7 +116,8 @@ class ThreadableTest:
|
||||||
self.fail(msg)
|
self.fail(msg)
|
||||||
|
|
||||||
def clientRun(self, test_func):
|
def clientRun(self, test_func):
|
||||||
self.ready.set()
|
self.server_ready.wait()
|
||||||
|
self.client_ready.set()
|
||||||
self.clientSetUp()
|
self.clientSetUp()
|
||||||
if not callable(test_func):
|
if not callable(test_func):
|
||||||
raise TypeError, "test_func must be a callable function"
|
raise TypeError, "test_func must be a callable function"
|
||||||
|
@ -117,6 +164,9 @@ class SocketConnectedTest(ThreadedTCPSocketTest):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
ThreadedTCPSocketTest.setUp(self)
|
ThreadedTCPSocketTest.setUp(self)
|
||||||
|
# Indicate explicitly we're ready for the client thread to
|
||||||
|
# proceed and then perform the blocking call to accept
|
||||||
|
self.serverExplicitReady()
|
||||||
conn, addr = self.serv.accept()
|
conn, addr = self.serv.accept()
|
||||||
self.cli_conn = conn
|
self.cli_conn = conn
|
||||||
|
|
||||||
|
@ -369,7 +419,6 @@ class BasicUDPTest(ThreadedUDPSocketTest):
|
||||||
self.assertEqual(msg, MSG)
|
self.assertEqual(msg, MSG)
|
||||||
|
|
||||||
def _testRecvFrom(self):
|
def _testRecvFrom(self):
|
||||||
time.sleep(1) # Give server a chance to set up
|
|
||||||
self.cli.sendto(MSG, 0, (HOST, PORT))
|
self.cli.sendto(MSG, 0, (HOST, PORT))
|
||||||
|
|
||||||
class NonBlockingTCPTests(ThreadedTCPSocketTest):
|
class NonBlockingTCPTests(ThreadedTCPSocketTest):
|
||||||
|
@ -407,12 +456,10 @@ class NonBlockingTCPTests(ThreadedTCPSocketTest):
|
||||||
self.fail("Error trying to do accept after select.")
|
self.fail("Error trying to do accept after select.")
|
||||||
|
|
||||||
def _testAccept(self):
|
def _testAccept(self):
|
||||||
time.sleep(1)
|
|
||||||
self.cli.connect((HOST, PORT))
|
self.cli.connect((HOST, PORT))
|
||||||
|
|
||||||
def testConnect(self):
|
def testConnect(self):
|
||||||
"""Testing non-blocking connect."""
|
"""Testing non-blocking connect."""
|
||||||
time.sleep(1)
|
|
||||||
conn, addr = self.serv.accept()
|
conn, addr = self.serv.accept()
|
||||||
|
|
||||||
def _testConnect(self):
|
def _testConnect(self):
|
||||||
|
@ -438,7 +485,6 @@ class NonBlockingTCPTests(ThreadedTCPSocketTest):
|
||||||
|
|
||||||
def _testRecv(self):
|
def _testRecv(self):
|
||||||
self.cli.connect((HOST, PORT))
|
self.cli.connect((HOST, PORT))
|
||||||
time.sleep(1)
|
|
||||||
self.cli.send(MSG)
|
self.cli.send(MSG)
|
||||||
|
|
||||||
class FileObjectClassTestCase(SocketConnectedTest):
|
class FileObjectClassTestCase(SocketConnectedTest):
|
||||||
|
@ -498,7 +544,7 @@ class FileObjectClassTestCase(SocketConnectedTest):
|
||||||
self.cli_file.write(MSG)
|
self.cli_file.write(MSG)
|
||||||
self.cli_file.flush()
|
self.cli_file.flush()
|
||||||
|
|
||||||
def main():
|
def test_main():
|
||||||
suite = unittest.TestSuite()
|
suite = unittest.TestSuite()
|
||||||
suite.addTest(unittest.makeSuite(GeneralModuleTests))
|
suite.addTest(unittest.makeSuite(GeneralModuleTests))
|
||||||
suite.addTest(unittest.makeSuite(BasicTCPTest))
|
suite.addTest(unittest.makeSuite(BasicTCPTest))
|
||||||
|
@ -508,4 +554,4 @@ def main():
|
||||||
test_support.run_suite(suite)
|
test_support.run_suite(suite)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
test_main()
|
||||||
|
|
Loading…
Reference in New Issue