def test_two_clients(q, bus, conn, stream, contact1, contact2, contact_handle1, contact_handle2, client, broken_hash): presence = make_presence(contact1, status='hello') stream.send(presence) q.expect('dbus-signal', signal='PresencesChanged', args=[{contact_handle1: (2, u'available', 'hello')}]) presence = make_presence(contact2, status='hello') stream.send(presence) q.expect('dbus-signal', signal='PresencesChanged', args=[{contact_handle2: (2, u'available', 'hello')}]) # no special capabilities for h in (contact_handle1, contact_handle2): for rcc in get_contacts_capabilities_sync(conn, [h])[h]: assertEquals(cs.CHANNEL_TYPE_TEXT, rcc[0].get(cs.CHANNEL_TYPE)) # send updated presence with Jingle caps info ver = compute_caps_hash(some_identities, jingle_av_features, {}) caps = { 'node': client, 'ver': ver, 'hash': 'sha-1', } presence = make_presence(contact1, status='hello', caps=caps) stream.send(presence) presence = make_presence(contact2, status='hello', caps=caps) stream.send(presence) # Gabble looks up our capabilities event = q.expect('stream-iq', to=contact1, query_ns='http://jabber.org/protocol/disco#info') query_node = xpath.queryForNodes('/iq/query', event.stanza)[0] assert query_node.attributes['node'] == \ client + '#' + ver # don't receive any D-Bus signal forbidden = [ EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), ] q.forbid_events(forbidden) sync_dbus(bus, q, conn) q.unforbid_events(forbidden) result = make_caps_disco_reply( stream, event.stanza, some_identities, jingle_av_features) if broken_hash: # make the hash break! query = result.firstChildElement() query.addElement('feature')['var'] = 'http://example.com/another-feature' stream.send(result) if broken_hash: # Gabble looks up our capabilities again because the first contact # failed to provide a valid hash event = q.expect('stream-iq', to=contact2, query_ns='http://jabber.org/protocol/disco#info') query_node = xpath.queryForNodes('/iq/query', event.stanza)[0] assert query_node.attributes['node'] == \ client + '#' + ver # don't receive any D-Bus signal q.forbid_events(forbidden) sync_dbus(bus, q, conn) q.unforbid_events(forbidden) # send good reply send_disco_reply(stream, event.stanza, some_identities, jingle_av_features) # we can now do audio calls cc, = q.expect_many( EventPattern('dbus-signal', signal='ContactCapabilitiesChanged', predicate=lambda e: contact_handle2 in e.args[0]), ) assert_rccs_callable(cc.args[0][contact_handle2]) if not broken_hash: # if the first contact failed to provide a good hash, it does not # deserve its capabilities to be understood by Gabble! cc, = q.expect_many( EventPattern('dbus-signal', signal='ContactCapabilitiesChanged', predicate=lambda e: contact_handle1 in e.args[0]), ) assert_rccs_callable(cc.args[0][contact_handle1]) # don't receive any further signals q.forbid_events(forbidden) sync_dbus(bus, q, conn) q.unforbid_events(forbidden)
def test_hash(q, bus, conn, stream, contact, contact_handle, client): global caps_changed_flag presence = make_presence(contact, status='hello') stream.send(presence) q.expect_many( EventPattern('dbus-signal', signal='PresenceUpdate', args=[{contact_handle: (0L, {u'available': {'message': 'hello'}})}]), EventPattern('dbus-signal', signal='PresencesChanged', args=[{contact_handle: (2, u'available', 'hello')}])) # no special capabilities basic_caps = [(contact_handle, cs.CHANNEL_TYPE_TEXT, 3, 0)] assert conn.Capabilities.GetCapabilities([contact_handle]) == basic_caps # send updated presence with Jingle caps info presence = make_presence(contact, status='hello', caps={'node': client, 'ver': '0.1', }) stream.send(presence) # Gabble looks up our capabilities event = q.expect('stream-iq', to=contact, query_ns='http://jabber.org/protocol/disco#info') query_node = xpath.queryForNodes('/iq/query', event.stanza)[0] assert query_node.attributes['node'] == \ client + '#' + '0.1' # send good reply stream.send(make_caps_disco_reply(stream, event.stanza, jingle_av_features)) # we can now do audio calls event = q.expect('dbus-signal', signal='CapabilitiesChanged') caps_changed_flag = False # send bogus presence caps = { 'node': client, 'ver': 'ceci=nest=pas=un=hash', 'hash': 'sha-1', } presence = make_presence(contact, status='hello', caps=caps) stream.send(presence) # Gabble looks up our capabilities event = q.expect('stream-iq', to=contact, query_ns='http://jabber.org/protocol/disco#info') query_node = xpath.queryForNodes('/iq/query', event.stanza)[0] assert query_node.attributes['node'] == \ client + '#' + caps['ver'] # send bogus reply stream.send(make_caps_disco_reply(stream, event.stanza, ['http://jabber.org/protocol/bogus-feature'])) # don't receive any D-Bus signal sync_dbus(bus, q, conn) sync_stream(q, stream) assert caps_changed_flag == False # send presence with empty caps presence = make_presence(contact, status='hello', caps={'node': client, 'ver': '0.0', }) stream.send(presence) # Gabble looks up our capabilities event = q.expect('stream-iq', to=contact, query_ns='http://jabber.org/protocol/disco#info') query_node = xpath.queryForNodes('/iq/query', event.stanza)[0] assert query_node.attributes['node'] == \ client + '#' + '0.0' # still don't receive any D-Bus signal sync_dbus(bus, q, conn) assert caps_changed_flag == False # send good reply result = make_result_iq(stream, event.stanza) query = result.firstChildElement() stream.send(result) # we can now do nothing event = q.expect('dbus-signal', signal='CapabilitiesChanged') assert caps_changed_flag == True caps_changed_flag = False # send correct presence ver = compute_caps_hash([], jingle_av_features, fake_client_dataforms) caps = { 'node': client, 'ver': ver, 'hash': 'sha-1', } presence = make_presence(contact, status='hello', caps=caps) stream.send(presence) # Gabble looks up our capabilities event = q.expect('stream-iq', to=contact, query_ns='http://jabber.org/protocol/disco#info') query_node = xpath.queryForNodes('/iq/query', event.stanza)[0] assert query_node.attributes['node'] == \ client + '#' + caps['ver'] # don't receive any D-Bus signal sync_dbus(bus, q, conn) assert caps_changed_flag == False # send good reply result = make_caps_disco_reply(stream, event.stanza, jingle_av_features, fake_client_dataforms) stream.send(result) # we can now do audio calls event = q.expect('dbus-signal', signal='CapabilitiesChanged', ) assert caps_changed_flag == True caps_changed_flag = False
def send_remote_disco_reply(self, stanza): reply = make_caps_disco_reply(self.stream, stanza, self.remote_feats) self.stream.send(reply.toXml())
def test_two_clients(q, bus, conn, stream, contact1, contact2, contact_handle1, contact_handle2, client, broken_hash): global caps_changed_flag presence = make_presence(contact1, status='hello') stream.send(presence) event = q.expect_many( EventPattern('dbus-signal', signal='PresenceUpdate', args=[{contact_handle1: (0L, {u'available': {'message': 'hello'}})}]), EventPattern('dbus-signal', signal='PresencesChanged', args=[{contact_handle1: (2, u'available', 'hello')}])) presence = make_presence(contact2, status='hello') stream.send(presence) event = q.expect_many( EventPattern('dbus-signal', signal='PresenceUpdate', args=[{contact_handle2: (0L, {u'available': {'message': 'hello'}})}]), EventPattern('dbus-signal', signal='PresencesChanged', args=[{contact_handle2: (2, u'available', 'hello')}])) # no special capabilities basic_caps = [(contact_handle1, cs.CHANNEL_TYPE_TEXT, 3, 0)] assert conn.Capabilities.GetCapabilities([contact_handle1]) == basic_caps basic_caps = [(contact_handle2, cs.CHANNEL_TYPE_TEXT, 3, 0)] assert conn.Capabilities.GetCapabilities([contact_handle2]) == basic_caps # send updated presence with Jingle caps info ver = compute_caps_hash([], jingle_av_features, {}) caps = { 'node': client, 'ver': ver, 'hash': 'sha-1', } presence = make_presence(contact1, status='hello', caps=caps) stream.send(presence) presence = make_presence(contact2, status='hello', caps=caps) stream.send(presence) # Gabble looks up our capabilities event = q.expect('stream-iq', to=contact1, query_ns='http://jabber.org/protocol/disco#info') query_node = xpath.queryForNodes('/iq/query', event.stanza)[0] assert query_node.attributes['node'] == \ client + '#' + ver # don't receive any D-Bus signal sync_dbus(bus, q, conn) assert caps_changed_flag == False result = make_caps_disco_reply(stream, event.stanza, jingle_av_features) if broken_hash: # make the hash break! query = result.firstChildElement() query.addElement('feature')['var'] = 'http://example.com/another-feature' stream.send(result) if broken_hash: # Gabble looks up our capabilities again because the first contact # failed to provide a valid hash event = q.expect('stream-iq', to=contact2, query_ns='http://jabber.org/protocol/disco#info') query_node = xpath.queryForNodes('/iq/query', event.stanza)[0] assert query_node.attributes['node'] == \ client + '#' + ver # don't receive any D-Bus signal sync_dbus(bus, q, conn) assert caps_changed_flag == False # send good reply result = make_caps_disco_reply(stream, event.stanza, jingle_av_features) stream.send(result) # we can now do audio calls with both contacts event = q.expect('dbus-signal', signal='CapabilitiesChanged', args=[[(contact_handle2, cs.CHANNEL_TYPE_STREAMED_MEDIA, 0, 3, 0, cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO)]]) if not broken_hash: # if the first contact failed to provide a good hash, it does not # deserve its capabilities to be understood by Gabble! event = q.expect('dbus-signal', signal='CapabilitiesChanged', args=[[(contact_handle1, cs.CHANNEL_TYPE_STREAMED_MEDIA, 0, 3, 0, cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO)]]) caps_changed_flag = False # don't receive any D-Bus signal sync_dbus(bus, q, conn) assert caps_changed_flag == False
def test(q, bus, conn, stream): conn.Connect() q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]) client = 'http://example.com/perverse-client' contact_bare_jid = '*****@*****.**' contact_with_resource = '[email protected]/hi' contact_handle = conn.RequestHandles(cs.HT_CONTACT, [contact_bare_jid])[0] # Gabble gets a presence stanza from a bare JID, which is a tad surprising. features = [ ns.JINGLE_015, ns.JINGLE_015_AUDIO, ns.JINGLE_015_VIDEO, ns.GOOGLE_P2P, ] caps = {'node': client, 'hash': 'sha-1', 'ver': compute_caps_hash([], features, {}), } p = make_presence(contact_bare_jid, status='Hello', caps=caps) stream.send(p) # Gabble looks up the hash event = q.expect('stream-iq', to=contact_bare_jid, query_ns='http://jabber.org/protocol/disco#info') query_node = xpath.queryForNodes('/iq/query', event.stanza)[0] assertEquals(client + '#' + caps['ver'], query_node.attributes['node']) # The bare jid replies result = make_caps_disco_reply(stream, event.stanza, features, {}) stream.send(result) # Gabble lets us know their caps have changed. (Gabble used to ignore the # reply.) streamed_media_caps = (contact_handle, cs.CHANNEL_TYPE_STREAMED_MEDIA, 0, 3, 0, cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO) e = q.expect('dbus-signal', signal='CapabilitiesChanged') assertContains(streamed_media_caps, e.args[0]) # Gabble gets another presence stanza from the bare JID, with different # caps. features.append(ns.TUBES) caps = {'node': client, 'hash': 'sha-1', 'ver': compute_caps_hash([], features, {}), } p = make_presence(contact_bare_jid, status='Get out the abacus', caps=caps) stream.send(p) # Gabble looks up the new hash disco2 = q.expect('stream-iq', to=contact_bare_jid, query_ns='http://jabber.org/protocol/disco#info') query_node = xpath.queryForNodes('/iq/query', disco2.stanza)[0] assertEquals(client + '#' + caps['ver'], query_node.attributes['node']) # This time, before the bare JID replies, Gabble gets a presence from the # resourceful jid. features_ = features + [ns.CHAT_STATES] caps = {'node': client, 'hash': 'sha-1', 'ver': compute_caps_hash([], features_, {}), } p = make_presence(contact_with_resource, status='Count this', caps=caps) stream.send(p) # Gabble throws away presence from the bare JID when it gets presence from # a resource (and vice versa), so it should now say the contact is # incapable. Gabble also looks up the resourceful JID's hash. cc, disco3 = q.expect_many( EventPattern('dbus-signal', signal='CapabilitiesChanged'), EventPattern('stream-iq', to=contact_with_resource, query_ns='http://jabber.org/protocol/disco#info'), ) assertDoesNotContain(streamed_media_caps, cc.args[0]) query_node = xpath.queryForNodes('/iq/query', disco3.stanza)[0] assertEquals(client + '#' + caps['ver'], query_node.attributes['node']) # The bare jid replies! Getting a disco reply from a bare JID when we've # got presence from resources used to crash Gabble, but now it just ignores # it. result = make_caps_disco_reply(stream, disco2.stanza, features, {}) stream.send(result) # Now the resourceful JID replies: result = make_caps_disco_reply(stream, disco3.stanza, features_, {}) stream.send(result) # Gabble should announce that the contact has acquired some caps. e = q.expect('dbus-signal', signal='CapabilitiesChanged') assertContains(streamed_media_caps, e.args[0])