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:
Guido van Rossum 2002-06-18 18:35:13 +00:00
parent 4837fa3a54
commit 83ccb4e011
1 changed files with 55 additions and 9 deletions

View File

@ -37,6 +37,42 @@ class SocketUDPTest(unittest.TestCase):
self.serv = None
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):
# Swap the true setup function
@ -45,8 +81,16 @@ class ThreadableTest:
self.setUp = self._setUp
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):
self.ready = threading.Event()
self.server_ready = threading.Event()
self.client_ready = threading.Event()
self.done = threading.Event()
self.queue = Queue.Queue(1)
@ -59,7 +103,9 @@ class ThreadableTest:
self.clientRun, (test_method,))
self.__setUp()
self.ready.wait()
if not self.server_ready.isSet():
self.server_ready.set()
self.client_ready.wait()
def _tearDown(self):
self.__tearDown()
@ -70,7 +116,8 @@ class ThreadableTest:
self.fail(msg)
def clientRun(self, test_func):
self.ready.set()
self.server_ready.wait()
self.client_ready.set()
self.clientSetUp()
if not callable(test_func):
raise TypeError, "test_func must be a callable function"
@ -117,6 +164,9 @@ class SocketConnectedTest(ThreadedTCPSocketTest):
def 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()
self.cli_conn = conn
@ -369,7 +419,6 @@ class BasicUDPTest(ThreadedUDPSocketTest):
self.assertEqual(msg, MSG)
def _testRecvFrom(self):
time.sleep(1) # Give server a chance to set up
self.cli.sendto(MSG, 0, (HOST, PORT))
class NonBlockingTCPTests(ThreadedTCPSocketTest):
@ -407,12 +456,10 @@ class NonBlockingTCPTests(ThreadedTCPSocketTest):
self.fail("Error trying to do accept after select.")
def _testAccept(self):
time.sleep(1)
self.cli.connect((HOST, PORT))
def testConnect(self):
"""Testing non-blocking connect."""
time.sleep(1)
conn, addr = self.serv.accept()
def _testConnect(self):
@ -438,7 +485,6 @@ class NonBlockingTCPTests(ThreadedTCPSocketTest):
def _testRecv(self):
self.cli.connect((HOST, PORT))
time.sleep(1)
self.cli.send(MSG)
class FileObjectClassTestCase(SocketConnectedTest):
@ -498,7 +544,7 @@ class FileObjectClassTestCase(SocketConnectedTest):
self.cli_file.write(MSG)
self.cli_file.flush()
def main():
def test_main():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(GeneralModuleTests))
suite.addTest(unittest.makeSuite(BasicTCPTest))
@ -508,4 +554,4 @@ def main():
test_support.run_suite(suite)
if __name__ == "__main__":
main()
test_main()