[Python-Dev] Socket servers in the test suite (original) (raw)
Vinay Sajip vinay_sajip at yahoo.co.uk
Mon May 2 16:26:56 CEST 2011
- Previous message: [Python-Dev] Raise OSError or RuntimeError in the OS module?
- Next message: [Python-Dev] Convert Py_Buffer to Py_UNICODE
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Nick Coghlan <ncoghlan gmail.com> writes:
sure the urllib tests already fire up a local server). Starting down the path of standardisation of that test functionality would be good.
I've made a start with test_logging.py by implementing some potential server classes for use in tests: in the latest test_logging.py, the servers are between comments containing the text "server_helper".
The basic approach for implementing socket servers is traditionally to use a request handler class which implements the custom logic, but for some testing applications this is overkill - you just want to be able to pass a handling callable which is, say, a test case method. So the signatures of the servers are all like this:
init(self, listen_addr, handler, poll_interval ...)
Initialise using the specified listen address and handler callable. Internally, a RequestHandler subclass will be used whose handle() delegates to the handler callable passed in. A zero port number can be passed in, and a port attribute will (after binding) have the actual port number used, so that clients can connect on that port.
start()
Start the server on a separate thread, using the poll_interval specified in the underlying poll()/select() call. Before this is called, the request handler class could be replaced with a subclass if need be.
stop(timeout=None)
Ask the server to stop and wait for the server thread to terminate.
The server also has a ready attribute which is a threading.Event, set just when the server is entering its service loop. Typical mode of use would be:
class ClientTestCase(unittest.TestCase): def setUp(self): self.server = TheAppropriateServerClass(('localhost', 0), self.handle_request, 0.01, ...) self.server.start() self.server.ready.wait() self.handled = threading.Event()
def tearDown(self):
self.server.stop(1.0) # wait up to 1 sec for thread to stop
def handle_request(self, request):
# Handle the request, e.g. by setting some attributes based on what
# was received at the server
# Set the flag to say we finished handling
self.handled.set()
def test_xxx(self):
# set up client and send stuff to server
# Wait for server to finish doing stuff
self.handled.wait()
# make assertions based on the attributes
# set during request handling
The server classes provided are TestSMTPServer, TestTCPServer, TestUDPServer and TestHTTPServer. There are examples of actual usage in test_logging.py: SMTPHandlerTest, SocketHandlerTest, DatagramHandlerTest, SysLogHandlerTest, HTTPHandlerTest.
I'd like some comments on this suggested API. I have not yet looked at how to adapt other stdlib code than test_logging to use these classes, but the above usage mode seems convenient and sufficient for testing applications. No doubt people will be able to suggest problems with/improvements to the approach outlined above.
Regards,
Vinay Sajip
- Previous message: [Python-Dev] Raise OSError or RuntimeError in the OS module?
- Next message: [Python-Dev] Convert Py_Buffer to Py_UNICODE
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]