From 222a59e6959bbc9e53b03812c0d3f314675fd402 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 11 Sep 2013 17:10:13 +0100 Subject: [PATCH 4/5] regression tests: avoid relying on ye olde Capabilities Telepathy 1.0 won't have these, only ContactCapabilities. We should make sure that deleting Capabilities isn't a test-coverage regression. --- tests/twisted/caps/caps-cache.py | 13 ++- tests/twisted/caps/caps-persistent-cache.py | 4 +- tests/twisted/caps/from-bare-jid.py | 27 ++++-- tests/twisted/caps/hashed-caps.py | 121 ++++++++++++++++----------- tests/twisted/caps/receive-jingle.py | 123 ++++++++++++++++++++-------- tests/twisted/caps/trust-thyself.py | 25 ++++-- tests/twisted/caps_helper.py | 70 ++++++++++++++++ 7 files changed, 289 insertions(+), 94 deletions(-) diff --git a/tests/twisted/caps/caps-cache.py b/tests/twisted/caps/caps-cache.py index 9c63e03..aea8bc2 100644 --- a/tests/twisted/caps/caps-cache.py +++ b/tests/twisted/caps/caps-cache.py @@ -12,7 +12,8 @@ import constants as cs import ns from caps_helper import ( compute_caps_hash, fake_client_dataforms, presence_and_disco, - send_presence, expect_disco, send_disco_reply) + send_presence, expect_disco, send_disco_reply, + assert_rccs_callable) from config import VOIP_ENABLED @@ -31,10 +32,18 @@ features = [ def expect_caps(q, conn, h): # we can now do audio and video calls - event = q.expect('dbus-signal', signal='CapabilitiesChanged') + old, new = q.expect_many( + EventPattern('dbus-signal', signal='CapabilitiesChanged'), + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged', + predicate=lambda e: h in e.args[0]), + ) + assert_rccs_callable(new.args[0][h], require_video=True) check_caps(conn, h) def check_caps(conn, h): + caps = conn.ContactCapabilities.GetContactCapabilities([h]) + assert_rccs_callable(caps[h], require_video=True) + assertContains((h, cs.CHANNEL_TYPE_STREAMED_MEDIA, 3, cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO), conn.Capabilities.GetCapabilities([h])) diff --git a/tests/twisted/caps/caps-persistent-cache.py b/tests/twisted/caps/caps-persistent-cache.py index 2b13183..0d418fe 100644 --- a/tests/twisted/caps/caps-persistent-cache.py +++ b/tests/twisted/caps/caps-persistent-cache.py @@ -5,7 +5,8 @@ from servicetest import ( assertEquals, assertContains, assertDoesNotContain, EventPattern, ) from gabbletest import make_presence, exec_test -from caps_helper import compute_caps_hash, send_disco_reply +from caps_helper import (compute_caps_hash, send_disco_reply, + assert_rccs_callable) import constants as cs import ns @@ -52,6 +53,7 @@ def capabilities_changed(q, contact_handle): assertContains(streamed_media_caps, e.args[0]) e = q.expect('dbus-signal', signal='ContactCapabilitiesChanged') assertContains(contact_handle, e.args[0]) + assert_rccs_callable(e.args[0][contact_handle], require_video=True) assertContains(xiangqi_tube_cap, e.args[0][contact_handle]) def test1(q, bus, conn, stream): diff --git a/tests/twisted/caps/from-bare-jid.py b/tests/twisted/caps/from-bare-jid.py index 0460fd6..c0d5234 100644 --- a/tests/twisted/caps/from-bare-jid.py +++ b/tests/twisted/caps/from-bare-jid.py @@ -8,7 +8,8 @@ from servicetest import ( assertEquals, assertContains, assertDoesNotContain, EventPattern, ) from gabbletest import make_presence, exec_test -from caps_helper import compute_caps_hash, send_disco_reply +from caps_helper import (compute_caps_hash, send_disco_reply, + assert_rccs_callable, assert_rccs_not_callable) import constants as cs import ns @@ -49,10 +50,14 @@ def test(q, bus, conn, stream): # Gabble lets us know their caps have changed. (Gabble used to ignore the # reply.) + old, new = q.expect_many( + EventPattern('dbus-signal', signal='CapabilitiesChanged'), + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), + ) 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]) + assertContains(streamed_media_caps, old.args[0]) + assert_rccs_callable(new.args[0][contact_handle]) # Gabble gets another presence stanza from the bare JID, with different # caps. @@ -83,13 +88,15 @@ def test(q, bus, conn, stream): # 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( + old, new, disco3 = q.expect_many( EventPattern('dbus-signal', signal='CapabilitiesChanged'), + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), EventPattern('stream-iq', to=contact_with_resource, query_ns='http://jabber.org/protocol/disco#info'), ) - assertDoesNotContain(streamed_media_caps, cc.args[0]) + assertDoesNotContain(streamed_media_caps, old.args[0]) + assert_rccs_not_callable(new.args[0][contact_handle]) query_node = xpath.queryForNodes('/iq/query', disco3.stanza)[0] assertEquals(client + '#' + caps['ver'], query_node.attributes['node']) @@ -103,8 +110,14 @@ def test(q, bus, conn, stream): send_disco_reply(stream, disco3.stanza, [], features_) # Gabble should announce that the contact has acquired some caps. - e = q.expect('dbus-signal', signal='CapabilitiesChanged') - assertContains(streamed_media_caps, e.args[0]) + old, new = q.expect_many( + EventPattern('dbus-signal', signal='CapabilitiesChanged'), + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), + ) + streamed_media_caps = (contact_handle, cs.CHANNEL_TYPE_STREAMED_MEDIA, + 0, 3, 0, cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO) + assertContains(streamed_media_caps, old.args[0]) + assert_rccs_callable(new.args[0][contact_handle]) if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/caps/hashed-caps.py b/tests/twisted/caps/hashed-caps.py index 5c4562c..5f612d9 100644 --- a/tests/twisted/caps/hashed-caps.py +++ b/tests/twisted/caps/hashed-caps.py @@ -27,12 +27,12 @@ from twisted.words.xish import xpath from gabbletest import ( exec_test, make_result_iq, make_presence, sync_stream, elem, ) -from servicetest import sync_dbus, EventPattern, assertLength +from servicetest import sync_dbus, EventPattern, assertLength, assertEquals import constants as cs import ns from caps_helper import ( compute_caps_hash, make_caps_disco_reply, send_disco_reply, - fake_client_dataforms) + fake_client_dataforms, assert_rccs_callable, assert_rccs_not_callable) from config import VOIP_ENABLED @@ -40,8 +40,6 @@ if not VOIP_ENABLED: print "NOTE: built with --disable-voip" raise SystemExit(77) -caps_changed_flag = False - some_identities = [ 'client/pc/fr/le gabble', 'client/pc/en/gabble', @@ -53,15 +51,7 @@ jingle_av_features = [ ns.GOOGLE_P2P, ] -def caps_changed_cb(dummy): - # Workaround to bug 9980: do not raise an error but use a flag - # https://bugs.freedesktop.org/show_bug.cgi?id=9980 - global caps_changed_flag - caps_changed_flag = True - def test_hash(q, bus, conn, stream, contact, contact_handle, client): - global caps_changed_flag - presence = make_presence(contact, status='hello') stream.send(presence) @@ -72,6 +62,8 @@ def test_hash(q, bus, conn, stream, contact, contact_handle, client): # no special capabilities basic_caps = [(contact_handle, cs.CHANNEL_TYPE_TEXT, 3, 0)] assert conn.Capabilities.GetCapabilities([contact_handle]) == basic_caps + for rcc in conn.ContactCapabilities.GetContactCapabilities([contact_handle])[contact_handle]: + assertEquals(cs.CHANNEL_TYPE_TEXT, rcc[0].get(cs.CHANNEL_TYPE)) # send updated presence with Jingle caps info presence = make_presence(contact, status='hello', @@ -91,12 +83,19 @@ def test_hash(q, bus, conn, stream, contact, contact_handle, client): send_disco_reply(stream, event.stanza, [], jingle_av_features) # we can now do audio calls - event = q.expect('dbus-signal', signal='CapabilitiesChanged') - caps_diff = event.args[0] + old, new = q.expect_many( + EventPattern('dbus-signal', signal='CapabilitiesChanged'), + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), + ) + + caps_diff = old.args[0] media_diff = [c for c in caps_diff if c[1] == cs.CHANNEL_TYPE_STREAMED_MEDIA][0] assert media_diff[5] & cs.MEDIA_CAP_AUDIO, media_diff[5] - caps_changed_flag = False + + assert_rccs_callable(new.args[0][contact_handle]) + assertEquals(new.args[0], + conn.ContactCapabilities.GetContactCapabilities([contact_handle])) # Send presence without any capabilities. XEP-0115 §8.4 Caps Optimization # says “receivers of presence notifications MUST NOT expect an annotation @@ -109,6 +108,9 @@ def test_hash(q, bus, conn, stream, contact, contact_handle, client): assertLength(1, [c for c in ye_olde_caps if c[1] == cs.CHANNEL_TYPE_STREAMED_MEDIA and c[3] & cs.MEDIA_CAP_AUDIO]) + # still exactly the same capabilities + assertEquals(new.args[0], + conn.ContactCapabilities.GetContactCapabilities([contact_handle])) # send bogus presence caps = { @@ -131,10 +133,13 @@ def test_hash(q, bus, conn, stream, contact, contact_handle, client): ['http://jabber.org/protocol/bogus-feature']) # don't receive any D-Bus signal + forbidden = [ + EventPattern('dbus-signal', signal='CapabilitiesChanged'), + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), + ] + q.forbid_events(forbidden) 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', @@ -152,18 +157,23 @@ def test_hash(q, bus, conn, stream, contact, contact_handle, client): # still don't receive any D-Bus signal sync_dbus(bus, q, conn) - assert caps_changed_flag == False # send good reply + q.unforbid_events(forbidden) 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 - + old, new = q.expect_many( + EventPattern('dbus-signal', signal='CapabilitiesChanged'), + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), + ) + for rcc in new.args[0][contact_handle]: + assertEquals(cs.CHANNEL_TYPE_TEXT, rcc[0].get(cs.CHANNEL_TYPE)) + assert_rccs_not_callable(new.args[0][contact_handle]) + assertEquals(new.args[0], + conn.ContactCapabilities.GetContactCapabilities([contact_handle])) # send correct presence ver = compute_caps_hash(some_identities, jingle_av_features, fake_client_dataforms) @@ -183,22 +193,25 @@ def test_hash(q, bus, conn, stream, contact, contact_handle, client): client + '#' + caps['ver'] # don't receive any D-Bus signal + q.forbid_events(forbidden) sync_dbus(bus, q, conn) - assert caps_changed_flag == False + q.unforbid_events(forbidden) # send good reply send_disco_reply( stream, event.stanza, some_identities, jingle_av_features, fake_client_dataforms) # we can now do audio calls - event = q.expect('dbus-signal', signal='CapabilitiesChanged', - ) - assert caps_changed_flag == True - caps_changed_flag = False + old, new = q.expect_many( + EventPattern('dbus-signal', signal='CapabilitiesChanged'), + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), + ) + assert_rccs_callable(new.args[0][contact_handle]) + assertEquals(new.args[0], + conn.ContactCapabilities.GetContactCapabilities([contact_handle])) 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) @@ -220,6 +233,10 @@ def test_two_clients(q, bus, conn, stream, contact1, contact2, basic_caps = [(contact_handle2, cs.CHANNEL_TYPE_TEXT, 3, 0)] assert conn.Capabilities.GetCapabilities([contact_handle2]) == basic_caps + for h in (contact_handle1, contact_handle2): + for rcc in conn.ContactCapabilities.GetContactCapabilities([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 = { @@ -240,8 +257,13 @@ def test_two_clients(q, bus, conn, stream, contact1, contact2, client + '#' + ver # don't receive any D-Bus signal + forbidden = [ + EventPattern('dbus-signal', signal='CapabilitiesChanged'), + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), + ] + q.forbid_events(forbidden) sync_dbus(bus, q, conn) - assert caps_changed_flag == False + q.unforbid_events(forbidden) result = make_caps_disco_reply( stream, event.stanza, some_identities, jingle_av_features) @@ -263,28 +285,39 @@ def test_two_clients(q, bus, conn, stream, contact1, contact2, client + '#' + ver # don't receive any D-Bus signal + q.forbid_events(forbidden) sync_dbus(bus, q, conn) - assert caps_changed_flag == False + q.unforbid_events(forbidden) # send good reply send_disco_reply(stream, event.stanza, some_identities, jingle_av_features) - # 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)]]) + # we can now do audio calls + old, new = q.expect_many( + EventPattern('dbus-signal', signal='CapabilitiesChanged', + args=[[(contact_handle2, cs.CHANNEL_TYPE_STREAMED_MEDIA, 0, 3, 0, + cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO)]]), + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged', + predicate=lambda e: contact_handle2 in e.args[0]), + ) + assert_rccs_callable(new.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! - 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 + old, new = q.expect_many( + EventPattern('dbus-signal', signal='CapabilitiesChanged', + args=[[(contact_handle1, cs.CHANNEL_TYPE_STREAMED_MEDIA, 0, 3, 0, + cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO)]]), + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged', + predicate=lambda e: contact_handle1 in e.args[0]), + ) + assert_rccs_callable(new.args[0][contact_handle1]) + + # don't receive any further signals + q.forbid_events(forbidden) sync_dbus(bus, q, conn) - assert caps_changed_flag == False + q.unforbid_events(forbidden) def test_39464(q, bus, conn, stream): """ @@ -318,10 +351,6 @@ def test_39464(q, bus, conn, stream): sync_stream(q, stream) def test(q, bus, conn, stream): - # be notified when the signal CapabilitiesChanged is fired - conn_caps_iface = dbus.Interface(conn, cs.CONN_IFACE_CAPS) - conn_caps_iface.connect_to_signal('CapabilitiesChanged', caps_changed_cb) - test_hash(q, bus, conn, stream, 'bob@foo.com/Foo', 2L, 'http://telepathy.freedesktop.org/fake-client') test_hash(q, bus, conn, stream, 'bob2@foo.com/Foo', 3L, 'http://telepathy.freedesktop.org/fake-client2') diff --git a/tests/twisted/caps/receive-jingle.py b/tests/twisted/caps/receive-jingle.py index 7ea84f5..cb67712 100644 --- a/tests/twisted/caps/receive-jingle.py +++ b/tests/twisted/caps/receive-jingle.py @@ -6,6 +6,8 @@ import dbus from servicetest import EventPattern, assertEquals, sync_dbus from gabbletest import exec_test, make_result_iq, make_presence, sync_stream +from caps_helper import (assert_rccs_callable, assert_rccs_not_callable, + check_rccs_callable) import constants as cs from config import VOIP_ENABLED @@ -15,25 +17,37 @@ if not VOIP_ENABLED: raise SystemExit(77) icaps_attr = cs.CONN_IFACE_CAPS + "/caps" -basic_caps = [(2, cs.CHANNEL_TYPE_TEXT, 3, 0)] def test(q, bus, conn, stream): + bob, = conn.RequestHandles(cs.HT_CONTACT, ['bob@foo.com']) + presence = make_presence('bob@foo.com/Foo', status='hello') stream.send(presence) q.expect('dbus-signal', signal='PresencesChanged', - args=[{2L: (2, u'available', 'hello')}]) + args=[{bob: (cs.PRESENCE_AVAILABLE, u'available', 'hello')}]) - # FIXME: throughout this test, Bob's handle is assumed to be 2. + basic_caps = [(bob, cs.CHANNEL_TYPE_TEXT, 3, 0)] # no special capabilities - assert conn.Capabilities.GetCapabilities([2]) == basic_caps + assert conn.Capabilities.GetCapabilities([bob]) == basic_caps + # only Text + for rcc in conn.ContactCapabilities.GetContactCapabilities([bob])[bob]: + assertEquals(cs.CHANNEL_TYPE_TEXT, rcc[0].get(cs.CHANNEL_TYPE)) # holding the handle here: see below assert conn.Contacts.GetContactAttributes( - [2], [cs.CONN_IFACE_CAPS], True) == \ - { 2L: { icaps_attr: basic_caps, + [bob], [cs.CONN_IFACE_CAPS], True) == \ + { bob: { icaps_attr: basic_caps, cs.CONN + '/contact-id': 'bob@foo.com'}} + assertEquals( + { bob: { + cs.ATTR_CONTACT_CAPABILITIES: + conn.ContactCapabilities.GetContactCapabilities([bob])[bob], + cs.CONN + '/contact-id': 'bob@foo.com', + }, + }, + conn.Contacts.GetContactAttributes([bob], [cs.CONN_IFACE_CONTACT_CAPS], True)) # send updated presence with Jingle audio/video caps info. we turn on both # audio and video at the same time to test that all of the capabilities are @@ -76,16 +90,32 @@ def test(q, bus, conn, stream): stream.send(result) # we can now do audio and video calls - event = q.expect('dbus-signal', signal='CapabilitiesChanged', - args=[[(2, cs.CHANNEL_TYPE_STREAMED_MEDIA, 0, 3, - 0, cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO)]]) - - caps = conn.Contacts.GetContactAttributes([2], [cs.CONN_IFACE_CAPS], False) - assert caps.keys() == [2L] - assert icaps_attr in caps[2L] - assert len(caps[2L][icaps_attr]) == 2 - assert basic_caps[0] in caps[2L][icaps_attr] - assert (2, cs.CHANNEL_TYPE_STREAMED_MEDIA, 3, 3) in caps[2L][icaps_attr] + old, new = q.expect_many( + EventPattern('dbus-signal', signal='CapabilitiesChanged', + args=[[(bob, cs.CHANNEL_TYPE_STREAMED_MEDIA, 0, 3, + 0, cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO)]]), + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged', + predicate=lambda e: check_rccs_callable(e.args[0][bob])), + ) + assert_rccs_callable(new.args[0][bob], require_video=True, + mutable_contents=True) + + caps = conn.Contacts.GetContactAttributes([bob], [cs.CONN_IFACE_CAPS], False) + assert caps.keys() == [bob] + assert icaps_attr in caps[bob] + assert len(caps[bob][icaps_attr]) == 2 + assert basic_caps[0] in caps[bob][icaps_attr] + assert (bob, cs.CHANNEL_TYPE_STREAMED_MEDIA, 3, 3) in caps[bob][icaps_attr] + + assertEquals( + { bob: { + cs.ATTR_CONTACT_CAPABILITIES: + new.args[0][bob], + cs.CONN + '/contact-id': 'bob@foo.com', + }, + }, + conn.Contacts.GetContactAttributes([bob], + [cs.CONN_IFACE_CONTACT_CAPS], True)) # send updated presence without video support presence = make_presence('bob@foo.com/Foo', status='hello', @@ -97,19 +127,35 @@ def test(q, bus, conn, stream): # we can now do only audio calls (and as a result have the ImmutableStreams # cap) - event = q.expect('dbus-signal', signal='CapabilitiesChanged', - args=[[(2, cs.CHANNEL_TYPE_STREAMED_MEDIA, 3, 3, - cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO, - cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_IMMUTABLE_STREAMS)]]) - - caps = conn.Contacts.GetContactAttributes([2], [cs.CONN_IFACE_CAPS], False) - assert caps.keys() == [2L] - assert icaps_attr in caps[2L] - assert len(caps[2L][icaps_attr]) == 2 - assert basic_caps[0] in caps[2L][icaps_attr] - assert (2, cs.CHANNEL_TYPE_STREAMED_MEDIA, 3, + old, new = q.expect_many( + EventPattern('dbus-signal', signal='CapabilitiesChanged', + args=[[(bob, cs.CHANNEL_TYPE_STREAMED_MEDIA, 3, 3, + cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO, + cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_IMMUTABLE_STREAMS)]]), + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), + ) + assert_rccs_callable(new.args[0][bob]) + assert_rccs_not_callable(new.args[0][bob], require_audio=False, + require_video=True, mutable_contents=False) + + caps = conn.Contacts.GetContactAttributes([bob], [cs.CONN_IFACE_CAPS], False) + assert caps.keys() == [bob] + assert icaps_attr in caps[bob] + assert len(caps[bob][icaps_attr]) == 2 + assert basic_caps[0] in caps[bob][icaps_attr] + assert (bob, cs.CHANNEL_TYPE_STREAMED_MEDIA, 3, cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_IMMUTABLE_STREAMS) \ - in caps[2L][icaps_attr] + in caps[bob][icaps_attr] + + assertEquals( + { bob: { + cs.ATTR_CONTACT_CAPABILITIES: + new.args[0][bob], + cs.CONN + '/contact-id': 'bob@foo.com', + }, + }, + conn.Contacts.GetContactAttributes([bob], + [cs.CONN_IFACE_CONTACT_CAPS], True)) # go offline presence = make_presence('bob@foo.com/Foo', type='unavailable') @@ -118,21 +164,34 @@ def test(q, bus, conn, stream): # can't do audio calls any more q.expect_many( EventPattern('dbus-signal', signal='CapabilitiesChanged', - args=[[(2, cs.CHANNEL_TYPE_STREAMED_MEDIA, 3, 0, + args=[[(bob, cs.CHANNEL_TYPE_STREAMED_MEDIA, 3, 0, cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_IMMUTABLE_STREAMS, 0)]], ), EventPattern('dbus-signal', signal='PresencesChanged', - args=[{2: (cs.PRESENCE_OFFLINE, 'offline', '')}]), + args=[{bob: (cs.PRESENCE_OFFLINE, 'offline', '')}]), + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), ) # Contact went offline. Previously, this test asserted that the handle # became invalid, but that's not guaranteed to happen immediately; so we # now hold the handle (above), to guarantee that it does *not* become # invalid. + rccs = conn.ContactCapabilities.GetContactCapabilities([bob])[bob] + for rcc in rccs: + assertEquals(cs.CHANNEL_TYPE_TEXT, rcc[0].get(cs.CHANNEL_TYPE)) + + assertEquals( + { bob: { + cs.ATTR_CONTACT_CAPABILITIES: rccs, + cs.CONN + '/contact-id': 'bob@foo.com', + }, + }, + conn.Contacts.GetContactAttributes([bob], + [cs.CONN_IFACE_CONTACT_CAPS], True)) assert conn.Contacts.GetContactAttributes( - [2], [cs.CONN_IFACE_CAPS], False) == \ - { 2L: { icaps_attr: basic_caps, + [bob], [cs.CONN_IFACE_CAPS], False) == \ + { bob: { icaps_attr: basic_caps, cs.CONN + '/contact-id': 'bob@foo.com'}} # What about a handle that's not valid? diff --git a/tests/twisted/caps/trust-thyself.py b/tests/twisted/caps/trust-thyself.py index 34a145b..fda08ec 100644 --- a/tests/twisted/caps/trust-thyself.py +++ b/tests/twisted/caps/trust-thyself.py @@ -49,12 +49,25 @@ def test(q, bus, conn, stream): stream.send(p) sync_stream(q, stream) - # Advertise some different capabilities, to change our own caps hash. - add = [(cs.CHANNEL_TYPE_STREAMED_MEDIA, 2L**32-1), - (cs.CHANNEL_TYPE_STREAM_TUBE, 2L**32-1), - (cs.CHANNEL_TYPE_STREAM_TUBE, 2L**32-1)] - remove = [] - caps = conn.Capabilities.AdvertiseCapabilities(add, remove) + conn.ContactCapabilities.UpdateCapabilities([ + (cs.CLIENT + '.AbiWord', [ + { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE, + cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, + cs.STREAM_TUBE_SERVICE: 'x-abiword' }, + { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE, + cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, + cs.STREAM_TUBE_SERVICE: 'x-abiword' }, + ], []), + (cs.CLIENT + '.KCall', [ + { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL }, + { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL, cs.CALL_INITIAL_AUDIO: True}, + { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL, cs.CALL_INITIAL_VIDEO: True}, + ], [ + cs.CHANNEL_TYPE_CALL + '/gtalk-p2p', + cs.CHANNEL_TYPE_CALL + '/ice-udp', + cs.CHANNEL_TYPE_CALL + '/video/h264', + ]), + ]) self_presence = q.expect('stream-presence') c_ = xpath.queryForNodes('/presence/c', self_presence.stanza)[0] diff --git a/tests/twisted/caps_helper.py b/tests/twisted/caps_helper.py index 11b05d9..f096038 100644 --- a/tests/twisted/caps_helper.py +++ b/tests/twisted/caps_helper.py @@ -329,6 +329,9 @@ def send_presence(q, conn, stream, contact, caps, initial=True, show=None): assertEquals([(h, cs.CHANNEL_TYPE_TEXT, 3, 0)], conn.Capabilities.GetCapabilities([h])) + for rcc in conn.ContactCapabilities.GetContactCapabilities([h])[h]: + assertEquals(cs.CHANNEL_TYPE_TEXT, rcc[0].get(cs.CHANNEL_TYPE)) + # send updated presence with caps info stream.send(make_presence(contact, show=show, status='hello', caps=caps)) @@ -345,6 +348,73 @@ def send_disco_reply(stream, stanza, identities, features, dataforms={}): stream.send( make_caps_disco_reply(stream, stanza, identities, features, dataforms)) +def assert_rccs_callable(rccs, **kwargs): + assert check_rccs_callable(rccs, **kwargs), rccs + +def assert_rccs_not_callable(rccs, **kwargs): + assert not check_rccs_callable(rccs, **kwargs), rccs + +def check_rccs_callable(rccs, + require_audio=True, + require_video=False, + mutable_contents=None): + """rccs: a list of RequestableChannelClass tuples""" + + audio_callable = False + video_callable = False + av_callable = False + + for rcc in rccs: + fixed, allowed = rcc + + if fixed.get(cs.CHANNEL_TYPE) != cs.CHANNEL_TYPE_CALL: + continue + + if fixed.get(cs.TARGET_HANDLE_TYPE) != cs.HT_CONTACT: + continue + + if len(fixed) > (int(cs.CHANNEL_TYPE in fixed) + + int(cs.TARGET_HANDLE_TYPE in fixed) + + int(cs.CALL_INITIAL_AUDIO in fixed) + + int(cs.CALL_INITIAL_VIDEO in fixed)): + continue + + assert fixed.get(cs.CALL_INITIAL_AUDIO) in (True, None) + assert fixed.get(cs.CALL_INITIAL_VIDEO) in (True, None) + + if mutable_contents is not None: + if mutable_contents: + assertContains(cs.CALL_MUTABLE_CONTENTS, allowed) + else: + assertDoesNotContain(cs.CALL_MUTABLE_CONTENTS, allowed) + + if (fixed.get(cs.CALL_INITIAL_AUDIO) == True or + cs.CALL_INITIAL_AUDIO in allowed): + audio_callable = True + assertContains(cs.CALL_INITIAL_AUDIO_NAME, allowed) + + if (fixed.get(cs.CALL_INITIAL_VIDEO) == True or + cs.CALL_INITIAL_VIDEO in allowed): + video_callable = True + assertContains(cs.CALL_INITIAL_VIDEO_NAME, allowed) + + if ((fixed.get(cs.CALL_INITIAL_AUDIO) == True or + cs.CALL_INITIAL_AUDIO in allowed) and + (fixed.get(cs.CALL_INITIAL_VIDEO) == True or + cs.CALL_INITIAL_VIDEO in allowed)): + av_callable = True + + if require_audio and not audio_callable: + return False + + if require_video and not video_callable: + return False + + if require_audio and require_video and not av_callable: + return False + + return True + if __name__ == '__main__': # example from XEP-0115 assertEquals('QgayPKawpkPSDYmwT/WM94uAlu0=', -- 1.8.4.rc3