def test(q, bus, conn, stream, image_data, mime_type): call_async(q, conn.Avatars, 'SetAvatar', image_data, mime_type) expect_and_handle_get_vcard(q, stream) def check(vcard): assertEquals(mime_type, xpath.queryForString('/vCard/PHOTO/TYPE', vcard)) binval = xpath.queryForString('/vCard/PHOTO/BINVAL', vcard) # <http://xmpp.org/extensions/xep-0153.html#bizrules-image> says: # # 5. The image data MUST conform to the base64Binary datatype and thus # be encoded in accordance with Section 6.8 of RFC 2045, which # recommends that base64 data should have lines limited to at most # 76 characters in length. lines = binval.split('\n') for line in lines: assert len(line) <= 76, line assertEquals(image_data, base64.decodestring(binval)) expect_and_handle_set_vcard(q, stream, check=check) q.expect('dbus-return', method='SetAvatar')
def test(q, bus, conn, stream): self_handle = conn.GetSelfHandle() conn.Aliasing.SetAliases({self_handle: 'lala'}) expect_and_handle_get_vcard(q, stream) pep_update = q.expect('stream-iq', iq_type='set', query_ns=ns.PUBSUB, query_name='pubsub') validate_pep_update(pep_update, 'lala') acknowledge_iq(stream, pep_update.stanza) def check(vCard): nickname = vCard.elements(uri=ns.VCARD_TEMP, name='NICKNAME').next() assertEquals('lala', nickname.children[0]) expect_and_handle_set_vcard(q, stream, check=check) event = q.expect('dbus-signal', signal='AliasesChanged', args=[[(self_handle, u'lala')]]) conn.Aliasing.SetAliases({self_handle: ''}) pep_update = q.expect('stream-iq', iq_type='set', query_ns=ns.PUBSUB, query_name='pubsub') validate_pep_update(pep_update, None) expect_and_handle_get_vcard(q, stream) def check(vCard): # The vCard should be empty, rather than having an empty <NICKNAME/> # element. assertLength(0, vCard.children) expect_and_handle_set_vcard(q, stream, check=check) event = q.expect('dbus-signal', signal='AliasesChanged', args=[[(self_handle, u'test@localhost')]])
def test(q, bus, conn, stream): expect_and_handle_get_vcard(q, stream) sync_stream(q, stream) call_async(q, conn.Avatars, 'SetAvatar', b'william shatner', 'image/x-actor-name') # Gabble request the last version of the vCard before changing it expect_and_handle_get_vcard(q, stream) set_vcard_event = q.expect('stream-iq', query_ns=ns.VCARD_TEMP, query_name='vCard', iq_type='set') iq = set_vcard_event.stanza error = domish.Element((None, 'error')) error['code'] = '400' error['type'] = 'modify' error.addElement((ns.STANZA, 'bad-request')) send_error_reply(stream, iq, error) event = q.expect('dbus-error', method='SetAvatar') assert event.error.get_dbus_name() == cs.INVALID_ARGUMENT, \ event.error.get_dbus_name()
def test(q, bus, conn, stream): conn.Connect() expect_and_handle_get_vcard(q, stream) sync_stream(q, stream) call_async(q, conn.Avatars, 'SetAvatar', 'william shatner', 'image/x-actor-name') # Gabble request the last version of the vCard before changing it expect_and_handle_get_vcard(q, stream) set_vcard_event = q.expect('stream-iq', query_ns=ns.VCARD_TEMP, query_name='vCard', iq_type='set') iq = set_vcard_event.stanza error = domish.Element((None, 'error')) error['code'] = '400' error['type'] = 'modify' error.addElement((ns.STANZA, 'bad-request')) send_error_reply(stream, iq, error) event = q.expect('dbus-error', method='SetAvatar') assert event.error.get_dbus_name() == cs.INVALID_ARGUMENT, \ event.error.get_dbus_name()
def test(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): expect_and_handle_get_vcard(q, stream) def check_vcard(vcard): for e in vcard.elements(): if e.name == 'NICKNAME': assert str(e) == 'Some Guy', e.toXml() return assert False, vcard.toXml() expect_and_handle_set_vcard(q, stream, check_vcard)
def test(q, bus, conn, stream): expect_and_handle_get_vcard(q, stream) # Ensure that Gabble's actually got the initial vCard reply; if it hasn't # processed it by the time we call SetAliases, the latter will wait for it # to reply and then set immediately. sync_stream(q, stream) handle = conn.Properties.Get(cs.CONN, "SelfHandle") call_async(q, conn.Aliasing, 'SetAliases', {handle: 'Some Guy'}) # SetAliases requests vCard v1 get_vcard_event = q.expect('stream-iq', query_ns=ns.VCARD_TEMP, query_name='vCard', iq_type='get') iq = get_vcard_event.stanza vcard = iq.firstChildElement() assert vcard.name == 'vCard', vcard.toXml() call_async(q, conn.Avatars, 'SetAvatar', 'hello', 'image/png') # We don't expect Gabble to send a second vCard request, since there's one # outstanding. But we want to ensure that SetAvatar reaches Gabble before # the empty vCard does. sync_dbus(bus, q, conn) # Send back current empty vCard result = make_result_iq(stream, iq) # result already includes the <vCard/> from the query, which is all we need stream.send(result) def has_nickname_and_photo(vcard): nicknames = xpath.queryForNodes('/vCard/NICKNAME', vcard) assert nicknames is not None assert len(nicknames) == 1 assert str(nicknames[0]) == 'Some Guy' photos = xpath.queryForNodes('/vCard/PHOTO', vcard) assert photos is not None and len(photos) == 1, repr(photos) types = xpath.queryForNodes('/PHOTO/TYPE', photos[0]) binvals = xpath.queryForNodes('/PHOTO/BINVAL', photos[0]) assert types is not None and len(types) == 1, repr(types) assert binvals is not None and len(binvals) == 1, repr(binvals) assert str(types[0]) == 'image/png' got = str(binvals[0]).strip() exp = base64.b64encode('hello') assertEquals(exp, got) # Now Gabble should set a new vCard with both of the above changes. expect_and_handle_set_vcard(q, stream, has_nickname_and_photo)
def test(q, bus, conn, stream): conn.Connect() expect_and_handle_get_vcard(q, stream) # Ensure that Gabble's actually got the initial vCard reply; if it hasn't # processed it by the time we call SetAliases, the latter will wait for it # to reply and then set immediately. sync_stream(q, stream) handle = conn.GetSelfHandle() call_async(q, conn.Aliasing, 'SetAliases', {handle: 'Some Guy'}) # SetAliases requests vCard v1 get_vcard_event = q.expect('stream-iq', query_ns=ns.VCARD_TEMP, query_name='vCard', iq_type='get') iq = get_vcard_event.stanza vcard = iq.firstChildElement() assert vcard.name == 'vCard', vcard.toXml() call_async(q, conn.Avatars, 'SetAvatar', 'hello', 'image/png') # We don't expect Gabble to send a second vCard request, since there's one # outstanding. But we want to ensure that SetAvatar reaches Gabble before # the empty vCard does. sync_dbus(bus, q, conn) # Send back current empty vCard result = make_result_iq(stream, iq) # result already includes the <vCard/> from the query, which is all we need stream.send(result) def has_nickname_and_photo(vcard): nicknames = xpath.queryForNodes('/vCard/NICKNAME', vcard) assert nicknames is not None assert len(nicknames) == 1 assert str(nicknames[0]) == 'Some Guy' photos = xpath.queryForNodes('/vCard/PHOTO', vcard) assert photos is not None and len(photos) == 1, repr(photos) types = xpath.queryForNodes('/PHOTO/TYPE', photos[0]) binvals = xpath.queryForNodes('/PHOTO/BINVAL', photos[0]) assert types is not None and len(types) == 1, repr(types) assert binvals is not None and len(binvals) == 1, repr(binvals) assert str(types[0]) == 'image/png' got = str(binvals[0]) exp = base64.b64encode('hello') assert got == exp, (got, exp) # Now Gabble should set a new vCard with both of the above changes. expect_and_handle_set_vcard(q, stream, has_nickname_and_photo)
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): photo = current_vcard.addElement((None, 'PHOTO')) photo.addElement((None, 'TYPE')).addContent('image/fake') photo.addElement((None, 'BINVAL')).addContent('NYANYANYANYANYAN') call_async(q, conn.Avatars, 'ClearAvatar') expect_and_handle_get_vcard(q, stream) def check(vcard): assert len(vcard.children) == 0, vcard.toXml() expect_and_handle_set_vcard(q, stream, check=check) q.expect('dbus-return', method='ClearAvatar')
def test(q, bus, conn, stream): expect_and_handle_get_vcard(q, stream) sync_stream(q, stream) call_async( q, conn.Avatars, 'SetAvatar', 'Guy.brush', 'image/x-mighty-pirate') expect_and_handle_get_vcard(q, stream) iq_event = q.expect( 'stream-iq', iq_type='set', query_ns='vcard-temp', query_name='vCard') call_async( q, conn.Avatars, 'SetAvatar', 'LeChuck.brush', 'image/x-ghost-pirate') disconnect_conn(q, conn, stream) q.expect('dbus-error', method='SetAvatar', name=cs.NOT_AVAILABLE) q.expect('dbus-error', method='SetAvatar', name=cs.NOT_AVAILABLE) sync_dbus(bus, q, conn)
def test(q, bus, conn, stream): expect_and_handle_get_vcard(q, stream) sync_stream(q, stream) call_async( q, conn.Avatars, 'SetAvatar', b'Guy.brush', 'image/x-mighty-pirate') expect_and_handle_get_vcard(q, stream) iq_event = q.expect( 'stream-iq', iq_type='set', query_ns='vcard-temp', query_name='vCard') call_async( q, conn.Avatars, 'SetAvatar', b'LeChuck.brush', 'image/x-ghost-pirate') disconnect_conn(q, conn, stream) q.expect('dbus-error', method='SetAvatar', name=cs.NOT_AVAILABLE) q.expect('dbus-error', method='SetAvatar', name=cs.NOT_AVAILABLE) sync_dbus(bus, q, conn)
def test(q, bus, conn, stream): self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") conn.Aliasing.SetAliases({self_handle: 'lala'}) expect_and_handle_get_vcard(q, stream) pep_update = q.expect('stream-iq', iq_type='set', query_ns=ns.PUBSUB, query_name='pubsub') validate_pep_update(pep_update, 'lala') acknowledge_iq(stream, pep_update.stanza) def check(vCard): nickname = next(vCard.elements(uri=ns.VCARD_TEMP, name='NICKNAME')) assertEquals('lala', nickname.children[0]) expect_and_handle_set_vcard(q, stream, check=check) event = q.expect('dbus-signal', signal='AliasesChanged', args=[[(self_handle, u'lala')]]) conn.Aliasing.SetAliases({self_handle: ''}) pep_update = q.expect('stream-iq', iq_type='set', query_ns=ns.PUBSUB, query_name='pubsub') validate_pep_update(pep_update, None) expect_and_handle_get_vcard(q, stream) def check(vCard): # The vCard should be empty, rather than having an empty <NICKNAME/> # element. assertLength(0, vCard.children) expect_and_handle_set_vcard(q, stream, check=check) event = q.expect('dbus-signal', signal='AliasesChanged', args=[[(self_handle, u'test@localhost')]])
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 test(q, bus, conn, stream): expect_and_handle_get_vcard(q, stream) jid = u'*****@*****.**' alias = u'Horza' handle = conn.get_contact_handle_sync(jid) # We don't have an interesting alias for Horza assertEquals({handle: jid}, get_aliases(conn, [handle])) # Horza sends us a message containing his preferred nickname. stream.send( elem('message', from_=jid, type='chat')(elem('body')(u"It's a long story."), elem(ns.NICK, 'nick')(alias))) _, mr = q.expect_many( EventPattern('dbus-signal', signal='AliasesChanged', args=[[(handle, alias)]]), EventPattern('dbus-signal', signal='MessageReceived'), ) channel = wrap_channel(bus.get_object(conn.bus_name, mr.path), 'Text') # So now we know his alias. assertEquals({handle: alias}, get_aliases(conn, [handle])) # Presumably to avoid non-contacts being able to make Gabble's memory # footprint grow forever, Gabble throws the alias away when we close the # channel. header = mr.args[0][0] channel.Text.AcknowledgePendingMessages([header['pending-message-id']]) channel.Close() # FIXME: Gabble forgets the alias, but it doesn't signal that it has done # so; it probably should. # q.expect('dbus-signal', signal='AliasesChanged', args=[[(handle, jid)]]) assertEquals({handle: jid}, get_aliases(conn, [handle])) # Basically the same test, but in a MUC. # # It's a bit questionable whether this ought to work. # <http://xmpp.org/extensions/xep-0172.html#muc> doesn't have anything to # say about including <nick/> in messages; it does talk about including # <nick> in your MUC presence, which is actually equally sketchy! If I join # a muc with the resource '/wjt', and you join with resource '/ohai' but # say that your nickname is 'wjt', what on earth is Alice's UI supposed to # show when you send a message? # # But anyway, at the time of writing this "works", so I'm adding a test to # make it explicit. Perhaps in future we might change this test to verify # that it doesn't "work". room_jid = '*****@*****.**' muc, _, _ = join_muc(q, bus, conn, stream, room_jid) bob_jid = room_jid + '/bob' bob_handle = conn.get_contact_handle_sync(bob_jid) assertEquals({bob_handle: 'bob'}, get_aliases(conn, [bob_handle])) stream.send( elem('message', from_=bob_jid, type='groupchat')( elem('body')(u'My religion dies with me.'), elem(ns.NICK, 'nick')(alias), )) q.expect_many( EventPattern('dbus-signal', signal='AliasesChanged', args=[[(bob_handle, alias)]]), EventPattern('dbus-signal', signal='MessageReceived'), ) assertEquals({bob_handle: alias}, get_aliases(conn, [bob_handle])) muc.Close() q.expect('stream-presence', to=room_jid + '/test') echo = make_muc_presence('member', 'none', room_jid, 'test') echo['type'] = 'unavailable' stream.send(echo) q.expect('dbus-signal', signal='ChannelClosed') # FIXME: Gabble forgets the alias, but it doesn't signal that it has done # so; it probably should. # q.expect('dbus-signal', signal='AliasesChanged', # args=[[(bob_handle, 'bob')]]) assertEquals({bob_handle: 'bob'}, get_aliases(conn, [bob_handle]))
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(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(q, bus, conn, stream): expect_and_handle_get_vcard(q, stream) jid = u"*****@*****.**" alias = u"Horza" handle = conn.RequestHandles(cs.HT_CONTACT, [jid])[0] # We don't have an interesting alias for Horza assertEquals({handle: jid}, conn.Aliasing.GetAliases([handle])) # Horza sends us a message containing his preferred nickname. stream.send( elem("message", from_=jid, type="chat")(elem("body")(u"It's a long story."), elem(ns.NICK, "nick")(alias)) ) _, mr = q.expect_many( EventPattern("dbus-signal", signal="AliasesChanged", args=[[(handle, alias)]]), EventPattern("dbus-signal", signal="MessageReceived"), ) channel = wrap_channel(bus.get_object(conn.bus_name, mr.path), "Text") # So now we know his alias. assertEquals({handle: alias}, conn.Aliasing.GetAliases([handle])) # Presumably to avoid non-contacts being able to make Gabble's memory # footprint grow forever, Gabble throws the alias away when we close the # channel. header = mr.args[0][0] channel.Text.AcknowledgePendingMessages([header["pending-message-id"]]) channel.Close() # FIXME: Gabble forgets the alias, but it doesn't signal that it has done # so; it probably should. # q.expect('dbus-signal', signal='AliasesChanged', args=[[(handle, jid)]]) assertEquals({handle: jid}, conn.Aliasing.GetAliases([handle])) # Basically the same test, but in a MUC. # # It's a bit questionable whether this ought to work. # <http://xmpp.org/extensions/xep-0172.html#muc> doesn't have anything to # say about including <nick/> in messages; it does talk about including # <nick> in your MUC presence, which is actually equally sketchy! If I join # a muc with the resource '/wjt', and you join with resource '/ohai' but # say that your nickname is 'wjt', what on earth is Alice's UI supposed to # show when you send a message? # # But anyway, at the time of writing this "works", so I'm adding a test to # make it explicit. Perhaps in future we might change this test to verify # that it doesn't "work". room_jid = "*****@*****.**" _, muc, _, _ = join_muc(q, bus, conn, stream, room_jid) bob_jid = room_jid + "/bob" bob_handle = conn.RequestHandles(cs.HT_CONTACT, [bob_jid])[0] assertEquals({bob_handle: "bob"}, conn.Aliasing.GetAliases([bob_handle])) stream.send( elem("message", from_=bob_jid, type="groupchat")( elem("body")(u"My religion dies with me."), elem(ns.NICK, "nick")(alias) ) ) q.expect_many( EventPattern("dbus-signal", signal="AliasesChanged", args=[[(bob_handle, alias)]]), EventPattern("dbus-signal", signal="MessageReceived"), ) assertEquals({bob_handle: alias}, conn.Aliasing.GetAliases([bob_handle])) muc.Close() q.expect("stream-presence", to=room_jid + "/test") echo = make_muc_presence("member", "none", room_jid, "test") echo["type"] = "unavailable" stream.send(echo) q.expect("dbus-signal", signal="ChannelClosed") # FIXME: Gabble forgets the alias, but it doesn't signal that it has done # so; it probably should. # q.expect('dbus-signal', signal='AliasesChanged', # args=[[(bob_handle, 'bob')]]) assertEquals({bob_handle: "bob"}, conn.Aliasing.GetAliases([bob_handle]))