def join_muc(q, bus, conn, stream, muc, request=None): """ Joins 'muc', returning the muc's handle, a proxy object for the channel, its path and its immutable properties just after the CreateChannel event has fired. The room contains one other member. """ if request is None: request = { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: muc, } muc_handle = request_muc_handle(q, conn, stream, muc) requests = dbus.Interface(conn, cs.CONN_IFACE_REQUESTS) call_async(q, requests, 'CreateChannel', dbus.Dictionary(request, signature='sv')) q.expect('stream-presence', to='%s/test' % muc) # Send presence for other member of room. stream.send(make_muc_presence('owner', 'moderator', muc, 'bob')) # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', muc, 'test')) event = q.expect('dbus-return', method='CreateChannel') path, props = event.value chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text', ['Messages']) return (muc_handle, chan, path, props)
def test_ensure_ensure(q, conn, bus, stream, room_jid): # Call Ensure twice for the same channel. call_async(q, conn.Requests, 'EnsureChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: room_jid, }) call_async(q, conn.Requests, 'EnsureChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: room_jid, }) mc, _ = q.expect_many( EventPattern('dbus-signal', signal='MembersChangedDetailed'), EventPattern('stream-presence', to=('%s/test' % room_jid))) added, removed, local_pending, remote_pending, details = mc.args assert added == [], mc.args assert removed == [], mc.args assert local_pending == [], mc.args assert len(remote_pending) == 1, mc.args # Send presence for other member of room. stream.send(make_muc_presence('owner', 'moderator', room_jid, 'bob')) # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', room_jid, 'test')) mc = q.expect('dbus-signal', signal='MembersChangedDetailed') added, removed, local_pending, remote_pending, details = mc.args assert len(added) == 2, mc.args assert removed == [], mc.args assert local_pending == [], mc.args assert remote_pending == [], mc.args members = conn.inspect_contacts_sync(added) members.sort() assert members == ['%s/bob' % room_jid, '%s/test' % room_jid], members # We should get two EnsureChannel returns es = [] while len(es) < 2: e = q.expect('dbus-return', method='EnsureChannel') es.append(e) e1, e2 = es assert len(e1.value) == 3 yours1, path1, props1 = e1.value assert len(e2.value) == 3 yours2, path2, props2 = e2.value # Exactly one Ensure should get Yours=True. assert (yours1 == (not yours2)) assert path1 == path2, (path1, path2) assert props1 == props2, (props1, props2)
def join_muc(q, bus, conn, stream, muc, request=None, also_capture=[], role='participant', affiliation='none'): """ Joins 'muc', returning a proxy object for the channel, its path and its immutable properties just after the CreateChannel event has fired. The room contains one other member. """ try_to_join_muc(q, bus, conn, stream, muc, request=request) # Send presence for other member of room. stream.send(make_muc_presence('owner', 'moderator', muc, 'bob')) # Send presence for own membership of room. stream.send(make_muc_presence(affiliation, role, muc, 'test')) captured = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), *also_capture) path, props = captured[0].value chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text', ['Subject.DRAFT']) return (chan, path, props) + tuple(captured[1:])
def test(q, bus, conn, stream): iq_event = q.expect('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard') acknowledge_iq(stream, iq_event.stanza) t.check_conn_properties(q, conn) # Create new style tube channel and make sure that is indeed # returned. muc = '*****@*****.**' call_async( q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_DBUS_TUBE, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: muc, cs.DBUS_TUBE_SERVICE_NAME: 'com.example.LolDongs' }) q.expect('stream-presence', to='%s/test' % muc) stream.send(make_muc_presence('owner', 'moderator', muc, 'bob')) stream.send(make_muc_presence('none', 'participant', muc, 'test')) ret, _ = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), EventPattern('dbus-signal', signal='NewChannels'), ) _, props = ret.value assertEquals(props[cs.CHANNEL_TYPE], cs.CHANNEL_TYPE_DBUS_TUBE) assertEquals(props[cs.TARGET_HANDLE_TYPE], cs.HT_ROOM) assertEquals(props[cs.TARGET_ID], muc) # Now try joining the text muc before asking for the tube channel. muc = '*****@*****.**' join_muc(q, bus, conn, stream, muc) call_async( q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_DBUS_TUBE, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: muc, cs.DBUS_TUBE_SERVICE_NAME: 'com.example.LolDongs' }) ret, _ = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), EventPattern('dbus-signal', signal='NewChannels'), ) _, props = ret.value assertEquals(props[cs.CHANNEL_TYPE], cs.CHANNEL_TYPE_DBUS_TUBE) assertEquals(props[cs.TARGET_HANDLE_TYPE], cs.HT_ROOM) assertEquals(props[cs.TARGET_ID], muc)
def test(q, bus, conn, stream): expect_and_handle_get_vcard(q, stream) self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") conn.Aliasing.SetAliases({self_handle: 'lala'}) expect_and_handle_set_vcard(q, stream) event = q.expect('dbus-signal', signal='AliasesChanged', args=[[(self_handle, u'lala')]]) room_jid = '*****@*****.**' # muc stream tube call_async( q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: room_jid }) gfc, _, _ = q.expect_many( EventPattern('dbus-signal', signal='GroupFlagsChanged'), 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]/lala'), EventPattern('stream-presence', to='%s/lala' % room_jid)) assert gfc.args[1] == 0 # Send presence for other member of room. stream.send(make_muc_presence('owner', 'moderator', room_jid, 'bob')) # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', room_jid, 'lala')) 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]/lala', '[email protected]/bob'])) event = q.expect('dbus-return', method='CreateChannel')
def test_create_ensure(q, conn, bus, stream, room_jid, room_handle): # Call both Create and Ensure for the same channel. call_async(q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_HANDLE: room_handle, }) call_async(q, conn.Requests, 'EnsureChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_HANDLE: room_handle, }) mc, _ = q.expect_many( EventPattern('dbus-signal', signal='MembersChanged'), EventPattern('stream-presence', to=('%s/test' % room_jid))) msg, added, removed, local_pending, remote_pending, actor, reason = mc.args assert added == [], mc.args assert removed == [], mc.args assert local_pending == [], mc.args assert len(remote_pending) == 1, mc.args # Send presence for other member of room. stream.send(make_muc_presence('owner', 'moderator', room_jid, 'bob')) # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', room_jid, 'test')) mc = q.expect('dbus-signal', signal='MembersChanged') msg, added, removed, local_pending, remote_pending, actor, reason = mc.args assert len(added) == 2, mc.args assert removed == [], mc.args assert local_pending == [], mc.args assert remote_pending == [], mc.args members = conn.InspectHandles(1, added) members.sort() assert members == ['%s/bob' % room_jid, '%s/test' % room_jid], members create_event, ensure_event = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), EventPattern('dbus-return', method='EnsureChannel')) assert len(create_event.value) == 2 c_path, c_props = create_event.value assert len(ensure_event.value) == 3 yours, e_path, e_props = ensure_event.value assert c_path == e_path, (c_path, e_path) assert c_props == e_props, (c_props, e_props) assert not yours
def test(q, bus, conn, stream): expect_and_handle_get_vcard(q, stream) self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") conn.Aliasing.SetAliases({self_handle: 'lala'}) expect_and_handle_set_vcard(q, stream) event = q.expect('dbus-signal', signal='AliasesChanged', args=[[(self_handle, u'lala')]]) room_jid = '*****@*****.**' # muc stream tube call_async(q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: room_jid}) gfc, _, _ = q.expect_many( EventPattern('dbus-signal', signal='GroupFlagsChanged'), 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]/lala'), EventPattern('stream-presence', to='%s/lala' % room_jid)) assert gfc.args[1] == 0 # Send presence for other member of room. stream.send(make_muc_presence('owner', 'moderator', room_jid, 'bob')) # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', room_jid, 'lala')) 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]/lala', '[email protected]/bob'])) event = q.expect('dbus-return', method='CreateChannel')
def test(q, bus, conn, stream): muc_handle = request_muc_handle(q, conn, stream, '*****@*****.**') call_async(q, conn, 'RequestChannel', cs.CHANNEL_TYPE_TEXT, cs.HT_ROOM, muc_handle, True) q.expect('stream-presence', to='[email protected]/test') # Send presence for own membership of room. stream.send( make_muc_presence('owner', 'moderator', '*****@*****.**', 'test')) iq, ret = q.expect_many( EventPattern('stream-iq', to='*****@*****.**', iq_type='get', query_ns=ns.MUC_OWNER), EventPattern('dbus-return', method='RequestChannel')) handle_muc_get_iq(stream, iq.stanza) text_chan = wrap_channel( bus.get_object(conn.bus_name, ret.value[0]), 'Text') props = dict([(name, id) for id, name, sig, flags in text_chan.TpProperties.ListProperties()]) call_async(q, text_chan.TpProperties, 'SetProperties', [(props['password'], 'foo'), (props['password-required'], True)]) event = q.expect('stream-iq', to='*****@*****.**', iq_type='get', query_ns=ns.MUC_OWNER) handle_muc_get_iq(stream, event.stanza) event = q.expect('stream-iq', to='*****@*****.**', iq_type='set', query_ns=ns.MUC_OWNER) fields = xpath.queryForNodes('/iq/query/x/field', event.stanza) form = {} for field in fields: values = xpath.queryForNodes('/field/value', field) form[field['var']] = [str(v) for v in values] assert form == {'password': ['foo'], 'password_protected': ['1'], 'muc#roomconfig_presencebroadcast' : ['moderator', 'participant', 'visitor']} acknowledge_iq(stream, event.stanza) event = q.expect('dbus-signal', signal='PropertiesChanged') assert event.args == [[(props['password'], 'foo'), (props['password-required'], True)]] q.expect('dbus-return', method='SetProperties', value=()) call_async(q, text_chan.TpProperties, 'SetProperties', [(31337, 'foo'), (props['password-required'], True)]) q.expect('dbus-error', name=cs.INVALID_ARGUMENT) call_async(q, text_chan.TpProperties, 'SetProperties', [(props['password'], True), (props['password-required'], 'foo')]) q.expect('dbus-error', name=cs.NOT_AVAILABLE) call_async(q, text_chan.TpProperties, 'SetProperties', [(props['subject-contact'], 42)]) q.expect('dbus-error', name=cs.PERMISSION_DENIED)
def create_muc(q, conn, stream, props): call_async(q, conn.Requests, 'CreateChannel', props) r = q.expect('stream-presence') muc_name = r.to.split('/', 2)[0] stream.send(make_muc_presence('owner', 'moderator', muc_name, 'test')) r = q.expect('dbus-return', method='CreateChannel') assertEquals(2, len(r.value)) return r.value[1]
def test(q, bus, conn, stream): conn.Connect() expect_and_handle_get_vcard(q, stream) self_handle = conn.GetSelfHandle() conn.Aliasing.SetAliases({self_handle: 'lala'}) expect_and_handle_set_vcard(q, stream) event = q.expect('dbus-signal', signal='AliasesChanged', args=[[(self_handle, u'lala')]]) room_jid = '*****@*****.**' room_handle = request_muc_handle(q, conn, stream, room_jid) call_async(q, conn, 'RequestChannel', cs.CHANNEL_TYPE_TEXT, cs.HT_ROOM, room_handle, True) gfc, _, _ = q.expect_many( EventPattern('dbus-signal', signal='GroupFlagsChanged'), EventPattern('dbus-signal', signal='MembersChanged', args=[u'', [], [], [], [2], 0, 0]), EventPattern('stream-presence', to='%s/lala' % room_jid)) assert gfc.args[1] == 0 # Send presence for other member of room. stream.send(make_muc_presence('owner', 'moderator', room_jid, 'bob')) # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', room_jid, 'lala')) event = q.expect('dbus-signal', signal='MembersChanged', args=[u'', [2, 3], [], [], [], 0, 0]) assert conn.InspectHandles(1, [2]) == ['[email protected]/lala'] assert conn.InspectHandles(1, [3]) == ['[email protected]/bob'] event = q.expect('dbus-return', method='RequestChannel')
def create_pmuc(q, conn, stream, extra_props=None): """ Request a PMUC just for ourselves. """ props = { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_NONE, cs.CONFERENCE_INITIAL_CHANNELS: dbus.Array([], signature='o'), } if extra_props: props.update(extra_props) call_async(q, conn.Requests, 'CreateChannel', props) # wait for the MUC name, so we can inject a reply r = q.expect('stream-presence') pmuc_name = r.to.split('/', 2)[0] assert re.match( r'^private-chat-\w{8}-\w{4}-\w{4}-\w{4}-\w{12}@conf.localhost$', pmuc_name), pmuc_name stream.send(make_muc_presence('owner', 'moderator', pmuc_name, 'test')) # wait for the method return r = q.expect('dbus-return', method='CreateChannel') assert len(r.value) == 2 path, out_props = r.value assert out_props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT assert out_props[cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM assert out_props[cs.TARGET_ID] == pmuc_name assertContains(cs.CHANNEL_IFACE_CONFERENCE, out_props[cs.INTERFACES]) assertEquals(props[cs.CONFERENCE_INITIAL_CHANNELS], out_props[cs.CONFERENCE_INITIAL_CHANNELS]) return pmuc_name, path, out_props
def join_channel(name, q, conn, stream): call_async(q, conn, 'RequestHandles', cs.HT_ROOM, [name]) # announce conference service event = q.expect('stream-iq', to='conference.localhost', query_ns=ns.DISCO_INFO) reply = make_result_iq(stream, event.stanza) feature = reply.firstChildElement().addElement('feature') feature['var'] = ns.MUC stream.send(reply) event = q.expect('dbus-return', method='RequestHandles') handles = event.value[0] call_async(q, conn, 'RequestChannel', cs.CHANNEL_TYPE_TEXT, cs.HT_ROOM, handles[0], True) event = q.expect('stream-presence', to='[email protected]/test') # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', '*****@*****.**', 'test')) event = q.expect('dbus-return', method='RequestChannel') return handles[0], event.value[0]
def test(q, bus, conn, stream): iq_event = q.expect('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard') acknowledge_iq(stream, iq_event.stanza) # muc stream tube call_async( q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: '*****@*****.**', cs.STREAM_TUBE_SERVICE: 'test' }) q.expect('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('owner', 'moderator', '*****@*****.**', 'test')) _, event = q.expect_many( EventPattern( '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'])), EventPattern('dbus-return', method='CreateChannel')) path = event.value[0] props = event.value[1] tube = bus.get_object(conn.bus_name, path) stream_tubes_types = tube.Get(cs.CHANNEL_TYPE_STREAM_TUBE, 'SupportedSocketTypes', dbus_interface=cs.PROPERTIES_IFACE) if os.name == 'posix': assert cs.SOCKET_ACCESS_CONTROL_LOCALHOST in \ stream_tubes_types[cs.SOCKET_ADDRESS_TYPE_UNIX], \ stream_tubes_types[cs.SOCKET_ADDRESS_TYPE_UNIX] # so far we only guarantee to support credentials-passing on Linux if sys.platform == 'linux2': assert cs.SOCKET_ACCESS_CONTROL_CREDENTIALS in \ stream_tubes_types[cs.SOCKET_ADDRESS_TYPE_UNIX], \ stream_tubes_types[cs.SOCKET_ADDRESS_TYPE_UNIX] assertEquals( [cs.SOCKET_ACCESS_CONTROL_LOCALHOST, cs.SOCKET_ACCESS_CONTROL_PORT], stream_tubes_types[cs.SOCKET_ADDRESS_TYPE_IPV4]) assertEquals( [cs.SOCKET_ACCESS_CONTROL_LOCALHOST, cs.SOCKET_ACCESS_CONTROL_PORT], stream_tubes_types[cs.SOCKET_ADDRESS_TYPE_IPV6])
def run_incoming_test(q, bus, conn, stream, bob_leaves_room = False): jp = JingleProtocol031 () jt = JingleTest2(jp, conn, q, stream, 'test@localhost', muc + "/bob") jt.prepare() forbidden = [ no_muji_presences (muc) ] self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") _, _, test_handle, bob_handle = \ join_muc_and_check(q, bus, conn, stream, muc) presence = make_muc_presence('owner', 'moderator', muc, 'bob') muji = ('muji', ns.MUJI, {}, [('content', ns.MUJI, { "name": "Voice" }, [( 'description', ns.JINGLE_RTP, {"media": "audio"}, jt.generate_payloads(jt.audio_codecs))])]) presence.addChild(jp._simple_xml(muji)) stream.send(presence) e = q.expect ('dbus-signal', signal='NewChannels', predicate=lambda e: \ e.args[0][0][1][cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_CALL ) (path, props) = e.args[0][0] assertContains((cs.CHANNEL_TYPE_CALL + '.InitialAudio', True), props.items()) assertContains((cs.CHANNEL_TYPE_CALL + '.InitialVideo', False), props.items()) general_tests (jp, q, bus, conn, stream, path, props) channel = bus.get_object (conn.bus_name, path) props = channel.GetAll (cs.CHANNEL_TYPE_CALL, dbus_interface = dbus.PROPERTIES_IFACE) content = bus.get_object (conn.bus_name, props['Contents'][0]) check_state (q, channel, cs.CALL_STATE_PENDING_RECEIVER) md = jt.get_call_audio_md_dbus() check_and_accept_offer (q, bus, conn, self_handle, content, md) channel.Accept (dbus_interface=cs.CHANNEL_TYPE_CALL) # Preparing stanza e = q.expect('stream-presence', to = muc + "/test") echo_muc_presence (q, stream, e.stanza, 'none', 'participant') # Codecs stanza e = q.expect('stream-presence', to = muc + "/test") echo_muc_presence (q, stream, e.stanza, 'none', 'participant') # Gabble shouldn't send new presences for a while q.forbid_events(forbidden) e = q.expect ('dbus-signal', signal = 'StreamsAdded') cstream = bus.get_object (conn.bus_name, e.args[0][0]) cstream.SetCredentials(jt.ufrag, jt.pwd, dbus_interface=cs.CALL_STREAM_IFACE_MEDIA) candidates = jt.get_call_remote_transports_dbus () cstream.AddCandidates (candidates, dbus_interface=cs.CALL_STREAM_IFACE_MEDIA) e = q.expect('stream-iq', predicate=jp.action_predicate('session-initiate')) jt.parse_session_initiate (e.query) jt.accept() # Bob adds a Video content presence = make_muc_presence('owner', 'moderator', muc, 'bob') presence.addElement ((ns.MUJI, 'muji')).addElement('preparing') stream.send(presence) presence = make_muc_presence('owner', 'moderator', muc, 'bob') muji = ('muji', ns.MUJI, {}, [('content', ns.MUJI, { "name": "Voice" }, [( 'description', ns.JINGLE_RTP, {"media": "audio"}, jt.generate_payloads(jt.audio_codecs))]), ('content', ns.MUJI, { "name": "Camera" }, [( 'description', ns.JINGLE_RTP, {"media": "video"}, jt.generate_payloads(jt.video_codecs))]), ]) presence.addChild(jp._simple_xml(muji)) stream.send(presence) # Gabble noticed bob added a content e = q.expect('dbus-signal', signal = 'ContentAdded') q.unforbid_events (forbidden) content = bus.get_object (conn.bus_name, e.args[0]) check_and_accept_offer (q, bus, conn, self_handle, content, jt.get_call_video_codecs_dbus(), check_codecs_changed = False) # Gabble sends a presence to prepare e = q.expect('stream-presence', to = muc + "/test") echo_muc_presence (q, stream, e.stanza, 'none', 'participant') # Gabble sends a presence with the video codecs e = q.expect('stream-presence', to = muc + "/test") echo_muc_presence (q, stream, e.stanza, 'none', 'participant') # Gabble adds a content to the jingle session and thus a stream is added e = q.expect ('dbus-signal', signal = 'StreamsAdded') cstream = bus.get_object (conn.bus_name, e.args[0][0]) candidates = jt.get_call_remote_transports_dbus () cstream.AddCandidates (candidates, dbus_interface=cs.CALL_STREAM_IFACE_MEDIA) # And now the content-add on the jingle streams e = q.expect('stream-iq', to = muc + "/bob", predicate = lambda x: \ xpath.queryForNodes("/iq/jingle[@action='content-add']", x.stanza)) # Bob leaves the call, bye bob if bob_leaves_room: presence = make_muc_presence('owner', 'moderator', muc, 'bob') presence['type'] = 'unavailable' else: presence = make_muc_presence('owner', 'moderator', muc, 'bob') stream.send(presence) (cmembers, _, _) = q.expect_many( EventPattern ('dbus-signal', signal = 'CallMembersChanged'), # Audio and video stream EventPattern ('dbus-signal', signal = 'StreamsRemoved'), EventPattern ('dbus-signal', signal = 'StreamsRemoved')) # Just bob left assertLength (1, cmembers.args[1])
def test(q, bus, conn, stream, access_control): iq_event = q.expect('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard') acknowledge_iq(stream, iq_event.stanza) muc = '*****@*****.**' _, test_handle, bob_handle = \ join_muc_and_check(q, bus, conn, stream, muc) # Bob offers a stream tube bob_bus_name = ':2.Ym9i' presence = make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob') tubes = presence.addElement((ns.TUBES, 'tubes')) tube = tubes.addElement((None, 'tube')) tube['type'] = 'dbus' tube['initiator'] = '[email protected]/bob' tube['stream-id'] = '10' tube['id'] = '1' tube['service'] = 'com.example.Test' tube['dbus-name'] = bob_bus_name parameters = tube.addElement((None, 'parameters')) parameter = parameters.addElement((None, 'parameter')) parameter['type'] = 'str' parameter['name'] = 'foo' parameter.addContent('bar') stream.send(presence) # tube channel is created def new_chan_predicate(e): path, props = e.args[0][0] return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE event = q.expect('dbus-signal', signal='NewChannels', predicate=new_chan_predicate) channels = event.args[0] path, props = channels[0] assertEquals(cs.CHANNEL_TYPE_DBUS_TUBE, props[cs.CHANNEL_TYPE]) assertEquals('[email protected]/bob', props[cs.INITIATOR_ID]) bob_handle = props[cs.INITIATOR_HANDLE] assertSameSets([cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_TUBE], props[cs.INTERFACES]) assertEquals(False, props[cs.REQUESTED]) assertEquals('*****@*****.**', props[cs.TARGET_ID]) assertEquals('com.example.Test', props[cs.DBUS_TUBE_SERVICE_NAME]) assertEquals({'foo': 'bar'}, props[cs.TUBE_PARAMETERS]) assertEquals([ cs.SOCKET_ACCESS_CONTROL_CREDENTIALS, cs.SOCKET_ACCESS_CONTROL_LOCALHOST ], props[cs.DBUS_TUBE_SUPPORTED_ACCESS_CONTROLS]) tube_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'DBusTube') # only Bob is in DBusNames dbus_names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE, 'DBusNames', dbus_interface=cs.PROPERTIES_IFACE) assertEquals({bob_handle: bob_bus_name}, dbus_names) call_async(q, tube_chan.DBusTube, 'Accept', access_control) return_event, names_changed1, names_changed2, presence_event = q.expect_many( EventPattern('dbus-return', method='Accept'), EventPattern('dbus-signal', signal='DBusNamesChanged', interface=cs.CHANNEL_TYPE_DBUS_TUBE), EventPattern('dbus-signal', signal='DBusNamesChanged', interface=cs.CHANNEL_TYPE_DBUS_TUBE), EventPattern('stream-presence', to='[email protected]/test', predicate=lambda e: t.presence_contains_tube(e))) tube_addr = return_event.value[0] assert len(tube_addr) > 0 # check presence stanza tube_node = xpath.queryForNodes('/presence/tubes/tube', presence_event.stanza)[0] assertEquals('[email protected]/bob', tube_node['initiator']) assertEquals('com.example.Test', tube_node['service']) assertEquals('10', tube_node['stream-id']) assertEquals('dbus', tube_node['type']) assertEquals('1', tube_node['id']) self_bus_name = tube_node['dbus-name'] tubes_self_handle = tube_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'SelfHandle') assertNotEquals(0, tubes_self_handle) # both of us are in DBusNames now dbus_names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE, 'DBusNames', dbus_interface=cs.PROPERTIES_IFACE) assertEquals({ bob_handle: bob_bus_name, tubes_self_handle: self_bus_name }, dbus_names) added, removed = names_changed1.args assertEquals({bob_handle: bob_bus_name}, added) assertEquals([], removed) added, removed = names_changed2.args assertEquals({tubes_self_handle: self_bus_name}, added) assertEquals([], removed) tube_chan.Channel.Close() q.expect_many(EventPattern('dbus-signal', signal='Closed'), EventPattern('dbus-signal', signal='ChannelClosed'))
def test(q, bus, conn, stream): self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") # When Gabble initially requests its avatar from the server, it discovers # it has none. expect_and_handle_get_vcard(q, stream) handle, signalled_token = q.expect('dbus-signal', signal='AvatarUpdated').args assertEquals(self_handle, handle) assertEquals('', signalled_token) # The user sets an avatar. call_async(q, conn.Avatars, 'SetAvatar', AVATAR_1_DATA, AVATAR_1_MIME_TYPE) expect_and_handle_get_vcard(q, stream) expect_and_handle_set_vcard(q, stream) # It's signalled on D-Bus … set_ret, avatar_updated = q.expect_many( EventPattern('dbus-return', method='SetAvatar'), EventPattern('dbus-signal', signal='AvatarUpdated'), ) returned_token, = set_ret.value handle, signalled_token = avatar_updated.args assertEquals(self_handle, handle) assertEquals(returned_token, signalled_token) # … and also on XMPP. broadcast = q.expect('stream-presence', to=None) broadcast_hash = extract_hash_from_presence(broadcast.stanza) assertEquals(AVATAR_1_SHA1, broadcast_hash) # If applications ask Gabble for information about the user's own avatar, # it should be able to answer. (Strictly speaking, expecting Gabble to know # the avatar data is risky because Gabble discards cached vCards after a # while, but we happen to know it takes 20 seconds or so for that to # happen.) known = conn.Avatars.GetKnownAvatarTokens([self_handle]) assertEquals({self_handle: signalled_token}, known) conn.Avatars.RequestAvatars([self_handle]) retrieved = q.expect('dbus-signal', signal='AvatarRetrieved') handle, token, data, mime_type = retrieved.args assertEquals(self_handle, handle) assertEquals(signalled_token, token) assertEquals(AVATAR_1_DATA, data) assertEquals(AVATAR_1_MIME_TYPE, mime_type) # Well, that was quite easy. How about we join a MUC? XEP-0153 §4.1 says: # If a client supports the protocol defined herein, it […] SHOULD # also include the update child in directed presence stanzas (e.g., # directed presence sent when joining Multi-User Chat [5] rooms). # — http://xmpp.org/extensions/xep-0153.html#bizrules-presence join_event = try_to_join_muc(q, bus, conn, stream, MUC) directed_hash = extract_hash_from_presence(join_event.stanza) assertEquals(AVATAR_1_SHA1, directed_hash) # There are two others in the MUC: fredrik has no avatar, wendy has an # avatar. We, of course, have our own avatar. stream.send(make_muc_presence('none', 'participant', MUC, 'fredrik')) stream.send( make_muc_presence('none', 'participant', MUC, 'wendy', photo=AVATAR_2_SHA1)) stream.send( make_muc_presence('owner', 'moderator', MUC, 'test', photo=AVATAR_1_SHA1)) path, _ = q.expect('dbus-return', method='CreateChannel').value chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text') members = chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'Members') assertLength(3, members) fredrik, wendy, muc_self_handle = conn.get_contact_handles_sync( ['%s/%s' % (MUC, x) for x in ["fredrik", "wendy", "test"]]) known = conn.Avatars.GetKnownAvatarTokens(members) # <https://bugs.freedesktop.org/show_bug.cgi?id=32017>: this assertion # failed, the MUC self handle's token was the empty string. assertEquals(AVATAR_1_SHA1, known[muc_self_handle]) assertEquals(AVATAR_2_SHA1, known[wendy]) assertEquals('', known[fredrik]) # 'k, cool. Wendy loves our avatar and switches to it. stream.send( make_muc_presence('none', 'participant', MUC, 'wendy', photo=AVATAR_1_SHA1)) # Okay this is technically assuming that we just expose the SHA1 sums # directly which is not guaranteed … but we do. q.expect('dbus-signal', signal='AvatarUpdated', args=[wendy, AVATAR_1_SHA1]) # Fredrik switches too. stream.send( make_muc_presence('none', 'participant', MUC, 'fredrik', photo=AVATAR_1_SHA1)) q.expect('dbus-signal', signal='AvatarUpdated', args=[fredrik, AVATAR_1_SHA1]) # And we switch to some other avatar. Gabble should update its vCard, and # then update its MUC presence (which the test, acting as the MUC server, # must echo). call_async(q, conn.Avatars, 'SetAvatar', AVATAR_2_DATA, AVATAR_2_MIME_TYPE) expect_and_handle_get_vcard(q, stream) expect_and_handle_set_vcard(q, stream) muc_presence = q.expect('stream-presence', to=('%s/test' % MUC)) directed_hash = extract_hash_from_presence(muc_presence.stanza) stream.send( make_muc_presence('owner', 'moderator', MUC, 'test', photo=directed_hash)) # Gabble should signal an avatar update for both our global self-handle and # our MUC self-handle. (The first of these of course does not need to wait # for the MUC server to echo our presence.) q.expect_many( EventPattern('dbus-signal', signal='AvatarUpdated', args=[self_handle, AVATAR_2_SHA1]), EventPattern('dbus-signal', signal='AvatarUpdated', args=[muc_self_handle, AVATAR_2_SHA1]), )
def test_role_changes(q, bus, conn, stream): # The test user joins a room. Bob is an owner (and moderator); the test # user starts out with no affiliation and the rôle of participant. MUC = 'aoeu@snth' chan, _, immutable_props, disco = join_muc(q, bus, conn, stream, MUC, role='participant', also_capture=[ EventPattern( 'stream-iq', to=MUC, iq_type='get', query_ns=ns.DISCO_INFO), ]) assertContains(cs.CHANNEL_IFACE_ROOM_CONFIG, immutable_props[cs.INTERFACES]) handle_disco_info_iq(stream, disco.stanza) q.expect('dbus-signal', signal='PropertiesChanged', args=[ cs.CHANNEL_IFACE_ROOM_CONFIG, { 'ConfigurationRetrieved': True }, [] ]) # If we try to change the configuration, Gabble should say no: it knows # we're not allowed to do that. call_async(q, chan.RoomConfig1, 'UpdateConfiguration', {}) q.expect('dbus-error', name=cs.PERMISSION_DENIED) config = chan.Properties.GetAll(cs.CHANNEL_IFACE_ROOM_CONFIG) assert not config['CanUpdateConfiguration'], config # If we acquire affiliation='owner', this should be signalled as our # becoming able to modify the channel configuration. stream.send(make_muc_presence('owner', 'moderator', MUC, 'test')) q.expect('dbus-signal', signal='PropertiesChanged', args=[ cs.CHANNEL_IFACE_ROOM_CONFIG, { 'CanUpdateConfiguration': True }, [] ]) # Due to silliness, Gabble has to grab 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) # Bob's ownership rights being taken away should have no effect. stream.send(make_muc_presence('none', 'participant', MUC, 'bob')) # So now we're an owner, and CanUpdateConfiguration is True, we should be # able to change some configuration. props = dbus.Dictionary({ 'Persistent': True, }, signature='sv') call_async(q, chan.RoomConfig1, 'UpdateConfiguration', props) 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) event = q.expect('stream-iq', to=MUC, iq_type='set', query_ns=ns.MUC_OWNER) handle_muc_owner_set_iq(stream, event.stanza, {'muc#roomconfig_persistentroom': ['1']}) q.expect_many( EventPattern('dbus-return', method='UpdateConfiguration'), EventPattern( 'dbus-signal', signal='PropertiesChanged', args=[cs.CHANNEL_IFACE_ROOM_CONFIG, { 'Persistent': True }, []])) # If we lose our affiliation, that should be signalled too. stream.send(make_muc_presence('none', 'participant', MUC, 'test')) q.expect('dbus-signal', signal='PropertiesChanged', args=[ cs.CHANNEL_IFACE_ROOM_CONFIG, { 'CanUpdateConfiguration': False }, [] ]) # Gabble should once again reject attempts to change the configuration call_async(q, chan.RoomConfig1, 'UpdateConfiguration', {}) q.expect('dbus-error', name=cs.PERMISSION_DENIED)
def test(q, bus, conn, stream): conn.Connect() q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]) # Need to call this asynchronously as it involves Gabble sending us a # query call_async(q, conn, 'RequestHandles', 2, ['*****@*****.**']) 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' stream.send(result) event = q.expect('dbus-return', method='RequestHandles') room_handle = event.value[0][0] call_async(q, conn, 'RequestChannel', cs.CHANNEL_TYPE_TEXT, cs.HT_ROOM, room_handle, True) gfc, _, _ = q.expect_many( EventPattern('dbus-signal', signal='GroupFlagsChanged'), EventPattern('dbus-signal', signal='MembersChanged', args=[u'', [], [], [], [2], 0, 0]), EventPattern('stream-presence', to='[email protected]/test')) assert gfc.args[1] == 0 event = q.expect('dbus-signal', signal='GroupFlagsChanged') assert event.args == [0, 1] # Send presence for anonymous other member of room. stream.send(make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob')) # Send presence for anonymous other member of room (2) stream.send(make_muc_presence('owner', 'moderator', '*****@*****.**', 'brian')) # Send presence for nonymous other member of room. stream.send(make_muc_presence('none', 'participant', '*****@*****.**', 'che', '*****@*****.**')) # Send presence for nonymous other member of room (2) stream.send(make_muc_presence('none', 'participant', '*****@*****.**', 'chris', '*****@*****.**')) # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', '*****@*****.**', 'test')) event = q.expect('dbus-signal', signal='GroupFlagsChanged') # Since we received MUC presence that contains an owner JID, the # OWNERS_NOT_AVAILABLE flag should be removed. assert event.args == [0, 1024] event = q.expect('dbus-signal', signal='HandleOwnersChanged', args=[{2: 1, 3: 0, 4: 0, 5: 6, 7: 8}, []]) event = q.expect('dbus-signal', signal='MembersChanged', args=[u'', [2, 3, 4, 5, 7], [], [], [], 0, 0]) assert conn.InspectHandles(1, [2]) == ['[email protected]/test'] assert conn.InspectHandles(1, [3]) == ['[email protected]/bob'] assert conn.InspectHandles(1, [4]) == ['[email protected]/brian'] assert conn.InspectHandles(1, [5]) == ['[email protected]/che'] assert conn.InspectHandles(1, [6]) == ['*****@*****.**'] assert conn.InspectHandles(1, [7]) == ['[email protected]/chris'] assert conn.InspectHandles(1, [8]) == ['*****@*****.**'] event = q.expect('dbus-return', method='RequestChannel') bus = dbus.SessionBus() chan = bus.get_object(conn.bus_name, event.value[0]) group = dbus.Interface(chan, cs.CHANNEL_IFACE_GROUP) props = dbus.Interface(chan, dbus.PROPERTIES_IFACE) # Exercise GetHandleOwners assert group.GetHandleOwners([5, 7]) == [6, 8] # Exercise D-Bus properties all = props.GetAll(cs.CHANNEL_IFACE_GROUP) assert all[u'LocalPendingMembers'] == [], all assert all[u'Members'] == [2, 3, 4, 5, 7], all assert all[u'RemotePendingMembers'] == [], all assert all[u'SelfHandle'] == 2, all assert all[u'HandleOwners'] == { 2: 1, 3: 0, 4: 0, 5: 6, 7: 8 }, all assert (all[u'GroupFlags'] & 2048) == 2048, all.get('GroupFlags')
def test_join(q, bus, conn, stream, room_jid, transient_conflict): """ Tells Gabble to join a MUC, but make the first nick it tries conflict with an existing member of the MUC. If transient_conflict is True, then when Gabble successfully joins with a different nick the originally conflicting user turns out not actually to be in the room (they left while we were retrying). """ # Implementation detail: Gabble uses the first part of your jid (if you # don't have an alias) as your room nickname, and appends an underscore a # few times before giving up. member, member_ = [room_jid + '/' + x for x in ['test', 'test_']] call_async( q, conn.Requests, 'CreateChannel', dbus.Dictionary( { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: room_jid, }, signature='sv')) # Gabble first tries to join as test q.expect('stream-presence', to=member) # MUC says no: there's already someone called test in room_jid presence = elem('presence', from_=member, type='error')(elem(ns.MUC, 'x'), elem('error', type='cancel')(elem( ns.STANZA, 'conflict'), )) stream.send(presence) # Gabble tries again as test_ q.expect('stream-presence', to=member_) # MUC says yes! if not transient_conflict: # Send the other member of the room's presence. This is the nick we # originally wanted. stream.send(make_muc_presence('owner', 'moderator', room_jid, 'test')) # If gabble erroneously thinks the other user's presence is our own, it'll # think that it's got the whole userlist now. If so, syncing here will make # CreateChannel incorrectly return here. sync_stream(q, stream) sync_dbus(bus, q, conn) # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', room_jid, 'test_')) # Only now should we have finished joining the room. event = q.expect('dbus-return', method='CreateChannel') path, props = event.value text_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text') group_props = unwrap(text_chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP)) t, t_ = conn.get_contact_handles_sync([member, member_]) # Check that Gabble think our nickname in the room is test_, not test muc_self_handle = group_props['SelfHandle'] assert muc_self_handle == t_, (muc_self_handle, t_, t) members = group_props['Members'] if transient_conflict: # The user we originally conflicted with isn't actually here; check # there's exactly one member (test_). assert members == [t_], (members, t_, t) else: # Check there are exactly two members (test and test_) assertSameSets([t, t_], members) # In either case, there should be no pending members. assert len(group_props['LocalPendingMembers']) == 0, group_props assert len(group_props['RemotePendingMembers']) == 0, group_props # Check that test_'s handle owner is us, and that test (if it's there) has # no owner. handle_owners = group_props['HandleOwners'] assertEquals(conn.Properties.Get(cs.CONN, "SelfHandle"), handle_owners[t_]) if not transient_conflict: assertEquals(0, handle_owners[t]) # test that closing the channel results in an unavailable message to the # right jid text_chan.Close() event = q.expect('stream-presence', to=member_) assertEquals('unavailable', event.stanza['type'])
def test(q, bus, conn, stream, access_control): conn.Connect() _, iq_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')) acknowledge_iq(stream, iq_event.stanza) muc = '*****@*****.**' _, _, test_handle, bob_handle = \ join_muc_and_check(q, bus, conn, stream, muc) # Bob offers a stream tube bob_bus_name = ':2.Ym9i' presence = make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob') tubes = presence.addElement((ns.TUBES, 'tubes')) tube = tubes.addElement((None, 'tube')) tube['type'] = 'dbus' tube['initiator'] = '[email protected]/bob' tube['stream-id'] = '10' tube['id'] = '1' tube['service'] = 'com.example.Test' tube['dbus-name'] = bob_bus_name parameters = tube.addElement((None, 'parameters')) parameter = parameters.addElement((None, 'parameter')) parameter['type'] = 'str' parameter['name'] = 'foo' parameter.addContent('bar') stream.send(presence) # tubes channel is created event = q.expect('dbus-signal', signal='NewChannels') channels = event.args[0] path, props = channels[0] # tube channel is created event = q.expect('dbus-signal', signal='NewChannels') channels = event.args[0] path, props = channels[0] assertEquals(cs.CHANNEL_TYPE_DBUS_TUBE, props[cs.CHANNEL_TYPE]) assertEquals('[email protected]/bob', props[cs.INITIATOR_ID]) bob_handle = props[cs.INITIATOR_HANDLE] assertEquals([cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_TUBE], props[cs.INTERFACES]) assertEquals(False, props[cs.REQUESTED]) assertEquals('*****@*****.**', props[cs.TARGET_ID]) assertEquals('com.example.Test', props[cs.DBUS_TUBE_SERVICE_NAME]) assertEquals({'foo': 'bar'}, props[cs.TUBE_PARAMETERS]) assertEquals([cs.SOCKET_ACCESS_CONTROL_CREDENTIALS, cs.SOCKET_ACCESS_CONTROL_LOCALHOST], props[cs.DBUS_TUBE_SUPPORTED_ACCESS_CONTROLS]) tube_chan = bus.get_object(conn.bus_name, path) tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_IFACE_TUBE) dbus_tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_DBUS_TUBE) tube_chan_iface = dbus.Interface(tube_chan, cs.CHANNEL) # only Bob is in DBusNames dbus_names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE, 'DBusNames', dbus_interface=cs.PROPERTIES_IFACE) assertEquals({bob_handle: bob_bus_name}, dbus_names) call_async(q, dbus_tube_iface, 'Accept', access_control) return_event, names_changed1, names_changed2, presence_event = q.expect_many( EventPattern('dbus-return', method='Accept'), EventPattern('dbus-signal', signal='DBusNamesChanged', interface=cs.CHANNEL_TYPE_DBUS_TUBE), EventPattern('dbus-signal', signal='DBusNamesChanged', interface=cs.CHANNEL_TYPE_DBUS_TUBE), EventPattern('stream-presence', to='[email protected]/test')) tube_addr = return_event.value[0] assert len(tube_addr) > 0 # check presence stanza tube_node = xpath.queryForNodes('/presence/tubes/tube', presence_event.stanza)[0] assertEquals('[email protected]/bob', tube_node['initiator']) assertEquals('com.example.Test', tube_node['service']) assertEquals('10', tube_node['stream-id']) assertEquals('dbus', tube_node['type']) assertEquals('1', tube_node['id']) self_bus_name = tube_node['dbus-name'] tubes_self_handle = tube_chan.GetSelfHandle(dbus_interface=cs.CHANNEL_IFACE_GROUP) assertNotEquals(0, tubes_self_handle) # both of us are in DBusNames now dbus_names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE, 'DBusNames', dbus_interface=cs.PROPERTIES_IFACE) assertEquals({bob_handle: bob_bus_name, tubes_self_handle: self_bus_name}, dbus_names) added, removed = names_changed1.args assertEquals({bob_handle: bob_bus_name}, added) assertEquals([], removed) added, removed = names_changed2.args assertEquals({tubes_self_handle: self_bus_name}, added) assertEquals([], removed) tube_chan_iface.Close() q.expect_many( EventPattern('dbus-signal', signal='Closed'), EventPattern('dbus-signal', signal='ChannelClosed'))
def test(q, bus, conn, stream): handles = {} handles['bob'] = conn.get_contact_handle_sync('bob@localhost') buddy_iface = dbus.Interface(conn, 'org.laptop.Telepathy.BuddyInfo') act_prop_iface = dbus.Interface(conn, 'org.laptop.Telepathy.ActivityProperties') call_async(q, buddy_iface, 'GetActivities', handles['bob']) event = q.expect('stream-iq', iq_type='get', to='bob@localhost') # Bob has no activities event.stanza['type'] = 'result' event.stanza['to'] = 'test@localhost' event.stanza['from'] = 'bob@localhost' stream.send(event.stanza) event = q.expect('dbus-return', method='GetActivities') # initially, Bob has no activities assert event.value == ([], ) # Bob sends an activity properties message message = domish.Element(('jabber:client', 'message')) message['from'] = 'bob@localhost' message['to'] = 'test@localhost' properties = message.addElement((ns.OLPC_ACTIVITY_PROPS, 'properties')) properties['room'] = '*****@*****.**' properties['activity'] = 'foo_id' property = properties.addElement((None, 'property')) property['type'] = 'str' property['name'] = 'color' property.addContent('#ffff00,#00ffff') property = properties.addElement((None, 'property')) property['type'] = 'bool' property['name'] = 'private' property.addContent('1') stream.send(message) event = q.expect('dbus-signal', signal='ActivityPropertiesChanged') handles['chat'], props = event.args assert props == {'color': '#ffff00,#00ffff', 'private': True} event = q.expect('dbus-signal', signal='ActivitiesChanged') assert event.args[0] == handles['bob'] acts = event.args[1] assert len(acts) == 1 assert acts[0] == ('foo_id', handles['chat']) props = act_prop_iface.GetProperties(handles['chat']) assert props == {'color': '#ffff00,#00ffff', 'private': True} # Bobs invites us to the activity message = domish.Element((None, 'message')) message['from'] = '*****@*****.**' message['to'] = 'test@localhost' x = message.addElement((ns.MUC_USER, 'x')) invite = x.addElement((None, 'invite')) invite['from'] = 'bob@localhost' reason = invite.addElement((None, 'reason')) reason.addContent('No good reason') stream.send(message) event = q.expect('dbus-signal', signal='NewChannel') assert event.args[1] == cs.CHANNEL_TYPE_TEXT assert event.args[2] == 2 # handle type assert event.args[3] == handles['chat'] # handle text_chan = wrap_channel(bus.get_object(conn.bus_name, event.args[0]), 'Text') group_iface = text_chan.Group members = group_iface.GetAllMembers()[0] local_pending = group_iface.GetAllMembers()[1] remote_pending = group_iface.GetAllMembers()[2] assert len(members) == 1 assert conn.inspect_contact_sync(members[0]) == 'bob@localhost' assert len(local_pending) == 1 # FIXME: the username-part-is-nickname assumption assert conn.inspect_contact_sync(local_pending[0]) == \ '[email protected]/test' assert len(remote_pending) == 0 handles['chat_self'] = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, "SelfHandle") assert handles['chat_self'] == local_pending[0] # by now, we should have picked up the extra activity properties call_async(q, buddy_iface, 'GetActivities', handles['bob']) event = q.expect('stream-iq', iq_type='get', to='bob@localhost') # Bob still has no (public) activities event.stanza['type'] = 'result' event.stanza['to'] = 'test@localhost' event.stanza['from'] = 'bob@localhost' stream.send(event.stanza) event = q.expect('dbus-return', method='GetActivities') assert event.value == ([('foo_id', handles['chat'])], ) # OK, now accept the invitation call_async(q, group_iface, 'AddMembers', [handles['chat_self']], 'Oh, OK then') _, event, _ = q.expect_many( EventPattern('stream-presence', to='[email protected]/test'), EventPattern('dbus-signal', signal='MembersChanged'), EventPattern('dbus-return', method='AddMembers')) assert event.args == [ '', [], [handles['bob']], [], [handles['chat_self']], 0, cs.GC_REASON_INVITED ] # Send presence for own membership of room. stream.send( make_muc_presence('owner', 'moderator', '*****@*****.**', 'test')) event = q.expect('dbus-signal', signal='MembersChanged') assert event.args == ['', [handles['chat_self']], [], [], [], 0, 0] call_async(q, buddy_iface, 'SetActivities', [('foo_id', handles['chat'])]) event = q.expect('stream-iq', iq_type='set') event.stanza['type'] = 'result' event.stanza['to'] = 'test@localhost' event.stanza['from'] = 'test@localhost' stream.send(event.stanza) q.expect('dbus-return', method='SetActivities') call_async(q, act_prop_iface, 'SetProperties', handles['chat'], { 'color': '#ffff00,#00ffff', 'private': True }) event = q.expect('dbus-signal', signal='ActivityPropertiesChanged') chat_handle, props = event.args assert chat_handle == handles['chat'] assert props == {'color': '#ffff00,#00ffff', 'private': True} q.expect('dbus-return', method='SetProperties') # Test sending an invitation handles['alice'] = conn.get_contact_handle_sync('alice@localhost') call_async(q, group_iface, 'AddMembers', [handles['alice']], 'I want to test invitations') event = q.expect('stream-message', to='alice@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'] == 'foo_id' property = xpath.queryForNodes('/properties/property', properties[0]) assert (property is not None and len(property) == 2), repr(property) seen = set() for p in property: seen.add(p['name']) if p['name'] == 'color': assert p['type'] == 'str' assert str(p) == '#ffff00,#00ffff' elif p['name'] == 'private': assert p['type'] == 'bool' assert str(p) == '1' else: assert False, 'Unexpected property %s' % p['name'] assert 'color' in seen, seen assert 'private' in seen, seen 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'] == 'alice@localhost' reasons = xpath.queryForNodes('/invite/reason', invites[0]) assert (reasons is not None and len(reasons) == 1), repr(reasons) assert str(reasons[0]) == 'I want to test invitations' call_async(q, act_prop_iface, 'SetProperties', handles['chat'], { 'color': '#f00baa,#f00baa', 'private': True }) event, apc_event, _ = q.expect_many( EventPattern('stream-message', to='alice@localhost'), EventPattern('dbus-signal', signal='ActivityPropertiesChanged'), EventPattern('dbus-return', method='SetProperties'), ) 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'] == 'foo_id' property = xpath.queryForNodes('/properties/property', properties[0]) assert (property is not None and len(property) == 2), repr(property) seen = set() for p in property: seen.add(p['name']) if p['name'] == 'color': assert p['type'] == 'str' assert str(p) == '#f00baa,#f00baa' elif p['name'] == 'private': assert p['type'] == 'bool' assert str(p) == '1' else: assert False, 'Unexpected property %s' % p['name'] assert 'color' in seen, seen assert 'private' in seen, seen chat_handle, props = apc_event.args assert chat_handle == handles['chat'] assert props == {'color': '#f00baa,#f00baa', 'private': True}
def send_muc_presence(q, stream, jid): q.expect('stream-presence', to='%s/test' % jid) stream.send(make_muc_presence('owner', 'moderator', jid, 'bob')) stream.send(make_muc_presence('none', 'participant', jid, 'test'))
def test(q, bus, conn, stream): self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") requests = dbus.Interface(conn, CONN_IFACE_REQUESTS) room_jid = '*****@*****.**' call_async( q, requests, 'CreateChannel', dbus.Dictionary( { CHANNEL_TYPE: CHANNEL_TYPE_TEXT, TARGET_HANDLE_TYPE: HT_ROOM, TARGET_ID: room_jid, }, signature='sv')) expected_jid = '%s/%s' % (room_jid, 'test') q.expect('stream-presence', to=expected_jid) # Send presence for another member of the MUC stream.send(make_muc_presence('owner', 'moderator', room_jid, 'liz')) # This is a themed discussion, so the MUC server forces you to have an # appropriate name. self_presence = make_muc_presence('none', 'participant', room_jid, 'toofer') x = [elt for elt in self_presence.elements() if elt.name == 'x'][0] status = x.addElement('status') status['code'] = '110' # "This is you" status = x.addElement('status') status['code'] = '210' # "I renamed you. Muahaha." stream.send(self_presence) # Gabble should figure out from 110 that it's in the room, and from 210 # that we've been renamed. event = q.expect('dbus-return', method='CreateChannel') path, props = event.value text_chan = bus.get_object(conn.bus_name, path) group_props = unwrap( text_chan.GetAll(CHANNEL_IFACE_GROUP, dbus_interface=dbus.PROPERTIES_IFACE)) liz, toofer, expected_handle = conn.get_contact_handles_sync( ["%s/%s" % (room_jid, m) for m in ['liz', 'toofer', 'test']]) # Check that Gabble think our nickname in the room is toofer not test muc_self_handle = group_props['SelfHandle'] assert muc_self_handle == toofer, (muc_self_handle, toofer, expected_handle) members = group_props['Members'] # Check there are exactly two members (liz and toofer) expected_members = [liz, toofer] assert sorted(members) == sorted(expected_members), \ (members, expected_members) # There should be no pending members. assert len(group_props['LocalPendingMembers']) == 0, group_props assert len(group_props['RemotePendingMembers']) == 0, group_props # Check that toofer's handle owner is us, and that liz has # no owner. handle_owners = group_props['HandleOwners'] assert handle_owners[toofer] == self_handle, \ (handle_owners, toofer, handle_owners[toofer], self_handle) assert handle_owners[liz] == 0, (handle_owners, liz)
def test(q, bus, conn, stream): # Bob has invited us to an activity. message = domish.Element((None, 'message')) message['from'] = '*****@*****.**' message['to'] = 'test@localhost' x = message.addElement(('http://jabber.org/protocol/muc#user', 'x')) invite = x.addElement((None, 'invite')) invite['from'] = 'bob@localhost' reason = invite.addElement((None, 'reason')) reason.addContent('No good reason') stream.send(message) event = q.expect('dbus-signal', signal='NewChannels') path, props = event.args[0][0] assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE]) assertEquals(cs.HT_ROOM, props[cs.TARGET_HANDLE_TYPE]) assertEquals(1, props[cs.TARGET_HANDLE]) text_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text') members = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'Members') local_pending = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'LocalPendingMembers') remote_pending = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'RemotePendingMembers') assert len(members) == 1 assert conn.inspect_contact_sync(members[0]) == 'bob@localhost' bob_handle = members[0] assert len(local_pending) == 1 # FIXME: the username-part-is-nickname assumption assert conn.inspect_contact_sync(local_pending[0][0]) == \ '[email protected]/test' assert len(remote_pending) == 0 room_self_handle = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, "SelfHandle") assert room_self_handle == local_pending[0][0] channel_props = text_chan.Properties.GetAll(cs.CHANNEL) assert channel_props['TargetID'] == '*****@*****.**', channel_props assert channel_props['Requested'] == False assert channel_props['InitiatorID'] == 'bob@localhost' assert channel_props['InitiatorHandle'] == bob_handle # set ourselves to away and back again, to check that we don't send any # presence to the MUC before the invite has been accepted conn.SimplePresence.SetPresence('away', 'failure') conn.SimplePresence.SetPresence('available', 'success') # accept the invitation call_async(q, text_chan.Group, 'AddMembers', [room_self_handle], 'Oh, OK then') event, event2, _ = q.expect_many( EventPattern('stream-presence', to='[email protected]/test'), EventPattern('dbus-signal', signal='MembersChangedDetailed'), EventPattern('dbus-return', method='AddMembers') ) # check that the status we joined with was available / success elem = event.stanza show = [e for e in elem.elements() if e.name == 'show'] assert not show status = [e for e in elem.elements() if e.name == 'status'][0] assert status assert status.children[0] == u'success' # We are added as remote pending while joining the room. The inviter (Bob) # is removed for now. It will be re-added with his channel specific handle # once we have joined. added, removed, local_pending, remote_pending, details = event2.args assertEquals([], added) assertEquals([bob_handle], removed) assertEquals([], local_pending) assertEquals([room_self_handle], remote_pending) assertEquals(cs.GC_REASON_INVITED, details['change-reason']) # Send presence for Bob's membership of room. stream.send(make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob')) # Send presence for own membership of room. stream.send(make_muc_presence('owner', 'moderator', '*****@*****.**', 'test')) event = q.expect('dbus-signal', signal='MembersChangedDetailed') room_bob_handle = conn.get_contact_handle_sync('[email protected]/bob') added, removed, local_pending, remote_pending, details = event.args assertEquals([room_self_handle, room_bob_handle], added) assertEquals([], removed) assertEquals([], local_pending) assertEquals([], remote_pending) # Test sending an invitation alice_handle = conn.get_contact_handle_sync('alice@localhost') call_async(q, text_chan.Group, 'AddMembers', [alice_handle], 'I want to test invitations') 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 == 'http://jabber.org/protocol/muc#user' invites = xpath.queryForNodes('/x/invite', x[0]) assert (invites is not None and len(invites) == 1), repr(invites) assert invites[0]['to'] == 'alice@localhost' reasons = xpath.queryForNodes('/invite/reason', invites[0]) assert (reasons is not None and len(reasons) == 1), repr(reasons) assert str(reasons[0]) == 'I want to test invitations'
def run_outgoing_test(q, bus, conn, stream, close_channel=False): jp = JingleProtocol031 () jt = JingleTest2(jp, conn, q, stream, 'test@localhost', muc + '/bob') jt.prepare() self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") # Not allowed to have muji related presences before we accept the channel forbidden = [ no_muji_presences (muc) ] (path, props) = create_muji_channel (q, conn, stream, muc) q.forbid_events(forbidden) general_tests (jp, q, bus, conn, stream, path, props) channel = bus.get_object (conn.bus_name, path) props = channel.GetAll (cs.CHANNEL_TYPE_CALL, dbus_interface = dbus.PROPERTIES_IFACE) content = bus.get_object (conn.bus_name, props['Contents'][0]) md = jt.get_call_audio_md_dbus() check_and_accept_offer (q, bus, conn, content, md) # Accept the channel, which means we can get muji presences q.unforbid_events (forbidden) channel.Accept() e = q.expect('stream-presence', to = muc + "/test") echo_muc_presence (q, stream, e.stanza, 'none', 'participant') mujinode = xpath.queryForNodes("/presence/muji", e.stanza) assertLength (1, mujinode) # The one with the codecs e = q.expect('stream-presence', to = muc + "/test") echo_muc_presence (q, stream, e.stanza, 'none', 'participant') # Gabble shouldn't send new presences for a while q.forbid_events(forbidden) presence = make_muc_presence('owner', 'moderator', muc, 'bob') presence.addElement ((ns.MUJI, 'muji')).addElement('preparing') stream.send(presence) presence = make_muc_presence('owner', 'moderator', muc, 'bob') muji = ('muji', ns.MUJI, {}, [('content', ns.MUJI, { "name": "Audio" }, [( 'description', ns.JINGLE_RTP, {"media": "audio"}, jt.generate_payloads(jt.audio_codecs))])]) presence.addChild(jp._simple_xml(muji)) stream.send(presence) q.expect('dbus-signal', signal = 'CallStateChanged') # Bob appears and starts a session right afterwards q.expect('dbus-signal', signal = 'CallMembersChanged') q.unforbid_events(forbidden) e = q.expect('dbus-signal', signal = 'NewMediaDescriptionOffer') offer = bus.get_object (conn.bus_name, e.args[0]) offer.Accept(md, dbus_interface=cs.CALL_CONTENT_MEDIA_DESCRIPTION) jt.incoming_call(audio = "Audio") e = q.expect ('dbus-signal', signal = 'StreamsAdded') cstream = bus.get_object (conn.bus_name, e.args[0][0]) candidates = jt.get_call_remote_transports_dbus () cstream.AddCandidates (candidates, dbus_interface=cs.CALL_STREAM_IFACE_MEDIA) # Fake our endpoint being connected endpoints = cstream.Get(cs.CALL_STREAM_IFACE_MEDIA, "Endpoints", dbus_interface=dbus.PROPERTIES_IFACE) assertLength (1, endpoints) endpoint = bus.get_object (conn.bus_name, endpoints[0]) endpoint.SetEndpointState (1, cs.MEDIA_STREAM_STATE_CONNECTED, dbus_interface=cs.CALL_STREAM_ENDPOINT) endpoint.SetEndpointState (2, cs.MEDIA_STREAM_STATE_CONNECTED, dbus_interface=cs.CALL_STREAM_ENDPOINT) e = q.expect ('stream-iq', predicate = jp.action_predicate ('session-accept')) stream.send(jp.xml(jp.ResultIq(jt.peer, e.stanza, []))) # But we want video as well ! c = channel.AddContent ("Camera!", cs.MEDIA_STREAM_TYPE_VIDEO, dbus_interface=cs.CHANNEL_TYPE_CALL) q.expect('dbus-signal', signal = 'ContentAdded') content = bus.get_object (conn.bus_name, c) # wait for the CodecOffer and Accept it q.expect('dbus-signal', signal = 'NewMediaDescriptionOffer') md = jt.get_call_video_md_dbus() check_and_accept_offer (q, bus, conn, content, md) # preparing e = q.expect('stream-presence', to = muc + "/test") echo_muc_presence (q, stream, e.stanza, 'none', 'participant') #codecs e = q.expect('stream-presence', to = muc + "/test") echo_muc_presence (q, stream, e.stanza, 'none', 'participant') # Bob would like to join our video party presence = make_muc_presence('owner', 'moderator', muc, 'bob') muji = ('muji', ns.MUJI, {}, [('content', ns.MUJI, { "name": "Audio" }, [( 'description', ns.JINGLE_RTP, {"media": "audio"}, jt.generate_payloads(jt.audio_codecs))]), ('content', ns.MUJI, { "name": "Camera!" }, [( 'description', ns.JINGLE_RTP, {"media": "video"}, jt.generate_payloads(jt.video_codecs))]), ]) presence.addChild(jp._simple_xml(muji)) stream.send(presence) # new codec offer as bob threw in some codecs q.expect('dbus-signal', signal='NewMediaDescriptionOffer') check_and_accept_offer (q, bus, conn, self_handle, content, codecs, check_codecs_changed = False) # Bob sends a content node = jp.SetIq(jt.peer, jt.jid, [ jp.Jingle(jt.sid, jt.peer, 'content-add', [ jp.Content('videostream', 'initiator', 'both', jp.Description('video', [ jp.PayloadType(name, str(rate), str(id), parameters) for (name, id, rate, parameters) in jt.video_codecs ]), jp.TransportGoogleP2P()) ]) ]) stream.send(jp.xml(node)) # We get a new stream q.expect('dbus-signal', signal = 'StreamsAdded') # Sync up the stream to ensure we sent out all the xmpp traffic that was # the result of a stream being added sync_stream (q, stream) # happiness.. Now let's hang up if close_channel: channel.Close() hangup_event = EventPattern ('dbus-signal', signal = "Closed", path = path) else: channel.Hangup (0, "", "", dbus_interface=cs.CHANNEL_TYPE_CALL) hangup_event = EventPattern ('dbus-signal', signal='CallStateChanged') # Should change the call state to ended, send a session-terminate to our # only peer and send a muc presence without any mention of muji q.forbid_events(forbidden) q.expect_many (EventPattern ('stream-presence', to = muc + "/test"), EventPattern ('stream-iq', predicate=jp.action_predicate ('session-terminate')), hangup_event) if not close_channel: channel.Close() q.expect ('dbus-signal', signal="Closed", path = path) try: channel.Close() raise AssertionError ("Channel didn't actually close") except DBusException: pass
def test(q, bus, conn, stream): room = '*****@*****.**' call_async(q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: room }) expected_muc_jid = '%s/%s' % (room, 'test') q.expect('stream-presence', to=expected_muc_jid) # tell gabble the room needs a password denied = \ elem('jabber:client', 'presence', from_=expected_muc_jid, type='error')( elem(ns.MUC, 'x'), elem('error', type='auth')( elem(ns.STANZA, 'not-authorized'), ), ) stream.send(denied) cc, _, _ = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), EventPattern('dbus-signal', signal='NewChannels'), EventPattern('dbus-signal', signal='PasswordFlagsChanged', args=[cs.PASSWORD_FLAG_PROVIDE, 0])) chan = wrap_channel(bus.get_object(conn.bus_name, cc.value[0]), 'Text') flags = chan.Password.GetPasswordFlags() assertEquals(cs.PASSWORD_FLAG_PROVIDE, flags) call_async(q, chan.Password, 'ProvidePassword', 'brand new benz') expect_attempt(q, expected_muc_jid, 'brand new benz') # Try again while the first attempt is outstanding. Gabble should say no. call_async(q, chan.Password, 'ProvidePassword', 'faster faster') q.expect('dbus-error', method='ProvidePassword') # Sorry, wrong password. stream.send(denied) ret = q.expect('dbus-return', method='ProvidePassword') assert not ret.value[0] call_async(q, chan.Password, 'ProvidePassword', 'bougie friends') expect_attempt(q, expected_muc_jid, 'bougie friends') # Well, this may be the right password, but actually that nick is in use. presence = elem('presence', from_=expected_muc_jid, type='error')( elem(ns.MUC, 'x'), elem('error', type='cancel')( elem(ns.STANZA, 'conflict'), )) stream.send(presence) # Okay, so Gabble tries again, with a new JID *and the same password*. expected_muc_jid = expected_muc_jid + '_' expect_attempt(q, expected_muc_jid, 'bougie friends') # Hey this worked. stream.send(make_muc_presence('none', 'participant', room, 'test_')) ret, _ = q.expect_many( EventPattern('dbus-return', method='ProvidePassword'), EventPattern('dbus-signal', signal='PasswordFlagsChanged', args=[0, cs.PASSWORD_FLAG_PROVIDE])) assert ret.value[0]
def test_gtalk_weirdness(q, bus, conn, stream, room_jid): """ There's a strange bug in the Google Talk MUC server where it sends the <conflict/> stanza twice. This has been reported to their server team; but in any case it triggered a crazy bug in Gabble, so here's a regression test. """ # Implementation detail: Gabble uses the first part of your jid (if you # don't have an alias) as your room nickname, and appends an underscore a # few times before giving up. jids = ['%s/test%s' % (room_jid, x) for x in ['', '_', '__']] member, member_, member__ = jids # Gabble should never get as far as trying to join as 'test__' since # joining as 'test_' will succeed. q.forbid_events([EventPattern('stream-presence', to=member__)]) call_async( q, conn.Requests, 'CreateChannel', dbus.Dictionary( { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: room_jid, }, signature='sv')) # Gabble first tries to join as test q.expect('stream-presence', to=member) # Google Talk says no from 'test', twice. presence = elem('presence', from_=member, type='error')(elem(ns.MUC, 'x'), elem('error', type='cancel')(elem( ns.STANZA, 'conflict'), )) stream.send(presence) stream.send(presence) # Gabble should try to join again as test_ q.expect('stream-presence', to=member_) # Since 'test_' is not in use in the MUC, joining should succeed. According # to XEP-0045 §7.1.3 <http://xmpp.org/extensions/xep-0045.html#enter-pres>: # The service MUST first send the complete list of the existing occupants # to the new occupant and only then send the new occupant's own presence # to the new occupant # but groupchat.google.com cheerfully violates this. stream.send(make_muc_presence('none', 'participant', room_jid, 'test_')) # Here's some other random person, who owns the MUC. stream.send( make_muc_presence('owner', 'moderator', room_jid, 'foobar_gmail.com')) # And here's our hypothetical other self. stream.send(make_muc_presence('none', 'participant', room_jid, 'test')) # The Gabble bug makes this time out: because Gabble thinks it's joining as # test__ it ignores the presence for test_, since it's not flagged with # code='210' to say “this is you”. (This is acceptable behaviour by the # server: it only needs to include code='210' if it's assigned the client a # name other than the one it asked for. # # The forbidden stream-presence event above doesn't blow up here because # servicetest doesn't process events on the 'stream-*' queue at all when # we're not waiting for one. But during disconnection in the test clean-up, # the forbidden event is encountered and correctly flagged up. event = q.expect('dbus-return', method='CreateChannel') path, _ = event.value text_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text') # As far as Gabble's concerned, the two other participants joined # immediately after we did. We can't request handles for them before we # try to join the MUC, because until we do so, Gabble doesn't know that # room_jid is a MUC, and so considers these three JIDs to be different # resources of the same contact. There is no race between this method # returning and MembersChangedDetailed firing, because libdbus reorders # messages when you make blocking calls. handle, handle_, handle__, foobar_handle = conn.get_contact_handles_sync( jids + ['%s/foobar_gmail.com' % room_jid]) q.expect('dbus-signal', signal='MembersChangedDetailed', predicate=lambda e: e.args[0:4] == [[foobar_handle], [], [], []]) q.expect('dbus-signal', signal='MembersChangedDetailed', predicate=lambda e: e.args[0:4] == [[handle], [], [], []]) group_props = text_chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP) assertEquals(handle_, group_props['SelfHandle']) assertSameSets([handle, handle_, foobar_handle], group_props['Members'])
def test(q, bus, conn, stream): conn.Connect() _, iq_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')) acknowledge_iq(stream, iq_event.stanza) buddy_iface = dbus.Interface(conn, 'org.laptop.Telepathy.BuddyInfo') act_prop_iface = dbus.Interface(conn, 'org.laptop.Telepathy.ActivityProperties') bob_handle = conn.RequestHandles(1, ['bob@localhost'])[0] # Bob invites us to a chatroom, pre-seeding properties message = domish.Element(('jabber:client', 'message')) message['from'] = 'bob@localhost' message['to'] = 'test@localhost' properties = message.addElement( (ns.OLPC_ACTIVITY_PROPS, 'properties')) properties['room'] = '*****@*****.**' properties['activity'] = 'foo_id' property = properties.addElement((None, 'property')) property['type'] = 'str' property['name'] = 'title' property.addContent('From the invitation') property = properties.addElement((None, 'property')) property['type'] = 'bool' property['name'] = 'private' property.addContent('1') stream.send(message) message = domish.Element((None, 'message')) message['from'] = '*****@*****.**' message['to'] = 'test@localhost' x = message.addElement((ns.MUC_USER, 'x')) invite = x.addElement((None, 'invite')) invite['from'] = 'bob@localhost' reason = invite.addElement((None, 'reason')) reason.addContent('No good reason') stream.send(message) event = q.expect('dbus-signal', signal='NewChannel') assert event.args[1] == cs.CHANNEL_TYPE_TEXT assert event.args[2] == 2 # handle type assert event.args[3] == 1 # handle room_handle = 1 text_chan = bus.get_object(conn.bus_name, event.args[0]) chan_iface = dbus.Interface(text_chan, cs.CHANNEL) group_iface = dbus.Interface(text_chan, cs.CHANNEL_IFACE_GROUP) members = group_iface.GetAllMembers()[0] local_pending = group_iface.GetAllMembers()[1] remote_pending = group_iface.GetAllMembers()[2] assert len(members) == 1 assert conn.InspectHandles(1, members)[0] == 'bob@localhost' bob_handle = members[0] assert len(local_pending) == 1 # FIXME: the username-part-is-nickname assumption assert conn.InspectHandles(1, local_pending)[0] == \ '[email protected]/test' assert len(remote_pending) == 0 room_self_handle = group_iface.GetSelfHandle() assert room_self_handle == local_pending[0] # by now, we should have picked up the extra activity properties buddy_iface = dbus.Interface(conn, 'org.laptop.Telepathy.BuddyInfo') call_async(q, buddy_iface, 'GetActivities', bob_handle) event = q.expect('stream-iq', iq_type='get', to='bob@localhost') # Bob still has no (public) activities event.stanza['type'] = 'result' event.stanza['to'] = 'test@localhost' event.stanza['from'] = 'bob@localhost' stream.send(event.stanza) event = q.expect('dbus-return', method='GetActivities') assert event.value == ([('foo_id', room_handle)],) props = act_prop_iface.GetProperties(room_handle) assert len(props) == 2 assert props['title'] == 'From the invitation' assert props['private'] == True # Now Bob changes the properties message = domish.Element(('jabber:client', 'message')) message['from'] = 'bob@localhost' message['to'] = 'test@localhost' properties = message.addElement( (ns.OLPC_ACTIVITY_PROPS, 'properties')) properties['room'] = '*****@*****.**' properties['activity'] = 'foo_id' property = properties.addElement((None, 'property')) property['type'] = 'str' property['name'] = 'title' property.addContent('Mushroom, mushroom') property = properties.addElement((None, 'property')) property['type'] = 'bool' property['name'] = 'private' property.addContent('0') stream.send(message) event = q.expect('dbus-signal', signal='ActivityPropertiesChanged') assert event.args == [room_handle, {'title': 'Mushroom, mushroom', 'private': False }] assert act_prop_iface.GetProperties(room_handle) == \ event.args[1] # OK, now accept the invitation call_async(q, group_iface, 'AddMembers', [room_self_handle], 'Oh, OK then') q.expect_many( EventPattern('stream-presence', to='[email protected]/test'), EventPattern('dbus-signal', signal='MembersChanged', args=['', [], [bob_handle], [], [room_self_handle], 0, cs.GC_REASON_INVITED]) ) # Send presence for own membership of room. stream.send(make_muc_presence('owner', 'moderator', '*****@*****.**', 'test')) q.expect('dbus-return', method='AddMembers') event = q.expect('dbus-signal', signal='MembersChanged') assert event.args == ['', [room_self_handle], [], [], [], 0, 0] call_async(q, buddy_iface, 'SetActivities', [('foo_id', room_handle)]) event = q.expect('stream-iq', iq_type='set') # Now that it's not private, it'll go in my PEP event.stanza['type'] = 'result' event.stanza['to'] = 'test@localhost' event.stanza['from'] = 'test@localhost' stream.send(event.stanza) q.expect('dbus-return', method='SetActivities') # Bob changes the properties and tells the room he's done so message = domish.Element(('jabber:client', 'message')) message['from'] = '[email protected]/bob' message['to'] = '*****@*****.**' properties = message.addElement( (ns.OLPC_ACTIVITY_PROPS, 'properties')) properties['activity'] = 'foo_id' property = properties.addElement((None, 'property')) property['type'] = 'str' property['name'] = 'title' property.addContent('Badger badger badger') property = properties.addElement((None, 'property')) property['type'] = 'bool' property['name'] = 'private' property.addContent('0') stream.send(message) event = q.expect('stream-iq', iq_type='set') message = event.stanza activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities', message) assert (activities is not None and len(activities) == 1), repr(activities) assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS properties = xpath.queryForNodes('/activities/properties', activities[0]) 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'] == 'foo_id' property = xpath.queryForNodes('/properties/property', properties[0]) assert (property is not None and len(property) == 2), repr(property) seen = set() for p in property: seen.add(p['name']) if p['name'] == 'title': assert p['type'] == 'str' assert str(p) == 'Badger badger badger' elif p['name'] == 'private': assert p['type'] == 'bool' assert str(p) == '0' else: assert False, 'Unexpected property %s' % p['name'] assert 'title' in seen, seen assert 'private' in seen, seen event.stanza['type'] = 'result' event.stanza['to'] = 'test@localhost' event.stanza['from'] = 'test@localhost' stream.send(event.stanza) act_prop_iface = dbus.Interface(conn, 'org.laptop.Telepathy.ActivityProperties') # test sets the title and sets private back to True call_async(q, act_prop_iface, 'SetProperties', room_handle, {'title': 'I can set the properties too', 'private': True}) event = q.expect('stream-message', to='*****@*****.**') 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'] == 'foo_id' property = xpath.queryForNodes('/properties/property', properties[0]) assert (property is not None and len(property) == 2), repr(property) seen = set() for p in property: seen.add(p['name']) if p['name'] == 'title': assert p['type'] == 'str' assert str(p) == 'I can set the properties too' elif p['name'] == 'private': assert p['type'] == 'bool' assert str(p) == '1' else: assert False, 'Unexpected property %s' % p['name'] assert 'title' in seen, seen assert 'private' in seen, seen event = q.expect('stream-iq', iq_type='set') event.stanza['type'] = 'result' event.stanza['to'] = 'test@localhost' event.stanza['from'] = 'test@localhost' stream.send(event.stanza) message = event.stanza activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities', message) assert (activities is not None and len(activities) == 1), repr(activities) assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS properties = xpath.queryForNodes('/activities/properties', activities[0]) assert properties is None, repr(properties) event = q.expect('stream-iq', iq_type='set') event.stanza['type'] = 'result' event.stanza['to'] = 'test@localhost' event.stanza['from'] = 'test@localhost' stream.send(event.stanza) message = event.stanza activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities', message) assert (activities is not None and len(activities) == 1), repr(activities) assert activities[0].uri == ns.OLPC_ACTIVITIES activity = xpath.queryForNodes('/activities/activity', activities[0]) assert activity is None, repr(activity) q.expect('dbus-return', method='SetProperties') # test sets the title and sets private back to True call_async(q, act_prop_iface, 'SetProperties', room_handle, {'title': 'I can set the properties too', 'private': False}) event = q.expect('stream-message', to='*****@*****.**') 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'] == 'foo_id' property = xpath.queryForNodes('/properties/property', properties[0]) assert (property is not None and len(property) == 2), repr(property) seen = set() for p in property: seen.add(p['name']) if p['name'] == 'title': assert p['type'] == 'str' assert str(p) == 'I can set the properties too' elif p['name'] == 'private': assert p['type'] == 'bool' assert str(p) == '0' else: assert False, 'Unexpected property %s' % p['name'] assert 'title' in seen, seen assert 'private' in seen, seen event = q.expect('stream-iq', iq_type='set') event.stanza['type'] = 'result' event.stanza['to'] = 'test@localhost' event.stanza['from'] = 'test@localhost' stream.send(event.stanza) message = event.stanza activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities', message) assert (activities is not None and len(activities) == 1), repr(activities) assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS properties = xpath.queryForNodes('/activities/properties', activities[0]) 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'] == 'foo_id' property = xpath.queryForNodes('/properties/property', properties[0]) assert (property is not None and len(property) == 2), repr(property) seen = set() for p in property: seen.add(p['name']) if p['name'] == 'title': assert p['type'] == 'str' assert str(p) == 'I can set the properties too' elif p['name'] == 'private': assert p['type'] == 'bool' assert str(p) == '0' else: assert False, 'Unexpected property %s' % p['name'] assert 'title' in seen, seen assert 'private' in seen, seen event = q.expect('stream-iq', iq_type='set') event.stanza['type'] = 'result' event.stanza['to'] = 'test@localhost' event.stanza['from'] = 'test@localhost' stream.send(event.stanza) message = event.stanza activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities', message) assert (activities is not None and len(activities) == 1), repr(activities) assert activities[0].uri == ns.OLPC_ACTIVITIES activity = xpath.queryForNodes('/activities/activity', activities[0]) assert (activity is not None and len(activity) == 1), repr(activity) assert activity[0]['room'] == '*****@*****.**' assert activity[0]['type'] == 'foo_id' # sic q.expect('dbus-return', method='SetProperties') chan_iface.Close() event = q.expect('stream-iq', iq_type='set') event.stanza['type'] = 'result' event.stanza['to'] = 'test@localhost' event.stanza['from'] = 'test@localhost' stream.send(event.stanza) message = event.stanza activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities', message) assert (activities is not None and len(activities) == 1), repr(activities) assert activities[0].uri == ns.OLPC_ACTIVITIES activity = xpath.queryForNodes('/activities/activity', activities[0]) assert activity is None, repr(activity) event = q.expect('stream-iq', iq_type='set') event.stanza['type'] = 'result' event.stanza['to'] = 'test@localhost' event.stanza['from'] = 'test@localhost' stream.send(event.stanza) message = event.stanza activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities', message) assert (activities is not None and len(activities) == 1), repr(activities) assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS properties = xpath.queryForNodes('/activities/properties', activities[0]) assert properties is None, repr(properties)
def test(q, bus, conn, stream, access_control): iq_event = q.expect('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard') acknowledge_iq(stream, iq_event.stanza) # check if we can request muc D-Bus tube t.check_conn_properties(q, conn) self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") self_name = conn.inspect_contact_sync(self_handle) # offer a D-Bus tube to another room using new API muc = '*****@*****.**' request = { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_DBUS_TUBE, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: '*****@*****.**', cs.DBUS_TUBE_SERVICE_NAME: 'com.example.TestCase', } join_muc(q, bus, conn, stream, muc, request=request) exv = q.expect('dbus-signal', signal='NewChannels') channels = exv.args[0] assert len(channels) == 1 path, prop = channels[0] assert prop[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE assert prop[cs.INITIATOR_ID] == '[email protected]/test' assert prop[cs.REQUESTED] == True assert prop[cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM assert prop[cs.TARGET_ID] == '*****@*****.**' assert prop[cs.DBUS_TUBE_SERVICE_NAME] == 'com.example.TestCase' assert prop[cs.DBUS_TUBE_SUPPORTED_ACCESS_CONTROLS] == [ cs.SOCKET_ACCESS_CONTROL_CREDENTIALS, cs.SOCKET_ACCESS_CONTROL_LOCALHOST ] # check that the tube channel is in the channels list all_channels = conn.Get(cs.CONN_IFACE_REQUESTS, 'Channels', dbus_interface=cs.PROPERTIES_IFACE, byte_arrays=True) assertContains((path, prop), all_channels) tube_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'DBusTube') tube_props = tube_chan.Properties.GetAll(cs.CHANNEL_IFACE_TUBE, byte_arrays=True) assert tube_props['State'] == cs.TUBE_CHANNEL_STATE_NOT_OFFERED # try to offer using a wrong access control try: tube_chan.DBusTube.Offer(sample_parameters, cs.SOCKET_ACCESS_CONTROL_PORT) except dbus.DBusException as e: assertEquals(e.get_dbus_name(), cs.INVALID_ARGUMENT) else: assert False # offer the tube call_async(q, tube_chan.DBusTube, 'Offer', sample_parameters, access_control) presence_event, return_event, status_event, dbus_changed_event = q.expect_many( EventPattern('stream-presence', to='[email protected]/test', predicate=lambda e: t.presence_contains_tube(e)), EventPattern('dbus-return', method='Offer'), EventPattern('dbus-signal', signal='TubeChannelStateChanged', args=[cs.TUBE_CHANNEL_STATE_OPEN]), EventPattern('dbus-signal', signal='DBusNamesChanged', interface=cs.CHANNEL_TYPE_DBUS_TUBE)) tube_self_handle = tube_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'SelfHandle') assert tube_self_handle != 0 # handle presence_event # We announce our newly created tube in our muc presence presence = presence_event.stanza dbus_stream_id, my_bus_name, dbus_tube_id = check_tube_in_presence( presence, '[email protected]/test') # handle dbus_changed_event added, removed = dbus_changed_event.args assert added == {tube_self_handle: my_bus_name} assert removed == [] dbus_tube_adr = return_event.value[0] bob_bus_name = ':2.Ym9i' bob_handle = conn.get_contact_handle_sync('[email protected]/bob') def bob_in_tube(): presence = elem('presence', from_='[email protected]/bob', to='*****@*****.**')( elem('x', xmlns=ns.MUC_USER), elem('tubes', xmlns=ns.TUBES)( elem('tube', type='dbus', initiator='[email protected]/test', service='com.example.TestCase', id=str(dbus_tube_id))(elem('parameters')( elem('parameter', name='ay', type='bytes')(u'aGVsbG8='), elem('parameter', name='s', type='str')(u'hello'), elem('parameter', name='i', type='int')(u'-123'), elem('parameter', name='u', type='uint')(u'123'))))) # have to add stream-id and dbus-name attributes manually as we can't use # keyword with '-'... tube_node = xpath.queryForNodes('/presence/tubes/tube', presence)[0] tube_node['stream-id'] = dbus_stream_id tube_node['dbus-name'] = bob_bus_name stream.send(presence) # Bob joins the tube bob_in_tube() dbus_changed_event = q.expect('dbus-signal', signal='DBusNamesChanged', interface=cs.CHANNEL_TYPE_DBUS_TUBE) added, removed = dbus_changed_event.args assert added == {bob_handle: bob_bus_name} assert removed == [] tube = Connection(dbus_tube_adr) fire_signal_on_tube(q, tube, '*****@*****.**', dbus_stream_id, my_bus_name) names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE, 'DBusNames', dbus_interface=cs.PROPERTIES_IFACE) assert names == {tube_self_handle: my_bus_name, bob_handle: bob_bus_name} # Bob leave the tube presence = elem('presence', from_='[email protected]/bob', to='*****@*****.**')(elem('x', xmlns=ns.MUC_USER), elem('tubes', xmlns=ns.TUBES)) stream.send(presence) dbus_changed_event = q.expect('dbus-signal', signal='DBusNamesChanged', interface=cs.CHANNEL_TYPE_DBUS_TUBE) added, removed = dbus_changed_event.args assert added == {} assert removed == [bob_handle] names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE, 'DBusNames', dbus_interface=cs.PROPERTIES_IFACE) assert names == {tube_self_handle: my_bus_name} tube_chan.Channel.Close() _, _, event = q.expect_many( EventPattern('dbus-signal', signal='Closed'), EventPattern('dbus-signal', signal='ChannelClosed'), EventPattern('stream-presence', to='[email protected]/test', presence_type='unavailable')) # we must echo the MUC presence so the room will actually close # and we should wait to make sure gabble has actually parsed our # echo before trying to rejoin echo_muc_presence(q, stream, event.stanza, 'none', 'participant') sync_stream(q, stream) # rejoin the room 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('stream-presence', to='[email protected]/test') # Bob is in the room and in the tube bob_in_tube() # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', muc, 'test')) def new_tube(e): path, props = e.args[0][0] return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE def new_text(e): path, props = e.args[0][0] return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT # tube and text is created text_event, tube_event = q.expect_many( EventPattern('dbus-signal', signal='NewChannels', predicate=new_text), EventPattern('dbus-signal', signal='NewChannels', predicate=new_tube)) channels = exv.args[0] tube_path, props = tube_event.args[0][0] assertEquals(cs.CHANNEL_TYPE_DBUS_TUBE, props[cs.CHANNEL_TYPE]) assertEquals('[email protected]/test', props[cs.INITIATOR_ID]) assertEquals(False, props[cs.REQUESTED]) assertEquals(cs.HT_ROOM, props[cs.TARGET_HANDLE_TYPE]) assertEquals('com.example.TestCase', props[cs.DBUS_TUBE_SERVICE_NAME]) _, props = text_event.args[0][0] assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE]) assertEquals(True, props[cs.REQUESTED]) # tube is local-pending tube_chan = bus.get_object(conn.bus_name, tube_path) state = tube_chan.Get(cs.CHANNEL_IFACE_TUBE, 'State', dbus_interface=dbus.PROPERTIES_IFACE) assertEquals(cs.TUBE_STATE_LOCAL_PENDING, state)
def get_muc_tubes_channel(q, bus, conn, stream, muc_jid, anonymous=True): """ Returns a singleton list containing the MUC's handle, a proxy for the Tubes channel, and a proxy for the Tubes iface on that channel. """ muc_server = muc_jid.split('@')[1] test_jid = muc_jid + "/test" bob_jid = muc_jid + "/bob" self_handle = conn.GetSelfHandle() self_name = conn.InspectHandles(cs.HT_CONTACT, [self_handle])[0] call_async(q, conn, 'RequestHandles', cs.HT_ROOM, [muc_jid]) event = q.expect('dbus-return', method='RequestHandles') handles = event.value[0] room_handle = handles[0] # request tubes channel call_async(q, conn, 'RequestChannel', tp_name_prefix + '.Channel.Type.Tubes', 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=test_jid)) # Send presence for other member of room. if not anonymous: real_jid = 'bob@localhost' else: real_jid = None stream.send(make_muc_presence('owner', 'moderator', muc_jid, 'bob', real_jid)) # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', muc_jid, 'test')) q.expect('dbus-signal', signal='MembersChanged', args=[u'', [2, 3], [], [], [], 0, 0]) assert conn.InspectHandles(cs.HT_CONTACT, [2]) == [test_jid] assert conn.InspectHandles(cs.HT_CONTACT, [3]) == [bob_jid] # text and tubes channels are created # FIXME: We can't check NewChannel signals (old API) because two of them # would be fired and we can't catch twice the same signals without specifying # all their arguments. new_sig, returned = q.expect_many( EventPattern('dbus-signal', signal='NewChannels'), EventPattern('dbus-return', method='RequestChannel')) channels = new_sig.args[0] assert len(channels) == 2 for channel in channels: path, props = channel type = props[cs.CHANNEL_TYPE] if type == cs.CHANNEL_TYPE_TEXT: # check text channel properties assert props[cs.TARGET_HANDLE] == room_handle assert props[cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM assert props[cs.TARGET_ID] == '*****@*****.**' assert props[cs.REQUESTED] == False assert props[cs.INITIATOR_HANDLE] == self_handle assert props[cs.INITIATOR_ID] == self_name elif type == cs.CHANNEL_TYPE_TUBES: # check tubes channel properties assert props[cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM assert props[cs.TARGET_HANDLE] == room_handle assert props[cs.TARGET_ID] == '*****@*****.**' assert props[cs.REQUESTED] == True assert props[cs.INITIATOR_HANDLE] == self_handle assert props[cs.INITIATOR_ID] == self_name else: assert True tubes_chan = bus.get_object(conn.bus_name, returned.value[0]) tubes_iface = dbus.Interface(tubes_chan, tp_name_prefix + '.Channel.Type.Tubes') return (room_handle, tubes_chan, tubes_iface)
def test(q, bus, conn, stream): iq_event = q.expect('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard') acknowledge_iq(stream, iq_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') text_chan = bus.get_object(conn.bus_name, event.value[0]) # Bob offers a muc tube tube_id = 666 stream_id = 1234 presence = make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob') tubes = presence.addElement((ns.TUBES, 'tubes')) tube = tubes.addElement((None, 'tube')) tube['type'] = 'dbus' tube['service'] = 'org.telepathy.freedesktop.test' tube['id'] = str(tube_id) tube['stream-id'] = str(stream_id) tube['dbus-name'] = ':2.Y2Fzc2lkeS10ZXN0MgAA' tube['initiator'] = '[email protected]/bob' 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) def new_chan_predicate(e): path, props = e.args[0][0] return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE # tube channel is automatically created event = q.expect('dbus-signal', signal='NewChannels', predicate=new_chan_predicate) path, props = event.args[0][0] assertEquals(cs.CHANNEL_TYPE_DBUS_TUBE, props[cs.CHANNEL_TYPE]) assertEquals(cs.HT_ROOM, props[cs.TARGET_HANDLE_TYPE]) assertEquals('*****@*****.**', props[cs.TARGET_ID]) assertEquals(False, props[cs.REQUESTED]) tube_chan = bus.get_object(conn.bus_name, path) tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_DBUS_TUBE) # reject the tube tube_iface.Close(dbus_interface=cs.CHANNEL) q.expect('dbus-signal', signal='ChannelClosed') # close the text channel text_chan.Close()
def test_role_changes(q, bus, conn, stream): # The test user joins a room. Bob is an owner (and moderator); the test # user starts out with no affiliation and the rôle of participant. MUC = 'aoeu@snth' chan, _, immutable_props, disco = join_muc(q, bus, conn, stream, MUC, role='participant', also_capture=[ EventPattern('stream-iq', to=MUC, iq_type='get', query_ns=ns.DISCO_INFO), ]) assertContains(cs.CHANNEL_IFACE_ROOM_CONFIG, immutable_props[cs.INTERFACES]) handle_disco_info_iq(stream, disco.stanza) q.expect('dbus-signal', signal='PropertiesChanged', args=[cs.CHANNEL_IFACE_ROOM_CONFIG, {'ConfigurationRetrieved': True}, [] ]) # If we try to change the configuration, Gabble should say no: it knows # we're not allowed to do that. call_async(q, chan.RoomConfig1, 'UpdateConfiguration', {}) q.expect('dbus-error', name=cs.PERMISSION_DENIED) config = chan.Properties.GetAll(cs.CHANNEL_IFACE_ROOM_CONFIG) assert not config['CanUpdateConfiguration'], config # If we acquire affiliation='owner', this should be signalled as our # becoming able to modify the channel configuration. stream.send(make_muc_presence('owner', 'moderator', MUC, 'test')) q.expect('dbus-signal', signal='PropertiesChanged', args=[cs.CHANNEL_IFACE_ROOM_CONFIG, {'CanUpdateConfiguration': True}, [] ]) # Due to silliness, Gabble has to grab 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) # Bob's ownership rights being taken away should have no effect. stream.send(make_muc_presence('none', 'participant', MUC, 'bob')) # So now we're an owner, and CanUpdateConfiguration is True, we should be # able to change some configuration. props = dbus.Dictionary( { 'Persistent': True, }, signature='sv') call_async(q, chan.RoomConfig1, 'UpdateConfiguration', props) 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) event = q.expect('stream-iq', to=MUC, iq_type='set', query_ns=ns.MUC_OWNER) handle_muc_owner_set_iq(stream, event.stanza, {'muc#roomconfig_persistentroom': ['1']}) q.expect_many( EventPattern('dbus-return', method='UpdateConfiguration'), EventPattern('dbus-signal', signal='PropertiesChanged', args=[cs.CHANNEL_IFACE_ROOM_CONFIG, {'Persistent': True}, [] ])) # If we lose our affiliation, that should be signalled too. stream.send(make_muc_presence('none', 'participant', MUC, 'test')) q.expect('dbus-signal', signal='PropertiesChanged', args=[cs.CHANNEL_IFACE_ROOM_CONFIG, {'CanUpdateConfiguration': False}, [] ]) # Gabble should once again reject attempts to change the configuration call_async(q, chan.RoomConfig1, 'UpdateConfiguration', {}) q.expect('dbus-error', name=cs.PERMISSION_DENIED)
def test(q, bus, conn, stream): self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") call_async( q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: '*****@*****.**' }) gfc, _, _, _ = q.expect_many( # Initial group flags EventPattern('dbus-signal', signal='GroupFlagsChanged', predicate=lambda e: e.args[0] != 0), EventPattern('dbus-signal', signal='MembersChangedDetailed', predicate=lambda e: e.args[3] == [2]), # Removing CAN_ADD EventPattern('dbus-signal', signal='GroupFlagsChanged', args=[0, cs.GF_CAN_ADD], predicate=lambda e: e.args[0] == 0), EventPattern('stream-presence', to='[email protected]/test')) assert gfc.args[1] == 0 # Send presence for anonymous other member of room. stream.send( make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob')) # Send presence for anonymous other member of room (2) stream.send( make_muc_presence('owner', 'moderator', '*****@*****.**', 'brian')) # Send presence for nonymous other member of room. stream.send( make_muc_presence('none', 'participant', '*****@*****.**', 'che', '*****@*****.**')) # Send presence for nonymous other member of room (2) stream.send( make_muc_presence('none', 'participant', '*****@*****.**', 'chris', '*****@*****.**')) # Send presence for own membership of room. stream.send( make_muc_presence('none', 'participant', '*****@*****.**', 'test')) # Since we received MUC presence that contains an owner JID, the # OWNERS_NOT_AVAILABLE flag should be removed. event = q.expect('dbus-signal', signal='GroupFlagsChanged', args=[0, cs.GF_HANDLE_OWNERS_NOT_AVAILABLE]) event = q.expect('dbus-signal', signal='HandleOwnersChanged') owners = event.args[0] event = q.expect('dbus-signal', signal='MembersChangedDetailed') added = event.args[0] [test, bob, brian, che, che_owner, chris, chris_owner] = \ conn.get_contact_handles_sync( [ '[email protected]/test', '[email protected]/bob', '[email protected]/brian', '[email protected]/che', '*****@*****.**', '[email protected]/chris', '*****@*****.**', ]) expected_members = sorted([test, bob, brian, che, chris]) expected_owners = { test: self_handle, bob: 0, brian: 0, che: che_owner, chris: chris_owner } assertEquals(expected_members, sorted(added)) assertEquals(expected_owners, owners) event = q.expect('dbus-return', method='CreateChannel') chan = wrap_channel(bus.get_object(conn.bus_name, event.value[0]), 'Text') # Exercise HandleOwners owners = chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'HandleOwners') assertEquals(che_owner, owners[che]) assertEquals(chris_owner, owners[chris]) # Exercise D-Bus properties all = chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP) assert all[u'LocalPendingMembers'] == [], all assert sorted(all[u'Members']) == expected_members, all assert all[u'RemotePendingMembers'] == [], all assert all[u'SelfHandle'] == test, all assert all[u'HandleOwners'] == expected_owners, all flags = all[u'GroupFlags'] assertFlagsSet(cs.GF_CHANNEL_SPECIFIC_HANDLES, flags) assertFlagsUnset(cs.GF_HANDLE_OWNERS_NOT_AVAILABLE, flags)
def test_gtalk_weirdness(q, bus, conn, stream, room_jid): """ There's a strange bug in the Google Talk MUC server where it sends the <conflict/> stanza twice. This has been reported to their server team; but in any case it triggered a crazy bug in Gabble, so here's a regression test. """ # Implementation detail: Gabble uses the first part of your jid (if you # don't have an alias) as your room nickname, and appends an underscore a # few times before giving up. jids = ['%s/test%s' % (room_jid, x) for x in ['', '_', '__']] member, member_, member__ = jids # Gabble should never get as far as trying to join as 'test__' since # joining as 'test_' will succeed. q.forbid_events([ EventPattern('stream-presence', to=member__) ]) call_async(q, conn.Requests, 'CreateChannel', dbus.Dictionary({ cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: room_jid, }, signature='sv')) # Gabble first tries to join as test q.expect('stream-presence', to=member) # Google Talk says no from 'test', twice. presence = elem('presence', from_=member, type='error')( elem(ns.MUC, 'x'), elem('error', type='cancel')( elem(ns.STANZA, 'conflict'), )) stream.send(presence) stream.send(presence) # Gabble should try to join again as test_ q.expect('stream-presence', to=member_) # Since 'test_' is not in use in the MUC, joining should succeed. According # to XEP-0045 §7.1.3 <http://xmpp.org/extensions/xep-0045.html#enter-pres>: # The service MUST first send the complete list of the existing occupants # to the new occupant and only then send the new occupant's own presence # to the new occupant # but groupchat.google.com cheerfully violates this. stream.send(make_muc_presence('none', 'participant', room_jid, 'test_')) # Here's some other random person, who owns the MUC. stream.send(make_muc_presence('owner', 'moderator', room_jid, 'foobar_gmail.com')) # And here's our hypothetical other self. stream.send(make_muc_presence('none', 'participant', room_jid, 'test')) # The Gabble bug makes this time out: because Gabble thinks it's joining as # test__ it ignores the presence for test_, since it's not flagged with # code='210' to say “this is you”. (This is acceptable behaviour by the # server: it only needs to include code='210' if it's assigned the client a # name other than the one it asked for. # # The forbidden stream-presence event above doesn't blow up here because # servicetest doesn't process events on the 'stream-*' queue at all when # we're not waiting for one. But during disconnection in the test clean-up, # the forbidden event is encountered and correctly flagged up. event = q.expect('dbus-return', method='CreateChannel') path, _ = event.value text_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text') # As far as Gabble's concerned, the two other participants joined # immediately after we did. We can't request handles for them before we # try to join the MUC, because until we do so, Gabble doesn't know that # room_jid is a MUC, and so considers these three JIDs to be different # resources of the same contact. There is no race between this method # returning and MembersChangedDetailed firing, because libdbus reorders # messages when you make blocking calls. handle, handle_, handle__, foobar_handle = conn.RequestHandles( cs.HT_CONTACT, jids + ['%s/foobar_gmail.com' % room_jid]) q.expect('dbus-signal', signal='MembersChangedDetailed', predicate=lambda e: e.args[0:4] == [[foobar_handle], [], [], []]) q.expect('dbus-signal', signal='MembersChangedDetailed', predicate=lambda e: e.args[0:4] == [[handle], [], [], []]) group_props = text_chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP) assertEquals(handle_, group_props['SelfHandle']) assertSameSets([handle, handle_, foobar_handle], group_props['Members'])
def test(q, bus, conn, stream): iq_event = q.expect('stream-iq', to=None, query_ns='vcard-temp', query_name='vCard') acknowledge_iq(stream, iq_event.stanza) buddy_iface = dbus.Interface(conn, 'org.laptop.Telepathy.BuddyInfo') act_prop_iface = dbus.Interface(conn, 'org.laptop.Telepathy.ActivityProperties') bob_handle = conn.get_contact_handle_sync('bob@localhost') # Bob invites us to a chatroom, pre-seeding properties message = domish.Element(('jabber:client', 'message')) message['from'] = 'bob@localhost' message['to'] = 'test@localhost' properties = message.addElement((ns.OLPC_ACTIVITY_PROPS, 'properties')) properties['room'] = '*****@*****.**' properties['activity'] = 'foo_id' property = properties.addElement((None, 'property')) property['type'] = 'str' property['name'] = 'title' property.addContent('From the invitation') property = properties.addElement((None, 'property')) property['type'] = 'bool' property['name'] = 'private' property.addContent('1') stream.send(message) message = domish.Element((None, 'message')) message['from'] = '*****@*****.**' message['to'] = 'test@localhost' x = message.addElement((ns.MUC_USER, 'x')) invite = x.addElement((None, 'invite')) invite['from'] = 'bob@localhost' reason = invite.addElement((None, 'reason')) reason.addContent('No good reason') stream.send(message) event = q.expect('dbus-signal', signal='NewChannel') assert event.args[1] == cs.CHANNEL_TYPE_TEXT assert event.args[2] == 2 # handle type assert event.args[3] == 1 # handle room_handle = 1 text_chan = wrap_channel(bus.get_object(conn.bus_name, event.args[0]), 'Text') group_iface = text_chan.Group members = group_iface.GetAllMembers()[0] local_pending = group_iface.GetAllMembers()[1] remote_pending = group_iface.GetAllMembers()[2] assert len(members) == 1 assert conn.inspect_contact_sync(members[0]) == 'bob@localhost' bob_handle = members[0] assert len(local_pending) == 1 # FIXME: the username-part-is-nickname assumption assert conn.inspect_contact_sync(local_pending[0]) == \ '[email protected]/test' assert len(remote_pending) == 0 room_self_handle = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, "SelfHandle") assert room_self_handle == local_pending[0] # by now, we should have picked up the extra activity properties buddy_iface = dbus.Interface(conn, 'org.laptop.Telepathy.BuddyInfo') call_async(q, buddy_iface, 'GetActivities', bob_handle) event = q.expect('stream-iq', iq_type='get', to='bob@localhost') # Bob still has no (public) activities event.stanza['type'] = 'result' event.stanza['to'] = 'test@localhost' event.stanza['from'] = 'bob@localhost' stream.send(event.stanza) event = q.expect('dbus-return', method='GetActivities') assert event.value == ([('foo_id', room_handle)], ) props = act_prop_iface.GetProperties(room_handle) assert len(props) == 2 assert props['title'] == 'From the invitation' assert props['private'] == True # Now Bob changes the properties message = domish.Element(('jabber:client', 'message')) message['from'] = 'bob@localhost' message['to'] = 'test@localhost' properties = message.addElement((ns.OLPC_ACTIVITY_PROPS, 'properties')) properties['room'] = '*****@*****.**' properties['activity'] = 'foo_id' property = properties.addElement((None, 'property')) property['type'] = 'str' property['name'] = 'title' property.addContent('Mushroom, mushroom') property = properties.addElement((None, 'property')) property['type'] = 'bool' property['name'] = 'private' property.addContent('0') stream.send(message) event = q.expect('dbus-signal', signal='ActivityPropertiesChanged') assert event.args == [ room_handle, { 'title': 'Mushroom, mushroom', 'private': False } ] assert act_prop_iface.GetProperties(room_handle) == \ event.args[1] # OK, now accept the invitation call_async(q, group_iface, 'AddMembers', [room_self_handle], 'Oh, OK then') q.expect_many( EventPattern('stream-presence', to='[email protected]/test'), EventPattern('dbus-signal', signal='MembersChanged', args=[ '', [], [bob_handle], [], [room_self_handle], 0, cs.GC_REASON_INVITED ]), EventPattern('dbus-return', method='AddMembers'), ) # Send presence for own membership of room. stream.send( make_muc_presence('owner', 'moderator', '*****@*****.**', 'test')) event = q.expect('dbus-signal', signal='MembersChanged') assert event.args == ['', [room_self_handle], [], [], [], 0, 0] call_async(q, buddy_iface, 'SetActivities', [('foo_id', room_handle)]) event = q.expect('stream-iq', iq_type='set') # Now that it's not private, it'll go in my PEP event.stanza['type'] = 'result' event.stanza['to'] = 'test@localhost' event.stanza['from'] = 'test@localhost' stream.send(event.stanza) q.expect('dbus-return', method='SetActivities') # Bob changes the properties and tells the room he's done so message = domish.Element(('jabber:client', 'message')) message['from'] = '[email protected]/bob' message['to'] = '*****@*****.**' properties = message.addElement((ns.OLPC_ACTIVITY_PROPS, 'properties')) properties['activity'] = 'foo_id' property = properties.addElement((None, 'property')) property['type'] = 'str' property['name'] = 'title' property.addContent('Badger badger badger') property = properties.addElement((None, 'property')) property['type'] = 'bool' property['name'] = 'private' property.addContent('0') stream.send(message) event = q.expect('stream-iq', iq_type='set') message = event.stanza activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities', message) assert (activities is not None and len(activities) == 1), repr(activities) assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS properties = xpath.queryForNodes('/activities/properties', activities[0]) 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'] == 'foo_id' property = xpath.queryForNodes('/properties/property', properties[0]) assert (property is not None and len(property) == 2), repr(property) seen = set() for p in property: seen.add(p['name']) if p['name'] == 'title': assert p['type'] == 'str' assert str(p) == 'Badger badger badger' elif p['name'] == 'private': assert p['type'] == 'bool' assert str(p) == '0' else: assert False, 'Unexpected property %s' % p['name'] assert 'title' in seen, seen assert 'private' in seen, seen event.stanza['type'] = 'result' event.stanza['to'] = 'test@localhost' event.stanza['from'] = 'test@localhost' stream.send(event.stanza) act_prop_iface = dbus.Interface(conn, 'org.laptop.Telepathy.ActivityProperties') # test sets the title and sets private back to True call_async(q, act_prop_iface, 'SetProperties', room_handle, { 'title': 'I can set the properties too', 'private': True }) event = q.expect('stream-message', to='*****@*****.**') 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'] == 'foo_id' property = xpath.queryForNodes('/properties/property', properties[0]) assert (property is not None and len(property) == 2), repr(property) seen = set() for p in property: seen.add(p['name']) if p['name'] == 'title': assert p['type'] == 'str' assert str(p) == 'I can set the properties too' elif p['name'] == 'private': assert p['type'] == 'bool' assert str(p) == '1' else: assert False, 'Unexpected property %s' % p['name'] assert 'title' in seen, seen assert 'private' in seen, seen event = q.expect('stream-iq', iq_type='set') event.stanza['type'] = 'result' event.stanza['to'] = 'test@localhost' event.stanza['from'] = 'test@localhost' stream.send(event.stanza) message = event.stanza activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities', message) assert (activities is not None and len(activities) == 1), repr(activities) assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS properties = xpath.queryForNodes('/activities/properties', activities[0]) assert properties is None, repr(properties) event = q.expect('stream-iq', iq_type='set') event.stanza['type'] = 'result' event.stanza['to'] = 'test@localhost' event.stanza['from'] = 'test@localhost' stream.send(event.stanza) message = event.stanza activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities', message) assert (activities is not None and len(activities) == 1), repr(activities) assert activities[0].uri == ns.OLPC_ACTIVITIES activity = xpath.queryForNodes('/activities/activity', activities[0]) assert activity is None, repr(activity) q.expect('dbus-return', method='SetProperties') # test sets the title and sets private back to True call_async(q, act_prop_iface, 'SetProperties', room_handle, { 'title': 'I can set the properties too', 'private': False }) event = q.expect('stream-message', to='*****@*****.**') 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'] == 'foo_id' property = xpath.queryForNodes('/properties/property', properties[0]) assert (property is not None and len(property) == 2), repr(property) seen = set() for p in property: seen.add(p['name']) if p['name'] == 'title': assert p['type'] == 'str' assert str(p) == 'I can set the properties too' elif p['name'] == 'private': assert p['type'] == 'bool' assert str(p) == '0' else: assert False, 'Unexpected property %s' % p['name'] assert 'title' in seen, seen assert 'private' in seen, seen event = q.expect('stream-iq', iq_type='set') event.stanza['type'] = 'result' event.stanza['to'] = 'test@localhost' event.stanza['from'] = 'test@localhost' stream.send(event.stanza) message = event.stanza activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities', message) assert (activities is not None and len(activities) == 1), repr(activities) assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS properties = xpath.queryForNodes('/activities/properties', activities[0]) 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'] == 'foo_id' property = xpath.queryForNodes('/properties/property', properties[0]) assert (property is not None and len(property) == 2), repr(property) seen = set() for p in property: seen.add(p['name']) if p['name'] == 'title': assert p['type'] == 'str' assert str(p) == 'I can set the properties too' elif p['name'] == 'private': assert p['type'] == 'bool' assert str(p) == '0' else: assert False, 'Unexpected property %s' % p['name'] assert 'title' in seen, seen assert 'private' in seen, seen event = q.expect('stream-iq', iq_type='set') event.stanza['type'] = 'result' event.stanza['to'] = 'test@localhost' event.stanza['from'] = 'test@localhost' stream.send(event.stanza) message = event.stanza activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities', message) assert (activities is not None and len(activities) == 1), repr(activities) assert activities[0].uri == ns.OLPC_ACTIVITIES activity = xpath.queryForNodes('/activities/activity', activities[0]) assert (activity is not None and len(activity) == 1), repr(activity) assert activity[0]['room'] == '*****@*****.**' assert activity[0]['type'] == 'foo_id' # sic q.expect('dbus-return', method='SetProperties') text_chan.Close() # we must echo the MUC presence so the room will actually close event = q.expect('stream-presence', to='[email protected]/test', presence_type='unavailable') echo_muc_presence(q, stream, event.stanza, 'none', 'participant') event = q.expect('stream-iq', iq_type='set') event.stanza['type'] = 'result' event.stanza['to'] = 'test@localhost' event.stanza['from'] = 'test@localhost' stream.send(event.stanza) message = event.stanza activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities', message) assert (activities is not None and len(activities) == 1), repr(activities) assert activities[0].uri == ns.OLPC_ACTIVITIES activity = xpath.queryForNodes('/activities/activity', activities[0]) assert activity is None, repr(activity) event = q.expect('stream-iq', iq_type='set') event.stanza['type'] = 'result' event.stanza['to'] = 'test@localhost' event.stanza['from'] = 'test@localhost' stream.send(event.stanza) message = event.stanza activities = xpath.queryForNodes('/iq/pubsub/publish/item/activities', message) assert (activities is not None and len(activities) == 1), repr(activities) assert activities[0].uri == ns.OLPC_ACTIVITY_PROPS properties = xpath.queryForNodes('/activities/properties', activities[0]) assert properties is None, repr(properties)
def test_join(q, bus, conn, stream, room_jid, transient_conflict): """ Tells Gabble to join a MUC, but make the first nick it tries conflict with an existing member of the MUC. If transient_conflict is True, then when Gabble successfully joins with a different nick the originally conflicting user turns out not actually to be in the room (they left while we were retrying). """ # Implementation detail: Gabble uses the first part of your jid (if you # don't have an alias) as your room nickname, and appends an underscore a # few times before giving up. member, member_ = [room_jid + '/' + x for x in ['test', 'test_']] call_async(q, conn.Requests, 'CreateChannel', dbus.Dictionary({ cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: room_jid, }, signature='sv')) # Gabble first tries to join as test q.expect('stream-presence', to=member) # MUC says no: there's already someone called test in room_jid presence = elem('presence', from_=member, type='error')( elem(ns.MUC, 'x'), elem('error', type='cancel')( elem(ns.STANZA, 'conflict'), )) stream.send(presence) # Gabble tries again as test_ q.expect('stream-presence', to=member_) # MUC says yes! if not transient_conflict: # Send the other member of the room's presence. This is the nick we # originally wanted. stream.send(make_muc_presence('owner', 'moderator', room_jid, 'test')) # If gabble erroneously thinks the other user's presence is our own, it'll # think that it's got the whole userlist now. If so, syncing here will make # CreateChannel incorrectly return here. sync_stream(q, stream) sync_dbus(bus, q, conn) # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', room_jid, 'test_')) # Only now should we have finished joining the room. event = q.expect('dbus-return', method='CreateChannel') path, props = event.value text_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text') group_props = unwrap(text_chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP)) t, t_ = conn.RequestHandles(cs.HT_CONTACT, [member, member_]) # Check that Gabble think our nickname in the room is test_, not test muc_self_handle = group_props['SelfHandle'] assert muc_self_handle == t_, (muc_self_handle, t_, t) members = group_props['Members'] if transient_conflict: # The user we originally conflicted with isn't actually here; check # there's exactly one member (test_). assert members == [t_], (members, t_, t) else: # Check there are exactly two members (test and test_) assertSameSets([t, t_], members) # In either case, there should be no pending members. assert len(group_props['LocalPendingMembers']) == 0, group_props assert len(group_props['RemotePendingMembers']) == 0, group_props # Check that test_'s handle owner is us, and that test (if it's there) has # no owner. handle_owners = group_props['HandleOwners'] assertEquals (conn.GetSelfHandle(), handle_owners[t_]) if not transient_conflict: assertEquals (0, handle_owners[t]) # test that closing the channel results in an unavailable message to the # right jid text_chan.Close() event = q.expect('stream-presence', to=member_) assertEquals('unavailable', event.stanza['type'])
echo_muc_presence(q, stream, event.stanza, 'none', 'participant') sync_stream(q, stream) # rejoin the room 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('stream-presence', to='[email protected]/test') # Bob is in the room and in the tube bob_in_tube() # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', muc, 'test')) def new_tube(e): path, props = e.args[0][0] return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE def new_text(e): path, props = e.args[0][0] return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT # tube and text is created text_event, tube_event = q.expect_many(EventPattern('dbus-signal', signal='NewChannels', predicate=new_text), EventPattern('dbus-signal', signal='NewChannels', predicate=new_tube))
def test(q, bus, conn, stream): 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_muc(q, bus, conn, stream, '*****@*****.**') # bob offers a stream tube stream_tube_id = 1 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')) stream.send(presence) def new_chan_predicate(e): path, props = e.args[0][0] return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE e = q.expect('dbus-signal', signal='NewChannels', predicate=new_chan_predicate) channels = e.args[0] assert len(channels) == 1 path, props = channels[0] assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE tube_chan = bus.get_object(conn.bus_name, path) tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_STREAM_TUBE) call_async(q, tube_iface, 'Accept', 0, 0, '', byte_arrays=True) accept_return_event, _ = q.expect_many( EventPattern('dbus-return', method='Accept'), EventPattern('dbus-signal', signal='TubeChannelStateChanged', args=[cs.TUBE_CHANNEL_STATE_OPEN])) unix_socket_adr = accept_return_event.value[0] factory = EventProtocolClientFactory(q) reactor.connectUNIX(unix_socket_adr, factory) # expect SI request e = q.expect('stream-iq', to='[email protected]/bob', query_ns=ns.SI, query_name='si') bytestream, profile = create_from_si_offer(stream, q, BytestreamS5BRelay, e.stanza, '[email protected]/bob') result, si = bytestream.create_si_reply(e.stanza, 'test@localhost/Resource') si.addElement((ns.TUBES, 'tube')) stream.send(result) # wait SOCKS5 init iq id, mode, si, hosts = bytestream._expect_socks5_init() for jid, host, port in hosts: # the proxy is not announced because we are in a muc assert jid != 'proxy.localhost'
def test(q, bus, conn, stream): conn.Connect() _, iq_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')) acknowledge_iq(stream, iq_event.stanza) call_async(q, conn, 'RequestHandles', cs.HT_ROOM, ['*****@*****.**']) 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' stream.send(result) 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(cs.HT_CONTACT, [2, 3]) == \ ['[email protected]/test', '[email protected]/bob'] bob_handle = 3 event = q.expect('dbus-return', method='RequestChannel') text_chan = bus.get_object(conn.bus_name, event.value[0]) # Bob offers a muc tube tube_id = 666 stream_id = 1234 presence = make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob') tubes = presence.addElement((ns.TUBES, 'tubes')) tube = tubes.addElement((None, 'tube')) tube['type'] = 'dbus' tube['service'] = 'org.telepathy.freedesktop.test' tube['id'] = str(tube_id) tube['stream-id'] = str(stream_id) tube['dbus-name'] = ':2.Y2Fzc2lkeS10ZXN0MgAA' tube['initiator'] = '[email protected]/bob' 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) # tubes channel is automatically created event = q.expect('dbus-signal', signal='NewChannel') if event.args[1] == cs.CHANNEL_TYPE_TEXT: # skip this one, try the next one event = q.expect('dbus-signal', signal='NewChannel') 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=dbus.PROPERTIES_IFACE) assert channel_props['TargetID'] == '*****@*****.**', channel_props assert channel_props['Requested'] == False assert channel_props['InitiatorID'] == '' assert channel_props['InitiatorHandle'] == 0 tubes_self_handle = tubes_chan.GetSelfHandle( dbus_interface=cs.CHANNEL_IFACE_GROUP) q.expect('dbus-signal', signal='NewTube', args=[tube_id, bob_handle, 0, 'org.telepathy.freedesktop.test', sample_parameters, 0]) expected_tube = (tube_id, bob_handle, cs.TUBE_TYPE_DBUS, 'org.telepathy.freedesktop.test', sample_parameters, cs.TUBE_STATE_LOCAL_PENDING) tubes = tubes_iface.ListTubes(byte_arrays=True) assert len(tubes) == 1, unwrap(tubes) t.check_tube_in_tubes(expected_tube, tubes) # reject the tube tubes_iface.CloseTube(tube_id) q.expect('dbus-signal', signal='TubeClosed', args=[tube_id]) # close the text channel text_chan.Close()
def test(q, bus, conn, stream): room = '*****@*****.**' handle = request_muc_handle(q, conn, stream, room) call_async(q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_HANDLE: handle}) expected_muc_jid = '%s/%s' % (room, 'test') q.expect('stream-presence', to=expected_muc_jid) # tell gabble the room needs a password denied = \ elem('jabber:client', 'presence', from_=expected_muc_jid, type='error')( elem(ns.MUC, 'x'), elem('error', type='auth')( elem(ns.STANZA, 'not-authorized'), ), ) stream.send(denied) cc, _, _ = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), EventPattern('dbus-signal', signal='NewChannels'), EventPattern('dbus-signal', signal='PasswordFlagsChanged', args=[cs.PASSWORD_FLAG_PROVIDE, 0])) chan = wrap_channel(bus.get_object(conn.bus_name, cc.value[0]), 'Text', ['Password']) flags = chan.Password.GetPasswordFlags() assertEquals(cs.PASSWORD_FLAG_PROVIDE, flags) call_async(q, chan.Password, 'ProvidePassword', 'brand new benz') expect_attempt(q, expected_muc_jid, 'brand new benz') # Try again while the first attempt is outstanding. Gabble should say no. call_async(q, chan.Password, 'ProvidePassword', 'faster faster') q.expect('dbus-error', method='ProvidePassword') # Sorry, wrong password. stream.send(denied) ret = q.expect('dbus-return', method='ProvidePassword') assert not ret.value[0] call_async(q, chan.Password, 'ProvidePassword', 'bougie friends') expect_attempt(q, expected_muc_jid, 'bougie friends') # Well, this may be the right password, but actually that nick is in use. presence = elem('presence', from_=expected_muc_jid, type='error')( elem(ns.MUC, 'x'), elem('error', type='cancel')( elem(ns.STANZA, 'conflict'), )) stream.send(presence) # Okay, so Gabble tries again, with a new JID *and the same password*. expected_muc_jid = expected_muc_jid + '_' expect_attempt(q, expected_muc_jid, 'bougie friends') # Hey this worked. stream.send(make_muc_presence('none', 'participant', room, 'test_')) ret, _ = q.expect_many( EventPattern('dbus-return', method='ProvidePassword'), EventPattern('dbus-signal', signal='PasswordFlagsChanged', args=[0, cs.PASSWORD_FLAG_PROVIDE])) assert ret.value[0]
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): 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]
conn.Requests, "CreateChannel", { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: "*****@*****.**", }, ) q.expect("stream-presence", to="[email protected]/test") # Bob is in the room and in the tube bob_in_tube() # Send presence for own membership of room. stream.send(make_muc_presence("none", "participant", muc, "test")) # tube is created as well e = q.expect("dbus-signal", signal="NewChannels") tube_path, props = e.args[0][0] assertEquals(cs.CHANNEL_TYPE_DBUS_TUBE, props[cs.CHANNEL_TYPE]) assertEquals("[email protected]/test", props[cs.INITIATOR_ID]) assertEquals(False, props[cs.REQUESTED]) assertEquals(cs.HT_ROOM, props[cs.TARGET_HANDLE_TYPE]) assertEquals("com.example.TestCase", props[cs.DBUS_TUBE_SERVICE_NAME]) # text channel is created e = q.expect("dbus-signal", signal="NewChannels") path, props = e.args[0][0] assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE]) assertEquals(True, props[cs.REQUESTED])
def test_create_ensure(q, conn, bus, stream, room_jid): # Call both Create and Ensure for the same channel. call_async(q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: room_jid, }) call_async(q, conn.Requests, 'EnsureChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: room_jid, }) mc, _ = q.expect_many( EventPattern('dbus-signal', signal='MembersChangedDetailed'), EventPattern('stream-presence', to=('%s/test' % room_jid))) added, removed, local_pending, remote_pending, details = mc.args assert added == [], mc.args assert removed == [], mc.args assert local_pending == [], mc.args assert len(remote_pending) == 1, mc.args # Send presence for other member of room. stream.send(make_muc_presence('owner', 'moderator', room_jid, 'bob')) # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', room_jid, 'test')) mc = q.expect('dbus-signal', signal='MembersChangedDetailed') added, removed, local_pending, remote_pending, details = mc.args assert len(added) == 2, mc.args assert removed == [], mc.args assert local_pending == [], mc.args assert remote_pending == [], mc.args members = conn.inspect_contacts_sync(added) members.sort() assert members == ['%s/bob' % room_jid, '%s/test' % room_jid], members create_event, ensure_event = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), EventPattern('dbus-return', method='EnsureChannel')) assert len(create_event.value) == 2 c_path, c_props = create_event.value assert len(ensure_event.value) == 3 yours, e_path, e_props = ensure_event.value assert c_path == e_path, (c_path, e_path) assert c_props == e_props, (c_props, e_props) assert not yours assertContains('text/plain', c_props[cs.SUPPORTED_CONTENT_TYPES]) assertEquals(0, c_props[cs.MESSAGE_PART_SUPPORT_FLAGS]) assertEquals( cs.DELIVERY_REPORTING_SUPPORT_FLAGS_RECEIVE_FAILURES | cs.DELIVERY_REPORTING_SUPPORT_FLAGS_RECEIVE_SUCCESSES, c_props[cs.DELIVERY_REPORTING_SUPPORT])
# rejoin the room 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('stream-presence', to='[email protected]/test') # Bob is in the room and in the tube bob_in_tube() # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', muc, 'test')) def new_tube(e): path, props = e.args[0][0] return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE def new_text(e): path, props = e.args[0][0] return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT # tube and text is created text_event, tube_event = q.expect_many( EventPattern('dbus-signal', signal='NewChannels', predicate=new_text), EventPattern('dbus-signal', signal='NewChannels', predicate=new_tube)) channels = e.args[0]
def test(q, bus, conn, stream): self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") call_async(q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, cs.TARGET_ID: '*****@*****.**' }) gfc, _, _, _ = q.expect_many( # Initial group flags EventPattern('dbus-signal', signal='GroupFlagsChanged', predicate=lambda e: e.args[0] != 0), EventPattern('dbus-signal', signal='MembersChangedDetailed', predicate=lambda e: e.args[3] == [2]), # Removing CAN_ADD EventPattern('dbus-signal', signal='GroupFlagsChanged', args = [0, cs.GF_CAN_ADD], predicate=lambda e: e.args[0] == 0), EventPattern('stream-presence', to='[email protected]/test')) assert gfc.args[1] == 0 # Send presence for anonymous other member of room. stream.send(make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob')) # Send presence for anonymous other member of room (2) stream.send(make_muc_presence('owner', 'moderator', '*****@*****.**', 'brian')) # Send presence for nonymous other member of room. stream.send(make_muc_presence('none', 'participant', '*****@*****.**', 'che', '*****@*****.**')) # Send presence for nonymous other member of room (2) stream.send(make_muc_presence('none', 'participant', '*****@*****.**', 'chris', '*****@*****.**')) # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', '*****@*****.**', 'test')) # Since we received MUC presence that contains an owner JID, the # OWNERS_NOT_AVAILABLE flag should be removed. event = q.expect('dbus-signal', signal='GroupFlagsChanged', args = [0, cs.GF_HANDLE_OWNERS_NOT_AVAILABLE ]) event = q.expect('dbus-signal', signal='HandleOwnersChanged') owners = event.args[0] event = q.expect('dbus-signal', signal='MembersChangedDetailed') added = event.args[0] [test, bob, brian, che, che_owner, chris, chris_owner] = \ conn.get_contact_handles_sync( [ '[email protected]/test', '[email protected]/bob', '[email protected]/brian', '[email protected]/che', '*****@*****.**', '[email protected]/chris', '*****@*****.**', ]) expected_members = sorted([test, bob, brian, che, chris]) expected_owners = { test: self_handle, bob: 0, brian: 0, che: che_owner, chris: chris_owner } assertEquals(expected_members, sorted(added)) assertEquals(expected_owners, owners) event = q.expect('dbus-return', method='CreateChannel') chan = wrap_channel(bus.get_object(conn.bus_name, event.value[0]), 'Text') # Exercise HandleOwners owners = chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'HandleOwners') assertEquals(che_owner, owners[che]) assertEquals(chris_owner, owners[chris]) # Exercise D-Bus properties all = chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP) assert all[u'LocalPendingMembers'] == [], all assert sorted(all[u'Members']) == expected_members, all assert all[u'RemotePendingMembers'] == [], all assert all[u'SelfHandle'] == test, all assert all[u'HandleOwners'] == expected_owners, all flags = all[u'GroupFlags'] assertFlagsSet(cs.GF_CHANNEL_SPECIFIC_HANDLES, flags) assertFlagsUnset(cs.GF_HANDLE_OWNERS_NOT_AVAILABLE, flags)
def run_outgoing_test(q, bus, conn, stream, close_channel=False): jp = JingleProtocol031 () jt = JingleTest2(jp, conn, q, stream, 'test@localhost', muc + '/bob') jt.prepare() self_handle = conn.GetSelfHandle() # Not allowed to have muji related presences before we accept the channel forbidden = [ no_muji_presences (muc) ] (path, props) = create_muji_channel (q, conn, stream, muc) q.forbid_events(forbidden) general_tests (jp, q, bus, conn, stream, path, props) channel = bus.get_object (conn.bus_name, path) props = channel.GetAll (cs.CHANNEL_TYPE_CALL, dbus_interface = dbus.PROPERTIES_IFACE) content = bus.get_object (conn.bus_name, props['Contents'][0]) codecs = jt.get_call_audio_codecs_dbus() # Accept codec offer props = content.GetAll(cs.CALL_CONTENT_IFACE_MEDIA, dbus_interface=dbus.PROPERTIES_IFACE) offer = bus.get_object (conn.bus_name, props["CodecOffer"][0]) offer.Accept(codecs, dbus_interface=cs.CALL_CONTENT_CODECOFFER) # Accept the channel, which means we can get muji presences q.unforbid_events (forbidden) channel.Accept() e = q.expect('stream-presence', to = muc + "/test") echo_muc_presence (q, stream, e.stanza, 'none', 'participant') mujinode = xpath.queryForNodes("/presence/muji", e.stanza) assertLength (1, mujinode) # The one with the codecs e = q.expect('stream-presence', to = muc + "/test") echo_muc_presence (q, stream, e.stanza, 'none', 'participant') # Gabble shouldn't send new presences for a while q.forbid_events(forbidden) presence = make_muc_presence('owner', 'moderator', muc, 'bob') presence.addElement ((ns.MUJI, 'muji')).addElement('preparing') stream.send(presence) presence = make_muc_presence('owner', 'moderator', muc, 'bob') muji = ('muji', ns.MUJI, {}, [('content', ns.MUJI, { "name": "Audio" }, [( 'description', ns.JINGLE_RTP, {"media": "audio"}, jt.generate_payloads(jt.audio_codecs))])]) presence.addChild(jp._simple_xml(muji)) stream.send(presence) q.expect('dbus-signal', signal = 'CallStateChanged') # Bob appears and starts a session right afterwards q.expect('dbus-signal', signal = 'CallMembersChanged') e = q.expect('dbus-signal', signal = 'NewCodecOffer') offer = bus.get_object (conn.bus_name, e.args[1]) offer.Accept(codecs, dbus_interface=cs.CALL_CONTENT_CODECOFFER) jt.incoming_call(audio = "Audio") e = q.expect ('dbus-signal', signal = 'StreamsAdded') cstream = bus.get_object (conn.bus_name, e.args[0][0]) candidates = jt.get_call_remote_transports_dbus () cstream.AddCandidates (candidates, dbus_interface=cs.CALL_STREAM_IFACE_MEDIA) # Fake our endpoint being connected endpoints = cstream.Get(cs.CALL_STREAM_IFACE_MEDIA, "Endpoints", dbus_interface=dbus.PROPERTIES_IFACE) assertLength (1, endpoints) endpoint = bus.get_object (conn.bus_name, endpoints[0]) endpoint.SetStreamState (cs.MEDIA_STREAM_STATE_CONNECTED, dbus_interface=cs.CALL_STREAM_ENDPOINT) e = q.expect ('stream-iq', predicate = jp.action_predicate ('session-accept')) stream.send(jp.xml(jp.ResultIq(jt.peer, e.stanza, []))) # But we want video as well ! c = channel.AddContent ("Camera!", cs.MEDIA_STREAM_TYPE_VIDEO, dbus_interface=cs.CHANNEL_TYPE_CALL) q.expect('dbus-signal', signal = 'ContentAdded') content = bus.get_object (conn.bus_name, c) codecs = jt.get_call_video_codecs_dbus() # wait for the CodecOffer and Accept it q.expect('dbus-signal', signal = 'NewCodecOffer') props = content.GetAll(cs.CALL_CONTENT_IFACE_MEDIA, dbus_interface=dbus.PROPERTIES_IFACE) offer = bus.get_object (conn.bus_name, props["CodecOffer"][0]) offer.Accept(codecs, dbus_interface=cs.CALL_CONTENT_CODECOFFER) q.unforbid_events(forbidden) # preparing e = q.expect('stream-presence', to = muc + "/test") echo_muc_presence (q, stream, e.stanza, 'none', 'participant') #codecs e = q.expect('stream-presence', to = muc + "/test") echo_muc_presence (q, stream, e.stanza, 'none', 'participant') # Bob would like to join our video party presence = make_muc_presence('owner', 'moderator', muc, 'bob') muji = ('muji', ns.MUJI, {}, [('content', ns.MUJI, { "name": "Audio" }, [( 'description', ns.JINGLE_RTP, {"media": "audio"}, jt.generate_payloads(jt.audio_codecs))]), ('content', ns.MUJI, { "name": "Camera!" }, [( 'description', ns.JINGLE_RTP, {"media": "video"}, jt.generate_payloads(jt.video_codecs))]), ]) presence.addChild(jp._simple_xml(muji)) stream.send(presence) # new codec offer as bob threw in some codecs q.expect('dbus-signal', signal='NewCodecOffer') check_and_accept_offer (q, bus, conn, self_handle, 0, content, codecs, check_codecs_changed = False) # Bob sends a content node = jp.SetIq(jt.peer, jt.jid, [ jp.Jingle(jt.sid, jt.peer, 'content-add', [ jp.Content('videostream', 'initiator', 'both', jp.Description('video', [ jp.PayloadType(name, str(rate), str(id), parameters) for (name, id, rate, parameters) in jt.video_codecs ]), jp.TransportGoogleP2P()) ]) ]) stream.send(jp.xml(node)) # We get a new stream q.expect('dbus-signal', signal = 'StreamsAdded') # Sync up the stream to ensure we sent out all the xmpp traffic that was # the result of a stream being added sync_stream (q, stream) # happiness.. Now let's hang up if close_channel: channel.Close() hangup_event = EventPattern ('dbus-signal', signal = "Closed", path = path) else: channel.Hangup (0, "", "", dbus_interface=cs.CHANNEL_TYPE_CALL) hangup_event = EventPattern ('dbus-signal', signal='CallStateChanged') # Should change the call state to ended, send a session-terminate to our # only peer and send a muc presence without any mention of muji q.forbid_events(forbidden) q.expect_many (EventPattern ('stream-presence', to = muc + "/test"), EventPattern ('stream-iq', predicate=jp.action_predicate ('session-terminate')), hangup_event) if not close_channel: channel.Close() q.expect ('dbus-signal', signal="Closed", path = path) try: channel.Close() raise AssertionError ("Channel didn't actually close") except DBusException: pass
def test(q, bus, conn, stream): # Bob has invited us to an activity. message = domish.Element((None, 'message')) message['from'] = '*****@*****.**' message['to'] = 'test@localhost' x = message.addElement(('http://jabber.org/protocol/muc#user', 'x')) invite = x.addElement((None, 'invite')) invite['from'] = 'bob@localhost' reason = invite.addElement((None, 'reason')) reason.addContent('No good reason') stream.send(message) event = q.expect('dbus-signal', signal='NewChannels') path, props = event.args[0][0] assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE]) assertEquals(cs.HT_ROOM, props[cs.TARGET_HANDLE_TYPE]) assertEquals(1, props[cs.TARGET_HANDLE]) text_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text') members = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'Members') local_pending = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'LocalPendingMembers') remote_pending = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'RemotePendingMembers') assert len(members) == 1 assert conn.inspect_contact_sync(members[0]) == 'bob@localhost' bob_handle = members[0] assert len(local_pending) == 1 # FIXME: the username-part-is-nickname assumption assert conn.inspect_contact_sync(local_pending[0][0]) == \ '[email protected]/test' assert len(remote_pending) == 0 room_self_handle = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, "SelfHandle") assert room_self_handle == local_pending[0][0] channel_props = text_chan.Properties.GetAll(cs.CHANNEL) assert channel_props['TargetID'] == '*****@*****.**', channel_props assert channel_props['Requested'] == False assert channel_props['InitiatorID'] == 'bob@localhost' assert channel_props['InitiatorHandle'] == bob_handle # set ourselves to away and back again, to check that we don't send any # presence to the MUC before the invite has been accepted conn.SimplePresence.SetPresence('away', 'failure') conn.SimplePresence.SetPresence('available', 'success') # accept the invitation call_async(q, text_chan.Group, 'AddMembers', [room_self_handle], 'Oh, OK then') event, event2, _ = q.expect_many( EventPattern('stream-presence', to='[email protected]/test'), EventPattern('dbus-signal', signal='MembersChangedDetailed'), EventPattern('dbus-return', method='AddMembers')) # check that the status we joined with was available / success elem = event.stanza show = [e for e in elem.elements() if e.name == 'show'] assert not show status = [e for e in elem.elements() if e.name == 'status'][0] assert status assert status.children[0] == u'success' # We are added as remote pending while joining the room. The inviter (Bob) # is removed for now. It will be re-added with his channel specific handle # once we have joined. added, removed, local_pending, remote_pending, details = event2.args assertEquals([], added) assertEquals([bob_handle], removed) assertEquals([], local_pending) assertEquals([room_self_handle], remote_pending) assertEquals(cs.GC_REASON_INVITED, details['change-reason']) # Send presence for Bob's membership of room. stream.send( make_muc_presence('owner', 'moderator', '*****@*****.**', 'bob')) # Send presence for own membership of room. stream.send( make_muc_presence('owner', 'moderator', '*****@*****.**', 'test')) event = q.expect('dbus-signal', signal='MembersChangedDetailed') room_bob_handle = conn.get_contact_handle_sync('[email protected]/bob') added, removed, local_pending, remote_pending, details = event.args assertEquals([room_self_handle, room_bob_handle], added) assertEquals([], removed) assertEquals([], local_pending) assertEquals([], remote_pending) # Test sending an invitation alice_handle = conn.get_contact_handle_sync('alice@localhost') call_async(q, text_chan.Group, 'AddMembers', [alice_handle], 'I want to test invitations') 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 == 'http://jabber.org/protocol/muc#user' invites = xpath.queryForNodes('/x/invite', x[0]) assert (invites is not None and len(invites) == 1), repr(invites) assert invites[0]['to'] == 'alice@localhost' reasons = xpath.queryForNodes('/invite/reason', invites[0]) assert (reasons is not None and len(reasons) == 1), repr(reasons) assert str(reasons[0]) == 'I want to test invitations'
def run_incoming_test(q, bus, conn, stream, bob_leaves_room = False): jp = JingleProtocol031 () jt = JingleTest2(jp, conn, q, stream, 'test@localhost', muc + "/bob") jt.prepare() forbidden = [ no_muji_presences (muc) ] self_handle = conn.GetSelfHandle() _, _, test_handle, bob_handle = \ join_muc_and_check(q, bus, conn, stream, muc) presence = make_muc_presence('owner', 'moderator', muc, 'bob') muji = ('muji', ns.MUJI, {}, [('content', ns.MUJI, { "name": "Voice" }, [( 'description', ns.JINGLE_RTP, {"media": "audio"}, jt.generate_payloads(jt.audio_codecs))])]) presence.addChild(jp._simple_xml(muji)) stream.send(presence) e = q.expect ('dbus-signal', signal='NewChannels', predicate=lambda e: \ e.args[0][0][1][cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_CALL ) (path, props) = e.args[0][0] assertContains((cs.CHANNEL_TYPE_CALL + '.InitialAudio', True), props.items()) assertContains((cs.CHANNEL_TYPE_CALL + '.InitialVideo', False), props.items()) general_tests (jp, q, bus, conn, stream, path, props) channel = bus.get_object (conn.bus_name, path) props = channel.GetAll (cs.CHANNEL_TYPE_CALL, dbus_interface = dbus.PROPERTIES_IFACE) content = bus.get_object (conn.bus_name, props['Contents'][0]) check_state (q, channel, cs.CALL_STATE_PENDING_RECEIVER) codecs = jt.get_call_audio_codecs_dbus() check_and_accept_offer (q, bus, conn, self_handle, 0, content, codecs) channel.Accept (dbus_interface=cs.CHANNEL_TYPE_CALL) # Preparing stanza e = q.expect('stream-presence', to = muc + "/test") echo_muc_presence (q, stream, e.stanza, 'none', 'participant') # Codecs stanza e = q.expect('stream-presence', to = muc + "/test") echo_muc_presence (q, stream, e.stanza, 'none', 'participant') # Gabble shouldn't send new presences for a while q.forbid_events(forbidden) e = q.expect ('dbus-signal', signal = 'StreamsAdded') cstream = bus.get_object (conn.bus_name, e.args[0][0]) cstream.SetCredentials(jt.ufrag, jt.pwd, dbus_interface=cs.CALL_STREAM_IFACE_MEDIA) candidates = jt.get_call_remote_transports_dbus () cstream.AddCandidates (candidates, dbus_interface=cs.CALL_STREAM_IFACE_MEDIA) e = q.expect('stream-iq', predicate=jp.action_predicate('session-initiate')) jt.parse_session_initiate (e.query) jt.accept() # Bob adds a Video content presence = make_muc_presence('owner', 'moderator', muc, 'bob') presence.addElement ((ns.MUJI, 'muji')).addElement('preparing') stream.send(presence) presence = make_muc_presence('owner', 'moderator', muc, 'bob') muji = ('muji', ns.MUJI, {}, [('content', ns.MUJI, { "name": "Voice" }, [( 'description', ns.JINGLE_RTP, {"media": "audio"}, jt.generate_payloads(jt.audio_codecs))]), ('content', ns.MUJI, { "name": "Camera" }, [( 'description', ns.JINGLE_RTP, {"media": "video"}, jt.generate_payloads(jt.video_codecs))]), ]) presence.addChild(jp._simple_xml(muji)) stream.send(presence) # Gabble noticed bob added a content e = q.expect('dbus-signal', signal = 'ContentAdded') q.unforbid_events (forbidden) content = bus.get_object (conn.bus_name, e.args[0]) check_and_accept_offer (q, bus, conn, self_handle, 0, content, jt.get_call_video_codecs_dbus(), check_codecs_changed = False) # Gabble sends a presence to prepare e = q.expect('stream-presence', to = muc + "/test") echo_muc_presence (q, stream, e.stanza, 'none', 'participant') # Gabble sends a presence with the video codecs e = q.expect('stream-presence', to = muc + "/test") echo_muc_presence (q, stream, e.stanza, 'none', 'participant') # Gabble adds a content to the jingle session and thus a stream is added e = q.expect ('dbus-signal', signal = 'StreamsAdded') cstream = bus.get_object (conn.bus_name, e.args[0][0]) candidates = jt.get_call_remote_transports_dbus () cstream.AddCandidates (candidates, dbus_interface=cs.CALL_STREAM_IFACE_MEDIA) # And now the content-add on the jingle streams e = q.expect('stream-iq', to = muc + "/bob", predicate = lambda x: \ xpath.queryForNodes("/iq/jingle[@action='content-add']", x.stanza)) # Bob leaves the call, bye bob if bob_leaves_room: presence = make_muc_presence('owner', 'moderator', muc, 'bob') presence['type'] = 'unavailable' else: presence = make_muc_presence('owner', 'moderator', muc, 'bob') stream.send(presence) (cmembers, _, _) = q.expect_many( EventPattern ('dbus-signal', signal = 'CallMembersChanged'), # Audio and video stream EventPattern ('dbus-signal', signal = 'StreamsRemoved'), EventPattern ('dbus-signal', signal = 'StreamsRemoved')) # Just bob left assertLength (1, cmembers.args[1])
def test(q, bus, conn, stream): self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") # When Gabble initially requests its avatar from the server, it discovers # it has none. expect_and_handle_get_vcard(q, stream) handle, signalled_token = q.expect('dbus-signal', signal='AvatarUpdated').args assertEquals(self_handle, handle) assertEquals('', signalled_token) # The user sets an avatar. call_async(q, conn.Avatars, 'SetAvatar', AVATAR_1_DATA, AVATAR_1_MIME_TYPE) expect_and_handle_get_vcard(q, stream) expect_and_handle_set_vcard(q, stream) # It's signalled on D-Bus … set_ret, avatar_updated = q.expect_many( EventPattern('dbus-return', method='SetAvatar'), EventPattern('dbus-signal', signal='AvatarUpdated'), ) returned_token, = set_ret.value handle, signalled_token = avatar_updated.args assertEquals(self_handle, handle) assertEquals(returned_token, signalled_token) # … and also on XMPP. broadcast = q.expect('stream-presence', to=None) broadcast_hash = extract_hash_from_presence(broadcast.stanza) assertEquals(AVATAR_1_SHA1, broadcast_hash) # If applications ask Gabble for information about the user's own avatar, # it should be able to answer. (Strictly speaking, expecting Gabble to know # the avatar data is risky because Gabble discards cached vCards after a # while, but we happen to know it takes 20 seconds or so for that to # happen.) known = conn.Avatars.GetKnownAvatarTokens([self_handle]) assertEquals({self_handle: signalled_token}, known) conn.Avatars.RequestAvatars([self_handle]) retrieved = q.expect('dbus-signal', signal='AvatarRetrieved') handle, token, data, mime_type = retrieved.args assertEquals(self_handle, handle) assertEquals(signalled_token, token) assertEquals(AVATAR_1_DATA, data) assertEquals(AVATAR_1_MIME_TYPE, mime_type) # Well, that was quite easy. How about we join a MUC? XEP-0153 §4.1 says: # If a client supports the protocol defined herein, it […] SHOULD # also include the update child in directed presence stanzas (e.g., # directed presence sent when joining Multi-User Chat [5] rooms). # — http://xmpp.org/extensions/xep-0153.html#bizrules-presence join_event = try_to_join_muc(q, bus, conn, stream, MUC) directed_hash = extract_hash_from_presence(join_event.stanza) assertEquals(AVATAR_1_SHA1, directed_hash) # There are two others in the MUC: fredrik has no avatar, wendy has an # avatar. We, of course, have our own avatar. stream.send(make_muc_presence('none', 'participant', MUC, 'fredrik')) stream.send(make_muc_presence('none', 'participant', MUC, 'wendy', photo=AVATAR_2_SHA1)) stream.send(make_muc_presence('owner', 'moderator', MUC, 'test', photo=AVATAR_1_SHA1)) path, _ = q.expect('dbus-return', method='CreateChannel').value chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text') members = chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'Members') assertLength(3, members) fredrik, wendy, muc_self_handle = conn.get_contact_handles_sync( ['%s/%s' % (MUC, x) for x in ["fredrik", "wendy", "test"]]) known = conn.Avatars.GetKnownAvatarTokens(members) # <https://bugs.freedesktop.org/show_bug.cgi?id=32017>: this assertion # failed, the MUC self handle's token was the empty string. assertEquals(AVATAR_1_SHA1, known[muc_self_handle]) assertEquals(AVATAR_2_SHA1, known[wendy]) assertEquals('', known[fredrik]) # 'k, cool. Wendy loves our avatar and switches to it. stream.send(make_muc_presence('none', 'participant', MUC, 'wendy', photo=AVATAR_1_SHA1)) # Okay this is technically assuming that we just expose the SHA1 sums # directly which is not guaranteed … but we do. q.expect('dbus-signal', signal='AvatarUpdated', args=[wendy, AVATAR_1_SHA1]) # Fredrik switches too. stream.send(make_muc_presence('none', 'participant', MUC, 'fredrik', photo=AVATAR_1_SHA1)) q.expect('dbus-signal', signal='AvatarUpdated', args=[fredrik, AVATAR_1_SHA1]) # And we switch to some other avatar. Gabble should update its vCard, and # then update its MUC presence (which the test, acting as the MUC server, # must echo). call_async(q, conn.Avatars, 'SetAvatar', AVATAR_2_DATA, AVATAR_2_MIME_TYPE) expect_and_handle_get_vcard(q, stream) expect_and_handle_set_vcard(q, stream) muc_presence = q.expect('stream-presence', to=('%s/test' % MUC)) directed_hash = extract_hash_from_presence(muc_presence.stanza) stream.send(make_muc_presence('owner', 'moderator', MUC, 'test', photo=directed_hash)) # Gabble should signal an avatar update for both our global self-handle and # our MUC self-handle. (The first of these of course does not need to wait # for the MUC server to echo our presence.) q.expect_many( EventPattern('dbus-signal', signal='AvatarUpdated', args=[self_handle, AVATAR_2_SHA1]), EventPattern('dbus-signal', signal='AvatarUpdated', args=[muc_self_handle, AVATAR_2_SHA1]), )
def test_subject(q, bus, conn, stream, change_subject, send_first, moderator): room = '*****@*****.**' chan, path, props, disco = join_muc(q, bus, conn, stream, room, also_capture=[EventPattern('stream-iq', iq_type='get', query_name='query', query_ns=ns.DISCO_INFO, to=room)], role=(moderator and 'moderator' or 'participant')) assert chan.Properties.Get(cs.CHANNEL_IFACE_SUBJECT, "CanSet") if send_first: # Someone sets a subject. message = domish.Element((None, 'message')) message['from'] = room + '/bob' message['type'] = 'groupchat' message.addElement('subject', content='Testing') stream.send(message) q.expect('dbus-signal', interface=cs.PROPERTIES_IFACE, signal='PropertiesChanged', predicate=lambda e: e.args[0] == cs.CHANNEL_IFACE_SUBJECT) check_subject_props(chan, 'Testing', room + '/bob', True) # Reply to the disco iq = make_result_iq(stream, disco.stanza) query = iq.firstChildElement() feat = query.addElement('feature') feat['var'] = 'muc_public' x = query.addElement((ns.X_DATA, 'x')) x['type'] = 'result' if change_subject is not None: # When fd.o #13157 has been fixed, this will actually do something. field = x.addElement('field') field['var'] = 'muc#roomconfig_changesubject' field.addElement('value', content=(change_subject and 'true' or 'false')) stream.send(iq) # Someone sets a subject. message = domish.Element((None, 'message')) message['from'] = room + '/bob' message['type'] = 'groupchat' message.addElement('subject', content='lalala') stream.send(message) q.expect('dbus-signal', interface=cs.PROPERTIES_IFACE, signal='PropertiesChanged', predicate=lambda e: e.args[0] == cs.CHANNEL_IFACE_SUBJECT) check_subject_props(chan, 'lalala', room + '/bob', True) # test changing the subject call_async(q, chan, 'SetSubject', 'le lolz', dbus_interface=cs.CHANNEL_IFACE_SUBJECT) e = q.expect('stream-message', to=room) elem = e.stanza assertEquals('groupchat', elem['type']) assertEquals(1, len(elem.children)) assertEquals(elem.children[0].name, 'subject') assertEquals(str(elem.children[0]), 'le lolz') elem['from'] = room + '/test' stream.send(elem) q.expect_many(EventPattern('dbus-signal', interface=cs.PROPERTIES_IFACE, signal='PropertiesChanged', predicate=lambda e: e.args[0] == cs.CHANNEL_IFACE_SUBJECT), EventPattern('dbus-return', method='SetSubject'), ) check_subject_props(chan, 'le lolz', room + '/test', True) # Test changing the subject and getting an error back. call_async(q, chan, 'SetSubject', 'CHICKEN MAN', dbus_interface=cs.CHANNEL_IFACE_SUBJECT) e = q.expect('stream-message', to=room) elem = e.stanza elem['from'] = room elem['type'] = 'error' error = elem.addElement((None, 'error')) error['type'] = 'auth' error.addElement((ns.STANZA, 'forbidden')) stream.send(elem) q.expect('dbus-error', method='SetSubject', name=cs.PERMISSION_DENIED) # Test changing the subject and getting an error back which doesn't echo # the <subject> element. call_async(q, chan, 'SetSubject', 'CHICKEN MAN', dbus_interface=cs.CHANNEL_IFACE_SUBJECT) e = q.expect('stream-message', to=room) message = domish.Element((None, 'message')) message['from'] = room message['id'] = e.stanza['id'] message['type'] = 'error' error = message.addElement((None, 'error')) error.addElement((ns.STANZA, 'forbidden')) stream.send(message) q.expect('dbus-error', method='SetSubject', name=cs.PERMISSION_DENIED) # Test changing the subject just before we leave the room (and hence not # getting a reply). While we're here, check that you can't have more than # one call in flight at a time. call_async(q, chan, 'SetSubject', 'le lolz', dbus_interface=cs.CHANNEL_IFACE_SUBJECT) e = q.expect('stream-message', to=room) call_async(q, chan, 'SetSubject', 'le lolz', dbus_interface=cs.CHANNEL_IFACE_SUBJECT) q.expect('dbus-error', method='SetSubject', name=cs.NOT_AVAILABLE) chan.Close() event = q.expect('stream-presence', to=room + '/test') elem = event.stanza assertEquals('unavailable', elem['type']) q.expect('dbus-error', method='SetSubject', name=cs.CANCELLED) call_async(q, chan, 'SetSubject', 'how about now?', dbus_interface=cs.CHANNEL_IFACE_SUBJECT) q.expect('dbus-error', method='SetSubject', name=cs.NOT_AVAILABLE) # The MUC confirms that we've left the room. echo = make_muc_presence('member', 'none', room, 'test') echo['type'] = 'unavailable' stream.send(echo) q.expect('dbus-signal', signal='ChannelClosed')