[68] | 1 | # HG changeset patch |
---|
[74] | 2 | # Parent 71082c22f73200a0b8b4b5c6e5d2773f9f68dd4d |
---|
[72] | 3 | Generalize StreamManager and add ServerStreamManager. |
---|
| 4 | |
---|
| 5 | This generalizes `StreamManager` to `BaseStreamManager` to take the |
---|
| 6 | common functionality and reuse it for `ServerStreamManager`. Where |
---|
| 7 | `StreamManager` is used for initiating connections, with a factory as |
---|
| 8 | a parameter, `ServerStreamManager` works for receiving connections. It |
---|
| 9 | must be created in a protocol factory when a connection is established, |
---|
| 10 | and then its `makeConnection` should be called to hook it up to the |
---|
| 11 | `XmlStream` instance. |
---|
[68] | 12 | |
---|
| 13 | diff --git a/wokkel/client.py b/wokkel/client.py |
---|
| 14 | --- a/wokkel/client.py |
---|
| 15 | +++ b/wokkel/client.py |
---|
| 16 | @@ -109,7 +109,7 @@ |
---|
| 17 | self._connection.disconnect() |
---|
| 18 | |
---|
| 19 | |
---|
| 20 | - def _authd(self, xs): |
---|
| 21 | + def connectionInitialized(self, xs): |
---|
| 22 | """ |
---|
| 23 | Called when the stream has been initialized. |
---|
| 24 | |
---|
| 25 | @@ -118,7 +118,7 @@ |
---|
| 26 | by its constituent initializers. |
---|
| 27 | """ |
---|
| 28 | self.jid = self.factory.authenticator.jid |
---|
| 29 | - StreamManager._authd(self, xs) |
---|
| 30 | + StreamManager.connectionInitialized(self, xs) |
---|
| 31 | |
---|
| 32 | |
---|
| 33 | def initializationFailed(self, reason): |
---|
[74] | 34 | diff --git a/wokkel/component.py b/wokkel/component.py |
---|
| 35 | --- a/wokkel/component.py |
---|
| 36 | +++ b/wokkel/component.py |
---|
| 37 | @@ -36,7 +36,7 @@ |
---|
| 38 | StreamManager.__init__(self, factory) |
---|
| 39 | |
---|
| 40 | |
---|
| 41 | - def _authd(self, xs): |
---|
| 42 | + def connectionInitialized(self, xs): |
---|
| 43 | """ |
---|
| 44 | Called when stream initialization has completed. |
---|
| 45 | |
---|
| 46 | @@ -53,7 +53,7 @@ |
---|
| 47 | old_send(obj) |
---|
| 48 | |
---|
| 49 | xs.send = send |
---|
| 50 | - StreamManager._authd(self, xs) |
---|
| 51 | + StreamManager.connectionInitialized(self, xs) |
---|
| 52 | |
---|
| 53 | |
---|
| 54 | def initializationFailed(self, reason): |
---|
[68] | 55 | diff --git a/wokkel/subprotocols.py b/wokkel/subprotocols.py |
---|
| 56 | --- a/wokkel/subprotocols.py |
---|
| 57 | +++ b/wokkel/subprotocols.py |
---|
[74] | 58 | @@ -120,7 +120,7 @@ |
---|
[68] | 59 | |
---|
| 60 | |
---|
| 61 | |
---|
| 62 | -class StreamManager(XMPPHandlerCollection): |
---|
| 63 | +class BaseStreamManager(XMPPHandlerCollection): |
---|
| 64 | """ |
---|
| 65 | Business logic representing a managed XMPP connection. |
---|
| 66 | |
---|
[74] | 67 | @@ -131,43 +131,39 @@ |
---|
[68] | 68 | |
---|
| 69 | @ivar xmlstream: currently managed XML stream |
---|
| 70 | @type xmlstream: L{XmlStream} |
---|
| 71 | + |
---|
| 72 | @ivar logTraffic: if true, log all traffic. |
---|
| 73 | @type logTraffic: C{bool} |
---|
| 74 | + |
---|
| 75 | @ivar _initialized: Whether the stream represented by L{xmlstream} has |
---|
| 76 | been initialized. This is used when caching outgoing |
---|
| 77 | stanzas. |
---|
| 78 | @type _initialized: C{bool} |
---|
| 79 | - @ivar _packetQueue: internal buffer of unsent data. See L{send} for details. |
---|
| 80 | - @type _packetQueue: L{list} |
---|
| 81 | + |
---|
| 82 | @ivar timeout: Default IQ request timeout in seconds. |
---|
| 83 | @type timeout: C{int} |
---|
| 84 | + |
---|
| 85 | @ivar _reactor: A provider of L{IReactorTime} to track timeouts. |
---|
| 86 | """ |
---|
| 87 | + |
---|
| 88 | timeout = None |
---|
| 89 | _reactor = None |
---|
| 90 | |
---|
| 91 | logTraffic = False |
---|
| 92 | |
---|
| 93 | - def __init__(self, factory, reactor=None): |
---|
| 94 | + def __init__(self, reactor=None): |
---|
| 95 | """ |
---|
| 96 | Construct a stream manager. |
---|
| 97 | |
---|
| 98 | - @param factory: The stream factory to connect with. |
---|
| 99 | @param reactor: A provider of L{IReactorTime} to track timeouts. |
---|
| 100 | If not provided, the global reactor will be used. |
---|
| 101 | """ |
---|
| 102 | XMPPHandlerCollection.__init__(self) |
---|
| 103 | + |
---|
| 104 | self.xmlstream = None |
---|
| 105 | self._packetQueue = [] |
---|
| 106 | self._initialized = False |
---|
| 107 | |
---|
| 108 | - factory.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT, self._connected) |
---|
| 109 | - factory.addBootstrap(xmlstream.STREAM_AUTHD_EVENT, self._authd) |
---|
| 110 | - factory.addBootstrap(xmlstream.INIT_FAILED_EVENT, |
---|
| 111 | - self.initializationFailed) |
---|
| 112 | - factory.addBootstrap(xmlstream.STREAM_END_EVENT, self._disconnected) |
---|
| 113 | - self.factory = factory |
---|
| 114 | - |
---|
| 115 | if reactor is None: |
---|
| 116 | from twisted.internet import reactor |
---|
| 117 | self._reactor = reactor |
---|
[74] | 118 | @@ -193,7 +189,7 @@ |
---|
[68] | 119 | handler.connectionInitialized() |
---|
| 120 | |
---|
| 121 | |
---|
| 122 | - def _connected(self, xs): |
---|
| 123 | + def makeConnection(self, xs): |
---|
| 124 | """ |
---|
| 125 | Called when the transport connection has been established. |
---|
| 126 | |
---|
[74] | 127 | @@ -211,13 +207,17 @@ |
---|
[68] | 128 | xs.rawDataInFn = logDataIn |
---|
| 129 | xs.rawDataOutFn = logDataOut |
---|
| 130 | |
---|
| 131 | + xs.addObserver(xmlstream.STREAM_AUTHD_EVENT, |
---|
| 132 | + self.connectionInitialized) |
---|
| 133 | + xs.addObserver(xmlstream.STREAM_END_EVENT, |
---|
| 134 | + self.connectionLost) |
---|
| 135 | self.xmlstream = xs |
---|
| 136 | |
---|
| 137 | for e in list(self): |
---|
| 138 | e.makeConnection(xs) |
---|
| 139 | |
---|
| 140 | |
---|
| 141 | - def _authd(self, xs): |
---|
| 142 | + def connectionInitialized(self, xs): |
---|
| 143 | """ |
---|
| 144 | Called when the stream has been initialized. |
---|
| 145 | |
---|
[74] | 146 | @@ -240,21 +240,8 @@ |
---|
[68] | 147 | e.connectionInitialized() |
---|
| 148 | |
---|
| 149 | |
---|
| 150 | - def initializationFailed(self, reason): |
---|
| 151 | - """ |
---|
| 152 | - Called when stream initialization has failed. |
---|
| 153 | |
---|
| 154 | - Stream initialization has halted, with the reason indicated by |
---|
| 155 | - C{reason}. It may be retried by calling the authenticator's |
---|
| 156 | - C{initializeStream}. See the respective authenticators for details. |
---|
| 157 | - |
---|
| 158 | - @param reason: A failure instance indicating why stream initialization |
---|
| 159 | - failed. |
---|
| 160 | - @type reason: L{failure.Failure} |
---|
| 161 | - """ |
---|
| 162 | - |
---|
| 163 | - |
---|
| 164 | - def _disconnected(self, reason): |
---|
| 165 | + def connectionLost(self, reason): |
---|
| 166 | """ |
---|
| 167 | Called when the stream has been closed. |
---|
| 168 | |
---|
[74] | 169 | @@ -464,6 +451,60 @@ |
---|
[68] | 170 | |
---|
| 171 | |
---|
| 172 | |
---|
| 173 | +class StreamManager(BaseStreamManager): |
---|
| 174 | + """ |
---|
| 175 | + Business logic representing a managed XMPP client connection. |
---|
| 176 | + |
---|
| 177 | + @ivar _packetQueue: internal buffer of unsent data. See L{send} for details. |
---|
| 178 | + @type _packetQueue: L{list} |
---|
| 179 | + """ |
---|
| 180 | + |
---|
| 181 | + def __init__(self, factory, reactor=None): |
---|
| 182 | + """ |
---|
| 183 | + Construct a stream manager. |
---|
| 184 | + |
---|
| 185 | + @param factory: The stream factory to connect with. |
---|
| 186 | + @param reactor: A provider of L{IReactorTime} to track timeouts. |
---|
| 187 | + If not provided, the global reactor will be used. |
---|
| 188 | + """ |
---|
| 189 | + BaseStreamManager.__init__(self, reactor=reactor) |
---|
| 190 | + |
---|
| 191 | + factory.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT, |
---|
| 192 | + self.makeConnection) |
---|
| 193 | + self.factory = factory |
---|
| 194 | + |
---|
| 195 | + |
---|
| 196 | + def makeConnection(self, xs): |
---|
| 197 | + xs.addObserver(xmlstream.INIT_FAILED_EVENT, |
---|
| 198 | + self.initializationFailed) |
---|
| 199 | + BaseStreamManager.makeConnection(self, xs) |
---|
| 200 | + |
---|
| 201 | + |
---|
| 202 | + def initializationFailed(self, reason): |
---|
| 203 | + """ |
---|
| 204 | + Called when stream initialization has failed. |
---|
| 205 | + |
---|
| 206 | + Stream initialization has halted, with the reason indicated by |
---|
| 207 | + C{reason}. It may be retried by calling the authenticator's |
---|
| 208 | + C{initializeStream}. See the respective authenticators for details. |
---|
| 209 | + |
---|
| 210 | + @param reason: A failure instance indicating why stream initialization |
---|
| 211 | + failed. |
---|
| 212 | + @type reason: L{failure.Failure} |
---|
| 213 | + """ |
---|
| 214 | + |
---|
| 215 | + |
---|
| 216 | + |
---|
| 217 | +class ServerStreamManager(BaseStreamManager): |
---|
| 218 | + """ |
---|
| 219 | + Business logic representing a managed server-side XMPP connection. |
---|
| 220 | + """ |
---|
| 221 | + |
---|
| 222 | + def __init__(self, reactor=None): |
---|
| 223 | + BaseStreamManager.__init__(self, reactor=reactor) |
---|
| 224 | + |
---|
| 225 | + |
---|
| 226 | + |
---|
| 227 | class IQHandlerMixin(object): |
---|
| 228 | """ |
---|
| 229 | XMPP subprotocol mixin for handle incoming IQ stanzas. |
---|
| 230 | diff --git a/wokkel/test/helpers.py b/wokkel/test/helpers.py |
---|
| 231 | --- a/wokkel/test/helpers.py |
---|
| 232 | +++ b/wokkel/test/helpers.py |
---|
| 233 | @@ -108,5 +108,5 @@ |
---|
| 234 | factory = DummyFactory() |
---|
| 235 | StreamManager.__init__(self, factory, reactor) |
---|
| 236 | self.stub = XmlStreamStub() |
---|
| 237 | - self._connected(self.stub.xmlstream) |
---|
| 238 | - self._authd(self.stub.xmlstream) |
---|
| 239 | + self.makeConnection(self.stub.xmlstream) |
---|
| 240 | + self.connectionInitialized(self.stub.xmlstream) |
---|
| 241 | diff --git a/wokkel/test/test_client.py b/wokkel/test/test_client.py |
---|
| 242 | --- a/wokkel/test/test_client.py |
---|
| 243 | +++ b/wokkel/test/test_client.py |
---|
| 244 | @@ -38,7 +38,7 @@ |
---|
| 245 | """ |
---|
| 246 | xs = self.client.factory.buildProtocol(None) |
---|
| 247 | self.client.factory.authenticator.jid = JID('user@example.org/test') |
---|
| 248 | - xs.dispatch(xs, xmlstream.STREAM_AUTHD_EVENT) |
---|
| 249 | + self.client.connectionInitialized(xs) |
---|
| 250 | self.assertEquals(JID('user@example.org/test'), self.client.jid) |
---|
| 251 | |
---|
| 252 | |
---|
[74] | 253 | diff --git a/wokkel/test/test_component.py b/wokkel/test/test_component.py |
---|
| 254 | --- a/wokkel/test/test_component.py |
---|
| 255 | +++ b/wokkel/test/test_component.py |
---|
| 256 | @@ -49,11 +49,18 @@ |
---|
| 257 | def __init__(self, *args, **kwargs): |
---|
| 258 | component.Component.__init__(self, *args, **kwargs) |
---|
| 259 | self.factory.clock = Clock() |
---|
| 260 | + self.output = [] |
---|
| 261 | |
---|
| 262 | |
---|
| 263 | def _getConnection(self): |
---|
| 264 | c = FakeConnector(self.factory, None, None) |
---|
| 265 | c.connect() |
---|
| 266 | + xs = self.factory.buildProtocol(None) |
---|
| 267 | + xs.send = self.output.append |
---|
| 268 | + xs.connectionMade() |
---|
| 269 | + self.makeConnection(xs) |
---|
| 270 | + xs.thisEntity = xs.otherEntity |
---|
| 271 | + xs.dispatch(xs, xmlstream.STREAM_AUTHD_EVENT) |
---|
| 272 | return c |
---|
| 273 | |
---|
| 274 | |
---|
| 275 | @@ -104,6 +111,21 @@ |
---|
| 276 | self.assertEqual(1, connector.connects) |
---|
| 277 | |
---|
| 278 | |
---|
| 279 | + def test_stampFrom(self): |
---|
| 280 | + """ |
---|
| 281 | + Outgoing elements with missing sender address get component JID. |
---|
| 282 | + """ |
---|
| 283 | + comp = TestableComponent('example.org', 5347, |
---|
| 284 | + 'test.example.org', 'secret') |
---|
| 285 | + comp.startService() |
---|
| 286 | + |
---|
| 287 | + element = domish.Element((component.NS_COMPONENT_ACCEPT, "message")) |
---|
| 288 | + element["to"] = "test@example.org" |
---|
| 289 | + comp.xmlstream.send(element) |
---|
| 290 | + |
---|
| 291 | + self.assertEqual('test.example.org', element.getAttribute("from")) |
---|
| 292 | + |
---|
| 293 | + |
---|
| 294 | |
---|
| 295 | class InternalComponentTest(unittest.TestCase): |
---|
| 296 | """ |
---|
[68] | 297 | diff --git a/wokkel/test/test_subprotocols.py b/wokkel/test/test_subprotocols.py |
---|
| 298 | --- a/wokkel/test/test_subprotocols.py |
---|
| 299 | +++ b/wokkel/test/test_subprotocols.py |
---|
| 300 | @@ -189,20 +189,7 @@ |
---|
| 301 | |
---|
| 302 | |
---|
| 303 | |
---|
| 304 | -class StreamManagerTest(unittest.TestCase): |
---|
| 305 | - """ |
---|
| 306 | - Tests for L{subprotocols.StreamManager}. |
---|
| 307 | - """ |
---|
| 308 | - |
---|
| 309 | - def setUp(self): |
---|
| 310 | - factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator()) |
---|
| 311 | - self.clock = task.Clock() |
---|
| 312 | - self.streamManager = subprotocols.StreamManager(factory, self.clock) |
---|
| 313 | - self.xmlstream = factory.buildProtocol(None) |
---|
| 314 | - self.transport = proto_helpers.StringTransport() |
---|
| 315 | - self.xmlstream.transport = self.transport |
---|
| 316 | - |
---|
| 317 | - self.request = IQGetStanza() |
---|
| 318 | +class BaseStreamManagerTestsMixin(object): |
---|
| 319 | |
---|
| 320 | def _streamStarted(self): |
---|
| 321 | """ |
---|
| 322 | @@ -216,25 +203,14 @@ |
---|
| 323 | self.xmlstream.dispatch(self.xmlstream, "//event/stream/authd") |
---|
| 324 | |
---|
| 325 | |
---|
| 326 | - def test_basic(self): |
---|
| 327 | + def test_interface(self): |
---|
| 328 | """ |
---|
| 329 | - Test correct initialization and setup of factory observers. |
---|
| 330 | + ServerStreamManager implements IXMPPHandlerCollection. |
---|
| 331 | """ |
---|
| 332 | - factory = DummyFactory() |
---|
| 333 | - sm = subprotocols.StreamManager(factory) |
---|
| 334 | - self.assertIdentical(None, sm.xmlstream) |
---|
| 335 | - self.assertEquals([], sm.handlers) |
---|
| 336 | - self.assertEquals(sm._connected, |
---|
| 337 | - sm.factory.callbacks['//event/stream/connected']) |
---|
| 338 | - self.assertEquals(sm._authd, |
---|
| 339 | - sm.factory.callbacks['//event/stream/authd']) |
---|
| 340 | - self.assertEquals(sm._disconnected, |
---|
| 341 | - sm.factory.callbacks['//event/stream/end']) |
---|
| 342 | - self.assertEquals(sm.initializationFailed, |
---|
| 343 | - sm.factory.callbacks['//event/xmpp/initfailed']) |
---|
| 344 | + verifyObject(ijabber.IXMPPHandlerCollection, self.streamManager) |
---|
| 345 | |
---|
| 346 | |
---|
| 347 | - def test_connected(self): |
---|
| 348 | + def test_makeConnection(self): |
---|
| 349 | """ |
---|
| 350 | Test that protocol handlers have their connectionMade method called |
---|
| 351 | when the XML stream is connected. |
---|
| 352 | @@ -242,27 +218,27 @@ |
---|
| 353 | sm = self.streamManager |
---|
| 354 | handler = DummyXMPPHandler() |
---|
| 355 | handler.setHandlerParent(sm) |
---|
| 356 | - xs = xmlstream.XmlStream(xmlstream.Authenticator()) |
---|
| 357 | - sm._connected(xs) |
---|
| 358 | + xs = self.xmlstream |
---|
| 359 | + sm.makeConnection(xs) |
---|
| 360 | self.assertEquals(1, handler.doneMade) |
---|
| 361 | self.assertEquals(0, handler.doneInitialized) |
---|
| 362 | self.assertEquals(0, handler.doneLost) |
---|
| 363 | |
---|
| 364 | |
---|
| 365 | - def test_connectedLogTrafficFalse(self): |
---|
| 366 | + def test_makeConnectionLogTrafficFalse(self): |
---|
| 367 | """ |
---|
| 368 | Test raw data functions unset when logTraffic is set to False. |
---|
| 369 | """ |
---|
| 370 | sm = self.streamManager |
---|
| 371 | handler = DummyXMPPHandler() |
---|
| 372 | handler.setHandlerParent(sm) |
---|
| 373 | - xs = xmlstream.XmlStream(xmlstream.Authenticator()) |
---|
| 374 | - sm._connected(xs) |
---|
| 375 | + xs = self.xmlstream |
---|
| 376 | + sm.makeConnection(xs) |
---|
| 377 | self.assertIdentical(None, xs.rawDataInFn) |
---|
| 378 | self.assertIdentical(None, xs.rawDataOutFn) |
---|
| 379 | |
---|
| 380 | |
---|
| 381 | - def test_connectedLogTrafficTrue(self): |
---|
| 382 | + def test_makeConnectionLogTrafficTrue(self): |
---|
| 383 | """ |
---|
| 384 | Test raw data functions set when logTraffic is set to True. |
---|
| 385 | """ |
---|
| 386 | @@ -270,13 +246,13 @@ |
---|
| 387 | sm.logTraffic = True |
---|
| 388 | handler = DummyXMPPHandler() |
---|
| 389 | handler.setHandlerParent(sm) |
---|
| 390 | - xs = xmlstream.XmlStream(xmlstream.Authenticator()) |
---|
| 391 | - sm._connected(xs) |
---|
| 392 | + xs = self.xmlstream |
---|
| 393 | + sm.makeConnection(xs) |
---|
| 394 | self.assertNotIdentical(None, xs.rawDataInFn) |
---|
| 395 | self.assertNotIdentical(None, xs.rawDataOutFn) |
---|
| 396 | |
---|
| 397 | |
---|
| 398 | - def test_authd(self): |
---|
| 399 | + def test_connectionInitialized(self): |
---|
| 400 | """ |
---|
| 401 | Test that protocol handlers have their connectionInitialized method |
---|
| 402 | called when the XML stream is initialized. |
---|
| 403 | @@ -284,27 +260,27 @@ |
---|
| 404 | sm = self.streamManager |
---|
| 405 | handler = DummyXMPPHandler() |
---|
| 406 | handler.setHandlerParent(sm) |
---|
| 407 | - xs = xmlstream.XmlStream(xmlstream.Authenticator()) |
---|
| 408 | - sm._authd(xs) |
---|
| 409 | + xs = self.xmlstream |
---|
| 410 | + sm.connectionInitialized(xs) |
---|
| 411 | self.assertEquals(0, handler.doneMade) |
---|
| 412 | self.assertEquals(1, handler.doneInitialized) |
---|
| 413 | self.assertEquals(0, handler.doneLost) |
---|
| 414 | |
---|
| 415 | |
---|
| 416 | - def test_disconnected(self): |
---|
| 417 | + def test_connectionLost(self): |
---|
| 418 | """ |
---|
| 419 | Protocol handlers have connectionLost called on stream disconnect. |
---|
| 420 | """ |
---|
| 421 | sm = self.streamManager |
---|
| 422 | handler = DummyXMPPHandler() |
---|
| 423 | handler.setHandlerParent(sm) |
---|
| 424 | - sm._disconnected(None) |
---|
| 425 | + sm.connectionLost(None) |
---|
| 426 | self.assertEquals(0, handler.doneMade) |
---|
| 427 | self.assertEquals(0, handler.doneInitialized) |
---|
| 428 | self.assertEquals(1, handler.doneLost) |
---|
| 429 | |
---|
| 430 | |
---|
| 431 | - def test_disconnectedReason(self): |
---|
| 432 | + def test_connectionLostReason(self): |
---|
| 433 | """ |
---|
| 434 | A L{STREAM_END_EVENT} results in L{StreamManager} firing the handlers |
---|
| 435 | L{connectionLost} methods, passing a L{failure.Failure} reason. |
---|
| 436 | @@ -313,7 +289,7 @@ |
---|
| 437 | handler = FailureReasonXMPPHandler() |
---|
| 438 | handler.setHandlerParent(sm) |
---|
| 439 | xmlstream.XmlStream(xmlstream.Authenticator()) |
---|
| 440 | - sm._disconnected(failure.Failure(Exception("no reason"))) |
---|
| 441 | + sm.connectionLost(failure.Failure(Exception("no reason"))) |
---|
| 442 | self.assertEquals(True, handler.gotFailureReason) |
---|
| 443 | |
---|
| 444 | |
---|
| 445 | @@ -335,8 +311,8 @@ |
---|
| 446 | Adding a handler when connected doesn't call connectionInitialized. |
---|
| 447 | """ |
---|
| 448 | sm = self.streamManager |
---|
| 449 | - xs = xmlstream.XmlStream(xmlstream.Authenticator()) |
---|
| 450 | - sm._connected(xs) |
---|
| 451 | + xs = self.xmlstream |
---|
| 452 | + sm.makeConnection(xs) |
---|
| 453 | handler = DummyXMPPHandler() |
---|
| 454 | handler.setHandlerParent(sm) |
---|
| 455 | |
---|
| 456 | @@ -358,10 +334,10 @@ |
---|
| 457 | self.nestedHandler.setHandlerParent(self.parent) |
---|
| 458 | |
---|
| 459 | sm = self.streamManager |
---|
| 460 | - xs = xmlstream.XmlStream(xmlstream.Authenticator()) |
---|
| 461 | + xs = self.xmlstream |
---|
| 462 | handler = NestingHandler() |
---|
| 463 | handler.setHandlerParent(sm) |
---|
| 464 | - sm._connected(xs) |
---|
| 465 | + sm.makeConnection(xs) |
---|
| 466 | |
---|
| 467 | self.assertEquals(1, handler.doneMade) |
---|
| 468 | self.assertEquals(0, handler.doneInitialized) |
---|
| 469 | @@ -383,9 +359,9 @@ |
---|
| 470 | called. |
---|
| 471 | """ |
---|
| 472 | sm = self.streamManager |
---|
| 473 | - xs = xmlstream.XmlStream(xmlstream.Authenticator()) |
---|
| 474 | - sm._connected(xs) |
---|
| 475 | - sm._authd(xs) |
---|
| 476 | + xs = self.xmlstream |
---|
| 477 | + sm.makeConnection(xs) |
---|
| 478 | + sm.connectionInitialized(xs) |
---|
| 479 | handler = DummyXMPPHandler() |
---|
| 480 | handler.setHandlerParent(sm) |
---|
| 481 | |
---|
| 482 | @@ -407,11 +383,11 @@ |
---|
| 483 | self.nestedHandler.setHandlerParent(self.parent) |
---|
| 484 | |
---|
| 485 | sm = self.streamManager |
---|
| 486 | - xs = xmlstream.XmlStream(xmlstream.Authenticator()) |
---|
| 487 | + xs = self.xmlstream |
---|
| 488 | handler = NestingHandler() |
---|
| 489 | handler.setHandlerParent(sm) |
---|
| 490 | - sm._connected(xs) |
---|
| 491 | - sm._authd(xs) |
---|
| 492 | + sm.makeConnection(xs) |
---|
| 493 | + sm.connectionInitialized(xs) |
---|
| 494 | |
---|
| 495 | self.assertEquals(1, handler.doneMade) |
---|
| 496 | self.assertEquals(1, handler.doneInitialized) |
---|
| 497 | @@ -435,12 +411,12 @@ |
---|
| 498 | self.nestedHandler.setHandlerParent(self.parent) |
---|
| 499 | |
---|
| 500 | sm = self.streamManager |
---|
| 501 | - xs = xmlstream.XmlStream(xmlstream.Authenticator()) |
---|
| 502 | + xs = self.xmlstream |
---|
| 503 | handler = NestingHandler() |
---|
| 504 | handler.setHandlerParent(sm) |
---|
| 505 | - sm._connected(xs) |
---|
| 506 | - sm._authd(xs) |
---|
| 507 | - sm._disconnected(xs) |
---|
| 508 | + sm.makeConnection(xs) |
---|
| 509 | + sm.connectionInitialized(xs) |
---|
| 510 | + sm.connectionLost(xs) |
---|
| 511 | |
---|
| 512 | self.assertEquals(1, handler.doneMade) |
---|
| 513 | self.assertEquals(1, handler.doneInitialized) |
---|
| 514 | @@ -470,16 +446,13 @@ |
---|
| 515 | |
---|
| 516 | The data should be sent directly over the XML stream. |
---|
| 517 | """ |
---|
| 518 | - factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator()) |
---|
| 519 | - sm = subprotocols.StreamManager(factory) |
---|
| 520 | - xs = factory.buildProtocol(None) |
---|
| 521 | - xs.transport = proto_helpers.StringTransport() |
---|
| 522 | + xs = self.xmlstream |
---|
| 523 | xs.connectionMade() |
---|
| 524 | xs.dataReceived("<stream:stream xmlns='jabber:client' " |
---|
| 525 | "xmlns:stream='http://etherx.jabber.org/streams' " |
---|
| 526 | "from='example.com' id='12345'>") |
---|
| 527 | xs.dispatch(xs, "//event/stream/authd") |
---|
| 528 | - sm.send("<presence/>") |
---|
| 529 | + self.streamManager.send("<presence/>") |
---|
| 530 | self.assertEquals("<presence/>", xs.transport.value()) |
---|
| 531 | |
---|
| 532 | |
---|
| 533 | @@ -490,12 +463,11 @@ |
---|
| 534 | The data should be cached until an XML stream has been established and |
---|
| 535 | initialized. |
---|
| 536 | """ |
---|
| 537 | - factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator()) |
---|
| 538 | - sm = subprotocols.StreamManager(factory) |
---|
| 539 | + sm = self.streamManager |
---|
| 540 | handler = DummyXMPPHandler() |
---|
| 541 | sm.addHandler(handler) |
---|
| 542 | |
---|
| 543 | - xs = factory.buildProtocol(None) |
---|
| 544 | + xs = self.xmlstream |
---|
| 545 | xs.transport = proto_helpers.StringTransport() |
---|
| 546 | sm.send("<presence/>") |
---|
| 547 | self.assertEquals("", xs.transport.value()) |
---|
| 548 | @@ -522,7 +494,7 @@ |
---|
| 549 | """ |
---|
| 550 | factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator()) |
---|
| 551 | sm = subprotocols.StreamManager(factory) |
---|
| 552 | - xs = factory.buildProtocol(None) |
---|
| 553 | + xs = self.xmlstream |
---|
| 554 | xs.transport = proto_helpers.StringTransport() |
---|
| 555 | xs.connectionMade() |
---|
| 556 | xs.dataReceived("<stream:stream xmlns='jabber:client' " |
---|
| 557 | @@ -545,7 +517,7 @@ |
---|
| 558 | handler = DummyXMPPHandler() |
---|
| 559 | sm.addHandler(handler) |
---|
| 560 | |
---|
| 561 | - xs = factory.buildProtocol(None) |
---|
| 562 | + xs = self.xmlstream |
---|
| 563 | xs.connectionMade() |
---|
| 564 | xs.transport = proto_helpers.StringTransport() |
---|
| 565 | xs.connectionLost(None) |
---|
| 566 | @@ -677,6 +649,7 @@ |
---|
| 567 | """ |
---|
| 568 | d = self.streamManager.request(self.request) |
---|
| 569 | xs = self.xmlstream |
---|
| 570 | + xs.connectionMade() |
---|
| 571 | xs.connectionLost(failure.Failure(ConnectionDone())) |
---|
| 572 | self.assertFailure(d, ConnectionDone) |
---|
| 573 | return d |
---|
| 574 | @@ -692,6 +665,7 @@ |
---|
| 575 | d = xmlstream.IQ(self.xmlstream).send() |
---|
| 576 | d.addErrback(eb) |
---|
| 577 | |
---|
| 578 | + self.xmlstream.connectionMade() |
---|
| 579 | d = self.streamManager.request(self.request) |
---|
| 580 | d.addErrback(eb) |
---|
| 581 | self.xmlstream.connectionLost(failure.Failure(ConnectionDone())) |
---|
| 582 | @@ -736,6 +710,7 @@ |
---|
| 583 | self.request.timeout = 60 |
---|
| 584 | d = self.streamManager.request(self.request) |
---|
| 585 | |
---|
| 586 | + self.xmlstream.connectionMade() |
---|
| 587 | self.xmlstream.connectionLost(failure.Failure(ConnectionDone())) |
---|
| 588 | self.assertFailure(d, ConnectionDone) |
---|
| 589 | self.assertFalse(self.clock.calls) |
---|
| 590 | @@ -778,6 +753,56 @@ |
---|
| 591 | |
---|
| 592 | |
---|
| 593 | |
---|
| 594 | +class StreamManagerTest(unittest.TestCase, BaseStreamManagerTestsMixin): |
---|
| 595 | + """ |
---|
| 596 | + Tests for L{subprotocols.StreamManager}. |
---|
| 597 | + """ |
---|
| 598 | + |
---|
| 599 | + def setUp(self): |
---|
| 600 | + factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator()) |
---|
| 601 | + self.clock = task.Clock() |
---|
| 602 | + self.streamManager = subprotocols.StreamManager(factory, self.clock) |
---|
| 603 | + self.xmlstream = factory.buildProtocol(None) |
---|
| 604 | + self.transport = proto_helpers.StringTransport() |
---|
| 605 | + self.xmlstream.transport = self.transport |
---|
| 606 | + |
---|
| 607 | + self.request = IQGetStanza() |
---|
| 608 | + |
---|
| 609 | + |
---|
| 610 | + def test_basic(self): |
---|
| 611 | + """ |
---|
| 612 | + Test correct initialization and setup of factory observers. |
---|
| 613 | + """ |
---|
| 614 | + factory = DummyFactory() |
---|
| 615 | + sm = subprotocols.StreamManager(factory) |
---|
| 616 | + self.assertIdentical(None, sm.xmlstream) |
---|
| 617 | + self.assertEquals([], sm.handlers) |
---|
| 618 | + self.assertEquals(sm.makeConnection, |
---|
| 619 | + sm.factory.callbacks['//event/stream/connected']) |
---|
| 620 | + |
---|
| 621 | + |
---|
| 622 | + |
---|
| 623 | +class ServerStreamManagerTest(unittest.TestCase, BaseStreamManagerTestsMixin): |
---|
| 624 | + """ |
---|
| 625 | + Tests for L{subprotocols.StreamManager}. |
---|
| 626 | + """ |
---|
| 627 | + |
---|
| 628 | + def setUp(self): |
---|
| 629 | + self.clock = task.Clock() |
---|
| 630 | + self.streamManager = subprotocols.ServerStreamManager( |
---|
| 631 | + reactor=self.clock) |
---|
| 632 | + |
---|
| 633 | + self.xmlstream = xmlstream.XmlStream(xmlstream.Authenticator()) |
---|
| 634 | + self.transport = proto_helpers.StringTransport() |
---|
| 635 | + self.xmlstream.transport = self.transport |
---|
| 636 | + |
---|
| 637 | + self.xmlstream.addObserver(xmlstream.STREAM_CONNECTED_EVENT, |
---|
| 638 | + self.streamManager.makeConnection) |
---|
| 639 | + |
---|
| 640 | + self.request = IQGetStanza() |
---|
| 641 | + |
---|
| 642 | + |
---|
| 643 | + |
---|
| 644 | class DummyIQHandler(subprotocols.IQHandlerMixin): |
---|
| 645 | iqHandlers = {'/iq[@type="get"]': 'onGet'} |
---|
| 646 | |
---|