~0x44/nova/bug838466

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/twisted/test/proto_helpers.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- test-case-name: twisted.test.test_stringtransport -*-
 
2
# Copyright (c) 2001-2010 Twisted Matrix Laboratories.
 
3
# See LICENSE for details.
 
4
 
 
5
"""
 
6
Assorted functionality which is commonly useful when writing unit tests.
 
7
"""
 
8
 
 
9
from StringIO import StringIO
 
10
 
 
11
from zope.interface import implements
 
12
from zope.interface.verify import verifyObject
 
13
 
 
14
from twisted.internet.interfaces import ITransport, IConsumer, IPushProducer
 
15
from twisted.internet.interfaces import IReactorTCP
 
16
from twisted.protocols import basic
 
17
from twisted.internet import protocol, error
 
18
 
 
19
 
 
20
class AccumulatingProtocol(protocol.Protocol):
 
21
    """
 
22
    L{AccumulatingProtocol} is an L{IProtocol} implementation which collects
 
23
    the data delivered to it and can fire a Deferred when it is connected or
 
24
    disconnected.
 
25
 
 
26
    @ivar made: A flag indicating whether C{connectionMade} has been called.
 
27
    @ivar data: A string giving all the data passed to C{dataReceived}.
 
28
    @ivar closed: A flag indicated whether C{connectionLost} has been called.
 
29
    @ivar closedReason: The value of the I{reason} parameter passed to
 
30
        C{connectionLost}.
 
31
    @ivar closedDeferred: If set to a L{Deferred}, this will be fired when
 
32
        C{connectionLost} is called.
 
33
    """
 
34
    made = closed = 0
 
35
    closedReason = None
 
36
 
 
37
    closedDeferred = None
 
38
 
 
39
    data = ""
 
40
 
 
41
    factory = None
 
42
 
 
43
    def connectionMade(self):
 
44
        self.made = 1
 
45
        if (self.factory is not None and
 
46
            self.factory.protocolConnectionMade is not None):
 
47
            d = self.factory.protocolConnectionMade
 
48
            self.factory.protocolConnectionMade = None
 
49
            d.callback(self)
 
50
 
 
51
    def dataReceived(self, data):
 
52
        self.data += data
 
53
 
 
54
    def connectionLost(self, reason):
 
55
        self.closed = 1
 
56
        self.closedReason = reason
 
57
        if self.closedDeferred is not None:
 
58
            d, self.closedDeferred = self.closedDeferred, None
 
59
            d.callback(None)
 
60
 
 
61
 
 
62
class LineSendingProtocol(basic.LineReceiver):
 
63
    lostConn = False
 
64
 
 
65
    def __init__(self, lines, start = True):
 
66
        self.lines = lines[:]
 
67
        self.response = []
 
68
        self.start = start
 
69
 
 
70
    def connectionMade(self):
 
71
        if self.start:
 
72
            map(self.sendLine, self.lines)
 
73
 
 
74
    def lineReceived(self, line):
 
75
        if not self.start:
 
76
            map(self.sendLine, self.lines)
 
77
            self.lines = []
 
78
        self.response.append(line)
 
79
 
 
80
    def connectionLost(self, reason):
 
81
        self.lostConn = True
 
82
 
 
83
 
 
84
class FakeDatagramTransport:
 
85
    noAddr = object()
 
86
 
 
87
    def __init__(self):
 
88
        self.written = []
 
89
 
 
90
    def write(self, packet, addr=noAddr):
 
91
        self.written.append((packet, addr))
 
92
 
 
93
 
 
94
class StringTransport:
 
95
    """
 
96
    A transport implementation which buffers data in memory and keeps track of
 
97
    its other state without providing any behavior.
 
98
 
 
99
    L{StringTransport} has a number of attributes which are not part of any of
 
100
    the interfaces it claims to implement.  These attributes are provided for
 
101
    testing purposes.  Implementation code should not use any of these
 
102
    attributes; they are not provided by other transports.
 
103
 
 
104
    @ivar disconnecting: A C{bool} which is C{False} until L{loseConnection} is
 
105
        called, then C{True}.
 
106
 
 
107
    @ivar producer: If a producer is currently registered, C{producer} is a
 
108
        reference to it.  Otherwise, C{None}.
 
109
 
 
110
    @ivar streaming: If a producer is currently registered, C{streaming} refers
 
111
        to the value of the second parameter passed to C{registerProducer}.
 
112
 
 
113
    @ivar hostAddr: C{None} or an object which will be returned as the host
 
114
        address of this transport.  If C{None}, a nasty tuple will be returned
 
115
        instead.
 
116
 
 
117
    @ivar peerAddr: C{None} or an object which will be returned as the peer
 
118
        address of this transport.  If C{None}, a nasty tuple will be returned
 
119
        instead.
 
120
 
 
121
    @ivar producerState: The state of this L{StringTransport} in its capacity
 
122
        as an L{IPushProducer}.  One of C{'producing'}, C{'paused'}, or
 
123
        C{'stopped'}.
 
124
 
 
125
    @ivar io: A L{StringIO} which holds the data which has been written to this
 
126
        transport since the last call to L{clear}.  Use L{value} instead of
 
127
        accessing this directly.
 
128
    """
 
129
    implements(ITransport, IConsumer, IPushProducer)
 
130
 
 
131
    disconnecting = False
 
132
 
 
133
    producer = None
 
134
    streaming = None
 
135
 
 
136
    hostAddr = None
 
137
    peerAddr = None
 
138
 
 
139
    producerState = 'producing'
 
140
 
 
141
    def __init__(self, hostAddress=None, peerAddress=None):
 
142
        self.clear()
 
143
        if hostAddress is not None:
 
144
            self.hostAddr = hostAddress
 
145
        if peerAddress is not None:
 
146
            self.peerAddr = peerAddress
 
147
        self.connected = True
 
148
 
 
149
    def clear(self):
 
150
        """
 
151
        Discard all data written to this transport so far.
 
152
 
 
153
        This is not a transport method.  It is intended for tests.  Do not use
 
154
        it in implementation code.
 
155
        """
 
156
        self.io = StringIO()
 
157
 
 
158
 
 
159
    def value(self):
 
160
        """
 
161
        Retrieve all data which has been buffered by this transport.
 
162
 
 
163
        This is not a transport method.  It is intended for tests.  Do not use
 
164
        it in implementation code.
 
165
 
 
166
        @return: A C{str} giving all data written to this transport since the
 
167
            last call to L{clear}.
 
168
        @rtype: C{str}
 
169
        """
 
170
        return self.io.getvalue()
 
171
 
 
172
 
 
173
    # ITransport
 
174
    def write(self, data):
 
175
        if isinstance(data, unicode): # no, really, I mean it
 
176
            raise TypeError("Data must not be unicode")
 
177
        self.io.write(data)
 
178
 
 
179
 
 
180
    def writeSequence(self, data):
 
181
        self.io.write(''.join(data))
 
182
 
 
183
 
 
184
    def loseConnection(self):
 
185
        """
 
186
        Close the connection. Does nothing besides toggle the C{disconnecting}
 
187
        instance variable to C{True}.
 
188
        """
 
189
        self.disconnecting = True
 
190
 
 
191
 
 
192
    def getPeer(self):
 
193
        if self.peerAddr is None:
 
194
            return ('StringIO', repr(self.io))
 
195
        return self.peerAddr
 
196
 
 
197
 
 
198
    def getHost(self):
 
199
        if self.hostAddr is None:
 
200
            return ('StringIO', repr(self.io))
 
201
        return self.hostAddr
 
202
 
 
203
 
 
204
    # IConsumer
 
205
    def registerProducer(self, producer, streaming):
 
206
        if self.producer is not None:
 
207
            raise RuntimeError("Cannot register two producers")
 
208
        self.producer = producer
 
209
        self.streaming = streaming
 
210
 
 
211
 
 
212
    def unregisterProducer(self):
 
213
        if self.producer is None:
 
214
            raise RuntimeError(
 
215
                "Cannot unregister a producer unless one is registered")
 
216
        self.producer = None
 
217
        self.streaming = None
 
218
 
 
219
 
 
220
    # IPushProducer
 
221
    def _checkState(self):
 
222
        if self.disconnecting:
 
223
            raise RuntimeError(
 
224
                "Cannot resume producing after loseConnection")
 
225
        if self.producerState == 'stopped':
 
226
            raise RuntimeError("Cannot resume a stopped producer")
 
227
 
 
228
 
 
229
    def pauseProducing(self):
 
230
        self._checkState()
 
231
        self.producerState = 'paused'
 
232
 
 
233
 
 
234
    def stopProducing(self):
 
235
        self.producerState = 'stopped'
 
236
 
 
237
 
 
238
    def resumeProducing(self):
 
239
        self._checkState()
 
240
        self.producerState = 'producing'
 
241
 
 
242
 
 
243
 
 
244
class StringTransportWithDisconnection(StringTransport):
 
245
    def loseConnection(self):
 
246
        if self.connected:
 
247
            self.connected = False
 
248
            self.protocol.connectionLost(error.ConnectionDone("Bye."))
 
249
 
 
250
 
 
251
 
 
252
class StringIOWithoutClosing(StringIO):
 
253
    """
 
254
    A StringIO that can't be closed.
 
255
    """
 
256
    def close(self):
 
257
        """
 
258
        Do nothing.
 
259
        """
 
260
 
 
261
 
 
262
class MemoryReactor(object):
 
263
    """
 
264
    A fake reactor to be used in tests.  This reactor doesn't actually do
 
265
    much that's useful yet.  It accepts TCP connection setup attempts, but
 
266
    they will never succeed.
 
267
 
 
268
    @ivar tcpClients: a list that keeps track of connection attempts (ie, calls
 
269
        to C{connectTCP}).
 
270
    @type tcpClients: C{list}
 
271
 
 
272
    @ivar tcpServers: a list that keeps track of server listen attempts (ie, calls
 
273
        to C{listenTCP}).
 
274
    @type tcpServers: C{list}
 
275
    """
 
276
    implements(IReactorTCP)
 
277
 
 
278
    def __init__(self):
 
279
        """
 
280
        Initialize the tracking lists.
 
281
        """
 
282
        self.tcpClients = []
 
283
        self.tcpServers = []
 
284
 
 
285
 
 
286
    def listenTCP(self, port, factory, backlog=50, interface=''):
 
287
        """
 
288
        Fake L{reactor.listenTCP}, that does nothing but log the call.
 
289
        """
 
290
        self.tcpServers.append((port, factory, backlog, interface))
 
291
 
 
292
 
 
293
    def connectTCP(self, host, port, factory, timeout=30, bindAddress=None):
 
294
        """
 
295
        Fake L{reactor.connectTCP}, that does nothing but log the call.
 
296
        """
 
297
        self.tcpClients.append((host, port, factory, timeout, bindAddress))
 
298
 
 
299
verifyObject(IReactorTCP, MemoryReactor())