[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


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



More information about the Python-Dev mailing list