def test_invisible_on_connect_fail(q, bus, conn, stream): props = conn.Properties.GetAll(cs.CONN_IFACE_SIMPLE_PRESENCE) assertNotEquals({}, props['Statuses']) presence_event_pattern = EventPattern('stream-presence') q.forbid_events([presence_event_pattern]) conn.SimplePresence.SetPresence("hidden", "") conn.Connect() stream.handle_get_all_privacy_lists(q, bus, conn) create_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set') # Check its name assertNotEquals([], xpath.queryForNodes('/query/list/item/presence-out', create_list.query)) acknowledge_iq(stream, create_list.stanza) set_active = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set') active = xpath.queryForNodes('//active', set_active.query)[0] assertEquals('invisible', active['name']) send_error_reply(stream, set_active.stanza) q.unforbid_events([presence_event_pattern]) # Darn! At least we should have our presence set to DND. q.expect_many( EventPattern('dbus-signal', signal='PresencesChanged', interface=cs.CONN_IFACE_SIMPLE_PRESENCE, args=[{1: (6, 'dnd', '')}]), EventPattern('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]))
def test_error(q, bus, conn, stream): assertContains(cs.CONN_IFACE_POWER_SAVING, conn.Get(cs.CONN, "Interfaces", dbus_interface=cs.PROPERTIES_IFACE)) assertEquals (False, conn.Get(cs.CONN_IFACE_POWER_SAVING, "PowerSavingActive", dbus_interface=cs.PROPERTIES_IFACE)) call_async(q, conn.PowerSaving, 'SetPowerSaving', True) stanza = expect_command(q, 'enable') error = domish.Element((None, 'error')) error.addElement((ns.STANZA, 'service-unavailable')) send_error_reply(stream, stanza, error) q.expect('dbus-error', method='SetPowerSaving', name=cs.NOT_AVAILABLE) # Power saving state should remain false assertEquals (False, conn.Get(cs.CONN_IFACE_POWER_SAVING, "PowerSavingActive", dbus_interface=cs.PROPERTIES_IFACE))
def test(q, bus, conn, stream): expect_and_handle_get_vcard(q, stream) sync_stream(q, stream) call_async(q, conn.Avatars, 'SetAvatar', b'william shatner', 'image/x-actor-name') # Gabble request the last version of the vCard before changing it expect_and_handle_get_vcard(q, stream) set_vcard_event = q.expect('stream-iq', query_ns=ns.VCARD_TEMP, query_name='vCard', iq_type='set') iq = set_vcard_event.stanza error = domish.Element((None, 'error')) error['code'] = '400' error['type'] = 'modify' error.addElement((ns.STANZA, 'bad-request')) send_error_reply(stream, iq, error) event = q.expect('dbus-error', method='SetAvatar') assert event.error.get_dbus_name() == cs.INVALID_ARGUMENT, \ event.error.get_dbus_name()
def test_invisible_on_connect_fail_no_list(q, bus, conn, stream): props = conn.Properties.GetAll(cs.CONN_IFACE_SIMPLE_PRESENCE) assertNotEquals({}, props['Statuses']) presence_event_pattern = EventPattern('stream-presence') q.forbid_events([presence_event_pattern]) conn.SimplePresence.SetPresence("hidden", "") conn.Connect() stream.handle_get_all_privacy_lists(q, bus, conn) get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='get') list_node = xpath.queryForNodes('//list', get_list.query)[0] assertEquals('invisible', list_node['name']) send_error_reply(stream, get_list.stanza) q.unforbid_events([presence_event_pattern]) # Darn! At least we should have our presence set to DND. q.expect_many( EventPattern('dbus-signal', signal='PresencesChanged', interface=cs.CONN_IFACE_SIMPLE_PRESENCE, args=[{1: (6, 'dnd', '')}]), EventPattern('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])) # 'hidden' should not be an available status. assertDoesNotContain("hidden", conn.Properties.Get(cs.CONN_IFACE_SIMPLE_PRESENCE, "Statuses"))
def test(q, bus, conn, stream): conn.Connect() expect_and_handle_get_vcard(q, stream) sync_stream(q, stream) call_async(q, conn.Avatars, 'SetAvatar', 'william shatner', 'image/x-actor-name') # Gabble request the last version of the vCard before changing it expect_and_handle_get_vcard(q, stream) set_vcard_event = q.expect('stream-iq', query_ns=ns.VCARD_TEMP, query_name='vCard', iq_type='set') iq = set_vcard_event.stanza error = domish.Element((None, 'error')) error['code'] = '400' error['type'] = 'modify' error.addElement((ns.STANZA, 'bad-request')) send_error_reply(stream, iq, error) event = q.expect('dbus-error', method='SetAvatar') assert event.error.get_dbus_name() == cs.INVALID_ARGUMENT, \ event.error.get_dbus_name()
def test_create_invisible_list(q, bus, conn, stream): conn.SimplePresence.SetPresence("away", "") conn.Connect() stream.handle_get_all_privacy_lists(q, bus, conn) get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='get') list_node = xpath.queryForNodes('//list', get_list.query)[0] assertEquals('invisible', list_node['name']) error = domish.Element((None, 'error')) error['type'] = 'cancel' error.addElement((ns.STANZA, 'item-not-found')) send_error_reply (stream, get_list.stanza, error) create_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set') list_node = xpath.queryForNodes('//list', create_list.query)[0] assertEquals('invisible', list_node['name']) assertNotEquals([], xpath.queryForNodes('/query/list/item/presence-out', create_list.query)) acknowledge_iq(stream, create_list.stanza) q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]) assertContains("hidden", conn.Properties.Get(cs.CONN_IFACE_SIMPLE_PRESENCE, "Statuses"))
def test_create_invisible_list_failed(q, bus, conn, stream): conn.SimplePresence.SetPresence("away", "") conn.Connect() stream.handle_get_all_privacy_lists(q, bus, conn) get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='get') list_node = xpath.queryForNodes('//list', get_list.query)[0] assertEquals('invisible', list_node['name']) error = domish.Element((None, 'error')) error['type'] = 'cancel' error.addElement((ns.STANZA, 'item-not-found')) send_error_reply(stream, get_list.stanza, error) create_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set') list_node = xpath.queryForNodes('//list', create_list.query)[0] assertEquals('invisible', list_node['name']) assertNotEquals([], xpath.queryForNodes('/query/list/item/presence-out', create_list.query)) send_error_reply(stream, create_list.stanza) q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]) assertDoesNotContain( "hidden", conn.Properties.Get(cs.CONN_IFACE_SIMPLE_PRESENCE, "Statuses"))
def test_error(q, bus, conn, stream): assertContains( cs.CONN_IFACE_POWER_SAVING, conn.Get(cs.CONN, "Interfaces", dbus_interface=cs.PROPERTIES_IFACE)) assertEquals( False, conn.Get(cs.CONN_IFACE_POWER_SAVING, "PowerSavingActive", dbus_interface=cs.PROPERTIES_IFACE)) call_async(q, conn.PowerSaving, 'SetPowerSaving', True) stanza = expect_command(q, 'enable') error = domish.Element((None, 'error')) error.addElement((ns.STANZA, 'service-unavailable')) send_error_reply(stream, stanza, error) q.expect('dbus-error', method='SetPowerSaving', name=cs.NOT_AVAILABLE) # Power saving state should remain false assertEquals( False, conn.Get(cs.CONN_IFACE_POWER_SAVING, "PowerSavingActive", dbus_interface=cs.PROPERTIES_IFACE))
def expect_get_and_send_item_not_found(q, stream): get_vcard_event = q.expect('stream-iq', query_ns=ns.VCARD_TEMP, query_name='vCard', iq_type='get') error = domish.Element((None, 'error')) error['type'] = 'cancel' error.addElement((ns.STANZA, 'item-not-found')) send_error_reply(stream, get_vcard_event.stanza, error)
def test(q, bus, conn, stream): statuses = conn.Properties.Get(cs.CONN_IFACE_SIMPLE_PRESENCE, 'Statuses') # testbusy and testaway are provided by test plugin assertContains('testbusy', statuses) assertContains('testaway', statuses) assertEquals(statuses['testbusy'][0], cs.PRESENCE_BUSY) assertEquals(statuses['testaway'][0], cs.PRESENCE_AWAY) conn.SimplePresence.SetPresence('testbusy', '') conn.Connect() # ... gabble asks for all the available lists on the server ... stream.handle_get_all_privacy_lists( q, bus, conn, lists=["foo-list", "test-busy-list", "bar-list"]) # ... gabble checks whether there's usable invisible list on the server ... get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='get') list_node = xpath.queryForNodes('//list', get_list.query)[0] assertEquals('invisible', list_node['name']) error = domish.Element((None, 'error')) error['type'] = 'cancel' error.addElement((ns.STANZA, 'item-not-found')) send_error_reply(stream, get_list.stanza, error) # ... since there is none, Gabble creates it ... create_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set') list_node = xpath.queryForNodes('//list', create_list.query)[0] assertEquals('invisible', list_node['name']) assertNotEquals([], xpath.queryForNodes('/query/list/item/presence-out', create_list.query)) acknowledge_iq(stream, create_list.stanza) get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set') list_node = xpath.queryForNodes('//active', get_list.query)[0] # ... and then activates the one linked with the requested status # Note: testbusy status is linked to test-busy-list by test plugin assertEquals('test-busy-list', list_node['name']) acknowledge_iq(stream, get_list.stanza) q.expect('dbus-signal', signal='PresencesChanged', args=[{ 1: (cs.PRESENCE_BUSY, u'testbusy', '') }]) q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]) # ... testaway is not supposed to be settable on us call_async(q, conn.SimplePresence, 'SetPresence', 'testaway', '') q.expect('dbus-error', method='SetPresence', name=cs.INVALID_ARGUMENT)
def forbidden(q, stream, conn): iq = call_create(q, conn, 'notforyou.localhost') e = domish.Element((None, 'error')) e['type'] = 'cancel' e.addElement((ns.STANZA, 'forbidden')) send_error_reply(stream, iq, e) event = q.expect('dbus-error', method='CreateChannel') assertDBusError(cs.PERMISSION_DENIED, event.error)
def not_a_search_server(q, stream, conn): iq = call_create(q, conn, 'notajud.localhost') e = domish.Element((None, 'error')) e['type'] = 'cancel' e.addElement((ns.STANZA, 'service-unavailable')) send_error_reply(stream, iq, e) event = q.expect('dbus-error', method='CreateChannel') assertDBusError(cs.NOT_AVAILABLE, event.error)
def invalid_jid(q, stream, conn): iq = call_create(q, conn, 'invalid.localhost') e = domish.Element((None, 'error')) e['type'] = 'cancel' e.addElement((ns.STANZA, 'jid-malformed')) send_error_reply(stream, iq, e) event = q.expect('dbus-error', method='CreateChannel') assertDBusError(cs.INVALID_ARGUMENT, event.error)
def test_conflict(q, bus, conn, stream): iq = connect_and_send_form(q, conn, stream) error = domish.Element((None, 'error')) error['code'] = '409' error['type'] = 'cancel' error.addElement((ns.STANZA, 'conflict')) send_error_reply(stream, iq, error) q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_DISCONNECTED, cs.CSR_NAME_IN_USE])
def _cb_bare_jid_disco_iq(self, iq): """ \o\ /o/ <o/ \o> /o> ... "Crap! It's the cops! Turn the music off!" """ send_error_reply(self, iq, error_stanza=elem('error')( elem(ns.STANZA, 'feature-not-implemented'), elem(ns.STANZA, 'text')( u'No, officer! This is certainly not an illegal party.') ))
def test_not_acceptable(q, gateways_iface, stream): call_async(q, gateways_iface, 'Register', 'fully-captcha-enabled.example.com', 'lalala', 'stoats') e = q.expect('stream-iq', iq_type='set', query_name='query', query_ns=ns.REGISTER, to='fully-captcha-enabled.example.com') assertEquals('lalala', xpath.queryForString('/query/username', e.query)) assertEquals('stoats', xpath.queryForString('/query/password', e.query)) error = domish.Element((None, 'error')) error['type'] = 'modify' error['code'] = '406' error.addElement((ns.STANZA, 'not-acceptable')) send_error_reply(stream, e.stanza, error) q.expect('dbus-error', method='Register', name=cs.NOT_AVAILABLE)
def test_conflict(q, gateways_iface, stream): call_async(q, gateways_iface, 'Register', 'sip.example.com', '8675309', 'jenny') e = q.expect('stream-iq', iq_type='set', query_name='query', query_ns=ns.REGISTER, to='sip.example.com') assertEquals('8675309', xpath.queryForString('/query/username', e.query)) assertEquals('jenny', xpath.queryForString('/query/password', e.query)) error = domish.Element((None, 'error')) error['type'] = 'cancel' error['code'] = '409' error.addElement((ns.STANZA, 'conflict')) send_error_reply(stream, e.stanza, error) q.expect('dbus-error', method='Register', name=cs.REGISTRATION_EXISTS)
def test_invisible_on_connect_fails(q, bus, conn, stream): conn.SimplePresence.SetPresence("hidden", "") conn.Connect() event = q.expect('stream-iq', query_name='invisible') send_error_reply(stream, event.stanza) # Darn! At least we should have our presence set to DND. q.expect_many( EventPattern('dbus-signal', signal='PresencesChanged', interface=cs.CONN_IFACE_SIMPLE_PRESENCE, args=[{1: (6, 'dnd', '')}]), EventPattern('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]))
def test_conflict(q, bus, conn, stream): iq = connect_and_send_form(q, conn, stream) error = domish.Element((None, 'error')) error['code'] = '409' error['type'] = 'cancel' error.addElement((ns.STANZA, 'conflict')) send_error_reply(stream, iq, error) e = q.expect('dbus-signal', signal='ConnectionError') assertEquals(cs.REGISTRATION_EXISTS, e.args[0]) q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_DISCONNECTED, cs.CSR_NAME_IN_USE])
def test_invisible_fails(q, bus, conn, stream): assertContains("hidden", conn.Properties.Get(cs.CONN_IFACE_SIMPLE_PRESENCE, "Statuses")) conn.SimplePresence.SetPresence("hidden", "") # First we send an <invisible/> command. event = q.expect('stream-iq', query_name='invisible') send_error_reply(stream, event.stanza) # When that fails, we should expect our status to change to dnd. q.expect('dbus-signal', signal='PresencesChanged', interface=cs.CONN_IFACE_SIMPLE_PRESENCE, args=[{1: (6, 'dnd', '')}])
def test(q, bus, conn, stream): statuses = conn.Properties.Get(cs.CONN_IFACE_SIMPLE_PRESENCE, 'Statuses') # testbusy and testaway are provided by test plugin assertContains('testbusy', statuses) assertContains('testaway', statuses) assertEquals(statuses['testbusy'][0], cs.PRESENCE_BUSY) assertEquals(statuses['testaway'][0], cs.PRESENCE_AWAY) conn.SimplePresence.SetPresence('testbusy', '') conn.Connect() # ... gabble asks for all the available lists on the server ... stream.handle_get_all_privacy_lists(q, bus, conn, lists=["foo-list", "test-busy-list", "bar-list"]) # ... gabble checks whether there's usable invisible list on the server ... get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='get') list_node = xpath.queryForNodes('//list', get_list.query)[0] assertEquals('invisible', list_node['name']) error = domish.Element((None, 'error')) error['type'] = 'cancel' error.addElement((ns.STANZA, 'item-not-found')) send_error_reply (stream, get_list.stanza, error) # ... since there is none, Gabble creates it ... create_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set') list_node = xpath.queryForNodes('//list', create_list.query)[0] assertEquals('invisible', list_node['name']) assertNotEquals([], xpath.queryForNodes('/query/list/item/presence-out', create_list.query)) acknowledge_iq(stream, create_list.stanza) get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set') list_node = xpath.queryForNodes('//active', get_list.query)[0] # ... and then activates the one linked with the requested status # Note: testbusy status is linked to test-busy-list by test plugin assertEquals('test-busy-list', list_node['name']) acknowledge_iq(stream, get_list.stanza) q.expect('dbus-signal', signal='PresencesChanged', args=[{1L: (cs.PRESENCE_BUSY, u'testbusy', '')}])
def proxy_error(q, bus, conn, stream): # Test if another proxy is queried if a query failed connect_and_announce_alice(q, bus, conn, stream) send_file_to_alice(q, conn) return_event, e1, e2, e3 = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), EventPattern('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS), EventPattern('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS), EventPattern('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS)) # Return errors for all the requests; the bugged proxies shouldn't be queried again q.forbid_events([EventPattern('stream-iq', to=e1.stanza['to'], iq_type='get', query_ns=ns.BYTESTREAMS)]) send_error_reply(stream, e1.stanza) # the fourth proxy is queried q.expect('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS) q.forbid_events([EventPattern('stream-iq', to=e2.stanza['to'], iq_type='get', query_ns=ns.BYTESTREAMS)]) send_error_reply(stream, e2.stanza) sync_stream(q, stream) q.forbid_events([EventPattern('stream-iq', to=e3.stanza['to'], iq_type='get', query_ns=ns.BYTESTREAMS)]) send_error_reply(stream, e3.stanza) sync_stream(q, stream)
def test_invisible_on_connect_fail(q, bus, conn, stream): props = conn.Properties.GetAll(cs.CONN_IFACE_SIMPLE_PRESENCE) assertNotEquals({}, props['Statuses']) presence_event_pattern = EventPattern('stream-presence') q.forbid_events([presence_event_pattern]) conn.SimplePresence.SetPresence("hidden", "") conn.Connect() stream.handle_get_all_privacy_lists(q, bus, conn) create_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set') # Check its name assertNotEquals([], xpath.queryForNodes('/query/list/item/presence-out', create_list.query)) acknowledge_iq(stream, create_list.stanza) set_active = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set') active = xpath.queryForNodes('//active', set_active.query)[0] assertEquals('invisible', active['name']) send_error_reply(stream, set_active.stanza) q.unforbid_events([presence_event_pattern]) # Darn! At least we should have our presence set to DND. q.expect_many( EventPattern('dbus-signal', signal='PresencesChanged', interface=cs.CONN_IFACE_SIMPLE_PRESENCE, args=[{ 1: (6, 'dnd', '') }]), EventPattern('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]))
def returns_error_from_search(q, stream, conn): server = 'nofunforyou.localhost' iq = call_create(q, conn, server) result = make_result_iq(stream, iq) query = result.firstChildElement() query.addElement("first") stream.send(result) event = q.expect('dbus-return', method='CreateChannel') c = make_channel_proxy(conn, event.value[0], 'Channel') c_search = dbus.Interface(c, cs.CHANNEL_TYPE_CONTACT_SEARCH) call_async(q, c_search, 'Search', {'x-n-given': 'World of Goo'}) iq_event, _ = q.expect_many( EventPattern('stream-iq', to=server, query_ns=ns.SEARCH), EventPattern('dbus-signal', signal='SearchStateChanged'), ) iq = iq_event.stanza error = domish.Element((None, 'error')) error['type'] = 'modify' error.addElement((ns.STANZA, 'not-acceptable')) error.addElement((ns.STANZA, 'text'), content="We don't believe in games here.") send_error_reply(stream, iq, error) ssc = q.expect('dbus-signal', signal='SearchStateChanged') new_state, reason, details = ssc.args assert new_state == cs.SEARCH_FAILED, new_state assert reason == cs.PERMISSION_DENIED, reason # We call stop after the search has failed; it should succeed and do nothing. call_async(q, c_search, 'Stop') event = q.expect('dbus-return', method='Stop') c.Close()
def test_invisible_on_connect_fail_no_list(q, bus, conn, stream): props = conn.Properties.GetAll(cs.CONN_IFACE_SIMPLE_PRESENCE) assertNotEquals({}, props['Statuses']) presence_event_pattern = EventPattern('stream-presence') q.forbid_events([presence_event_pattern]) conn.SimplePresence.SetPresence("hidden", "") conn.Connect() stream.handle_get_all_privacy_lists(q, bus, conn) get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='get') list_node = xpath.queryForNodes('//list', get_list.query)[0] assertEquals('invisible', list_node['name']) send_error_reply(stream, get_list.stanza) q.unforbid_events([presence_event_pattern]) # Darn! At least we should have our presence set to DND. q.expect_many( EventPattern('dbus-signal', signal='PresencesChanged', interface=cs.CONN_IFACE_SIMPLE_PRESENCE, args=[{ 1: (6, 'dnd', '') }]), EventPattern('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])) # 'hidden' should not be an available status. assertDoesNotContain( "hidden", conn.Properties.Get(cs.CONN_IFACE_SIMPLE_PRESENCE, "Statuses"))
def privacy_list_iq_cb(self, iq): if iq.getAttribute("type") == 'set': active = xpath.queryForNodes("//active", iq) if active and ('name' not in active[0].attributes or active[0]['name'] == 'invisible'): acknowledge_iq(self, iq) else: # Don't allow other lists to be activated; and don't allow # modifications. send_error_reply(self, iq) else: requested_lists = xpath.queryForNodes('//list', iq) if not requested_lists: self.send_privacy_list_list(iq['id'], ['invisible']) elif requested_lists[0]['name'] == 'invisible': self.send_privacy_list(iq, [ elem('item', action='deny', order='1')( elem('presence-out')) ]) else: send_error_reply(self, iq, elem(ns.STANZA, 'item-not-found'))
def privacy_list_iq_cb(self, iq): if iq.getAttribute("type") == 'set': active = xpath.queryForNodes("//active", iq) if active and ('name' not in active[0].attributes or active[0]['name'] == 'invisible'): acknowledge_iq(self, iq) else: # Don't allow other lists to be activated; and don't allow # modifications. send_error_reply(self, iq) else: requested_lists = xpath.queryForNodes('//list', iq) if not requested_lists: self.send_privacy_list_list(iq['id'], ['invisible']) elif requested_lists[0]['name'] == 'invisible': self.send_privacy_list(iq, [elem('item', action='deny', order='1')( elem('presence-out') ) ]) else: send_error_reply(self, iq, elem(ns.STANZA, 'item-not-found'))
def proxy_error(q, bus, conn, stream): # Test if another proxy is queried if a query failed connect_and_announce_alice(q, bus, conn, stream) send_file_to_alice(q, conn) return_event, e1, e2, e3 = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), EventPattern('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS), EventPattern('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS), EventPattern('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS)) # Return errors for all the requests; the bugged proxies shouldn't be queried again q.forbid_events([ EventPattern('stream-iq', to=e1.stanza['to'], iq_type='get', query_ns=ns.BYTESTREAMS) ]) send_error_reply(stream, e1.stanza) # the fourth proxy is queried q.expect('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS) q.forbid_events([ EventPattern('stream-iq', to=e2.stanza['to'], iq_type='get', query_ns=ns.BYTESTREAMS) ]) send_error_reply(stream, e2.stanza) sync_stream(q, stream) q.forbid_events([ EventPattern('stream-iq', to=e3.stanza['to'], iq_type='get', query_ns=ns.BYTESTREAMS) ]) send_error_reply(stream, e3.stanza) sync_stream(q, stream)
def test(q, bus, conn, stream, bytestream_cls, address_type, access_control, access_control_param): if bytestream_cls in [BytestreamS5BRelay, BytestreamS5BRelayBugged]: # disable SOCKS5 relay tests because proxy can't be used with muc # contacts atm return if access_control == cs.SOCKET_ACCESS_CONTROL_CREDENTIALS: print("Skip Socket_Access_Control_Credentials (fdo #45445)") return iq_event, disco_event = q.expect_many( EventPattern('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard'), EventPattern('stream-iq', to='localhost', query_ns=ns.DISCO_ITEMS)) acknowledge_iq(stream, iq_event.stanza) announce_socks5_proxy(q, stream, disco_event.stanza) # join the muc call_async( q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: '*****@*****.**' }) q.expect_many( EventPattern( 'dbus-signal', signal='MembersChangedDetailed', predicate=lambda e: e.args[0] == [] and # added e.args[1] == [] and # removed e.args[2] == [] and # local pending len(e.args[3]) == 1 and # remote pending e.args[4].get('actor', 0) == 0 and e.args[4].get( 'change-reason', 0) == 0 and e.args[4]['contact-ids'][e.args[ 3][0]] == '[email protected]/test'), EventPattern('stream-presence', to='[email protected]/test')) # Send presence for other member of room. stream.send( make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob')) # Send presence for own membership of room. stream.send( make_muc_presence('none', 'participant', '*****@*****.**', 'test')) event = q.expect( 'dbus-signal', signal='MembersChangedDetailed', predicate=lambda e: len(e.args[0]) == 2 and # added e.args[1] == [] and # removed e.args[2] == [] and # local pending e.args[3] == [] and # remote pending e.args[4].get('actor', 0) == 0 and e.args[4].get('change-reason', 0) == 0 and set([e.args[4]['contact-ids'][h] for h in e.args[0]]) == set( ['[email protected]/test', '[email protected]/bob'])) for h in event.args[0]: if event.args[4]['contact-ids'][h] == '[email protected]/bob': bob_handle = h event = q.expect('dbus-return', method='CreateChannel') # Bob offers a stream tube stream_tube_id = 666 presence = make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob') tubes = presence.addElement((ns.TUBES, 'tubes')) tube = tubes.addElement((None, 'tube')) tube['type'] = 'stream' tube['service'] = 'echo' tube['id'] = str(stream_tube_id) parameters = tube.addElement((None, 'parameters')) parameter = parameters.addElement((None, 'parameter')) parameter['name'] = 's' parameter['type'] = 'str' parameter.addContent('hello') parameter = parameters.addElement((None, 'parameter')) parameter['name'] = 'ay' parameter['type'] = 'bytes' parameter.addContent('aGVsbG8=') parameter = parameters.addElement((None, 'parameter')) parameter['name'] = 'u' parameter['type'] = 'uint' parameter.addContent('123') parameter = parameters.addElement((None, 'parameter')) parameter['name'] = 'i' parameter['type'] = 'int' parameter.addContent('-123') stream.send(presence) # text channel new_event = q.expect('dbus-signal', signal='NewChannels') channels = new_event.args[0] assert len(channels) == 1 path, props = channels[0] assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT def new_chan_predicate(e): path, props = e.args[0][0] return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE # tube channel is announced new_event = q.expect('dbus-signal', signal='NewChannels', predicate=new_chan_predicate) channels = new_event.args[0] assert len(channels) == 1 path, props = channels[0] assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE assert props[cs.INITIATOR_HANDLE] == bob_handle assert props[cs.INITIATOR_ID] == '[email protected]/bob' assertSameSets([cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_TUBE], props[cs.INTERFACES]) assert props[cs.REQUESTED] == False assert props[cs.TARGET_ID] == '*****@*****.**' assert props[cs.STREAM_TUBE_SERVICE] == 'echo' assert props[cs.TUBE_PARAMETERS] == { 's': 'hello', 'ay': b'hello', 'u': 123, 'i': -123 } assert access_control in \ props[cs.STREAM_TUBE_SUPPORTED_SOCKET_TYPES][address_type] tube_chan = bus.get_object(conn.bus_name, path) tube_props = tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE, dbus_interface=cs.PROPERTIES_IFACE, byte_arrays=True) tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_STREAM_TUBE) assert tube_props['Parameters'] == sample_parameters assert tube_props['State'] == cs.TUBE_CHANNEL_STATE_LOCAL_PENDING # Accept the tube call_async(q, tube_iface, 'Accept', address_type, access_control, access_control_param, byte_arrays=True) accept_return_event, _ = q.expect_many( EventPattern('dbus-return', method='Accept'), EventPattern('dbus-signal', signal='TubeChannelStateChanged', args=[2])) address = accept_return_event.value[0] if isinstance(address, bytes): address = address.decode() socket_event, si_event, conn_id = t.connect_to_cm_socket( q, '[email protected]/bob', address_type, address, access_control, access_control_param) protocol = socket_event.protocol protocol.sendData(b"hello initiator") def accept_tube_si_connection(): bytestream, profile = create_from_si_offer(stream, q, bytestream_cls, si_event.stanza, '[email protected]/test') assert profile == ns.TUBES muc_stream_node = xpath.queryForNodes( '/iq/si/muc-stream[@xmlns="%s"]' % ns.TUBES, si_event.stanza)[0] assert muc_stream_node is not None assert muc_stream_node['tube'] == str(stream_tube_id) # set the real jid of the target as 'to' because the XMPP server changes # it when delivering the IQ result, si = bytestream.create_si_reply(si_event.stanza, 'test@localhost/Resource') si.addElement((ns.TUBES, 'tube')) stream.send(result) bytestream.wait_bytestream_open() return bytestream bytestream = accept_tube_si_connection() binary = bytestream.get_data() assert binary == b'hello initiator' # reply on the socket bytestream.send_data(b'hi joiner!') q.expect('socket-data', protocol=protocol, data=b"hi joiner!") # peer closes the bytestream bytestream.close() e = q.expect('dbus-signal', signal='ConnectionClosed') assertEquals(conn_id, e.args[0]) assertEquals(cs.CONNECTION_LOST, e.args[1]) # establish another tube connection socket_event, si_event, conn_id = t.connect_to_cm_socket( q, '[email protected]/bob', address_type, address, access_control, access_control_param) # bytestream is refused send_error_reply(stream, si_event.stanza) e, _ = q.expect_many( EventPattern('dbus-signal', signal='ConnectionClosed'), EventPattern('socket-disconnected')) assertEquals(conn_id, e.args[0]) assertEquals(cs.CONNECTION_REFUSED, e.args[1]) # establish another tube connection socket_event, si_event, conn_id = t.connect_to_cm_socket( q, '[email protected]/bob', address_type, address, access_control, access_control_param) protocol = socket_event.protocol bytestream = accept_tube_si_connection() # disconnect local socket protocol.transport.loseConnection() e, _ = q.expect_many( EventPattern('dbus-signal', signal='ConnectionClosed'), EventPattern('socket-disconnected')) assertEquals(conn_id, e.args[0]) assertEquals(cs.CANCELLED, e.args[1]) # OK, we're done disconnect_conn(q, conn, stream)
def test(q, bus, conn, stream, bytestream_cls, address_type, access_control, access_control_param): if access_control == cs.SOCKET_ACCESS_CONTROL_CREDENTIALS: print "Skip Socket_Access_Control_Credentials (fdo #45445)" return vcard_event, roster_event, disco_event = q.expect_many( EventPattern('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard'), EventPattern('stream-iq', query_ns=ns.ROSTER), EventPattern('stream-iq', to='localhost', query_ns=ns.DISCO_ITEMS)) acknowledge_iq(stream, vcard_event.stanza) announce_socks5_proxy(q, stream, disco_event.stanza) roster = roster_event.stanza roster['type'] = 'result' item = roster_event.query.addElement('item') item['jid'] = 'bob@localhost' # Bob can do tubes item['subscription'] = 'both' stream.send(roster) # Send Bob presence and his caps presence = domish.Element(('jabber:client', 'presence')) presence['from'] = 'bob@localhost/Bob' presence['to'] = 'test@localhost/Resource' c = presence.addElement('c') c['xmlns'] = 'http://jabber.org/protocol/caps' c['node'] = 'http://example.com/ICantBelieveItsNotTelepathy' c['ver'] = '1.2.3' stream.send(presence) event = q.expect('stream-iq', iq_type='get', query_ns='http://jabber.org/protocol/disco#info', to='bob@localhost/Bob') assert event.query['node'] == \ 'http://example.com/ICantBelieveItsNotTelepathy#1.2.3' result = make_result_iq(stream, event.stanza) query = result.firstChildElement() feature = query.addElement('feature') feature['var'] = ns.TUBES stream.send(result) sync_dbus(bus, q, conn) # Receive a tube offer from Bob (new_tube_chan, new_tube_iface) = \ receive_tube_offer(q, bus, conn, stream) # Try bad parameters on the new iface call_async(q, new_tube_iface, 'Accept', 20, 0, '', byte_arrays=True) q.expect('dbus-error', method='Accept') call_async(q, new_tube_iface, 'Accept', 0, 1, '', byte_arrays=True) q.expect('dbus-error', method='Accept') # Receive a tube offer from Bob (new_tube_chan, new_tube_iface) = \ receive_tube_offer(q, bus, conn, stream) # Accept the tube with new iface, and use UNIX sockets call_async(q, new_tube_iface, 'Accept', address_type, access_control, access_control_param, byte_arrays=True) accept_return_event, _ = q.expect_many( EventPattern('dbus-return', method='Accept'), EventPattern('dbus-signal', signal='TubeChannelStateChanged', args=[2])) socket_address = accept_return_event.value[0] bytestream, conn_id = expect_tube_activity(q, bus, conn, stream, bytestream_cls, address_type, socket_address, access_control, access_control_param) # peer closes the bytestream bytestream.close() e = q.expect('dbus-signal', signal='ConnectionClosed') assertEquals(conn_id, e.args[0]) assertEquals(cs.CONNECTION_LOST, e.args[1]) # establish another tube connection event_socket, si_event, conn_id = t.connect_to_cm_socket( q, bob_jid, address_type, socket_address, access_control, access_control_param) # bytestream is refused send_error_reply(stream, si_event.stanza) e = q.expect('dbus-signal', signal='ConnectionClosed') assertEquals(conn_id, e.args[0]) assertEquals(cs.CONNECTION_REFUSED, e.args[1]) new_tube_chan.Close() # Receive a tube offer from Bob (new_tube_chan, new_tube_iface) = \ receive_tube_offer(q, bus, conn, stream) # Just close the tube new_tube_chan.Close() q.expect_many(EventPattern('dbus-signal', signal='Closed'), EventPattern('dbus-signal', signal='ChannelClosed'))
lat = xpath.queryForNodes('/geoloc/accuracy', geoloc)[0] assertEquals(float(str(lat)), 1.4) acknowledge_iq(stream, event.stanza) q.expect('dbus-return', method='SetLocation') # Server refuses to set Location call_async(q, conn.Location, 'SetLocation', {'lat': 0.0, 'lon': 0.0}) geoloc_iq_set_event = EventPattern( 'stream-iq', predicate=lambda x: xpath.queryForNodes( "/iq/pubsub/publish/item/geoloc", x.stanza)) event = q.expect_many(geoloc_iq_set_event)[0] send_error_reply(stream, event.stanza) q.expect('dbus-error', method='SetLocation') # Request Bob's location bob_handle = conn.get_contact_handle_sync('*****@*****.**') # Gabble should not send a pubsub query. The point of PEP is that we don't # have to do this. pubsub_get_pattern = EventPattern('stream-iq', iq_type='get', query_ns=ns.PUBSUB) q.forbid_events([pubsub_get_pattern]) location = get_location(conn, bob_handle) # Location isn't known yet assertEquals(None, location)
def test(q, bus, conn, stream): iq_event = q.expect('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard') # When we start, there is no avatar acknowledge_iq(stream, iq_event.stanza) self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") # Another resource confirms we have no avatar. We don't request our vCard # because we already know there is no avatar presence_stanza = make_presence('test@localhost/noavatar', to='test@localhost/Resource', show='away', status='At the pub', photo="") q.forbid_events([avatar_request_event, avatar_retrieved_event]) # Gabble must resist temptation to send vCard requests even with several # presence stanza sent! stream.send(presence_stanza) stream.send(presence_stanza) sync_stream(q, stream) # Twice because the vCard request is done in sync_stream(q, stream) # g_idle_add q.unforbid_events([avatar_request_event, avatar_retrieved_event]) # Request on the first contact. Test the cache. handle = conn.get_contact_handle_sync('*****@*****.**') test_get_avatar(q, bus, conn, stream, '*****@*****.**', handle, in_cache=False) test_get_avatar(q, bus, conn, stream, '*****@*****.**', handle, in_cache=True) # Request another vCard and get resource-constraint busy_contact = '*****@*****.**' busy_handle = conn.get_contact_handle_sync(busy_contact) conn.Avatars.RequestAvatars([busy_handle]) iq_event = q.expect('stream-iq', to=busy_contact, query_ns='vcard-temp', query_name='vCard') iq = iq_event.stanza error = domish.Element((None, 'error')) error['code'] = '500' error['type'] = 'wait' error.addElement((ns.STANZA, 'resource-constraint')) q.forbid_events([avatar_retrieved_event, avatar_request_event]) send_error_reply(stream, iq, error) # Request the same vCard again during the suspended delay # We should not get the avatar conn.Avatars.RequestAvatars([busy_handle]) sync_stream(q, stream) sync_dbus(bus, q, conn) q.unforbid_events([avatar_retrieved_event, avatar_request_event]) # Request on a different contact, on another server # We should get the avatar handle = conn.get_contact_handle_sync('*****@*****.**') test_get_avatar(q, bus, conn, stream, '*****@*****.**', handle) # Try again the contact on the busy server. # We should not get the avatar # Note: the timeout is 3 seconds for the test suites. We assume that # a few stanza with be processed fast enough to avoid the race. q.forbid_events([avatar_retrieved_event, avatar_request_event]) conn.Avatars.RequestAvatars([busy_handle]) sync_stream(q, stream) sync_dbus(bus, q, conn) q.unforbid_events([avatar_retrieved_event, avatar_request_event]) # After 3 seconds, we receive a new vCard request on the busy server iq_event = q.expect('stream-iq', to=busy_contact, query_ns='vcard-temp', query_name='vCard') iq = make_result_iq(stream, iq_event.stanza) vcard = iq.firstChildElement() photo = vcard.addElement('PHOTO') photo.addElement('TYPE', content='image/png') photo.addElement('BINVAL', content=base64.b64encode(b'hello').decode()) stream.send(iq) event = q.expect('dbus-signal', signal='AvatarRetrieved') assertEquals(busy_handle, event.args[0]) assertEquals(hashlib.sha1(b'hello').hexdigest(), event.args[1]) assertEquals(b'hello', event.args[2]) assertEquals('image/png', event.args[3]) # Test with our own avatar test@localhost/Resource2 presence_stanza = make_presence('test@localhost/Resource2', to='test@localhost/Resource', show='away', status='At the pub', photo=hashlib.sha1(b':-D').hexdigest()) stream.send(presence_stanza) iq_event = q.expect('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard') iq = make_result_iq(stream, iq_event.stanza) vcard = iq.firstChildElement() photo = vcard.addElement('PHOTO') photo.addElement('TYPE', content='image/png') photo.addElement('BINVAL', content=base64.b64encode(b':-D').decode()) # do not send the vCard reply now. First, send another presence. q.forbid_events([avatar_request_event]) stream.send(presence_stanza) sync_stream(q, stream) # Now send the reply. stream.send(iq) # Which results in an AvatarUpdated signal event = q.expect('dbus-signal', signal='AvatarUpdated') assertEquals(self_handle, event.args[0]) assertEquals(hashlib.sha1(b':-D').hexdigest(), event.args[1]) # So Gabble has the right hash, and no need to ask the vCard again stream.send(presence_stanza) sync_stream(q, stream) q.unforbid_events([avatar_request_event]) # But if the hash is different, the vCard is asked again presence_stanza = make_presence('test@localhost/Resource2', to='test@localhost/Resource', show='away', status='At the pub', photo=hashlib.sha1(b'\o/').hexdigest()) stream.send(presence_stanza) iq_event = q.expect('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard') iq = make_result_iq(stream, iq_event.stanza) vcard = iq.firstChildElement() photo = vcard.addElement('PHOTO') photo.addElement('TYPE', content='image/png') photo.addElement('BINVAL', content=base64.b64encode(b'\o/').decode()) stream.send(iq) event = q.expect('dbus-signal', signal='AvatarUpdated') assertEquals(self_handle, event.args[0]) assertEquals(hashlib.sha1(b'\o/').hexdigest(), event.args[1]) # Gabble must reply without asking the vCard to the server because the # avatar must be in the cache q.forbid_events([avatar_request_event]) conn.Avatars.RequestAvatars([self_handle]) e = q.expect('dbus-signal', signal='AvatarRetrieved') assertEquals(b'\o/', e.args[2]) conn.Avatars.RequestAvatars([handle]) e = q.expect('dbus-signal', signal='AvatarRetrieved') assertEquals(b'hello', e.args[2]) q.unforbid_events([avatar_request_event]) # First, ensure the pipeline is full contacts = ['*****@*****.**' % i for i in range(1, 100)] handles = conn.get_contact_handles_sync(contacts) conn.Avatars.RequestAvatars(handles) # Then, request yet another avatar. The request will time out before # the IQ is sent, which used to trigger a crash in Gabble # (LP#445847). conn.Avatars.RequestAvatars([handles[-1]]) sync_dbus(bus, q, conn)
def test(q, bus, conn, stream): # Request a sidecar thate we support before we're connected; it should just # wait around until we're connected. call_async(q, conn.Sidecars1, 'EnsureSidecar', TEST_PLUGIN_IFACE) if PLUGINS_ENABLED: # Now we're connected, the call we made earlier should return. path, props = q.expect('dbus-return', method='EnsureSidecar').value # This sidecar doesn't even implement get_immutable_properties; it # should just get the empty dict filled in for it. assertEquals({}, props) # We should get the same sidecar if we request it again path2, props2 = conn.Sidecars1.EnsureSidecar(TEST_PLUGIN_IFACE) assertEquals((path, props), (path2, props2)) else: # Only now does it fail. q.expect('dbus-error', method='EnsureSidecar') # This is not a valid interface name call_async(q, conn.Sidecars1, 'EnsureSidecar', 'not an interface') q.expect('dbus-error', name=cs.INVALID_ARGUMENT) # The test plugin makes no reference to this interface. call_async(q, conn.Sidecars1, 'EnsureSidecar', 'unsupported.sidecar') q.expect('dbus-error', name=cs.NOT_IMPLEMENTED) if PLUGINS_ENABLED: # This sidecar does have some properties: path, props = conn.Sidecars1.EnsureSidecar(TEST_PLUGIN_IFACE + ".Props") assertContains(TEST_PLUGIN_IFACE + ".Props.Greeting", props) # The plugin claims it implements this sidecar, but actually doesn't. # Check that we don't blow up (although this is no different from # Gabble's perspective to creating a sidecar failing because a network # service wasn't there, for instance). call_async(q, conn.Sidecars1, 'EnsureSidecar', TEST_PLUGIN_IFACE + ".Buggy") q.expect('dbus-error', name=cs.NOT_IMPLEMENTED) # This sidecar sends a stanza, and waits for a reply, before being # created. pattern = EventPattern('stream-iq', to='sidecar.example.com', query_ns='http://example.com/sidecar') call_async(q, conn.Sidecars1, 'EnsureSidecar', TEST_PLUGIN_IFACE + ".IQ") e = q.expect_many(pattern)[0] sync_dbus(bus, q, conn) # If the server says no, EnsureSidecar should fail. send_error_reply(stream, e.stanza) q.expect('dbus-error', method='EnsureSidecar', name=cs.NOT_AVAILABLE) # Let's try again. The plugin should get a chance to ping the server # again. call_async(q, conn.Sidecars1, 'EnsureSidecar', TEST_PLUGIN_IFACE + ".IQ") e = q.expect_many(pattern)[0] # The server said yes, so we should get a sidecar back! acknowledge_iq(stream, e.stanza) q.expect('dbus-return', method='EnsureSidecar') # If we ask again once the plugin has been created, it should return at # once without any more network traffic. q.forbid_events([pattern]) conn.Sidecars1.EnsureSidecar(TEST_PLUGIN_IFACE + ".IQ") sync_stream(q, stream) # TODO: test ensuring a sidecar that waits for something from the # network, disconnecting while it's waiting, and ensuring that nothing # breaks regardless of whether the network replies before # </stream:stream> or not. call_async(q, conn, 'Disconnect') q.expect_many( EventPattern('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_DISCONNECTED, cs.CSR_REQUESTED]), EventPattern('stream-closed'), ) call_async(q, conn.Sidecars1, 'EnsureSidecar', 'zomg.what') # With older telepathy-glib this would be DISCONNECTED; # with newer telepathy-glib the Connection disappears from the bus # sooner, and you get UnknownMethod or something from dbus-glib. q.expect('dbus-error') stream.sendFooter() q.expect('dbus-return', method='Disconnect')
def test(q, bus, conn, stream): iq_event = q.expect('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard') # When we start, there is no avatar acknowledge_iq(stream, iq_event.stanza) self_handle = conn.GetSelfHandle() # Another resource confirms we have no avatar. We don't request our vCard # because we already know there is no avatar presence_stanza = make_presence('test@localhost/noavatar', to='test@localhost/Resource', show='away', status='At the pub', photo="") q.forbid_events([avatar_request_event, avatar_retrieved_event]) # Gabble must resist temptation to send vCard requests even with several # presence stanza sent! stream.send(presence_stanza) stream.send(presence_stanza) sync_stream(q, stream) # Twice because the vCard request is done in sync_stream(q, stream) # g_idle_add q.unforbid_events([avatar_request_event, avatar_retrieved_event]) # Request on the first contact. Test the cache. handle = conn.RequestHandles(cs.HT_CONTACT, ['*****@*****.**'])[0] test_get_avatar(q, bus, conn, stream, '*****@*****.**', handle, in_cache=False) test_get_avatar(q, bus, conn, stream, '*****@*****.**', handle, in_cache=True) # Request another vCard and get resource-constraint busy_contact = '*****@*****.**' busy_handle = conn.RequestHandles(cs.HT_CONTACT, [busy_contact])[0] conn.Avatars.RequestAvatars([busy_handle]) iq_event = q.expect('stream-iq', to=busy_contact, query_ns='vcard-temp', query_name='vCard') iq = iq_event.stanza error = domish.Element((None, 'error')) error['code'] = '500' error['type'] = 'wait' error.addElement((ns.STANZA, 'resource-constraint')) q.forbid_events([avatar_retrieved_event, avatar_request_event]) send_error_reply(stream, iq, error) # Request the same vCard again during the suspended delay # We should not get the avatar conn.Avatars.RequestAvatars([busy_handle]) sync_stream(q, stream) sync_dbus(bus, q, conn) q.unforbid_events([avatar_retrieved_event, avatar_request_event]) # Request on a different contact, on another server # We should get the avatar handle = conn.RequestHandles(cs.HT_CONTACT, ['*****@*****.**'])[0] test_get_avatar(q, bus, conn, stream, '*****@*****.**', handle) # Try again the contact on the busy server. # We should not get the avatar # Note: the timeout is 3 seconds for the test suites. We assume that # a few stanza with be processed fast enough to avoid the race. q.forbid_events([avatar_retrieved_event, avatar_request_event]) conn.Avatars.RequestAvatars([busy_handle]) sync_stream(q, stream) sync_dbus(bus, q, conn) q.unforbid_events([avatar_retrieved_event, avatar_request_event]) # After 3 seconds, we receive a new vCard request on the busy server iq_event = q.expect('stream-iq', to=busy_contact, query_ns='vcard-temp', query_name='vCard') iq = make_result_iq(stream, iq_event.stanza) vcard = iq.firstChildElement() photo = vcard.addElement('PHOTO') photo.addElement('TYPE', content='image/png') photo.addElement('BINVAL', content=base64.b64encode('hello')) stream.send(iq) event = q.expect('dbus-signal', signal='AvatarRetrieved') assertEquals(busy_handle, event.args[0]) assertEquals(hashlib.sha1('hello').hexdigest(), event.args[1]) assertEquals('hello', event.args[2]) assertEquals('image/png', event.args[3]) # Test with our own avatar test@localhost/Resource2 presence_stanza = make_presence('test@localhost/Resource2', to='test@localhost/Resource', show='away', status='At the pub', photo=hashlib.sha1(':-D').hexdigest()) stream.send(presence_stanza) iq_event = q.expect('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard') iq = make_result_iq(stream, iq_event.stanza) vcard = iq.firstChildElement() photo = vcard.addElement('PHOTO') photo.addElement('TYPE', content='image/png') photo.addElement('BINVAL', content=base64.b64encode(':-D')) # do not send the vCard reply now. First, send another presence. q.forbid_events([avatar_request_event]) stream.send(presence_stanza) sync_stream(q, stream) # Now send the reply. stream.send(iq) # Which results in an AvatarUpdated signal event = q.expect('dbus-signal', signal='AvatarUpdated') assertEquals(self_handle, event.args[0]) assertEquals(hashlib.sha1(':-D').hexdigest(), event.args[1]) # So Gabble has the right hash, and no need to ask the vCard again stream.send(presence_stanza) sync_stream(q, stream) q.unforbid_events([avatar_request_event]) # But if the hash is different, the vCard is asked again presence_stanza = make_presence('test@localhost/Resource2', to='test@localhost/Resource', show='away', status='At the pub', photo=hashlib.sha1('\o/').hexdigest()) stream.send(presence_stanza) iq_event = q.expect('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard') iq = make_result_iq(stream, iq_event.stanza) vcard = iq.firstChildElement() photo = vcard.addElement('PHOTO') photo.addElement('TYPE', content='image/png') photo.addElement('BINVAL', content=base64.b64encode('\o/')) stream.send(iq) event = q.expect('dbus-signal', signal='AvatarUpdated') assertEquals(self_handle, event.args[0]) assertEquals(hashlib.sha1('\o/').hexdigest(), event.args[1]) # Gabble must reply without asking the vCard to the server because the # avatar must be in the cache q.forbid_events([avatar_request_event]) data, mime = conn.Avatars.RequestAvatar(self_handle, byte_arrays=True) assertEquals('\o/', data) data, mime = conn.Avatars.RequestAvatar(handle, byte_arrays=True) assertEquals('hello', data) q.unforbid_events([avatar_request_event]) # First, ensure the pipeline is full contacts = ['*****@*****.**' % i for i in range(1, 100) ] handles = conn.RequestHandles(cs.HT_CONTACT, contacts) conn.Avatars.RequestAvatars(handles) # Then, request yet another avatar. The request will time out before # the IQ is sent, which used to trigger a crash in Gabble # (LP#445847). So, we assert that the error is NotAvailable (rather # than the error returned when the service crashes). try: conn.Avatars.RequestAvatar(handles[-1]) except dbus.DBusException, e: assertEquals(cs.NOT_AVAILABLE, e.get_dbus_name())
def test(q, bus, conn, stream, bytestream_cls, address_type, access_control, access_control_param): if bytestream_cls in [BytestreamS5BRelay, BytestreamS5BRelayBugged]: # disable SOCKS5 relay tests because proxy can't be used with muc # contacts atm return iq_event, disco_event = q.expect_many( EventPattern('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard'), EventPattern('stream-iq', to='localhost', query_ns=ns.DISCO_ITEMS)) acknowledge_iq(stream, iq_event.stanza) announce_socks5_proxy(q, stream, disco_event.stanza) call_async(q, conn, 'RequestHandles', 2, ['*****@*****.**']) event = q.expect('dbus-return', method='RequestHandles') handles = event.value[0] room_handle = handles[0] # join the muc call_async(q, conn, 'RequestChannel', cs.CHANNEL_TYPE_TEXT, cs.HT_ROOM, room_handle, True) _, stream_event = q.expect_many( EventPattern('dbus-signal', signal='MembersChanged', args=[u'', [], [], [], [2], 0, 0]), EventPattern('stream-presence', to='[email protected]/test')) # Send presence for other member of room. stream.send(make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob')) # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', '*****@*****.**', 'test')) q.expect('dbus-signal', signal='MembersChanged', args=[u'', [2, 3], [], [], [], 0, 0]) assert conn.InspectHandles(1, [2]) == ['[email protected]/test'] assert conn.InspectHandles(1, [3]) == ['[email protected]/bob'] bob_handle = 3 event = q.expect('dbus-return', method='RequestChannel') # Bob offers a stream tube stream_tube_id = 666 presence = make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob') tubes = presence.addElement((ns.TUBES, 'tubes')) tube = tubes.addElement((None, 'tube')) tube['type'] = 'stream' tube['service'] = 'echo' tube['id'] = str(stream_tube_id) parameters = tube.addElement((None, 'parameters')) parameter = parameters.addElement((None, 'parameter')) parameter['name'] = 's' parameter['type'] = 'str' parameter.addContent('hello') parameter = parameters.addElement((None, 'parameter')) parameter['name'] = 'ay' parameter['type'] = 'bytes' parameter.addContent('aGVsbG8=') parameter = parameters.addElement((None, 'parameter')) parameter['name'] = 'u' parameter['type'] = 'uint' parameter.addContent('123') parameter = parameters.addElement((None, 'parameter')) parameter['name'] = 'i' parameter['type'] = 'int' parameter.addContent('-123') stream.send(presence) # text channel event, new_event = q.expect_many( EventPattern('dbus-signal', signal='NewChannel'), EventPattern('dbus-signal', signal='NewChannels')) assert event.args[1] == cs.CHANNEL_TYPE_TEXT, event.args channels = new_event.args[0] assert len(channels) == 1 path, props = channels[0] assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT # tubes channel is automatically created event, new_event = q.expect_many( EventPattern('dbus-signal', signal='NewChannel'), EventPattern('dbus-signal', signal='NewChannels')) assert event.args[1] == cs.CHANNEL_TYPE_TUBES, event.args assert event.args[2] == cs.HT_ROOM assert event.args[3] == room_handle tubes_chan = bus.get_object(conn.bus_name, event.args[0]) tubes_iface = dbus.Interface(tubes_chan, event.args[1]) channel_props = tubes_chan.GetAll(cs.CHANNEL, dbus_interface=cs.PROPERTIES_IFACE) assert channel_props['TargetID'] == '*****@*****.**', channel_props assert channel_props['Requested'] == False assert channel_props['InitiatorID'] == '' assert channel_props['InitiatorHandle'] == 0 channels = new_event.args[0] assert len(channels) == 1 path, props = channels[0] assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TUBES tubes_self_handle = tubes_chan.GetSelfHandle(dbus_interface=cs.CHANNEL_IFACE_GROUP) q.expect('dbus-signal', signal='NewTube', args=[stream_tube_id, bob_handle, 1, 'echo', sample_parameters, 0]) expected_tube = (stream_tube_id, bob_handle, cs.TUBE_TYPE_STREAM, 'echo', sample_parameters, cs.TUBE_STATE_LOCAL_PENDING) tubes = tubes_iface.ListTubes(byte_arrays=True) assert tubes == [( stream_tube_id, bob_handle, 1, # Stream 'echo', sample_parameters, cs.TUBE_CHANNEL_STATE_LOCAL_PENDING )] assert len(tubes) == 1, unwrap(tubes) t.check_tube_in_tubes(expected_tube, tubes) # tube channel is also announced (new API) new_event = q.expect('dbus-signal', signal='NewChannels') channels = new_event.args[0] assert len(channels) == 1 path, props = channels[0] assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE assert props[cs.INITIATOR_HANDLE] == bob_handle assert props[cs.INITIATOR_ID] == '[email protected]/bob' assert props[cs.INTERFACES] == [cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_TUBE] assert props[cs.REQUESTED] == False assert props[cs.TARGET_HANDLE] == room_handle assert props[cs.TARGET_ID] == '*****@*****.**' assert props[cs.STREAM_TUBE_SERVICE] == 'echo' assert props[cs.TUBE_PARAMETERS] == {'s': 'hello', 'ay': 'hello', 'u': 123, 'i': -123} assert access_control in \ props[cs.STREAM_TUBE_SUPPORTED_SOCKET_TYPES][address_type] tube_chan = bus.get_object(conn.bus_name, path) tube_props = tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE, dbus_interface=cs.PROPERTIES_IFACE, byte_arrays=True) assert tube_props['Parameters'] == sample_parameters assert tube_props['State'] == cs.TUBE_CHANNEL_STATE_LOCAL_PENDING # Accept the tube call_async(q, tubes_iface, 'AcceptStreamTube', stream_tube_id, address_type, access_control, access_control_param, byte_arrays=True) accept_return_event, _ = q.expect_many( EventPattern('dbus-return', method='AcceptStreamTube'), EventPattern('dbus-signal', signal='TubeStateChanged', args=[stream_tube_id, 2])) address = accept_return_event.value[0] socket_event, si_event, conn_id = t.connect_to_cm_socket(q, '[email protected]/bob', address_type, address, access_control, access_control_param) protocol = socket_event.protocol protocol.sendData("hello initiator") def accept_tube_si_connection(): bytestream, profile = create_from_si_offer(stream, q, bytestream_cls, si_event.stanza, '[email protected]/test') assert profile == ns.TUBES muc_stream_node = xpath.queryForNodes('/iq/si/muc-stream[@xmlns="%s"]' % ns.TUBES, si_event.stanza)[0] assert muc_stream_node is not None assert muc_stream_node['tube'] == str(stream_tube_id) # set the real jid of the target as 'to' because the XMPP server changes # it when delivering the IQ result, si = bytestream.create_si_reply(si_event.stanza, 'test@localhost/Resource') si.addElement((ns.TUBES, 'tube')) stream.send(result) bytestream.wait_bytestream_open() return bytestream bytestream = accept_tube_si_connection() binary = bytestream.get_data() assert binary == 'hello initiator' # reply on the socket bytestream.send_data('hi joiner!') q.expect('socket-data', protocol=protocol, data="hi joiner!") # peer closes the bytestream bytestream.close() e = q.expect('dbus-signal', signal='ConnectionClosed') assertEquals(conn_id, e.args[0]) assertEquals(cs.CONNECTION_LOST, e.args[1]) # establish another tube connection socket_event, si_event, conn_id = t.connect_to_cm_socket(q, '[email protected]/bob', address_type, address, access_control, access_control_param) # bytestream is refused send_error_reply(stream, si_event.stanza) e, _ = q.expect_many( EventPattern('dbus-signal', signal='ConnectionClosed'), EventPattern('socket-disconnected')) assertEquals(conn_id, e.args[0]) assertEquals(cs.CONNECTION_REFUSED, e.args[1]) # establish another tube connection socket_event, si_event, conn_id = t.connect_to_cm_socket(q, '[email protected]/bob', address_type, address, access_control, access_control_param) protocol = socket_event.protocol bytestream = accept_tube_si_connection() # disconnect local socket protocol.transport.loseConnection() e, _ = q.expect_many( EventPattern('dbus-signal', signal='ConnectionClosed'), EventPattern('socket-disconnected')) assertEquals(conn_id, e.args[0]) assertEquals(cs.CANCELLED, e.args[1]) # OK, we're done disconnect_conn(q, conn, stream, [EventPattern('dbus-signal', signal='TubeClosed', args=[stream_tube_id])])
def test(q, bus, conn, stream, bytestream_cls, address_type, access_control, access_control_param): vcard_event, roster_event, disco_event = q.expect_many( EventPattern('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard'), EventPattern('stream-iq', query_ns=ns.ROSTER), EventPattern('stream-iq', to='localhost', query_ns=ns.DISCO_ITEMS)) acknowledge_iq(stream, vcard_event.stanza) announce_socks5_proxy(q, stream, disco_event.stanza) roster = roster_event.stanza roster['type'] = 'result' item = roster_event.query.addElement('item') item['jid'] = 'bob@localhost' # Bob can do tubes item['subscription'] = 'both' stream.send(roster) # Send Bob presence and his caps presence = domish.Element(('jabber:client', 'presence')) presence['from'] = 'bob@localhost/Bob' presence['to'] = 'test@localhost/Resource' c = presence.addElement('c') c['xmlns'] = 'http://jabber.org/protocol/caps' c['node'] = 'http://example.com/ICantBelieveItsNotTelepathy' c['ver'] = '1.2.3' stream.send(presence) event = q.expect('stream-iq', iq_type='get', query_ns='http://jabber.org/protocol/disco#info', to='bob@localhost/Bob') assert event.query['node'] == \ 'http://example.com/ICantBelieveItsNotTelepathy#1.2.3' result = make_result_iq(stream, event.stanza) query = result.firstChildElement() feature = query.addElement('feature') feature['var'] = ns.TUBES stream.send(result) sync_dbus(bus, q, conn) # Receive a tube offer from Bob (tubes_chan, tubes_iface, new_tube_chan, new_tube_iface) = \ receive_tube_offer(q, bus, conn, stream) # Try bad parameters on the old iface call_async(q, tubes_iface, 'AcceptStreamTube', stream_tube_id+1, 2, 0, '', byte_arrays=True) q.expect('dbus-error', method='AcceptStreamTube') call_async(q, tubes_iface, 'AcceptStreamTube', stream_tube_id, 2, 1, '', byte_arrays=True) q.expect('dbus-error', method='AcceptStreamTube') call_async(q, tubes_iface, 'AcceptStreamTube', stream_tube_id, 20, 0, '', byte_arrays=True) q.expect('dbus-error', method='AcceptStreamTube') # Try bad parameters on the new iface call_async(q, new_tube_iface, 'Accept', 20, 0, '', byte_arrays=True) q.expect('dbus-error', method='Accept') call_async(q, new_tube_iface, 'Accept', 0, 1, '', byte_arrays=True) q.expect('dbus-error', method='Accept') # Accept the tube with old iface call_async(q, tubes_iface, 'AcceptStreamTube', stream_tube_id, address_type, access_control, access_control_param, byte_arrays=True) accept_return_event, _ = q.expect_many( EventPattern('dbus-return', method='AcceptStreamTube'), EventPattern('dbus-signal', signal='TubeStateChanged', args=[stream_tube_id, 2])) socket_address = accept_return_event.value[0] bytestream, conn_id = expect_tube_activity(q, bus, conn, stream, bytestream_cls, address_type, socket_address, access_control, access_control_param) tubes_chan.Close() bytestream.wait_bytestream_closed() # Receive a tube offer from Bob (tubes_chan, tubes_iface, new_tube_chan, new_tube_iface) = \ receive_tube_offer(q, bus, conn, stream) # Accept the tube with old iface, and use UNIX sockets call_async(q, tubes_iface, 'AcceptStreamTube', stream_tube_id, address_type, access_control, access_control_param, byte_arrays=True) accept_return_event, _ = q.expect_many( EventPattern('dbus-return', method='AcceptStreamTube'), EventPattern('dbus-signal', signal='TubeStateChanged', args=[stream_tube_id, 2])) socket_address = accept_return_event.value[0] bytestream, conn_id = expect_tube_activity(q, bus, conn, stream, bytestream_cls, address_type, socket_address, access_control, access_control_param) tubes_chan.Close() bytestream.wait_bytestream_closed() # Receive a tube offer from Bob (tubes_chan, tubes_iface, new_tube_chan, new_tube_iface) = \ receive_tube_offer(q, bus, conn, stream) # Accept the tube with new iface, and use IPv4 call_async(q, new_tube_iface, 'Accept', address_type, access_control, access_control_param, byte_arrays=True) accept_return_event, _ = q.expect_many( EventPattern('dbus-return', method='Accept'), EventPattern('dbus-signal', signal='TubeStateChanged', args=[stream_tube_id, 2])) socket_address = accept_return_event.value[0] bytestream, conn_id = expect_tube_activity(q, bus, conn, stream, bytestream_cls, address_type, socket_address, access_control, access_control_param) tubes_chan.Close() e, _ = bytestream.wait_bytestream_closed([ EventPattern('dbus-signal', signal='ConnectionClosed'), EventPattern('socket-disconnected')]) assertEquals(conn_id, e.args[0]) assertEquals(cs.CANCELLED, e.args[1]) # Receive a tube offer from Bob (tubes_chan, tubes_iface, new_tube_chan, new_tube_iface) = \ receive_tube_offer(q, bus, conn, stream) # Accept the tube with new iface, and use UNIX sockets call_async(q, new_tube_iface, 'Accept', address_type, access_control, access_control_param, byte_arrays=True) accept_return_event, _ = q.expect_many( EventPattern('dbus-return', method='Accept'), EventPattern('dbus-signal', signal='TubeStateChanged', args=[stream_tube_id, 2])) socket_address = accept_return_event.value[0] bytestream, conn_id = expect_tube_activity(q, bus, conn, stream, bytestream_cls, address_type, socket_address, access_control, access_control_param) # peer closes the bytestream bytestream.close() e = q.expect('dbus-signal', signal='ConnectionClosed') assertEquals(conn_id, e.args[0]) assertEquals(cs.CONNECTION_LOST, e.args[1]) # establish another tube connection event_socket, si_event, conn_id = t.connect_to_cm_socket(q, bob_jid, address_type, socket_address, access_control, access_control_param) # bytestream is refused send_error_reply(stream, si_event.stanza) e = q.expect('dbus-signal', signal='ConnectionClosed') assertEquals(conn_id, e.args[0]) assertEquals(cs.CONNECTION_REFUSED, e.args[1]) tubes_chan.Close() # Receive a tube offer from Bob (tubes_chan, tubes_iface, new_tube_chan, new_tube_iface) = \ receive_tube_offer(q, bus, conn, stream) # Just close the tube tubes_chan.Close() # Receive a tube offer from Bob (tubes_chan, tubes_iface, new_tube_chan, new_tube_iface) = \ receive_tube_offer(q, bus, conn, stream) # Just close the tube new_tube_chan.Close() q.expect_many( EventPattern('dbus-signal', signal='Closed'), EventPattern('dbus-signal', signal='ChannelClosed'))
def test(q, bus, conn, stream, bytestream_cls, address_type, access_control, access_control_param): if bytestream_cls in [BytestreamS5BRelay, BytestreamS5BRelayBugged]: # disable SOCKS5 relay tests because proxy can't be used with muc # contacts atm return if access_control == cs.SOCKET_ACCESS_CONTROL_CREDENTIALS: print "Skip Socket_Access_Control_Credentials (fdo #45445)" return iq_event, disco_event = q.expect_many( EventPattern('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard'), EventPattern('stream-iq', to='localhost', query_ns=ns.DISCO_ITEMS)) acknowledge_iq(stream, iq_event.stanza) announce_socks5_proxy(q, stream, disco_event.stanza) # join the muc call_async(q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: '*****@*****.**'}) q.expect_many( EventPattern('dbus-signal', signal='MembersChangedDetailed', predicate=lambda e: e.args[0] == [] and # added e.args[1] == [] and # removed e.args[2] == [] and # local pending len(e.args[3]) == 1 and # remote pending e.args[4].get('actor', 0) == 0 and e.args[4].get('change-reason', 0) == 0 and e.args[4]['contact-ids'][e.args[3][0]] == '[email protected]/test'), EventPattern('stream-presence', to='[email protected]/test')) # Send presence for other member of room. stream.send(make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob')) # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', '*****@*****.**', 'test')) event = q.expect('dbus-signal', signal='MembersChangedDetailed', predicate=lambda e: len(e.args[0]) == 2 and # added e.args[1] == [] and # removed e.args[2] == [] and # local pending e.args[3] == [] and # remote pending e.args[4].get('actor', 0) == 0 and e.args[4].get('change-reason', 0) == 0 and set([e.args[4]['contact-ids'][h] for h in e.args[0]]) == set(['[email protected]/test', '[email protected]/bob'])) for h in event.args[0]: if event.args[4]['contact-ids'][h] == '[email protected]/bob': bob_handle = h event = q.expect('dbus-return', method='CreateChannel') # Bob offers a stream tube stream_tube_id = 666 presence = make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob') tubes = presence.addElement((ns.TUBES, 'tubes')) tube = tubes.addElement((None, 'tube')) tube['type'] = 'stream' tube['service'] = 'echo' tube['id'] = str(stream_tube_id) parameters = tube.addElement((None, 'parameters')) parameter = parameters.addElement((None, 'parameter')) parameter['name'] = 's' parameter['type'] = 'str' parameter.addContent('hello') parameter = parameters.addElement((None, 'parameter')) parameter['name'] = 'ay' parameter['type'] = 'bytes' parameter.addContent('aGVsbG8=') parameter = parameters.addElement((None, 'parameter')) parameter['name'] = 'u' parameter['type'] = 'uint' parameter.addContent('123') parameter = parameters.addElement((None, 'parameter')) parameter['name'] = 'i' parameter['type'] = 'int' parameter.addContent('-123') stream.send(presence) # text channel new_event = q.expect('dbus-signal', signal='NewChannels') channels = new_event.args[0] assert len(channels) == 1 path, props = channels[0] assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT def new_chan_predicate(e): path, props = e.args[0][0] return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE # tube channel is announced new_event = q.expect('dbus-signal', signal='NewChannels', predicate=new_chan_predicate) channels = new_event.args[0] assert len(channels) == 1 path, props = channels[0] assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE assert props[cs.INITIATOR_HANDLE] == bob_handle assert props[cs.INITIATOR_ID] == '[email protected]/bob' assertSameSets([cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_TUBE], props[cs.INTERFACES]) assert props[cs.REQUESTED] == False assert props[cs.TARGET_ID] == '*****@*****.**' assert props[cs.STREAM_TUBE_SERVICE] == 'echo' assert props[cs.TUBE_PARAMETERS] == {'s': 'hello', 'ay': 'hello', 'u': 123, 'i': -123} assert access_control in \ props[cs.STREAM_TUBE_SUPPORTED_SOCKET_TYPES][address_type] tube_chan = bus.get_object(conn.bus_name, path) tube_props = tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE, dbus_interface=cs.PROPERTIES_IFACE, byte_arrays=True) tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_STREAM_TUBE) assert tube_props['Parameters'] == sample_parameters assert tube_props['State'] == cs.TUBE_CHANNEL_STATE_LOCAL_PENDING # Accept the tube call_async(q, tube_iface, 'Accept', address_type, access_control, access_control_param, byte_arrays=True) accept_return_event, _ = q.expect_many( EventPattern('dbus-return', method='Accept'), EventPattern('dbus-signal', signal='TubeChannelStateChanged', args=[2])) address = accept_return_event.value[0] socket_event, si_event, conn_id = t.connect_to_cm_socket(q, '[email protected]/bob', address_type, address, access_control, access_control_param) protocol = socket_event.protocol protocol.sendData("hello initiator") def accept_tube_si_connection(): bytestream, profile = create_from_si_offer(stream, q, bytestream_cls, si_event.stanza, '[email protected]/test') assert profile == ns.TUBES muc_stream_node = xpath.queryForNodes('/iq/si/muc-stream[@xmlns="%s"]' % ns.TUBES, si_event.stanza)[0] assert muc_stream_node is not None assert muc_stream_node['tube'] == str(stream_tube_id) # set the real jid of the target as 'to' because the XMPP server changes # it when delivering the IQ result, si = bytestream.create_si_reply(si_event.stanza, 'test@localhost/Resource') si.addElement((ns.TUBES, 'tube')) stream.send(result) bytestream.wait_bytestream_open() return bytestream bytestream = accept_tube_si_connection() binary = bytestream.get_data() assert binary == 'hello initiator' # reply on the socket bytestream.send_data('hi joiner!') q.expect('socket-data', protocol=protocol, data="hi joiner!") # peer closes the bytestream bytestream.close() e = q.expect('dbus-signal', signal='ConnectionClosed') assertEquals(conn_id, e.args[0]) assertEquals(cs.CONNECTION_LOST, e.args[1]) # establish another tube connection socket_event, si_event, conn_id = t.connect_to_cm_socket(q, '[email protected]/bob', address_type, address, access_control, access_control_param) # bytestream is refused send_error_reply(stream, si_event.stanza) e, _ = q.expect_many( EventPattern('dbus-signal', signal='ConnectionClosed'), EventPattern('socket-disconnected')) assertEquals(conn_id, e.args[0]) assertEquals(cs.CONNECTION_REFUSED, e.args[1]) # establish another tube connection socket_event, si_event, conn_id = t.connect_to_cm_socket(q, '[email protected]/bob', address_type, address, access_control, access_control_param) protocol = socket_event.protocol bytestream = accept_tube_si_connection() # disconnect local socket protocol.transport.loseConnection() e, _ = q.expect_many( EventPattern('dbus-signal', signal='ConnectionClosed'), EventPattern('socket-disconnected')) assertEquals(conn_id, e.args[0]) assertEquals(cs.CANCELLED, e.args[1]) # OK, we're done disconnect_conn(q, conn, stream)
def test(q, bus, conn, stream): # we don't yet know we have PEP assertEquals( 0, conn.Get(cs.CONN_IFACE_LOCATION, "SupportedLocationFeatures", dbus_interface=cs.PROPERTIES_IFACE)) conn.Connect() # discard activities request and status change q.expect_many( EventPattern('stream-iq', iq_type='set', query_ns=ns.PUBSUB), EventPattern('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]), ) # we now know we have PEP assertEquals( cs.LOCATION_FEATURE_CAN_SET, conn.Get(cs.CONN_IFACE_LOCATION, "SupportedLocationFeatures", dbus_interface=cs.PROPERTIES_IFACE)) # check location properties access_control_types = conn.Get(cs.CONN_IFACE_LOCATION, "LocationAccessControlTypes", dbus_interface=cs.PROPERTIES_IFACE) # only one access control is implemented in Gabble at the moment: assert len(access_control_types) == 1, access_control_types assert access_control_types[0] == \ Rich_Presence_Access_Control_Type_Publish_List access_control = conn.Get(cs.CONN_IFACE_LOCATION, "LocationAccessControl", dbus_interface=cs.PROPERTIES_IFACE) assert len(access_control) == 2, access_control assert access_control[0] == \ Rich_Presence_Access_Control_Type_Publish_List properties = conn.GetAll(cs.CONN_IFACE_LOCATION, dbus_interface=cs.PROPERTIES_IFACE) assert properties.get('LocationAccessControlTypes') == access_control_types assert properties.get('LocationAccessControl') == access_control # Test setting the properties # Enum out of range bad_access_control = dbus.Struct( [dbus.UInt32(99), dbus.UInt32(0, variant_level=1)], signature=dbus.Signature('uv')) try: conn.Set(cs.CONN_IFACE_LOCATION, 'LocationAccessControl', bad_access_control, dbus_interface=cs.PROPERTIES_IFACE) except dbus.DBusException as e: pass else: assert False, "Should have had an error!" # Bad type bad_access_control = dbus.String("This should not be a string") try: conn.Set(cs.CONN_IFACE_LOCATION, 'LocationAccessControl', bad_access_control, dbus_interface=cs.PROPERTIES_IFACE) except dbus.DBusException as e: assert e.get_dbus_name() == cs.INVALID_ARGUMENT, e.get_dbus_name() else: assert False, "Should have had an error!" # Bad type bad_access_control = dbus.Struct([ dbus.String("bad"), dbus.String("!"), dbus.UInt32(0, variant_level=1) ], signature=dbus.Signature('ssv')) try: conn.Set(cs.CONN_IFACE_LOCATION, 'LocationAccessControl', bad_access_control, dbus_interface=cs.PROPERTIES_IFACE) except dbus.DBusException as e: assert e.get_dbus_name() == cs.INVALID_ARGUMENT, e.get_dbus_name() else: assert False, "Should have had an error!" # Correct conn.Set(cs.CONN_IFACE_LOCATION, 'LocationAccessControl', access_control, dbus_interface=cs.PROPERTIES_IFACE) # LocationAccessControlTypes is read-only, check Gabble return the # PermissionDenied error try: conn.Set(cs.CONN_IFACE_LOCATION, 'LocationAccessControlTypes', access_control_types, dbus_interface=cs.PROPERTIES_IFACE) except dbus.DBusException as e: assert e.get_dbus_name() == cs.PERMISSION_DENIED, e.get_dbus_name() else: assert False, "Should have had an error!" date = dbus.Int64(time.time()) date_str = datetime.datetime.utcfromtimestamp(date).strftime( '%FT%H:%M:%SZ') # set a Location call_async( q, conn.Location, 'SetLocation', { 'lat': dbus.Double(0.0, variant_level=1), 'lon': 0.0, 'language': 'en', 'timestamp': date, 'country': 'Congo', 'accuracy': 1.4, # Gabble silently ignores unknown keys 'badger': 'mushroom' }) geoloc_iq_set_event = EventPattern( 'stream-iq', predicate=lambda x: xpath.queryForNodes( "/iq/pubsub/publish/item/geoloc", x.stanza)) event = q.expect_many(geoloc_iq_set_event)[0] geoloc = xpath.queryForNodes("/iq/pubsub/publish/item/geoloc", event.stanza)[0] assertEquals(geoloc.getAttribute((ns.XML, 'lang')), 'en') lon = xpath.queryForNodes('/geoloc/lon', geoloc)[0] assertEquals(float(str(lon)), 0.0) lat = xpath.queryForNodes('/geoloc/lat', geoloc)[0] assertEquals(float(str(lat)), 0.0) timestamp = xpath.queryForNodes('/geoloc/timestamp', geoloc)[0] assertEquals(str(timestamp), date_str) country = xpath.queryForNodes('/geoloc/country', geoloc)[0] assertEquals(str(country), 'Congo') lat = xpath.queryForNodes('/geoloc/accuracy', geoloc)[0] assertEquals(float(str(lat)), 1.4) acknowledge_iq(stream, event.stanza) q.expect('dbus-return', method='SetLocation') # Server refuses to set Location call_async(q, conn.Location, 'SetLocation', {'lat': 0.0, 'lon': 0.0}) geoloc_iq_set_event = EventPattern( 'stream-iq', predicate=lambda x: xpath.queryForNodes( "/iq/pubsub/publish/item/geoloc", x.stanza)) event = q.expect_many(geoloc_iq_set_event)[0] send_error_reply(stream, event.stanza) q.expect('dbus-error', method='SetLocation') # Request Bob's location bob_handle = conn.get_contact_handle_sync('*****@*****.**') # Gabble should not send a pubsub query. The point of PEP is that we don't # have to do this. pubsub_get_pattern = EventPattern('stream-iq', iq_type='get', query_ns=ns.PUBSUB) q.forbid_events([pubsub_get_pattern]) location = get_location(conn, bob_handle) # Location isn't known yet assertEquals(None, location) # Sync the XMPP stream to ensure Gabble hasn't sent a query. sync_stream(q, stream) # Bob updates his location message = elem('message', from_='*****@*****.**')( elem((ns.PUBSUB_EVENT), 'event')( elem('items', node=ns.GEOLOC)( elem('item', id='12345')( elem(ns.GEOLOC, 'geoloc', attrs={'xml:lang': 'en'})( elem('lat')(u'1.25'), elem('lon')(u'5.5'), elem('country')(u'Belgium'), elem('accuracy')(u'2.3'), elem('timestamp')(date_str), # invalid element, will be ignored by Gabble elem('badger')(u'mushroom'), ))))) stream.send(message) update_event = q.expect('dbus-signal', signal='LocationUpdated') handle, location = update_event.args assertEquals(bob_handle, handle) assertLength(6, location) assertEquals(location['language'], 'en') assertEquals(location['lat'], 1.25) assertEquals(location['lon'], 5.5) assertEquals(location['country'], 'Belgium') assertEquals(location['accuracy'], 2.3) assertEquals(location['timestamp'], date) # Get location again; Gabble should return the cached location loc = get_location(conn, bob_handle) assertEquals(loc, location) charles_handle = conn.get_contact_handle_sync('*****@*****.**') # check that Contacts interface supports location attributes = conn.Contacts.GetContactAttributes( [bob_handle, charles_handle], [cs.CONN_IFACE_LOCATION], False) assertLength(2, attributes) assertContains(bob_handle, attributes) assertContains(charles_handle, attributes) assertEquals( { cs.CONN_IFACE_LOCATION + '/location': location, cs.CONN + '/contact-id': '*****@*****.**' }, attributes[bob_handle]) assertEquals({cs.CONN + '/contact-id': '*****@*****.**'}, attributes[charles_handle]) # Try to set our location by passing a valid with an invalid type (lat is # supposed to be a double) q.forbid_events([geoloc_iq_set_event]) try: conn.Location.SetLocation({'lat': 'pony'}) except dbus.DBusException as e: assertEquals(e.get_dbus_name(), cs.INVALID_ARGUMENT) else: assert False # Bob updates his location again message = elem('message', from_='*****@*****.**')(elem( (ns.PUBSUB_EVENT), 'event')(elem('items', node=ns.GEOLOC)(elem('item', id='12345')(elem( ns.GEOLOC, 'geoloc')(elem('country')(u'France')))))) stream.send(message) update_event = q.expect('dbus-signal', signal='LocationUpdated') handle, location = update_event.args assertEquals(handle, bob_handle) assertLength(1, location) assertEquals(location['country'], 'France') # Now we test explicitly retrieving Bob's location, so we should not forbid # such queries. :) q.unforbid_events([pubsub_get_pattern]) call_async(q, conn.Location, 'RequestLocation', bob_handle) e = q.expect('stream-iq', iq_type='get', query_ns=ns.PUBSUB, to='*****@*****.**') # Hey, while we weren't looking Bob moved abroad! result = make_result_iq(stream, e.stanza) result['from'] = '*****@*****.**' pubsub_node = result.firstChildElement() pubsub_node.addChild( elem('items', node=ns.GEOLOC)(elem('item', id='12345')(elem( ns.GEOLOC, 'geoloc')(elem('country')(u'Chad'))))) stream.send(result) ret = q.expect('dbus-return', method='RequestLocation') location, = ret.value assertLength(1, location) assertEquals(location['country'], 'Chad') # Let's ask again; this time Bob's server hates us for some reason. call_async(q, conn.Location, 'RequestLocation', bob_handle) e = q.expect('stream-iq', iq_type='get', query_ns=ns.PUBSUB, to='*****@*****.**') send_error_reply(stream, e.stanza, elem('error', type='auth')(elem(ns.STANZA, 'forbidden'))) e = q.expect('dbus-error', method='RequestLocation') assertEquals(cs.PERMISSION_DENIED, e.name) # FIXME: maybe we should check that the cache gets invalidated in this # case? We should also test whether or not the cache is invalidated # properly if the contact clears their PEP node. # Let's ask a final time, and disconnect while we're doing so, to make sure # this doesn't break Gabble or Wocky. call_async(q, conn.Location, 'RequestLocation', bob_handle) e = q.expect('stream-iq', iq_type='get', query_ns=ns.PUBSUB, to='*****@*****.**') # Tasty argument unpacking. disconnect_conn returns two lists, one for # expeced_before=[] and one for expected_after=[...] _, (e, ) = disconnect_conn( q, conn, stream, expected_after=[EventPattern('dbus-error', method='RequestLocation')]) assertEquals(cs.CANCELLED, e.name)
lat = xpath.queryForNodes('/geoloc/accuracy', geoloc)[0] assertEquals(float(str(lat)), 1.4) acknowledge_iq(stream, event.stanza) q.expect('dbus-return', method='SetLocation') # Server refuses to set Location call_async(q, conn.Location, 'SetLocation', { 'lat': 0.0, 'lon': 0.0}) geoloc_iq_set_event = EventPattern('stream-iq', predicate=lambda x: xpath.queryForNodes("/iq/pubsub/publish/item/geoloc", x.stanza)) event = q.expect_many(geoloc_iq_set_event)[0] send_error_reply(stream, event.stanza) q.expect('dbus-error', method='SetLocation') # Request Bob's location bob_handle = conn.RequestHandles(1, ['*****@*****.**'])[0] call_async(q, conn.Location, 'GetLocations', [bob_handle]) # Gabble should not send a pubsub query. The point of PEP is that we don't # have to do this. pubsub_get_pattern = EventPattern('stream-iq', iq_type='get', query_ns=ns.PUBSUB) q.forbid_events([ pubsub_get_pattern ]) # GetLocations returns immediately. get_locations = q.expect('dbus-return', method='GetLocations') locations = get_locations.value[0]