def test(q, bus, conn1, conn2, stream1, stream2): # Connection 1 conn1.Connect() q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTING, cs.CSR_REQUESTED]) # Connection 1 blocks because the fake jabber server behind conn1 does not # proceed to the tls handshake. The second connection is independant and # should work. # Connection 2 conn2.Connect() q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTING, cs.CSR_REQUESTED]) q.expect('stream-authenticated') q.expect('dbus-signal', signal='PresencesChanged', args=[{ 1: (cs.PRESENCE_AVAILABLE, 'available', '') }]) q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]) # Disconnection 2 disconnect_conn(q, conn2, stream2)
def test(q, bus, conn, stream): event = q.expect('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard') acknowledge_iq(stream, event.stanza) handle = conn.get_contact_handle_sync('*****@*****.**') call_async(q, conn.Aliasing, 'RequestAliases', [handle]) # First, Gabble sends a PEP query event = q.expect('stream-iq', to='*****@*****.**', iq_type='get', query_ns='http://jabber.org/protocol/pubsub', query_name='pubsub') # We disconnect too soon to get a reply disconnect_conn(q, conn, stream) # fd.o #31412 was that while the request pipeline was shutting down, # it would give the PEP query an error; the aliasing code would # respond by falling back to vCard via the request pipeline, which # was no longer there, *crash*. # check that Gabble hasn't crashed sync_dbus(bus, q, conn)
def test_disconnect_during_update_configuration(q, bus, conn, stream): """ Test disconnecting while a pair of UpdateConfiguration requests are in flight: one waiting for the muc#owner form, and the other waiting for its changes to be acked. """ def join_me_up_buttercup(muc): chan, _, _ = join_muc(q, bus, conn, stream, muc, affiliation='owner') # Gabble grabs the owner configuration form to see whether it's # possible to change the room description. owner_iq = q.expect('stream-iq', to=muc, iq_type='get', query_ns=ns.MUC_OWNER) handle_muc_owner_get_iq(stream, owner_iq.stanza) call_async(q, chan.RoomConfig1, 'UpdateConfiguration', {'Persistent': True}) e = q.expect('stream-iq', to=muc, iq_type='get', query_ns=ns.MUC_OWNER) return chan, e ONE = '1@ttt' one, _ = join_me_up_buttercup(ONE) TWO = '2@ttt' two, e = join_me_up_buttercup(TWO) handle_muc_owner_get_iq(stream, e.stanza) q.expect('stream-iq', to=TWO, iq_type='set', query_ns=ns.MUC_OWNER) disconnect_conn(q, conn, stream, expected_after=[ # Buh. We can't match on paths or on message serials … but we know # there are two of them! EventPattern('dbus-error', method='UpdateConfiguration', name=cs.CANCELLED), EventPattern('dbus-error', method='UpdateConfiguration', name=cs.CANCELLED), ])
def test_too_slow(self, req1, req2, too_slow): """ Regression test for a bug where if the channel was closed before the HTTP responses arrived, the responses finally arriving crashed Gabble. """ # User gets bored, and ends the call. e = EventPattern('dbus-signal', signal='Closed', path=chan.object_path) if too_slow == TOO_SLOW_CLOSE: call_async(self.q, self.chan, 'Close', dbus_interface=cs.CHANNEL) elif too_slow == TOO_SLOW_REMOVE_SELF: self.chan.Hangup (0, "", "", dbus_interface=cs.CHANNEL_TYPE_CALL) elif too_slow == TOO_SLOW_DISCONNECT: disconnect_conn(q, conn, stream, [e]) try: chan.GetMembers() except dbus.DBusException, e: # This should fail because the object's gone away, not because # Gabble's crashed. assert cs.DBUS_ERROR_UNKNOWN_METHOD == e.get_dbus_name(), \ "maybe Gabble crashed? %s" % e else: # Gabble will probably also crash in a moment, because the http # request callbacks will be called after the channel's meant to # have died, which will cause the channel to try to call # methods on the (finalized) connection. assert False, "the channel should be dead by now" return
def test(q, bus, conn1, conn2, stream1, stream2): # Connection 1 conn1.Connect() q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTING, cs.CSR_REQUESTED]) q.expect('stream-authenticated') q.expect('dbus-signal', signal='PresenceUpdate', args=[{1L: (0L, {u'available': {}})}]) q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]) # Connection 2 conn2.Connect() q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTING, cs.CSR_REQUESTED]) q.expect('stream-authenticated') q.expect('dbus-signal', signal='PresenceUpdate', args=[{1L: (0L, {u'available': {}})}]) q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]) # Disconnection 1 disconnect_conn(q, conn1, stream1) # Disconnection 2 disconnect_conn(q, conn2, stream2)
def run_cancel_test(q, bus, conn, stream): call_async (q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: muc, cs.CALL_INITIAL_AUDIO: True, }, byte_arrays = True) q.expect('stream-presence', to = muc + "/test") disconnect_conn(q, conn, stream)
def test_disconnect(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') disconnect_conn(q, conn, stream)
def run_cancel_test(q, bus, conn, stream): call_async(q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: muc, cs.CALL_INITIAL_AUDIO: True, }, byte_arrays=True) q.expect('stream-presence', to=muc + "/test") disconnect_conn(q, conn, stream)
def disconnect_before_disco(q, bus, conn, stream, server=None): 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) # try to create a channel before the disco process is completed. # This creation will fail call_create(q, conn, server=server) # connection is disconnected. CreateChannel fails disconnect_conn(q, conn, stream, [ EventPattern('dbus-error', method='CreateChannel', name=cs.DISCONNECTED)])
def test(q, bus, conn, stream, channel_type): jt = jingletest.JingleTest(stream, 'test@localhost', '[email protected]/Foo') # We intentionally DON'T set remote presence yet. Since Gabble is still # unsure whether to treat contact as offline for this purpose, it # will tentatively allow channel creation and contact handle addition handle = conn.RequestHandles(cs.HT_CONTACT, [jt.remote_jid])[0] if channel_type == cs.CHANNEL_TYPE_STREAMED_MEDIA: path = conn.RequestChannel(cs.CHANNEL_TYPE_STREAMED_MEDIA, cs.HT_CONTACT, handle, True) media_iface = make_channel_proxy(conn, path, 'Channel.Type.StreamedMedia') # So it turns out that the calls to RequestStreams and Disconnect could be # reordered while the first waits on the result of introspecting the # channel's object which is kicked off by making a proxy object for it, # whereas the connection proxy is long ago introspected. Isn't dbus-python # great? Syncing here forces that introspection to finish so we can rely on # the ordering of RequestStreams and Disconnect. Yay. sync_dbus(bus, q, conn) # Now we request streams before either <presence> or caps have arrived if channel_type == cs.CHANNEL_TYPE_STREAMED_MEDIA: call_async(q, media_iface, 'RequestStreams', handle, [cs.MEDIA_STREAM_TYPE_AUDIO]) before_events, after_events = disconnect_conn(q, conn, stream, [EventPattern('dbus-error', method='RequestStreams')]) # RequestStreams should now return NotAvailable assert before_events[0].error.get_dbus_name() == cs.NOT_AVAILABLE, \ before_events[0].error else: call_async(q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: channel_type, cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, cs.TARGET_ID: jt.remote_jid, cs.CALL_INITIAL_AUDIO: True }) before_events, after_events = disconnect_conn(q, conn, stream, [EventPattern('dbus-error', method='CreateChannel')]) # CreateChannel should now return Disconnected assert before_events[0].error.get_dbus_name() == cs.DISCONNECTED, \ before_events[0].error
def test_disconnect(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') disconnect_conn(q, conn, stream)
def test(q, bus, conn, stream): expect_and_handle_get_vcard(q, stream) sync_stream(q, stream) call_async( q, conn.Avatars, 'SetAvatar', 'Guy.brush', 'image/x-mighty-pirate') expect_and_handle_get_vcard(q, stream) iq_event = q.expect( 'stream-iq', iq_type='set', query_ns='vcard-temp', query_name='vCard') call_async( q, conn.Avatars, 'SetAvatar', 'LeChuck.brush', 'image/x-ghost-pirate') disconnect_conn(q, conn, stream) q.expect('dbus-error', method='SetAvatar', name=cs.NOT_AVAILABLE) q.expect('dbus-error', method='SetAvatar', name=cs.NOT_AVAILABLE) sync_dbus(bus, q, conn)
def test(q, bus, conn, stream): expect_and_handle_get_vcard(q, stream) sync_stream(q, stream) call_async( q, conn.Avatars, 'SetAvatar', b'Guy.brush', 'image/x-mighty-pirate') expect_and_handle_get_vcard(q, stream) iq_event = q.expect( 'stream-iq', iq_type='set', query_ns='vcard-temp', query_name='vCard') call_async( q, conn.Avatars, 'SetAvatar', b'LeChuck.brush', 'image/x-ghost-pirate') disconnect_conn(q, conn, stream) q.expect('dbus-error', method='SetAvatar', name=cs.NOT_AVAILABLE) q.expect('dbus-error', method='SetAvatar', name=cs.NOT_AVAILABLE) sync_dbus(bus, q, conn)
def disconnect_before_disco(q, bus, conn, stream, server=None): 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) # try to create a channel before the disco process is completed. # This creation will fail call_create(q, conn, server=server) # connection is disconnected. CreateChannel fails disconnect_conn(q, conn, stream, [ EventPattern( 'dbus-error', method='CreateChannel', name=cs.DISCONNECTED) ])
def test_disconnect_during_update_configuration(q, bus, conn, stream): """ Test disconnecting while a pair of UpdateConfiguration requests are in flight: one waiting for the muc#owner form, and the other waiting for its changes to be acked. """ def join_me_up_buttercup(muc): chan, _, _ = join_muc(q, bus, conn, stream, muc, affiliation='owner') # Gabble grabs the owner configuration form to see whether it's # possible to change the room description. owner_iq = q.expect('stream-iq', to=muc, iq_type='get', query_ns=ns.MUC_OWNER) handle_muc_owner_get_iq(stream, owner_iq.stanza) call_async(q, chan.RoomConfig1, 'UpdateConfiguration', {'Persistent': True}) e = q.expect('stream-iq', to=muc, iq_type='get', query_ns=ns.MUC_OWNER) return chan, e ONE = '1@ttt' one, _ = join_me_up_buttercup(ONE) TWO = '2@ttt' two, e = join_me_up_buttercup(TWO) handle_muc_owner_get_iq(stream, e.stanza) q.expect('stream-iq', to=TWO, iq_type='set', query_ns=ns.MUC_OWNER) disconnect_conn( q, conn, stream, expected_after=[ # Buh. We can't match on paths or on message serials … but we know # there are two of them! EventPattern('dbus-error', method='UpdateConfiguration', name=cs.CANCELLED), EventPattern('dbus-error', method='UpdateConfiguration', name=cs.CANCELLED), ])
def test(q, bus, conn1, conn2, stream1, stream2): # Connection 1 conn1.Connect() q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTING, cs.CSR_REQUESTED]) # Connection 1 blocks because the fake jabber server behind conn1 does not # proceed to the tls handshake. The second connection is independant and # should work. # Connection 2 conn2.Connect() q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTING, cs.CSR_REQUESTED]) q.expect('stream-authenticated') q.expect('dbus-signal', signal='PresenceUpdate', args=[{1L: (0L, {u'available': {}})}]) q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]) # Disconnection 2 disconnect_conn(q, conn2, stream2)
def test(q, bus, conn, stream): event = q.expect('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard') acknowledge_iq(stream, event.stanza) handle = conn.RequestHandles(cs.HT_CONTACT, ['*****@*****.**'])[0] call_async(q, conn.Aliasing, 'RequestAliases', [handle]) # First, Gabble sends a PEP query event = q.expect('stream-iq', to='*****@*****.**', iq_type='get', query_ns='http://jabber.org/protocol/pubsub', query_name='pubsub') # We disconnect too soon to get a reply disconnect_conn(q, conn, stream) # fd.o #31412 was that while the request pipeline was shutting down, # it would give the PEP query an error; the aliasing code would # respond by falling back to vCard via the request pipeline, which # was no longer there, *crash*. # check that Gabble hasn't crashed sync_dbus(bus, q, conn)
def test(q, bus, conn, stream): jt = jingletest.JingleTest(stream, 'test@localhost', '[email protected]/Foo') conn.Connect() q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTING, cs.CSR_REQUESTED]) q.expect('stream-authenticated') q.expect('dbus-signal', signal='PresenceUpdate', args=[{1L: (0L, {u'available': {}})}]) q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]) # We intentionally DON'T set remote presence yet. Since Gabble is still # unsure whether to treat contact as offline for this purpose, it # will tentatively allow channel creation and contact handle addition handle = conn.RequestHandles(cs.HT_CONTACT, [jt.remote_jid])[0] path = conn.RequestChannel(cs.CHANNEL_TYPE_STREAMED_MEDIA, cs.HT_CONTACT, handle, True) media_iface = make_channel_proxy(conn, path, 'Channel.Type.StreamedMedia') # So it turns out that the calls to RequestStreams and Disconnect could be # reordered while the first waits on the result of introspecting the # channel's object which is kicked off by making a proxy object for it, # whereas the connection proxy is long ago introspected. Isn't dbus-python # great? Syncing here forces that introspection to finish so we can rely on # the ordering of RequestStreams and Disconnect. Yay. sync_dbus(bus, q, conn) # Now we request streams before either <presence> or caps have arrived call_async(q, media_iface, 'RequestStreams', handle, [cs.MEDIA_STREAM_TYPE_AUDIO]) event = disconnect_conn(q, conn, stream, [EventPattern('dbus-error', method='RequestStreams')])[0] # RequestStreams should now return NotAvailable assert event.error.get_dbus_name() == cs.NOT_AVAILABLE, event.error
def test(q, bus, conn, stream): event = q.expect('stream-iq', to='localhost', query_ns='http://jabber.org/protocol/disco#items') result = make_result_iq(stream, event.stanza) item = result.firstChildElement().addElement('item') item['jid'] = 'conf.localhost' stream.send(result) event = q.expect('stream-iq', to='conf.localhost', query_ns='http://jabber.org/protocol/disco#info') result = make_result_iq(stream, event.stanza) feature = result.firstChildElement().addElement('feature') feature['var'] = 'http://jabber.org/protocol/muc' identity = result.firstChildElement().addElement('identity') identity['category'] = 'conference' identity['name'] = 'conference service' identity['type'] = 'text' stream.send(result) # Make sure the stream has been processed sync_stream(q, stream) properties = conn.GetAll( tp_name_prefix + '.Connection.Interface.Requests', dbus_interface=dbus.PROPERTIES_IFACE) assert properties.get('Channels') == [], properties['Channels'] assert ({tp_name_prefix + '.Channel.ChannelType': tp_name_prefix + '.Channel.Type.RoomList', tp_name_prefix + '.Channel.TargetHandleType': 0, }, [tp_name_prefix + '.Channel.Type.RoomList.Server'], ) in properties.get('RequestableChannelClasses'),\ properties['RequestableChannelClasses'] call_async(q, conn, 'RequestChannel', tp_name_prefix + '.Channel.Type.RoomList', 0, 0, True) ret, old_sig, new_sig = q.expect_many( EventPattern('dbus-return', method='RequestChannel'), EventPattern('dbus-signal', signal='NewChannel'), EventPattern('dbus-signal', signal='NewChannels'), ) bus = dbus.SessionBus() path1 = ret.value[0] chan = bus.get_object(conn.bus_name, path1) assert new_sig.args[0][0][0] == path1 props = new_sig.args[0][0][1] assert props[tp_name_prefix + '.Channel.ChannelType'] ==\ tp_name_prefix + '.Channel.Type.RoomList' assert props[tp_name_prefix + '.Channel.TargetHandleType'] == 0 assert props[tp_name_prefix + '.Channel.TargetHandle'] == 0 assert props[tp_name_prefix + '.Channel.TargetID'] == '' assert props[tp_name_prefix + '.Channel.Requested'] == True assert props[tp_name_prefix + '.Channel.InitiatorHandle'] \ == conn.GetSelfHandle() assert props[tp_name_prefix + '.Channel.InitiatorID'] \ == 'test@localhost' assert props[tp_name_prefix + '.Channel.Type.RoomList.Server'] == \ 'conf.localhost' assert old_sig.args[0] == path1 assert old_sig.args[1] == tp_name_prefix + '.Channel.Type.RoomList' assert old_sig.args[2] == 0 # handle type assert old_sig.args[3] == 0 # handle assert old_sig.args[4] == 1 # suppress handler # Exercise basic Channel Properties from spec 0.17.7 channel_props = chan.GetAll( tp_name_prefix + '.Channel', dbus_interface=dbus.PROPERTIES_IFACE) assert channel_props.get('TargetHandle') == 0,\ channel_props.get('TargetHandle') assert channel_props['TargetID'] == '', channel_props assert channel_props.get('TargetHandleType') == 0,\ channel_props.get('TargetHandleType') assert channel_props.get('ChannelType') == \ tp_name_prefix + '.Channel.Type.RoomList',\ channel_props.get('ChannelType') assert channel_props['Requested'] == True assert channel_props['InitiatorID'] == 'test@localhost' assert channel_props['InitiatorHandle'] == conn.GetSelfHandle() assert chan.Get( tp_name_prefix + '.Channel.Type.RoomList', 'Server', dbus_interface=dbus.PROPERTIES_IFACE) == \ 'conf.localhost' # FIXME: actually list the rooms! call_async(q, conn.Requests, 'CreateChannel', { tp_name_prefix + '.Channel.ChannelType': tp_name_prefix + '.Channel.Type.RoomList', tp_name_prefix + '.Channel.TargetHandleType': 0, tp_name_prefix + '.Channel.Type.RoomList.Server': 'conference.example.net', }) ret, old_sig, new_sig = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), EventPattern('dbus-signal', signal='NewChannel'), EventPattern('dbus-signal', signal='NewChannels'), ) path2 = ret.value[0] chan = bus.get_object(conn.bus_name, path2) props = ret.value[1] assert props[tp_name_prefix + '.Channel.ChannelType'] ==\ tp_name_prefix + '.Channel.Type.RoomList' assert props[tp_name_prefix + '.Channel.TargetHandleType'] == 0 assert props[tp_name_prefix + '.Channel.TargetHandle'] == 0 assert props[tp_name_prefix + '.Channel.TargetID'] == '' assert props[tp_name_prefix + '.Channel.Requested'] == True assert props[tp_name_prefix + '.Channel.InitiatorHandle'] \ == conn.GetSelfHandle() assert props[tp_name_prefix + '.Channel.InitiatorID'] \ == 'test@localhost' assert props[tp_name_prefix + '.Channel.Type.RoomList.Server'] == \ 'conference.example.net' assert new_sig.args[0][0][0] == path2 assert new_sig.args[0][0][1] == props assert old_sig.args[0] == path2 assert old_sig.args[1] == tp_name_prefix + '.Channel.Type.RoomList' assert old_sig.args[2] == 0 # handle type assert old_sig.args[3] == 0 # handle assert old_sig.args[4] == 1 # suppress handler assert chan.Get( tp_name_prefix + '.Channel.Type.RoomList', 'Server', dbus_interface=dbus.PROPERTIES_IFACE) == \ 'conference.example.net' # FIXME: actually list the rooms! call_async(q, conn.Requests, 'EnsureChannel', { tp_name_prefix + '.Channel.ChannelType': tp_name_prefix + '.Channel.Type.RoomList', tp_name_prefix + '.Channel.TargetHandleType': 0, tp_name_prefix + '.Channel.Type.RoomList.Server': 'conference.example.net', }) ret = q.expect('dbus-return', method='EnsureChannel') yours, ensured_path, ensured_props = ret.value assert not yours assert ensured_path == path2, (ensured_path, path2) disconnect_conn(q, conn, stream, [ EventPattern('dbus-signal', signal='Closed', path=path1), EventPattern('dbus-signal', signal='Closed', path=path2), EventPattern('dbus-signal', signal='ChannelClosed', args=[path1]), EventPattern('dbus-signal', signal='ChannelClosed', args=[path2])])
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)
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): event = q.expect('stream-iq', to='localhost', query_ns='http://jabber.org/protocol/disco#items') result = make_result_iq(stream, event.stanza) item = result.firstChildElement().addElement('item') item['jid'] = 'conf.localhost' stream.send(result) event = q.expect('stream-iq', to='conf.localhost', query_ns='http://jabber.org/protocol/disco#info') result = make_result_iq(stream, event.stanza) feature = result.firstChildElement().addElement('feature') feature['var'] = 'http://jabber.org/protocol/muc' identity = result.firstChildElement().addElement('identity') identity['category'] = 'conference' identity['name'] = 'conference service' identity['type'] = 'text' stream.send(result) # Make sure the stream has been processed sync_stream(q, stream) properties = conn.Properties.GetAll(cs.CONN_IFACE_REQUESTS) assert properties.get('Channels') == [], properties['Channels'] assert ({ cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_ROOM_LIST, cs.TARGET_HANDLE_TYPE: cs.HT_NONE, }, [cs.CHANNEL_TYPE_ROOM_LIST + '.Server'], ) in properties.get('RequestableChannelClasses'),\ properties['RequestableChannelClasses'] # FIXME: actually list the rooms! call_async( q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_ROOM_LIST, cs.TARGET_HANDLE_TYPE: cs.HT_NONE, cs.CHANNEL_TYPE_ROOM_LIST + '.Server': 'conference.example.net', }) ret, sig = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), EventPattern('dbus-signal', signal='NewChannels'), ) path2 = ret.value[0] chan = bus.get_object(conn.bus_name, path2) props = ret.value[1] assertEquals(cs.CHANNEL_TYPE_ROOM_LIST, props[cs.CHANNEL_TYPE]) assertEquals(cs.HT_NONE, props[cs.TARGET_HANDLE_TYPE]) assertEquals(0, props[cs.TARGET_HANDLE]) assertEquals('', props[cs.TARGET_ID]) assertEquals(True, props[cs.REQUESTED]) assertEquals(conn.Properties.Get(cs.CONN, "SelfHandle"), props[cs.INITIATOR_HANDLE]) assertEquals('test@localhost', props[cs.INITIATOR_ID]) assertEquals('conference.example.net', props[cs.CHANNEL_TYPE_ROOM_LIST + '.Server']) assert sig.args[0][0][0] == path2 assert sig.args[0][0][1] == props assert chan.Get(cs.CHANNEL_TYPE_ROOM_LIST, 'Server', dbus_interface=dbus.PROPERTIES_IFACE) == \ 'conference.example.net' # FIXME: actually list the rooms! call_async( q, conn.Requests, 'EnsureChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_ROOM_LIST, cs.TARGET_HANDLE_TYPE: cs.HT_NONE, cs.CHANNEL_TYPE_ROOM_LIST + '.Server': 'conference.example.net', }) ret = q.expect('dbus-return', method='EnsureChannel') yours, ensured_path, ensured_props = ret.value assert not yours assert ensured_path == path2, (ensured_path, path2) disconnect_conn(q, conn, stream, [ EventPattern('dbus-signal', signal='Closed', path=path2), EventPattern('dbus-signal', signal='ChannelClosed', args=[path2]) ])
def test(q, bus, conn, stream, incoming=True, too_slow=None, use_call=False): jt = jingletest.JingleTest(stream, 'test@localhost', '[email protected]/Foo') if use_call: # wjt only updated just about enough of this test for Call to check for # one specific crash, not to verify that it all works... assert incoming assert too_slow in [TOO_SLOW_CLOSE, TOO_SLOW_DISCONNECT] # Tell Gabble we want to use Call. conn.ContactCapabilities.UpdateCapabilities([ (cs.CLIENT + ".CallHandler", [ { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL, cs.CALL_INITIAL_AUDIO: True}, { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL, cs.CALL_INITIAL_VIDEO: True}, ], [ cs.CHANNEL_TYPE_CALL + '/gtalk-p2p', cs.CHANNEL_TYPE_CALL + '/ice-udp', cs.CHANNEL_TYPE_CALL + '/video/h264', ]), ]) # See: http://code.google.com/apis/talk/jep_extensions/jingleinfo.html ji_event = q.expect('stream-iq', query_ns='google:jingleinfo', to='test@localhost') # Regression test for a bug where Gabble would crash if it disconnected # before receiving a reply to the google:jingleinfo query. if too_slow == TOO_SLOW_DISCONNECT_IMMEDIATELY: disconnect_conn(q, conn, stream, []) return listen_port = listen_http(q, 0) jingleinfo = make_result_iq(stream, ji_event.stanza) stun = jingleinfo.firstChildElement().addElement('stun') server = stun.addElement('server') server['host'] = 'resolves-to-1.2.3.4' server['udp'] = '12345' expected_stun_server = '1.2.3.4' expected_stun_port = 12345 # This bit is undocumented... but it has the same format as what we get # from Google Talk servers: # <iq to="censored" from="censored" id="73930208084" type="result"> # <query xmlns="google:jingleinfo"> # <stun> # <server host="stun.l.google.com" udp="19302"/> # <server host="stun4.l.google.com" udp="19302"/> # <server host="stun3.l.google.com" udp="19302"/> # <server host="stun1.l.google.com" udp="19302"/> # <server host="stun2.l.google.com" udp="19302"/> # </stun> # <relay> # <token>censored</token> # <server host="relay.google.com" udp="19295" tcp="19294" # tcpssl="443"/> # </relay> # </query> # </iq> relay = jingleinfo.firstChildElement().addElement('relay') relay.addElement('token', content='jingle all the way') server = relay.addElement('server') server['host'] = '127.0.0.1' server['udp'] = '11111' server['tcp'] = '22222' server['tcpssl'] = '443' # The special regression-test build of Gabble parses this attribute, # because we can't listen on port 80 server['gabble-test-http-port'] = str(listen_port.getHost().port) stream.send(jingleinfo) jingleinfo = None # Spoof some jingle info. This is a regression test for # <https://bugs.freedesktop.org/show_bug.cgi?id=34048>. We assert that # Gabble has ignored this stuff later. iq = IQ(stream, 'set') iq['from'] = "*****@*****.**" query = iq.addElement((ns.GOOGLE_JINGLE_INFO, "query")) stun = query.addElement('stun') server = stun.addElement('server') server['host'] = '6.6.6.6' server['udp'] = '6666' relay = query.addElement('relay') relay.addElement('token', content='mwohahahahaha') server = relay.addElement('server') server['host'] = '127.0.0.1' server['udp'] = '666' server['tcp'] = '999' server['tcpssl'] = '666' stream.send(iq) # We need remote end's presence for capabilities jt.send_remote_presence() # Gabble doesn't trust it, so makes a disco event = q.expect('stream-iq', query_ns='http://jabber.org/protocol/disco#info', to='[email protected]/Foo') jt.send_remote_disco_reply(event.stanza) # Force Gabble to process the capabilities sync_stream(q, stream) remote_handle = conn.RequestHandles(cs.HT_CONTACT, ["[email protected]/Foo"])[0] self_handle = conn.GetSelfHandle() req_pattern = EventPattern('http-request', method='GET', path='/create_session') if incoming: # Remote end calls us jt.incoming_call() if use_call: def looks_like_a_call_to_me(event): channels, = event.args path, props = channels[0] return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_CALL new_channels = q.expect('dbus-signal', signal='NewChannels', predicate=looks_like_a_call_to_me) path = new_channels.args[0][0][0] media_chan = bus.get_object(conn.bus_name, path) else: # FIXME: these signals are not observable by real clients, since they # happen before NewChannels. # The caller is in members # We're pending because of remote_handle mc, _, e = q.expect_many( EventPattern('dbus-signal', signal='MembersChanged', args=[u'', [remote_handle], [], [], [], 0, 0]), EventPattern('dbus-signal', signal='MembersChanged', args=[u'', [], [], [self_handle], [], remote_handle, cs.GC_REASON_INVITED]), EventPattern('dbus-signal', signal='NewSessionHandler')) media_chan = make_channel_proxy(conn, mc.path, 'Channel.Interface.Group') media_iface = make_channel_proxy(conn, mc.path, 'Channel.Type.StreamedMedia') else: call_async(q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA, cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, cs.TARGET_HANDLE: remote_handle, }) ret, old_sig, new_sig = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), EventPattern('dbus-signal', signal='NewChannel', predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args), EventPattern('dbus-signal', signal='NewChannels', predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args[0][0][1].values()), ) path = ret.value[0] media_chan = make_channel_proxy(conn, path, 'Channel.Interface.Group') media_iface = make_channel_proxy(conn, path, 'Channel.Type.StreamedMedia') call_async(q, media_iface, 'RequestStreams', remote_handle, [cs.MEDIA_STREAM_TYPE_AUDIO]) e = q.expect('dbus-signal', signal='NewSessionHandler') req1 = q.expect('http-request', method='GET', path='/create_session') req2 = q.expect('http-request', method='GET', path='/create_session') if too_slow is not None: test_too_slow(q, bus, conn, stream, req1, req2, media_chan, too_slow) return if incoming: assertLength(0, media_iface.ListStreams()) # Accept the call. media_chan.AddMembers([self_handle], '') # In response to the streams call, we now have two HTTP requests # (for RTP and RTCP) handle_request(req1.request, 0) handle_request(req2.request, 1) if incoming: # We accepted the call, and it should get a new, bidirectional stream # now that the relay info request has finished. This tests against a # regression of bug #24023. q.expect('dbus-signal', signal='StreamAdded', args=[1, remote_handle, cs.MEDIA_STREAM_TYPE_AUDIO]) q.expect('dbus-signal', signal='StreamDirectionChanged', args=[1, cs.MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, 0]) else: # Now that we have the relay info, RequestStreams can return q.expect('dbus-return', method='RequestStreams') session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') session_handler.Ready() e = q.expect('dbus-signal', signal='NewStreamHandler') stream_handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler') # Exercise channel properties channel_props = media_chan.GetAll( cs.CHANNEL, dbus_interface=dbus.PROPERTIES_IFACE) assert channel_props['TargetHandle'] == remote_handle assert channel_props['TargetHandleType'] == cs.HT_CONTACT assert channel_props['TargetID'] == '*****@*****.**' assert channel_props['Requested'] == (not incoming) # The new API for STUN servers etc. sh_props = stream_handler.GetAll( cs.STREAM_HANDLER, dbus_interface=dbus.PROPERTIES_IFACE) assert sh_props['NATTraversal'] == 'gtalk-p2p' assert sh_props['CreatedLocally'] == (not incoming) # If Gabble has erroneously paid attention to the contact [email protected] who # sent us a google:jingleinfo stanza, this assertion will fail. assertEquals([(expected_stun_server, expected_stun_port)], sh_props['STUNServers']) credentials_used = {} credentials = {} for relay in sh_props['RelayInfo']: assert relay['ip'] == '127.0.0.1', sh_props['RelayInfo'] assert relay['type'] in ('udp', 'tcp', 'tls') assert relay['component'] in (1, 2) if relay['type'] == 'udp': assert relay['port'] == 11111, sh_props['RelayInfo'] elif relay['type'] == 'tcp': assert relay['port'] == 22222, sh_props['RelayInfo'] elif relay['type'] == 'tls': assert relay['port'] == 443, sh_props['RelayInfo'] assert relay['username'][:8] == 'UUUUUUUU', sh_props['RelayInfo'] assert relay['password'][:8] == 'PPPPPPPP', sh_props['RelayInfo'] assert relay['password'][8:] == relay['username'][8:], \ sh_props['RelayInfo'] assert (relay['password'][8:], relay['type']) not in credentials_used credentials_used[(relay['password'][8:], relay['type'])] = 1 credentials[(relay['component'], relay['type'])] = relay['password'][8:] assert (1, 'udp') in credentials assert (1, 'tcp') in credentials assert (1, 'tls') in credentials assert (2, 'udp') in credentials assert (2, 'tcp') in credentials assert (2, 'tls') in credentials assert ('0', 'udp') in credentials_used assert ('0', 'tcp') in credentials_used assert ('0', 'tls') in credentials_used assert ('1', 'udp') in credentials_used assert ('1', 'tcp') in credentials_used assert ('1', 'tls') in credentials_used # consistency check, since we currently reimplement Get separately for k in sh_props: assert sh_props[k] == stream_handler.Get( 'org.freedesktop.Telepathy.Media.StreamHandler', k, dbus_interface=dbus.PROPERTIES_IFACE), k media_chan.RemoveMembers([self_handle], '') if incoming: q.expect_many( EventPattern('stream-iq', predicate=lambda e: e.query is not None and e.query.name == 'jingle' and e.query['action'] == 'session-terminate'), EventPattern('dbus-signal', signal='Closed'), ) else: # We haven't sent a session-initiate, so we shouldn't expect to send a # session-terminate. q.expect('dbus-signal', signal='Closed')
def test(q, bus, conn, stream): conn.Connect() _, iq_event, disco_event = q.expect_many( EventPattern('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]), 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_gadget(q, stream, disco_event.stanza) act_prop_iface = dbus.Interface(conn, 'org.laptop.Telepathy.ActivityProperties') buddy_info_iface = dbus.Interface(conn, 'org.laptop.Telepathy.BuddyInfo') simple_presence_iface = dbus.Interface(conn, 'org.freedesktop.Telepathy.Connection.Interface.SimplePresence') q.expect('dbus-signal', signal='GadgetDiscovered') gadget_publish(q, stream, conn, True) # join a room room_handle, room_path = join_channel('*****@*****.**', q, conn, stream) call_async (q, buddy_info_iface, 'SetActivities', [("roomid", room_handle)]) # pubsub activity iq event = q.expect('stream-iq', iq_type='set', query_name='pubsub', query_ns=ns.PUBSUB) acknowledge_iq(stream, event.stanza) event = q.expect('dbus-return', method='SetActivities') # make activity public call_async(q, act_prop_iface, 'SetProperties', 1, {'title': 'My test activity', 'private': False}) # pseudo invite event = q.expect('stream-message', to='gadget.localhost') message = event.stanza properties = xpath.queryForNodes('/message/properties', message) assert (properties is not None and len(properties) == 1), repr(properties) assert properties[0].uri == ns.OLPC_ACTIVITY_PROPS assert properties[0]['room'] == '*****@*****.**' assert properties[0]['activity'] == 'roomid' # invite event = q.expect('stream-message', to='*****@*****.**') message = event.stanza x = xpath.queryForNodes('/message/x', message) assert (x is not None and len(x) == 1), repr(x) assert x[0].uri == ns.MUC_USER invites = xpath.queryForNodes('/x/invite', x[0]) assert (invites is not None and len(invites) == 1), repr(invites) assert invites[0]['to'] == 'gadget.localhost' # pubsub activity prop iq event = q.expect('stream-iq') acknowledge_iq(stream, event.stanza) # pubsub activity iq event = q.expect('stream-iq') acknowledge_iq(stream, event.stanza) event = q.expect('dbus-return', method='SetProperties') # Gadget joins the room stream.send(make_muc_presence('none', 'participant', '*****@*****.**', 'inspector', 'gadget.localhost')) muc = bus.get_object(conn.bus_name, room_path) muc_group = dbus.Interface(muc, "org.freedesktop.Telepathy.Channel.Interface.Group") sync_stream(q, stream) members = muc_group.GetMembers() assert conn.InspectHandles(1, members) == ['[email protected]/test'] # Regression test for a nasty bug caused by the presence cache handling # the inspector presence as a non-MUC one because the inspector is not # added to MUC's members. handle = conn.RequestHandles(1, ['*****@*****.**'])[0] presence = simple_presence_iface.GetPresences([handle]) assert presence[handle] == (7, 'unknown', '') # PEP activity update disconnect_conn(q, conn, stream, [EventPattern('stream-iq')])[0]
conn2.Connect() q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTING, cs.CSR_REQUESTED]) q.expect('stream-authenticated') q.expect('dbus-signal', signal='PresencesChanged', args=[{ 1L: (cs.PRESENCE_AVAILABLE, 'available', '') }]) q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]) # Disconnection 2 disconnect_conn(q, conn2, stream2) if __name__ == '__main__': queue = servicetest.IteratingEventQueue(None) queue.verbose = (os.environ.get('CHECK_TWISTED_VERBOSE', '') != '' or '-v' in sys.argv) bus = dbus.SessionBus() params = { 'account': 'test1@localhost/Resource', 'password': '******', 'resource': 'Resource', 'server': 'localhost', 'port': dbus.UInt32(4242),
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) if __name__ == '__main__': exec_test(test, do_connect=False)
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) if __name__ == '__main__': exec_test(test, do_connect=False)
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): # Initial vCard request. Respond only after we call SetAliases(). vcard_get_event = q.expect('stream-iq', iq_type='get', to=None, query_ns=ns.VCARD_TEMP, query_name='vCard') sync_stream(q, stream) handle = conn.Properties.Get(cs.CONN, "SelfHandle") call_async(q, conn.Aliasing, 'SetAliases', {handle: 'Robert the Bruce'}) sync_dbus(bus, q, conn) acknowledge_iq(stream, vcard_get_event.stanza) # Gabble sets a new vCard with our nickname. vcard_set_event = q.expect('stream-iq', iq_type='set', query_ns=ns.VCARD_TEMP, query_name='vCard') assertEquals('Robert the Bruce', xpath.queryForString('/iq/vCard/NICKNAME', vcard_set_event.stanza)) assertEquals(None, xpath.queryForNodes('/iq/vCard/PHOTO', vcard_set_event.stanza)) assertEquals(None, xpath.queryForNodes('/iq/vCard/FN', vcard_set_event.stanza)) assertEquals(None, xpath.queryForNodes('/iq/vCard/N', vcard_set_event.stanza)) # Before the server replies, the user sets their avatar call_async(q, conn.Avatars, 'SetAvatar', 'hello', 'image/png') sync_dbus(bus, q, conn) # This acknowledgement is for the nickname acknowledge_iq(stream, vcard_set_event.stanza) hello_binval = base64.b64encode('hello') # This sets the avatar vcard_set_event = q.expect('stream-iq', iq_type='set', query_ns=ns.VCARD_TEMP, query_name='vCard') assertEquals('Robert the Bruce', xpath.queryForString('/iq/vCard/NICKNAME', vcard_set_event.stanza)) assertLength(1, xpath.queryForNodes('/iq/vCard/PHOTO', vcard_set_event.stanza)) assertEquals('image/png', xpath.queryForString('/iq/vCard/PHOTO/TYPE', vcard_set_event.stanza)) binval = xpath.queryForString('/iq/vCard/PHOTO/BINVAL', vcard_set_event.stanza) assertEquals(hello_binval, binval.strip()) assertEquals(None, xpath.queryForNodes('/iq/vCard/FN', vcard_set_event.stanza)) assertEquals(None, xpath.queryForNodes('/iq/vCard/N', vcard_set_event.stanza)) # Before the server replies, the user sets their ContactInfo call_async(q, conn.ContactInfo, 'SetContactInfo', [(u'fn', [], [u'King Robert I']), (u'n', [], [u'de Brus', u'Robert', u'', u'King', u'']), (u'nickname', [], [u'Bob'])]) sync_dbus(bus, q, conn) # This acknowledgement is for the avatar; SetAvatar won't happen # until this has acknowledge_iq(stream, vcard_set_event.stanza) # This sets the ContactInfo vcard_set_event, _ = q.expect_many( EventPattern('stream-iq', iq_type='set', query_ns=ns.VCARD_TEMP, query_name='vCard'), EventPattern('dbus-return', method='SetAvatar')) assertEquals('Bob', xpath.queryForString('/iq/vCard/NICKNAME', vcard_set_event.stanza)) assertLength(1, xpath.queryForNodes('/iq/vCard/PHOTO', vcard_set_event.stanza)) assertEquals('image/png', xpath.queryForString('/iq/vCard/PHOTO/TYPE', vcard_set_event.stanza)) binval = xpath.queryForString('/iq/vCard/PHOTO/BINVAL', vcard_set_event.stanza) assertEquals(hello_binval, binval.strip()) assertLength(1, xpath.queryForNodes('/iq/vCard/N', vcard_set_event.stanza)) assertEquals('Robert', xpath.queryForString('/iq/vCard/N/GIVEN', vcard_set_event.stanza)) assertEquals('de Brus', xpath.queryForString('/iq/vCard/N/FAMILY', vcard_set_event.stanza)) assertEquals('King', xpath.queryForString('/iq/vCard/N/PREFIX', vcard_set_event.stanza)) assertEquals('King Robert I', xpath.queryForString('/iq/vCard/FN', vcard_set_event.stanza)) # Before the server replies, the user unsets their avatar call_async(q, conn.Avatars, 'SetAvatar', '', '') sync_dbus(bus, q, conn) # This acknowledgement is for the ContactInfo; SetContactInfo won't happen # until this has acknowledge_iq(stream, vcard_set_event.stanza) vcard_set_event, _ = q.expect_many( EventPattern('stream-iq', iq_type='set', query_ns=ns.VCARD_TEMP, query_name='vCard'), EventPattern('dbus-return', method='SetContactInfo')) assertEquals('Bob', xpath.queryForString('/iq/vCard/NICKNAME', vcard_set_event.stanza)) assertEquals(None, xpath.queryForNodes('/iq/vCard/PHOTO', vcard_set_event.stanza)) assertLength(1, xpath.queryForNodes('/iq/vCard/N', vcard_set_event.stanza)) assertEquals('Robert', xpath.queryForString('/iq/vCard/N/GIVEN', vcard_set_event.stanza)) assertEquals('de Brus', xpath.queryForString('/iq/vCard/N/FAMILY', vcard_set_event.stanza)) assertEquals('King', xpath.queryForString('/iq/vCard/N/PREFIX', vcard_set_event.stanza)) assertEquals('King Robert I', xpath.queryForString('/iq/vCard/FN', vcard_set_event.stanza)) # This acknowledgement is for the avatar; SetAvatar won't finish # until this is received acknowledge_iq(stream, vcard_set_event.stanza) q.expect('dbus-return', method='SetAvatar') # Now Gabble gets disconnected. sync_stream(q, stream) disconnect_conn(q, conn, 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 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): # Initial vCard request. Respond only after we call SetAliases(). vcard_get_event = q.expect('stream-iq', iq_type='get', to=None, query_ns=ns.VCARD_TEMP, query_name='vCard') sync_stream(q, stream) handle = conn.Properties.Get(cs.CONN, "SelfHandle") call_async(q, conn.Aliasing, 'SetAliases', {handle: 'Robert the Bruce'}) sync_dbus(bus, q, conn) acknowledge_iq(stream, vcard_get_event.stanza) # Gabble sets a new vCard with our nickname. vcard_set_event = q.expect('stream-iq', iq_type='set', query_ns=ns.VCARD_TEMP, query_name='vCard') assertEquals('Robert the Bruce', xpath.queryForString('/iq/vCard/NICKNAME', vcard_set_event.stanza)) assertEquals(None, xpath.queryForNodes('/iq/vCard/PHOTO', vcard_set_event.stanza)) assertEquals(None, xpath.queryForNodes('/iq/vCard/FN', vcard_set_event.stanza)) assertEquals(None, xpath.queryForNodes('/iq/vCard/N', vcard_set_event.stanza)) # Before the server replies, the user sets their avatar call_async(q, conn.Avatars, 'SetAvatar', b'hello', 'image/png') sync_dbus(bus, q, conn) # This acknowledgement is for the nickname acknowledge_iq(stream, vcard_set_event.stanza) hello_binval = base64.b64encode(b'hello').decode() # This sets the avatar vcard_set_event = q.expect('stream-iq', iq_type='set', query_ns=ns.VCARD_TEMP, query_name='vCard') assertEquals('Robert the Bruce', xpath.queryForString('/iq/vCard/NICKNAME', vcard_set_event.stanza)) assertLength(1, xpath.queryForNodes('/iq/vCard/PHOTO', vcard_set_event.stanza)) assertEquals('image/png', xpath.queryForString('/iq/vCard/PHOTO/TYPE', vcard_set_event.stanza)) binval = xpath.queryForString('/iq/vCard/PHOTO/BINVAL', vcard_set_event.stanza) assertEquals(hello_binval, binval.strip()) assertEquals(None, xpath.queryForNodes('/iq/vCard/FN', vcard_set_event.stanza)) assertEquals(None, xpath.queryForNodes('/iq/vCard/N', vcard_set_event.stanza)) # Before the server replies, the user sets their ContactInfo call_async(q, conn.ContactInfo, 'SetContactInfo', [(u'fn', [], [u'King Robert I']), (u'n', [], [u'de Brus', u'Robert', u'', u'King', u'']), (u'nickname', [], [u'Bob'])]) sync_dbus(bus, q, conn) # This acknowledgement is for the avatar; SetAvatar won't happen # until this has acknowledge_iq(stream, vcard_set_event.stanza) # This sets the ContactInfo vcard_set_event, _ = q.expect_many( EventPattern('stream-iq', iq_type='set', query_ns=ns.VCARD_TEMP, query_name='vCard'), EventPattern('dbus-return', method='SetAvatar')) assertEquals('Bob', xpath.queryForString('/iq/vCard/NICKNAME', vcard_set_event.stanza)) assertLength(1, xpath.queryForNodes('/iq/vCard/PHOTO', vcard_set_event.stanza)) assertEquals('image/png', xpath.queryForString('/iq/vCard/PHOTO/TYPE', vcard_set_event.stanza)) binval = xpath.queryForString('/iq/vCard/PHOTO/BINVAL', vcard_set_event.stanza) assertEquals(hello_binval, binval.strip()) assertLength(1, xpath.queryForNodes('/iq/vCard/N', vcard_set_event.stanza)) assertEquals('Robert', xpath.queryForString('/iq/vCard/N/GIVEN', vcard_set_event.stanza)) assertEquals('de Brus', xpath.queryForString('/iq/vCard/N/FAMILY', vcard_set_event.stanza)) assertEquals('King', xpath.queryForString('/iq/vCard/N/PREFIX', vcard_set_event.stanza)) assertEquals('King Robert I', xpath.queryForString('/iq/vCard/FN', vcard_set_event.stanza)) # Before the server replies, the user unsets their avatar call_async(q, conn.Avatars, 'SetAvatar', '', '') sync_dbus(bus, q, conn) # This acknowledgement is for the ContactInfo; SetContactInfo won't happen # until this has acknowledge_iq(stream, vcard_set_event.stanza) vcard_set_event, _ = q.expect_many( EventPattern('stream-iq', iq_type='set', query_ns=ns.VCARD_TEMP, query_name='vCard'), EventPattern('dbus-return', method='SetContactInfo')) assertEquals('Bob', xpath.queryForString('/iq/vCard/NICKNAME', vcard_set_event.stanza)) assertEquals(None, xpath.queryForNodes('/iq/vCard/PHOTO', vcard_set_event.stanza)) assertLength(1, xpath.queryForNodes('/iq/vCard/N', vcard_set_event.stanza)) assertEquals('Robert', xpath.queryForString('/iq/vCard/N/GIVEN', vcard_set_event.stanza)) assertEquals('de Brus', xpath.queryForString('/iq/vCard/N/FAMILY', vcard_set_event.stanza)) assertEquals('King', xpath.queryForString('/iq/vCard/N/PREFIX', vcard_set_event.stanza)) assertEquals('King Robert I', xpath.queryForString('/iq/vCard/FN', vcard_set_event.stanza)) # This acknowledgement is for the avatar; SetAvatar won't finish # until this is received acknowledge_iq(stream, vcard_set_event.stanza) q.expect('dbus-return', method='SetAvatar') # Now Gabble gets disconnected. sync_stream(q, stream) disconnect_conn(q, conn, stream)
# Connection 1 blocks because the fake jabber server behind conn1 does not # proceed to the tls handshake. The second connection is independant and # should work. # Connection 2 conn2.Connect() q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTING, cs.CSR_REQUESTED]) q.expect('stream-authenticated') q.expect('dbus-signal', signal='PresencesChanged', args=[{1L: (cs.PRESENCE_AVAILABLE, 'available', '')}]) q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]) # Disconnection 2 disconnect_conn(q, conn2, stream2) if __name__ == '__main__': queue = servicetest.IteratingEventQueue(None) queue.verbose = ( os.environ.get('CHECK_TWISTED_VERBOSE', '') != '' or '-v' in sys.argv) bus = dbus.SessionBus() params = { 'account': 'test1@localhost/Resource', 'password': '******', 'resource': 'Resource', 'server': 'localhost', 'port': dbus.UInt32(4242),
def test(q, bus, conn, stream): event = q.expect('stream-iq', to='localhost', query_ns='http://jabber.org/protocol/disco#items') result = make_result_iq(stream, event.stanza) item = result.firstChildElement().addElement('item') item['jid'] = 'conf.localhost' stream.send(result) event = q.expect('stream-iq', to='conf.localhost', query_ns='http://jabber.org/protocol/disco#info') result = make_result_iq(stream, event.stanza) feature = result.firstChildElement().addElement('feature') feature['var'] = 'http://jabber.org/protocol/muc' identity = result.firstChildElement().addElement('identity') identity['category'] = 'conference' identity['name'] = 'conference service' identity['type'] = 'text' stream.send(result) # Make sure the stream has been processed sync_stream(q, stream) properties = conn.Properties.GetAll(cs.CONN_IFACE_REQUESTS) assert properties.get('Channels') == [], properties['Channels'] assert ({ cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_ROOM_LIST, cs.TARGET_HANDLE_TYPE: cs.HT_NONE, }, [cs.CHANNEL_TYPE_ROOM_LIST + '.Server'], ) in properties.get('RequestableChannelClasses'),\ properties['RequestableChannelClasses'] # FIXME: actually list the rooms! call_async(q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_ROOM_LIST, cs.TARGET_HANDLE_TYPE: cs.HT_NONE, cs.CHANNEL_TYPE_ROOM_LIST + '.Server': 'conference.example.net', }) ret, sig = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), EventPattern('dbus-signal', signal='NewChannels'), ) path2 = ret.value[0] chan = bus.get_object(conn.bus_name, path2) props = ret.value[1] assertEquals(cs.CHANNEL_TYPE_ROOM_LIST, props[cs.CHANNEL_TYPE]) assertEquals(cs.HT_NONE, props[cs.TARGET_HANDLE_TYPE]) assertEquals(0, props[cs.TARGET_HANDLE]) assertEquals('', props[cs.TARGET_ID]) assertEquals(True, props[cs.REQUESTED]) assertEquals(conn.Properties.Get(cs.CONN, "SelfHandle"), props[cs.INITIATOR_HANDLE]) assertEquals('test@localhost', props[cs.INITIATOR_ID]) assertEquals('conference.example.net', props[cs.CHANNEL_TYPE_ROOM_LIST+ '.Server']) assert sig.args[0][0][0] == path2 assert sig.args[0][0][1] == props assert chan.Get(cs.CHANNEL_TYPE_ROOM_LIST, 'Server', dbus_interface=dbus.PROPERTIES_IFACE) == \ 'conference.example.net' # FIXME: actually list the rooms! call_async(q, conn.Requests, 'EnsureChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_ROOM_LIST, cs.TARGET_HANDLE_TYPE: cs.HT_NONE, cs.CHANNEL_TYPE_ROOM_LIST + '.Server': 'conference.example.net', }) ret = q.expect('dbus-return', method='EnsureChannel') yours, ensured_path, ensured_props = ret.value assert not yours assert ensured_path == path2, (ensured_path, path2) disconnect_conn(q, conn, stream, [ EventPattern('dbus-signal', signal='Closed', path=path2), EventPattern('dbus-signal', signal='ChannelClosed', args=[path2])])