You are viewing blackjml

How to Disconnect in Twisted, Really

« previous entry | next entry »
Jul. 7th, 2006 | 06:51 pm

Trial is about to become a fair bit stricter on tests that don't clean up after themselves. In particular, any test that doesn't properly close all of its connections is going to fail ugly. Lots of Twisted's tests fail very ugly.

If you are already glazing over with apathy towards unit tests, unglaze now. Disconnecting is a little more involved than you might expect, and there's every chance you aren't doing it correctly.

Thanks to moshez and teratorn for reviewing this document. Any errors are still my fault.

How to Disconnect in Twisted, Really

You are writing a test for some network code. You have already written many unit tests for the protocol and the protocol factories, and you assume that the lower level socket calls all work. You have deep confidence in your code, but you need more.

You yearn to write an end-to-end test. To set up the server, have it really listen, have the client really connect. You want data to zoom back and forth over the wire like luxury sportscars on the Autobahn.

Fine.

You start with a server and a client.

You want the client to connect to the server. You want things to happen. When things have happened, you want to assert stuff.

After the assertions, you want to disconnect the client and you want the server to go away.

Good.

I'm not going to help you set things up, I'm not going to help you make things happen. I am going to help you make all your connections just go away.

Let me lay down the law:

  1. The server must stop listening.
  2. The client connection must disconnect.
  3. The server connection must disconnect.

You have to make each of these things happen. That's easy. Here's the tricky part: you have to wait for each of these things to happen.

To make the server stop listening:
    port = reactor.listenTCP(portNumber, factory)
    ...
    port.stopListening()
You can effect the last two with one stroke, using either of the following commands:
    protocol.transport.loseConnection()

OR

    connector = reactor.connectTCP(host, port, factory)
    ...
    connector.disconnect()

Now, just running these commands is not enough. Twisted is asynchronous: you have to wait for it to call you.

The way to wait for something in a Trial test is to return a Deferred from the test method.

stopListening is easy. It returns a Deferred if it is going to take a while. The others are harder. There is only one way to know when the connection has truly been lost: override connectionLost on a Protocol instance. Pass a Deferred to your Protocol and have connectionLost call callback on that Deferred. You will need to do this for both the client and the server protocols. Once you have your three Deferreds, return them in a DeferredList.

Simple.

UPDATE: exarkun tells me that there are two ways to know when the connection has truly been lost on the client side. ClientFactory.clientConnectionLost is the other one.

Summary

In order to clean up a test that connects a client to a server, you need to wait on three Deferreds: one for the listening port, one for the server protocol and one for the client protocol.

Below is an example demonstrating how to disconnect. As you can see, it is quite verbose. Trial does not provide any shortcuts, even though it should.

from twisted.internet import defer, protocol
from twisted.trial import unittest

class ServerProtocol(protocol.Protocol):
    def connectionLost(self, *a):
        self.factory.onConnectionLost.callback(self)

class ClientProtocol(protocol.Protocol):
    def connectionMade(self):
        self.factory.onConnectionMade.callback(self)

    def connectionLost(self, *a):
        self.factory.onConnectionLost.callback(self)


class TestDisconnect(unittest.TestCase):
    def setUp(self):
        self.serverDisconnected = defer.Deferred()
        self.serverPort = self._listenServer(self.serverDisconnected)
        connected = defer.Deferred()
        self.clientDisconnected = defer.Deferred()
        self.clientConnection = self._connectClient(connected,
                                                    self.clientDisconnected)
        return connected

    def _listenServer(self, d):
        from twisted.internet import reactor
        f = protocol.Factory()
        f.onConnectionLost = d
        f.protocol = ServerProtocol
        return reactor.listenTCP(0, f)

    def _connectClient(self, d1, d2):
        from twisted.internet import reactor
        factory = protocol.ClientFactory()
        factory.protocol = ClientProtocol
        factory.onConnectionMade = d1
        factory.onConnectionLost = d2
        return reactor.connectTCP('localhost',
                                  self.serverPort.getHost().port,
                                  factory)

    def tearDown(self):
        d = defer.maybeDeferred(self.serverPort.stopListening)
        self.clientConnection.disconnect()
        return defer.gatherResults([d,
                                    self.clientDisconnected,
                                    self.serverDisconnected])

    def test_disconnect(self):
        pass

Link | Leave a comment | Share

Comments {14}

(no subject)

from: skyline12340
date: Nov. 29th, 2007 02:10 am (UTC)
Link

Thanks for the technical help. I'll try to spread the word. Samir
Coffee Machine

Reply | Thread

(no subject)

from: atlasvain
date: Dec. 1st, 2007 01:46 am (UTC)
Link

Thank you so much! This helped out a lot.
http://www.asgenergy.com/

Reply | Thread

Here

from: blogman001
date: Dec. 1st, 2007 06:14 pm (UTC)
Link

I was wondering what type of systems this would be able to run on

Auto Loans

Reply | Thread

(no subject)

from: hasyer
date: Apr. 10th, 2008 10:57 pm (UTC)
Link

Thank you.

---------------------
muhabbet | korku | msn nickleri | msn nickleri | netlog

Reply | Thread

good

from: keji01
date: Jul. 23rd, 2009 03:22 am (UTC)
Link

good
---------------------------------------------------------------------------------------------
christian louboutin shoes

Reply | Thread

About our site www.ecvtop.com

from: ecvtop
date: Aug. 10th, 2009 08:13 am (UTC)
Link

Ecvtop.com is a world-wide wholesale company,We are a manufacturing and warehouse facility located in Xiamen China exporting clothing to the world. Our pricing is unsurpassed and the lowest as we are a factory. WHOLESALE ABERCROMBIE,WHOLELSAE LACOSTE ,WHOLESALE RALPH LAUREN POLO,WHOLESALE POLO SHIRTS,ABERCROMBIE POLO all have the best quality,and lower price, Please enjoy your shopping experience on our on line factory outlet clearance center. We have partnered with other manufactures and warehouses from our province in order to bring you the most products available on one site. Welcome to Ecvtop.com where we bring high quality products at an affordable price to your front door

Reply | Thread

Welcome to www.vtopshop.com Wholesale Abercrombie

from: ecvtop
date: Sep. 1st, 2009 06:44 am (UTC)
Link

Welcome to www.vtopshop.com Wholesale Abercrombie,Abercrombie Wholesaler From China, accept paypal,including Abercrombie and fitch polo ,cheap abercrombie clothing,abercrombie jeans,abercrombie handbag etc,also we can have wholesale Juicy couture, Wholesale Ralph Lauren polo,please vist our site(www.vtopshop.com ) for details.

Reply | Thread

(no subject)

from: ecvtop
date: Sep. 7th, 2009 02:24 am (UTC)
Link

Someone like shopping wholesale abercrombie online, I think it’s a good way, you’ll also interested in the wholesale abercrombie,

Reply | Thread

christian louboutin

from: amyfanfan
date: Jan. 22nd, 2010 08:33 am (UTC)
Link

well, it's very good, tks for your sharing... tks again

christian louboutin boots, christian louboutin, louboutin sale: http://www.8-mall.com

Reply | Thread

lujiajie

(no subject)

from: lujiajie
date: Jun. 25th, 2010 01:20 pm (UTC)
Link

higher normal is their architectural textile. coach outlet, on the contrary of shopping centers, are usually habitus spreading through trifling towns, ditch streets, seats, alleys, and burberry outlets shops along the roads and streets. Their organize is very much offbeat than prevalent malls, which are closed spaces, adumbrate loud tune passage outer of the louis vuitton outlets speakers and neon scintillating that could damaged somebody’s view. Lately multifarious outlet stores believe been developed according to coach outlets symptomatic regional architectural themes, owing to presentation some of them adopted a neoclassical burberry outlet polish credit Veneto, the moor whereabouts the celebrated neoclassical sculptor Canova was born, or they lap up been realized hep by the Renaissance pulchritude force Tuscany. These solutions induce the environment supremely additional louis vuitton outlet pleasant, since is largely supplementary well-off to trudge abandoned its alleys, clout comparison to score spaces stow away no windows of stereotyped shopping centers.

Reply | Thread

askı

from: sporaletleri
date: Jul. 1st, 2010 08:44 am (UTC)
Link

Nice article thank you...

askı

Reply | Thread

moncler jackets

from: moncler13
date: Dec. 8th, 2010 07:25 am (UTC)
Link

Develop in cooperation with the above mode, moncler jacket in accession to the alternation was added Sergio Rossi Puma YvesSaintLaurent in general. Although the acidity of Clyde is the top heels, but blubbery abundant heel, moncler jackets on sale the sole actual is aswell a able assembly Moncler Jackets For Men anorak , covering lining, cutting comfortable, has a acceptable damping. Cuffs and basal are too confusing, and acorns in the aboriginal area of scarves and absolute knitting,moncler jackets for cheap , printed skirt, panties, physique is a clock! Extend your high physique lower physique arrangement as a “new structure” of beauty. Employees have to abide a winter anorak is a different product,Moncler Vest For Men is the fat aggrandized accompaniment alike with the old jackets, dress for chargeless outside, cutting jacket, Moncler Coats For Men’s rain, even wind. Moncler Himalaya Dawn Anne Brill Anorak Red mo , a amount of defenders.

Reply | Thread

(no subject)

from: naramalaia
date: Feb. 8th, 2011 04:00 pm (UTC)
Link

Somehow, the antispyware software prevents me from accessing the server from time to time; I can only access it after I'm disabling the rogue software.

Reply | Thread