def receive_caps(q, conn, stream, contact, contact_handle, features, expected_caps, expect_disco=True, expect_ccc=True): caps = {'node': client, 'ver': compute_caps_hash([], features, {}), 'hash': 'sha-1'} presence_and_disco(q, conn, stream, contact, expect_disco, client, caps, features, initial=False) if expect_ccc: event = q.expect('dbus-signal', signal='ContactCapabilitiesChanged') announced_ccs, = event.args assertSameElements(expected_caps, announced_ccs[contact_handle]) else: # Make sure Gabble's got the caps sync_stream(q, stream) caps = get_contacts_capabilities_sync(conn, [contact_handle]) assertSameElements(expected_caps, caps[contact_handle]) # test again, to check GetContactCapabilities does not have side effect caps = get_contacts_capabilities_sync(conn, [contact_handle]) assertSameElements(expected_caps, caps[contact_handle]) # check the Contacts interface give the same caps caps_via_contacts_iface = conn.Contacts.GetContactAttributes( [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [contact_handle][cs.ATTR_CONTACT_CAPABILITIES] assertSameElements(caps[contact_handle], caps_via_contacts_iface)
def wait_for_ft_caps(self): caps = get_contacts_capabilities_sync(self.conn, [self.handle]) if caps != dbus.Dictionary({self.handle:generic_ft_caps}): self.q.expect('dbus-signal', signal='ContactCapabilitiesChanged', path=self.conn.object.object_path, args=[{self.handle:generic_ft_caps}]) caps = get_contacts_capabilities_sync(self.conn, [self.handle]) assert caps == dbus.Dictionary({self.handle:generic_ft_caps}), caps
def wait_for_ft_caps(self): caps = get_contacts_capabilities_sync(self.conn, [self.handle]) if caps != dbus.Dictionary({self.handle:generic_ft_caps}): self.q.expect('dbus-signal', signal='ContactCapabilitiesChanged', path=self.conn.object.object_path, args=[{self.handle:generic_ft_caps}]) caps = get_contacts_capabilities_sync(self.conn, [self.handle]) assert caps == dbus.Dictionary({self.handle:generic_ft_caps}), caps
def receive_caps(q, conn, stream, contact, contact_handle, features, expected_caps, expect_disco=True, expect_ccc=True): presence = make_presence(contact, status='hello') c = presence.addElement((ns.CAPS, 'c')) c['node'] = client c['ver'] = compute_caps_hash([], features if features is not None else [], {}) c['hash'] = 'sha-1' stream.send(presence) if expect_disco: # Gabble looks up our capabilities event = q.expect('stream-iq', to=contact, query_ns=ns.DISCO_INFO) query_node = xpath.queryForNodes('/iq/query', event.stanza)[0] assert query_node.attributes['node'] == \ client + '#' + c['ver'] # send good reply result = make_result_iq(stream, event.stanza) query = result.firstChildElement() query['node'] = client + '#' + c['ver'] for f in features: feature = query.addElement('feature') feature['var'] = f stream.send(result) if expect_ccc: event = q.expect('dbus-signal', signal='ContactCapabilitiesChanged') announced_ccs, = event.args assertSameElements(expected_caps, announced_ccs) else: # Make sure Gabble's got the caps sync_stream(q, stream) caps = get_contacts_capabilities_sync(conn, [contact_handle]) assertSameElements(expected_caps, caps) # test again, to check GetContactCapabilities does not have side effect caps = get_contacts_capabilities_sync(conn, [contact_handle]) assertSameElements(expected_caps, caps) # check the Contacts interface give the same caps caps_via_contacts_iface = conn.Contacts.GetContactAttributes( [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [contact_handle][cs.ATTR_CONTACT_CAPABILITIES] assertSameElements(caps[contact_handle], caps_via_contacts_iface)
def receive_caps(q, conn, stream, contact, contact_handle, features, expected_caps, expect_disco=True, expect_ccc=True): presence = make_presence(contact, status='hello') c = presence.addElement((ns.CAPS, 'c')) c['node'] = client c['ver'] = compute_caps_hash([], features if features is not None else [], {}) c['hash'] = 'sha-1' stream.send(presence) if expect_disco: # Gabble looks up our capabilities event = q.expect('stream-iq', to=contact, query_ns=ns.DISCO_INFO) query_node = xpath.queryForNodes('/iq/query', event.stanza)[0] assert query_node.attributes['node'] == \ client + '#' + c['ver'] # send good reply result = make_result_iq(stream, event.stanza) query = result.firstChildElement() query['node'] = client + '#' + c['ver'] for f in features: feature = query.addElement('feature') feature['var'] = f stream.send(result) if expect_ccc: event = q.expect('dbus-signal', signal='ContactCapabilitiesChanged') announced_ccs, = event.args assertSameElements(expected_caps, announced_ccs) else: # Make sure Gabble's got the caps sync_stream(q, stream) caps = get_contacts_capabilities_sync(conn, [contact_handle]) assertSameElements(expected_caps, caps) # test again, to check GetContactCapabilities does not have side effect caps = get_contacts_capabilities_sync(conn, [contact_handle]) assertSameElements(expected_caps, caps) # check the Contacts interface give the same caps caps_via_contacts_iface = conn.Contacts.GetContactAttributes( [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [contact_handle][cs.ATTR_CONTACT_CAPABILITIES] assertSameElements(caps[contact_handle], caps_via_contacts_iface)
def advertise_caps(q, conn, stream, filters, expected_features, unexpected_features, expected_caps): self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") ret_caps = conn.ContactCapabilities.UpdateCapabilities([ (cs.CLIENT + '.Foo', filters, []) ]) # Expect Gabble to reply with the correct caps event, namespaces, _, signaled_caps = receive_presence_and_ask_caps( q, stream) assertSameElements(expected_caps, signaled_caps) assertContains(ns.TUBES, namespaces) for var in expected_features: assertContains(var, namespaces) for var in unexpected_features: assertDoesNotContain(var, namespaces) # Check our own caps caps = get_contacts_capabilities_sync(conn, [self_handle]) assertSameElements(expected_caps, caps) # check the Contacts interface give the same caps caps_via_contacts_iface = conn.Contacts.GetContactAttributes( [self_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [self_handle][cs.ATTR_CONTACT_CAPABILITIES] assertSameElements(caps[self_handle], caps_via_contacts_iface)
def test_caps(q, conn, stream, contact, features, audio, video, google=False): caps['ver'] = compute_caps_hash([], features, {}) h = presence_and_disco(q, conn, stream, contact, True, client, caps, features) cflags = 0 call_expected_media_caps = [] if audio: cflags |= cs.MEDIA_CAP_AUDIO call_expected_media_caps.append(cs.CALL_INITIAL_AUDIO) call_expected_media_caps.append(cs.CALL_INITIAL_AUDIO_NAME) if video: cflags |= cs.MEDIA_CAP_VIDEO call_expected_media_caps.append(cs.CALL_INITIAL_VIDEO) call_expected_media_caps.append(cs.CALL_INITIAL_VIDEO_NAME) # If the contact can only do one of audio or video, or uses a Google # client, they'll have the ImmutableStreams cap. if cflags < (cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO) or google: cflags |= cs.MEDIA_CAP_IMMUTABLE_STREAMS else: call_expected_media_caps.append(cs.CALL_MUTABLE_CONTENTS) event, = q.expect_many( EventPattern('dbus-signal', signal='ContactCapabilitiesChanged')) # Check Contact capabilities assertEquals(len(event.args), 1) assertEquals(event.args[0], get_contacts_capabilities_sync(conn, [h])) check_contact_caps(event.args[0][h], cs.CHANNEL_TYPE_CALL, call_expected_media_caps)
def advertise_caps(q, bus, conn, stream, filters, expected_features, unexpected_features, expected_caps): # make sure nothing from a previous update is still running sync_dbus(bus, q, conn) self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") ret_caps = conn.ContactCapabilities.UpdateCapabilities( [(cs.CLIENT + '.Foo', filters, [])]) # Expect Gabble to reply with the correct caps event, namespaces, _, signaled_caps = receive_presence_and_ask_caps(q, stream) assertSameElements(expected_caps, signaled_caps[self_handle]) assertContains(ns.TP_FT_METADATA, namespaces) for var in expected_features: assertContains(var, namespaces) for var in unexpected_features: assertDoesNotContain(var, namespaces) # Check our own caps caps = get_contacts_capabilities_sync(conn, [self_handle]) assertSameElements(expected_caps, caps[self_handle]) # check the Contacts interface give the same caps caps_via_contacts_iface = conn.Contacts.GetContactAttributes( [self_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [self_handle][cs.ATTR_CONTACT_CAPABILITIES] assertSameElements(caps[self_handle], caps_via_contacts_iface)
def receive_caps(q, conn, stream, contact, contact_handle, features, expected_caps, expect_disco=True, expect_ccc=True): caps = { 'node': client, 'ver': compute_caps_hash([], features, {}), 'hash': 'sha-1' } presence_and_disco(q, conn, stream, contact, expect_disco, client, caps, features, initial=False) if expect_ccc: event = q.expect('dbus-signal', signal='ContactCapabilitiesChanged') announced_ccs, = event.args assertSameElements(expected_caps, announced_ccs[contact_handle]) else: # Make sure Gabble's got the caps sync_stream(q, stream) caps = get_contacts_capabilities_sync(conn, [contact_handle]) assertSameElements(expected_caps, caps[contact_handle]) # test again, to check GetContactCapabilities does not have side effect caps = get_contacts_capabilities_sync(conn, [contact_handle]) assertSameElements(expected_caps, caps[contact_handle]) # check the Contacts interface give the same caps caps_via_contacts_iface = conn.Contacts.GetContactAttributes( [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [contact_handle][cs.ATTR_CONTACT_CAPABILITIES] assertSameElements(caps[contact_handle], caps_via_contacts_iface)
def test_ft_caps_from_contact(q, bus, conn, stream, contact): contact_handle = conn.get_contact_handle_sync(contact) # Check that we don't crash if we haven't seen any caps/presence for this # contact yet. caps = get_contacts_capabilities_sync(conn, [contact_handle]) basic_caps = [(text_fixed_properties, text_allowed_properties)] # Since we don't know their caps, they should be omitted from the dict, # rather than present with no caps, but all contacts have text chat caps. assertEquals(basic_caps, caps[contact_handle]) # send presence with no FT cap # We don't expect ContactCapabilitiesChanged to be emitted here: we always # assume people can do text channels. receive_caps(q, conn, stream, contact, contact_handle, [], basic_caps, expect_ccc=False) # send presence with no mention of metadata no_metadata_ft_caps = [ (text_fixed_properties, text_allowed_properties), (ft_fixed_properties, ft_allowed_properties) ] receive_caps(q, conn, stream, contact, contact_handle, [ns.FILE_TRANSFER], no_metadata_ft_caps) # send presence with generic FT caps including metadata from now on generic_ft_caps = [ (text_fixed_properties, text_allowed_properties), (ft_fixed_properties, ft_allowed_properties_with_metadata) ] generic_ft_features = [ns.FILE_TRANSFER, ns.TP_FT_METADATA] receive_caps(q, conn, stream, contact, contact_handle, generic_ft_features, generic_ft_caps) # send presence with 1 FT cap with a service daap_caps = generic_ft_caps + [ (bidir_daap_fixed_properties, ft_allowed_properties + [cs.FT_METADATA])] receive_caps(q, conn, stream, contact, contact_handle, generic_ft_features + [ns.TP_FT_METADATA + '#daap'], daap_caps) # send presence with 2 FT caps daap_xiangqi_caps = daap_caps + [ (xiangqi_fixed_properties, ft_allowed_properties + [cs.FT_METADATA])] receive_caps(q, conn, stream, contact, contact_handle, generic_ft_features + [ns.TP_FT_METADATA + '#com.example.Xiangqi', ns.TP_FT_METADATA + '#daap', ], daap_xiangqi_caps) # send presence with 1 FT cap again # Gabble does not look up our capabilities because of the cache receive_caps(q, conn, stream, contact, contact_handle, generic_ft_features + [ns.TP_FT_METADATA + '#daap'], daap_caps, expect_disco=False)
def check_contact_caps(conn, handle, with_ft): conn_contacts_iface = dbus.Interface(conn, cs.CONN_IFACE_CONTACTS) if with_ft: expected_caps = dbus.Dictionary({handle: generic_ft_caps}) else: expected_caps = dbus.Dictionary({handle: generic_caps}) caps = get_contacts_capabilities_sync(conn, [handle]) assert caps == expected_caps, caps # check the Contacts interface give the same caps caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes( [handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [handle][cs.ATTR_CONTACT_CAPABILITIES] assert caps_via_contacts_iface == caps[handle], \ caps_via_contacts_iface
def check_contact_caps(conn, handle, with_ft): conn_contacts_iface = dbus.Interface(conn, cs.CONN_IFACE_CONTACTS) if with_ft: expected_caps = dbus.Dictionary({handle: generic_ft_caps}) else: expected_caps = dbus.Dictionary({handle: generic_caps}) caps = get_contacts_capabilities_sync(conn, [handle]) assert caps == expected_caps, caps # check the Contacts interface give the same caps caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes( [handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [handle][cs.ATTR_CONTACT_CAPABILITIES] assert caps_via_contacts_iface == caps[handle], \ caps_via_contacts_iface
def test(q, bus, conn, stream): conn.Connect() # bob is offline jid = '*****@*****.**' event = q.expect('stream-iq', query_ns=ns.ROSTER) event.stanza['type'] = 'result' item = event.query.addElement('item') item['jid'] = jid item['subscription'] = 'from' stream.send(event.stanza) q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]), bob_handle = conn.get_contact_handle_sync(jid) # new ContactCapabilities ccaps_map = get_contacts_capabilities_sync(conn, [bob_handle]) assertLength(1, ccaps_map) assertLength(1, ccaps_map[bob_handle]) fixed, allowed = ccaps_map[bob_handle][0] assertEquals( { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT }, fixed) assertSameSets([cs.TARGET_HANDLE], allowed)
def test_caps(q, conn, stream, contact, features, audio, video, google=False): caps['ver'] = compute_caps_hash ([], features, {}) h = presence_and_disco(q, conn, stream, contact, True, client, caps, features) cflags = 0 call_expected_media_caps = [] if audio: cflags |= cs.MEDIA_CAP_AUDIO call_expected_media_caps.append (cs.CALL_INITIAL_AUDIO) call_expected_media_caps.append (cs.CALL_INITIAL_AUDIO_NAME) if video: cflags |= cs.MEDIA_CAP_VIDEO call_expected_media_caps.append (cs.CALL_INITIAL_VIDEO) call_expected_media_caps.append (cs.CALL_INITIAL_VIDEO_NAME) # If the contact can only do one of audio or video, or uses a Google # client, they'll have the ImmutableStreams cap. if cflags < (cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO) or google: cflags |= cs.MEDIA_CAP_IMMUTABLE_STREAMS else: call_expected_media_caps.append(cs.CALL_MUTABLE_CONTENTS) event, = q.expect_many( EventPattern('dbus-signal', signal='ContactCapabilitiesChanged') ) # Check Contact capabilities assertEquals(len(event.args), 1) assertEquals (event.args[0], get_contacts_capabilities_sync(conn, [h])) check_contact_caps (event.args[0][h], cs.CHANNEL_TYPE_CALL, call_expected_media_caps)
def test_ft_caps_to_contact(q, bus, conn, stream): self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") basic_caps = [ (text_fixed_properties, text_allowed_properties), (stream_tube_fixed_properties, stream_tube_allowed_properties), (dbus_tube_fixed_properties, dbus_tube_allowed_properties), ] simple_ft_caps = basic_caps + [ (ft_fixed_properties, ft_allowed_properties_with_metadata), ] daap_caps = simple_ft_caps + [ (bidir_daap_fixed_properties, ft_allowed_properties + [cs.FT_METADATA]), ] xiangqi_caps = simple_ft_caps + [ (xiangqi_fixed_properties, ft_allowed_properties + [cs.FT_METADATA]), ] xiangqi_go_caps = xiangqi_caps + [ (go_fixed_properties, ft_allowed_properties + [cs.FT_METADATA]), ] go_caps = simple_ft_caps + [ (go_fixed_properties, ft_allowed_properties + [cs.FT_METADATA]), ] # # Check our own caps; we should have no FT caps # caps = get_contacts_capabilities_sync(conn, [self_handle]) assertEquals(basic_caps, caps[self_handle]) # check the Contacts interface give the same caps caps_via_contacts_iface = conn.Contacts.GetContactAttributes( [self_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [self_handle][cs.ATTR_CONTACT_CAPABILITIES] assertEquals(caps[self_handle], caps_via_contacts_iface) # # Advertise nothing # conn.ContactCapabilities.UpdateCapabilities( [(cs.CLIENT + '.Foo', {}, [])]) # Check our own caps caps = get_contacts_capabilities_sync(conn, [self_handle]) assertLength(1, caps) assertEquals(basic_caps, caps[self_handle]) # check the Contacts interface give the same caps caps_via_contacts_iface = conn.Contacts.GetContactAttributes( [self_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [self_handle][cs.ATTR_CONTACT_CAPABILITIES] assertEquals(caps[self_handle], caps_via_contacts_iface) sync_stream(q, stream) # # Advertise FT but with no service name # conn.ContactCapabilities.UpdateCapabilities( [(cs.CLIENT + '.Foo', [no_service_fixed_properties], [])]) # Check our own caps caps = get_contacts_capabilities_sync(conn, [self_handle]) assertLength(1, caps) assertEquals(simple_ft_caps, caps[self_handle]) # check the Contacts interface give the same caps caps_via_contacts_iface = conn.Contacts.GetContactAttributes( [self_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [self_handle][cs.ATTR_CONTACT_CAPABILITIES] assertEquals(caps[self_handle], caps_via_contacts_iface) sync_stream(q, stream) # # Advertise a Requested=True FT cap # conn.ContactCapabilities.UpdateCapabilities( [(cs.CLIENT + '.Foo', [outgoing_daap_fixed_properties], [])]) # Check our own caps caps = get_contacts_capabilities_sync(conn, [self_handle]) assertLength(1, caps) assertEquals(simple_ft_caps, caps[self_handle]) # check the Contacts interface give the same caps caps_via_contacts_iface = conn.Contacts.GetContactAttributes( [self_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [self_handle][cs.ATTR_CONTACT_CAPABILITIES] assertEquals(caps[self_handle], caps_via_contacts_iface) advertise_caps(q, bus, conn, stream, [bidir_daap_fixed_properties], [ns.TP_FT_METADATA + '#daap'], [ns.TP_FT_METADATA + '#http', ns.TP_FT_METADATA + '#com.example.Go', ns.TP_FT_METADATA + '#com.example.Xiangqi', ], daap_caps) advertise_caps(q, bus, conn, stream, [xiangqi_fixed_properties, no_service_fixed_properties], [ns.TP_FT_METADATA + '#com.example.Xiangqi'], [ns.TP_FT_METADATA + '#daap', ns.TP_FT_METADATA + '#http', ns.TP_FT_METADATA + '#com.example.Go', ], xiangqi_caps) advertise_caps(q, bus, conn, stream, [xiangqi_fixed_properties, go_fixed_properties], [ns.TP_FT_METADATA + '#com.example.Xiangqi', ns.TP_FT_METADATA + '#com.example.Go', ], [ns.TP_FT_METADATA + '#http', ns.TP_FT_METADATA + '#daap', ], xiangqi_go_caps) advertise_caps(q, bus, conn, stream, [go_fixed_properties], [ns.TP_FT_METADATA + '#com.example.Go', ], [ns.TP_FT_METADATA + '#http', ns.TP_FT_METADATA + '#daap', ns.TP_FT_METADATA + '#com.example.Xiangqi', ], go_caps)
def test_ft_caps_to_contact(q, bus, conn, stream): self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") basic_caps = [ (text_fixed_properties, text_allowed_properties), (stream_tube_fixed_properties, stream_tube_allowed_properties), (dbus_tube_fixed_properties, dbus_tube_allowed_properties), ] simple_ft_caps = basic_caps + [ (ft_fixed_properties, ft_allowed_properties_with_metadata), ] daap_caps = simple_ft_caps + [ (bidir_daap_fixed_properties, ft_allowed_properties + [cs.FT_METADATA]), ] xiangqi_caps = simple_ft_caps + [ (xiangqi_fixed_properties, ft_allowed_properties + [cs.FT_METADATA]), ] xiangqi_go_caps = xiangqi_caps + [ (go_fixed_properties, ft_allowed_properties + [cs.FT_METADATA]), ] go_caps = simple_ft_caps + [ (go_fixed_properties, ft_allowed_properties + [cs.FT_METADATA]), ] # # Check our own caps; we should have no FT caps # caps = get_contacts_capabilities_sync(conn, [self_handle]) assertEquals(basic_caps, caps[self_handle]) # check the Contacts interface give the same caps caps_via_contacts_iface = conn.Contacts.GetContactAttributes( [self_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [self_handle][cs.ATTR_CONTACT_CAPABILITIES] assertEquals(caps[self_handle], caps_via_contacts_iface) # # Advertise nothing # conn.ContactCapabilities.UpdateCapabilities([(cs.CLIENT + '.Foo', {}, [])]) # Check our own caps caps = get_contacts_capabilities_sync(conn, [self_handle]) assertLength(1, caps) assertEquals(basic_caps, caps[self_handle]) # check the Contacts interface give the same caps caps_via_contacts_iface = conn.Contacts.GetContactAttributes( [self_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [self_handle][cs.ATTR_CONTACT_CAPABILITIES] assertEquals(caps[self_handle], caps_via_contacts_iface) sync_stream(q, stream) # # Advertise FT but with no service name # conn.ContactCapabilities.UpdateCapabilities([ (cs.CLIENT + '.Foo', [no_service_fixed_properties], []) ]) # Check our own caps caps = get_contacts_capabilities_sync(conn, [self_handle]) assertLength(1, caps) assertEquals(simple_ft_caps, caps[self_handle]) # check the Contacts interface give the same caps caps_via_contacts_iface = conn.Contacts.GetContactAttributes( [self_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [self_handle][cs.ATTR_CONTACT_CAPABILITIES] assertEquals(caps[self_handle], caps_via_contacts_iface) sync_stream(q, stream) # # Advertise a Requested=True FT cap # conn.ContactCapabilities.UpdateCapabilities([ (cs.CLIENT + '.Foo', [outgoing_daap_fixed_properties], []) ]) # Check our own caps caps = get_contacts_capabilities_sync(conn, [self_handle]) assertLength(1, caps) assertEquals(simple_ft_caps, caps[self_handle]) # check the Contacts interface give the same caps caps_via_contacts_iface = conn.Contacts.GetContactAttributes( [self_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [self_handle][cs.ATTR_CONTACT_CAPABILITIES] assertEquals(caps[self_handle], caps_via_contacts_iface) advertise_caps(q, bus, conn, stream, [bidir_daap_fixed_properties], [ns.TP_FT_METADATA + '#daap'], [ ns.TP_FT_METADATA + '#http', ns.TP_FT_METADATA + '#com.example.Go', ns.TP_FT_METADATA + '#com.example.Xiangqi', ], daap_caps) advertise_caps(q, bus, conn, stream, [xiangqi_fixed_properties, no_service_fixed_properties], [ns.TP_FT_METADATA + '#com.example.Xiangqi'], [ ns.TP_FT_METADATA + '#daap', ns.TP_FT_METADATA + '#http', ns.TP_FT_METADATA + '#com.example.Go', ], xiangqi_caps) advertise_caps(q, bus, conn, stream, [xiangqi_fixed_properties, go_fixed_properties], [ ns.TP_FT_METADATA + '#com.example.Xiangqi', ns.TP_FT_METADATA + '#com.example.Go', ], [ ns.TP_FT_METADATA + '#http', ns.TP_FT_METADATA + '#daap', ], xiangqi_go_caps) advertise_caps(q, bus, conn, stream, [go_fixed_properties], [ ns.TP_FT_METADATA + '#com.example.Go', ], [ ns.TP_FT_METADATA + '#http', ns.TP_FT_METADATA + '#daap', ns.TP_FT_METADATA + '#com.example.Xiangqi', ], go_caps)
def test_tube_caps_from_contact(q, bus, conn, stream, contact): contact_handle = conn.get_contact_handle_sync(contact) # Check that we don't crash if we haven't seen any caps/presence for this # contact yet. caps = get_contacts_capabilities_sync(conn, [contact_handle]) basic_caps = dbus.Dictionary( {contact_handle: [(text_fixed_properties, text_allowed_properties)]}) # Since we don't know their caps, they should be omitted from the dict, # rather than present with no caps, but all contacts have text chat caps. assertEquals(basic_caps, caps) # send presence with no tube cap # We don't expect ContactCapabilitiesChanged to be emitted here: we always # assume people can do text channels. receive_caps(q, conn, stream, contact, contact_handle, [], basic_caps, expect_ccc=False) # send presence with generic tubes caps generic_tubes_caps = dbus.Dictionary({ contact_handle: [(text_fixed_properties, text_allowed_properties), (stream_tube_fixed_properties, stream_tube_allowed_properties), (dbus_tube_fixed_properties, dbus_tube_allowed_properties)] }) receive_caps(q, conn, stream, contact, contact_handle, [ns.TUBES], generic_tubes_caps) # send presence with 1 stream tube cap daap_caps = dbus.Dictionary({ contact_handle: [(text_fixed_properties, text_allowed_properties), (stream_tube_fixed_properties, stream_tube_allowed_properties), (dbus_tube_fixed_properties, dbus_tube_allowed_properties), (incoming_daap_fixed_properties, specialized_tube_allowed_properties)] }) receive_caps(q, conn, stream, contact, contact_handle, [ns.TUBES + '/stream#daap'], daap_caps) # send presence with 1 D-Bus tube cap xiangqi_caps = dbus.Dictionary({ contact_handle: [(text_fixed_properties, text_allowed_properties), (stream_tube_fixed_properties, stream_tube_allowed_properties), (dbus_tube_fixed_properties, dbus_tube_allowed_properties), (xiangqi_fixed_properties, specialized_tube_allowed_properties)] }) receive_caps(q, conn, stream, contact, contact_handle, [ns.TUBES + '/dbus#com.example.Xiangqi'], xiangqi_caps) # send presence with both D-Bus and stream tube caps daap_xiangqi_caps = dbus.Dictionary({ contact_handle: [(text_fixed_properties, text_allowed_properties), (stream_tube_fixed_properties, stream_tube_allowed_properties), (dbus_tube_fixed_properties, dbus_tube_allowed_properties), (incoming_daap_fixed_properties, specialized_tube_allowed_properties), (xiangqi_fixed_properties, specialized_tube_allowed_properties)] }) receive_caps(q, conn, stream, contact, contact_handle, [ ns.TUBES + '/dbus#com.example.Xiangqi', ns.TUBES + '/stream#daap', ], daap_xiangqi_caps) # send presence with 4 tube caps all_tubes_caps = dbus.Dictionary({ contact_handle: [(text_fixed_properties, text_allowed_properties), (stream_tube_fixed_properties, stream_tube_allowed_properties), (dbus_tube_fixed_properties, dbus_tube_allowed_properties), (incoming_daap_fixed_properties, specialized_tube_allowed_properties), (http_fixed_properties, specialized_tube_allowed_properties), (xiangqi_fixed_properties, specialized_tube_allowed_properties), (go_fixed_properties, specialized_tube_allowed_properties)] }) receive_caps(q, conn, stream, contact, contact_handle, [ ns.TUBES + '/dbus#com.example.Xiangqi', ns.TUBES + '/dbus#com.example.Go', ns.TUBES + '/stream#daap', ns.TUBES + '/stream#http', ], all_tubes_caps) # send presence with both D-Bus and stream tube caps # Gabble does not look up our capabilities because of the cache receive_caps(q, conn, stream, contact, contact_handle, [ ns.TUBES + '/dbus#com.example.Xiangqi', ns.TUBES + '/stream#daap', ], daap_xiangqi_caps, expect_disco=False)
def test(q, bus, conn, stream): bob = conn.get_contact_handle_sync('*****@*****.**') presence = make_presence('[email protected]/Foo', status='hello') stream.send(presence) q.expect('dbus-signal', signal='PresencesChanged', args=[{bob: (cs.PRESENCE_AVAILABLE, u'available', 'hello')}]) basic_caps = [(bob, cs.CHANNEL_TYPE_TEXT, 3, 0)] # only Text for rcc in get_contacts_capabilities_sync(conn, [bob])[bob]: assertEquals(cs.CHANNEL_TYPE_TEXT, rcc[0].get(cs.CHANNEL_TYPE)) # holding the handle here: see below assertEquals( { bob: { cs.ATTR_CONTACT_CAPABILITIES: get_contacts_capabilities_sync(conn, [bob])[bob], cs.CONN + '/contact-id': '*****@*****.**', }, }, 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 # discovered before any capabilities change signal is emitted presence = make_presence('[email protected]/Foo', status='hello', caps={ 'node': 'http://telepathy.freedesktop.org/fake-client', 'ver' : '0.1', 'ext' : 'video', }) stream.send(presence) # Gabble looks up both the version and the video bundles, in any order (version_event, video_event) = q.expect_many( EventPattern('stream-iq', to='[email protected]/Foo', query_ns='http://jabber.org/protocol/disco#info', query_node='http://telepathy.freedesktop.org/fake-client#0.1'), EventPattern('stream-iq', to='[email protected]/Foo', query_ns='http://jabber.org/protocol/disco#info', query_node='http://telepathy.freedesktop.org/fake-client#video')) # reply to the video bundle query first - this capability alone is not # sufficient to make us callable result = make_result_iq(stream, video_event.stanza) query = result.firstChildElement() feature = query.addElement('feature') feature['var'] = 'http://jabber.org/protocol/jingle/description/video' stream.send(result) # reply to the version bundle query, which should make us audio and # video callable result = make_result_iq(stream, version_event.stanza) query = result.firstChildElement() feature = query.addElement('feature') feature['var'] = 'http://jabber.org/protocol/jingle' feature = query.addElement('feature') feature['var'] = 'http://jabber.org/protocol/jingle/description/audio' feature = query.addElement('feature') feature['var'] = 'http://www.google.com/transport/p2p' stream.send(result) # we can now do audio and video calls cc, = q.expect_many( EventPattern('dbus-signal', signal='ContactCapabilitiesChanged', predicate=lambda e: check_rccs_callable(e.args[0][bob])), ) assert_rccs_callable(cc.args[0][bob], require_video=True, mutable_contents=True) assertEquals( { bob: { cs.ATTR_CONTACT_CAPABILITIES: cc.args[0][bob], cs.CONN + '/contact-id': '*****@*****.**', }, }, conn.Contacts.GetContactAttributes([bob], [cs.CONN_IFACE_CONTACT_CAPS], True)) # send updated presence without video support presence = make_presence('[email protected]/Foo', status='hello', caps={ 'node': 'http://telepathy.freedesktop.org/fake-client', 'ver' : '0.1', }) stream.send(presence) # we can now do only audio calls (and as a result have the ImmutableStreams # cap) cc, = q.expect_many( EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), ) assert_rccs_callable(cc.args[0][bob]) assert_rccs_not_callable(cc.args[0][bob], require_audio=False, require_video=True, mutable_contents=False) assertEquals( { bob: { cs.ATTR_CONTACT_CAPABILITIES: cc.args[0][bob], cs.CONN + '/contact-id': '*****@*****.**', }, }, conn.Contacts.GetContactAttributes([bob], [cs.CONN_IFACE_CONTACT_CAPS], True)) # go offline presence = make_presence('[email protected]/Foo', type='unavailable') stream.send(presence) # can't do audio calls any more q.expect_many( EventPattern('dbus-signal', signal='PresencesChanged', 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 = get_contacts_capabilities_sync(conn, [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': '*****@*****.**', }, }, conn.Contacts.GetContactAttributes([bob], [cs.CONN_IFACE_CONTACT_CAPS], True)) # What about a handle that's not valid? assertEquals({}, conn.Contacts.GetContactAttributes( [31337], [cs.CONN_IFACE_CONTACT_CAPS], False))
def test_tube_caps_from_contact(q, bus, conn, stream, contact): contact_handle = conn.get_contact_handle_sync(contact) # Check that we don't crash if we haven't seen any caps/presence for this # contact yet. caps = get_contacts_capabilities_sync(conn, [contact_handle]) basic_caps = dbus.Dictionary({contact_handle: [(text_fixed_properties, text_allowed_properties)]}) # Since we don't know their caps, they should be omitted from the dict, # rather than present with no caps, but all contacts have text chat caps. assertEquals(basic_caps, caps) # send presence with no tube cap # We don't expect ContactCapabilitiesChanged to be emitted here: we always # assume people can do text channels. receive_caps(q, conn, stream, contact, contact_handle, [], basic_caps, expect_ccc=False) # send presence with generic tubes caps generic_tubes_caps = dbus.Dictionary({contact_handle: [(text_fixed_properties, text_allowed_properties), (stream_tube_fixed_properties, stream_tube_allowed_properties), (dbus_tube_fixed_properties, dbus_tube_allowed_properties)]}) receive_caps(q, conn, stream, contact, contact_handle, [ns.TUBES], generic_tubes_caps) # send presence with 1 stream tube cap daap_caps = dbus.Dictionary({contact_handle: [(text_fixed_properties, text_allowed_properties), (stream_tube_fixed_properties, stream_tube_allowed_properties), (dbus_tube_fixed_properties, dbus_tube_allowed_properties), (incoming_daap_fixed_properties, specialized_tube_allowed_properties)]}) receive_caps(q, conn, stream, contact, contact_handle, [ns.TUBES + '/stream#daap'], daap_caps) # send presence with 1 D-Bus tube cap xiangqi_caps = dbus.Dictionary({contact_handle: [(text_fixed_properties, text_allowed_properties), (stream_tube_fixed_properties, stream_tube_allowed_properties), (dbus_tube_fixed_properties, dbus_tube_allowed_properties), (xiangqi_fixed_properties, specialized_tube_allowed_properties)]}) receive_caps(q, conn, stream, contact, contact_handle, [ns.TUBES + '/dbus#com.example.Xiangqi'], xiangqi_caps) # send presence with both D-Bus and stream tube caps daap_xiangqi_caps = dbus.Dictionary({contact_handle: [(text_fixed_properties, text_allowed_properties), (stream_tube_fixed_properties, stream_tube_allowed_properties), (dbus_tube_fixed_properties, dbus_tube_allowed_properties), (incoming_daap_fixed_properties, specialized_tube_allowed_properties), (xiangqi_fixed_properties, specialized_tube_allowed_properties)]}) receive_caps(q, conn, stream, contact, contact_handle, [ns.TUBES + '/dbus#com.example.Xiangqi', ns.TUBES + '/stream#daap', ], daap_xiangqi_caps) # send presence with 4 tube caps all_tubes_caps = dbus.Dictionary({contact_handle: [(text_fixed_properties, text_allowed_properties), (stream_tube_fixed_properties, stream_tube_allowed_properties), (dbus_tube_fixed_properties, dbus_tube_allowed_properties), (incoming_daap_fixed_properties, specialized_tube_allowed_properties), (http_fixed_properties, specialized_tube_allowed_properties), (xiangqi_fixed_properties, specialized_tube_allowed_properties), (go_fixed_properties, specialized_tube_allowed_properties)]}) receive_caps(q, conn, stream, contact, contact_handle, [ns.TUBES + '/dbus#com.example.Xiangqi', ns.TUBES + '/dbus#com.example.Go', ns.TUBES + '/stream#daap', ns.TUBES + '/stream#http', ], all_tubes_caps) # send presence with both D-Bus and stream tube caps # Gabble does not look up our capabilities because of the cache receive_caps(q, conn, stream, contact, contact_handle, [ns.TUBES + '/dbus#com.example.Xiangqi', ns.TUBES + '/stream#daap', ], daap_xiangqi_caps, expect_disco=False)
def test_tube_caps_to_contact(q, bus, conn, stream): self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") basic_caps = dbus.Dictionary({ self_handle: [ (text_fixed_properties, text_allowed_properties), (stream_tube_fixed_properties, stream_tube_allowed_properties), (dbus_tube_fixed_properties, dbus_tube_allowed_properties), ] }) daap_caps = dbus.Dictionary({ self_handle: [(text_fixed_properties, text_allowed_properties), (stream_tube_fixed_properties, stream_tube_allowed_properties), (dbus_tube_fixed_properties, dbus_tube_allowed_properties), (incoming_daap_fixed_properties, specialized_tube_allowed_properties), (ft_fixed_properties, ft_allowed_properties)] }) xiangqi_caps = dbus.Dictionary({ self_handle: [(text_fixed_properties, text_allowed_properties), (stream_tube_fixed_properties, stream_tube_allowed_properties), (dbus_tube_fixed_properties, dbus_tube_allowed_properties), (xiangqi_fixed_properties, specialized_tube_allowed_properties), (ft_fixed_properties, ft_allowed_properties)] }) daap_xiangqi_caps = dbus.Dictionary({ self_handle: [(text_fixed_properties, text_allowed_properties), (stream_tube_fixed_properties, stream_tube_allowed_properties), (dbus_tube_fixed_properties, dbus_tube_allowed_properties), (incoming_daap_fixed_properties, specialized_tube_allowed_properties), (xiangqi_fixed_properties, specialized_tube_allowed_properties), (ft_fixed_properties, ft_allowed_properties)] }) all_tubes_caps = dbus.Dictionary({ self_handle: [(text_fixed_properties, text_allowed_properties), (stream_tube_fixed_properties, stream_tube_allowed_properties), (dbus_tube_fixed_properties, dbus_tube_allowed_properties), (incoming_daap_fixed_properties, specialized_tube_allowed_properties), (http_fixed_properties, specialized_tube_allowed_properties), (xiangqi_fixed_properties, specialized_tube_allowed_properties), (go_fixed_properties, specialized_tube_allowed_properties), (ft_fixed_properties, ft_allowed_properties)] }) # Check our own caps caps = get_contacts_capabilities_sync(conn, [self_handle]) assertEquals(basic_caps, caps) # check the Contacts interface give the same caps caps_via_contacts_iface = conn.Contacts.GetContactAttributes( [self_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [self_handle][cs.ATTR_CONTACT_CAPABILITIES] assertEquals(caps[self_handle], caps_via_contacts_iface) # Advertise nothing conn.ContactCapabilities.UpdateCapabilities([(cs.CLIENT + '.Foo', {}, [])]) # Check our own caps caps = get_contacts_capabilities_sync(conn, [self_handle]) assertLength(1, caps) assertEquals(basic_caps, caps) # check the Contacts interface give the same caps caps_via_contacts_iface = conn.Contacts.GetContactAttributes( [self_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [self_handle][cs.ATTR_CONTACT_CAPABILITIES] assertEquals(caps[self_handle], caps_via_contacts_iface) sync_stream(q, stream) # Advertise a Requested=True tube cap conn.ContactCapabilities.UpdateCapabilities([ (cs.CLIENT + '.Foo', [outgoing_daap_fixed_properties], []) ]) # Check our own caps caps = get_contacts_capabilities_sync(conn, [self_handle]) assertLength(1, caps) assertEquals(basic_caps, caps) # check the Contacts interface give the same caps caps_via_contacts_iface = conn.Contacts.GetContactAttributes( [self_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [self_handle][cs.ATTR_CONTACT_CAPABILITIES] assertEquals(caps[self_handle], caps_via_contacts_iface) sync_stream(q, stream) advertise_caps(q, conn, stream, [bidir_daap_fixed_properties], [ns.TUBES + '/stream#daap'], [ ns.TUBES + '/stream#http', ns.TUBES + '/dbus#com.example.Go', ns.TUBES + '/dbus#com.example.Xiangqi', ], daap_caps) advertise_caps(q, conn, stream, [outgoing_daap_fixed_properties, xiangqi_fixed_properties], [ns.TUBES + '/dbus#com.example.Xiangqi'], [ ns.TUBES + '/stream#daap', ns.TUBES + '/stream#http', ns.TUBES + '/dbus#com.example.Go', ], xiangqi_caps) advertise_caps(q, conn, stream, [ incoming_daap_fixed_properties, outgoing_daap_fixed_properties, xiangqi_fixed_properties ], [ ns.TUBES + '/dbus#com.example.Xiangqi', ns.TUBES + '/stream#daap', ], [ ns.TUBES + '/stream#http', ns.TUBES + '/dbus#com.example.Go', ], daap_xiangqi_caps) advertise_caps(q, conn, stream, [ incoming_daap_fixed_properties, http_fixed_properties, go_fixed_properties, xiangqi_fixed_properties ], [ ns.TUBES + '/dbus#com.example.Xiangqi', ns.TUBES + '/stream#daap', ns.TUBES + '/stream#http', ns.TUBES + '/dbus#com.example.Go', ], [], all_tubes_caps) # test daap + xiangqi again for some reason advertise_caps(q, conn, stream, [incoming_daap_fixed_properties, xiangqi_fixed_properties], [ ns.TUBES + '/dbus#com.example.Xiangqi', ns.TUBES + '/stream#daap', ], [ ns.TUBES + '/stream#http', ns.TUBES + '/dbus#com.example.Go', ], daap_xiangqi_caps)
def test_ft_caps_from_contact(q, bus, conn, stream, contact, contact_handle, client): conn_caps_iface = dbus.Interface(conn, cs.CONN_IFACE_CONTACT_CAPS) conn_contacts_iface = dbus.Interface(conn, cs.CONN_IFACE_CONTACTS) # send presence with no FT cap presence = make_presence(contact, status='hello') c = presence.addElement((ns.CAPS, 'c')) c['node'] = client c['ver'] = compute_caps_hash([], [], {}) c['hash'] = 'sha-1' stream.send(presence) # Gabble looks up our capabilities event = q.expect('stream-iq', to=contact, query_ns=ns.DISCO_INFO) query_node = xpath.queryForNodes('/iq/query', event.stanza)[0] assert query_node.attributes['node'] == \ client + '#' + c['ver'] # send good reply result = make_result_iq(stream, event.stanza) query = result.firstChildElement() query['node'] = client + '#' + c['ver'] stream.send(result) # no change in ContactCapabilities, so no signal ContactCapabilitiesChanged sync_stream(q, stream) # no special capabilities basic_caps = dbus.Dictionary({contact_handle: [(text_fixed_properties, text_allowed_properties)]}) caps = get_contacts_capabilities_sync(conn, [contact_handle]) assert caps == basic_caps, caps # test again, to check GetContactCapabilities does not have side effect caps = get_contacts_capabilities_sync(conn, [contact_handle]) assert caps == basic_caps, caps # check the Contacts interface give the same caps caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes( [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [contact_handle][cs.ATTR_CONTACT_CAPABILITIES] assert caps_via_contacts_iface == caps[contact_handle], \ caps_via_contacts_iface # send presence with ft capa presence = make_presence(contact, status='hello') c = presence.addElement((ns.CAPS, 'c')) c['node'] = client c['ver'] = compute_caps_hash([], [ns.FILE_TRANSFER], {}) c['hash'] = 'sha-1' stream.send(presence) # Gabble looks up our capabilities event = q.expect('stream-iq', to=contact, query_ns=ns.DISCO_INFO) query_node = xpath.queryForNodes('/iq/query', event.stanza)[0] assert query_node.attributes['node'] == \ client + '#' + c['ver'] # send good reply result = make_result_iq(stream, event.stanza) query = result.firstChildElement() query['node'] = client + '#' + c['ver'] feature = query.addElement('feature') feature['var'] = ns.FILE_TRANSFER stream.send(result) generic_tubes_caps = dbus.Dictionary({contact_handle: [(text_fixed_properties, text_allowed_properties), (ft_fixed_properties, ft_allowed_properties)]}) event = q.expect('dbus-signal', signal='ContactCapabilitiesChanged') assert len(event.args) == 1 assert event.args[0] == generic_tubes_caps caps = get_contacts_capabilities_sync(conn, [contact_handle]) assert caps == generic_tubes_caps, caps # test again, to check GetContactCapabilities does not have side effect caps = get_contacts_capabilities_sync(conn, [contact_handle]) assert caps == generic_tubes_caps, caps # check the Contacts interface give the same caps caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes( [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [contact_handle][cs.ATTR_CONTACT_CAPABILITIES] assert caps_via_contacts_iface == caps[contact_handle], \ caps_via_contacts_iface
def test_ft_caps_from_contact(q, bus, conn, stream, contact): contact_handle = conn.get_contact_handle_sync(contact) # Check that we don't crash if we haven't seen any caps/presence for this # contact yet. caps = get_contacts_capabilities_sync(conn, [contact_handle]) basic_caps = [(text_fixed_properties, text_allowed_properties)] # Since we don't know their caps, they should be omitted from the dict, # rather than present with no caps, but all contacts have text chat caps. assertEquals(basic_caps, caps[contact_handle]) # send presence with no FT cap # We don't expect ContactCapabilitiesChanged to be emitted here: we always # assume people can do text channels. receive_caps(q, conn, stream, contact, contact_handle, [], basic_caps, expect_ccc=False) # send presence with no mention of metadata no_metadata_ft_caps = [(text_fixed_properties, text_allowed_properties), (ft_fixed_properties, ft_allowed_properties)] receive_caps(q, conn, stream, contact, contact_handle, [ns.FILE_TRANSFER], no_metadata_ft_caps) # send presence with generic FT caps including metadata from now on generic_ft_caps = [(text_fixed_properties, text_allowed_properties), (ft_fixed_properties, ft_allowed_properties_with_metadata)] generic_ft_features = [ns.FILE_TRANSFER, ns.TP_FT_METADATA] receive_caps(q, conn, stream, contact, contact_handle, generic_ft_features, generic_ft_caps) # send presence with 1 FT cap with a service daap_caps = generic_ft_caps + [ (bidir_daap_fixed_properties, ft_allowed_properties + [cs.FT_METADATA]) ] receive_caps(q, conn, stream, contact, contact_handle, generic_ft_features + [ns.TP_FT_METADATA + '#daap'], daap_caps) # send presence with 2 FT caps daap_xiangqi_caps = daap_caps + [ (xiangqi_fixed_properties, ft_allowed_properties + [cs.FT_METADATA]) ] receive_caps( q, conn, stream, contact, contact_handle, generic_ft_features + [ ns.TP_FT_METADATA + '#com.example.Xiangqi', ns.TP_FT_METADATA + '#daap', ], daap_xiangqi_caps) # send presence with 1 FT cap again # Gabble does not look up our capabilities because of the cache receive_caps(q, conn, stream, contact, contact_handle, generic_ft_features + [ns.TP_FT_METADATA + '#daap'], daap_caps, expect_disco=False)
def check_caps(conn, h): caps = get_contacts_capabilities_sync(conn, [h]) assert_rccs_callable(caps[h], require_video=True)
def test_tube_caps_to_contact(q, bus, conn, stream): self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") basic_caps = dbus.Dictionary({self_handle: [(text_fixed_properties, text_allowed_properties), (stream_tube_fixed_properties, stream_tube_allowed_properties), (dbus_tube_fixed_properties, dbus_tube_allowed_properties), ]}) daap_caps = dbus.Dictionary({self_handle: [(text_fixed_properties, text_allowed_properties), (stream_tube_fixed_properties, stream_tube_allowed_properties), (dbus_tube_fixed_properties, dbus_tube_allowed_properties), (incoming_daap_fixed_properties, specialized_tube_allowed_properties), (ft_fixed_properties, ft_allowed_properties)]}) xiangqi_caps = dbus.Dictionary({self_handle: [(text_fixed_properties, text_allowed_properties), (stream_tube_fixed_properties, stream_tube_allowed_properties), (dbus_tube_fixed_properties, dbus_tube_allowed_properties), (xiangqi_fixed_properties, specialized_tube_allowed_properties), (ft_fixed_properties, ft_allowed_properties)]}) daap_xiangqi_caps = dbus.Dictionary({self_handle: [(text_fixed_properties, text_allowed_properties), (stream_tube_fixed_properties, stream_tube_allowed_properties), (dbus_tube_fixed_properties, dbus_tube_allowed_properties), (incoming_daap_fixed_properties, specialized_tube_allowed_properties), (xiangqi_fixed_properties, specialized_tube_allowed_properties), (ft_fixed_properties, ft_allowed_properties)]}) all_tubes_caps = dbus.Dictionary({self_handle: [(text_fixed_properties, text_allowed_properties), (stream_tube_fixed_properties, stream_tube_allowed_properties), (dbus_tube_fixed_properties, dbus_tube_allowed_properties), (incoming_daap_fixed_properties, specialized_tube_allowed_properties), (http_fixed_properties, specialized_tube_allowed_properties), (xiangqi_fixed_properties, specialized_tube_allowed_properties), (go_fixed_properties, specialized_tube_allowed_properties), (ft_fixed_properties, ft_allowed_properties)]}) # Check our own caps caps = get_contacts_capabilities_sync(conn, [self_handle]) assertEquals(basic_caps, caps) # check the Contacts interface give the same caps caps_via_contacts_iface = conn.Contacts.GetContactAttributes( [self_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [self_handle][cs.ATTR_CONTACT_CAPABILITIES] assertEquals(caps[self_handle], caps_via_contacts_iface) # Advertise nothing conn.ContactCapabilities.UpdateCapabilities( [(cs.CLIENT + '.Foo', {}, [])]) # Check our own caps caps = get_contacts_capabilities_sync(conn, [self_handle]) assertLength(1, caps) assertEquals(basic_caps, caps) # check the Contacts interface give the same caps caps_via_contacts_iface = conn.Contacts.GetContactAttributes( [self_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [self_handle][cs.ATTR_CONTACT_CAPABILITIES] assertEquals(caps[self_handle], caps_via_contacts_iface) sync_stream(q, stream) # Advertise a Requested=True tube cap conn.ContactCapabilities.UpdateCapabilities( [(cs.CLIENT + '.Foo', [outgoing_daap_fixed_properties], [])]) # Check our own caps caps = get_contacts_capabilities_sync(conn, [self_handle]) assertLength(1, caps) assertEquals(basic_caps, caps) # check the Contacts interface give the same caps caps_via_contacts_iface = conn.Contacts.GetContactAttributes( [self_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [self_handle][cs.ATTR_CONTACT_CAPABILITIES] assertEquals(caps[self_handle], caps_via_contacts_iface) sync_stream(q, stream) advertise_caps(q, conn, stream, [bidir_daap_fixed_properties], [ns.TUBES + '/stream#daap'], [ns.TUBES + '/stream#http', ns.TUBES + '/dbus#com.example.Go', ns.TUBES + '/dbus#com.example.Xiangqi', ], daap_caps) advertise_caps(q, conn, stream, [outgoing_daap_fixed_properties, xiangqi_fixed_properties], [ns.TUBES + '/dbus#com.example.Xiangqi'], [ns.TUBES + '/stream#daap', ns.TUBES + '/stream#http', ns.TUBES + '/dbus#com.example.Go', ], xiangqi_caps) advertise_caps(q, conn, stream, [incoming_daap_fixed_properties, outgoing_daap_fixed_properties, xiangqi_fixed_properties], [ns.TUBES + '/dbus#com.example.Xiangqi', ns.TUBES + '/stream#daap', ], [ns.TUBES + '/stream#http', ns.TUBES + '/dbus#com.example.Go', ], daap_xiangqi_caps) advertise_caps(q, conn, stream, [incoming_daap_fixed_properties, http_fixed_properties, go_fixed_properties, xiangqi_fixed_properties], [ns.TUBES + '/dbus#com.example.Xiangqi', ns.TUBES + '/stream#daap', ns.TUBES + '/stream#http', ns.TUBES + '/dbus#com.example.Go', ], [], all_tubes_caps) # test daap + xiangqi again for some reason advertise_caps(q, conn, stream, [incoming_daap_fixed_properties, xiangqi_fixed_properties], [ns.TUBES + '/dbus#com.example.Xiangqi', ns.TUBES + '/stream#daap', ], [ns.TUBES + '/stream#http', ns.TUBES + '/dbus#com.example.Go', ], daap_xiangqi_caps)
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 check_caps(conn, h): caps = get_contacts_capabilities_sync(conn, [h]) assert_rccs_callable(caps[h], require_video=True)
def test_hash(q, bus, conn, stream, contact, contact_handle, client): presence = make_presence(contact, status='hello') stream.send(presence) q.expect('dbus-signal', signal='PresencesChanged', args=[{contact_handle: (2, u'available', 'hello')}]) # no special capabilities for rcc in get_contacts_capabilities_sync(conn, [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', 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 send_disco_reply(stream, event.stanza, [], jingle_av_features) # we can now do audio calls cc, = q.expect_many( EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), ) assert_rccs_callable(cc.args[0][contact_handle]) assertEquals(cc.args[0], get_contacts_capabilities_sync(conn, [contact_handle])) # Send presence without any capabilities. XEP-0115 §8.4 Caps Optimization # says “receivers of presence notifications MUST NOT expect an annotation # on every presence notification they receive”, so the contact should still # be media-capable afterwards. stream.send(make_presence(contact, status='very capable')) q.expect('dbus-signal', signal='PresencesChanged', args=[{contact_handle: (2, u'available', 'very capable')}]) # still exactly the same capabilities assertEquals(cc.args[0], get_contacts_capabilities_sync(conn, [contact_handle])) # 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 send_disco_reply(stream, event.stanza, [], ['http://jabber.org/protocol/bogus-feature']) # don't receive any D-Bus signal forbidden = [ EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), ] q.forbid_events(forbidden) sync_dbus(bus, q, conn) sync_stream(q, stream) # 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) # 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 cc, = q.expect_many( EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), ) for rcc in cc.args[0][contact_handle]: assertEquals(cs.CHANNEL_TYPE_TEXT, rcc[0].get(cs.CHANNEL_TYPE)) assert_rccs_not_callable(cc.args[0][contact_handle]) assertEquals(cc.args[0], get_contacts_capabilities_sync(conn, [contact_handle])) # send correct presence ver = compute_caps_hash(some_identities, 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 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, fake_client_dataforms) # we can now do audio calls cc, = q.expect_many( EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), ) assert_rccs_callable(cc.args[0][contact_handle]) assertEquals(cc.args[0], get_contacts_capabilities_sync(conn, [contact_handle]))
def test_ft_caps_from_contact(q, bus, conn, stream, contact, contact_handle, client): conn_caps_iface = dbus.Interface(conn, cs.CONN_IFACE_CONTACT_CAPS) conn_contacts_iface = dbus.Interface(conn, cs.CONN_IFACE_CONTACTS) # send presence with no FT cap presence = make_presence(contact, status='hello') c = presence.addElement((ns.CAPS, 'c')) c['node'] = client c['ver'] = compute_caps_hash([], [], {}) c['hash'] = 'sha-1' stream.send(presence) # Gabble looks up our capabilities event = q.expect('stream-iq', to=contact, query_ns=ns.DISCO_INFO) query_node = xpath.queryForNodes('/iq/query', event.stanza)[0] assert query_node.attributes['node'] == \ client + '#' + c['ver'] # send good reply result = make_result_iq(stream, event.stanza) query = result.firstChildElement() query['node'] = client + '#' + c['ver'] stream.send(result) # no change in ContactCapabilities, so no signal ContactCapabilitiesChanged sync_stream(q, stream) # no special capabilities basic_caps = dbus.Dictionary( {contact_handle: [(text_fixed_properties, text_allowed_properties)]}) caps = get_contacts_capabilities_sync(conn, [contact_handle]) assert caps == basic_caps, caps # test again, to check GetContactCapabilities does not have side effect caps = get_contacts_capabilities_sync(conn, [contact_handle]) assert caps == basic_caps, caps # check the Contacts interface give the same caps caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes( [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [contact_handle][cs.ATTR_CONTACT_CAPABILITIES] assert caps_via_contacts_iface == caps[contact_handle], \ caps_via_contacts_iface # send presence with ft capa presence = make_presence(contact, status='hello') c = presence.addElement((ns.CAPS, 'c')) c['node'] = client c['ver'] = compute_caps_hash([], [ns.FILE_TRANSFER], {}) c['hash'] = 'sha-1' stream.send(presence) # Gabble looks up our capabilities event = q.expect('stream-iq', to=contact, query_ns=ns.DISCO_INFO) query_node = xpath.queryForNodes('/iq/query', event.stanza)[0] assert query_node.attributes['node'] == \ client + '#' + c['ver'] # send good reply result = make_result_iq(stream, event.stanza) query = result.firstChildElement() query['node'] = client + '#' + c['ver'] feature = query.addElement('feature') feature['var'] = ns.FILE_TRANSFER stream.send(result) generic_tubes_caps = dbus.Dictionary({ contact_handle: [(text_fixed_properties, text_allowed_properties), (ft_fixed_properties, ft_allowed_properties)] }) event = q.expect('dbus-signal', signal='ContactCapabilitiesChanged') assert len(event.args) == 1 assert event.args[0] == generic_tubes_caps caps = get_contacts_capabilities_sync(conn, [contact_handle]) assert caps == generic_tubes_caps, caps # test again, to check GetContactCapabilities does not have side effect caps = get_contacts_capabilities_sync(conn, [contact_handle]) assert caps == generic_tubes_caps, caps # check the Contacts interface give the same caps caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes( [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \ [contact_handle][cs.ATTR_CONTACT_CAPABILITIES] assert caps_via_contacts_iface == caps[contact_handle], \ caps_via_contacts_iface
def test(q, bus, conn, stream): bob = conn.get_contact_handle_sync('*****@*****.**') presence = make_presence('[email protected]/Foo', status='hello') stream.send(presence) q.expect('dbus-signal', signal='PresencesChanged', args=[{ bob: (cs.PRESENCE_AVAILABLE, u'available', 'hello') }]) basic_caps = [(bob, cs.CHANNEL_TYPE_TEXT, 3, 0)] # only Text for rcc in get_contacts_capabilities_sync(conn, [bob])[bob]: assertEquals(cs.CHANNEL_TYPE_TEXT, rcc[0].get(cs.CHANNEL_TYPE)) # holding the handle here: see below assertEquals( { bob: { cs.ATTR_CONTACT_CAPABILITIES: get_contacts_capabilities_sync(conn, [bob])[bob], cs.CONN + '/contact-id': '*****@*****.**', }, }, 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 # discovered before any capabilities change signal is emitted presence = make_presence( '[email protected]/Foo', status='hello', caps={ 'node': 'http://telepathy.freedesktop.org/fake-client', 'ver': '0.1', 'ext': 'video', }) stream.send(presence) # Gabble looks up both the version and the video bundles, in any order (version_event, video_event) = q.expect_many( EventPattern( 'stream-iq', to='[email protected]/Foo', query_ns='http://jabber.org/protocol/disco#info', query_node='http://telepathy.freedesktop.org/fake-client#0.1'), EventPattern( 'stream-iq', to='[email protected]/Foo', query_ns='http://jabber.org/protocol/disco#info', query_node='http://telepathy.freedesktop.org/fake-client#video')) # reply to the video bundle query first - this capability alone is not # sufficient to make us callable result = make_result_iq(stream, video_event.stanza) query = result.firstChildElement() feature = query.addElement('feature') feature['var'] = 'http://jabber.org/protocol/jingle/description/video' stream.send(result) # reply to the version bundle query, which should make us audio and # video callable result = make_result_iq(stream, version_event.stanza) query = result.firstChildElement() feature = query.addElement('feature') feature['var'] = 'http://jabber.org/protocol/jingle' feature = query.addElement('feature') feature['var'] = 'http://jabber.org/protocol/jingle/description/audio' feature = query.addElement('feature') feature['var'] = 'http://www.google.com/transport/p2p' stream.send(result) # we can now do audio and video calls cc, = q.expect_many( EventPattern( 'dbus-signal', signal='ContactCapabilitiesChanged', predicate=lambda e: check_rccs_callable(e.args[0][bob])), ) assert_rccs_callable(cc.args[0][bob], require_video=True, mutable_contents=True) assertEquals( { bob: { cs.ATTR_CONTACT_CAPABILITIES: cc.args[0][bob], cs.CONN + '/contact-id': '*****@*****.**', }, }, conn.Contacts.GetContactAttributes([bob], [cs.CONN_IFACE_CONTACT_CAPS], True)) # send updated presence without video support presence = make_presence( '[email protected]/Foo', status='hello', caps={ 'node': 'http://telepathy.freedesktop.org/fake-client', 'ver': '0.1', }) stream.send(presence) # we can now do only audio calls (and as a result have the ImmutableStreams # cap) cc, = q.expect_many( EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), ) assert_rccs_callable(cc.args[0][bob]) assert_rccs_not_callable(cc.args[0][bob], require_audio=False, require_video=True, mutable_contents=False) assertEquals( { bob: { cs.ATTR_CONTACT_CAPABILITIES: cc.args[0][bob], cs.CONN + '/contact-id': '*****@*****.**', }, }, conn.Contacts.GetContactAttributes([bob], [cs.CONN_IFACE_CONTACT_CAPS], True)) # go offline presence = make_presence('[email protected]/Foo', type='unavailable') stream.send(presence) # can't do audio calls any more q.expect_many( EventPattern('dbus-signal', signal='PresencesChanged', 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 = get_contacts_capabilities_sync(conn, [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': '*****@*****.**', }, }, conn.Contacts.GetContactAttributes([bob], [cs.CONN_IFACE_CONTACT_CAPS], True)) # What about a handle that's not valid? assertEquals({}, conn.Contacts.GetContactAttributes( [31337], [cs.CONN_IFACE_CONTACT_CAPS], False))