| OLD | NEW |
| (Empty) |
| 1 # Copyright (c) 2001-2008 Twisted Matrix Laboratories. | |
| 2 # See LICENSE for details. | |
| 3 | |
| 4 """ | |
| 5 Tests for L{twisted.words.protocols.jabber.xmlstream}. | |
| 6 """ | |
| 7 | |
| 8 from twisted.trial import unittest | |
| 9 | |
| 10 from zope.interface.verify import verifyObject | |
| 11 | |
| 12 from twisted.internet import defer, task | |
| 13 from twisted.internet.error import ConnectionLost | |
| 14 from twisted.test import proto_helpers | |
| 15 from twisted.words.xish import domish | |
| 16 from twisted.words.protocols.jabber import error, ijabber, jid, xmlstream | |
| 17 | |
| 18 | |
| 19 | |
| 20 NS_XMPP_TLS = 'urn:ietf:params:xml:ns:xmpp-tls' | |
| 21 | |
| 22 | |
| 23 | |
| 24 class IQTest(unittest.TestCase): | |
| 25 """ | |
| 26 Tests both IQ and the associated IIQResponseTracker callback. | |
| 27 """ | |
| 28 | |
| 29 def setUp(self): | |
| 30 authenticator = xmlstream.ConnectAuthenticator('otherhost') | |
| 31 authenticator.namespace = 'testns' | |
| 32 self.xmlstream = xmlstream.XmlStream(authenticator) | |
| 33 self.clock = task.Clock() | |
| 34 self.xmlstream._callLater = self.clock.callLater | |
| 35 self.xmlstream.makeConnection(proto_helpers.StringTransport()) | |
| 36 self.xmlstream.dataReceived( | |
| 37 "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' " | |
| 38 "xmlns='testns' from='otherhost' version='1.0'>") | |
| 39 self.iq = xmlstream.IQ(self.xmlstream, 'get') | |
| 40 | |
| 41 | |
| 42 def testBasic(self): | |
| 43 self.assertEquals(self.iq['type'], 'get') | |
| 44 self.assertTrue(self.iq['id']) | |
| 45 | |
| 46 | |
| 47 def testSend(self): | |
| 48 self.xmlstream.transport.clear() | |
| 49 self.iq.send() | |
| 50 self.assertEquals("<iq type='get' id='%s'/>" % self.iq['id'], | |
| 51 self.xmlstream.transport.value()) | |
| 52 | |
| 53 | |
| 54 def testResultResponse(self): | |
| 55 def cb(result): | |
| 56 self.assertEquals(result['type'], 'result') | |
| 57 | |
| 58 d = self.iq.send() | |
| 59 d.addCallback(cb) | |
| 60 | |
| 61 xs = self.xmlstream | |
| 62 xs.dataReceived("<iq type='result' id='%s'/>" % self.iq['id']) | |
| 63 return d | |
| 64 | |
| 65 | |
| 66 def testErrorResponse(self): | |
| 67 d = self.iq.send() | |
| 68 self.assertFailure(d, error.StanzaError) | |
| 69 | |
| 70 xs = self.xmlstream | |
| 71 xs.dataReceived("<iq type='error' id='%s'/>" % self.iq['id']) | |
| 72 return d | |
| 73 | |
| 74 | |
| 75 def testNonTrackedResponse(self): | |
| 76 """ | |
| 77 Test that untracked iq responses don't trigger any action. | |
| 78 | |
| 79 Untracked means that the id of the incoming response iq is not | |
| 80 in the stream's C{iqDeferreds} dictionary. | |
| 81 """ | |
| 82 xs = self.xmlstream | |
| 83 xmlstream.upgradeWithIQResponseTracker(xs) | |
| 84 | |
| 85 # Make sure we aren't tracking any iq's. | |
| 86 self.failIf(xs.iqDeferreds) | |
| 87 | |
| 88 # Set up a fallback handler that checks the stanza's handled attribute. | |
| 89 # If that is set to True, the iq tracker claims to have handled the | |
| 90 # response. | |
| 91 def cb(iq): | |
| 92 self.failIf(getattr(iq, 'handled', False)) | |
| 93 | |
| 94 xs.addObserver("/iq", cb, -1) | |
| 95 | |
| 96 # Receive an untracked iq response | |
| 97 xs.dataReceived("<iq type='result' id='test'/>") | |
| 98 | |
| 99 | |
| 100 def testCleanup(self): | |
| 101 """ | |
| 102 Test if the deferred associated with an iq request is removed | |
| 103 from the list kept in the L{XmlStream} object after it has | |
| 104 been fired. | |
| 105 """ | |
| 106 | |
| 107 d = self.iq.send() | |
| 108 xs = self.xmlstream | |
| 109 xs.dataReceived("<iq type='result' id='%s'/>" % self.iq['id']) | |
| 110 self.assertNotIn(self.iq['id'], xs.iqDeferreds) | |
| 111 return d | |
| 112 | |
| 113 | |
| 114 def testDisconnectCleanup(self): | |
| 115 """ | |
| 116 Test if deferreds for iq's that haven't yet received a response | |
| 117 have their errback called on stream disconnect. | |
| 118 """ | |
| 119 | |
| 120 d = self.iq.send() | |
| 121 xs = self.xmlstream | |
| 122 xs.connectionLost("Closed by peer") | |
| 123 self.assertFailure(d, ConnectionLost) | |
| 124 return d | |
| 125 | |
| 126 | |
| 127 def testNoModifyingDict(self): | |
| 128 """ | |
| 129 Test to make sure the errbacks cannot cause the iteration of the | |
| 130 iqDeferreds to blow up in our face. | |
| 131 """ | |
| 132 | |
| 133 def eb(failure): | |
| 134 d = xmlstream.IQ(self.xmlstream).send() | |
| 135 d.addErrback(eb) | |
| 136 | |
| 137 d = self.iq.send() | |
| 138 d.addErrback(eb) | |
| 139 self.xmlstream.connectionLost("Closed by peer") | |
| 140 return d | |
| 141 | |
| 142 | |
| 143 def testRequestTimingOut(self): | |
| 144 """ | |
| 145 Test that an iq request with a defined timeout times out. | |
| 146 """ | |
| 147 self.iq.timeout = 60 | |
| 148 d = self.iq.send() | |
| 149 self.assertFailure(d, xmlstream.TimeoutError) | |
| 150 | |
| 151 self.clock.pump([1, 60]) | |
| 152 self.failIf(self.clock.calls) | |
| 153 self.failIf(self.xmlstream.iqDeferreds) | |
| 154 return d | |
| 155 | |
| 156 | |
| 157 def testRequestNotTimingOut(self): | |
| 158 """ | |
| 159 Test that an iq request with a defined timeout does not time out | |
| 160 when a response was received before the timeout period elapsed. | |
| 161 """ | |
| 162 self.iq.timeout = 60 | |
| 163 d = self.iq.send() | |
| 164 self.clock.callLater(1, self.xmlstream.dataReceived, | |
| 165 "<iq type='result' id='%s'/>" % self.iq['id']) | |
| 166 self.clock.pump([1, 1]) | |
| 167 self.failIf(self.clock.calls) | |
| 168 return d | |
| 169 | |
| 170 | |
| 171 def testDisconnectTimeoutCancellation(self): | |
| 172 """ | |
| 173 Test if timeouts for iq's that haven't yet received a response | |
| 174 are cancelled on stream disconnect. | |
| 175 """ | |
| 176 | |
| 177 self.iq.timeout = 60 | |
| 178 d = self.iq.send() | |
| 179 | |
| 180 xs = self.xmlstream | |
| 181 xs.connectionLost("Closed by peer") | |
| 182 self.assertFailure(d, ConnectionLost) | |
| 183 self.failIf(self.clock.calls) | |
| 184 return d | |
| 185 | |
| 186 | |
| 187 | |
| 188 class XmlStreamTest(unittest.TestCase): | |
| 189 | |
| 190 def onStreamStart(self, obj): | |
| 191 self.gotStreamStart = True | |
| 192 | |
| 193 | |
| 194 def onStreamEnd(self, obj): | |
| 195 self.gotStreamEnd = True | |
| 196 | |
| 197 | |
| 198 def onStreamError(self, obj): | |
| 199 self.gotStreamError = True | |
| 200 | |
| 201 | |
| 202 def setUp(self): | |
| 203 """ | |
| 204 Set up XmlStream and several observers. | |
| 205 """ | |
| 206 self.gotStreamStart = False | |
| 207 self.gotStreamEnd = False | |
| 208 self.gotStreamError = False | |
| 209 xs = xmlstream.XmlStream(xmlstream.Authenticator()) | |
| 210 xs.addObserver('//event/stream/start', self.onStreamStart) | |
| 211 xs.addObserver('//event/stream/end', self.onStreamEnd) | |
| 212 xs.addObserver('//event/stream/error', self.onStreamError) | |
| 213 xs.makeConnection(proto_helpers.StringTransportWithDisconnection()) | |
| 214 xs.transport.protocol = xs | |
| 215 xs.namespace = 'testns' | |
| 216 xs.version = (1, 0) | |
| 217 self.xmlstream = xs | |
| 218 | |
| 219 | |
| 220 def test_sendHeaderBasic(self): | |
| 221 """ | |
| 222 Basic test on the header sent by sendHeader. | |
| 223 """ | |
| 224 xs = self.xmlstream | |
| 225 xs.sendHeader() | |
| 226 splitHeader = self.xmlstream.transport.value()[0:-1].split(' ') | |
| 227 self.assertIn("<stream:stream", splitHeader) | |
| 228 self.assertIn("xmlns:stream='http://etherx.jabber.org/streams'", | |
| 229 splitHeader) | |
| 230 self.assertIn("xmlns='testns'", splitHeader) | |
| 231 self.assertIn("version='1.0'", splitHeader) | |
| 232 self.assertTrue(xs._headerSent) | |
| 233 | |
| 234 | |
| 235 def test_sendHeaderAdditionalNamespaces(self): | |
| 236 """ | |
| 237 Test for additional namespace declarations. | |
| 238 """ | |
| 239 xs = self.xmlstream | |
| 240 xs.prefixes['jabber:server:dialback'] = 'db' | |
| 241 xs.sendHeader() | |
| 242 splitHeader = self.xmlstream.transport.value()[0:-1].split(' ') | |
| 243 self.assertIn("<stream:stream", splitHeader) | |
| 244 self.assertIn("xmlns:stream='http://etherx.jabber.org/streams'", | |
| 245 splitHeader) | |
| 246 self.assertIn("xmlns:db='jabber:server:dialback'", splitHeader) | |
| 247 self.assertIn("xmlns='testns'", splitHeader) | |
| 248 self.assertIn("version='1.0'", splitHeader) | |
| 249 self.assertTrue(xs._headerSent) | |
| 250 | |
| 251 | |
| 252 def test_sendHeaderInitiating(self): | |
| 253 """ | |
| 254 Test addressing when initiating a stream. | |
| 255 """ | |
| 256 xs = self.xmlstream | |
| 257 xs.thisEntity = jid.JID('thisHost') | |
| 258 xs.otherEntity = jid.JID('otherHost') | |
| 259 xs.initiating = True | |
| 260 xs.sendHeader() | |
| 261 splitHeader = xs.transport.value()[0:-1].split(' ') | |
| 262 self.assertIn("to='otherhost'", splitHeader) | |
| 263 self.assertIn("from='thishost'", splitHeader) | |
| 264 | |
| 265 | |
| 266 def test_sendHeaderReceiving(self): | |
| 267 """ | |
| 268 Test addressing when receiving a stream. | |
| 269 """ | |
| 270 xs = self.xmlstream | |
| 271 xs.thisEntity = jid.JID('thisHost') | |
| 272 xs.otherEntity = jid.JID('otherHost') | |
| 273 xs.initiating = False | |
| 274 xs.sid = 'session01' | |
| 275 xs.sendHeader() | |
| 276 splitHeader = xs.transport.value()[0:-1].split(' ') | |
| 277 self.assertIn("to='otherhost'", splitHeader) | |
| 278 self.assertIn("from='thishost'", splitHeader) | |
| 279 self.assertIn("id='session01'", splitHeader) | |
| 280 | |
| 281 | |
| 282 def test_receiveStreamError(self): | |
| 283 """ | |
| 284 Test events when a stream error is received. | |
| 285 """ | |
| 286 xs = self.xmlstream | |
| 287 xs.dataReceived("<stream:stream xmlns='jabber:client' " | |
| 288 "xmlns:stream='http://etherx.jabber.org/streams' " | |
| 289 "from='example.com' id='12345' version='1.0'>") | |
| 290 xs.dataReceived("<stream:error/>") | |
| 291 self.assertTrue(self.gotStreamError) | |
| 292 self.assertTrue(self.gotStreamEnd) | |
| 293 | |
| 294 | |
| 295 def test_sendStreamErrorInitiating(self): | |
| 296 """ | |
| 297 Test sendStreamError on an initiating xmlstream with a header sent. | |
| 298 | |
| 299 An error should be sent out and the connection lost. | |
| 300 """ | |
| 301 xs = self.xmlstream | |
| 302 xs.initiating = True | |
| 303 xs.sendHeader() | |
| 304 xs.transport.clear() | |
| 305 xs.sendStreamError(error.StreamError('version-unsupported')) | |
| 306 self.assertNotEqual('', xs.transport.value()) | |
| 307 self.assertTrue(self.gotStreamEnd) | |
| 308 | |
| 309 | |
| 310 def test_sendStreamErrorInitiatingNoHeader(self): | |
| 311 """ | |
| 312 Test sendStreamError on an initiating xmlstream without having sent a | |
| 313 header. | |
| 314 | |
| 315 In this case, no header should be generated. Also, the error should | |
| 316 not be sent out on the stream. Just closing the connection. | |
| 317 """ | |
| 318 xs = self.xmlstream | |
| 319 xs.initiating = True | |
| 320 xs.transport.clear() | |
| 321 xs.sendStreamError(error.StreamError('version-unsupported')) | |
| 322 self.assertNot(xs._headerSent) | |
| 323 self.assertEqual('', xs.transport.value()) | |
| 324 self.assertTrue(self.gotStreamEnd) | |
| 325 | |
| 326 | |
| 327 def test_sendStreamErrorReceiving(self): | |
| 328 """ | |
| 329 Test sendStreamError on a receiving xmlstream with a header sent. | |
| 330 | |
| 331 An error should be sent out and the connection lost. | |
| 332 """ | |
| 333 xs = self.xmlstream | |
| 334 xs.initiating = False | |
| 335 xs.sendHeader() | |
| 336 xs.transport.clear() | |
| 337 xs.sendStreamError(error.StreamError('version-unsupported')) | |
| 338 self.assertNotEqual('', xs.transport.value()) | |
| 339 self.assertTrue(self.gotStreamEnd) | |
| 340 | |
| 341 | |
| 342 def test_sendStreamErrorReceivingNoHeader(self): | |
| 343 """ | |
| 344 Test sendStreamError on a receiving xmlstream without having sent a | |
| 345 header. | |
| 346 | |
| 347 In this case, a header should be generated. Then, the error should | |
| 348 be sent out on the stream followed by closing the connection. | |
| 349 """ | |
| 350 xs = self.xmlstream | |
| 351 xs.initiating = False | |
| 352 xs.transport.clear() | |
| 353 xs.sendStreamError(error.StreamError('version-unsupported')) | |
| 354 self.assertTrue(xs._headerSent) | |
| 355 self.assertNotEqual('', xs.transport.value()) | |
| 356 self.assertTrue(self.gotStreamEnd) | |
| 357 | |
| 358 | |
| 359 def test_reset(self): | |
| 360 """ | |
| 361 Test resetting the XML stream to start a new layer. | |
| 362 """ | |
| 363 xs = self.xmlstream | |
| 364 xs.sendHeader() | |
| 365 stream = xs.stream | |
| 366 xs.reset() | |
| 367 self.assertNotEqual(stream, xs.stream) | |
| 368 self.assertNot(xs._headerSent) | |
| 369 | |
| 370 | |
| 371 def test_send(self): | |
| 372 """ | |
| 373 Test send with various types of objects. | |
| 374 """ | |
| 375 xs = self.xmlstream | |
| 376 xs.send('<presence/>') | |
| 377 self.assertEqual(xs.transport.value(), '<presence/>') | |
| 378 | |
| 379 xs.transport.clear() | |
| 380 el = domish.Element(('testns', 'presence')) | |
| 381 xs.send(el) | |
| 382 self.assertEqual(xs.transport.value(), '<presence/>') | |
| 383 | |
| 384 xs.transport.clear() | |
| 385 el = domish.Element(('http://etherx.jabber.org/streams', 'features')) | |
| 386 xs.send(el) | |
| 387 self.assertEqual(xs.transport.value(), '<stream:features/>') | |
| 388 | |
| 389 | |
| 390 def test_authenticator(self): | |
| 391 """ | |
| 392 Test that the associated authenticator is correctly called. | |
| 393 """ | |
| 394 connectionMadeCalls = [] | |
| 395 streamStartedCalls = [] | |
| 396 associateWithStreamCalls = [] | |
| 397 | |
| 398 class TestAuthenticator: | |
| 399 def connectionMade(self): | |
| 400 connectionMadeCalls.append(None) | |
| 401 | |
| 402 def streamStarted(self, rootElement): | |
| 403 streamStartedCalls.append(rootElement) | |
| 404 | |
| 405 def associateWithStream(self, xs): | |
| 406 associateWithStreamCalls.append(xs) | |
| 407 | |
| 408 a = TestAuthenticator() | |
| 409 xs = xmlstream.XmlStream(a) | |
| 410 self.assertEqual([xs], associateWithStreamCalls) | |
| 411 xs.connectionMade() | |
| 412 self.assertEqual([None], connectionMadeCalls) | |
| 413 xs.dataReceived("<stream:stream xmlns='jabber:client' " | |
| 414 "xmlns:stream='http://etherx.jabber.org/streams' " | |
| 415 "from='example.com' id='12345'>") | |
| 416 self.assertEqual(1, len(streamStartedCalls)) | |
| 417 xs.reset() | |
| 418 self.assertEqual([None], connectionMadeCalls) | |
| 419 | |
| 420 | |
| 421 | |
| 422 class TestError(Exception): | |
| 423 pass | |
| 424 | |
| 425 | |
| 426 | |
| 427 class AuthenticatorTest(unittest.TestCase): | |
| 428 def setUp(self): | |
| 429 self.authenticator = xmlstream.ListenAuthenticator() | |
| 430 self.xmlstream = xmlstream.XmlStream(self.authenticator) | |
| 431 | |
| 432 | |
| 433 def test_streamStart(self): | |
| 434 """ | |
| 435 Test streamStart to fill the appropriate attributes from the | |
| 436 stream header. | |
| 437 """ | |
| 438 xs = self.xmlstream | |
| 439 xs.makeConnection(proto_helpers.StringTransport()) | |
| 440 xs.dataReceived("<stream:stream xmlns='jabber:client' " | |
| 441 "xmlns:stream='http://etherx.jabber.org/streams' " | |
| 442 "from='example.org' to='example.com' id='12345' " | |
| 443 "version='1.0'>") | |
| 444 self.assertEqual((1, 0), xs.version) | |
| 445 self.assertIdentical(None, xs.sid) | |
| 446 self.assertEqual('jabber:client', xs.namespace) | |
| 447 self.assertIdentical(None, xs.otherEntity) | |
| 448 self.assertEqual('example.com', xs.thisEntity.host) | |
| 449 | |
| 450 | |
| 451 def test_streamStartLegacy(self): | |
| 452 """ | |
| 453 Test streamStart to fill the appropriate attributes from the | |
| 454 stream header for a pre-XMPP-1.0 header. | |
| 455 """ | |
| 456 xs = self.xmlstream | |
| 457 xs.makeConnection(proto_helpers.StringTransport()) | |
| 458 xs.dataReceived("<stream:stream xmlns='jabber:client' " | |
| 459 "xmlns:stream='http://etherx.jabber.org/streams' " | |
| 460 "from='example.com' id='12345'>") | |
| 461 self.assertEqual((0, 0), xs.version) | |
| 462 | |
| 463 | |
| 464 def test_streamBadVersionOneDigit(self): | |
| 465 """ | |
| 466 Test streamStart to fill the appropriate attributes from the | |
| 467 stream header for a version with only one digit. | |
| 468 """ | |
| 469 xs = self.xmlstream | |
| 470 xs.makeConnection(proto_helpers.StringTransport()) | |
| 471 xs.dataReceived("<stream:stream xmlns='jabber:client' " | |
| 472 "xmlns:stream='http://etherx.jabber.org/streams' " | |
| 473 "from='example.com' id='12345' version='1'>") | |
| 474 self.assertEqual((0, 0), xs.version) | |
| 475 | |
| 476 | |
| 477 def test_streamBadVersionNoNumber(self): | |
| 478 """ | |
| 479 Test streamStart to fill the appropriate attributes from the | |
| 480 stream header for a malformed version. | |
| 481 """ | |
| 482 xs = self.xmlstream | |
| 483 xs.makeConnection(proto_helpers.StringTransport()) | |
| 484 xs.dataReceived("<stream:stream xmlns='jabber:client' " | |
| 485 "xmlns:stream='http://etherx.jabber.org/streams' " | |
| 486 "from='example.com' id='12345' version='blah'>") | |
| 487 self.assertEqual((0, 0), xs.version) | |
| 488 | |
| 489 | |
| 490 | |
| 491 class ConnectAuthenticatorTest(unittest.TestCase): | |
| 492 | |
| 493 def setUp(self): | |
| 494 self.gotAuthenticated = False | |
| 495 self.initFailure = None | |
| 496 self.authenticator = xmlstream.ConnectAuthenticator('otherHost') | |
| 497 self.xmlstream = xmlstream.XmlStream(self.authenticator) | |
| 498 self.xmlstream.addObserver('//event/stream/authd', self.onAuthenticated) | |
| 499 self.xmlstream.addObserver('//event/xmpp/initfailed', self.onInitFailed) | |
| 500 | |
| 501 | |
| 502 def onAuthenticated(self, obj): | |
| 503 self.gotAuthenticated = True | |
| 504 | |
| 505 | |
| 506 def onInitFailed(self, failure): | |
| 507 self.initFailure = failure | |
| 508 | |
| 509 | |
| 510 def testSucces(self): | |
| 511 """ | |
| 512 Test successful completion of an initialization step. | |
| 513 """ | |
| 514 class Initializer: | |
| 515 def initialize(self): | |
| 516 pass | |
| 517 | |
| 518 init = Initializer() | |
| 519 self.xmlstream.initializers = [init] | |
| 520 | |
| 521 self.authenticator.initializeStream() | |
| 522 self.assertEqual([], self.xmlstream.initializers) | |
| 523 self.assertTrue(self.gotAuthenticated) | |
| 524 | |
| 525 | |
| 526 def testFailure(self): | |
| 527 """ | |
| 528 Test failure of an initialization step. | |
| 529 """ | |
| 530 class Initializer: | |
| 531 def initialize(self): | |
| 532 raise TestError | |
| 533 | |
| 534 init = Initializer() | |
| 535 self.xmlstream.initializers = [init] | |
| 536 | |
| 537 self.authenticator.initializeStream() | |
| 538 self.assertEqual([init], self.xmlstream.initializers) | |
| 539 self.assertFalse(self.gotAuthenticated) | |
| 540 self.assertNotIdentical(None, self.initFailure) | |
| 541 self.assertTrue(self.initFailure.check(TestError)) | |
| 542 | |
| 543 | |
| 544 def test_streamStart(self): | |
| 545 """ | |
| 546 Test streamStart to fill the appropriate attributes from the | |
| 547 stream header. | |
| 548 """ | |
| 549 self.authenticator.namespace = 'testns' | |
| 550 xs = self.xmlstream | |
| 551 xs.makeConnection(proto_helpers.StringTransport()) | |
| 552 xs.dataReceived("<stream:stream xmlns='jabber:client' " | |
| 553 "xmlns:stream='http://etherx.jabber.org/streams' " | |
| 554 "from='example.com' to='example.org' id='12345' " | |
| 555 "version='1.0'>") | |
| 556 self.assertEqual((1, 0), xs.version) | |
| 557 self.assertEqual('12345', xs.sid) | |
| 558 self.assertEqual('testns', xs.namespace) | |
| 559 self.assertEqual('example.com', xs.otherEntity.host) | |
| 560 self.assertIdentical(None, xs.thisEntity) | |
| 561 self.assertNot(self.gotAuthenticated) | |
| 562 xs.dataReceived("<stream:features>" | |
| 563 "<test xmlns='testns'/>" | |
| 564 "</stream:features>") | |
| 565 self.assertIn(('testns', 'test'), xs.features) | |
| 566 self.assertTrue(self.gotAuthenticated) | |
| 567 | |
| 568 | |
| 569 | |
| 570 class ListenAuthenticatorTest(unittest.TestCase): | |
| 571 def setUp(self): | |
| 572 self.authenticator = xmlstream.ListenAuthenticator() | |
| 573 self.xmlstream = xmlstream.XmlStream(self.authenticator) | |
| 574 | |
| 575 | |
| 576 def test_streamStart(self): | |
| 577 """ | |
| 578 Test streamStart to fill the appropriate attributes from the | |
| 579 stream header. | |
| 580 """ | |
| 581 xs = self.xmlstream | |
| 582 xs.makeConnection(proto_helpers.StringTransport()) | |
| 583 xs.dataReceived("<stream:stream xmlns='jabber:client' " | |
| 584 "xmlns:stream='http://etherx.jabber.org/streams' " | |
| 585 "from='example.org' to='example.com' id='12345' " | |
| 586 "version='1.0'>") | |
| 587 self.assertEqual((1, 0), xs.version) | |
| 588 self.assertIdentical(None, xs.sid) | |
| 589 self.assertEqual('jabber:client', xs.namespace) | |
| 590 self.assertIdentical(None, xs.otherEntity) | |
| 591 self.assertEqual('example.com', xs.thisEntity.host) | |
| 592 | |
| 593 | |
| 594 | |
| 595 class TLSInitiatingInitializerTest(unittest.TestCase): | |
| 596 def setUp(self): | |
| 597 self.output = [] | |
| 598 self.done = [] | |
| 599 | |
| 600 self.savedSSL = xmlstream.ssl | |
| 601 | |
| 602 self.authenticator = xmlstream.Authenticator() | |
| 603 self.xmlstream = xmlstream.XmlStream(self.authenticator) | |
| 604 self.xmlstream.send = self.output.append | |
| 605 self.xmlstream.connectionMade() | |
| 606 self.xmlstream.dataReceived("<stream:stream xmlns='jabber:client' " | |
| 607 "xmlns:stream='http://etherx.jabber.org/streams' " | |
| 608 "from='example.com' id='12345' version='1.0'>") | |
| 609 self.init = xmlstream.TLSInitiatingInitializer(self.xmlstream) | |
| 610 | |
| 611 | |
| 612 def tearDown(self): | |
| 613 xmlstream.ssl = self.savedSSL | |
| 614 | |
| 615 | |
| 616 def testWantedSupported(self): | |
| 617 """ | |
| 618 Test start when TLS is wanted and the SSL library available. | |
| 619 """ | |
| 620 self.xmlstream.transport = proto_helpers.StringTransport() | |
| 621 self.xmlstream.transport.startTLS = lambda ctx: self.done.append('TLS') | |
| 622 self.xmlstream.reset = lambda: self.done.append('reset') | |
| 623 self.xmlstream.sendHeader = lambda: self.done.append('header') | |
| 624 | |
| 625 d = self.init.start() | |
| 626 d.addCallback(self.assertEquals, xmlstream.Reset) | |
| 627 starttls = self.output[0] | |
| 628 self.assertEquals('starttls', starttls.name) | |
| 629 self.assertEquals(NS_XMPP_TLS, starttls.uri) | |
| 630 self.xmlstream.dataReceived("<proceed xmlns='%s'/>" % NS_XMPP_TLS) | |
| 631 self.assertEquals(['TLS', 'reset', 'header'], self.done) | |
| 632 | |
| 633 return d | |
| 634 | |
| 635 if not xmlstream.ssl: | |
| 636 testWantedSupported.skip = "SSL not available" | |
| 637 | |
| 638 | |
| 639 def testWantedNotSupportedNotRequired(self): | |
| 640 """ | |
| 641 Test start when TLS is wanted and the SSL library available. | |
| 642 """ | |
| 643 xmlstream.ssl = None | |
| 644 | |
| 645 d = self.init.start() | |
| 646 d.addCallback(self.assertEquals, None) | |
| 647 self.assertEquals([], self.output) | |
| 648 | |
| 649 return d | |
| 650 | |
| 651 | |
| 652 def testWantedNotSupportedRequired(self): | |
| 653 """ | |
| 654 Test start when TLS is wanted and the SSL library available. | |
| 655 """ | |
| 656 xmlstream.ssl = None | |
| 657 self.init.required = True | |
| 658 | |
| 659 d = self.init.start() | |
| 660 self.assertFailure(d, xmlstream.TLSNotSupported) | |
| 661 self.assertEquals([], self.output) | |
| 662 | |
| 663 return d | |
| 664 | |
| 665 | |
| 666 def testNotWantedRequired(self): | |
| 667 """ | |
| 668 Test start when TLS is not wanted, but required by the server. | |
| 669 """ | |
| 670 tls = domish.Element(('urn:ietf:params:xml:ns:xmpp-tls', 'starttls')) | |
| 671 tls.addElement('required') | |
| 672 self.xmlstream.features = {(tls.uri, tls.name): tls} | |
| 673 self.init.wanted = False | |
| 674 | |
| 675 d = self.init.start() | |
| 676 self.assertEquals([], self.output) | |
| 677 self.assertFailure(d, xmlstream.TLSRequired) | |
| 678 | |
| 679 return d | |
| 680 | |
| 681 | |
| 682 def testNotWantedNotRequired(self): | |
| 683 """ | |
| 684 Test start when TLS is not wanted, but required by the server. | |
| 685 """ | |
| 686 tls = domish.Element(('urn:ietf:params:xml:ns:xmpp-tls', 'starttls')) | |
| 687 self.xmlstream.features = {(tls.uri, tls.name): tls} | |
| 688 self.init.wanted = False | |
| 689 | |
| 690 d = self.init.start() | |
| 691 d.addCallback(self.assertEqual, None) | |
| 692 self.assertEquals([], self.output) | |
| 693 return d | |
| 694 | |
| 695 | |
| 696 def testFailed(self): | |
| 697 """ | |
| 698 Test failed TLS negotiation. | |
| 699 """ | |
| 700 # Pretend that ssl is supported, it isn't actually used when the | |
| 701 # server starts out with a failure in response to our initial | |
| 702 # C{starttls} stanza. | |
| 703 xmlstream.ssl = 1 | |
| 704 | |
| 705 d = self.init.start() | |
| 706 self.assertFailure(d, xmlstream.TLSFailed) | |
| 707 self.xmlstream.dataReceived("<failure xmlns='%s'/>" % NS_XMPP_TLS) | |
| 708 return d | |
| 709 | |
| 710 | |
| 711 | |
| 712 class TestFeatureInitializer(xmlstream.BaseFeatureInitiatingInitializer): | |
| 713 feature = ('testns', 'test') | |
| 714 | |
| 715 def start(self): | |
| 716 return defer.succeed(None) | |
| 717 | |
| 718 | |
| 719 | |
| 720 class BaseFeatureInitiatingInitializerTest(unittest.TestCase): | |
| 721 | |
| 722 def setUp(self): | |
| 723 self.xmlstream = xmlstream.XmlStream(xmlstream.Authenticator()) | |
| 724 self.init = TestFeatureInitializer(self.xmlstream) | |
| 725 | |
| 726 | |
| 727 def testAdvertized(self): | |
| 728 """ | |
| 729 Test that an advertized feature results in successful initialization. | |
| 730 """ | |
| 731 self.xmlstream.features = {self.init.feature: | |
| 732 domish.Element(self.init.feature)} | |
| 733 return self.init.initialize() | |
| 734 | |
| 735 | |
| 736 def testNotAdvertizedRequired(self): | |
| 737 """ | |
| 738 Test that when the feature is not advertized, but required by the | |
| 739 initializer, an exception is raised. | |
| 740 """ | |
| 741 self.init.required = True | |
| 742 self.assertRaises(xmlstream.FeatureNotAdvertized, self.init.initialize) | |
| 743 | |
| 744 | |
| 745 def testNotAdvertizedNotRequired(self): | |
| 746 """ | |
| 747 Test that when the feature is not advertized, and not required by the | |
| 748 initializer, the initializer silently succeeds. | |
| 749 """ | |
| 750 self.init.required = False | |
| 751 self.assertIdentical(None, self.init.initialize()) | |
| 752 | |
| 753 | |
| 754 | |
| 755 class ToResponseTest(unittest.TestCase): | |
| 756 | |
| 757 def test_toResponse(self): | |
| 758 """ | |
| 759 Test that a response stanza is generated with addressing swapped. | |
| 760 """ | |
| 761 stanza = domish.Element(('jabber:client', 'iq')) | |
| 762 stanza['type'] = 'get' | |
| 763 stanza['to'] = 'user1@example.com' | |
| 764 stanza['from'] = 'user2@example.com/resource' | |
| 765 stanza['id'] = 'stanza1' | |
| 766 response = xmlstream.toResponse(stanza, 'result') | |
| 767 self.assertNotIdentical(stanza, response) | |
| 768 self.assertEqual(response['from'], 'user1@example.com') | |
| 769 self.assertEqual(response['to'], 'user2@example.com/resource') | |
| 770 self.assertEqual(response['type'], 'result') | |
| 771 self.assertEqual(response['id'], 'stanza1') | |
| 772 | |
| 773 | |
| 774 def test_toResponseNoFrom(self): | |
| 775 """ | |
| 776 Test that a response is generated from a stanza without a from address. | |
| 777 """ | |
| 778 stanza = domish.Element(('jabber:client', 'iq')) | |
| 779 stanza['type'] = 'get' | |
| 780 stanza['to'] = 'user1@example.com' | |
| 781 response = xmlstream.toResponse(stanza) | |
| 782 self.assertEqual(response['from'], 'user1@example.com') | |
| 783 self.failIf(response.hasAttribute('to')) | |
| 784 | |
| 785 | |
| 786 def test_toResponseNoTo(self): | |
| 787 """ | |
| 788 Test that a response is generated from a stanza without a to address. | |
| 789 """ | |
| 790 stanza = domish.Element(('jabber:client', 'iq')) | |
| 791 stanza['type'] = 'get' | |
| 792 stanza['from'] = 'user2@example.com/resource' | |
| 793 response = xmlstream.toResponse(stanza) | |
| 794 self.failIf(response.hasAttribute('from')) | |
| 795 self.assertEqual(response['to'], 'user2@example.com/resource') | |
| 796 | |
| 797 | |
| 798 def test_toResponseNoAddressing(self): | |
| 799 """ | |
| 800 Test that a response is generated from a stanza without any addressing. | |
| 801 """ | |
| 802 stanza = domish.Element(('jabber:client', 'message')) | |
| 803 stanza['type'] = 'chat' | |
| 804 response = xmlstream.toResponse(stanza) | |
| 805 self.failIf(response.hasAttribute('to')) | |
| 806 self.failIf(response.hasAttribute('from')) | |
| 807 | |
| 808 | |
| 809 def test_noID(self): | |
| 810 """ | |
| 811 Test that a proper response is generated without id attribute. | |
| 812 """ | |
| 813 stanza = domish.Element(('jabber:client', 'message')) | |
| 814 response = xmlstream.toResponse(stanza) | |
| 815 self.failIf(response.hasAttribute('id')) | |
| 816 | |
| 817 | |
| 818 | |
| 819 class DummyFactory(object): | |
| 820 """ | |
| 821 Dummy XmlStream factory that only registers bootstrap observers. | |
| 822 """ | |
| 823 def __init__(self): | |
| 824 self.callbacks = {} | |
| 825 | |
| 826 | |
| 827 def addBootstrap(self, event, callback): | |
| 828 self.callbacks[event] = callback | |
| 829 | |
| 830 | |
| 831 | |
| 832 class DummyXMPPHandler(xmlstream.XMPPHandler): | |
| 833 """ | |
| 834 Dummy XMPP subprotocol handler to count the methods are called on it. | |
| 835 """ | |
| 836 def __init__(self): | |
| 837 self.doneMade = 0 | |
| 838 self.doneInitialized = 0 | |
| 839 self.doneLost = 0 | |
| 840 | |
| 841 | |
| 842 def makeConnection(self, xs): | |
| 843 self.connectionMade() | |
| 844 | |
| 845 | |
| 846 def connectionMade(self): | |
| 847 self.doneMade += 1 | |
| 848 | |
| 849 | |
| 850 def connectionInitialized(self): | |
| 851 self.doneInitialized += 1 | |
| 852 | |
| 853 | |
| 854 def connectionLost(self, reason): | |
| 855 self.doneLost += 1 | |
| 856 | |
| 857 | |
| 858 | |
| 859 class XMPPHandlerTest(unittest.TestCase): | |
| 860 """ | |
| 861 Tests for L{xmlstream.XMPPHandler}. | |
| 862 """ | |
| 863 | |
| 864 def test_interface(self): | |
| 865 """ | |
| 866 L{xmlstream.XMPPHandler} implements L{ijabber.IXMPPHandler}. | |
| 867 """ | |
| 868 verifyObject(ijabber.IXMPPHandler, xmlstream.XMPPHandler()) | |
| 869 | |
| 870 | |
| 871 def test_send(self): | |
| 872 """ | |
| 873 Test that data is passed on for sending by the stream manager. | |
| 874 """ | |
| 875 class DummyStreamManager(object): | |
| 876 def __init__(self): | |
| 877 self.outlist = [] | |
| 878 | |
| 879 def send(self, data): | |
| 880 self.outlist.append(data) | |
| 881 | |
| 882 handler = xmlstream.XMPPHandler() | |
| 883 handler.parent = DummyStreamManager() | |
| 884 handler.send('<presence/>') | |
| 885 self.assertEquals(['<presence/>'], handler.parent.outlist) | |
| 886 | |
| 887 | |
| 888 def test_makeConnection(self): | |
| 889 """ | |
| 890 Test that makeConnection saves the XML stream and calls connectionMade. | |
| 891 """ | |
| 892 class TestXMPPHandler(xmlstream.XMPPHandler): | |
| 893 def connectionMade(self): | |
| 894 self.doneMade = True | |
| 895 | |
| 896 handler = TestXMPPHandler() | |
| 897 xs = xmlstream.XmlStream(xmlstream.Authenticator()) | |
| 898 handler.makeConnection(xs) | |
| 899 self.assertTrue(handler.doneMade) | |
| 900 self.assertIdentical(xs, handler.xmlstream) | |
| 901 | |
| 902 | |
| 903 def test_connectionLost(self): | |
| 904 """ | |
| 905 Test that connectionLost forgets the XML stream. | |
| 906 """ | |
| 907 handler = xmlstream.XMPPHandler() | |
| 908 xs = xmlstream.XmlStream(xmlstream.Authenticator()) | |
| 909 handler.makeConnection(xs) | |
| 910 handler.connectionLost(Exception()) | |
| 911 self.assertIdentical(None, handler.xmlstream) | |
| 912 | |
| 913 | |
| 914 | |
| 915 class XMPPHandlerCollectionTest(unittest.TestCase): | |
| 916 """ | |
| 917 Tests for L{xmlstream.XMPPHandlerCollection}. | |
| 918 """ | |
| 919 | |
| 920 def setUp(self): | |
| 921 self.collection = xmlstream.XMPPHandlerCollection() | |
| 922 | |
| 923 | |
| 924 def test_interface(self): | |
| 925 """ | |
| 926 L{xmlstream.StreamManager} implements L{ijabber.IXMPPHandlerCollection}. | |
| 927 """ | |
| 928 verifyObject(ijabber.IXMPPHandlerCollection, self.collection) | |
| 929 | |
| 930 | |
| 931 def test_addHandler(self): | |
| 932 """ | |
| 933 Test the addition of a protocol handler. | |
| 934 """ | |
| 935 handler = DummyXMPPHandler() | |
| 936 handler.setHandlerParent(self.collection) | |
| 937 self.assertIn(handler, self.collection) | |
| 938 self.assertIdentical(self.collection, handler.parent) | |
| 939 | |
| 940 | |
| 941 def test_removeHandler(self): | |
| 942 """ | |
| 943 Test removal of a protocol handler. | |
| 944 """ | |
| 945 handler = DummyXMPPHandler() | |
| 946 handler.setHandlerParent(self.collection) | |
| 947 handler.disownHandlerParent(self.collection) | |
| 948 self.assertNotIn(handler, self.collection) | |
| 949 self.assertIdentical(None, handler.parent) | |
| 950 | |
| 951 | |
| 952 | |
| 953 class StreamManagerTest(unittest.TestCase): | |
| 954 """ | |
| 955 Tests for L{xmlstream.StreamManager}. | |
| 956 """ | |
| 957 | |
| 958 def setUp(self): | |
| 959 factory = DummyFactory() | |
| 960 self.streamManager = xmlstream.StreamManager(factory) | |
| 961 | |
| 962 | |
| 963 def test_basic(self): | |
| 964 """ | |
| 965 Test correct initialization and setup of factory observers. | |
| 966 """ | |
| 967 sm = self.streamManager | |
| 968 self.assertIdentical(None, sm.xmlstream) | |
| 969 self.assertEquals([], sm.handlers) | |
| 970 self.assertEquals(sm._connected, | |
| 971 sm.factory.callbacks['//event/stream/connected']) | |
| 972 self.assertEquals(sm._authd, | |
| 973 sm.factory.callbacks['//event/stream/authd']) | |
| 974 self.assertEquals(sm._disconnected, | |
| 975 sm.factory.callbacks['//event/stream/end']) | |
| 976 self.assertEquals(sm.initializationFailed, | |
| 977 sm.factory.callbacks['//event/xmpp/initfailed']) | |
| 978 | |
| 979 | |
| 980 def test_connected(self): | |
| 981 """ | |
| 982 Test that protocol handlers have their connectionMade method called | |
| 983 when the XML stream is connected. | |
| 984 """ | |
| 985 sm = self.streamManager | |
| 986 handler = DummyXMPPHandler() | |
| 987 handler.setHandlerParent(sm) | |
| 988 xs = xmlstream.XmlStream(xmlstream.Authenticator()) | |
| 989 sm._connected(xs) | |
| 990 self.assertEquals(1, handler.doneMade) | |
| 991 self.assertEquals(0, handler.doneInitialized) | |
| 992 self.assertEquals(0, handler.doneLost) | |
| 993 | |
| 994 | |
| 995 def test_connectedLogTrafficFalse(self): | |
| 996 """ | |
| 997 Test raw data functions unset when logTraffic is set to False. | |
| 998 """ | |
| 999 sm = self.streamManager | |
| 1000 handler = DummyXMPPHandler() | |
| 1001 handler.setHandlerParent(sm) | |
| 1002 xs = xmlstream.XmlStream(xmlstream.Authenticator()) | |
| 1003 sm._connected(xs) | |
| 1004 self.assertIdentical(None, xs.rawDataInFn) | |
| 1005 self.assertIdentical(None, xs.rawDataOutFn) | |
| 1006 | |
| 1007 | |
| 1008 def test_connectedLogTrafficTrue(self): | |
| 1009 """ | |
| 1010 Test raw data functions set when logTraffic is set to True. | |
| 1011 """ | |
| 1012 sm = self.streamManager | |
| 1013 sm.logTraffic = True | |
| 1014 handler = DummyXMPPHandler() | |
| 1015 handler.setHandlerParent(sm) | |
| 1016 xs = xmlstream.XmlStream(xmlstream.Authenticator()) | |
| 1017 sm._connected(xs) | |
| 1018 self.assertNotIdentical(None, xs.rawDataInFn) | |
| 1019 self.assertNotIdentical(None, xs.rawDataOutFn) | |
| 1020 | |
| 1021 | |
| 1022 def test_authd(self): | |
| 1023 """ | |
| 1024 Test that protocol handlers have their connectionInitialized method | |
| 1025 called when the XML stream is initialized. | |
| 1026 """ | |
| 1027 sm = self.streamManager | |
| 1028 handler = DummyXMPPHandler() | |
| 1029 handler.setHandlerParent(sm) | |
| 1030 xs = xmlstream.XmlStream(xmlstream.Authenticator()) | |
| 1031 sm._authd(xs) | |
| 1032 self.assertEquals(0, handler.doneMade) | |
| 1033 self.assertEquals(1, handler.doneInitialized) | |
| 1034 self.assertEquals(0, handler.doneLost) | |
| 1035 | |
| 1036 | |
| 1037 def test_disconnected(self): | |
| 1038 """ | |
| 1039 Test that protocol handlers have their connectionLost method | |
| 1040 called when the XML stream is disconnected. | |
| 1041 """ | |
| 1042 sm = self.streamManager | |
| 1043 handler = DummyXMPPHandler() | |
| 1044 handler.setHandlerParent(sm) | |
| 1045 xs = xmlstream.XmlStream(xmlstream.Authenticator()) | |
| 1046 sm._disconnected(xs) | |
| 1047 self.assertEquals(0, handler.doneMade) | |
| 1048 self.assertEquals(0, handler.doneInitialized) | |
| 1049 self.assertEquals(1, handler.doneLost) | |
| 1050 | |
| 1051 | |
| 1052 def test_addHandler(self): | |
| 1053 """ | |
| 1054 Test the addition of a protocol handler while not connected. | |
| 1055 """ | |
| 1056 sm = self.streamManager | |
| 1057 handler = DummyXMPPHandler() | |
| 1058 handler.setHandlerParent(sm) | |
| 1059 | |
| 1060 self.assertEquals(0, handler.doneMade) | |
| 1061 self.assertEquals(0, handler.doneInitialized) | |
| 1062 self.assertEquals(0, handler.doneLost) | |
| 1063 | |
| 1064 | |
| 1065 def test_addHandlerInitialized(self): | |
| 1066 """ | |
| 1067 Test the addition of a protocol handler after the stream | |
| 1068 have been initialized. | |
| 1069 | |
| 1070 Make sure that the handler will have the connected stream | |
| 1071 passed via C{makeConnection} and have C{connectionInitialized} | |
| 1072 called. | |
| 1073 """ | |
| 1074 sm = self.streamManager | |
| 1075 xs = xmlstream.XmlStream(xmlstream.Authenticator()) | |
| 1076 sm._connected(xs) | |
| 1077 sm._authd(xs) | |
| 1078 handler = DummyXMPPHandler() | |
| 1079 handler.setHandlerParent(sm) | |
| 1080 | |
| 1081 self.assertEquals(1, handler.doneMade) | |
| 1082 self.assertEquals(1, handler.doneInitialized) | |
| 1083 self.assertEquals(0, handler.doneLost) | |
| 1084 | |
| 1085 | |
| 1086 def test_sendInitialized(self): | |
| 1087 """ | |
| 1088 Test send when the stream has been initialized. | |
| 1089 | |
| 1090 The data should be sent directly over the XML stream. | |
| 1091 """ | |
| 1092 factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator()) | |
| 1093 sm = xmlstream.StreamManager(factory) | |
| 1094 xs = factory.buildProtocol(None) | |
| 1095 xs.transport = proto_helpers.StringTransport() | |
| 1096 xs.connectionMade() | |
| 1097 xs.dataReceived("<stream:stream xmlns='jabber:client' " | |
| 1098 "xmlns:stream='http://etherx.jabber.org/streams' " | |
| 1099 "from='example.com' id='12345'>") | |
| 1100 xs.dispatch(xs, "//event/stream/authd") | |
| 1101 sm.send("<presence/>") | |
| 1102 self.assertEquals("<presence/>", xs.transport.value()) | |
| 1103 | |
| 1104 | |
| 1105 def test_sendNotConnected(self): | |
| 1106 """ | |
| 1107 Test send when there is no established XML stream. | |
| 1108 | |
| 1109 The data should be cached until an XML stream has been established and | |
| 1110 initialized. | |
| 1111 """ | |
| 1112 factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator()) | |
| 1113 sm = xmlstream.StreamManager(factory) | |
| 1114 handler = DummyXMPPHandler() | |
| 1115 sm.addHandler(handler) | |
| 1116 | |
| 1117 xs = factory.buildProtocol(None) | |
| 1118 xs.transport = proto_helpers.StringTransport() | |
| 1119 sm.send("<presence/>") | |
| 1120 self.assertEquals("", xs.transport.value()) | |
| 1121 self.assertEquals("<presence/>", sm._packetQueue[0]) | |
| 1122 | |
| 1123 xs.connectionMade() | |
| 1124 self.assertEquals("", xs.transport.value()) | |
| 1125 self.assertEquals("<presence/>", sm._packetQueue[0]) | |
| 1126 | |
| 1127 xs.dataReceived("<stream:stream xmlns='jabber:client' " | |
| 1128 "xmlns:stream='http://etherx.jabber.org/streams' " | |
| 1129 "from='example.com' id='12345'>") | |
| 1130 xs.dispatch(xs, "//event/stream/authd") | |
| 1131 | |
| 1132 self.assertEquals("<presence/>", xs.transport.value()) | |
| 1133 self.failIf(sm._packetQueue) | |
| 1134 | |
| 1135 | |
| 1136 def test_sendNotInitialized(self): | |
| 1137 """ | |
| 1138 Test send when the stream is connected but not yet initialized. | |
| 1139 | |
| 1140 The data should be cached until the XML stream has been initialized. | |
| 1141 """ | |
| 1142 factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator()) | |
| 1143 sm = xmlstream.StreamManager(factory) | |
| 1144 xs = factory.buildProtocol(None) | |
| 1145 xs.transport = proto_helpers.StringTransport() | |
| 1146 xs.connectionMade() | |
| 1147 xs.dataReceived("<stream:stream xmlns='jabber:client' " | |
| 1148 "xmlns:stream='http://etherx.jabber.org/streams' " | |
| 1149 "from='example.com' id='12345'>") | |
| 1150 sm.send("<presence/>") | |
| 1151 self.assertEquals("", xs.transport.value()) | |
| 1152 self.assertEquals("<presence/>", sm._packetQueue[0]) | |
| 1153 | |
| 1154 | |
| 1155 def test_sendDisconnected(self): | |
| 1156 """ | |
| 1157 Test send after XML stream disconnection. | |
| 1158 | |
| 1159 The data should be cached until a new XML stream has been established | |
| 1160 and initialized. | |
| 1161 """ | |
| 1162 factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator()) | |
| 1163 sm = xmlstream.StreamManager(factory) | |
| 1164 handler = DummyXMPPHandler() | |
| 1165 sm.addHandler(handler) | |
| 1166 | |
| 1167 xs = factory.buildProtocol(None) | |
| 1168 xs.connectionMade() | |
| 1169 xs.transport = proto_helpers.StringTransport() | |
| 1170 xs.connectionLost(None) | |
| 1171 | |
| 1172 sm.send("<presence/>") | |
| 1173 self.assertEquals("", xs.transport.value()) | |
| 1174 self.assertEquals("<presence/>", sm._packetQueue[0]) | |
| OLD | NEW |