diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/test_plugins.py | 162 | ||||
-rw-r--r-- | tests/test_stanza_xep_0009.py | 26 | ||||
-rw-r--r-- | tests/test_stanza_xep_0047.py | 90 | ||||
-rw-r--r-- | tests/test_stanza_xep_0085.py | 6 | ||||
-rw-r--r-- | tests/test_stanza_xep_0184.py | 38 | ||||
-rw-r--r-- | tests/test_stream_filters.py | 88 | ||||
-rw-r--r-- | tests/test_stream_presence.py | 12 | ||||
-rw-r--r-- | tests/test_stream_roster.py | 132 | ||||
-rw-r--r-- | tests/test_stream_xep_0030.py | 16 | ||||
-rw-r--r-- | tests/test_stream_xep_0047.py | 180 |
10 files changed, 729 insertions, 21 deletions
diff --git a/tests/test_plugins.py b/tests/test_plugins.py new file mode 100644 index 00000000..6220d7a5 --- /dev/null +++ b/tests/test_plugins.py @@ -0,0 +1,162 @@ +import unittest +import logging + +from sleekxmpp.plugins.base import PluginManager, BasePlugin, register_plugin + + +class A(BasePlugin): + name = 'a' + + +class B(BasePlugin): + name = 'b' + + +class C(BasePlugin): + name = 'c' + dependencies = set(['b', 'd']) + + +class D(BasePlugin): + name = 'd' + dependencies = set(['c']) + + +class E(BasePlugin): + name = 'e' + dependencies = set(['a', 'd']) + +class F(BasePlugin): + name = 'f' + dependencies = set(['a', 'b']) + + +register_plugin(A) +register_plugin(B) +register_plugin(C) +register_plugin(D) +register_plugin(E) +register_plugin(F) + + +class TestPlugins(unittest.TestCase): + + + def test_enable(self): + """Enable a single plugin.""" + p = PluginManager(None) + + events = [] + + def init(self): + events.append('init') + + A.plugin_init = init + + p.enable('a') + + self.assertEqual(len(p), 1, "Wrong number of enabled plugins.") + self.assertEqual(events, ['init'], "Plugin init method not called.") + + def test_disable(self): + """Disable a single plugin.""" + p = PluginManager(None) + + events = [] + + def init(self): + events.append('init') + + def end(self): + events.append('end') + + A.plugin_init = init + A.plugin_end = end + + p.enable('a') + p.disable('a') + + self.assertEqual(len(p), 0, "Wrong number of enabled plugins.") + self.assertEqual(events, ['init', 'end'], + "Plugin lifecycle methods not called.") + + def test_enable_dependencies(self): + """Enable a plugin with acyclic dependencies.""" + p = PluginManager(None) + + events = [] + + A.plugin_init = lambda s: events.append('init_a') + B.plugin_init = lambda s: events.append('init_b') + + p.enable('f') + + self.assertEqual(len(p), 3, "Wrong number of enabled plugins.") + self.assertTrue('init_a' in events, "Dependency A not enabled.") + self.assertTrue('init_b' in events, "Dependency B not enabled.") + + def test_enable_cyclic_dependencies(self): + """Enable a plugin with cyclic dependencies.""" + + p = PluginManager(None) + + events = [] + + B.plugin_init = lambda s: events.append('init_b') + C.plugin_init = lambda s: events.append('init_c') + D.plugin_init = lambda s: events.append('init_d') + + p.enable('c') + + self.assertEqual(len(p), 3, "Wrong number of enabled plugins.") + self.assertTrue('init_b' in events, "Dependency B not enabled.") + self.assertTrue('init_c' in events, "Dependency C not enabled.") + self.assertTrue('init_d' in events, "Dependency D not enabled.") + + def test_disable_dependendents(self): + """Disable a plugin with dependents.""" + + p = PluginManager(None) + + events = [] + + A.plugin_end = lambda s: events.append('end_a') + B.plugin_end = lambda s: events.append('end_b') + F.plugin_end = lambda s: events.append('end_f') + + p.enable('f') + p.disable('a') + + self.assertEqual(len(p), 1, "Wrong number of enabled plugins.") + self.assertTrue('end_f' in events, "Dependent F not disabled.") + self.assertTrue('end_a' in events, "Plugin A not disabled.") + + def test_disable_cyclic_dependents(self): + """Disable a plugin with cyclic dependents.""" + + p = PluginManager(None) + + events = [] + + B.plugin_end = lambda s: events.append('end_b') + C.plugin_end = lambda s: events.append('end_c') + D.plugin_end = lambda s: events.append('end_d') + + p.enable('c') + p.disable('b') + + self.assertEqual(len(p), 0, "Wrong number of enabled plugins.") + self.assertTrue('end_b' in events, "Plugin B not disabled.") + self.assertTrue('end_c' in events, "Dependent C not disabled.") + self.assertTrue('end_d' in events, "Dependent D not disabled.") + + + +suite = unittest.TestLoader().loadTestsFromTestCase(TestPlugins) + +if __name__ == '__main__': + logging.basicConfig(level=logging.DEBUG, + format='%(levelname)-8s %(message)s') + + tests = unittest.TestSuite([suite]) + unittest.TextTestRunner(verbosity=2).run(tests) diff --git a/tests/test_stanza_xep_0009.py b/tests/test_stanza_xep_0009.py index 36800335..fa1ed19b 100644 --- a/tests/test_stanza_xep_0009.py +++ b/tests/test_stanza_xep_0009.py @@ -1,3 +1,5 @@ +# -*- encoding:utf-8 -*- + """ SleekXMPP: The Sleek XMPP Library Copyright (C) 2011 Nathanael C. Fritz, Dann Martens (TOMOTON). @@ -6,7 +8,10 @@ See the file LICENSE for copying permission. """ +from __future__ import unicode_literals + import base64 +import sys from sleekxmpp.plugins.xep_0009.stanza.RPC import RPCQuery, MethodCall, \ MethodResponse @@ -19,6 +24,9 @@ from sleekxmpp.xmlstream.tostring import tostring import unittest +if sys.version_info > (3, 0): + unicode = str + class TestJabberRPC(SleekTest): @@ -114,6 +122,24 @@ class TestJabberRPC(SleekTest): self.assertEqual(params, xml2py(expected_xml), "XML to string conversion") + def testConvertUnicodeString(self): + params = ["おはよう"] + params_xml = py2xml(*params) + expected_xml = self.parse_xml(""" + <params xmlns="jabber:iq:rpc"> + <param> + <value> + <string>おはよう</string> + </value> + </param> + </params> + """) + self.assertTrue(self.compare(expected_xml, params_xml), + "String to XML conversion\nExpected: %s\nGot: %s" % ( + tostring(expected_xml), tostring(params_xml))) + self.assertEqual(params, xml2py(expected_xml), + "XML to string conversion") + def testConvertInteger(self): params = [32767, -32768] params_xml = py2xml(*params) diff --git a/tests/test_stanza_xep_0047.py b/tests/test_stanza_xep_0047.py new file mode 100644 index 00000000..6aa2314b --- /dev/null +++ b/tests/test_stanza_xep_0047.py @@ -0,0 +1,90 @@ +from sleekxmpp.test import * +from sleekxmpp.plugins.xep_0047 import Data + + +class TestIBB(SleekTest): + + def setUp(self): + register_stanza_plugin(Iq, Data) + + def testInvalidBase64MidEqual(self): + """ + Test detecting invalid base64 data with = inside the + character data instead of at the end. + """ + iq = Iq(xml=ET.fromstring(""" + <iq type="set" id="0" to="tester@localhost"> + <data xmlns="http://jabber.org/protocol/ibb" seq="0"> + ABC=DEFGH + </data> + </iq> + """)) + + errored = False + + try: + data = iq['ibb_data']['data'] + except XMPPError: + errored = True + + self.assertTrue(errored, "ABC=DEFGH did not raise base64 error") + + def testInvalidBase64PrefixEqual(self): + """ + Test detecting invalid base64 data with = as a prefix + to the character data. + """ + iq = Iq(xml=ET.fromstring(""" + <iq type="set" id="0" to="tester@localhost"> + <data xmlns="http://jabber.org/protocol/ibb" seq="0"> + =ABCDEFGH + </data> + </iq> + """)) + + errored = False + + try: + data = iq['ibb_data']['data'] + except XMPPError: + errored = True + + self.assertTrue(errored, "=ABCDEFGH did not raise base64 error") + + def testInvalidBase64Alphabet(self): + """ + Test detecting invalid base64 data with characters + outside of the base64 alphabet. + """ + iq = Iq(xml=ET.fromstring(""" + <iq type="set" id="0" to="tester@localhost"> + <data xmlns="http://jabber.org/protocol/ibb" seq="0"> + ABCD?EFGH + </data> + </iq> + """)) + + errored = False + + try: + data = iq['ibb_data']['data'] + except XMPPError: + errored = True + + self.assertTrue(errored, "ABCD?EFGH did not raise base64 error") + + def testConvertData(self): + """Test that data is converted to base64""" + iq = Iq() + iq['type'] = 'set' + iq['ibb_data']['seq'] = 0 + iq['ibb_data']['data'] = 'sleekxmpp' + + self.check(iq, """ + <iq type="set"> + <data xmlns="http://jabber.org/protocol/ibb" seq="0">c2xlZWt4bXBw</data> + </iq> + """) + + +suite = unittest.TestLoader().loadTestsFromTestCase(TestIBB) diff --git a/tests/test_stanza_xep_0085.py b/tests/test_stanza_xep_0085.py index b08404e2..61784e47 100644 --- a/tests/test_stanza_xep_0085.py +++ b/tests/test_stanza_xep_0085.py @@ -4,7 +4,11 @@ import sleekxmpp.plugins.xep_0085 as xep_0085 class TestChatStates(SleekTest): def setUp(self): - register_stanza_plugin(Message, xep_0085.ChatState) + register_stanza_plugin(Message, xep_0085.stanza.Active) + register_stanza_plugin(Message, xep_0085.stanza.Composing) + register_stanza_plugin(Message, xep_0085.stanza.Gone) + register_stanza_plugin(Message, xep_0085.stanza.Inactive) + register_stanza_plugin(Message, xep_0085.stanza.Paused) def testCreateChatState(self): """Testing creating chat states.""" diff --git a/tests/test_stanza_xep_0184.py b/tests/test_stanza_xep_0184.py new file mode 100644 index 00000000..13472373 --- /dev/null +++ b/tests/test_stanza_xep_0184.py @@ -0,0 +1,38 @@ +from sleekxmpp.test import * +import sleekxmpp.plugins.xep_0184 as xep_0184 + + +class TestReciept(SleekTest): + + def setUp(self): + register_stanza_plugin(Message, xep_0184.Request) + register_stanza_plugin(Message, xep_0184.Received) + + def testCreateRequest(self): + request = """ + <message> + <request xmlns="urn:xmpp:receipts" /> + </message> + """ + + msg = self.Message() + + self.assertEqual(msg['request_receipt'], False) + + msg['request_receipt'] = True + self.check(msg, request) + + def testCreateReceived(self): + received = """ + <message> + <received xmlns="urn:xmpp:receipts" id="1" /> + </message> + """ + + msg = self.Message() + + msg['receipt'] = '1' + self.check(msg, received) + + +suite = unittest.TestLoader().loadTestsFromTestCase(TestReciept) diff --git a/tests/test_stream_filters.py b/tests/test_stream_filters.py new file mode 100644 index 00000000..ef4d5dc8 --- /dev/null +++ b/tests/test_stream_filters.py @@ -0,0 +1,88 @@ +import time + +from sleekxmpp import Message +from sleekxmpp.test import * +from sleekxmpp.xmlstream.handler import * +from sleekxmpp.xmlstream.matcher import * + + +class TestFilters(SleekTest): + + """ + Test using incoming and outgoing filters. + """ + + def setUp(self): + self.stream_start() + + def tearDown(self): + self.stream_close() + + def testIncoming(self): + + data = [] + + def in_filter(stanza): + if isinstance(stanza, Message): + if stanza['body'] == 'testing': + stanza['subject'] = stanza['body'] + ' filter' + print('>>> %s' % stanza['subject']) + return stanza + + def on_message(msg): + print('<<< %s' % msg['subject']) + data.append(msg['subject']) + + self.xmpp.add_filter('in', in_filter) + self.xmpp.add_event_handler('message', on_message) + + self.recv(""" + <message> + <body>no filter</body> + </message> + """) + + self.recv(""" + <message> + <body>testing</body> + </message> + """) + + time.sleep(0.5) + + self.assertEqual(data, ['', 'testing filter'], + 'Incoming filter did not apply %s' % data) + + def testOutgoing(self): + + def out_filter(stanza): + if isinstance(stanza, Message): + if stanza['body'] == 'testing': + stanza['body'] = 'changed!' + return stanza + + self.xmpp.add_filter('out', out_filter) + + m1 = self.Message() + m1['body'] = 'testing' + m1.send() + + m2 = self.Message() + m2['body'] = 'blah' + m2.send() + + self.send(""" + <message> + <body>changed!</body> + </message> + """) + + self.send(""" + <message> + <body>blah</body> + </message> + """) + + + +suite = unittest.TestLoader().loadTestsFromTestCase(TestFilters) diff --git a/tests/test_stream_presence.py b/tests/test_stream_presence.py index 63ccb043..4f2ede16 100644 --- a/tests/test_stream_presence.py +++ b/tests/test_stream_presence.py @@ -7,6 +7,9 @@ class TestStreamPresence(SleekTest): Test handling roster updates. """ + def setUp(self): + self.stream_start(jid='tester@localhost', plugins=[]) + def tearDown(self): self.stream_close() @@ -25,7 +28,6 @@ class TestStreamPresence(SleekTest): # The presence_unavailable event should be triggered. events.add('unavailable') - self.stream_start() self.xmpp.add_event_handler('got_offline', got_offline) self.xmpp.add_event_handler('presence_unavailable', unavailable) @@ -48,7 +50,6 @@ class TestStreamPresence(SleekTest): def got_offline(presence): events.append('got_offline') - self.stream_start() self.xmpp.add_event_handler('got_offline', got_offline) # Setup roster. Use a 'set' instead of 'result' so we @@ -98,7 +99,6 @@ class TestStreamPresence(SleekTest): def got_online(p): events.add('got_online') - self.stream_start() self.xmpp.add_event_handler('presence_available', presence_available) self.xmpp.add_event_handler('got_online', got_online) @@ -128,7 +128,6 @@ class TestStreamPresence(SleekTest): def changed_subscription(p): events.add('changed_subscription') - self.stream_start(jid='tester@localhost') self.xmpp.add_event_handler('changed_subscription', changed_subscription) @@ -175,8 +174,6 @@ class TestStreamPresence(SleekTest): def changed_subscription(p): events.add('changed_subscription') - self.stream_start(jid='tester@localhost') - self.xmpp.add_event_handler('changed_subscription', changed_subscription) self.xmpp.add_event_handler('presence_subscribe', @@ -205,8 +202,6 @@ class TestStreamPresence(SleekTest): events = [] - self.stream_start() - ptypes = ['available', 'away', 'dnd', 'xa', 'chat', 'unavailable', 'subscribe', 'subscribed', 'unsubscribe', 'unsubscribed'] @@ -254,7 +249,6 @@ class TestStreamPresence(SleekTest): def test_changed_status(self): """Test that the changed_status event is handled properly.""" events = [] - self.stream_start() def changed_status(presence): events.append(presence['type']) diff --git a/tests/test_stream_roster.py b/tests/test_stream_roster.py index 1f83f0ec..2d0da173 100644 --- a/tests/test_stream_roster.py +++ b/tests/test_stream_roster.py @@ -104,6 +104,74 @@ class TestStreamRoster(SleekTest): self.failUnless('roster_update' in events, "Roster updated event not triggered: %s" % events) + def testRosterPushRemove(self): + """Test handling roster item removal updates.""" + self.stream_start(mode='client') + events = [] + + # Add roster item + self.recv(""" + <iq to='tester@localhost' type="set" id="1"> + <query xmlns="jabber:iq:roster"> + <item jid="user@localhost" + name="User" + subscription="both"> + <group>Friends</group> + <group>Examples</group> + </item> + </query> + </iq> + """) + self.send(""" + <iq type="result" id="1"> + <query xmlns="jabber:iq:roster" /> + </iq> + """) + + self.assertTrue('user@localhost' in self.xmpp.client_roster) + + # Receive item remove push + self.recv(""" + <iq to='tester@localhost' type="set" id="1"> + <query xmlns="jabber:iq:roster"> + <item jid="user@localhost" + subscription="remove"> + </item> + </query> + </iq> + """) + self.send(""" + <iq type="result" id="1"> + <query xmlns="jabber:iq:roster" /> + </iq> + """) + + self.assertTrue('user@localhost' not in self.xmpp.client_roster) + + def testUnauthorizedRosterPush(self): + """Test rejecting a roster push from an unauthorized source.""" + self.stream_start() + self.recv(""" + <iq to='tester@localhost' from="malicious_user@localhost" + type="set" id="1"> + <query xmlns="jabber:iq:roster"> + <item jid="user@localhost" + name="User" + subscription="both"> + <group>Friends</group> + <group>Examples</group> + </item> + </query> + </iq> + """) + self.send(""" + <iq to="malicious_user@localhost" type="error" id="1"> + <error type="cancel" code="503"> + <service-unavailable xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" /> + </error> + </iq> + """) + def testRosterTimeout(self): """Test handling a timed out roster request.""" self.stream_start() @@ -125,7 +193,8 @@ class TestStreamRoster(SleekTest): # Since get_roster blocks, we need to run it in a thread. t = threading.Thread(name='get_roster', target=self.xmpp.get_roster, - kwargs={str('callback'): roster_callback}) + kwargs={str('block'): False, + str('callback'): roster_callback}) t.start() self.send(""" @@ -157,7 +226,7 @@ class TestStreamRoster(SleekTest): def testRosterUnicode(self): """Test that JIDs with Unicode values are handled properly.""" - self.stream_start() + self.stream_start(plugins=[]) self.recv(""" <iq to="tester@localhost" type="set" id="1"> <query xmlns="jabber:iq:roster"> @@ -198,7 +267,7 @@ class TestStreamRoster(SleekTest): def testSendLastPresence(self): """Test that sending the last presence works.""" - self.stream_start() + self.stream_start(plugins=[]) self.xmpp.send_presence(pshow='dnd') self.xmpp.auto_authorize = True self.xmpp.auto_subscribe = True @@ -226,5 +295,62 @@ class TestStreamRoster(SleekTest): </presence> """) + def testUnsupportedRosterVer(self): + """Test working with a server without roster versioning.""" + self.stream_start() + self.assertTrue('rosterver' not in self.xmpp.features) + + t = threading.Thread(name='get_roster', target=self.xmpp.get_roster) + t.start() + self.send(""" + <iq type="get" id="1"> + <query xmlns="jabber:iq:roster" /> + </iq> + """) + self.recv(""" + <iq to="tester@localhost" type="result" id="1" /> + """) + + t.join() + + def testBootstrapRosterVer(self): + """Test bootstrapping with roster versioning.""" + self.stream_start() + self.xmpp.features.add('rosterver') + self.xmpp.client_roster.version = '' + + t = threading.Thread(name='get_roster', target=self.xmpp.get_roster) + t.start() + self.send(""" + <iq type="get" id="1"> + <query xmlns="jabber:iq:roster" ver="" /> + </iq> + """) + self.recv(""" + <iq to="tester@localhost" type="result" id="1" /> + """) + + t.join() + + + def testExistingRosterVer(self): + """Test using a stored roster version.""" + self.stream_start() + self.xmpp.features.add('rosterver') + self.xmpp.client_roster.version = '42' + + t = threading.Thread(name='get_roster', target=self.xmpp.get_roster) + t.start() + self.send(""" + <iq type="get" id="1"> + <query xmlns="jabber:iq:roster" ver="42" /> + </iq> + """) + self.recv(""" + <iq to="tester@localhost" type="result" id="1" /> + """) + + t.join() + suite = unittest.TestLoader().loadTestsFromTestCase(TestStreamRoster) diff --git a/tests/test_stream_xep_0030.py b/tests/test_stream_xep_0030.py index 1666d3a1..dd43778a 100644 --- a/tests/test_stream_xep_0030.py +++ b/tests/test_stream_xep_0030.py @@ -122,7 +122,7 @@ class TestStreamDisco(SleekTest): self.stream_start(mode='client', plugins=['xep_0030']) - def dynamic_jid(jid, node, iq): + def dynamic_jid(jid, node, ifrom, iq): result = self.xmpp['xep_0030'].stanza.DiscoInfo() result['node'] = node result.add_identity('client', 'console', name='Dynamic Info') @@ -158,7 +158,7 @@ class TestStreamDisco(SleekTest): jid='tester.localhost', plugins=['xep_0030']) - def dynamic_global(jid, node, iq): + def dynamic_global(jid, node, ifrom, iq): result = self.xmpp['xep_0030'].stanza.DiscoInfo() result['node'] = node result.add_identity('component', 'generic', name='Dynamic Info') @@ -194,7 +194,7 @@ class TestStreamDisco(SleekTest): self.stream_start(mode='client', plugins=['xep_0030']) - def dynamic_jid(jid, node, iq): + def dynamic_jid(jid, node, ifrom, iq): result = self.xmpp['xep_0030'].stanza.DiscoInfo() result['node'] = node result.add_identity('client', 'console', name='Dynamic Info') @@ -236,7 +236,7 @@ class TestStreamDisco(SleekTest): jid='tester.localhost', plugins=['xep_0030']) - def dynamic_global(jid, node, iq): + def dynamic_global(jid, node, ifrom, iq): result = self.xmpp['xep_0030'].stanza.DiscoInfo() result['node'] = node result.add_identity('component', 'generic', name='Dynamic Info') @@ -325,7 +325,7 @@ class TestStreamDisco(SleekTest): self.stream_start(mode='client', plugins=['xep_0030']) - def dynamic_jid(jid, node, iq): + def dynamic_jid(jid, node, ifrom, iq): result = self.xmpp['xep_0030'].stanza.DiscoItems() result['node'] = node result.add_item('tester@localhost', node='foo', name='JID') @@ -359,7 +359,7 @@ class TestStreamDisco(SleekTest): jid='tester.localhost', plugins=['xep_0030']) - def dynamic_global(jid, node, iq): + def dynamic_global(jid, node, ifrom, iq): result = self.xmpp['xep_0030'].stanza.DiscoItems() result['node'] = node result.add_item('tester@localhost', node='foo', name='Global') @@ -393,7 +393,7 @@ class TestStreamDisco(SleekTest): self.stream_start(mode='client', plugins=['xep_0030']) - def dynamic_jid(jid, node, iq): + def dynamic_jid(jid, node, ifrom, iq): result = self.xmpp['xep_0030'].stanza.DiscoItems() result['node'] = node result.add_item('tester@localhost', node='foo', name='Global') @@ -435,7 +435,7 @@ class TestStreamDisco(SleekTest): jid='tester.localhost', plugins=['xep_0030']) - def dynamic_global(jid, node, iq): + def dynamic_global(jid, node, ifrom, iq): result = self.xmpp['xep_0030'].stanza.DiscoItems() result['node'] = node result.add_item('tester.localhost', node='foo', name='Global') diff --git a/tests/test_stream_xep_0047.py b/tests/test_stream_xep_0047.py new file mode 100644 index 00000000..d8cdd6a3 --- /dev/null +++ b/tests/test_stream_xep_0047.py @@ -0,0 +1,180 @@ +import threading +import time + +from sleekxmpp.test import * + + +class TestInBandByteStreams(SleekTest): + + def setUp(self): + self.stream_start(plugins=['xep_0047', 'xep_0030']) + + def tearDown(self): + self.stream_close() + + def testOpenStream(self): + """Test requesting a stream, successfully""" + + events = [] + + def on_stream_start(stream): + events.append('ibb_stream_start') + + + self.xmpp.add_event_handler('ibb_stream_start', on_stream_start) + + t = threading.Thread(name='open_stream', + target=self.xmpp['xep_0047'].open_stream, + args=('tester@localhost/receiver',), + kwargs={'sid': 'testing'}) + t.start() + + self.send(""" + <iq type="set" to="tester@localhost/receiver" id="1"> + <open xmlns="http://jabber.org/protocol/ibb" + sid="testing" + block-size="4096" + stanza="iq" /> + </iq> + """) + + self.recv(""" + <iq type="result" id="1" + to="tester@localhost" + from="tester@localhost/receiver" /> + """) + + t.join() + + time.sleep(0.2) + + self.assertEqual(events, ['ibb_stream_start']) + + def testAysncOpenStream(self): + """Test requesting a stream, aysnc""" + + events = set() + + def on_stream_start(stream): + events.add('ibb_stream_start') + + def stream_callback(iq): + events.add('callback') + + self.xmpp.add_event_handler('ibb_stream_start', on_stream_start) + + t = threading.Thread(name='open_stream', + target=self.xmpp['xep_0047'].open_stream, + args=('tester@localhost/receiver',), + kwargs={'sid': 'testing', + 'block': False, + 'callback': stream_callback}) + t.start() + + self.send(""" + <iq type="set" to="tester@localhost/receiver" id="1"> + <open xmlns="http://jabber.org/protocol/ibb" + sid="testing" + block-size="4096" + stanza="iq" /> + </iq> + """) + + self.recv(""" + <iq type="result" id="1" + to="tester@localhost" + from="tester@localhost/receiver" /> + """) + + t.join() + + time.sleep(0.2) + + self.assertEqual(events, set(['ibb_stream_start', 'callback'])) + + def testSendData(self): + """Test sending data over an in-band bytestream.""" + + streams = [] + data = [] + + def on_stream_start(stream): + streams.append(stream) + + def on_stream_data(d): + data.append(d['data']) + + self.xmpp.add_event_handler('ibb_stream_start', on_stream_start) + self.xmpp.add_event_handler('ibb_stream_data', on_stream_data) + + t = threading.Thread(name='open_stream', + target=self.xmpp['xep_0047'].open_stream, + args=('tester@localhost/receiver',), + kwargs={'sid': 'testing'}) + t.start() + + self.send(""" + <iq type="set" to="tester@localhost/receiver" id="1"> + <open xmlns="http://jabber.org/protocol/ibb" + sid="testing" + block-size="4096" + stanza="iq" /> + </iq> + """) + + self.recv(""" + <iq type="result" id="1" + to="tester@localhost" + from="tester@localhost/receiver" /> + """) + + t.join() + + time.sleep(0.2) + + stream = streams[0] + + + # Test sending data out + stream.send("Testing") + + self.send(""" + <iq type="set" id="2" + from="tester@localhost" + to="tester@localhost/receiver"> + <data xmlns="http://jabber.org/protocol/ibb" + seq="0" + sid="testing"> + VGVzdGluZw== + </data> + </iq> + """) + + self.recv(""" + <iq type="result" id="2" + to="tester@localhost" + from="tester@localhost/receiver" /> + """) + + # Test receiving data + self.recv(""" + <iq type="set" id="A" + to="tester@localhost" + from="tester@localhost/receiver"> + <data xmlns="http://jabber.org/protocol/ibb" + seq="0" + sid="testing"> + aXQgd29ya3Mh + </data> + </iq> + """) + + self.send(""" + <iq type="result" id="A" + to="tester@localhost/receiver" /> + """) + + self.assertEqual(data, ['it works!']) + + +suite = unittest.TestLoader().loadTestsFromTestCase(TestInBandByteStreams) |