Exemplo n.º 1
0
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
Exemplo n.º 2
0
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
def test_create_invisible_list_failed(q, bus, conn, stream):
    conn.SimplePresence.SetPresence("away", "")

    conn.Connect()

    stream.handle_get_all_privacy_lists(q, bus, conn)

    get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='get')
    list_node = xpath.queryForNodes('//list', get_list.query)[0]
    assertEquals('invisible', list_node['name'])

    error = domish.Element((None, 'error'))
    error['type'] = 'cancel'
    error.addElement((ns.STANZA, 'item-not-found'))
    send_error_reply (stream, get_list.stanza, error)

    create_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set')
    list_node = xpath.queryForNodes('//list', create_list.query)[0]
    assertEquals('invisible', list_node['name'])
    assertNotEquals([],
        xpath.queryForNodes('/query/list/item/presence-out', create_list.query))
    send_error_reply(stream, create_list.stanza)

    q.expect('dbus-signal', signal='StatusChanged',
        args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])

    assertDoesNotContain("hidden",
        conn.Properties.Get(cs.CONN_IFACE_SIMPLE_PRESENCE, "Statuses"))
Exemplo n.º 4
0
def advertise_caps(q, conn, stream, filters, expected_features, unexpected_features,
                   expected_caps):
    self_handle = conn.GetSelfHandle()
    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 = conn.ContactCapabilities.GetContactCapabilities([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)
Exemplo n.º 5
0
def test_deny_unblock_remove(q, bus, conn, stream, stored, deny):
    """
    Test unblocking a contact, and, while that request is pending, deleting
    them.
    """
    self_handle = conn.GetSelfHandle()

    # This contact was on our roster, blocked and subscribed, when we started.
    contact = '*****@*****.**'
    handle = conn.RequestHandles(cs.HT_CONTACT, [contact])[0]

    # They're blocked, and we have a bidi subscription, so they should be on
    # deny and stored. (We already checked this earlier, but we've been messing
    # with the roster so let's be sure the preconditions are okay...)
    assertContains(handle,
        deny.Properties.Get(cs.CHANNEL_IFACE_GROUP, "Members"))
    assertContains(handle,
        stored.Properties.Get(cs.CHANNEL_IFACE_GROUP, "Members"))

    # Unblock them.
    call_async(q, deny.Group, 'RemoveMembers', [handle], "")

    roster_event = q.expect('stream-iq', query_ns=ns.ROSTER)
    item = roster_event.query.firstChildElement()
    assertEquals(contact, item['jid'])
    assertDoesNotContain((ns.GOOGLE_ROSTER, 't'), item.attributes)

    # If we now remove them from stored, the edit shouldn't be sent until the
    # unblock event has had a reply.
    q.forbid_events(remove_events)
    call_async(q, stored.Group, 'RemoveMembers', [handle], "")

    # Make sure if the remove is sent prematurely, we catch it.
    sync_stream(q, stream)
    q.unforbid_events(remove_events)

    # So now we send a roster push and reply for the unblock request.
    stream.send(make_set_roster_iq(stream, 'test@localhost/Resource', contact,
        'both', False, attrs={}))
    acknowledge_iq(stream, roster_event.stanza)

    # And on receiving the push and reply, Gabble should show them being
    # removed from deny, and send a remove.

    _, roster_event = q.expect_many(
        EventPattern('dbus-signal', signal='MembersChanged',
            args=['', [], [handle], [], [], self_handle, cs.GC_REASON_NONE],
            predicate=is_deny),
        remove_events[0],
        )
    item = roster_event.query.firstChildElement()
    assertEquals(contact, item['jid'])

    stream.send(make_set_roster_iq(stream, 'test@localhost/Resource', contact,
        'remove', False, attrs={}))
    acknowledge_iq(stream, roster_event.stanza)

    q.expect('dbus-signal', signal='MembersChanged',
        args=['', [], [handle], [], [], 0, cs.GC_REASON_NONE],
        predicate=is_stored)
Exemplo n.º 6
0
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)
Exemplo n.º 7
0
def test_invisible_on_connect_fail_no_list(q, bus, conn, stream):
    props = conn.Properties.GetAll(cs.CONN_IFACE_SIMPLE_PRESENCE)
    assertNotEquals({}, props['Statuses'])

    presence_event_pattern = EventPattern('stream-presence')

    q.forbid_events([presence_event_pattern])

    conn.SimplePresence.SetPresence("hidden", "")

    conn.Connect()

    stream.handle_get_all_privacy_lists(q, bus, conn)

    get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='get')
    list_node = xpath.queryForNodes('//list', get_list.query)[0]
    assertEquals('invisible', list_node['name'])

    send_error_reply(stream, get_list.stanza)

    q.unforbid_events([presence_event_pattern])

    # Darn! At least we should have our presence set to DND.
    q.expect_many(
        EventPattern('dbus-signal', signal='PresencesChanged',
                     interface=cs.CONN_IFACE_SIMPLE_PRESENCE,
                     args=[{1: (6, 'dnd', '')}]),
        EventPattern('dbus-signal', signal='StatusChanged',
                     args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]))

    # 'hidden' should not be an available status.
    assertDoesNotContain("hidden",
        conn.Properties.Get(cs.CONN_IFACE_SIMPLE_PRESENCE, "Statuses"))
Exemplo n.º 8
0
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 test_create_invisible_list_failed(q, bus, conn, stream):
    conn.SimplePresence.SetPresence("away", "")

    conn.Connect()

    stream.handle_get_all_privacy_lists(q, bus, conn)

    get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='get')
    list_node = xpath.queryForNodes('//list', get_list.query)[0]
    assertEquals('invisible', list_node['name'])

    error = domish.Element((None, 'error'))
    error['type'] = 'cancel'
    error.addElement((ns.STANZA, 'item-not-found'))
    send_error_reply(stream, get_list.stanza, error)

    create_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set')
    list_node = xpath.queryForNodes('//list', create_list.query)[0]
    assertEquals('invisible', list_node['name'])
    assertNotEquals([],
                    xpath.queryForNodes('/query/list/item/presence-out',
                                        create_list.query))
    send_error_reply(stream, create_list.stanza)

    q.expect('dbus-signal',
             signal='StatusChanged',
             args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])

    assertDoesNotContain(
        "hidden", conn.Properties.Get(cs.CONN_IFACE_SIMPLE_PRESENCE,
                                      "Statuses"))
Exemplo n.º 10
0
    def reject_start_receiving(self, content):
        self.stop_receiving(content)

        content.stream.RequestReceiving(self.remote_handle, True)

        self.q.expect('dbus-signal',
                      signal='ReceivingStateChanged',
                      args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                      path=content.stream.__dbus_object_path__),

        content.stream.Media.CompleteReceivingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STARTED)

        o = self.q.expect_many(
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STARTED],
                         path=content.stream.__dbus_object_path__),
            EventPattern('dbus-signal',
                         signal='RemoteMembersChanged',
                         path=content.stream.__dbus_object_path__),
            EventPattern('sip-invite'))

        assertLength(0, o[1].args[2])
        assertLength(1, o[1].args[0])
        assertEquals(cs.CALL_SENDING_STATE_PENDING_SEND,
                     o[1].args[0][self.remote_handle])
        assertEquals(self.self_handle, o[1].args[3][0])
        assertEquals(cs.CALL_STATE_CHANGE_REASON_USER_REQUESTED,
                     o[1].args[3][1])
        reinvite_event = o[2]

        assertDoesNotContain('a=sendonly', reinvite_event.sip_message.body)
        assertDoesNotContain('a=inactive', reinvite_event.sip_message.body)

        self.context.check_call_sdp(reinvite_event.sip_message.body)
        body = reinvite_event.sip_message.body + 'a=recvonly\r\r'
        self.context.accept(reinvite_event.sip_message, body)

        ack_cseq = "%s ACK" % reinvite_event.cseq.split()[0]
        self.q.expect_many(EventPattern('sip-ack', cseq=ack_cseq))

        # Now let's restart receiving for real
        self.receiving = True
        self.context.reinvite()

        acc, rmb = self.q.expect_many(
            EventPattern('sip-response', code=200),
            EventPattern('dbus-signal',
                         signal='RemoteMembersChanged',
                         path=content.stream.__dbus_object_path__,
                         predicate=lambda e: e.args[0] ==
                         {self.remote_handle: cs.CALL_SENDING_STATE_SENDING}))

        self.context.check_call_sdp(acc.sip_message.body, self.medias)
        self.context.ack(acc.sip_message)
Exemplo n.º 11
0
def test_deny_unblock_remove(q, bus, conn, stream):
    """
    Test unblocking a contact, and, while that request is pending, deleting
    them.
    """

    # This contact was on our roster, blocked and subscribed, when we started.
    contact = '*****@*****.**'
    handle = conn.get_contact_handle_sync(contact)

    check_contact_roster(conn, contact, [],
            cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_YES)

    # They're blocked, and we have a bidi subscription, so they should be on
    # deny and stored. (We already checked this earlier, but we've been messing
    # with the roster so let's be sure the preconditions are okay...)
    assertContains(handle,
        conn.ContactBlocking.RequestBlockedContacts().keys())

    # Unblock them.
    call_async(q, conn.ContactBlocking, 'UnblockContacts', [handle])

    roster_event = q.expect('stream-iq', query_ns=ns.ROSTER)
    item = roster_event.query.firstChildElement()
    assertEquals(contact, item['jid'])
    assertDoesNotContain((ns.GOOGLE_ROSTER, 't'), item.attributes)

    # If we now remove them from stored, the edit shouldn't be sent until the
    # unblock event has had a reply.
    q.forbid_events(remove_events)
    call_async(q, conn.ContactList, 'RemoveContacts', [handle])

    # Make sure if the remove is sent prematurely, we catch it.
    sync_stream(q, stream)
    q.unforbid_events(remove_events)

    # So now we send a roster push and reply for the unblock request.
    stream.send(make_set_roster_iq(stream, 'test@localhost/Resource', contact,
        'both', False, attrs={}))
    acknowledge_iq(stream, roster_event.stanza)

    # And on receiving the push and reply, Gabble should show them being
    # removed from deny, and send a remove.

    _, roster_event = q.expect_many(
        EventPattern('dbus-signal', signal='BlockedContactsChanged',
            predicate=lambda e: blocked_contacts_changed_predicate(e, [], [contact])),
        remove_events[0],
        )
    item = roster_event.query.firstChildElement()
    assertEquals(contact, item['jid'])

    stream.send(make_set_roster_iq(stream, 'test@localhost/Resource', contact,
        'remove', False, attrs={}))
    acknowledge_iq(stream, roster_event.stanza)
    def reject_start_receiving(self, content):
        self.stop_receiving(content)

        content.stream.RequestReceiving(self.remote_handle, True)

        self.q.expect('dbus-signal', signal='ReceivingStateChanged',
                 args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                 path=content.stream.__dbus_object_path__),

        content.stream.Media.CompleteReceivingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STARTED)

        o = self.q.expect_many(
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STARTED],
                         path=content.stream.__dbus_object_path__),
            EventPattern('dbus-signal', signal='RemoteMembersChanged',
                         path=content.stream.__dbus_object_path__),
            EventPattern('sip-invite'))


        assertLength(0, o[1].args[2])
        assertLength(1, o[1].args[0])
        assertEquals(cs.CALL_SENDING_STATE_PENDING_SEND,
                     o[1].args[0][self.remote_handle])
        assertEquals(self.self_handle, o[1].args[3][0])
        assertEquals(cs.CALL_STATE_CHANGE_REASON_USER_REQUESTED, o[1].args[3][1])
        reinvite_event = o[2]

        assertDoesNotContain('a=sendonly', reinvite_event.sip_message.body)
        assertDoesNotContain('a=inactive', reinvite_event.sip_message.body)

        self.context.check_call_sdp(reinvite_event.sip_message.body)
        body = reinvite_event.sip_message.body + 'a=recvonly\r\r'
        self.context.accept(reinvite_event.sip_message, body)

        ack_cseq = "%s ACK" % reinvite_event.cseq.split()[0]
        self.q.expect_many(
            EventPattern('sip-ack', cseq=ack_cseq))

        # Now let's restart receiving for real
        self.receiving = True
        self.context.reinvite()

        acc , rmb = self.q.expect_many(
            EventPattern('sip-response', code=200),
            EventPattern('dbus-signal', signal='RemoteMembersChanged',
                         path=content.stream.__dbus_object_path__,
                         predicate=lambda e: e.args[0] == {self.remote_handle: cs.CALL_SENDING_STATE_SENDING}))

        self.context.check_call_sdp(acc.sip_message.body, self.medias)
        self.context.ack(acc.sip_message)
Exemplo n.º 13
0
def check_caps(namespaces, desired):
    """Assert that all the FIXED_CAPS are supported, and of the VARIABLE_CAPS,
    every capability in desired is supported, and every other capability is
    not.
    """
    for c in FIXED_CAPS:
        assertContains(c, namespaces)

    for c in VARIABLE_CAPS:
        if c in desired:
            assertContains(c, namespaces)
        else:
            assertDoesNotContain(c, namespaces)
Exemplo n.º 14
0
def check_caps(namespaces, desired):
    """Assert that all the FIXED_CAPS are supported, and of the VARIABLE_CAPS,
    every capability in desired is supported, and every other capability is
    not.
    """
    for c in FIXED_CAPS:
        assertContains(c, namespaces)

    for c in VARIABLE_CAPS:
        if c in desired:
            assertContains(c, namespaces)
        else:
            assertDoesNotContain(c, namespaces)
Exemplo n.º 15
0
    def start_receiving(self, content, already_receiving=False):
        self.receiving = True

        content.stream.RequestReceiving(self.remote_handle, True)

        self.q.expect('dbus-signal',
                      signal='ReceivingStateChanged',
                      args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                      path=content.stream.__dbus_object_path__),

        content.stream.Media.CompleteReceivingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STARTED)

        o = self.q.expect_many(
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STARTED],
                         path=content.stream.__dbus_object_path__),
            EventPattern('dbus-signal',
                         signal='RemoteMembersChanged',
                         path=content.stream.__dbus_object_path__),
            EventPattern('sip-invite'))

        assertLength(0, o[1].args[2])
        assertLength(1, o[1].args[0])
        assertEquals(cs.CALL_SENDING_STATE_PENDING_SEND,
                     o[1].args[0][self.remote_handle])
        assertEquals(self.self_handle, o[1].args[3][0])
        assertEquals(cs.CALL_STATE_CHANGE_REASON_USER_REQUESTED,
                     o[1].args[3][1])
        reinvite_event = o[2]

        assertDoesNotContain('a=sendonly', reinvite_event.sip_message.body)
        assertDoesNotContain('a=inactive', reinvite_event.sip_message.body)
        self.context.check_call_sdp(reinvite_event.sip_message.body)

        self.context.accept(reinvite_event.sip_message)

        ack_cseq = "%s ACK" % reinvite_event.cseq.split()[0]
        o = self.q.expect_many(
            EventPattern('sip-ack', cseq=ack_cseq),
            EventPattern('dbus-signal',
                         signal='RemoteMembersChanged',
                         path=content.stream.__dbus_object_path__))

        assertLength(1, o[1].args[0])
        assertLength(0, o[1].args[2])
        assertEquals(cs.CALL_SENDING_STATE_SENDING,
                     o[1].args[0][self.remote_handle])
Exemplo n.º 16
0
def advertise_caps(q, bus, conn, service, 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")
    self_handle_name = conn.Properties.Get(cs.CONN, "SelfID")
    ret_caps = conn.ContactCapabilities.UpdateCapabilities([
        (cs.CLIENT + '.Foo', filters, [])
    ])

    presence, event_dbus = q.expect_many(
        EventPattern('service-resolved', service=service),
        EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'))
    assertLength(1, event_dbus.args)
    signaled_caps = event_dbus.args[0]

    outbound = connect_to_stream(q, 'test@foobar', self_handle_name,
                                 str(presence.pt), presence.port)

    e = q.expect('connection-result')
    assert e.succeeded, e.reason

    e = q.expect('stream-opened', connection=outbound)

    # Expect Salut to reply with the correct caps
    event, namespaces = disco_caps(q, outbound, presence.txt)

    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 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(expected_caps, caps_via_contacts_iface)

    # close things...
    outbound.send('</stream:stream>')
    sync_dbus(bus, q, conn)
    outbound.transport.loseConnection()
def advertise_caps(q, bus, conn, service, 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")
    self_handle_name =  conn.Properties.Get(cs.CONN, "SelfID")
    ret_caps = conn.ContactCapabilities.UpdateCapabilities(
            [(cs.CLIENT + '.Foo', filters, [])])

    presence, event_dbus = q.expect_many(
        EventPattern('service-resolved', service=service),
        EventPattern('dbus-signal', signal='ContactCapabilitiesChanged')
        )
    assertLength(1, event_dbus.args)
    signaled_caps = event_dbus.args[0]

    outbound = connect_to_stream(q, 'test@foobar',
        self_handle_name, str(presence.pt), presence.port)

    e = q.expect('connection-result')
    assert e.succeeded, e.reason

    e = q.expect('stream-opened', connection=outbound)

    # Expect Salut to reply with the correct caps
    event, namespaces = disco_caps(q, outbound, presence.txt)

    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 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(expected_caps, caps_via_contacts_iface)

    # close things...
    outbound.send('</stream:stream>')
    sync_dbus(bus, q, conn)
    outbound.transport.loseConnection()
    def start_receiving(self, content, already_receiving=False):
        self.receiving = True

        content.stream.RequestReceiving(self.remote_handle, True)

        self.q.expect('dbus-signal', signal='ReceivingStateChanged',
                 args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                 path=content.stream.__dbus_object_path__),

        content.stream.Media.CompleteReceivingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STARTED)

        o = self.q.expect_many(
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STARTED],
                         path=content.stream.__dbus_object_path__),
            EventPattern('dbus-signal', signal='RemoteMembersChanged',
                         path=content.stream.__dbus_object_path__),
            EventPattern('sip-invite'))


        assertLength(0, o[1].args[2])
        assertLength(1, o[1].args[0])
        assertEquals(cs.CALL_SENDING_STATE_PENDING_SEND,
                     o[1].args[0][self.remote_handle])
        assertEquals(self.self_handle, o[1].args[3][0])
        assertEquals(cs.CALL_STATE_CHANGE_REASON_USER_REQUESTED, o[1].args[3][1])
        reinvite_event = o[2]

        assertDoesNotContain('a=sendonly', reinvite_event.sip_message.body)
        assertDoesNotContain('a=inactive', reinvite_event.sip_message.body)
        self.context.check_call_sdp(reinvite_event.sip_message.body)
        
        self.context.accept(reinvite_event.sip_message)

        ack_cseq = "%s ACK" % reinvite_event.cseq.split()[0]
        o = self.q.expect_many(
            EventPattern('sip-ack', cseq=ack_cseq),
            EventPattern('dbus-signal', signal='RemoteMembersChanged',
                         path=content.stream.__dbus_object_path__))

        assertLength(1, o[1].args[0])
        assertLength(0, o[1].args[2])
        assertEquals(cs.CALL_SENDING_STATE_SENDING,
                     o[1].args[0][self.remote_handle])
def test_google_caps(q, bus, conn, stream):
    i = 1

    # we want to make sure all permutations of voice-v1 and video-v1
    # result in the correct caps, so let's do exactly that.
    for j in (1, 2):
        for ext_set in permutations(['voice-v1', 'video-v1'], j):
            jid = 'larry%s@page/mountainview' % i
            i += 1

            # order of these ext values shouldn't matter
            gcaps = {
                'node': 'blahblahthiskeepsonchanging',
                'ver': '1.1',
                'ext': ' '.join(ext_set)
            }

            handle = conn.get_contact_handle_sync(jid)

            send_presence(q, conn, stream, jid, gcaps, initial=True)

            e = q.expect('dbus-signal',
                         signal='ContactCapabilitiesChanged',
                         predicate=lambda e: handle in e.args[0])

            assertEquals(1, len(e.args[0]))
            rccs = e.args[0][handle]

            found = False
            for fixed, allowed in rccs:
                if fixed[cs.CHANNEL_TYPE] != cs.CHANNEL_TYPE_CALL:
                    continue

                # we should only have InitialAudio or InitialVideo if
                # voice-v1 or video-v1 is present respectively
                for a, b in [('voice-v1' in ext_set, cs.CALL_INITIAL_AUDIO),
                             ('video-v1' in ext_set, cs.CALL_INITIAL_VIDEO)]:
                    if a:
                        assertContains(b, allowed)
                    else:
                        assertDoesNotContain(b, allowed)

                found = True

            assert found
Exemplo n.º 20
0
def test_google_caps(q, bus, conn, stream):
    i = 1

    # we want to make sure all permutations of voice-v1 and video-v1
    # result in the correct caps, so let's do exactly that.
    for j in (1, 2):
        for ext_set in permutations(['voice-v1', 'video-v1'], j):
            jid = 'larry%s@page/mountainview' % i
            i += 1

            # order of these ext values shouldn't matter
            gcaps = { 'node': 'blahblahthiskeepsonchanging',
                      'ver':  '1.1',
                      'ext': ' '.join(ext_set) }

            handle = conn.get_contact_handle_sync(jid)

            send_presence(q, conn, stream, jid, gcaps, initial=True)

            e = q.expect('dbus-signal', signal='ContactCapabilitiesChanged',
                         predicate=lambda e: handle in e.args[0])

            assertEquals(1, len(e.args[0]))
            rccs = e.args[0][handle]

            found = False
            for fixed, allowed in rccs:
                if fixed[cs.CHANNEL_TYPE] != cs.CHANNEL_TYPE_CALL:
                    continue

                # we should only have InitialAudio or InitialVideo if
                # voice-v1 or video-v1 is present respectively
                for a, b in [('voice-v1' in ext_set, cs.CALL_INITIAL_AUDIO),
                             ('video-v1' in ext_set, cs.CALL_INITIAL_VIDEO)]:
                    if a:
                        assertContains(b, allowed)
                    else:
                        assertDoesNotContain(b, allowed)

                found = True

            assert found
Exemplo n.º 21
0
def extract_disco_parts(stanza):
    identity_nodes = xpath.queryForNodes('/iq/query/identity', stanza)
    assertLength(1, identity_nodes)
    identity_node = identity_nodes[0]

    assertEquals('client', identity_node['category'])
    assertEquals(config.CLIENT_TYPE, identity_node['type'])
    assertEquals(config.PACKAGE_STRING, identity_node['name'])
    assertDoesNotContain('xml:lang', identity_node.attributes)

    identity = 'client/%s//%s' % (config.CLIENT_TYPE, config.PACKAGE_STRING)

    features = []
    for feature in xpath.queryForNodes('/iq/query/feature', stanza):
        features.append(feature['var'])

    # a quick and ugly data form extractor
    x_nodes = xpath.queryForNodes('/iq/query/x', stanza) or []
    dataforms = extract_data_forms(x_nodes)
    return ([identity], features, dataforms)
Exemplo n.º 22
0
def extract_disco_parts(stanza):
    identity_nodes = xpath.queryForNodes('/iq/query/identity', stanza)
    assertLength(1, identity_nodes)
    identity_node = identity_nodes[0]

    assertEquals('client', identity_node['category'])
    assertEquals(config.CLIENT_TYPE, identity_node['type'])
    assertEquals(config.PACKAGE_STRING, identity_node['name'])
    assertDoesNotContain('xml:lang', identity_node.attributes)

    identity = 'client/%s//%s' % (config.CLIENT_TYPE, config.PACKAGE_STRING)

    features = []
    for feature in xpath.queryForNodes('/iq/query/feature', stanza):
        features.append(feature['var'])

    # a quick and ugly data form extractor
    x_nodes = xpath.queryForNodes('/iq/query/x', stanza) or []
    dataforms = extract_data_forms(x_nodes)
    return ([identity], features, dataforms)
    def unhold_succeed(self):
        self.chan.Hold.RequestHold(False)

        events = self.stream_dbus_signal_event (
            'ReceivingStateChanged',
            args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START])
        events += self.stream_dbus_signal_event(
            'SendingStateChanged',
                args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START])
        o = self.q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                         args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]),
            *events)
        for c in self.contents:
            c.stream.Media.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED)
            c.stream.Media.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED)

        events = self.stream_dbus_signal_event (
            'ReceivingStateChanged',
            args=[cs.CALL_STREAM_FLOW_STATE_STARTED])
        events += self.stream_dbus_signal_event(
            'SendingStateChanged',
            args=[cs.CALL_STREAM_FLOW_STATE_STARTED])
        o = self.q.expect_many(
            EventPattern('sip-invite'),
            EventPattern('dbus-signal', signal='HoldStateChanged',
                         args=[cs.HS_UNHELD, cs.HSR_REQUESTED]),
            *events)
        reinvite_event = o[0]
        medias = map(lambda x: (x[0], None), self.medias)
        assertDoesNotContain('a=sendonly', reinvite_event.sip_message.body)
        assertDoesNotContain('a=inactive', reinvite_event.sip_message.body)
        self.context.check_call_sdp(reinvite_event.sip_message.body, medias)

        self.context.accept(reinvite_event.sip_message)

        ack_cseq = "%s ACK" % reinvite_event.cseq.split()[0]
        self.q.expect('sip-ack', cseq=ack_cseq)
Exemplo n.º 24
0
    def unhold_succeed(self):
        self.chan.Hold.RequestHold(False)

        events = self.stream_dbus_signal_event(
            'ReceivingStateChanged',
            args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START])
        events += self.stream_dbus_signal_event(
            'SendingStateChanged',
            args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START])
        o = self.q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]),
            *events)
        for c in self.contents:
            c.stream.Media.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED)
            c.stream.Media.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED)

        events = self.stream_dbus_signal_event(
            'ReceivingStateChanged', args=[cs.CALL_STREAM_FLOW_STATE_STARTED])
        events += self.stream_dbus_signal_event(
            'SendingStateChanged', args=[cs.CALL_STREAM_FLOW_STATE_STARTED])
        o = self.q.expect_many(
            EventPattern('sip-invite'),
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_UNHELD, cs.HSR_REQUESTED]), *events)
        reinvite_event = o[0]
        medias = map(lambda x: (x[0], None), self.medias)
        assertDoesNotContain('a=sendonly', reinvite_event.sip_message.body)
        assertDoesNotContain('a=inactive', reinvite_event.sip_message.body)
        self.context.check_call_sdp(reinvite_event.sip_message.body, medias)

        self.context.accept(reinvite_event.sip_message)

        ack_cseq = "%s ACK" % reinvite_event.cseq.split()[0]
        self.q.expect('sip-ack', cseq=ack_cseq)
Exemplo n.º 25
0
def disco_caps(q, stream, presence):
    c_nodes = xpath.queryForNodes('/presence/c', presence.stanza)
    assert c_nodes is not None
    assertLength(1, c_nodes)
    hash = c_nodes[0].attributes['hash']
    ver = c_nodes[0].attributes['ver']
    node = c_nodes[0].attributes['node']
    assertEquals('sha-1', hash)

    # ask caps
    request = \
        elem_iq(stream, 'get', from_='[email protected]/resource')(
          elem(ns.DISCO_INFO, 'query', node=(node + '#' + ver))
        )
    stream.send(request)

    # receive caps
    event = q.expect('stream-iq', query_ns=ns.DISCO_INFO, iq_id=request['id'])

    # Check that Gabble's announcing the identity we think it should be.
    identity_nodes = xpath.queryForNodes('/iq/query/identity', event.stanza)
    assertLength(1, identity_nodes)
    identity_node = identity_nodes[0]

    assertEquals('client', identity_node['category'])
    assertEquals(config.CLIENT_TYPE, identity_node['type'])
    assertEquals(config.PACKAGE_STRING, identity_node['name'])
    assertDoesNotContain('xml:lang', identity_node.attributes)

    identity = 'client/%s//%s' % (config.CLIENT_TYPE, config.PACKAGE_STRING)

    features = []
    for feature in xpath.queryForNodes('/iq/query/feature', event.stanza):
        features.append(feature['var'])

    # Check if the hash matches the announced capabilities
    assertEquals(compute_caps_hash([identity], features, {}), ver)

    return (event, features)
def test_invisible_on_connect_fail_no_list(q, bus, conn, stream):
    props = conn.Properties.GetAll(cs.CONN_IFACE_SIMPLE_PRESENCE)
    assertNotEquals({}, props['Statuses'])

    presence_event_pattern = EventPattern('stream-presence')

    q.forbid_events([presence_event_pattern])

    conn.SimplePresence.SetPresence("hidden", "")

    conn.Connect()

    stream.handle_get_all_privacy_lists(q, bus, conn)

    get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='get')
    list_node = xpath.queryForNodes('//list', get_list.query)[0]
    assertEquals('invisible', list_node['name'])

    send_error_reply(stream, get_list.stanza)

    q.unforbid_events([presence_event_pattern])

    # Darn! At least we should have our presence set to DND.
    q.expect_many(
        EventPattern('dbus-signal',
                     signal='PresencesChanged',
                     interface=cs.CONN_IFACE_SIMPLE_PRESENCE,
                     args=[{
                         1: (6, 'dnd', '')
                     }]),
        EventPattern('dbus-signal',
                     signal='StatusChanged',
                     args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]))

    # 'hidden' should not be an available status.
    assertDoesNotContain(
        "hidden", conn.Properties.Get(cs.CONN_IFACE_SIMPLE_PRESENCE,
                                      "Statuses"))
Exemplo n.º 27
0
def disco_caps(q, stream, txt):
    hash = txt_get_key(txt, 'hash')
    ver = txt_get_key(txt, 'ver')
    node = txt_get_key(txt, 'node')
    assertEquals('sha-1', hash)

    # ask caps
    request = \
        elem_iq(stream, 'get', from_='fake_contact@nearby')(
          elem(ns.DISCO_INFO, 'query', node=(node + '#' + ver))
        )
    stream.send(request)

    # receive caps
    event = q.expect('stream-iq', query_ns=ns.DISCO_INFO, iq_id=request['id'])

    # Check that Gabble's announcing the identity we think it should be.
    identity_nodes = xpath.queryForNodes('/iq/query/identity', event.stanza)
    assertLength(1, identity_nodes)
    identity_node = identity_nodes[0]

    assertEquals('client', identity_node['category'])
    assertEquals('pc', identity_node['type'])
    assertEquals(config.PACKAGE_STRING, identity_node['name'])
    assertDoesNotContain('xml:lang', identity_node.attributes)

    identity = 'client/%s//%s' % ('pc', config.PACKAGE_STRING)

    features = []
    for feature in xpath.queryForNodes('/iq/query/feature', event.stanza):
        features.append(feature['var'])

    # Check if the hash matches the announced capabilities
    assertEquals(compute_caps_hash([identity], features, {}), ver)

    return (event, features)
    def start_sending(self, content):
        content.stream.SetSending(True)

        self.sending = True

        reinvite_event, lss = self.q.expect_many(
            EventPattern('sip-invite'),
            EventPattern('dbus-signal', signal='LocalSendingStateChanged',
                         path=content.stream.__dbus_object_path__))

        assertEquals(cs.CALL_SENDING_STATE_SENDING, lss.args[0])
        assertEquals(self.self_handle, lss.args[1][0])

        assertDoesNotContain('a=sendonly', reinvite_event.sip_message.body)

        if self.receiving:
            assertDoesNotContain('a=inactive',
                                 reinvite_event.sip_message.body)
            assertDoesNotContain('a=recvonly',
                                 reinvite_event.sip_message.body)
        else:
            self.context.check_call_sdp(reinvite_event.sip_message.body,
                                        [('audio','recvonly')])


        self.context.check_call_sdp(reinvite_event.sip_message.body)
        self.context.accept(reinvite_event.sip_message)

        ack_cseq = "%s ACK" % reinvite_event.cseq.split()[0]
        self.q.expect_many(
            EventPattern('sip-ack', cseq=ack_cseq),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START]))

        content.stream.Media.CompleteSendingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STARTED)

        self.q.expect('dbus-signal', signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STARTED],
                         path=content.stream.__dbus_object_path__)
Exemplo n.º 29
0
    def start_sending(self, content):
        content.stream.SetSending(True)

        self.sending = True

        reinvite_event, lss = self.q.expect_many(
            EventPattern('sip-invite'),
            EventPattern('dbus-signal',
                         signal='LocalSendingStateChanged',
                         path=content.stream.__dbus_object_path__))

        assertEquals(cs.CALL_SENDING_STATE_SENDING, lss.args[0])
        assertEquals(self.self_handle, lss.args[1][0])

        assertDoesNotContain('a=sendonly', reinvite_event.sip_message.body)

        if self.receiving:
            assertDoesNotContain('a=inactive', reinvite_event.sip_message.body)
            assertDoesNotContain('a=recvonly', reinvite_event.sip_message.body)
        else:
            self.context.check_call_sdp(reinvite_event.sip_message.body,
                                        [('audio', 'recvonly')])

        self.context.check_call_sdp(reinvite_event.sip_message.body)
        self.context.accept(reinvite_event.sip_message)

        ack_cseq = "%s ACK" % reinvite_event.cseq.split()[0]
        self.q.expect_many(
            EventPattern('sip-ack', cseq=ack_cseq),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START]))

        content.stream.Media.CompleteSendingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STARTED)

        self.q.expect('dbus-signal',
                      signal='SendingStateChanged',
                      args=[cs.CALL_STREAM_FLOW_STATE_STARTED],
                      path=content.stream.__dbus_object_path__)
Exemplo n.º 30
0
def test(q, bus, conn, stream):
    # Ignore conn here, we're only dealing with the CM and Protocol objects.
    cm = bus.get_object(cs.CM + '.haze',
                        tp_path_prefix + '/ConnectionManager/haze')
    cm_iface = dbus.Interface(cm, cs.CM)
    cm_props = dbus.Interface(cm, cs.PROPERTIES_IFACE)

    protocols = cm_props.Get(cs.CM, 'Protocols')
    protocol_names = cm_iface.ListProtocols()
    assertEquals(set(protocols.iterkeys()), set(protocol_names))

    for name in protocol_names:
        props = protocols[name]
        protocol = bus.get_object(
            cm.bus_name, cm.object_path + '/' + name.replace('-', '_'))
        protocol_iface = dbus.Interface(protocol, cs.PROTOCOL)
        protocol_props = dbus.Interface(protocol, cs.PROPERTIES_IFACE)
        flat_props = protocol_props.GetAll(cs.PROTOCOL)
        protocol_avatar_props = protocol_props.GetAll(
            cs.PROTOCOL_IFACE_AVATARS)

        # Protocol is supposed to implement Interface.Avatars iff the
        # connection implements Avatars as well.
        if cs.CONN_IFACE_AVATARS in flat_props['ConnectionInterfaces']:
            assertContains(cs.PROTOCOL_IFACE_AVATARS,
                           props[cs.PROTOCOL + '.Interfaces'])
        else:
            assertDoesNotContain(cs.PROTOCOL_IFACE_AVATARS,
                                 props[cs.PROTOCOL + '.Interfaces'])

        parameters = cm_iface.GetParameters(name)
        assertEquals(parameters, props[cs.PROTOCOL + '.Parameters'])
        assertEquals(parameters, flat_props['Parameters'])
        assertEquals(parameters, protocol_props.Get(cs.PROTOCOL, 'Parameters'))

        assertEquals(flat_props['VCardField'],
                     props[cs.PROTOCOL + '.VCardField'])
        assertEquals(flat_props['Interfaces'],
                     props[cs.PROTOCOL + '.Interfaces'])
        assertEquals(flat_props['EnglishName'],
                     props[cs.PROTOCOL + '.EnglishName'])
        assertEquals(flat_props['Icon'], props[cs.PROTOCOL + '.Icon'])
        assertEquals(flat_props['ConnectionInterfaces'],
                     props[cs.PROTOCOL + '.ConnectionInterfaces'])
        assertEquals(flat_props['RequestableChannelClasses'],
                     props[cs.PROTOCOL + '.RequestableChannelClasses'])

        param_map = {}
        param_flags = {}
        param_type = {}
        param_def = {}

        for p in parameters:
            param_map[p[0]] = tuple(p[1:])
            param_flags[p[0]] = p[1]
            param_type[p[0]] = p[2]
            param_def[p[0]] = p[3]

        # We use special cases to rename these; make sure they don't come back
        assertDoesNotContain(name, ('meanwhile', 'simple'))
        assertDoesNotContain('encoding', param_map)
        assertDoesNotContain('local_charset', param_map)

        if name not in ('local-xmpp', 'irc'):
            # it would be more correct for these protocols not to have this
            # parameter
            assertEquals((cs.PARAM_REQUIRED, 's', ''), param_map['account'])

        # a random selection of checks for known parameters...

        if name == 'gadugadu':
            assertEquals('x-gadugadu', flat_props['VCardField'])
            assertEquals('im-gadugadu', flat_props['Icon'])
            assertEquals((cs.PARAM_SECRET, 's', ''), param_map['password'])
            assertEquals('s', param_type['nick'])
            assertEquals('s', param_type['gg-server'])
        elif name == 'silc':
            assertEquals('x-silc', flat_props['VCardField'])
            assertEquals('im-silc', flat_props['Icon'])
            assertEquals((cs.PARAM_SECRET, 's', ''), param_map['password'])
            assertEquals('s', param_type['server'])
        elif name == 'irc':
            assertEquals('x-irc', flat_props['VCardField'])
            assertEquals('im-irc', flat_props['Icon'])
            assertEquals((cs.PARAM_SECRET, 's', ''), param_map['password'])
            assertEquals('s', param_type['charset'])
            assertEquals('s', param_type['username'])
            assertEquals('s', param_type['realname'])
            assertEquals('s', param_type['server'])
            assertEquals(cs.PARAM_HAS_DEFAULT, param_flags['server'])

            assertEquals(
                '*****@*****.**',
                protocol_iface.IdentifyAccount({
                    'account': 'smcv',
                    'server': 'irc.debian.org'
                }))

            assertDoesNotContain(cs.CONN_IFACE_AVATARS,
                                 flat_props['ConnectionInterfaces'])
            assertDoesNotContain(cs.CONN_IFACE_CONTACT_BLOCKING,
                                 flat_props['ConnectionInterfaces'])
            assertDoesNotContain(cs.CONN_IFACE_MAIL_NOTIFICATION,
                                 flat_props['ConnectionInterfaces'])

            # Avatar not supported
            assertEquals(0, protocol_avatar_props['MaximumAvatarBytes'])
            assertEquals(0, protocol_avatar_props['MaximumAvatarHeight'])
            assertEquals(0, protocol_avatar_props['MaximumAvatarWidth'])
            assertEquals(0, protocol_avatar_props['MinimumAvatarHeight'])
            assertEquals(0, protocol_avatar_props['MinimumAvatarWidth'])
            assertEquals(0, protocol_avatar_props['RecommendedAvatarHeight'])
            assertEquals(0, protocol_avatar_props['RecommendedAvatarWidth'])
            assertEquals([], protocol_avatar_props['SupportedAvatarMIMETypes'])
        elif name == 'myspace':
            assertEquals('x-myspace', flat_props['VCardField'])
            assertEquals('im-myspace', flat_props['Icon'])
            assertEquals('s', param_type['server'])
        elif name == 'yahoo':
            assertEquals('x-yahoo', flat_props['VCardField'])
            assertEquals('im-yahoo', flat_props['Icon'])
            assertEquals('s', param_type['charset'])
        elif name == 'yahoojp':
            assertEquals('x-yahoo', flat_props['VCardField'])
            assertEquals('im-yahoojp', flat_props['Icon'])
            assertEquals('s', param_type['charset'])
        elif name == 'aim':
            assertEquals('x-aim', flat_props['VCardField'])
            assertEquals('im-aim', flat_props['Icon'])
            assertEquals('s', param_type['server'])
        elif name == 'msn':
            assertEquals('x-msn', flat_props['VCardField'])
            assertEquals('im-msn', flat_props['Icon'])
            assertEquals('s', param_type['server'])
        elif name == 'jabber':
            assertEquals('x-jabber', flat_props['VCardField'])
            assertEquals('im-jabber', flat_props['Icon'])
            assertDoesNotContain('require_tls', param_map)
            assertDoesNotContain('connect_server', param_map)
            assertEquals((cs.PARAM_SECRET, 's', ''), param_map['password'])
            assertEquals((cs.PARAM_HAS_DEFAULT, 'b', True),
                         param_map['require-encryption'])

            assertEquals(
                '*****@*****.**',
                protocol_iface.IdentifyAccount({
                    'account': '*****@*****.**',
                    'password': '******'
                }))
            assertEquals(
                r'*****@*****.**',
                protocol_iface.IdentifyAccount({
                    'account': '*****@*****.**',
                    'server': r'corp.example.com',
                    'password': '******'
                }))

            # this contains an unsupported parameter
            call_async(
                q, protocol_iface, 'IdentifyAccount', {
                    'account': '*****@*****.**',
                    'embrace-and-extend': r'WORKGROUP\Bill',
                    'password': '******'
                })
            q.expect('dbus-error', name=cs.INVALID_ARGUMENT)

            assertContains(cs.CONN_IFACE_AVATARS,
                           flat_props['ConnectionInterfaces'])
            assertContains(cs.CONN_IFACE_CONTACT_BLOCKING,
                           flat_props['ConnectionInterfaces'])
            assertContains(cs.CONN_IFACE_MAIL_NOTIFICATION,
                           flat_props['ConnectionInterfaces'])

            # libpurple currently says there's no max size
            assertEquals(0, protocol_avatar_props['MaximumAvatarBytes'])
            assertEquals(96, protocol_avatar_props['MaximumAvatarHeight'])
            assertEquals(96, protocol_avatar_props['MaximumAvatarWidth'])
            assertEquals(32, protocol_avatar_props['MinimumAvatarHeight'])
            assertEquals(32, protocol_avatar_props['MinimumAvatarWidth'])
            assertEquals(0, protocol_avatar_props['RecommendedAvatarHeight'])
            assertEquals(0, protocol_avatar_props['RecommendedAvatarWidth'])
            assertEquals(['image/png'],
                         protocol_avatar_props['SupportedAvatarMIMETypes'])
        elif name == 'qq':
            assertEquals('x-qq', flat_props['VCardField'])
            assertEquals('im-qq', flat_props['Icon'])
        elif name == 'sametime':
            assertEquals('x-sametime', flat_props['VCardField'])
            assertEquals('im-sametime', flat_props['Icon'])
        elif name == 'zephyr':
            assertEquals('x-zephyr', flat_props['VCardField'])
            assertEquals('im-zephyr', flat_props['Icon'])
            assertEquals('s', param_type['realm'])
            assertEquals('s', param_type['charset'])
        elif name == 'local-xmpp':
            # makes very little sense in an address book
            assertEquals('', flat_props['VCardField'])
            assertEquals('im-local-xmpp', flat_props['Icon'])
            assertEquals((cs.PARAM_REQUIRED, 's', ''), param_map['first-name'])
            assertDoesNotContain('first', param_map)
            assertEquals((cs.PARAM_REQUIRED, 's', ''), param_map['last-name'])
            assertDoesNotContain('last', param_map)
            assertEquals((0, 's', ''), param_map['email'])
            assertEquals((0, 's', ''), param_map['jid'])
        elif name == 'icq':
            assertEquals('x-icq', flat_props['VCardField'])
            assertEquals('im-icq', flat_props['Icon'])
        elif name == 'groupwise':
            assertEquals('x-groupwise', flat_props['VCardField'])
            assertEquals('im-groupwise', flat_props['Icon'])
        elif name == 'sipe':
            assertEquals('im-sipe', flat_props['Icon'])
            assertDoesNotContain('usersplit1', param_map)
            assertEquals((cs.PARAM_HAS_DEFAULT, 's', ''), param_map['login'])

            assertEquals(
                '[email protected],',
                protocol_iface.IdentifyAccount({
                    'account': '*****@*****.**',
                    'password': '******'
                }))
            assertEquals(
                r'[email protected],WORKGROUP\Bill',
                protocol_iface.IdentifyAccount({
                    'account': '*****@*****.**',
                    'login': r'WORKGROUP\Bill',
                    'password': '******'
                }))
Exemplo n.º 31
0
def test(q, bus, conn, stream):
    event = q.expect('stream-iq', query_ns=ns.ROSTER)
    event.stanza['type'] = 'result'

    item = event.query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'both'
    item.addElement('group', content='women')

    item = event.query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'from'
    item.addElement('group', content='men')

    item = event.query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'to'
    item.addElement('group', content='men')

    stream.send(event.stanza)

    # Avoid relying on the implementation detail of exactly when
    # TpBaseContactList emits ContactsChanged, relative to when it
    # announces its channels. Prior to 0.20.3, 0.21.1 it would
    # announce the channels, emit GroupsChanged, then announce the channels
    # again... which was a bug, but it turned out this test relied on it.
    #
    # We do still rely on the implementation detail that we emit GroupsChanged
    # once per group with all of its members, not once per contact with all
    # of their groups. On a typical contact list, there are more contacts
    # than groups, so that'll work out smaller.

    q.expect_many(
        EventPattern(
            'dbus-signal',
            signal='GroupsCreated',
            interface=cs.CONN_IFACE_CONTACT_GROUPS,
            path=conn.object_path,
            predicate=lambda e: groups_created_predicate(e, ['men', 'women'])),
        EventPattern('dbus-signal',
                     signal='GroupsChanged',
                     interface=cs.CONN_IFACE_CONTACT_GROUPS,
                     path=conn.object_path,
                     predicate=lambda e: groups_changed_predicate(
                         e, conn, ['*****@*****.**'], ['women'], [])),
        EventPattern(
            'dbus-signal',
            signal='GroupsChanged',
            interface=cs.CONN_IFACE_CONTACT_GROUPS,
            path=conn.object_path,
            predicate=lambda e: groups_changed_predicate(
                e, conn, ['*****@*****.**', '*****@*****.**'], ['men'], [])),
    )

    amy, bob, che = conn.get_contact_handles_sync(
        ['*****@*****.**', '*****@*****.**', '*****@*****.**'])

    q.expect('dbus-signal',
             signal='ContactListStateChanged',
             args=[cs.CONTACT_LIST_STATE_SUCCESS])

    # change Amy's groups
    call_async(q, conn.ContactGroups, 'SetContactGroups', amy,
               ['ladies', 'people starting with A'])

    s, iq = q.expect_many(
        EventPattern('dbus-signal', signal='GroupsCreated'),
        EventPattern('stream-iq',
                     iq_type='set',
                     query_name='query',
                     query_ns=ns.ROSTER),
    )

    assertEquals(set(('ladies', 'people starting with A')), set(s.args[0]))

    jid, groups = parse_roster_change_request(iq.query, iq.stanza)
    assertEquals('*****@*****.**', jid)
    assertEquals(set(('ladies', 'people starting with A')), groups)

    acknowledge_iq(stream, iq.stanza)
    q.expect('dbus-return', method='SetContactGroups')

    # Now the server sends us a roster push.
    send_roster_push(stream, '*****@*****.**',
                     ['people starting with A', 'ladies'])

    # We get a single signal corresponding to that roster push
    e = q.expect('dbus-signal',
                 signal='GroupsChanged',
                 predicate=lambda e: e.args[0] == [amy])
    assertEquals(set(['ladies', 'people starting with A']), set(e.args[1]))
    assertEquals(['women'], e.args[2])

    # check that Amy's state is what we expected
    attrs = conn.Contacts.GetContactAttributes([amy],
                                               [cs.CONN_IFACE_CONTACT_GROUPS],
                                               False)[amy]
    # make the group list order-independent
    attrs[cs.CONN_IFACE_CONTACT_GROUPS + '/groups'] = \
        set(attrs[cs.CONN_IFACE_CONTACT_GROUPS + '/groups'])

    assertEquals(
        {
            cs.CONN_IFACE_CONTACT_GROUPS + '/groups':
            set(['ladies', 'people starting with A']),
            cs.CONN + '/contact-id':
            '*****@*****.**'
        }, attrs)

    for it_worked in (False, True):
        # remove a group with a member (the old API couldn't do this)
        call_async(q, conn.ContactGroups, 'RemoveGroup',
                   'people starting with A')

        iq = q.expect('stream-iq',
                      iq_type='set',
                      query_name='query',
                      query_ns=ns.ROSTER)

        jid, groups = parse_roster_change_request(iq.query, iq.stanza)
        assertEquals('*****@*****.**', jid)
        assertEquals(set(('ladies', )), groups)

        acknowledge_iq(stream, iq.stanza)

        # we emit these as soon as the IQ is ack'd, so that we can indicate
        # group removal...
        q.expect('dbus-signal',
                 signal='GroupsRemoved',
                 args=[['people starting with A']])
        q.expect('dbus-signal',
                 signal='GroupsChanged',
                 args=[[amy], [], ['people starting with A']])

        q.expect('dbus-return', method='RemoveGroup')

        if it_worked:
            # ... although in fact this is what *actually* removes Amy from the
            # group
            send_roster_push(stream, '*****@*****.**', ['ladies'])
        else:
            # if the change didn't "stick", this message will revert it
            send_roster_push(stream, '*****@*****.**',
                             ['ladies', 'people starting with A'])

            q.expect('dbus-signal',
                     signal='GroupsCreated',
                     args=[['people starting with A']])
            q.expect('dbus-signal',
                     signal='GroupsChanged',
                     args=[[amy], ['people starting with A'], []])

            sync_dbus(bus, q, conn)
            sync_stream(q, stream)

            check_contact_roster(conn, '*****@*****.**',
                                 ['ladies', 'people starting with A'])

    # sanity check: after all that, we expect Amy to be in group 'ladies' only
    sync_dbus(bus, q, conn)
    sync_stream(q, stream)
    assertEquals(
        {
            cs.CONN_IFACE_CONTACT_GROUPS + '/groups': ['ladies'],
            cs.CONN + '/contact-id': '*****@*****.**'
        },
        conn.Contacts.GetContactAttributes([amy],
                                           [cs.CONN_IFACE_CONTACT_GROUPS],
                                           False)[amy])

    # Rename group 'ladies' to 'girls'
    call_async(q, conn.ContactGroups, 'RenameGroup', 'ladies', 'girls')

    # Amy is added to 'girls'
    e = q.expect('stream-iq',
                 iq_type='set',
                 query_name='query',
                 query_ns=ns.ROSTER)
    jid, groups = parse_roster_change_request(e.query, e.stanza)
    assertEquals('*****@*****.**', jid)
    assertEquals(set(['girls', 'ladies']), groups)

    send_roster_push(stream, '*****@*****.**', ['girls', 'ladies'])
    acknowledge_iq(stream, e.stanza)

    # Amy is removed from 'ladies'
    e = q.expect('stream-iq',
                 iq_type='set',
                 query_name='query',
                 query_ns=ns.ROSTER)
    jid, groups = parse_roster_change_request(e.query, e.stanza)
    assertEquals('*****@*****.**', jid)
    assertEquals(set(['girls']), groups)

    send_roster_push(stream, '*****@*****.**', ['girls'])
    acknowledge_iq(stream, e.stanza)

    q.expect('dbus-return', method='RenameGroup')

    # check everything has been updated
    groups = conn.Properties.Get(cs.CONN_IFACE_CONTACT_GROUPS, 'Groups')
    assertContains('girls', groups)
    assertDoesNotContain('ladies', groups)

    contacts = conn.ContactList.GetContactListAttributes(
        [cs.CONN_IFACE_CONTACT_GROUPS], False)
    assertEquals(['girls'],
                 contacts[amy][cs.CONN_IFACE_CONTACT_GROUPS + '/groups'])
def test(q, bus, mc):
    simulated_cm = SimulatedConnectionManager(q, bus)

    ctl_dir = os.environ['MC_ACCOUNT_DIR']
    old_key_file_name = os.path.join(ctl_dir, 'accounts.cfg')
    newer_key_file_name = os.path.join(os.environ['XDG_DATA_HOME'],
                                       'telepathy', 'mission-control',
                                       'accounts.cfg')

    # We do several scenarios in one MC run, to speed up testing a bit.
    scenarios = ('low', 'priority', 'masked', 'migration', 'absentcm')

    variant_file_names = {}
    low_prio_variant_file_names = {}
    account_paths = {}
    tails = {}

    for s in scenarios:
        variant_file_names[s] = os.path.join(
            os.environ['XDG_DATA_HOME'], 'telepathy', 'mission-control',
            'fakecm-fakeprotocol-dontdivert%s_40example_2ecom0.account' % s)
        tails[s] = ('fakecm/fakeprotocol/dontdivert%s_40example_2ecom0' % s)
        account_paths[s] = cs.ACCOUNT_PATH_PREFIX + tails[s]
        low_prio_variant_file_names[s] = os.path.join(
            os.environ['XDG_DATA_DIRS'].split(':')[0], 'telepathy',
            'mission-control',
            'fakecm-fakeprotocol-dontdivert%s_40example_2ecom0.account' % s)

        try:
            os.makedirs(os.path.dirname(variant_file_names[s]), 0700)
        except OSError as e:
            if e.errno != errno.EEXIST:
                raise

        try:
            os.makedirs(os.path.dirname(low_prio_variant_file_names[s]), 0700)
        except OSError as e:
            if e.errno != errno.EEXIST:
                raise

    # This is deliberately a lower-priority location
    open(low_prio_variant_file_names['low'], 'w').write("""{
'manager': <'fakecm'>,
'protocol': <'fakeprotocol'>,
'DisplayName': <'Account in a low-priority location'>,
'AutomaticPresence': <(uint32 2, 'available', '')>,
'Parameters': <{
    'account': <'*****@*****.**'>,
    'password': <'password_in_variant_file'>,
    'snakes': <uint32 42>
    }>
}
""")

    # This is in a lower-priority location and we don't know the
    # parameters' types yet
    open(low_prio_variant_file_names['migration'], 'w').write("""{
'manager': <'fakecm'>,
'protocol': <'fakeprotocol'>,
'DisplayName': <'Account in a low-priority location with KeyFileParameters'>,
'AutomaticPresence': <(uint32 2, 'available', '')>,
'KeyFileParameters': <{
    'account': '*****@*****.**',
    'password': '******',
    'snakes': '42'
    }>
}
""")

    # This is in a lower-priority location, and we don't know the
    # parameters' types, and we can't learn them by asking the CM
    # because it isn't installed
    open(low_prio_variant_file_names['absentcm'], 'w').write("""{
'manager': <'absentcm'>,
'protocol': <'absentprotocol'>,
'DisplayName': <'Account in a low-priority location with absent CM'>,
'AutomaticPresence': <(uint32 2, 'available', '')>,
'KeyFileParameters': <{
    'account': '*****@*****.**',
    'password': '******',
    'snakes': '42'
    }>
}
""")

    # This version of this account will be used
    open(variant_file_names['priority'], 'w').write("""{
'manager': <'fakecm'>,
'protocol': <'fakeprotocol'>,
'DisplayName': <'Visible'>,
'AutomaticPresence': <(uint32 2, 'available', '')>,
'KeyFileParameters': <{'account': '*****@*****.**',
    'password': '******',
    'snakes': '42'
    }>
}
""")
    # This one won't, because it's "masked" by the higher-priority one
    open(low_prio_variant_file_names['priority'], 'w').write("""{
'manager': <'fakecm'>,
'protocol': <'fakeprotocol'>,
'DisplayName': <'Hidden'>,
'Nickname': <'Hidden'>,
'AutomaticPresence': <(uint32 2, 'available', '')>,
'KeyFileParameters': <{'account': '*****@*****.**',
    'password': '******',
    'snakes': '42'
    }>
}
""")

    # This empty file is considered to "mask" the lower-priority one
    open(variant_file_names['masked'], 'w').write('')
    open(low_prio_variant_file_names['masked'], 'w').write("""{
'manager': <'fakecm'>,
'protocol': <'fakeprotocol'>,
'AutomaticPresence': <(uint32 2, 'available', '')>,
'KeyFileParameters': <{'account': '*****@*****.**',
    'password': '******',
    'snakes': '42'
    }>
}
""")

    mc = MC(q, bus)
    account_manager, properties, interfaces = connect_to_mc(q, bus, mc)

    for s in scenarios:
        if s == 'masked':
            assertDoesNotContain(account_paths[s], properties['ValidAccounts'])
            assertDoesNotContain(account_paths[s],
                                 properties['InvalidAccounts'])
        elif s == 'absentcm':
            assertContains(account_paths[s], properties['InvalidAccounts'])
            assertDoesNotContain(account_paths[s], properties['ValidAccounts'])
        else:
            assertContains(account_paths[s], properties['ValidAccounts'])
            assertDoesNotContain(account_paths[s],
                                 properties['InvalidAccounts'])

    accounts = {}
    account_ifaces = {}

    for s in scenarios:
        if s != 'masked':
            accounts[s] = get_fakecm_account(bus, mc, account_paths[s])
            account_ifaces[s] = dbus.Interface(accounts[s], cs.ACCOUNT)

        if s not in ('masked', 'absentcm'):
            # We can't get untyped parameters if we don't know what types
            # the CM gives them.
            assertEquals(
                42, accounts[s].Properties.Get(cs.ACCOUNT,
                                               'Parameters')['snakes'])
            assertEquals(
                dbus.UInt32,
                type(accounts[s].Properties.Get(cs.ACCOUNT,
                                                'Parameters')['snakes']))

        # Files in lower-priority XDG locations aren't copied until something
        # actually changes, and they aren't deleted.

        if s == 'low':
            assert os.path.exists(low_prio_variant_file_names[s])

    # Delete the password (only), like Empathy 3.0-3.4 do when migrating.
    # This results in the higher-priority file being written out.
    account_ifaces['low'].UpdateParameters({}, ['password'])
    q.expect(
        'dbus-signal',
        path=account_paths['low'],
        signal='AccountPropertyChanged',
        interface=cs.ACCOUNT,
        predicate=(lambda e: 'Parameters' in e.args[0]),
    )
    # Check the account has copied (not moved! XDG_DATA_DIRS are,
    # conceptually, read-only) 'low' from the old to the new name
    assert not os.path.exists(old_key_file_name)
    assert not os.path.exists(newer_key_file_name)
    assert os.path.exists(low_prio_variant_file_names['low'])
    assert os.path.exists(variant_file_names['low'])

    # test that priority works
    assertContains(account_paths["priority"], properties['ValidAccounts'])
    assertEquals('',
                 accounts['priority'].Properties.Get(cs.ACCOUNT, 'Nickname'))
    assertEquals(
        'Visible', accounts['priority'].Properties.Get(cs.ACCOUNT,
                                                       'DisplayName'))

    # test what happens when we delete an account that has a lower-priority
    # "other self": it becomes masked
    assert accounts['priority'].Remove() is None
    assert not os.path.exists(old_key_file_name)
    assert not os.path.exists(newer_key_file_name)
    assert os.path.exists(low_prio_variant_file_names['priority'])
    assert os.path.exists(variant_file_names['priority'])
    assert open(variant_file_names['priority'], 'r').read() == ''
    assertContains('password_in_variant_file',
                   open(low_prio_variant_file_names['priority'], 'r').read())

    # The masked account is still masked
    assert open(variant_file_names['masked'], 'r').read() == ''

    # Because the CM exists, we can work out the correct types
    # for the 'migration' account's parameters. This triggers a commit
    # even though nothing has conceptually changed, so we have the type
    # for later. The file is copied, not moved, because XDG_DATA_DIRS are,
    # conceptually, read-only.
    assert not os.path.exists(old_key_file_name)
    assert not os.path.exists(newer_key_file_name)
    assert os.path.exists(low_prio_variant_file_names['migration'])
    assert os.path.exists(variant_file_names['migration'])
    assertEquals(
        "'password_in_variant_file'",
        account_store('get',
                      'variant-file',
                      'param-password',
                      account=tails['migration']))
    assertEquals(
        "uint32 42",
        account_store('get',
                      'variant-file',
                      'param-snakes',
                      account=tails['migration']))

    # Setting the password still does the right thing.
    account_ifaces['migration'].UpdateParameters({'password': '******'}, [])
    q.expect(
        'dbus-signal',
        path=account_paths['migration'],
        signal='AccountPropertyChanged',
        interface=cs.ACCOUNT,
        predicate=(lambda e: 'Parameters' in e.args[0]),
    )
    assert not os.path.exists(old_key_file_name)
    assert not os.path.exists(newer_key_file_name)
    assert os.path.exists(low_prio_variant_file_names['migration'])
    assert os.path.exists(variant_file_names['migration'])
    assertEquals(
        "'hello'",
        account_store('get',
                      'variant-file',
                      'param-password',
                      account=tails['migration']))

    # 'absentcm' is still only in the low-priority location: we can't
    # known the types of its parameters, so it doesn't get migrated.
    assert not os.path.exists(old_key_file_name)
    assert not os.path.exists(newer_key_file_name)
    assert os.path.exists(low_prio_variant_file_names['absentcm'])
    assert not os.path.exists(variant_file_names['absentcm'])
def cache_full(q, bus, conn, stream):
    # Test how Gabble manages the proxy cache once it's full
    connect_and_announce_alice(q, bus, conn, stream)

    send_file_to_alice(q, conn)

    # 3 proxies are queried (NB_MIN_SOCKS5_PROXIES)
    return_event, e1, e2, e3 = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'),
        EventPattern('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS),
        EventPattern('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS),
        EventPattern('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS))

    send_socks5_reply(stream, e1.stanza)
    send_socks5_reply(stream, e2.stanza)
    send_socks5_reply(stream, e3.stanza)

    proxies = wait_si_and_return_proxies(q, stream)
    assertLength(3, set(proxies))

    oldest_proxy = proxies[2]

    # send another file, one more proxy is queried
    send_file_to_alice(q, conn)

    return_event, e1, = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'),
        EventPattern('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS))

    send_socks5_reply(stream, e1.stanza)

    proxies = wait_si_and_return_proxies(q, stream)
    assertLength(4, set(proxies))

    # the new proxy is the head of the list
    assertEquals(e1.stanza['to'], proxies[0][0])

    # send another file, one more proxy is queried
    send_file_to_alice(q, conn)

    return_event, e1, = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'),
        EventPattern('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS))

    send_socks5_reply(stream, e1.stanza)

    proxies = wait_si_and_return_proxies(q, stream)
    assertLength(5, set(proxies))

    # the new proxy is the head of the list
    assertEquals(e1.stanza['to'], proxies[0][0])

    # send another file, one more proxy is queried
    send_file_to_alice(q, conn)

    return_event, e1, = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'),
        EventPattern('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS))

    send_socks5_reply(stream, e1.stanza)

    proxies = wait_si_and_return_proxies(q, stream)
    # we reached the max size of the cache (FALLBACK_PROXY_CACHE_SIZE) so the
    # oldest proxy has been removed
    assertLength(5, set(proxies))

    # the new proxy is the head of the list
    assertEquals(e1.stanza['to'], proxies[0][0])

    # the oldest proxy has been removed
    assertDoesNotContain(oldest_proxy, proxies)

     #send another file. We already queried all the proxies so the list is recycled
    send_file_to_alice(q, conn)

    # the oldest proxy is re-requested first
    return_event, e1, = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'),
        EventPattern('stream-iq', to=oldest_proxy[0], iq_type='get', query_ns=ns.BYTESTREAMS))
Exemplo n.º 34
0
def cache_full(q, bus, conn, stream):
    # Test how Gabble manages the proxy cache once it's full
    connect_and_announce_alice(q, bus, conn, stream)

    send_file_to_alice(q, conn)

    # 3 proxies are queried (NB_MIN_SOCKS5_PROXIES)
    return_event, e1, e2, e3 = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'),
        EventPattern('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS),
        EventPattern('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS),
        EventPattern('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS))

    send_socks5_reply(stream, e1.stanza)
    send_socks5_reply(stream, e2.stanza)
    send_socks5_reply(stream, e3.stanza)

    proxies = wait_si_and_return_proxies(q, stream)
    assertLength(3, set(proxies))

    oldest_proxy = proxies[2]

    # send another file, one more proxy is queried
    send_file_to_alice(q, conn)

    return_event, e1, = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'),
        EventPattern('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS))

    send_socks5_reply(stream, e1.stanza)

    proxies = wait_si_and_return_proxies(q, stream)
    assertLength(4, set(proxies))

    # the new proxy is the head of the list
    assertEquals(e1.stanza['to'], proxies[0][0])

    # send another file, one more proxy is queried
    send_file_to_alice(q, conn)

    return_event, e1, = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'),
        EventPattern('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS))

    send_socks5_reply(stream, e1.stanza)

    proxies = wait_si_and_return_proxies(q, stream)
    assertLength(5, set(proxies))

    # the new proxy is the head of the list
    assertEquals(e1.stanza['to'], proxies[0][0])

    # send another file, one more proxy is queried
    send_file_to_alice(q, conn)

    return_event, e1, = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'),
        EventPattern('stream-iq', iq_type='get', query_ns=ns.BYTESTREAMS))

    send_socks5_reply(stream, e1.stanza)

    proxies = wait_si_and_return_proxies(q, stream)
    # we reached the max size of the cache (FALLBACK_PROXY_CACHE_SIZE) so the
    # oldest proxy has been removed
    assertLength(5, set(proxies))

    # the new proxy is the head of the list
    assertEquals(e1.stanza['to'], proxies[0][0])

    # the oldest proxy has been removed
    assertDoesNotContain(oldest_proxy, proxies)

    #send another file. We already queried all the proxies so the list is recycled
    send_file_to_alice(q, conn)

    # the oldest proxy is re-requested first
    return_event, e1, = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'),
        EventPattern('stream-iq',
                     to=oldest_proxy[0],
                     iq_type='get',
                     query_ns=ns.BYTESTREAMS))
Exemplo n.º 35
0
def test(q, bus, conn, stream):
    room = '*****@*****.**'
    room_handle, chan, test_handle, bob_handle = \
        join_muc_and_check(q, bus, conn, stream, room)

    # Exercise basic Channel Properties from spec 0.17.7
    channel_props = chan.Properties.GetAll(cs.CHANNEL)
    assertEquals(room_handle, channel_props.get('TargetHandle'))
    assertEquals(cs.HT_ROOM, channel_props.get('TargetHandleType'))
    assertEquals(cs.CHANNEL_TYPE_TEXT, channel_props.get('ChannelType'))

    interfaces = channel_props.get('Interfaces')
    assertContains(cs.CHANNEL_IFACE_GROUP, interfaces)
    assertContains(cs.CHANNEL_IFACE_PASSWORD, interfaces)
    assertDoesNotContain(cs.TP_AWKWARD_PROPERTIES, interfaces)
    assertContains(cs.CHANNEL_IFACE_CHAT_STATE, interfaces)
    assertContains(cs.CHANNEL_IFACE_MESSAGES, interfaces)

    assert channel_props['TargetID'] == '*****@*****.**', channel_props
    assert channel_props['Requested'] == True
    assert channel_props['InitiatorID'] == 'test@localhost'
    assert channel_props['InitiatorHandle'] == conn.GetSelfHandle()

    # Exercise Group Properties from spec 0.17.6 (in a basic way)
    group_props = chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP)
    assert 'HandleOwners' in group_props, group_props
    assert 'Members' in group_props, group_props
    assert 'LocalPendingMembers' in group_props, group_props
    assert 'RemotePendingMembers' in group_props, group_props
    assert 'GroupFlags' in group_props, group_props


    # Test receiving a message from Bob in the MUC
    message = domish.Element((None, 'message'))
    message['from'] = '[email protected]/bob'
    message['type'] = 'groupchat'
    body = message.addElement('body', content='hello')
    stream.send(message)

    received, message_received = q.expect_many(
        EventPattern('dbus-signal', signal='Received'),
        EventPattern('dbus-signal', signal='MessageReceived'),
        )

    # Check Channel.Type.Text.Received:
    # sender: bob
    assert received.args[2] == bob_handle
    # message type: normal
    assert received.args[3] == 0
    # flags: none
    assert received.args[4] == 0
    # body
    assert received.args[5] == 'hello'

    # Check Channel.Interface.Messages.MessageReceived:
    message = message_received.args[0]

    # message should have two parts: the header and one content part
    assert len(message) == 2, message
    header, body = message

    assert header['message-sender'] == bob_handle, header
    # the spec says that message-type "SHOULD be omitted for normal chat
    # messages."
    assert 'message-type' not in header, header

    assert body['content-type'] == 'text/plain', body
    assert body['content'] == 'hello', body


    # Remove the message from the pending message queue, and check that
    # PendingMessagesRemoved fires.
    message_id = header['pending-message-id']

    chan.Text.AcknowledgePendingMessages([message_id])

    removed = q.expect('dbus-signal', signal='PendingMessagesRemoved')

    removed_ids = removed.args[0]
    assert len(removed_ids) == 1, removed_ids
    assert removed_ids[0] == message_id, (removed_ids, message_id)


    # Send an action using the Messages API
    greeting = [
        dbus.Dictionary({ 'message-type': 1, # Action
                        }, signature='sv'),
        { 'content-type': 'text/plain',
          'content': u"peers through a gap in the curtains",
        }
    ]

    # We ask for delivery reports (which MUCs provide) and read reports (which
    # MUCs do not provide).
    sent_token = chan.Messages.SendMessage(greeting,
        cs.MSG_SENDING_FLAGS_REPORT_DELIVERY |
        cs.MSG_SENDING_FLAGS_REPORT_READ)

    assert sent_token

    stream_message, sent, message_sent = q.expect_many(
        EventPattern('stream-message'),
        EventPattern('dbus-signal', signal='Sent'),
        EventPattern('dbus-signal', signal='MessageSent'),
        )

    sent_message, flags, token = message_sent.args
    assert len(sent_message) == 2, sent_message
    header = sent_message[0]
    assert header['message-type'] == 1, header # Action
    assertEquals(test_handle, header['message-sender'])
    assertEquals('[email protected]/test', header['message-sender-id'])
    body = sent_message[1]
    assert body['content-type'] == 'text/plain', body
    assert body['content'] == u'peers through a gap in the curtains', body

    # Of the flags passed to SendMessage, Gabble should only report the
    # DELIVERY flag, since the other is not supported.
    assertEquals(cs.MSG_SENDING_FLAGS_REPORT_DELIVERY, flags)
    assertEquals(sent_token, token)

    assert sent.args[1] == 1, sent.args # Action
    assert sent.args[2] == u'peers through a gap in the curtains', sent.args

    assert message_sent.args[2] == sent_token

    elem = stream_message.stanza
    assert elem.name == 'message'
    assert elem['type'] == 'groupchat', repr(elem)
    assert elem['id'] == sent_token, repr(elem)
    assert elem['to'] == '*****@*****.**', repr(elem)
    for sub_elem in stream_message.stanza.elements():
        if sub_elem.name == 'body':
            found_body = True
            assert sub_elem.children[0] == u'/me peers through a gap in the curtains'
            break
    assert found_body


    # reflect the sent message back to the MUC
    elem['from'] = '[email protected]/test'
    stream.send(elem)

    # Check that we got the corresponding delivery report
    report, old_received = q.expect_many(
        EventPattern('dbus-signal', signal='MessageReceived'),
        EventPattern('dbus-signal', signal='Received'),
        )

    assert len(report.args) == 1, report.args
    parts = report.args[0]
    # The delivery report should just be a header, no body.
    assert len(parts) == 1, parts
    part = parts[0]
    # The intended recipient was the MUC, so there's no contact handle
    # suitable for being 'message-sender'.
    assert 'message-sender' not in part or part['message-sender'] == 0, part
    assert part['message-type'] == 4, part # Message_Type_Delivery_Report
    assert part['delivery-status'] == 1, part # Delivery_Status_Delivered
    assert part['delivery-token'] == sent_token, part
    assert 'delivery-error' not in part, part
    assert 'delivery-echo' in part, part

    # Check that the included echo is from us, and matches all the keys in the
    # message we sent.
    echo = part['delivery-echo']
    assert len(echo) == len(greeting), (echo, greeting)
    assert echo[0]['message-sender'] == test_handle, echo[0]
    assert echo[0]['message-token'] == sent_token, echo[0]
    for i in range(0, len(echo)):
        for key in greeting[i]:
            assert key in echo[i], (i, key, echo)
            assert echo[i][key] == greeting[i][key], (i, key, echo, greeting)

    # The Text.Received signal should be a "you're not tall enough" stub
    id, timestamp, sender, type, flags, text = old_received.args
    assert sender == 0, old_received.args
    assert type == 4, old_received.args # Message_Type_Delivery_Report
    assert flags == 2, old_received.args # Non_Text_Content
    assert text == '', old_received.args


    # Send a normal message using the Channel.Type.Text API
    chan.Text.Send(0, 'goodbye')

    event, sent, message_sent = q.expect_many(
        EventPattern('stream-message'),
        EventPattern('dbus-signal', signal='Sent'),
        EventPattern('dbus-signal', signal='MessageSent'),
        )

    sent_message, flags, _ = message_sent.args
    assert len(sent_message) == 2, sent_message
    header = sent_message[0]
    assert 'message-type' not in header, header # Normal
    body = sent_message[1]
    assert body['content-type'] == 'text/plain', body
    assert body['content'] == u'goodbye', body

    # The caller didn't ask for delivery reports (how could they? they're using
    # the old API), but the server's going to send us an echo anyway, so
    # Gabble's within its rights to pretend that the caller asked.
    assert flags in [0, cs.MSG_SENDING_FLAGS_REPORT_DELIVERY], flags

    assert sent.args[1] == 0, sent.args # Normal
    assert sent.args[2] == u'goodbye', sent.args

    sent_token = message_sent.args[2]

    elem = event.stanza
    assert elem.name == 'message'
    assert elem['type'] == 'groupchat'
    assert elem['id'] == message_sent.args[2]
    body = list(event.stanza.elements())[0]
    assert body.name == 'body'
    assert body.children[0] == u'goodbye'

    # reflect the sent message back to the MUC
    elem['from'] = '[email protected]/test'
    stream.send(elem)

    # TODO: check for a delivery report.


    # test that presence changes are sent via the MUC
    conn.SimplePresence.SetPresence('away', 'hurrah')

    event = q.expect('stream-presence', to='[email protected]/test')
    elem = event.stanza
    show = [e for e in elem.elements() if e.name == 'show'][0]
    assert show
    assert show.children[0] == u'away'
    status = [e for e in elem.elements() if e.name == 'status'][0]
    assert status
    assert status.children[0] == u'hurrah'

    # Check that there's no <x xmlns='.../muc'/> element in the <presence>
    # stanza when we're just updating our presence, as opposed to joining the
    # MUC in the first place. This is a regression test for
    # <https://bugs.freedesktop.org/show_bug.cgi?id=29147>. XEP-0045 §7.4 shows
    # that you do not need to include this element in presence updates; if we
    # erroneously include it, some implementations take this to mean that we're
    # trying to join the MUC again and helpfully send us all the scrollback
    # again.
    x_muc_nodes = xpath.queryForNodes('/presence/x[@xmlns="%s"]' % ns.MUC, elem)
    assert x_muc_nodes is None, elem.toXml()

    # test that leaving the channel results in an unavailable message
    chan.Group.RemoveMembers([chan.Group.GetSelfHandle()], 'booo')

    event = q.expect('stream-presence', to='[email protected]/test')
    elem = event.stanza
    assert elem['type'] == 'unavailable'
    status = [e for e in elem.elements() if e.name == 'status']
    assertLength(1, status)
    assertEquals(status[0].children[0], u'booo')
Exemplo n.º 36
0
def run_test(jp, q, bus, conn, stream, incoming):
    jt2 = JingleTest2(jp, conn, q, stream, "test@localhost", "[email protected]/Foo")
    jt2.prepare()

    self_handle = conn.GetSelfHandle()
    remote_handle = conn.RequestHandles(1, ["[email protected]/Foo"])[0]

    # Advertise that we can do new style calls
    conn.ContactCapabilities.UpdateCapabilities(
        [
            (
                cs.CLIENT + ".CallHandler",
                [
                    {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",
                ],
            )
        ]
    )

    # Ensure a channel that doesn't exist yet.
    if incoming:
        jt2.incoming_call()
    else:
        ret = conn.Requests.CreateChannel(
            {
                cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL,
                cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
                cs.TARGET_HANDLE: remote_handle,
                cs.CALL_INITIAL_AUDIO: True,
            }
        )

    signal = q.expect(
        "dbus-signal",
        signal="NewChannels",
        predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args[0][0][1].values(),
    )

    assertLength(1, signal.args)
    assertLength(1, signal.args[0])  # one channel
    assertLength(2, signal.args[0][0])  # two struct members
    emitted_props = signal.args[0][0][1]

    assertEquals(cs.CHANNEL_TYPE_CALL, emitted_props[cs.CHANNEL_TYPE])

    assertEquals(remote_handle, emitted_props[cs.TARGET_HANDLE])
    assertEquals(cs.HT_CONTACT, emitted_props[cs.TARGET_HANDLE_TYPE])
    assertEquals("*****@*****.**", emitted_props[cs.TARGET_ID])

    assertEquals(not incoming, emitted_props[cs.REQUESTED])
    if incoming:
        assertEquals(remote_handle, emitted_props[cs.INITIATOR_HANDLE])
        assertEquals("*****@*****.**", emitted_props[cs.INITIATOR_ID])
    else:
        assertEquals(self_handle, emitted_props[cs.INITIATOR_HANDLE])
        assertEquals("test@localhost", emitted_props[cs.INITIATOR_ID])

    assertEquals(True, emitted_props[cs.CALL_INITIAL_AUDIO])
    assertEquals(False, emitted_props[cs.CALL_INITIAL_VIDEO])

    chan = bus.get_object(conn.bus_name, signal.args[0][0][0])

    properties = chan.GetAll(cs.CHANNEL_TYPE_CALL, dbus_interface=dbus.PROPERTIES_IFACE)

    # Check if all the properties are there
    assertEquals(
        sorted(
            [
                "Contents",
                "CallMembers",
                "CallState",
                "CallFlags",
                "CallStateReason",
                "CallStateDetails",
                "HardwareStreaming",
                "InitialAudio",
                "InitialAudioName",
                "InitialVideo",
                "InitialVideoName",
                "MutableContents",
            ]
        ),
        sorted(properties.keys()),
    )

    # Remote member is the target
    assertEquals([remote_handle], properties["CallMembers"].keys())
    assertEquals(0, properties["CallMembers"][remote_handle])

    # No Hardware Streaming for you
    assertEquals(False, properties["HardwareStreaming"])

    # Only an audio content
    assertLength(1, properties["Contents"])

    content = bus.get_object(conn.bus_name, properties["Contents"][0])

    content_properties = content.GetAll(cs.CALL_CONTENT, dbus_interface=dbus.PROPERTIES_IFACE)

    # Has one stream
    assertLength(1, content_properties["Streams"])
    assertEquals(cs.CALL_DISPOSITION_INITIAL, content_properties["Disposition"])

    # Implements Content.Interface.Media
    assertEquals([cs.CALL_CONTENT_IFACE_MEDIA], content_properties["Interfaces"])

    # if incoming:
    #    assertEquals (remote_handle, content_properties["Creator"])
    # else:
    #    assertEquals (self_handle, content_properties["Creator"])

    assertContains("Name", content_properties.keys())

    cstream = bus.get_object(conn.bus_name, content_properties["Streams"][0])

    stream_props = cstream.GetAll(cs.CALL_STREAM, dbus_interface=dbus.PROPERTIES_IFACE)

    assertDoesNotContain(self_handle, stream_props["RemoteMembers"].keys())
    assertContains(remote_handle, stream_props["RemoteMembers"].keys())
    assertEquals([cs.CALL_STREAM_IFACE_MEDIA], stream_props["Interfaces"])

    if incoming:
        assertEquals(cs.CALL_SENDING_STATE_PENDING_SEND, stream_props["LocalSendingState"])
        assertEquals(cs.CALL_SENDING_STATE_SENDING, stream_props["RemoteMembers"][remote_handle])
    else:
        assertEquals(cs.CALL_SENDING_STATE_PENDING_SEND, stream_props["RemoteMembers"][remote_handle])
        assertEquals(cs.CALL_SENDING_STATE_PENDING_SEND, stream_props["LocalSendingState"])

    # Media type should audio
    assertEquals(cs.CALL_MEDIA_TYPE_AUDIO, content_properties["Type"])

    # Packetization should be RTP
    content_media_properties = content.GetAll(cs.CALL_CONTENT_IFACE_MEDIA, dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals(cs.CALL_CONTENT_PACKETIZATION_RTP, content_media_properties["Packetization"])

    # Check if the channel is in the right pending state
    if not incoming:
        check_state(q, chan, cs.CALL_STATE_PENDING_INITIATOR)
        chan.Accept(dbus_interface=cs.CHANNEL_TYPE_CALL)

    check_state(q, chan, cs.CALL_STATE_PENDING_RECEIVER, wait=not incoming)

    # Setup codecs
    codecs = jt2.get_call_audio_codecs_dbus()
    if incoming:
        # Act as if we're ringing
        chan.SetRinging(dbus_interface=cs.CHANNEL_TYPE_CALL)
        signal = q.expect("dbus-signal", signal="CallStateChanged")
        assertEquals(cs.CALL_STATE_RINGING, signal.args[1] & cs.CALL_STATE_RINGING)

    # make sure this fails with NotAvailable
    try:
        content.UpdateCodecs(codecs, dbus_interface=cs.CALL_CONTENT_IFACE_MEDIA)
    except DBusException, e:
        if e.get_dbus_name() != cs.NOT_AVAILABLE:
            raise e
Exemplo n.º 37
0
    def reject_stop_receiving(self, content):
        content.stream.RequestReceiving(self.remote_handle, False)

        o = self.q.expect_many(
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                         path=content.stream.__dbus_object_path__),
            EventPattern('dbus-signal',
                         signal='RemoteMembersChanged',
                         path=content.stream.__dbus_object_path__),
            EventPattern('sip-invite'))

        assertLength(0, o[1].args[2])
        assertLength(1, o[1].args[0])
        assertEquals(cs.CALL_SENDING_STATE_PENDING_STOP_SENDING,
                     o[1].args[0][self.remote_handle])
        assertEquals(self.self_handle, o[1].args[3][0])
        assertEquals(cs.CALL_STATE_CHANGE_REASON_USER_REQUESTED,
                     o[1].args[3][1])
        reinvite_event = o[2]

        self.context.check_call_sdp(reinvite_event.sip_message.body,
                                    [('audio', None, 'sendonly')])
        if self.sending:
            body = reinvite_event.sip_message.body.replace(
                'sendonly', 'sendrecv')

        self.context.accept(reinvite_event.sip_message, body)

        ack_cseq = "%s ACK" % reinvite_event.cseq.split()[0]
        self.q.expect('sip-ack', cseq=ack_cseq)

        # Return to regular state

        invite_event = [EventPattern('sip-invite')]

        self.q.forbid_events(invite_event)

        content.stream.RequestReceiving(self.remote_handle, True)

        _, o = self.q.expect_many(
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                         path=content.stream.__dbus_object_path__),
            EventPattern('dbus-signal',
                         signal='RemoteMembersChanged',
                         path=content.stream.__dbus_object_path__,
                         predicate=lambda e: self.remote_handle in e.args[
                             0] and e.args[0][self.remote_handle] == cs.
                         CALL_SENDING_STATE_PENDING_SEND))

        assertLength(1, o.args[0])
        assertLength(0, o.args[2])
        assertEquals(cs.CALL_SENDING_STATE_PENDING_SEND,
                     o.args[0][self.remote_handle])
        assertEquals(self.self_handle, o.args[3][0])
        assertEquals(cs.CALL_STATE_CHANGE_REASON_USER_REQUESTED, o.args[3][1])

        self.context.options_ping(self.q)
        self.q.unforbid_events(invite_event)

        content.stream.Media.CompleteReceivingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STARTED)

        _, reinvite_event = self.q.expect_many(
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STARTED],
                         path=content.stream.__dbus_object_path__),
            EventPattern('sip-invite'))

        assertDoesNotContain('a=sendonly', reinvite_event.sip_message.body)
        assertDoesNotContain('a=recvonly', reinvite_event.sip_message.body)
        assertDoesNotContain('a=inactive', reinvite_event.sip_message.body)
        self.context.check_call_sdp(reinvite_event.sip_message.body)
        self.context.accept(reinvite_event.sip_message)

        ack_cseq = "%s ACK" % reinvite_event.cseq.split()[0]
        o = self.q.expect_many(
            EventPattern('sip-ack', cseq=ack_cseq),
            EventPattern('dbus-signal',
                         signal='RemoteMembersChanged',
                         path=content.stream.__dbus_object_path__))

        assertLength(0, o[1].args[2])
        assertLength(1, o[1].args[0])
        assertEquals(cs.CALL_SENDING_STATE_SENDING,
                     o[1].args[0][self.remote_handle])
    def reject_stop_receiving(self, content):
        content.stream.RequestReceiving(self.remote_handle, False)


        o = self.q.expect_many(
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                         path=content.stream.__dbus_object_path__),
            EventPattern('dbus-signal', signal='RemoteMembersChanged',
                         path=content.stream.__dbus_object_path__),
            EventPattern('sip-invite'))


        assertLength(0, o[1].args[2])
        assertLength(1, o[1].args[0])
        assertEquals(cs.CALL_SENDING_STATE_PENDING_STOP_SENDING,
                     o[1].args[0][self.remote_handle])
        assertEquals(self.self_handle, o[1].args[3][0])
        assertEquals(cs.CALL_STATE_CHANGE_REASON_USER_REQUESTED, o[1].args[3][1])
        reinvite_event = o[2]


        self.context.check_call_sdp(reinvite_event.sip_message.body,
                                    [('audio', None, 'sendonly')])
        if self.sending:
            body = reinvite_event.sip_message.body.replace('sendonly',
                                                           'sendrecv')
        
        self.context.accept(reinvite_event.sip_message, body)

        ack_cseq = "%s ACK" % reinvite_event.cseq.split()[0]
        self.q.expect('sip-ack', cseq=ack_cseq)

        # Return to regular state

        invite_event = [EventPattern('sip-invite')]

        self.q.forbid_events(invite_event)

        content.stream.RequestReceiving(self.remote_handle, True)

        _ , o = self.q.expect_many(
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                         path=content.stream.__dbus_object_path__),
            EventPattern('dbus-signal', signal='RemoteMembersChanged',
                         path=content.stream.__dbus_object_path__,
                         predicate=lambda e: self.remote_handle in e.args[0] and e.args[0][self.remote_handle] == cs.CALL_SENDING_STATE_PENDING_SEND))

        assertLength(1, o.args[0])
        assertLength(0, o.args[2])
        assertEquals(cs.CALL_SENDING_STATE_PENDING_SEND,
                     o.args[0][self.remote_handle])
        assertEquals(self.self_handle, o.args[3][0])
        assertEquals(cs.CALL_STATE_CHANGE_REASON_USER_REQUESTED, o.args[3][1])
        
        self.context.options_ping(self.q)
        self.q.unforbid_events(invite_event)

        content.stream.Media.CompleteReceivingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STARTED)

        _, reinvite_event = self.q.expect_many(
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STARTED],
                         path=content.stream.__dbus_object_path__),
            EventPattern('sip-invite'))

        assertDoesNotContain('a=sendonly', reinvite_event.sip_message.body)
        assertDoesNotContain('a=recvonly', reinvite_event.sip_message.body)
        assertDoesNotContain('a=inactive', reinvite_event.sip_message.body)
        self.context.check_call_sdp(reinvite_event.sip_message.body)
        self.context.accept(reinvite_event.sip_message)

        ack_cseq = "%s ACK" % reinvite_event.cseq.split()[0]
        o = self.q.expect_many(
            EventPattern('sip-ack', cseq=ack_cseq),
            EventPattern('dbus-signal', signal='RemoteMembersChanged',
                         path=content.stream.__dbus_object_path__))

        assertLength(0, o[1].args[2])
        assertLength(1, o[1].args[0])
        assertEquals(cs.CALL_SENDING_STATE_SENDING,
                     o[1].args[0][self.remote_handle])
Exemplo n.º 39
0
def test_ft_caps_from_contact(q, bus, conn, 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 FT capa
    ver = compute_caps_hash([], [ns.IQ_OOB], {})
    txt_record = {
        "txtvers": "1",
        "status": "avail",
        "node": client,
        "ver": ver,
        "hash": "sha-1"
    }
    contact_name = "test-caps-ft@" + get_host_name()
    listener, port = setup_stream_listener(q, contact_name)
    announcer = AvahiAnnouncer(contact_name, "_presence._tcp", port,
                               txt_record)

    # this is the first presence, Salut connects to the contact
    e = q.expect('incoming-connection', listener=listener)
    incoming = e.connection

    # Salut looks up our capabilities
    event = q.expect('stream-iq',
                     connection=incoming,
                     query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + ver, (query_node.attributes['node'], client, ver)

    contact_handle = conn_contacts_iface.GetContactByID(contact_name, [])[0]

    # send good reply
    result = make_result_iq(event.stanza)
    query = result.firstChildElement()
    query['node'] = client + '#' + ver

    feature = query.addElement('feature')
    feature['var'] = ns.IQ_OOB
    incoming.send(result)

    # FT capa is announced
    e = q.expect('dbus-signal',
                 signal='ContactCapabilitiesChanged',
                 predicate=lambda e: contact_handle in e.args[0])
    caps = e.args[0][contact_handle]
    assertContains(ft_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.CONN_IFACE_CONTACT_CAPS + '/capabilities']
    assert caps_via_contacts_iface == caps, caps_via_contacts_iface

    # check if Salut announces the OOB capa
    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")
    self_handle_name = conn.Properties.Get(cs.CONN, "SelfID")

    AvahiListener(q).listen_for_service("_presence._tcp")
    e = q.expect('service-added',
                 name=self_handle_name,
                 protocol=avahi.PROTO_INET)
    service = e.service
    service.resolve()

    receive_presence_and_ask_caps(q, incoming, service, contact_name)

    # capa announced without FT
    ver = compute_caps_hash([], ["http://telepathy.freedesktop.org/xmpp/pony"],
                            {})
    txt_record = {
        "txtvers": "1",
        "status": "avail",
        "node": client,
        "ver": ver,
        "hash": "sha-1"
    }
    contact_name = "test-caps-ft2@" + get_host_name()
    listener, port = setup_stream_listener(q, contact_name)
    announcer = AvahiAnnouncer(contact_name, "_presence._tcp", port,
                               txt_record)

    # this is the first presence, Salut connects to the contact
    e = q.expect('incoming-connection', listener=listener)
    incoming = e.connection

    # Salut looks up our capabilities
    event = q.expect('stream-iq',
                     connection=incoming,
                     query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + ver, (query_node.attributes['node'], client, ver)

    contact_handle = conn_contacts_iface.GetContactByID(contact_name, [])[0]

    # send good reply
    result = make_result_iq(event.stanza)
    query = result.firstChildElement()
    query['node'] = client + '#' + ver

    feature = query.addElement('feature')
    feature['var'] = "http://telepathy.freedesktop.org/xmpp/pony"
    incoming.send(result)

    # the FT capability is not announced
    e = q.expect('dbus-signal', signal='ContactCapabilitiesChanged')
    caps = e.args[0][contact_handle]
    assertDoesNotContain(ft_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.CONN_IFACE_CONTACT_CAPS + '/capabilities']
    assert caps_via_contacts_iface == caps, caps_via_contacts_iface

    # no capabilites announced (assume FT is supported to insure interop)
    txt_record = {"txtvers": "1", "status": "avail"}
    contact_name = "test-caps-ft-no-capa2@" + get_host_name()
    contact_handle = conn_contacts_iface.GetContactByID(contact_name, [])[0]
    listener, port = setup_stream_listener(q, contact_name)
    announcer = AvahiAnnouncer(contact_name, "_presence._tcp", port,
                               txt_record)

    # FT capa is announced
    e = q.expect('dbus-signal',
                 signal='ContactCapabilitiesChanged',
                 predicate=lambda e: contact_handle in e.args[0].keys())

    caps = e.args[0][contact_handle]
    assertContains(ft_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.CONN_IFACE_CONTACT_CAPS + '/capabilities']
    assert caps_via_contacts_iface == caps, caps_via_contacts_iface
def test(q, bus, conn, stream):
    # Ignore conn here, we're only dealing with the CM and Protocol objects.
    cm = bus.get_object(cs.CM + '.haze',
        tp_path_prefix + '/ConnectionManager/haze')
    cm_iface = dbus.Interface(cm, cs.CM)
    cm_props = dbus.Interface(cm, cs.PROPERTIES_IFACE)

    protocols = cm_props.Get(cs.CM, 'Protocols')
    protocol_names = cm_iface.ListProtocols()
    assertEquals(set(protocols.iterkeys()), set(protocol_names))

    for name in protocol_names:
        props = protocols[name]
        protocol = bus.get_object(cm.bus_name,
            cm.object_path + '/' + name.replace('-', '_'))
        protocol_iface = dbus.Interface(protocol, cs.PROTOCOL)
        protocol_props = dbus.Interface(protocol, cs.PROPERTIES_IFACE)
        flat_props = protocol_props.GetAll(cs.PROTOCOL)
        protocol_avatar_props = protocol_props.GetAll(cs.PROTOCOL_IFACE_AVATARS)

        # Protocol is supposed to implement Interface.Avatars iff the
        # connection implements Avatars as well.
        if cs.CONN_IFACE_AVATARS in flat_props['ConnectionInterfaces']:
            assertContains(cs.PROTOCOL_IFACE_AVATARS, props[cs.PROTOCOL + '.Interfaces'])
        else:
            assertDoesNotContain(cs.PROTOCOL_IFACE_AVATARS, props[cs.PROTOCOL + '.Interfaces'])

        parameters = cm_iface.GetParameters(name)
        assertEquals(parameters, props[cs.PROTOCOL + '.Parameters'])
        assertEquals(parameters, flat_props['Parameters'])
        assertEquals(parameters, protocol_props.Get(cs.PROTOCOL, 'Parameters'))

        assertEquals(flat_props['VCardField'],
                props[cs.PROTOCOL + '.VCardField'])
        assertEquals(flat_props['Interfaces'],
                props[cs.PROTOCOL + '.Interfaces'])
        assertEquals(flat_props['EnglishName'],
                props[cs.PROTOCOL + '.EnglishName'])
        assertEquals(flat_props['Icon'], props[cs.PROTOCOL + '.Icon'])
        assertEquals(flat_props['ConnectionInterfaces'],
            props[cs.PROTOCOL + '.ConnectionInterfaces'])
        assertEquals(flat_props['RequestableChannelClasses'],
            props[cs.PROTOCOL + '.RequestableChannelClasses'])

        param_map = {}
        param_flags = {}
        param_type = {}
        param_def = {}

        for p in parameters:
            param_map[p[0]] = tuple(p[1:])
            param_flags[p[0]] = p[1]
            param_type[p[0]] = p[2]
            param_def[p[0]] = p[3]

        # We use special cases to rename these; make sure they don't come back
        assertDoesNotContain(name, ('meanwhile', 'simple'))
        assertDoesNotContain('encoding', param_map)
        assertDoesNotContain('local_charset', param_map)

        if name not in ('local-xmpp', 'irc'):
            # it would be more correct for these protocols not to have this
            # parameter
            assertEquals((cs.PARAM_REQUIRED, 's', ''), param_map['account'])

        # a random selection of checks for known parameters...

        if name == 'gadugadu':
            assertEquals('x-gadugadu', flat_props['VCardField'])
            assertEquals('im-gadugadu', flat_props['Icon'])
            assertEquals((cs.PARAM_SECRET, 's', ''),
                    param_map['password'])
            assertEquals('s', param_type['nick'])
            assertEquals('s', param_type['gg-server'])
        elif name == 'silc':
            assertEquals('x-silc', flat_props['VCardField'])
            assertEquals('im-silc', flat_props['Icon'])
            assertEquals((cs.PARAM_SECRET, 's', ''), param_map['password'])
            assertEquals('s', param_type['server'])
        elif name == 'irc':
            assertEquals('x-irc', flat_props['VCardField'])
            assertEquals('im-irc', flat_props['Icon'])
            assertEquals((cs.PARAM_SECRET, 's', ''), param_map['password'])
            assertEquals('s', param_type['charset'])
            assertEquals('s', param_type['username'])
            assertEquals('s', param_type['realname'])
            assertEquals('s', param_type['server'])
            assertEquals(cs.PARAM_HAS_DEFAULT, param_flags['server'])

            assertEquals('*****@*****.**',
                    protocol_iface.IdentifyAccount({
                        'account': 'smcv',
                        'server': 'irc.debian.org'}))

            assertDoesNotContain(cs.CONN_IFACE_AVATARS, flat_props['ConnectionInterfaces'])
            assertDoesNotContain(cs.CONN_IFACE_CONTACT_BLOCKING, flat_props['ConnectionInterfaces'])
            assertDoesNotContain(cs.CONN_IFACE_MAIL_NOTIFICATION, flat_props['ConnectionInterfaces'])

            # Avatar not supported
            assertEquals(0, protocol_avatar_props['MaximumAvatarBytes'])
            assertEquals(0, protocol_avatar_props['MaximumAvatarHeight'])
            assertEquals(0, protocol_avatar_props['MaximumAvatarWidth'])
            assertEquals(0, protocol_avatar_props['MinimumAvatarHeight'])
            assertEquals(0, protocol_avatar_props['MinimumAvatarWidth'])
            assertEquals(0, protocol_avatar_props['RecommendedAvatarHeight'])
            assertEquals(0, protocol_avatar_props['RecommendedAvatarWidth'])
            assertEquals([], protocol_avatar_props['SupportedAvatarMIMETypes'])
        elif name == 'myspace':
            assertEquals('x-myspace', flat_props['VCardField'])
            assertEquals('im-myspace', flat_props['Icon'])
            assertEquals('s', param_type['server'])
        elif name == 'yahoo':
            assertEquals('x-yahoo', flat_props['VCardField'])
            assertEquals('im-yahoo', flat_props['Icon'])
            assertEquals('s', param_type['charset'])
        elif name == 'yahoojp':
            assertEquals('x-yahoo', flat_props['VCardField'])
            assertEquals('im-yahoojp', flat_props['Icon'])
            assertEquals('s', param_type['charset'])
        elif name == 'aim':
            assertEquals('x-aim', flat_props['VCardField'])
            assertEquals('im-aim', flat_props['Icon'])
            assertEquals('s', param_type['server'])
        elif name == 'msn':
            assertEquals('x-msn', flat_props['VCardField'])
            assertEquals('im-msn', flat_props['Icon'])
            assertEquals('s', param_type['server'])
        elif name == 'jabber':
            assertEquals('x-jabber', flat_props['VCardField'])
            assertEquals('im-jabber', flat_props['Icon'])
            assertDoesNotContain('require_tls', param_map)
            assertDoesNotContain('connect_server', param_map)
            assertEquals((cs.PARAM_SECRET, 's', ''), param_map['password'])
            assertEquals((cs.PARAM_HAS_DEFAULT, 'b', True),
                    param_map['require-encryption'])

            assertEquals('*****@*****.**',
                    protocol_iface.IdentifyAccount({
                        'account': '*****@*****.**',
                        'password': '******'}))
            assertEquals(r'*****@*****.**',
                    protocol_iface.IdentifyAccount({
                        'account': '*****@*****.**',
                        'server': r'corp.example.com',
                        'password': '******'}))

            # this contains an unsupported parameter
            call_async(q, protocol_iface, 'IdentifyAccount',
                    { 'account': '*****@*****.**',
                        'embrace-and-extend': r'WORKGROUP\Bill',
                        'password': '******'})
            q.expect('dbus-error', name=cs.INVALID_ARGUMENT)

            assertContains(cs.CONN_IFACE_AVATARS, flat_props['ConnectionInterfaces'])
            assertContains(cs.CONN_IFACE_CONTACT_BLOCKING, flat_props['ConnectionInterfaces'])
            assertContains(cs.CONN_IFACE_MAIL_NOTIFICATION, flat_props['ConnectionInterfaces'])

            # libpurple currently says there's no max size
            assertEquals(0, protocol_avatar_props['MaximumAvatarBytes'])
            assertEquals(96, protocol_avatar_props['MaximumAvatarHeight'])
            assertEquals(96, protocol_avatar_props['MaximumAvatarWidth'])
            assertEquals(32, protocol_avatar_props['MinimumAvatarHeight'])
            assertEquals(32, protocol_avatar_props['MinimumAvatarWidth'])
            assertEquals(0, protocol_avatar_props['RecommendedAvatarHeight'])
            assertEquals(0, protocol_avatar_props['RecommendedAvatarWidth'])
            assertEquals(['image/png'], protocol_avatar_props['SupportedAvatarMIMETypes'])
        elif name == 'qq':
            assertEquals('x-qq', flat_props['VCardField'])
            assertEquals('im-qq', flat_props['Icon'])
        elif name == 'sametime':
            assertEquals('x-sametime', flat_props['VCardField'])
            assertEquals('im-sametime', flat_props['Icon'])
        elif name == 'zephyr':
            assertEquals('x-zephyr', flat_props['VCardField'])
            assertEquals('im-zephyr', flat_props['Icon'])
            assertEquals('s', param_type['realm'])
            assertEquals('s', param_type['charset'])
        elif name == 'local-xmpp':
            # makes very little sense in an address book
            assertEquals('', flat_props['VCardField'])
            assertEquals('im-local-xmpp', flat_props['Icon'])
            assertEquals((cs.PARAM_REQUIRED, 's', ''), param_map['first-name'])
            assertDoesNotContain('first', param_map)
            assertEquals((cs.PARAM_REQUIRED, 's', ''), param_map['last-name'])
            assertDoesNotContain('last', param_map)
            assertEquals((0, 's', ''), param_map['email'])
            assertEquals((0, 's', ''), param_map['jid'])
        elif name == 'icq':
            assertEquals('x-icq', flat_props['VCardField'])
            assertEquals('im-icq', flat_props['Icon'])
        elif name == 'groupwise':
            assertEquals('x-groupwise', flat_props['VCardField'])
            assertEquals('im-groupwise', flat_props['Icon'])
        elif name == 'sipe':
            assertEquals('im-sipe', flat_props['Icon'])
            assertDoesNotContain('usersplit1', param_map)
            assertEquals((cs.PARAM_HAS_DEFAULT, 's', ''), param_map['login'])

            assertEquals('[email protected],',
                    protocol_iface.IdentifyAccount({
                        'account': '*****@*****.**',
                        'password': '******'}))
            assertEquals(r'[email protected],WORKGROUP\Bill',
                    protocol_iface.IdentifyAccount({
                        'account': '*****@*****.**',
                        'login': r'WORKGROUP\Bill',
                        'password': '******'}))
def test_ft_caps_from_contact(q, bus, conn, 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 FT capa
    ver = compute_caps_hash([], [ns.IQ_OOB], {})
    txt_record = { "txtvers": "1", "status": "avail",
        "node": client, "ver": ver, "hash": "sha-1"}
    contact_name = "test-caps-ft@" + get_host_name()
    listener, port = setup_stream_listener(q, contact_name)
    announcer = AvahiAnnouncer(contact_name, "_presence._tcp", port,
            txt_record)

    # this is the first presence, Salut connects to the contact
    e = q.expect('incoming-connection', listener = listener)
    incoming = e.connection

    # Salut looks up our capabilities
    event = q.expect('stream-iq', connection = incoming,
        query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + ver, (query_node.attributes['node'], client, ver)

    contact_handle = conn_contacts_iface.GetContactByID(contact_name, [])[0]

    # send good reply
    result = make_result_iq(event.stanza)
    query = result.firstChildElement()
    query['node'] = client + '#' + ver

    feature = query.addElement('feature')
    feature['var'] = ns.IQ_OOB
    incoming.send(result)

    # FT capa is announced
    e = q.expect('dbus-signal', signal='ContactCapabilitiesChanged',
            predicate=lambda e: contact_handle in e.args[0])
    caps = e.args[0][contact_handle]
    assertContains(ft_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.CONN_IFACE_CONTACT_CAPS + '/capabilities']
    assert caps_via_contacts_iface == caps, caps_via_contacts_iface

    # check if Salut announces the OOB capa
    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")
    self_handle_name =  conn.Properties.Get(cs.CONN, "SelfID")

    AvahiListener(q).listen_for_service("_presence._tcp")
    e = q.expect('service-added', name = self_handle_name,
            protocol = avahi.PROTO_INET)
    service = e.service
    service.resolve()

    receive_presence_and_ask_caps(q, incoming, service, contact_name)

    # capa announced without FT
    ver = compute_caps_hash([], ["http://telepathy.freedesktop.org/xmpp/pony"], {})
    txt_record = { "txtvers": "1", "status": "avail",
        "node": client, "ver": ver, "hash": "sha-1"}
    contact_name = "test-caps-ft2@" + get_host_name()
    listener, port = setup_stream_listener(q, contact_name)
    announcer = AvahiAnnouncer(contact_name, "_presence._tcp", port,
            txt_record)

    # this is the first presence, Salut connects to the contact
    e = q.expect('incoming-connection', listener = listener)
    incoming = e.connection

    # Salut looks up our capabilities
    event = q.expect('stream-iq', connection = incoming,
        query_ns='http://jabber.org/protocol/disco#info')
    query_node = xpath.queryForNodes('/iq/query', event.stanza)[0]
    assert query_node.attributes['node'] == \
        client + '#' + ver, (query_node.attributes['node'], client, ver)

    contact_handle = conn_contacts_iface.GetContactByID(contact_name, [])[0]

    # send good reply
    result = make_result_iq(event.stanza)
    query = result.firstChildElement()
    query['node'] = client + '#' + ver

    feature = query.addElement('feature')
    feature['var'] = "http://telepathy.freedesktop.org/xmpp/pony"
    incoming.send(result)

    # the FT capability is not announced
    e = q.expect('dbus-signal', signal='ContactCapabilitiesChanged')
    caps = e.args[0][contact_handle]
    assertDoesNotContain(ft_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.CONN_IFACE_CONTACT_CAPS + '/capabilities']
    assert caps_via_contacts_iface == caps, caps_via_contacts_iface

    # no capabilites announced (assume FT is supported to insure interop)
    txt_record = { "txtvers": "1", "status": "avail"}
    contact_name = "test-caps-ft-no-capa2@" + get_host_name()
    contact_handle = conn_contacts_iface.GetContactByID(contact_name, [])[0]
    listener, port = setup_stream_listener(q, contact_name)
    announcer = AvahiAnnouncer(contact_name, "_presence._tcp", port,
            txt_record)

    # FT capa is announced
    e = q.expect('dbus-signal', signal='ContactCapabilitiesChanged',
            predicate=lambda e: contact_handle in e.args[0].keys())

    caps = e.args[0][contact_handle]
    assertContains(ft_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.CONN_IFACE_CONTACT_CAPS + '/capabilities']
    assert caps_via_contacts_iface == caps, caps_via_contacts_iface
Exemplo n.º 42
0
    def store_content(self, content_path, initial = True, incoming = None):
        if incoming is None:
            incoming = self.incoming

        content = wrap_content(self.bus.get_object(self.conn.bus_name,
                    content_path), ['DTMF', 'Media'])
        content_props = content.GetAll(cs.CALL_CONTENT,
                dbus_interface=dbus.PROPERTIES_IFACE)

        # Has one stream
        assertLength(1, content_props["Streams"])
        if initial:
            assertEquals(cs.CALL_DISPOSITION_INITIAL,
                    content_props["Disposition"])
        else:
            assertEquals(cs.CALL_DISPOSITION_NONE, content_props["Disposition"])


        # Implements Content.Interface.Media
        assertContains(cs.CALL_CONTENT_IFACE_MEDIA, content_props["Interfaces"])

        if content_props['Type'] == cs.CALL_MEDIA_TYPE_AUDIO:
            # Implements Content.Interface.DTMF
            assertContains(cs.CALL_CONTENT_IFACE_DTMF,
                    content_props["Interfaces"])

        assertContains("Name", content_props.keys())
        content_name = content_props["Name"]

        stream = self.bus.get_object(self.conn.bus_name,
                content_props["Streams"][0])

        stream_props = stream.GetAll(cs.CALL_STREAM,
                dbus_interface = dbus.PROPERTIES_IFACE)

        assertDoesNotContain(self.self_handle,
                stream_props["RemoteMembers"].keys())
        assertContains(self.peer_handle, stream_props["RemoteMembers"].keys())
        assertEquals([cs.CALL_STREAM_IFACE_MEDIA], stream_props["Interfaces"])
        assertEquals(self.can_change_direction,
                stream_props["CanRequestReceiving"])

        if incoming:
            assertEquals(cs.CALL_SENDING_STATE_PENDING_SEND,
                         stream_props["LocalSendingState"])
            assertEquals(cs.CALL_SENDING_STATE_SENDING,
                         stream_props["RemoteMembers"][self.peer_handle])
        else:
            if initial:
                assertEquals(cs.CALL_SENDING_STATE_PENDING_SEND,
                             stream_props["RemoteMembers"][self.peer_handle])
            else:
                assertEquals(cs.CALL_SENDING_STATE_SENDING,
                             stream_props["RemoteMembers"][self.peer_handle])

            assertEquals(cs.CALL_SENDING_STATE_SENDING,
                         stream_props["LocalSendingState"])

        # Packetization should be RTP
        content_media_props = content.GetAll(cs.CALL_CONTENT_IFACE_MEDIA,
                dbus_interface=dbus.PROPERTIES_IFACE)
        assertEquals(cs.CALL_CONTENT_PACKETIZATION_RTP,
                content_media_props["Packetization"])

        # Check the directions
        stream_media_props = stream.GetAll(cs.CALL_STREAM_IFACE_MEDIA,
                dbus_interface=dbus.PROPERTIES_IFACE)
        if initial or incoming:
            assertEquals(cs.CALL_STREAM_FLOW_STATE_STOPPED,
                         stream_media_props["SendingState"])
        else:
            assertEquals(cs.CALL_STREAM_FLOW_STATE_PENDING_START,
                         stream_media_props["SendingState"])
        if initial:
            assertEquals(cs.CALL_STREAM_FLOW_STATE_STOPPED,
                         stream_media_props["ReceivingState"])
        else:
            assertEquals(cs.CALL_STREAM_FLOW_STATE_PENDING_START,
                         stream_media_props["ReceivingState"])
        assertEquals(False,  stream_media_props["ICERestartPending"])

        # Store the content and stream
        if content_props['Type'] == cs.CALL_MEDIA_TYPE_AUDIO:
            assert self.initial_audio == initial
            assert self.audio_content == None
            assert self.audio_stream == None
            self.audio_content = content
            self.audio_content_name = content_name
            self.audio_stream = stream
        elif content_props['Type'] == cs.CALL_MEDIA_TYPE_VIDEO:
            assert self.initial_video == initial
            assert self.video_content == None
            assert self.video_stream == None
            self.video_content = content
            self.video_content_name = content_name
            self.video_stream = stream
        else:
            assert not 'Bad content type value'
Exemplo n.º 43
0
def test(q, bus, conn, stream):
    event = q.expect('stream-iq', query_ns=ns.ROSTER)
    event.stanza['type'] = 'result'

    item = event.query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'both'
    item.addElement('group', content='women')

    item = event.query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'from'
    item.addElement('group', content='men')

    item = event.query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'to'
    item.addElement('group', content='men')

    stream.send(event.stanza)

    # slight implementation detail: TpBaseContactList emits ContactsChanged
    # etc. before it announces its channels, and it emits one CGC per group.
    s1, s2 = q.expect_many(
        EventPattern('dbus-signal', signal='GroupsChanged',
            interface=cs.CONN_IFACE_CONTACT_GROUPS, path=conn.object_path,
            predicate=lambda e: 'women' in e.args[1]),
        EventPattern('dbus-signal', signal='GroupsChanged',
            interface=cs.CONN_IFACE_CONTACT_GROUPS, path=conn.object_path,
            predicate=lambda e: 'men' in e.args[1]),
        )

    amy, bob, che = conn.RequestHandles(cs.HT_CONTACT,
            ['*****@*****.**', '*****@*****.**', '*****@*****.**'])

    assertEquals([[amy], ['women'], []], s1.args)
    assertEquals([[bob, che], ['men'], []], s2.args)

    pairs = expect_contact_list_signals(q, bus, conn, [], ['men', 'women'])

    q.expect('dbus-signal', signal='ContactListStateChanged',
            args=[cs.CONTACT_LIST_STATE_SUCCESS])

    check_contact_list_signals(q, bus, conn, pairs.pop(0), cs.HT_GROUP,
            'men', ['*****@*****.**', '*****@*****.**'])
    check_contact_list_signals(q, bus, conn, pairs.pop(0), cs.HT_GROUP,
            'women', ['*****@*****.**'])

    assertLength(0, pairs)      # i.e. we've checked all of them

    # change Amy's groups
    call_async(q, conn.ContactGroups, 'SetContactGroups', amy,
            ['ladies', 'people starting with A'])

    s, iq = q.expect_many(
        EventPattern('dbus-signal', signal='GroupsCreated'),
        EventPattern('stream-iq', iq_type='set',
            query_name='query', query_ns=ns.ROSTER),
        )

    assertEquals(set(('ladies', 'people starting with A')), set(s.args[0]))

    jid, groups = parse_roster_change_request(iq.query, iq.stanza)
    assertEquals('*****@*****.**', jid)
    assertEquals(set(('ladies', 'people starting with A')), groups)

    acknowledge_iq(stream, iq.stanza)
    q.expect('dbus-return', method='SetContactGroups')

    # Now the server sends us a roster push.
    send_roster_push(stream, '*****@*****.**', ['people starting with A', 'ladies'])

    # We get a single signal corresponding to that roster push
    e = q.expect('dbus-signal', signal='GroupsChanged',
            predicate=lambda e: e.args[0] == [amy])
    assertEquals(set(['ladies', 'people starting with A']), set(e.args[1]))
    assertEquals(['women'], e.args[2])

    # check that Amy's state is what we expected
    attrs = conn.Contacts.GetContactAttributes([amy],
            [cs.CONN_IFACE_CONTACT_GROUPS], False)[amy]
    # make the group list order-independent
    attrs[cs.CONN_IFACE_CONTACT_GROUPS + '/groups'] = \
        set(attrs[cs.CONN_IFACE_CONTACT_GROUPS + '/groups'])

    assertEquals({ cs.CONN_IFACE_CONTACT_GROUPS + '/groups':
                set(['ladies', 'people starting with A']),
            cs.CONN + '/contact-id': '*****@*****.**' }, attrs)

    for it_worked in (False, True):
        # remove a group with a member (the old API couldn't do this)
        call_async(q, conn.ContactGroups, 'RemoveGroup',
                'people starting with A')

        iq = q.expect('stream-iq', iq_type='set',
                query_name='query', query_ns=ns.ROSTER)

        jid, groups = parse_roster_change_request(iq.query, iq.stanza)
        assertEquals('*****@*****.**', jid)
        assertEquals(set(('ladies',)), groups)

        acknowledge_iq(stream, iq.stanza)

        # we emit these as soon as the IQ is ack'd, so that we can indicate
        # group removal...
        q.expect('dbus-signal', signal='GroupsRemoved',
                args=[['people starting with A']])
        q.expect('dbus-signal', signal='GroupsChanged',
                args=[[amy], [], ['people starting with A']])

        q.expect('dbus-return', method='RemoveGroup')

        if it_worked:
            # ... although in fact this is what *actually* removes Amy from the
            # group
            send_roster_push(stream, '*****@*****.**', ['ladies'])
        else:
            # if the change didn't "stick", this message will revert it
            send_roster_push(stream, '*****@*****.**', ['ladies', 'people starting with A'])

            q.expect('dbus-signal', signal='GroupsCreated',
                    args=[['people starting with A']])
            q.expect('dbus-signal', signal='GroupsChanged',
                    args=[[amy], ['people starting with A'], []])

            sync_dbus(bus, q, conn)
            sync_stream(q, stream)
            assertEquals({
                    cs.CONN_IFACE_CONTACT_GROUPS + '/groups':
                        ['ladies', 'people starting with A'],
                    cs.CONN + '/contact-id':
                        '*****@*****.**' },
                conn.Contacts.GetContactAttributes([amy],
                    [cs.CONN_IFACE_CONTACT_GROUPS], False)[amy])

    # sanity check: after all that, we expect Amy to be in group 'ladies' only
    sync_dbus(bus, q, conn)
    sync_stream(q, stream)
    assertEquals({ cs.CONN_IFACE_CONTACT_GROUPS + '/groups': ['ladies'],
            cs.CONN + '/contact-id': '*****@*****.**' },
        conn.Contacts.GetContactAttributes([amy],
            [cs.CONN_IFACE_CONTACT_GROUPS], False)[amy])

    # Rename group 'ladies' to 'girls'
    call_async(q, conn.ContactGroups, 'RenameGroup', 'ladies', 'girls')

    # Amy is added to 'girls'
    e = q.expect('stream-iq', iq_type='set', query_name='query', query_ns=ns.ROSTER)
    jid, groups = parse_roster_change_request(e.query, e.stanza)
    assertEquals('*****@*****.**', jid)
    assertEquals(set(['girls', 'ladies']), groups)

    send_roster_push(stream, '*****@*****.**', ['girls', 'ladies'])
    acknowledge_iq(stream, e.stanza)

    # Amy is removed from 'ladies'
    e = q.expect('stream-iq', iq_type='set', query_name='query', query_ns=ns.ROSTER)
    jid, groups = parse_roster_change_request(e.query, e.stanza)
    assertEquals('*****@*****.**', jid)
    assertEquals(set(['girls']), groups)

    send_roster_push(stream, '*****@*****.**', ['girls'])
    acknowledge_iq(stream, e.stanza)

    q.expect('dbus-return', method='RenameGroup')

    # check everything has been updated
    groups = conn.Properties.Get(cs.CONN_IFACE_CONTACT_GROUPS, 'Groups')
    assertContains('girls', groups)
    assertDoesNotContain('ladies', groups)

    contacts = conn.ContactList.GetContactListAttributes([cs.CONN_IFACE_CONTACT_GROUPS], False)
    assertEquals(['girls'], contacts[amy][cs.CONN_IFACE_CONTACT_GROUPS + '/groups'])
Exemplo n.º 44
0
    def store_content(self, content_path, initial = True, incoming = None):
        if incoming is None:
            incoming = self.incoming

        content = wrap_content(self.bus.get_object(self.conn.bus_name,
                    content_path))
        content_props = content.GetAll(cs.CALL_CONTENT,
                dbus_interface=dbus.PROPERTIES_IFACE)

        # Has one stream
        assertLength(1, content_props["Streams"])
        if initial:
            assertEquals(cs.CALL_DISPOSITION_INITIAL,
                    content_props["Disposition"])
        else:
            assertEquals(cs.CALL_DISPOSITION_NONE, content_props["Disposition"])


        # Implements Content.Interface.Media
        assertContains(cs.CALL_CONTENT_IFACE_MEDIA, content_props["Interfaces"])

        if content_props['Type'] == cs.CALL_MEDIA_TYPE_AUDIO:
            # Implements Content.Interface.DTMF
            assertContains(cs.CALL_CONTENT_IFACE_DTMF,
                    content_props["Interfaces"])

        assertContains("Name", content_props.keys())
        content_name = content_props["Name"]

        stream = self.bus.get_object(self.conn.bus_name,
                content_props["Streams"][0])

        stream_props = stream.GetAll(cs.CALL_STREAM,
                dbus_interface = dbus.PROPERTIES_IFACE)

        assertDoesNotContain(self.self_handle,
                stream_props["RemoteMembers"].keys())
        assertContains(self.peer_handle, stream_props["RemoteMembers"].keys())
        assertEquals([cs.CALL_STREAM_IFACE_MEDIA], stream_props["Interfaces"])
        assertEquals(self.can_change_direction,
                stream_props["CanRequestReceiving"])

        if incoming:
            assertEquals(cs.CALL_SENDING_STATE_PENDING_SEND,
                         stream_props["LocalSendingState"])
            assertEquals(cs.CALL_SENDING_STATE_SENDING,
                         stream_props["RemoteMembers"][self.peer_handle])
        else:
            if initial:
                assertEquals(cs.CALL_SENDING_STATE_PENDING_SEND,
                             stream_props["RemoteMembers"][self.peer_handle])
            else:
                assertEquals(cs.CALL_SENDING_STATE_SENDING,
                             stream_props["RemoteMembers"][self.peer_handle])

            assertEquals(cs.CALL_SENDING_STATE_SENDING,
                         stream_props["LocalSendingState"])

        # Packetization should be RTP
        content_media_props = content.GetAll(cs.CALL_CONTENT_IFACE_MEDIA,
                dbus_interface=dbus.PROPERTIES_IFACE)
        assertEquals(cs.CALL_CONTENT_PACKETIZATION_RTP,
                content_media_props["Packetization"])

        # Check the directions
        stream_media_props = stream.GetAll(cs.CALL_STREAM_IFACE_MEDIA,
                dbus_interface=dbus.PROPERTIES_IFACE)
        if initial or incoming:
            assertEquals(cs.CALL_STREAM_FLOW_STATE_STOPPED,
                         stream_media_props["SendingState"])
        else:
            assertEquals(cs.CALL_STREAM_FLOW_STATE_PENDING_START,
                         stream_media_props["SendingState"])
        if initial:
            assertEquals(cs.CALL_STREAM_FLOW_STATE_STOPPED,
                         stream_media_props["ReceivingState"])
        else:
            assertEquals(cs.CALL_STREAM_FLOW_STATE_PENDING_START,
                         stream_media_props["ReceivingState"])
        assertEquals(False,  stream_media_props["ICERestartPending"])

        # Store the content and stream
        if content_props['Type'] == cs.CALL_MEDIA_TYPE_AUDIO:
            assert self.initial_audio == initial
            assert self.audio_content == None
            assert self.audio_stream == None
            self.audio_content = content
            self.audio_content_name = content_name
            self.audio_stream = stream
        elif content_props['Type'] == cs.CALL_MEDIA_TYPE_VIDEO:
            assert self.initial_video == initial
            assert self.video_content == None
            assert self.video_stream == None
            self.video_content = content
            self.video_content_name = content_name
            self.video_stream = stream
        else:
            assert not 'Bad content type value'
Exemplo n.º 45
0
def test(q, bus, conn, stream):
    event = q.expect('stream-iq', query_ns=ns.ROSTER)
    event.stanza['type'] = 'result'

    item = event.query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'both'
    item.addElement('group', content='women')

    item = event.query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'from'
    item.addElement('group', content='men')

    item = event.query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'to'
    item.addElement('group', content='men')

    stream.send(event.stanza)

    # Avoid relying on the implementation detail of exactly when
    # TpBaseContactList emits ContactsChanged, relative to when it
    # announces its channels. Prior to 0.20.3, 0.21.1 it would
    # announce the channels, emit GroupsChanged, then announce the channels
    # again... which was a bug, but it turned out this test relied on it.
    #
    # We do still rely on the implementation detail that we emit GroupsChanged
    # once per group with all of its members, not once per contact with all
    # of their groups. On a typical contact list, there are more contacts
    # than groups, so that'll work out smaller.

    q.expect_many(
            EventPattern('dbus-signal', signal='GroupsCreated',
                interface=cs.CONN_IFACE_CONTACT_GROUPS,
                path=conn.object_path,
                predicate=lambda e: groups_created_predicate(e, ['men', 'women'])),
            EventPattern('dbus-signal', signal='GroupsChanged',
                interface=cs.CONN_IFACE_CONTACT_GROUPS,
                path=conn.object_path,
                predicate=lambda e: groups_changed_predicate(e, conn, ['*****@*****.**'], ['women'], [])),
            EventPattern('dbus-signal', signal='GroupsChanged',
                interface=cs.CONN_IFACE_CONTACT_GROUPS,
                path=conn.object_path,
                predicate=lambda e: groups_changed_predicate(e, conn, ['*****@*****.**', '*****@*****.**'], ['men'], [])),
            )

    amy, bob, che = conn.get_contact_handles_sync(
            ['*****@*****.**', '*****@*****.**', '*****@*****.**'])

    q.expect('dbus-signal', signal='ContactListStateChanged',
            args=[cs.CONTACT_LIST_STATE_SUCCESS])

    # change Amy's groups
    call_async(q, conn.ContactGroups, 'SetContactGroups', amy,
            ['ladies', 'people starting with A'])

    s, iq = q.expect_many(
        EventPattern('dbus-signal', signal='GroupsCreated'),
        EventPattern('stream-iq', iq_type='set',
            query_name='query', query_ns=ns.ROSTER),
        )

    assertEquals(set(('ladies', 'people starting with A')), set(s.args[0]))

    jid, groups = parse_roster_change_request(iq.query, iq.stanza)
    assertEquals('*****@*****.**', jid)
    assertEquals(set(('ladies', 'people starting with A')), groups)

    acknowledge_iq(stream, iq.stanza)
    q.expect('dbus-return', method='SetContactGroups')

    # Now the server sends us a roster push.
    send_roster_push(stream, '*****@*****.**', ['people starting with A', 'ladies'])

    # We get a single signal corresponding to that roster push
    e = q.expect('dbus-signal', signal='GroupsChanged',
            predicate=lambda e: e.args[0] == [amy])
    assertEquals(set(['ladies', 'people starting with A']), set(e.args[1]))
    assertEquals(['women'], e.args[2])

    # check that Amy's state is what we expected
    attrs = conn.Contacts.GetContactAttributes([amy],
            [cs.CONN_IFACE_CONTACT_GROUPS], False)[amy]
    # make the group list order-independent
    attrs[cs.CONN_IFACE_CONTACT_GROUPS + '/groups'] = \
        set(attrs[cs.CONN_IFACE_CONTACT_GROUPS + '/groups'])

    assertEquals({ cs.CONN_IFACE_CONTACT_GROUPS + '/groups':
                set(['ladies', 'people starting with A']),
            cs.CONN + '/contact-id': '*****@*****.**' }, attrs)

    for it_worked in (False, True):
        # remove a group with a member (the old API couldn't do this)
        call_async(q, conn.ContactGroups, 'RemoveGroup',
                'people starting with A')

        iq = q.expect('stream-iq', iq_type='set',
                query_name='query', query_ns=ns.ROSTER)

        jid, groups = parse_roster_change_request(iq.query, iq.stanza)
        assertEquals('*****@*****.**', jid)
        assertEquals(set(('ladies',)), groups)

        acknowledge_iq(stream, iq.stanza)

        # we emit these as soon as the IQ is ack'd, so that we can indicate
        # group removal...
        q.expect('dbus-signal', signal='GroupsRemoved',
                args=[['people starting with A']])
        q.expect('dbus-signal', signal='GroupsChanged',
                args=[[amy], [], ['people starting with A']])

        q.expect('dbus-return', method='RemoveGroup')

        if it_worked:
            # ... although in fact this is what *actually* removes Amy from the
            # group
            send_roster_push(stream, '*****@*****.**', ['ladies'])
        else:
            # if the change didn't "stick", this message will revert it
            send_roster_push(stream, '*****@*****.**', ['ladies', 'people starting with A'])

            q.expect('dbus-signal', signal='GroupsCreated',
                    args=[['people starting with A']])
            q.expect('dbus-signal', signal='GroupsChanged',
                    args=[[amy], ['people starting with A'], []])

            sync_dbus(bus, q, conn)
            sync_stream(q, stream)

            check_contact_roster(conn, '*****@*****.**', ['ladies', 'people starting with A'])

    # sanity check: after all that, we expect Amy to be in group 'ladies' only
    sync_dbus(bus, q, conn)
    sync_stream(q, stream)
    assertEquals({ cs.CONN_IFACE_CONTACT_GROUPS + '/groups': ['ladies'],
            cs.CONN + '/contact-id': '*****@*****.**' },
        conn.Contacts.GetContactAttributes([amy],
            [cs.CONN_IFACE_CONTACT_GROUPS], False)[amy])

    # Rename group 'ladies' to 'girls'
    call_async(q, conn.ContactGroups, 'RenameGroup', 'ladies', 'girls')

    # Amy is added to 'girls'
    e = q.expect('stream-iq', iq_type='set', query_name='query', query_ns=ns.ROSTER)
    jid, groups = parse_roster_change_request(e.query, e.stanza)
    assertEquals('*****@*****.**', jid)
    assertEquals(set(['girls', 'ladies']), groups)

    send_roster_push(stream, '*****@*****.**', ['girls', 'ladies'])
    acknowledge_iq(stream, e.stanza)

    # Amy is removed from 'ladies'
    e = q.expect('stream-iq', iq_type='set', query_name='query', query_ns=ns.ROSTER)
    jid, groups = parse_roster_change_request(e.query, e.stanza)
    assertEquals('*****@*****.**', jid)
    assertEquals(set(['girls']), groups)

    send_roster_push(stream, '*****@*****.**', ['girls'])
    acknowledge_iq(stream, e.stanza)

    q.expect('dbus-return', method='RenameGroup')

    # check everything has been updated
    groups = conn.Properties.Get(cs.CONN_IFACE_CONTACT_GROUPS, 'Groups')
    assertContains('girls', groups)
    assertDoesNotContain('ladies', groups)

    contacts = conn.ContactList.GetContactListAttributes([cs.CONN_IFACE_CONTACT_GROUPS], False)
    assertEquals(['girls'], contacts[amy][cs.CONN_IFACE_CONTACT_GROUPS + '/groups'])
Exemplo n.º 46
0
def test(q, bus, conn, stream):
    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
    send_disco_reply(stream, event.stanza, [], features)

    # 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.
    send_disco_reply(stream, disco2.stanza, [], features)

    # Now the resourceful JID replies:
    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])
def test(q, bus, mc):
    simulated_cm = SimulatedConnectionManager(q, bus)

    ctl_dir = os.environ['MC_ACCOUNT_DIR']
    old_key_file_name = os.path.join(ctl_dir, 'accounts.cfg')
    newer_key_file_name = os.path.join(os.environ['XDG_DATA_HOME'],
            'telepathy', 'mission-control', 'accounts.cfg')

    # We do several scenarios in one MC run, to speed up testing a bit.
    scenarios = ('low', 'priority', 'masked', 'migration', 'absentcm')

    variant_file_names = {}
    low_prio_variant_file_names = {}
    account_paths = {}
    tails = {}

    for s in scenarios:
        variant_file_names[s] = os.path.join(os.environ['XDG_DATA_HOME'],
                'telepathy', 'mission-control',
                'fakecm-fakeprotocol-dontdivert%s_40example_2ecom0.account'
                    % s)
        tails[s] = ('fakecm/fakeprotocol/dontdivert%s_40example_2ecom0' % s)
        account_paths[s] = cs.ACCOUNT_PATH_PREFIX + tails[s]
        low_prio_variant_file_names[s] = os.path.join(
                os.environ['XDG_DATA_DIRS'].split(':')[0],
                'telepathy', 'mission-control',
                'fakecm-fakeprotocol-dontdivert%s_40example_2ecom0.account' %
                    s)

        try:
            os.makedirs(os.path.dirname(variant_file_names[s]), 0700)
        except OSError as e:
            if e.errno != errno.EEXIST:
                raise

        try:
            os.makedirs(os.path.dirname(low_prio_variant_file_names[s]), 0700)
        except OSError as e:
            if e.errno != errno.EEXIST:
                raise

    # This is deliberately a lower-priority location
    open(low_prio_variant_file_names['low'], 'w').write(
"""{
'manager': <'fakecm'>,
'protocol': <'fakeprotocol'>,
'DisplayName': <'Account in a low-priority location'>,
'AutomaticPresence': <(uint32 2, 'available', '')>,
'Parameters': <{
    'account': <'*****@*****.**'>,
    'password': <'password_in_variant_file'>,
    'snakes': <uint32 42>
    }>
}
""")

    # This is in a lower-priority location and we don't know the
    # parameters' types yet
    open(low_prio_variant_file_names['migration'], 'w').write(
"""{
'manager': <'fakecm'>,
'protocol': <'fakeprotocol'>,
'DisplayName': <'Account in a low-priority location with KeyFileParameters'>,
'AutomaticPresence': <(uint32 2, 'available', '')>,
'KeyFileParameters': <{
    'account': '*****@*****.**',
    'password': '******',
    'snakes': '42'
    }>
}
""")

    # This is in a lower-priority location, and we don't know the
    # parameters' types, and we can't learn them by asking the CM
    # because it isn't installed
    open(low_prio_variant_file_names['absentcm'], 'w').write(
"""{
'manager': <'absentcm'>,
'protocol': <'absentprotocol'>,
'DisplayName': <'Account in a low-priority location with absent CM'>,
'AutomaticPresence': <(uint32 2, 'available', '')>,
'KeyFileParameters': <{
    'account': '*****@*****.**',
    'password': '******',
    'snakes': '42'
    }>
}
""")

    # This version of this account will be used
    open(variant_file_names['priority'], 'w').write("""{
'manager': <'fakecm'>,
'protocol': <'fakeprotocol'>,
'DisplayName': <'Visible'>,
'AutomaticPresence': <(uint32 2, 'available', '')>,
'KeyFileParameters': <{'account': '*****@*****.**',
    'password': '******',
    'snakes': '42'
    }>
}
""")
    # This one won't, because it's "masked" by the higher-priority one
    open(low_prio_variant_file_names['priority'], 'w').write("""{
'manager': <'fakecm'>,
'protocol': <'fakeprotocol'>,
'DisplayName': <'Hidden'>,
'Nickname': <'Hidden'>,
'AutomaticPresence': <(uint32 2, 'available', '')>,
'KeyFileParameters': <{'account': '*****@*****.**',
    'password': '******',
    'snakes': '42'
    }>
}
""")

    # This empty file is considered to "mask" the lower-priority one
    open(variant_file_names['masked'], 'w').write('')
    open(low_prio_variant_file_names['masked'], 'w').write("""{
'manager': <'fakecm'>,
'protocol': <'fakeprotocol'>,
'AutomaticPresence': <(uint32 2, 'available', '')>,
'KeyFileParameters': <{'account': '*****@*****.**',
    'password': '******',
    'snakes': '42'
    }>
}
""")

    mc = MC(q, bus)
    account_manager, properties, interfaces = connect_to_mc(q, bus, mc)

    for s in scenarios:
        if s == 'masked':
            assertDoesNotContain(account_paths[s], properties['ValidAccounts'])
            assertDoesNotContain(account_paths[s], properties['InvalidAccounts'])
        elif s == 'absentcm':
            assertContains(account_paths[s], properties['InvalidAccounts'])
            assertDoesNotContain(account_paths[s], properties['ValidAccounts'])
        else:
            assertContains(account_paths[s], properties['ValidAccounts'])
            assertDoesNotContain(account_paths[s], properties['InvalidAccounts'])

    accounts = {}
    account_ifaces = {}

    for s in scenarios:
        if s != 'masked':
            accounts[s] = get_fakecm_account(bus, mc, account_paths[s])
            account_ifaces[s] = dbus.Interface(accounts[s], cs.ACCOUNT)

        if s not in ('masked', 'absentcm'):
            # We can't get untyped parameters if we don't know what types
            # the CM gives them.
            assertEquals(42, accounts[s].Properties.Get(cs.ACCOUNT,
                'Parameters')['snakes'])
            assertEquals(dbus.UInt32,
                    type(accounts[s].Properties.Get(cs.ACCOUNT,
                        'Parameters')['snakes']))

        # Files in lower-priority XDG locations aren't copied until something
        # actually changes, and they aren't deleted.

        if s == 'low':
            assert os.path.exists(low_prio_variant_file_names[s])

    # Delete the password (only), like Empathy 3.0-3.4 do when migrating.
    # This results in the higher-priority file being written out.
    account_ifaces['low'].UpdateParameters({}, ['password'])
    q.expect('dbus-signal',
            path=account_paths['low'],
            signal='AccountPropertyChanged',
            interface=cs.ACCOUNT,
            predicate=(lambda e:
                'Parameters' in e.args[0]),
            )
    # Check the account has copied (not moved! XDG_DATA_DIRS are,
    # conceptually, read-only) 'low' from the old to the new name
    assert not os.path.exists(old_key_file_name)
    assert not os.path.exists(newer_key_file_name)
    assert os.path.exists(low_prio_variant_file_names['low'])
    assert os.path.exists(variant_file_names['low'])

    # test that priority works
    assertContains(account_paths["priority"], properties['ValidAccounts'])
    assertEquals('',
            accounts['priority'].Properties.Get(cs.ACCOUNT, 'Nickname'))
    assertEquals('Visible',
            accounts['priority'].Properties.Get(cs.ACCOUNT, 'DisplayName'))

    # test what happens when we delete an account that has a lower-priority
    # "other self": it becomes masked
    assert accounts['priority'].Remove() is None
    assert not os.path.exists(old_key_file_name)
    assert not os.path.exists(newer_key_file_name)
    assert os.path.exists(low_prio_variant_file_names['priority'])
    assert os.path.exists(variant_file_names['priority'])
    assert open(variant_file_names['priority'], 'r').read() == ''
    assertContains('password_in_variant_file',
            open(low_prio_variant_file_names['priority'], 'r').read())

    # The masked account is still masked
    assert open(variant_file_names['masked'], 'r').read() == ''

    # Because the CM exists, we can work out the correct types
    # for the 'migration' account's parameters. This triggers a commit
    # even though nothing has conceptually changed, so we have the type
    # for later. The file is copied, not moved, because XDG_DATA_DIRS are,
    # conceptually, read-only.
    assert not os.path.exists(old_key_file_name)
    assert not os.path.exists(newer_key_file_name)
    assert os.path.exists(low_prio_variant_file_names['migration'])
    assert os.path.exists(variant_file_names['migration'])
    assertEquals("'password_in_variant_file'",
        account_store('get', 'variant-file', 'param-password',
            account=tails['migration']))
    assertEquals("uint32 42", account_store('get', 'variant-file',
        'param-snakes', account=tails['migration']))

    # Setting the password still does the right thing.
    account_ifaces['migration'].UpdateParameters({'password': '******'}, [])
    q.expect('dbus-signal',
            path=account_paths['migration'],
            signal='AccountPropertyChanged',
            interface=cs.ACCOUNT,
            predicate=(lambda e:
                'Parameters' in e.args[0]),
            )
    assert not os.path.exists(old_key_file_name)
    assert not os.path.exists(newer_key_file_name)
    assert os.path.exists(low_prio_variant_file_names['migration'])
    assert os.path.exists(variant_file_names['migration'])
    assertEquals("'hello'",
        account_store('get', 'variant-file', 'param-password',
            account=tails['migration']))

    # 'absentcm' is still only in the low-priority location: we can't
    # known the types of its parameters, so it doesn't get migrated.
    assert not os.path.exists(old_key_file_name)
    assert not os.path.exists(newer_key_file_name)
    assert os.path.exists(low_prio_variant_file_names['absentcm'])
    assert not os.path.exists(variant_file_names['absentcm'])