Пример #1
0
def test(q, bus, mc):
    # For this test, we should never actually be asked to make a channel.
    forbidden = [
        EventPattern('dbus-method-call', method='CreateChannel'),
        EventPattern('dbus-method-call', method='EnsureChannel'),
        EventPattern('dbus-method-call', method='ObserveChannels'),
        EventPattern('dbus-method-call', method='AddDispatchOperation'),
        EventPattern('dbus-method-call', method='HandleChannels'),
    ]
    q.forbid_events(forbidden)

    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******"
        },
        signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

    fixed_properties = dbus.Dictionary(
        {
            cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT,
            cs.CHANNEL + '.ChannelType': FORBIDDEN_CTYPE,
        },
        signature='sv')

    client = SimulatedClient(q,
                             bus,
                             'Empathy',
                             observe=[fixed_properties],
                             approve=[fixed_properties],
                             handle=[fixed_properties],
                             bypass_approval=False)

    # wait for MC to download the properties
    expect_client_setup(q, [client])

    user_action_time = dbus.Int64(1238582606)

    cd = bus.get_object(cs.CD, cs.CD_PATH)
    cd_props = dbus.Interface(cd, cs.PROPERTIES_IFACE)

    # UI calls ChannelDispatcher.CreateChannel
    request = dbus.Dictionary(
        {
            cs.CHANNEL + '.ChannelType': FORBIDDEN_CTYPE,
            cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT,
            cs.CHANNEL + '.TargetID': 'juliet',
        },
        signature='sv')
    call_async(q,
               cd,
               'CreateChannel',
               account.object_path,
               request,
               user_action_time,
               client.bus_name,
               dbus_interface=cs.CD)

    ret = q.expect('dbus-return', method='CreateChannel')
    request_path = ret.value[0]

    # UI connects to signals and calls ChannelRequest.Proceed()

    cr = bus.get_object(cs.AM, request_path)
    request_props = cr.GetAll(cs.CR, dbus_interface=cs.PROPERTIES_IFACE)
    assert request_props['Account'] == account.object_path
    assert request_props['Requests'] == [request]
    assert request_props['UserActionTime'] == user_action_time
    assert request_props['PreferredHandler'] == client.bus_name
    assert request_props['Interfaces'] == []

    call_async(q, cr, 'Proceed', dbus_interface=cs.CR)

    q.expect('dbus-return', method='Proceed')
    q.expect('dbus-signal',
             path=cr.object_path,
             interface=cs.CR,
             signal='Failed',
             args=[cs.PERMISSION_DENIED, "No, you don't"])
def no_muji_presences(muc):
    return EventPattern(
        'stream-presence',
        to=muc + "/test",
        predicate=lambda x: xpath.queryForNodes("/presence/muji", x.stanza))
Пример #3
0
def test(q, bus, conn, stream, bytestream_cls, address_type, access_control,
         access_control_param):
    address1 = t.set_up_echo(q, address_type, True, streamfile='stream')
    address2 = t.set_up_echo(q, address_type, True, streamfile='stream2')

    t.check_conn_properties(q, conn)

    vcard_event, roster_event = q.expect_many(
        EventPattern('stream-iq',
                     to=None,
                     query_ns='vcard-temp',
                     query_name='vCard'),
        EventPattern('stream-iq', query_ns=ns.ROSTER))

    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")

    acknowledge_iq(stream, vcard_event.stanza)

    roster = roster_event.stanza
    roster['type'] = 'result'
    item = roster_event.query.addElement('item')
    item['jid'] = 'bob@localhost'  # Bob can do tubes
    item['subscription'] = 'both'
    stream.send(roster)

    bob_full_jid = 'bob@localhost/Bob'
    self_full_jid = 'test@localhost/Resource'

    # Send Bob presence and his tube caps
    presence = domish.Element(('jabber:client', 'presence'))
    presence['from'] = bob_full_jid
    presence['to'] = self_full_jid
    c = presence.addElement('c')
    c['xmlns'] = 'http://jabber.org/protocol/caps'
    c['node'] = 'http://example.com/ICantBelieveItsNotTelepathy'
    c['ver'] = '1.2.3'
    stream.send(presence)

    event = q.expect('stream-iq',
                     iq_type='get',
                     query_ns='http://jabber.org/protocol/disco#info',
                     to=bob_full_jid)
    assert event.query['node'] == \
        'http://example.com/ICantBelieveItsNotTelepathy#1.2.3'
    result = make_result_iq(stream, event.stanza)
    query = result.firstChildElement()
    feature = query.addElement('feature')
    feature['var'] = ns.TUBES
    stream.send(result)

    # A tube request can be done only if the contact has tube capabilities
    # Ensure that Bob's caps have been received
    sync_stream(q, stream)

    # Also ensure that all the new contact list channels have been announced,
    # so that the NewChannel(s) signals we look for after calling
    # RequestChannel are the ones we wanted.
    sync_dbus(bus, q, conn)

    # Test tubes with Bob. Bob has tube capabilities.
    bob_handle = conn.get_contact_handle_sync('bob@localhost')

    # Try CreateChannel with correct properties
    # Gabble must succeed
    call_async(
        q, conn.Requests, 'CreateChannel', {
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE,
            cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
            cs.TARGET_HANDLE: bob_handle,
            cs.STREAM_TUBE_SERVICE: "newecho",
        })

    def find_stream_tube(channels):
        for path, props in channels:
            if props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE:
                return path, props

        return None, None

    def new_chan_predicate(e):
        path, _ = find_stream_tube(e.args[0])
        return path is not None

    ret, new_sig = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'),
        EventPattern('dbus-signal',
                     signal='NewChannels',
                     predicate=new_chan_predicate),
    )

    new_chan_path = ret.value[0]
    new_chan_prop_asv = ret.value[1]
    # State and Parameters are mutables so not announced
    assert cs.TUBE_STATE not in new_chan_prop_asv
    assert cs.TUBE_PARAMETERS not in new_chan_prop_asv
    assert new_chan_path.find("StreamTube") != -1, new_chan_path
    assert new_chan_path.find("SITubesChannel") == -1, new_chan_path

    new_tube_chan = bus.get_object(conn.bus_name, new_chan_path)
    new_tube_iface = dbus.Interface(new_tube_chan, cs.CHANNEL_TYPE_STREAM_TUBE)

    # check State and Parameters
    new_tube_props = new_tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE,
                                          dbus_interface=cs.PROPERTIES_IFACE)

    # the tube created using the new API is in the "not offered" state
    assert new_tube_props['State'] == cs.TUBE_CHANNEL_STATE_NOT_OFFERED

    _, stream_tube_channel_properties = find_stream_tube(new_sig.args[0])
    assert cs.TUBE_STATE not in stream_tube_channel_properties
    assert cs.TUBE_PARAMETERS not in stream_tube_channel_properties

    # Offer the first tube created
    call_async(q, new_tube_iface, 'Offer', address_type, address2,
               access_control, new_sample_parameters)

    msg_event, state_event = q.expect_many(
        EventPattern('stream-message'),
        EventPattern('dbus-signal', signal='TubeChannelStateChanged'))

    assert state_event.args[0] == cs.TUBE_CHANNEL_STATE_REMOTE_PENDING

    message = msg_event.stanza
    assert message['to'] == bob_full_jid
    tube_nodes = xpath.queryForNodes('/message/tube[@xmlns="%s"]' % ns.TUBES,
                                     message)
    assert tube_nodes is not None
    assert len(tube_nodes) == 1
    tube = tube_nodes[0]

    assert tube['service'] == 'newecho'
    assert tube['type'] == 'stream'
    assert not tube.hasAttribute('initiator')
    stream_tube_id = int(tube['id'])

    params = {}
    parameter_nodes = xpath.queryForNodes('/tube/parameters/parameter', tube)
    for node in parameter_nodes:
        assert node['name'] not in params
        params[node['name']] = (node['type'], str(node))
    assert params == {
        'ay': ('bytes', 'bmV3aGVsbG8='),
        's': ('str', 'newhello'),
        'i': ('int', '-123'),
        'u': ('uint', '123'),
    }

    # The new tube has been offered, the parameters cannot be changed anymore
    # We need to use call_async to check the error
    tube_prop_iface = dbus.Interface(new_tube_chan, cs.PROPERTIES_IFACE)
    call_async(q,
               tube_prop_iface,
               'Set',
               cs.CHANNEL_IFACE_TUBE,
               'Parameters',
               dbus.Dictionary({dbus.String(u'foo2'): dbus.String(u'bar2')},
                               signature=dbus.Signature('sv')),
               dbus_interface=cs.PROPERTIES_IFACE)
    set_error = q.expect('dbus-error')
    # check it is *not* correctly changed
    new_tube_props = new_tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE,
                                          dbus_interface=cs.PROPERTIES_IFACE,
                                          byte_arrays=True)
    assert new_tube_props.get("Parameters") == new_sample_parameters, \
            new_tube_props.get("Parameters")

    # The CM is the server, so fake a client wanting to talk to it
    # Old API tube
    bytestream1 = bytestream_cls(stream, q, 'alpha', bob_full_jid,
                                 self_full_jid, True)
    iq, si = bytestream1.create_si_offer(ns.TUBES)

    stream_node = si.addElement((ns.TUBES, 'stream'))
    stream_node['tube'] = str(stream_tube_id)
    stream.send(iq)

    si_reply_event, _, new_conn_event, socket_event = q.expect_many(
        EventPattern('stream-iq', iq_type='result'),
        EventPattern('dbus-signal',
                     signal='TubeChannelStateChanged',
                     args=[cs.TUBE_STATE_OPEN]),
        EventPattern('dbus-signal', signal='NewRemoteConnection'),
        EventPattern('socket-connected'))

    bytestream1.check_si_reply(si_reply_event.stanza)
    tube = xpath.queryForNodes('/iq/si/tube[@xmlns="%s"]' % ns.TUBES,
                               si_reply_event.stanza)
    assert len(tube) == 1

    handle, access, id = new_conn_event.args
    assert handle == bob_handle
    protocol = socket_event.protocol
    # we don't want to echo the access control byte
    protocol.echoed = False

    # start to read from the transport so we can read the control byte
    protocol.transport.startReading()
    t.check_new_connection_access(q, access_control, access, protocol)
    protocol.echoed = True

    # The CM is the server, so fake a client wanting to talk to it
    # New API tube
    bytestream2 = bytestream_cls(stream, q, 'beta', bob_full_jid,
                                 self_full_jid, True)
    iq, si = bytestream2.create_si_offer(ns.TUBES)

    stream_node = si.addElement((ns.TUBES, 'stream'))
    stream_node['tube'] = str(stream_tube_id)
    stream.send(iq)

    si_reply_event, new_conn_event, socket_event = q.expect_many(
        EventPattern('stream-iq', iq_type='result'),
        EventPattern('dbus-signal', signal='NewRemoteConnection'),
        EventPattern('socket-connected'))

    bytestream2.check_si_reply(si_reply_event.stanza)
    tube = xpath.queryForNodes('/iq/si/tube[@xmlns="%s"]' % ns.TUBES,
                               si_reply_event.stanza)
    assert len(tube) == 1

    handle, access, conn_id = new_conn_event.args
    assert handle == bob_handle
    protocol = socket_event.protocol
    # we don't want to echo the access control byte
    protocol.echoed = False

    # start to read from the transport so we can read the control byte
    protocol.transport.startReading()
    t.check_new_connection_access(q, access_control, access, protocol)
    protocol.echoed = True

    # have the fake client open the stream
    bytestream1.open_bytestream()

    # have the fake client send us some data
    data = b'hello, world'
    bytestream1.send_data(data)

    binary = bytestream1.get_data(len(data))
    assert binary == data, binary

    # have the fake client open the stream
    bytestream2.open_bytestream()

    # have the fake client send us some data
    data = b'hello, new world'
    bytestream2.send_data(data)

    binary = bytestream2.get_data(len(data))
    assert binary == data, binary

    # peer closes the bytestream
    bytestream2.close()
    e = q.expect('dbus-signal', signal='ConnectionClosed')
    assertEquals(conn_id, e.args[0])
    assertEquals(cs.CONNECTION_LOST, e.args[1])

    t.cleanup()
def test(q, bus, conn, stream):
    iq_event, disco_event = q.expect_many(
        EventPattern('stream-iq',
                     to=None,
                     query_ns='vcard-temp',
                     query_name='vCard'),
        EventPattern('stream-iq', to='localhost', query_ns=ns.DISCO_ITEMS))

    acknowledge_iq(stream, iq_event.stanza)

    announce_socks5_proxy(q, stream, disco_event.stanza)

    join_muc(q, bus, conn, stream, '*****@*****.**')

    # bob offers a stream tube
    stream_tube_id = 1

    presence = make_muc_presence('owner', 'moderator', '*****@*****.**',
                                 'bob')
    tubes = presence.addElement((ns.TUBES, 'tubes'))
    tube = tubes.addElement((None, 'tube'))
    tube['type'] = 'stream'
    tube['service'] = 'echo'
    tube['id'] = str(stream_tube_id)
    parameters = tube.addElement((None, 'parameters'))
    stream.send(presence)

    def new_chan_predicate(e):
        path, props = e.args[0][0]
        return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE

    e = q.expect('dbus-signal',
                 signal='NewChannels',
                 predicate=new_chan_predicate)
    channels = e.args[0]
    assert len(channels) == 1
    path, props = channels[0]
    assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE

    tube_chan = bus.get_object(conn.bus_name, path)
    tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_STREAM_TUBE)

    call_async(q, tube_iface, 'Accept', 0, 0, '', byte_arrays=True)

    accept_return_event, _ = q.expect_many(
        EventPattern('dbus-return', method='Accept'),
        EventPattern('dbus-signal',
                     signal='TubeChannelStateChanged',
                     args=[cs.TUBE_CHANNEL_STATE_OPEN]))

    unix_socket_adr = accept_return_event.value[0].decode()

    factory = EventProtocolClientFactory(q)
    reactor.connectUNIX(unix_socket_adr, factory)

    # expect SI request
    e = q.expect('stream-iq',
                 to='[email protected]/bob',
                 query_ns=ns.SI,
                 query_name='si')

    bytestream, profile = create_from_si_offer(stream, q, BytestreamS5BRelay,
                                               e.stanza,
                                               '[email protected]/bob')

    result, si = bytestream.create_si_reply(e.stanza,
                                            'test@localhost/Resource')
    si.addElement((ns.TUBES, 'tube'))
    stream.send(result)

    # wait SOCKS5 init iq
    id, mode, si, hosts = bytestream._expect_socks5_init()
    for jid, host, port in hosts:
        # the proxy is not announced because we are in a muc
        assert jid != 'proxy.localhost'
def test(q, bus, mc):
    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******"
        },
        signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

    # Two clients want to observe, approve and handle channels. Additionally,
    # Kopete recognises an "Urgent" flag on certain incoming channels, and
    # wants to bypass approval for them.
    empathy = SimulatedClient(q,
                              bus,
                              'Empathy',
                              observe=[text_fixed_properties],
                              approve=[text_fixed_properties],
                              handle=[text_fixed_properties],
                              bypass_approval=False)
    kopete = SimulatedClient(q,
                             bus,
                             'Kopete',
                             observe=[contact_text_fixed_properties],
                             approve=[contact_text_fixed_properties],
                             handle=[contact_text_fixed_properties],
                             bypass_approval=False)
    bypass = SimulatedClient(q,
                             bus,
                             'Kopete.BypassApproval',
                             observe=[],
                             approve=[],
                             handle=[urgent_fixed_properties],
                             bypass_approval=True)

    # wait for MC to download the properties
    expect_client_setup(q, [empathy, kopete, bypass])

    # subscribe to the OperationList interface (MC assumes that until this
    # property has been retrieved once, nobody cares)

    cd = bus.get_object(cs.CD, cs.CD_PATH)
    cd_props = dbus.Interface(cd, cs.PROPERTIES_IFACE)
    assert cd_props.Get(cs.CD_IFACE_OP_LIST, 'DispatchOperations') == []

    # First, a non-urgent channel is created

    cdo_iface, chan, channel_properties, observe_events = announce_common(
        q, bus, empathy, kopete, account, conn, cd_props, False)

    # Both Observers indicate that they are ready to proceed
    for e in observe_events:
        q.dbus_return(e.message, signature='')

    expect_and_exercise_approval(q, bus, chan, channel_properties, empathy,
                                 kopete, cdo_iface, cd_props)

    # Now a channel that bypasses approval comes in. During this process,
    # we should never be asked to approve anything.

    approval = [
        EventPattern('dbus-method-call', method='AddDispatchOperation'),
    ]

    q.forbid_events(approval)

    cdo_iface, chan, channel_properties, observe_events = announce_common(
        q, bus, empathy, kopete, account, conn, cd_props, True)

    # Both Observers indicate that they are ready to proceed
    for e in observe_events:
        q.dbus_return(e.message, signature='')

    # Kopete's BypassApproval part is asked to handle the channels
    e = q.expect('dbus-method-call',
                 path=bypass.object_path,
                 interface=cs.HANDLER,
                 method='HandleChannels',
                 handled=False)
    # Kopete accepts the channels
    q.dbus_return(e.message, signature='')

    q.unforbid_events(approval)

    # Regression test for fd.o #22670

    closure = [
        EventPattern('dbus-method-call', method='Close'),
    ]

    q.forbid_events(closure)

    bypass.release_name()
    sync_dbus(bus, q, mc)

    q.unforbid_events(closure)

    # Bring back that handler
    del bypass
    bypass = SimulatedClient(q,
                             bus,
                             'Kopete.BypassApproval',
                             observe=[],
                             approve=[],
                             handle=[urgent_fixed_properties],
                             bypass_approval=True)
    expect_client_setup(q, [bypass])

    # Another channel that bypasses approval comes in, but the handler that
    # bypasses approval fails.

    cdo_iface, chan, channel_properties, observe_events = announce_common(
        q, bus, empathy, kopete, account, conn, cd_props, True)

    # Both Observers indicate that they are ready to proceed
    for e in observe_events:
        q.dbus_return(e.message, signature='')

    # Kopete's BypassApproval part is asked to handle the channels
    e = q.expect('dbus-method-call',
                 path=bypass.object_path,
                 interface=cs.HANDLER,
                 method='HandleChannels',
                 handled=False)
    # Kopete's BypassApproval part fails to accept the channels
    q.dbus_raise(e.message, 'com.example.Broken', 'No way')

    # MC recovers by running the approvers and doing what they say
    expect_and_exercise_approval(q, bus, chan, channel_properties, empathy,
                                 kopete, cdo_iface, cd_props)
Пример #6
0
def test(q, bus, mc):
    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******"
        }, signature='sv')
    (simulated_cm, account) = create_fakecm_account(q, bus, mc, params)

    srv_name = 'fu-bar-42'
    account_iface = dbus.Interface(account, cs.ACCOUNT)
    account_props = dbus.Interface(account, cs.PROPERTIES_IFACE)

    # defaults to the empty string
    assertEquals(account_props.Get(cs.ACCOUNT, 'Service'), '')

    # set to a new value after creation
    call_async(q, account_props, 'Set', cs.ACCOUNT, 'Service', srv_name)
    q.expect_many(
        EventPattern('dbus-signal',
                     path=account.object_path,
                     signal='AccountPropertyChanged',
                     interface=cs.ACCOUNT,
                     args=[{
                         'Service': srv_name
                     }]),
        EventPattern('dbus-return', method='Set'),
    )
    assertEquals(account_props.Get(cs.ACCOUNT, 'Service'), srv_name)

    # set to an invalid value (no actual change should occur)

    # leading non-alphabetic (make sure _ isn't considered alphabetic)
    call_async(q, account_props, 'Set', cs.ACCOUNT, 'Service', '_fu-bar')
    q.expect_many(EventPattern('dbus-error', method='Set'))
    assertEquals(account_props.Get(cs.ACCOUNT, 'Service'), srv_name)

    # leading non-alphabetic
    call_async(q, account_props, 'Set', cs.ACCOUNT, 'Service', '.moose')
    q.expect_many(EventPattern('dbus-error', method='Set'))
    assertEquals(account_props.Get(cs.ACCOUNT, 'Service'), srv_name)

    # gregexes have an option to be lenient about trailing newlines:
    # this makes sure we haven't made that mistake
    call_async(q, account_props, 'Set', cs.ACCOUNT, 'Service', srv_name + '\n')
    q.expect_many(EventPattern('dbus-error', method='Set'))
    assertEquals(account_props.Get(cs.ACCOUNT, 'Service'), srv_name)

    # set to an empty string
    call_async(q, account_props, 'Set', cs.ACCOUNT, 'Service', '')
    q.expect_many(EventPattern('dbus-return', method='Set'))
    assertEquals(account_props.Get(cs.ACCOUNT, 'Service'), '')

    # test creation with a service
    account_manager = bus.get_object(cs.AM, cs.AM_PATH)
    am_iface = dbus.Interface(account_manager, cs.AM)

    service_prop = dbus.Dictionary({
        cs.ACCOUNT + '.Service': "moomin-troll",
    },
                                   signature='sv')

    call_async(
        q,
        am_iface,
        'CreateAccount',
        'fakecm',  # Connection_Manager
        'fakeprotocol',  # Protocol
        'fakeaccount',  # Display_Name
        params,  # Parameters
        service_prop,  # Properties
    )

    ret = q.expect('dbus-return', method='CreateAccount')
    path = ret.value[0]
    account = bus.get_object(cs.tp_name_prefix + '.AccountManager', path)
    if_props = dbus.Interface(account, cs.PROPERTIES_IFACE)
    props = if_props.GetAll(cs.ACCOUNT)
    assertEquals(props.get('Service'), 'moomin-troll')

    # attempt creation with a bogus service
    service_prop = dbus.Dictionary({cs.ACCOUNT + '.Service': "1337"},
                                   signature='sv')

    call_async(
        q,
        am_iface,
        'CreateAccount',
        'fakecm',  # Connection_Manager
        'fakeprotocol',  # Protocol
        'fakeaccount',  # Display_Name
        params,  # Parameters
        service_prop,  # Properties
    )

    ret = q.expect('dbus-error', method='CreateAccount')
def expect_close(q, path):
    q.expect_many(EventPattern('dbus-signal', signal='ChannelClosed',
                               args=[path]),
                  EventPattern('dbus-signal', signal='Closed',
                               path=path))
"""
Test connecting with different ContactList.DownloadAtConnection values
"""

import dbus

from servicetest import EventPattern
from gabbletest import exec_test, sync_stream, call_async
import constants as cs
import ns

forbidden = [EventPattern('stream-iq', query_ns=ns.ROSTER)]


def test_get_roster(q, bus, conn, stream):
    # DownloadAtConnection = True, so gabble should get the roster
    # automatically
    q.expect('stream-iq', query_ns=ns.ROSTER)

    # but calling ContactList.Download should not try and get the
    # roster again
    q.forbid_events(forbidden)
    conn.ContactList.Download()
    sync_stream(q, stream)
    q.unforbid_events(forbidden)


def test_dont_get_roster(q, bus, conn, stream):
    # DownloadAtConnection = False, so let's make sure the roster
    # isn't fetched automatically
    q.forbid_events(forbidden)
def test(q, bus, conn, stream):
    conn.Connect()

    q.expect('dbus-signal', signal='StatusChanged', args=[0, 1])

    alice_handle, bob_handle = conn.get_contact_handles_sync(['alice', 'bob'])

    call_async(q, conn.Requests, 'CreateChannel',
            { CHANNEL_TYPE: CHANNEL_TYPE_TEXT,
              TARGET_HANDLE_TYPE: HT_ROOM,
              TARGET_ID: room })

    q.expect('stream-JOIN')
    event = q.expect('dbus-return', method='CreateChannel')
    path = event.value[0]

    channel = wrap_channel(bus.get_object(conn.bus_name, path), 'Text',
        ['Subject2'])

    assertContains(CHANNEL_IFACE_SUBJECT,
        channel.Properties.Get(CHANNEL, 'Interfaces'))

    # No topic set
    subject_props = channel.Properties.GetAll(CHANNEL_IFACE_SUBJECT)
    assertEquals('', subject_props['Subject'])
    assertEquals(0x7fffffffffffffff, subject_props['Timestamp'])
    assertEquals('', subject_props['Actor'])
    assertEquals(0, subject_props['ActorHandle'])

    # Before the topic arrives from the server, check that our API works okay.
    # FIXME: when we make SetSubject return asynchronously, this will need
    # revising.
    test_can_set(q, stream, channel)

    # We're told the channel's topic, and (in a separte message) who set it and
    # when.
    stream.sendMessage('332', stream.nick, room, ':Test123',
        prefix='idle.test.server')
    stream.sendMessage('333', stream.nick, room, 'bob', '1307802600',
        prefix='idle.test.server')

    # FIXME: signal these together, if possible.
    expect_subject_props_changed(q, { 'Subject': 'Test123' })
    expect_subject_props_changed(q,
        { 'Timestamp': 1307802600,
          'Actor': 'bob',
          'ActorHandle': bob_handle,
        }, exact_timestamp=True)

    # Another user changes the topic.
    stream.sendMessage('TOPIC', room, ':I am as high as a kite',
        prefix='alice')
    expect_subject_props_changed(q,
        { 'Subject': 'I am as high as a kite',
          'Actor': 'alice',
          'ActorHandle': alice_handle,
          'Timestamp': 1234,
        })

    # BIP omits the : for the trailing parameter if it's a single word, make
    # sure we pass that as well
    stream.sendMessage('TOPIC', room, 'badgers!',
        prefix='alice')
    expect_subject_props_changed(q,
        { 'Subject': 'badgers!',
          'Actor': 'alice',
          'ActorHandle': alice_handle,
          'Timestamp': 1234,
        })

    test_can_set(q, stream, channel)

    # Topic is read/write, if we get ops it should stay that way
    forbidden = [
        EventPattern('dbus-signal', signal='PropertiesChanged',
            predicate=lambda e: e.args[0] == CHANNEL_IFACE_SUBJECT)
    ]
    q.forbid_events(forbidden)

    # Set ops, check that t flag becomes a no-op
    change_channel_mode (stream, '+o ' + stream.nick)
    change_channel_mode (stream, '+t')
    change_channel_mode (stream, '-t')
    change_channel_mode (stream, '-o ' + stream.nick)

    # Check that other flags don't cause issues
    change_channel_mode (stream, '+n')
    change_channel_mode (stream, '+n')

    change_channel_mode (stream, '+to ' + stream.nick)
    change_channel_mode (stream, '-to ' + stream.nick)

    sync_stream(q, stream)
    sync_dbus(bus, q, conn)
    q.unforbid_events(forbidden)

    # back to normal?
    test_can_set(q, stream, channel)

    # Check if setting ops gives us write access on +t channels
    change_channel_mode (stream, '+t')
    expect_and_check_can_set(q, channel, False)

    change_channel_mode (stream, '+o ' + stream.nick)
    expect_and_check_can_set(q, channel, True)

    change_channel_mode (stream, '-o ' + stream.nick)
    expect_and_check_can_set(q, channel, False)

    change_channel_mode (stream, '-t')
    expect_and_check_can_set(q, channel, True)

    # And back to normal again ?
    test_can_set(q, stream, channel)

    channel.Subject2.SetSubject('')
    # Verify that we send an empty final parameter ("clear the topic") as
    # opposed to no final parameter ("what is the topic").
    q.expect('stream-TOPIC', data=[room, ''])
Пример #10
0
    def pickup(self):
        CallTest.pickup(self, held=True)

        q = self.q
        stream = self.stream
        chan = self.chan
        cstream = self.audio_stream

        assertEquals((cs.HS_HELD, cs.HSR_REQUESTED), chan.Hold.GetHoldState())

        recv_state = cstream.Get(cs.CALL_STREAM_IFACE_MEDIA,
                                 "ReceivingState",
                                 dbus_interface=dbus.PROPERTIES_IFACE)
        assertEquals(cs.CALL_STREAM_FLOW_STATE_STOPPED, recv_state)
        send_state = cstream.Get(cs.CALL_STREAM_IFACE_MEDIA,
                                 "SendingState",
                                 dbus_interface=dbus.PROPERTIES_IFACE)
        assertEquals(cs.CALL_STREAM_FLOW_STATE_STOPPED, send_state)

        # Now we decide we do actually want to speak to them, and unhold.
        # Ensure that if Gabble sent the <unhold/> stanza too early it's already
        # arrived.
        sync_stream(q, stream)
        q.forbid_events(self.unhold_event)

        call_async(q, chan.Hold, 'RequestHold', False)
        q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
        )

        # Ensure that if Gabble sent the <unhold/> stanza too early it's already
        # arrived.
        sync_stream(q, stream)
        q.unforbid_events(self.unhold_event)

        cstream.CompleteReceivingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STARTED,
            dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)
        cstream.CompleteSendingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STARTED,
            dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)

        q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_UNHELD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STARTED],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STARTED],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            *self.unhold_event)

        # Hooray! Now let's check that Hold works properly once the call's fully
        # established.

        # ---- Test 1: GetHoldState returns unheld and unhold is a no-op ----

        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_UNHELD, hold_state
        chan.Hold.RequestHold(False)

        # ---- Test 2: successful hold ----

        call_async(q, chan.Hold, 'RequestHold', True)
        q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
            *self.hold_event)

        cstream.CompleteReceivingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STOPPED,
            dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)
        cstream.CompleteSendingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STOPPED,
            dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)
        q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_HELD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STOPPED],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STOPPED],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
        )

        # ---- Test 3: GetHoldState returns held and hold is a no-op ----

        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_HELD, hold_state
        chan.Hold.RequestHold(True)

        # ---- Test 4: successful unhold ----

        q.forbid_events(self.unhold_event)

        call_async(q, chan.Hold, 'RequestHold', False)
        q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
        )

        # Ensure that if Gabble sent the <unhold/> stanza too early it's already
        # arrived.
        sync_stream(q, stream)
        q.unforbid_events(self.unhold_event)

        cstream.CompleteReceivingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STARTED,
            dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)
        cstream.CompleteSendingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STARTED,
            dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)
        q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_UNHELD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STARTED],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STARTED],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            *self.unhold_event)

        # ---- Test 5: GetHoldState returns False and unhold is a no-op ----

        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_UNHELD, hold_state
        chan.Hold.RequestHold(False)

        # ---- Test 6: 3 parallel calls to hold ----

        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_UNHELD, hold_state

        call_async(q, chan.Hold, 'RequestHold', True)
        call_async(q, chan.Hold, 'RequestHold', True)
        call_async(q, chan.Hold, 'RequestHold', True)
        q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
            *self.hold_event)

        cstream.CompleteReceivingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STOPPED,
            dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)
        cstream.CompleteSendingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STOPPED,
            dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)
        q.expect_many(
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STOPPED],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STOPPED],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_HELD, cs.HSR_REQUESTED]),
        )

        # ---- Test 7: 3 parallel calls to unhold ----

        q.forbid_events(self.unhold_event)

        call_async(q, chan.Hold, 'RequestHold', False)
        call_async(q, chan.Hold, 'RequestHold', False)
        call_async(q, chan.Hold, 'RequestHold', False)
        q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
        )

        # Ensure that if Gabble sent the <unhold/> stanza too early it's already
        # arrived.
        sync_stream(q, stream)
        q.unforbid_events(self.unhold_event)

        cstream.CompleteReceivingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STARTED,
            dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)
        cstream.CompleteSendingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STARTED,
            dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)
        q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_UNHELD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STARTED],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STARTED],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            *self.unhold_event)

        # ---- Test 8: hold, then change our minds before s-e has responded ----

        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_UNHELD, hold_state

        call_async(q, chan.Hold, 'RequestHold', True)
        q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            *self.hold_event)

        q.forbid_events(self.unhold_event)

        call_async(q, chan.Hold, 'RequestHold', False)
        q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            # Gabble shouldn't send <unhold/> here because s-e might have
            # already relinquished the audio hardware.
        )

        sync_stream(q, stream)
        q.unforbid_events(self.unhold_event)

        try:
            cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)
        except dbus.DBusException, e:
            assertEquals(cs.INVALID_ARGUMENT, e.get_dbus_name())
Пример #11
0
def test(q, bus, conn, stream):
    rccs = conn.Properties.Get(cs.CONN_IFACE_REQUESTS,
                               'RequestableChannelClasses')

    fixed = {
        cs.CHANNEL_TYPE: CONSOLE_PLUGIN_IFACE,
        cs.TARGET_HANDLE_TYPE: cs.HT_NONE,
    }
    allowed = []
    assertContains((fixed, allowed), rccs)

    path, _ = conn.Requests.CreateChannel(
        {cs.CHANNEL_TYPE: CONSOLE_PLUGIN_IFACE})
    other_path, _ = conn.Requests.CreateChannel(
        {cs.CHANNEL_TYPE: CONSOLE_PLUGIN_IFACE})

    assertNotEquals(path, other_path)
    # leave the other one open, to test we don't crash on disconnect

    console = ProxyWrapper(bus.get_object(conn.bus_name, path),
                           CONSOLE_PLUGIN_IFACE, {'Channel': cs.CHANNEL})

    assert not console.Properties.Get(CONSOLE_PLUGIN_IFACE, 'SpewStanzas')
    es = [
        EventPattern('dbus-signal', signal='StanzaReceived'),
        EventPattern('dbus-signal', signal='StanzaSent'),
    ]
    q.forbid_events(es)

    call_async(q, console, 'SendIQ', 'get', STACY,
               '<coffee xmlns="urn:unimaginative"/>')
    e = q.expect('stream-iq',
                 iq_type='get',
                 query_ns='urn:unimaginative',
                 query_name='coffee')
    acknowledge_iq(stream, e.stanza)
    e = q.expect('dbus-return', method='SendIQ')
    type_, body = e.value
    assertEquals('result', type_)
    # We just assume the body works.

    # Turn on signalling incoming and outgoing stanzas
    console.Properties.Set(CONSOLE_PLUGIN_IFACE, 'SpewStanzas', True)
    sync_dbus(bus, q, conn)
    q.unforbid_events(es)

    send_unrecognised_get(q, stream)

    e = q.expect('dbus-signal', signal='StanzaReceived')
    xml, = e.args
    assertContains('<iq', xml)
    assertContains('<dont-handle-me-bro', xml)

    signal = q.expect('dbus-signal', signal='StanzaSent')
    assertContains('service-unavailable', signal.args[0])

    # Turn off spewing out stanzas; check it works.
    console.Properties.Set(CONSOLE_PLUGIN_IFACE, 'SpewStanzas', False)
    q.forbid_events(es)
    send_unrecognised_get(q, stream)
    sync_dbus(bus, q, conn)

    # Try sending just any old stanza
    console.SendStanza('''
        <message to='%(stacy)s' type='headline'>
          <body>
            Hi sis.
          </body>
        </message>''' % {'stacy': STACY})

    e = q.expect('stream-message', to=STACY, message_type='headline')

    # Make sure that Wocky has filled in the jabber:client namespace we
    # carelessly omitted.
    message = e.stanza
    assertEquals('message', message.name)
    assertEquals(ns.CLIENT, message.uri)
    body = message.firstChildElement()
    assertEquals('body', body.name)
    assertEquals(ns.CLIENT, body.uri)

    console.Channel.Close()
Пример #12
0
        try:
            cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)
        except dbus.DBusException, e:
            assertEquals(cs.INVALID_ARGUMENT, e.get_dbus_name())

        cstream.CompleteReceivingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STARTED,
            dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)
        cstream.CompleteSendingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STARTED,
            dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)
        q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_UNHELD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STARTED],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STARTED],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            *self.unhold_event)

        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_UNHELD, hold_state

        # ---- Test 9: unhold, then change our minds before s-e has responded --
Пример #13
0
def test(q, bus, conn, stream):
    jid = '*****@*****.**'

    # <message type="chat"><body>hello</body</message>
    m = domish.Element((None, 'message'))
    m['from'] = '[email protected]/Pidgin'
    m['type'] = 'chat'
    m.addElement('body', content='hello')
    stream.send(m)

    event = q.expect('dbus-signal', signal='NewChannels')
    assertEquals(cs.CHANNEL_TYPE_TEXT, event.args[0][0][1][cs.CHANNEL_TYPE])
    assertEquals(cs.HT_CONTACT, event.args[0][0][1][cs.TARGET_HANDLE_TYPE])
    assertEquals(jid, event.args[0][0][1][cs.TARGET_ID])
    foo_at_bar_dot_com_handle = event.args[0][0][1][cs.TARGET_HANDLE]

    text_chan = bus.get_object(conn.bus_name, event.args[0][0][0])

    # Exercise basic Channel Properties from spec 0.17.7
    channel_props = text_chan.GetAll(cs.CHANNEL,
            dbus_interface=dbus.PROPERTIES_IFACE)
    assertEquals(foo_at_bar_dot_com_handle, channel_props.get('TargetHandle'))
    assert channel_props.get('TargetHandleType') == 1,\
            channel_props.get('TargetHandleType')
    assertEquals(cs.CHANNEL_TYPE_TEXT, channel_props.get('ChannelType'))
    assertContains(cs.CHANNEL_IFACE_CHAT_STATE,
            channel_props.get('Interfaces', ()))
    assertContains(cs.CHANNEL_IFACE_MESSAGES,
            channel_props.get('Interfaces', ()))
    assert channel_props['TargetID'] == jid,\
            (channel_props['TargetID'], jid)
    assert channel_props['Requested'] == False
    assertEquals(foo_at_bar_dot_com_handle, channel_props['InitiatorHandle'])
    assert channel_props['InitiatorID'] == jid,\
            (channel_props['InitiatorID'], jid)

    message_received = q.expect('dbus-signal', signal='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'] == foo_at_bar_dot_com_handle, header
    # the spec says that message-type "MAY be omitted for normal chat
    # messages."
    assert 'message-type' not in header or header['message-type'] == 0, 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']

    dbus.Interface(text_chan, cs.CHANNEL_TYPE_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
    # In Gabble, this is a Notice, but we don't support those.
    greeting = [
        dbus.Dictionary({ 'message-type': cs.MT_ACTION,
                        }, signature='sv'),
        { 'content-type': 'text/plain',
          'content': u"waves",
        }
    ]

    dbus.Interface(text_chan, cs.CHANNEL_IFACE_MESSAGES
        ).SendMessage(greeting, dbus.UInt32(0))

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

    elem = stream_message.stanza
    assert elem.name == 'message'
    assert elem['type'] == 'chat'

    found = False
    for e in elem.elements():
        if e.name == 'body':
            found = True
            e.children[0] == u'/me waves'
            break
    assert found, elem.toXml()

    sent_message = message_sent.args[0]
    assert len(sent_message) == 2, sent_message
    header = sent_message[0]
    assert header['message-type'] == 1, header # Action
    body = sent_message[1]
    assert body['content-type'] == 'text/plain', body
    assert body['content'] == u'waves', body

    dbus.Interface(text_chan, cs.CHANNEL_IFACE_MESSAGES
            ).SendMessage([{}, {
        'content-type': 'text/plain',
        'content': 'goodbye',
        }], 0)

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

    elem = stream_message.stanza
    assert elem.name == 'message'
    assert elem['type'] == 'chat'

    found = False
    for e in elem.elements():
        if e.name == 'body':
            found = True
            e.children[0] == u'goodbye'
            break
    assert found, elem.toXml()

    sent_message = message_sent.args[0]
    assert len(sent_message) == 2, sent_message
    header = sent_message[0]
    # the spec says that message-type "MAY be omitted for normal chat
    # messages."
    assert 'message-type' not in header or header['message-type'] == 0, header
    body = sent_message[1]
    assert body['content-type'] == 'text/plain', body
    assert body['content'] == u'goodbye', body

    conn.Disconnect()
    q.expect('dbus-signal', signal='StatusChanged', args=[2, 1])
Пример #14
0
def test(q, bus, mc):
    # Create an account
    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******"
        },
        signature='sv')
    (simulated_cm, account) = create_fakecm_account(q, bus, mc, params)

    # Events that indicate that Reconnect might have done something
    looks_like_reconnection = [
        EventPattern('dbus-method-call', method='RequestConnection'),
        EventPattern('dbus-method-call', method='Disconnect'),
    ]

    q.forbid_events(looks_like_reconnection)

    # While we want to be online but the account is disabled, Reconnect is a
    # no-op. Set Enabled to False explicitly, so we're less reliant on initial
    # state.

    call_async(q,
               account,
               'Set',
               cs.ACCOUNT,
               'Enabled',
               False,
               dbus_interface=cs.PROPERTIES_IFACE)
    q.expect('dbus-return', method='Set')

    requested_presence = dbus.Struct(
        (dbus.UInt32(cs.PRESENCE_AVAILABLE), dbus.String(u'available'),
         dbus.String(u'')))
    call_async(q,
               account,
               'Set',
               cs.ACCOUNT,
               'RequestedPresence',
               requested_presence,
               dbus_interface=cs.PROPERTIES_IFACE)
    q.expect('dbus-return', method='Set')

    call_async(q, account, 'Reconnect', dbus_interface=cs.ACCOUNT)
    q.expect('dbus-return', method='Reconnect')

    sync_dbus(bus, q, account)

    # While we want to be offline but the account is enabled, Reconnect is
    # still a no-op.
    requested_presence = dbus.Struct(
        (dbus.UInt32(cs.PRESENCE_OFFLINE), dbus.String(u'offline'),
         dbus.String(u'')))
    call_async(q,
               account,
               'Set',
               cs.ACCOUNT,
               'RequestedPresence',
               requested_presence,
               dbus_interface=cs.PROPERTIES_IFACE)
    q.expect_many(
        EventPattern('dbus-return', method='Set'),
        EventPattern('dbus-signal',
                     path=account.object_path,
                     signal='AccountPropertyChanged',
                     interface=cs.ACCOUNT),
    )

    # Enable the account
    call_async(q,
               account,
               'Set',
               cs.ACCOUNT,
               'Enabled',
               True,
               dbus_interface=cs.PROPERTIES_IFACE)
    q.expect_many(
        EventPattern('dbus-return', method='Set'),
        EventPattern('dbus-signal',
                     path=account.object_path,
                     signal='AccountPropertyChanged',
                     interface=cs.ACCOUNT),
    )

    call_async(q, account, 'Reconnect', dbus_interface=cs.ACCOUNT)
    q.expect('dbus-return', method='Reconnect')

    sync_dbus(bus, q, account)

    # Actually go online now

    q.unforbid_events(looks_like_reconnection)

    requested_presence = dbus.Struct(
        (dbus.UInt32(cs.PRESENCE_AVAILABLE), dbus.String(u'brb'),
         dbus.String(u'Be back soon!')))
    account.Set(cs.ACCOUNT,
                'RequestedPresence',
                requested_presence,
                dbus_interface=cs.PROPERTIES_IFACE)

    e = q.expect('dbus-method-call',
                 method='RequestConnection',
                 args=['fakeprotocol', params],
                 destination=tp_name_prefix + '.ConnectionManager.fakecm',
                 path=tp_path_prefix + '/ConnectionManager/fakecm',
                 interface=tp_name_prefix + '.ConnectionManager',
                 handled=False)

    conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', '_', 'myself')

    q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so')

    # MC does some setup, including fetching the list of Channels

    q.expect_many(
        EventPattern('dbus-method-call',
                     interface=cs.PROPERTIES_IFACE,
                     method='GetAll',
                     args=[cs.CONN_IFACE_REQUESTS],
                     path=conn.object_path,
                     handled=True), )

    # MC prepares the connection, does any pre-Connect setup, then
    # calls Connect
    q.expect('dbus-method-call',
             method='Connect',
             path=conn.object_path,
             handled=True)

    # Connect succeeds
    conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CSR_NONE_SPECIFIED)

    # Assert that the NormalizedName is harvested from the Connection at some
    # point
    while 1:
        e = q.expect('dbus-signal',
                     interface=cs.ACCOUNT,
                     signal='AccountPropertyChanged',
                     path=account.object_path)
        if 'NormalizedName' in e.args[0]:
            assert e.args[0]['NormalizedName'] == 'myself', e.args
            break

    # Check the requested presence is online
    properties = account.GetAll(cs.ACCOUNT, dbus_interface=cs.PROPERTIES_IFACE)
    assert properties is not None
    assert properties.get('RequestedPresence') == requested_presence, \
        properties.get('RequestedPresence')

    # Reconnect
    account.Reconnect(dbus_interface=cs.ACCOUNT)

    q.expect('dbus-method-call',
             method='Disconnect',
             path=conn.object_path,
             handled=True)

    e = q.expect('dbus-method-call',
                 method='RequestConnection',
                 args=['fakeprotocol', params],
                 destination=tp_name_prefix + '.ConnectionManager.fakecm',
                 path=tp_path_prefix + '/ConnectionManager/fakecm',
                 interface=tp_name_prefix + '.ConnectionManager',
                 handled=False)
    # The object path needs to be different from the first simulated
    # connection which we made above, because the object isn't removed
    # from this bus and it's actually hard to do so because it's not
    # really on a bus, it's on the queue. So let's just change the
    # object path and it's fine.
    conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', 'second',
                               'myself')
    q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so')

    q.expect_many(
        EventPattern('dbus-method-call',
                     interface=cs.PROPERTIES_IFACE,
                     method='GetAll',
                     args=[cs.CONN_IFACE_REQUESTS],
                     path=conn.object_path,
                     handled=True), )

    q.expect('dbus-method-call',
             method='Connect',
             path=conn.object_path,
             handled=True)
    conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CSR_NONE_SPECIFIED)

    # Put the account offline
    requested_presence = (dbus.UInt32(cs.PRESENCE_OFFLINE), 'offline', '')
    account.Set(cs.ACCOUNT,
                'RequestedPresence',
                requested_presence,
                dbus_interface=cs.PROPERTIES_IFACE)

    # In response, MC tells us to Disconnect, and we do
    q.expect('dbus-method-call',
             method='Disconnect',
             path=conn.object_path,
             handled=True)

    properties = account.GetAll(cs.ACCOUNT, dbus_interface=cs.PROPERTIES_IFACE)
    assert properties['Connection'] == '/'
    assert properties['ConnectionStatus'] == cs.CONN_STATUS_DISCONNECTED
    assert properties['CurrentPresence'] == requested_presence
    assert properties['RequestedPresence'] == requested_presence
Пример #15
0
def test(q, bus, mc):
    # Create an account
    (simulated_cm, account) = create_fakecm_account(q, bus, mc, params)

    account_iface = dbus.Interface(account, cs.ACCOUNT)
    account_props = dbus.Interface(account, cs.PROPERTIES_IFACE)

    call_async(q,
               account,
               'Set',
               cs.ACCOUNT,
               'Enabled',
               False,
               dbus_interface=cs.PROPERTIES_IFACE)
    q.expect('dbus-return', method='Set')

    # Enable the account
    call_async(q,
               account,
               'Set',
               cs.ACCOUNT,
               'Enabled',
               True,
               dbus_interface=cs.PROPERTIES_IFACE)

    # Set online presence
    presence = dbus.Struct(
        (dbus.UInt32(cs.PRESENCE_BUSY), 'busy', 'Fixing MC bugs'),
        signature='uss')
    call_async(q,
               account,
               'Set',
               cs.ACCOUNT,
               'RequestedPresence',
               presence,
               dbus_interface=cs.PROPERTIES_IFACE)

    e = q.expect('dbus-method-call',
                 method='RequestConnection',
                 args=['fakeprotocol', params],
                 destination=tp_name_prefix + '.ConnectionManager.fakecm',
                 path=tp_path_prefix + '/ConnectionManager/fakecm',
                 interface=tp_name_prefix + '.ConnectionManager',
                 handled=False)

    conn = SimulatedConnection(q,
                               bus,
                               'fakecm',
                               'fakeprotocol',
                               '_',
                               'myself',
                               has_presence=True)

    q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so')

    # MC prepares the connection, does any pre-Connect setup, then
    # calls Connect
    q.expect('dbus-method-call',
             method='Connect',
             path=conn.object_path,
             handled=True)

    # Connect succeeds
    conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CSR_NONE_SPECIFIED)

    conn = drop_and_expect_reconnect(q, bus, conn)
    conn = drop_and_expect_reconnect(q, bus, conn)
    conn = drop_and_expect_reconnect(q, bus, conn)

    forbidden = [EventPattern('dbus-method-call', method='RequestConnection')]
    q.forbid_events(forbidden)

    # Connection falls over for a miscellaneous reason
    conn.StatusChanged(cs.CONN_STATUS_DISCONNECTED, cs.CSR_NETWORK_ERROR)
    # Right, that's it, I'm giving up...

    # This test can be considered to have succeeded if we don't
    # RequestConnection again before the test fails due to timeout.
    try:
        q.expect('the end of the world')
    except TimeoutError:
        return
    else:
        raise AssertionError('An impossible event happened')
def test(q, bus, conn, stream, access_control):
    iq_event = q.expect('stream-iq',
                        to=None,
                        query_ns='vcard-temp',
                        query_name='vCard')

    acknowledge_iq(stream, iq_event.stanza)

    muc = '*****@*****.**'
    _, test_handle, bob_handle = \
        join_muc_and_check(q, bus, conn, stream, muc)

    # Bob offers a stream tube
    bob_bus_name = ':2.Ym9i'
    presence = make_muc_presence('owner', 'moderator', '*****@*****.**',
                                 'bob')
    tubes = presence.addElement((ns.TUBES, 'tubes'))
    tube = tubes.addElement((None, 'tube'))
    tube['type'] = 'dbus'
    tube['initiator'] = '[email protected]/bob'
    tube['stream-id'] = '10'
    tube['id'] = '1'
    tube['service'] = 'com.example.Test'
    tube['dbus-name'] = bob_bus_name
    parameters = tube.addElement((None, 'parameters'))
    parameter = parameters.addElement((None, 'parameter'))
    parameter['type'] = 'str'
    parameter['name'] = 'foo'
    parameter.addContent('bar')
    stream.send(presence)

    # tube channel is created
    def new_chan_predicate(e):
        path, props = e.args[0][0]
        return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE

    event = q.expect('dbus-signal',
                     signal='NewChannels',
                     predicate=new_chan_predicate)
    channels = event.args[0]
    path, props = channels[0]

    assertEquals(cs.CHANNEL_TYPE_DBUS_TUBE, props[cs.CHANNEL_TYPE])
    assertEquals('[email protected]/bob', props[cs.INITIATOR_ID])
    bob_handle = props[cs.INITIATOR_HANDLE]
    assertSameSets([cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_TUBE],
                   props[cs.INTERFACES])
    assertEquals(False, props[cs.REQUESTED])
    assertEquals('*****@*****.**', props[cs.TARGET_ID])
    assertEquals('com.example.Test', props[cs.DBUS_TUBE_SERVICE_NAME])
    assertEquals({'foo': 'bar'}, props[cs.TUBE_PARAMETERS])
    assertEquals([
        cs.SOCKET_ACCESS_CONTROL_CREDENTIALS,
        cs.SOCKET_ACCESS_CONTROL_LOCALHOST
    ], props[cs.DBUS_TUBE_SUPPORTED_ACCESS_CONTROLS])

    tube_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'DBusTube')

    # only Bob is in DBusNames
    dbus_names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE,
                               'DBusNames',
                               dbus_interface=cs.PROPERTIES_IFACE)
    assertEquals({bob_handle: bob_bus_name}, dbus_names)

    call_async(q, tube_chan.DBusTube, 'Accept', access_control)

    return_event, names_changed1, names_changed2, presence_event = q.expect_many(
        EventPattern('dbus-return', method='Accept'),
        EventPattern('dbus-signal',
                     signal='DBusNamesChanged',
                     interface=cs.CHANNEL_TYPE_DBUS_TUBE),
        EventPattern('dbus-signal',
                     signal='DBusNamesChanged',
                     interface=cs.CHANNEL_TYPE_DBUS_TUBE),
        EventPattern('stream-presence',
                     to='[email protected]/test',
                     predicate=lambda e: t.presence_contains_tube(e)))

    tube_addr = return_event.value[0]
    assert len(tube_addr) > 0

    # check presence stanza
    tube_node = xpath.queryForNodes('/presence/tubes/tube',
                                    presence_event.stanza)[0]
    assertEquals('[email protected]/bob', tube_node['initiator'])
    assertEquals('com.example.Test', tube_node['service'])
    assertEquals('10', tube_node['stream-id'])
    assertEquals('dbus', tube_node['type'])
    assertEquals('1', tube_node['id'])
    self_bus_name = tube_node['dbus-name']

    tubes_self_handle = tube_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP,
                                                 'SelfHandle')
    assertNotEquals(0, tubes_self_handle)

    # both of us are in DBusNames now
    dbus_names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE,
                               'DBusNames',
                               dbus_interface=cs.PROPERTIES_IFACE)
    assertEquals({
        bob_handle: bob_bus_name,
        tubes_self_handle: self_bus_name
    }, dbus_names)

    added, removed = names_changed1.args
    assertEquals({bob_handle: bob_bus_name}, added)
    assertEquals([], removed)

    added, removed = names_changed2.args
    assertEquals({tubes_self_handle: self_bus_name}, added)
    assertEquals([], removed)

    tube_chan.Channel.Close()
    q.expect_many(EventPattern('dbus-signal', signal='Closed'),
                  EventPattern('dbus-signal', signal='ChannelClosed'))
def test_gtalk_weirdness(q, bus, conn, stream, room_jid):
    """
    There's a strange bug in the Google Talk MUC server where it sends the
    <conflict/> stanza twice. This has been reported to their server team; but
    in any case it triggered a crazy bug in Gabble, so here's a regression test.
    """

    # Implementation detail: Gabble uses the first part of your jid (if you
    # don't have an alias) as your room nickname, and appends an underscore a
    # few times before giving up.
    jids = ['%s/test%s' % (room_jid, x) for x in ['', '_', '__']]
    member, member_, member__ = jids

    # Gabble should never get as far as trying to join as 'test__' since
    # joining as 'test_' will succeed.
    q.forbid_events([EventPattern('stream-presence', to=member__)])

    call_async(
        q, conn.Requests, 'CreateChannel',
        dbus.Dictionary(
            {
                cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
                cs.TARGET_HANDLE_TYPE: cs.HT_ROOM,
                cs.TARGET_ID: room_jid,
            },
            signature='sv'))

    # Gabble first tries to join as test
    q.expect('stream-presence', to=member)

    # Google Talk says no from 'test', twice.
    presence = elem('presence', from_=member,
                    type='error')(elem(ns.MUC, 'x'),
                                  elem('error', type='cancel')(elem(
                                      ns.STANZA, 'conflict'), ))
    stream.send(presence)
    stream.send(presence)

    # Gabble should try to join again as test_
    q.expect('stream-presence', to=member_)

    # Since 'test_' is not in use in the MUC, joining should succeed. According
    # to XEP-0045 §7.1.3 <http://xmpp.org/extensions/xep-0045.html#enter-pres>:
    #  The service MUST first send the complete list of the existing occupants
    #  to the new occupant and only then send the new occupant's own presence
    #  to the new occupant
    # but groupchat.google.com cheerfully violates this.
    stream.send(make_muc_presence('none', 'participant', room_jid, 'test_'))

    # Here's some other random person, who owns the MUC.
    stream.send(
        make_muc_presence('owner', 'moderator', room_jid, 'foobar_gmail.com'))
    # And here's our hypothetical other self.
    stream.send(make_muc_presence('none', 'participant', room_jid, 'test'))

    # The Gabble bug makes this time out: because Gabble thinks it's joining as
    # test__ it ignores the presence for test_, since it's not flagged with
    # code='210' to say “this is you”. (This is acceptable behaviour by the
    # server: it only needs to include code='210' if it's assigned the client a
    # name other than the one it asked for.
    #
    # The forbidden stream-presence event above doesn't blow up here because
    # servicetest doesn't process events on the 'stream-*' queue at all when
    # we're not waiting for one. But during disconnection in the test clean-up,
    # the forbidden event is encountered and correctly flagged up.
    event = q.expect('dbus-return', method='CreateChannel')
    path, _ = event.value
    text_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text')

    # As far as Gabble's concerned, the two other participants joined
    # immediately after we did.  We can't request handles for them before we
    # try to join the MUC, because until we do so, Gabble doesn't know that
    # room_jid is a MUC, and so considers these three JIDs to be different
    # resources of the same contact. There is no race between this method
    # returning and MembersChangedDetailed firing, because libdbus reorders
    # messages when you make blocking calls.
    handle, handle_, handle__, foobar_handle = conn.get_contact_handles_sync(
        jids + ['%s/foobar_gmail.com' % room_jid])

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

    group_props = text_chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP)
    assertEquals(handle_, group_props['SelfHandle'])
    assertSameSets([handle, handle_, foobar_handle], group_props['Members'])
Пример #18
0
def test(q, bus, conn, stream):
    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")

    # When Gabble initially requests its avatar from the server, it discovers
    # it has none.
    expect_and_handle_get_vcard(q, stream)
    handle, signalled_token = q.expect('dbus-signal',
                                       signal='AvatarUpdated').args

    assertEquals(self_handle, handle)
    assertEquals('', signalled_token)

    # The user sets an avatar.
    call_async(q, conn.Avatars, 'SetAvatar', AVATAR_1_DATA, AVATAR_1_MIME_TYPE)
    expect_and_handle_get_vcard(q, stream)
    expect_and_handle_set_vcard(q, stream)

    # It's signalled on D-Bus …
    set_ret, avatar_updated = q.expect_many(
        EventPattern('dbus-return', method='SetAvatar'),
        EventPattern('dbus-signal', signal='AvatarUpdated'),
    )

    returned_token, = set_ret.value
    handle, signalled_token = avatar_updated.args

    assertEquals(self_handle, handle)
    assertEquals(returned_token, signalled_token)

    # … and also on XMPP.
    broadcast = q.expect('stream-presence', to=None)
    broadcast_hash = extract_hash_from_presence(broadcast.stanza)
    assertEquals(AVATAR_1_SHA1, broadcast_hash)

    # If applications ask Gabble for information about the user's own avatar,
    # it should be able to answer. (Strictly speaking, expecting Gabble to know
    # the avatar data is risky because Gabble discards cached vCards after a
    # while, but we happen to know it takes 20 seconds or so for that to
    # happen.)
    known = conn.Avatars.GetKnownAvatarTokens([self_handle])
    assertEquals({self_handle: signalled_token}, known)

    conn.Avatars.RequestAvatars([self_handle])
    retrieved = q.expect('dbus-signal', signal='AvatarRetrieved')
    handle, token, data, mime_type = retrieved.args
    assertEquals(self_handle, handle)
    assertEquals(signalled_token, token)
    assertEquals(AVATAR_1_DATA, data)
    assertEquals(AVATAR_1_MIME_TYPE, mime_type)

    # Well, that was quite easy. How about we join a MUC? XEP-0153 §4.1 says:
    #     If a client supports the protocol defined herein, it […] SHOULD
    #     also include the update child in directed presence stanzas (e.g.,
    #     directed presence sent when joining Multi-User Chat [5] rooms).
    #         — http://xmpp.org/extensions/xep-0153.html#bizrules-presence
    join_event = try_to_join_muc(q, bus, conn, stream, MUC)
    directed_hash = extract_hash_from_presence(join_event.stanza)
    assertEquals(AVATAR_1_SHA1, directed_hash)

    # There are two others in the MUC: fredrik has no avatar, wendy has an
    # avatar. We, of course, have our own avatar.
    stream.send(make_muc_presence('none', 'participant', MUC, 'fredrik'))
    stream.send(
        make_muc_presence('none',
                          'participant',
                          MUC,
                          'wendy',
                          photo=AVATAR_2_SHA1))
    stream.send(
        make_muc_presence('owner',
                          'moderator',
                          MUC,
                          'test',
                          photo=AVATAR_1_SHA1))

    path, _ = q.expect('dbus-return', method='CreateChannel').value
    chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text')

    members = chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'Members')
    assertLength(3, members)

    fredrik, wendy, muc_self_handle = conn.get_contact_handles_sync(
        ['%s/%s' % (MUC, x) for x in ["fredrik", "wendy", "test"]])

    known = conn.Avatars.GetKnownAvatarTokens(members)
    # <https://bugs.freedesktop.org/show_bug.cgi?id=32017>: this assertion
    # failed, the MUC self handle's token was the empty string.
    assertEquals(AVATAR_1_SHA1, known[muc_self_handle])
    assertEquals(AVATAR_2_SHA1, known[wendy])
    assertEquals('', known[fredrik])

    # 'k, cool. Wendy loves our avatar and switches to it.
    stream.send(
        make_muc_presence('none',
                          'participant',
                          MUC,
                          'wendy',
                          photo=AVATAR_1_SHA1))
    # Okay this is technically assuming that we just expose the SHA1 sums
    # directly which is not guaranteed … but we do.
    q.expect('dbus-signal',
             signal='AvatarUpdated',
             args=[wendy, AVATAR_1_SHA1])

    # Fredrik switches too.
    stream.send(
        make_muc_presence('none',
                          'participant',
                          MUC,
                          'fredrik',
                          photo=AVATAR_1_SHA1))
    q.expect('dbus-signal',
             signal='AvatarUpdated',
             args=[fredrik, AVATAR_1_SHA1])

    # And we switch to some other avatar. Gabble should update its vCard, and
    # then update its MUC presence (which the test, acting as the MUC server,
    # must echo).
    call_async(q, conn.Avatars, 'SetAvatar', AVATAR_2_DATA, AVATAR_2_MIME_TYPE)
    expect_and_handle_get_vcard(q, stream)
    expect_and_handle_set_vcard(q, stream)

    muc_presence = q.expect('stream-presence', to=('%s/test' % MUC))
    directed_hash = extract_hash_from_presence(muc_presence.stanza)
    stream.send(
        make_muc_presence('owner',
                          'moderator',
                          MUC,
                          'test',
                          photo=directed_hash))

    # Gabble should signal an avatar update for both our global self-handle and
    # our MUC self-handle. (The first of these of course does not need to wait
    # for the MUC server to echo our presence.)
    q.expect_many(
        EventPattern('dbus-signal',
                     signal='AvatarUpdated',
                     args=[self_handle, AVATAR_2_SHA1]),
        EventPattern('dbus-signal',
                     signal='AvatarUpdated',
                     args=[muc_self_handle, AVATAR_2_SHA1]),
    )
Пример #19
0
def test_channel_creation(q,
                          bus,
                          account,
                          client,
                          conn,
                          ensure=False,
                          prefer=None,
                          channel_type=cs.CHANNEL_TYPE_TEXT):
    user_action_time = dbus.Int64(1238582606)
    hints = dbus.Dictionary({'badger': 42, 'snake': 'pony'}, signature='sv')

    if prefer is None:
        prefer = client

    cd = ChannelDispatcher(bus)
    assert cd.Properties.Get(cs.CD, "SupportsRequestHints")

    # chat UI calls ChannelDispatcher.EnsureChannelWithHints or
    # CreateChannelWithHints
    request = dbus.Dictionary(
        {
            cs.CHANNEL + '.ChannelType': channel_type,
            cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT,
            cs.CHANNEL + '.TargetID': 'juliet',
        },
        signature='sv')
    call_async(
        q,
        cd, (ensure and 'EnsureChannelWithHints' or 'CreateChannelWithHints'),
        account.object_path,
        request,
        user_action_time,
        prefer.bus_name,
        hints,
        dbus_interface=cs.CD)
    ret = q.expect('dbus-return',
                   method=(ensure and 'EnsureChannelWithHints'
                           or 'CreateChannelWithHints'))
    request_path = ret.value[0]

    # chat UI connects to signals and calls ChannelRequest.Proceed()

    cr = bus.get_object(cs.AM, request_path)
    request_props = cr.GetAll(cs.CR, dbus_interface=cs.PROPERTIES_IFACE)
    assert request_props['Account'] == account.object_path
    assert request_props['Requests'] == [request]
    assert request_props['UserActionTime'] == user_action_time
    assert request_props['PreferredHandler'] == prefer.bus_name
    assert request_props['Interfaces'] == []
    assertEquals(hints, request_props['Hints'])

    cr.Proceed(dbus_interface=cs.CR)

    # FIXME: should the EnsureChannel/CreateChannel call, and the AddRequest
    # call, be in a defined order? Probably not though, since CMs and Clients
    # aren't meant to be the same process!

    cm_request_call, add_request_call = q.expect_many(
        EventPattern('dbus-method-call',
                     interface=cs.CONN_IFACE_REQUESTS,
                     method=(ensure and 'EnsureChannel' or 'CreateChannel'),
                     path=conn.object_path,
                     args=[request],
                     handled=False),
        EventPattern('dbus-method-call',
                     handled=False,
                     interface=cs.CLIENT_IFACE_REQUESTS,
                     method='AddRequest'),
    )

    assert add_request_call.args[0] == request_path
    assert add_request_call.path == prefer.object_path
    request_props = add_request_call.args[1]
    assert request_props[cs.CR + '.Account'] == account.object_path
    assert request_props[cs.CR + '.Requests'] == [request]
    assert request_props[cs.CR + '.UserActionTime'] == user_action_time
    assert request_props[cs.CR + '.PreferredHandler'] == prefer.bus_name
    assert request_props[cs.CR + '.Interfaces'] == []

    q.dbus_return(add_request_call.message, signature='')

    # Time passes. A channel is returned.

    channel_immutable = dbus.Dictionary(request)
    channel_immutable[cs.CHANNEL + '.InitiatorID'] = conn.self_ident
    channel_immutable[cs.CHANNEL + '.InitiatorHandle'] = conn.self_handle
    channel_immutable[cs.CHANNEL + '.Requested'] = True
    channel_immutable[cs.CHANNEL + '.Interfaces'] = \
        dbus.Array([], signature='s')
    channel_immutable[cs.CHANNEL + '.TargetHandle'] = \
        conn.ensure_handle(cs.HT_CONTACT, 'juliet')
    channel = SimulatedChannel(conn, channel_immutable)

    # this order of events is guaranteed by telepathy-spec (since 0.17.14)
    if ensure:
        q.dbus_return(
            cm_request_call.message,
            True,  # <- Yours
            channel.object_path,
            channel.immutable,
            signature='boa{sv}')
    else:  # Create
        q.dbus_return(cm_request_call.message,
                      channel.object_path,
                      channel.immutable,
                      signature='oa{sv}')
    channel.announce()

    if channel_type == cs.CHANNEL_TYPE_TEXT:
        # Observer should get told, processing waits for it
        e = q.expect('dbus-method-call',
                     path=client.object_path,
                     interface=cs.OBSERVER,
                     method='ObserveChannels',
                     handled=False)
        assert e.args[0] == account.object_path, e.args
        assert e.args[1] == conn.object_path, e.args
        assert e.args[3] == '/', e.args  # no dispatch operation
        assert e.args[4] == [request_path], e.args
        channels = e.args[2]
        assert len(channels) == 1, channels
        assert channels[0][0] == channel.object_path, channels
        assert channels[0][1] == channel_immutable, channels
        info = e.args[5]
        assert info['request-properties'] == {
            request_path: request_props
        }, info

        # Observer says "OK, go"
        q.dbus_return(e.message, signature='')

    # Handler is next
    e = q.expect('dbus-method-call',
                 path=prefer.object_path,
                 interface=cs.HANDLER,
                 method='HandleChannels',
                 handled=False)
    assert e.args[0] == account.object_path, e.args
    assert e.args[1] == conn.object_path, e.args
    channels = e.args[2]
    assert len(channels) == 1, channels
    assert channels[0][0] == channel.object_path, channels
    assert channels[0][1] == channel_immutable, channels
    assert e.args[3] == [request_path], e.args
    assert e.args[4] == user_action_time
    assert isinstance(e.args[5], dict)
    assert len(e.args) == 6

    # Handler accepts the Channels
    q.dbus_return(e.message, signature='')

    # SucceededWithChannel is fired first
    e = q.expect('dbus-signal',
                 path=request_path,
                 interface=cs.CR,
                 signal='SucceededWithChannel')

    assertEquals(conn.object_path, e.args[0])
    assert isinstance(e.args[1], dict), e.args[1]
    assertEquals(channel.object_path, e.args[2])
    assertEquals(channel_immutable, e.args[3])

    # CR emits Succeeded
    q.expect('dbus-signal',
             path=request_path,
             interface=cs.CR,
             signal='Succeeded')

    # Close the channel
    channel.close()
def test(q, bus, mc):
    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******"
        },
        signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

    text_fixed_properties = dbus.Dictionary(
        {
            cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT,
            cs.CHANNEL + '.ChannelType': cs.CHANNEL + '.Type.RespawnObservers'
        },
        signature='sv')

    # Logger is an activatable Observer who will crash
    logger_bus = dbus.bus.BusConnection()
    logger_bus.set_exit_on_disconnect(False)  # we'll disconnect later

    # Kopete is an Approver, Handler and will not crash
    kopete_bus = dbus.bus.BusConnection()
    q.attach_to_bus(logger_bus)
    q.attach_to_bus(kopete_bus)

    kopete = SimulatedClient(q,
                             kopete_bus,
                             'Kopete',
                             observe=[],
                             approve=[text_fixed_properties],
                             handle=[text_fixed_properties],
                             bypass_approval=False)

    # wait for MC to download the properties
    expect_client_setup(q, [kopete])

    # subscribe to the OperationList interface (MC assumes that until this
    # property has been retrieved once, nobody cares)

    cd = bus.get_object(cs.CD, cs.CD_PATH)
    cd_props = dbus.Interface(cd, cs.PROPERTIES_IFACE)
    assert cd_props.Get(cs.CD_IFACE_OP_LIST, 'DispatchOperations') == []

    channel_properties = dbus.Dictionary(text_fixed_properties, signature='sv')
    channel_properties[cs.CHANNEL + '.TargetID'] = 'juliet'
    channel_properties[cs.CHANNEL + '.TargetHandle'] = \
            conn.ensure_handle(cs.HT_CONTACT, 'juliet')
    channel_properties[cs.CHANNEL + '.InitiatorID'] = 'juliet'
    channel_properties[cs.CHANNEL + '.InitiatorHandle'] = \
            conn.ensure_handle(cs.HT_CONTACT, 'juliet')
    channel_properties[cs.CHANNEL + '.Requested'] = False
    channel_properties[cs.CHANNEL + '.Interfaces'] = dbus.Array(signature='s')

    chan = SimulatedChannel(conn, channel_properties)
    chan.announce()

    # A channel dispatch operation is created

    e = q.expect('dbus-signal',
                 path=cs.CD_PATH,
                 interface=cs.CD_IFACE_OP_LIST,
                 signal='NewDispatchOperation')

    cdo_path = e.args[0]
    cdo_properties = e.args[1]

    assert cdo_properties[cs.CDO + '.Account'] == account.object_path
    assert cdo_properties[cs.CDO + '.Connection'] == conn.object_path
    assert cs.CDO + '.Interfaces' in cdo_properties

    handlers = cdo_properties[cs.CDO + '.PossibleHandlers'][:]
    handlers.sort()
    assert handlers == [cs.tp_name_prefix + '.Client.Kopete'], handlers

    assert cs.CD_IFACE_OP_LIST in cd_props.Get(cs.CD, 'Interfaces')
    assert cd_props.Get(cs.CD_IFACE_OP_LIST, 'DispatchOperations') ==\
            [(cdo_path, cdo_properties)]

    cdo = bus.get_object(cs.CD, cdo_path)
    cdo_iface = dbus.Interface(cdo, cs.CDO)
    cdo_props_iface = dbus.Interface(cdo, cs.PROPERTIES_IFACE)

    assert cdo_props_iface.Get(cs.CDO, 'Interfaces') == \
            cdo_properties[cs.CDO + '.Interfaces']
    assert cdo_props_iface.Get(cs.CDO, 'Connection') == conn.object_path
    assert cdo_props_iface.Get(cs.CDO, 'Account') == account.object_path
    assert cdo_props_iface.Get(cs.CDO, 'Channels') == [(chan.object_path,
                                                        channel_properties)]
    assert cdo_props_iface.Get(cs.CDO, 'PossibleHandlers') == \
            cdo_properties[cs.CDO + '.PossibleHandlers']

    k = q.expect('dbus-method-call',
                 path=kopete.object_path,
                 interface=cs.APPROVER,
                 method='AddDispatchOperation',
                 handled=False)

    assert k.args == [[(chan.object_path, channel_properties)], cdo_path,
                      cdo_properties]

    q.dbus_return(k.message, bus=kopete_bus, signature='')

    # The fake Logger implementation is run
    e = q.expect(
        'dbus-signal',
        path=cs.tp_path_prefix + '/RegressionTests',
        interface=cs.tp_name_prefix + '.RegressionTests',
        signal='FakeStartup',
        args=[cs.tp_name_prefix + '.Client.Logger'],
    )
    # We take on its identity to be able to continue with the test
    logger = SimulatedClient(q, bus, 'Logger', observe=[text_fixed_properties])

    # Logger is told about the new channel
    e = q.expect('dbus-method-call',
                 path=logger.object_path,
                 interface=cs.OBSERVER,
                 method='ObserveChannels',
                 handled=False)

    assert e.args[0] == account.object_path, e.args
    assert e.args[1] == conn.object_path, e.args
    assert e.args[3] == cdo_path, e.args
    assert e.args[4] == [], e.args  # no requests satisfied
    channels = e.args[2]
    assert len(channels) == 1, channels
    assert channels[0][0] == chan.object_path, channels
    assert channels[0][1] == channel_properties, channels

    # Logger indicates that it is ready to proceed
    q.dbus_return(e.message, bus=logger_bus, signature='')

    # The Approver (Kopete) is next

    # The user responds to Kopete
    call_async(q, cdo_iface, 'HandleWith',
               cs.tp_name_prefix + '.Client.Kopete')

    # Kopete is asked to handle the channels
    k = q.expect('dbus-method-call',
                 path=kopete.object_path,
                 interface=cs.HANDLER,
                 method='HandleChannels',
                 handled=False)

    # Kopete accepts the channels
    q.dbus_return(k.message, bus=kopete_bus, signature='')

    q.expect_many(
        EventPattern('dbus-return', method='HandleWith'),
        EventPattern('dbus-signal', interface=cs.CDO, signal='Finished'),
        EventPattern('dbus-signal',
                     interface=cs.CD_IFACE_OP_LIST,
                     signal='DispatchOperationFinished'),
    )

    # Now there are no more active channel dispatch operations
    assert cd_props.Get(cs.CD_IFACE_OP_LIST, 'DispatchOperations') == []

    # Logger crashes
    logger.release_name()

    e = q.expect(
        'dbus-signal',
        signal='NameOwnerChanged',
        predicate=(lambda e: e.args[0] == logger.bus_name and e.args[2] == ''),
    )
    logger_unique_name = e.args[1]

    logger_bus.flush()

    # Logger gets restart request
    e = q.expect(
        'dbus-signal',
        path=cs.tp_path_prefix + '/RegressionTests',
        interface=cs.tp_name_prefix + '.RegressionTests',
        signal='FakeStartup',
        args=[cs.tp_name_prefix + '.Client.Logger'],
    )

    # Logger gets restarted
    logger.reacquire_name()

    e = q.expect(
        'dbus-signal',
        signal='NameOwnerChanged',
        predicate=(lambda e: e.args[0] == logger.bus_name and e.args[1] == ''),
    )
    logger_unique_name = e.args[2]

    e = q.expect('dbus-method-call',
                 path=logger.object_path,
                 interface=cs.OBSERVER,
                 method='ObserveChannels',
                 handled=False)

    # FIXME: assert the same things as before, except CDO (which we don't
    # have) and account path (which we don't know how to get); also check
    # that the recovering observer info key is set
    assert e.args[0] == account.object_path, e.args
    assert e.args[1] == conn.object_path, e.args
    assert e.args[4] == [], e.args  # no requests satisfied
    assert e.args[5]['recovering'] == 1, e.args  # due to observer recovery
    channels = e.args[2]
    assert len(channels) == 1, channels
    assert channels[0][0] == chan.object_path, channels
    assert channels[0][1] == channel_properties, channels

    # Logger indicates that it is ready to proceed
    q.dbus_return(e.message, bus=logger_bus, signature='')

    sync_dbus(bus, q, mc)
Пример #21
0
def test(q, bus, conn, stream):
    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")

    call_async(q, conn.ContactList, 'GetContactListAttributes',
            [cs.CONN_IFACE_CONTACT_GROUPS], False)
    r = q.expect('dbus-return', method='GetContactListAttributes')
    assertLength(0, r.value[0].keys())

    # request subscription
    handle = conn.get_contact_handle_sync('*****@*****.**')
    call_async(q, conn.ContactList, 'RequestSubscription', [handle],
            'half past monsoon')

    # libpurple puts him on our blist as soon as we've asked; there doesn't
    # seem to be any concept of remote-pending state.
    #
    # It also puts him in the default group, probably "Buddies".
    set_iq, _, _, _, groups_changed = q.expect_many(
            EventPattern('stream-iq', iq_type='set',
                query_ns=ns.ROSTER, query_name='query'),
            EventPattern('stream-presence', presence_type='subscribe',
                to='*****@*****.**'),
            EventPattern('dbus-return', method='RequestSubscription', value=()),
            EventPattern('dbus-signal', signal='ContactsChangedWithID',
                args=[{
                    handle:
                        (cs.SUBSCRIPTION_STATE_YES,
                            cs.SUBSCRIPTION_STATE_UNKNOWN, ''),
                    },
                    {handle: '*****@*****.**'}, {}]),
            EventPattern('dbus-signal', signal='GroupsChanged',
                predicate=lambda e: e.args[0] == [handle]),
            )

    assertEquals('*****@*****.**', set_iq.query.item['jid'])
    acknowledge_iq(stream, set_iq.stanza)

    assertLength(1, groups_changed.args[1])
    assertLength(0, groups_changed.args[2])
    def_group = groups_changed.args[1][0]

    # Suggs accepts our subscription request
    presence = domish.Element(('jabber:client', 'presence'))
    presence['from'] = '*****@*****.**'
    presence['type'] = 'subscribed'
    stream.send(presence)

    # ... but nothing much happens, because there's no concept of pending
    # state in libpurple

    # put a contact into the *group* explicitly: this shouldn't ask for
    # subscription, but it does, because libpurple
    handle = conn.get_contact_handle_sync('*****@*****.**')
    call_async(q, conn.ContactGroups, 'AddToGroup', def_group, [handle])

    # libpurple puts her on our blist as soon as we've asked; there doesn't
    # seem to be any concept of remote-pending state. It also puts her in the
    # same group.
    set_iq, _, _, _, _ = q.expect_many(
            EventPattern('stream-iq', iq_type='set',
                query_ns=ns.ROSTER, query_name='query'),
            EventPattern('stream-presence', presence_type='subscribe',
                to='*****@*****.**'),
            EventPattern('dbus-return', method='AddToGroup', value=()),
            EventPattern('dbus-signal', signal='ContactsChangedWithID',
                args=[{
                    handle:
                        (cs.SUBSCRIPTION_STATE_YES,
                            cs.SUBSCRIPTION_STATE_UNKNOWN, ''),
                    },
                    {handle: '*****@*****.**'}, {}]),
            EventPattern('dbus-signal', signal='GroupsChanged',
                args=[[handle], [def_group], []]),
            )

    acknowledge_iq(stream, set_iq.stanza)
    assertEquals('*****@*****.**', set_iq.query.item['jid'])

    # cybergoths are less receptive to random subscription requests, so it
    # gets rejected
    presence = domish.Element(('jabber:client', 'presence'))
    presence['from'] = '*****@*****.**'
    presence['type'] = 'unsubscribed'
    stream.send(presence)

    # nothing happens, because there's no concept of pending state...

    sync_dbus(bus, q, conn)
    sync_stream(q, stream)
Пример #22
0
def run_outgoing_test(q, bus, conn, stream, close_channel=False):
    jp = JingleProtocol031 ()
    jt = JingleTest2(jp, conn, q, stream, 'test@localhost', muc + '/bob')
    jt.prepare()

    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")

    # Not allowed to have muji related presences before we accept the channel
    forbidden = [ no_muji_presences (muc) ]

    (path, props) = create_muji_channel (q, conn, stream, muc)

    q.forbid_events(forbidden)
    general_tests (jp, q, bus, conn, stream, path, props)

    channel = bus.get_object (conn.bus_name, path)

    props = channel.GetAll (cs.CHANNEL_TYPE_CALL,
        dbus_interface = dbus.PROPERTIES_IFACE)

    content = bus.get_object (conn.bus_name, props['Contents'][0])


    md = jt.get_call_audio_md_dbus()
    check_and_accept_offer (q, bus, conn, content, md)

    # Accept the channel, which means we can get muji presences
    q.unforbid_events (forbidden)
    channel.Accept()

    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')
    mujinode = xpath.queryForNodes("/presence/muji", e.stanza)
    assertLength (1, mujinode)

    # The one with the codecs
    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')

    # Gabble shouldn't send new presences for a while
    q.forbid_events(forbidden)

    presence = make_muc_presence('owner', 'moderator', muc, 'bob')
    presence.addElement ((ns.MUJI, 'muji')).addElement('preparing')
    stream.send(presence)

    presence = make_muc_presence('owner', 'moderator', muc, 'bob')
    muji =  ('muji', ns.MUJI, {},
        [('content', ns.MUJI, { "name": "Audio" },
            [( 'description', ns.JINGLE_RTP, {"media": "audio"},
            jt.generate_payloads(jt.audio_codecs))])])
    presence.addChild(jp._simple_xml(muji))
    stream.send(presence)

    q.expect('dbus-signal', signal = 'CallStateChanged')

    # Bob appears and starts a session right afterwards
    q.expect('dbus-signal', signal = 'CallMembersChanged')

    q.unforbid_events(forbidden)

    e = q.expect('dbus-signal', signal = 'NewMediaDescriptionOffer')
    offer = bus.get_object (conn.bus_name, e.args[0])
    offer.Accept(md, dbus_interface=cs.CALL_CONTENT_MEDIA_DESCRIPTION)

    jt.incoming_call(audio = "Audio")

    e = q.expect ('dbus-signal', signal = 'StreamsAdded')
    cstream = bus.get_object (conn.bus_name, e.args[0][0])

    candidates = jt.get_call_remote_transports_dbus ()
    cstream.AddCandidates (candidates,
        dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)

    # Fake our endpoint being connected
    endpoints = cstream.Get(cs.CALL_STREAM_IFACE_MEDIA,
        "Endpoints", dbus_interface=dbus.PROPERTIES_IFACE)
    assertLength (1, endpoints)

    endpoint = bus.get_object (conn.bus_name, endpoints[0])

    endpoint.SetEndpointState (1, cs.MEDIA_STREAM_STATE_CONNECTED,
                               dbus_interface=cs.CALL_STREAM_ENDPOINT)
    endpoint.SetEndpointState (2, cs.MEDIA_STREAM_STATE_CONNECTED,
                               dbus_interface=cs.CALL_STREAM_ENDPOINT)

    e = q.expect ('stream-iq',
        predicate = jp.action_predicate ('session-accept'))
    stream.send(jp.xml(jp.ResultIq(jt.peer, e.stanza, [])))

    # But we want video as well !
    c = channel.AddContent ("Camera!", cs.MEDIA_STREAM_TYPE_VIDEO,
        dbus_interface=cs.CHANNEL_TYPE_CALL)

    q.expect('dbus-signal', signal = 'ContentAdded')

    content = bus.get_object (conn.bus_name, c)

    # wait for the CodecOffer and Accept it
    q.expect('dbus-signal', signal = 'NewMediaDescriptionOffer')

    md = jt.get_call_video_md_dbus()
    check_and_accept_offer (q, bus, conn, content, md)
    
    # preparing
    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')

    #codecs
    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')

    # Bob would like to join our video party
    presence = make_muc_presence('owner', 'moderator', muc, 'bob')
    muji =  ('muji', ns.MUJI, {},
        [('content', ns.MUJI, { "name": "Audio" },
            [( 'description', ns.JINGLE_RTP, {"media": "audio"},
            jt.generate_payloads(jt.audio_codecs))]),
         ('content', ns.MUJI, { "name": "Camera!" },
            [( 'description', ns.JINGLE_RTP, {"media": "video"},
            jt.generate_payloads(jt.video_codecs))]),
        ])
    presence.addChild(jp._simple_xml(muji))
    stream.send(presence)

    # new codec offer as bob threw in some codecs
    q.expect('dbus-signal', signal='NewMediaDescriptionOffer')
    check_and_accept_offer (q, bus, conn, self_handle,
            content, codecs, check_codecs_changed = False)

    # Bob sends a content
    node = jp.SetIq(jt.peer, jt.jid, [
        jp.Jingle(jt.sid, jt.peer, 'content-add', [
            jp.Content('videostream', 'initiator', 'both',
                jp.Description('video', [
                    jp.PayloadType(name, str(rate), str(id), parameters) for
                        (name, id, rate, parameters) in jt.video_codecs ]),
            jp.TransportGoogleP2P()) ]) ])
    stream.send(jp.xml(node))

    # We get a new stream
    q.expect('dbus-signal', signal = 'StreamsAdded')

    # Sync up the stream to ensure we sent out all the xmpp traffic that was
    # the result of a stream being added
    sync_stream (q, stream)

    # happiness.. Now let's hang up
    if close_channel:
        channel.Close()
        hangup_event = EventPattern ('dbus-signal', signal = "Closed",
            path = path)
    else:
        channel.Hangup (0, "", "", dbus_interface=cs.CHANNEL_TYPE_CALL)
        hangup_event = EventPattern ('dbus-signal', signal='CallStateChanged')

    # Should change the call state to ended, send a session-terminate to our
    # only peer and send a muc presence without any mention of muji
    q.forbid_events(forbidden)
    q.expect_many (EventPattern ('stream-presence', to = muc + "/test"),
        EventPattern ('stream-iq',
                predicate=jp.action_predicate ('session-terminate')),
        hangup_event)

    if not close_channel:
        channel.Close()
        q.expect ('dbus-signal', signal="Closed", path = path)

    try:
        channel.Close()
        raise AssertionError ("Channel didn't actually close")
    except DBusException:
        pass
def test(q, bus, conn, stream):
    event = q.expect('stream-iq', query_ns=ns.ROSTER)

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

    assertEquals(
        {
            amy: UNKNOWN,
            bob: UNKNOWN,
            che: UNKNOWN,
            dre: UNKNOWN,
            eve: UNKNOWN,
        }, get_contacts_presences_sync(conn, [amy, bob, che, dre, eve]))

    # Before the server sends Gabble the roster, it relays an 'unavailable'
    # presence for one of the contacts we're subscribed to. This seems to
    # happen in practice when using Prosody with a shared roster: the presence
    # probes start coming back negatively before the shared roster is retrieved
    # and returned to the client.
    stream.send(make_presence('*****@*****.**', type='unavailable'))

    # Dre's presence is still unknown, since we don't have the roster. This
    # isn't a change per se---we checked above, and Dre's presence was
    # unknown---so it shouldn't be signalled.
    q.forbid_events([
        EventPattern('dbus-signal',
                     signal='PresencesChanged',
                     args=[{
                         dre: UNKNOWN
                     }])
    ])

    # We also receive an available presence from Eve before the roster arrives:
    # this presence should behave normally.
    stream.send(make_presence('*****@*****.**'))
    q.expect('dbus-signal', signal='PresencesChanged', args=[{eve: AVAILABLE}])

    # We also get a message from a contact before we get the roster (presumably
    # they sent this while we were offline?). This shouldn't affect the contact
    # being reported as offline when we finally do get the roster, but it used
    # to: <https://bugs.freedesktop.org/show_bug.cgi?id=41743>.
    stream.send(
        elem('message', from_='*****@*****.**',
             type='chat')(elem('body')(u'why are you never online?')))
    q.expect('dbus-signal', signal='MessageReceived')

    event.stanza['type'] = 'result'
    event.query.addChild(make_roster_item('*****@*****.**', 'both'))
    event.query.addChild(make_roster_item('*****@*****.**', 'from'))
    event.query.addChild(make_roster_item('*****@*****.**', 'to'))
    event.query.addChild(make_roster_item('*****@*****.**', 'both'))
    event.query.addChild(make_roster_item('*****@*****.**', 'both'))
    stream.send(event.stanza)

    # The presence for contacts on the roster whose subscription is 'to' or
    # 'both' but for whom we haven't already received presence should change
    # from 'unknown' (as checked above) to 'offline'.
    e = q.expect('dbus-signal', signal='PresencesChanged')
    changed_presences, = e.args
    assertEquals({
        amy: OFFLINE,
        che: OFFLINE,
        dre: OFFLINE,
    }, changed_presences)

    assertEquals(
        {
            amy: OFFLINE,
            bob: UNKNOWN,
            che: OFFLINE,
            dre: OFFLINE,
            eve: AVAILABLE,
        }, get_contacts_presences_sync(conn, [amy, bob, che, dre, eve]))
Пример #24
0
def run_incoming_test(q, bus, conn, stream, bob_leaves_room = False):
    jp = JingleProtocol031 ()
    jt = JingleTest2(jp, conn, q, stream, 'test@localhost', muc + "/bob")
    jt.prepare()
    forbidden = [ no_muji_presences (muc) ]

    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")

    _, _, test_handle, bob_handle = \
        join_muc_and_check(q, bus, conn, stream, muc)

    presence = make_muc_presence('owner', 'moderator', muc, 'bob')
    muji =  ('muji', ns.MUJI, {},
        [('content', ns.MUJI, { "name": "Voice" },
            [( 'description', ns.JINGLE_RTP, {"media": "audio"},
            jt.generate_payloads(jt.audio_codecs))])])
    presence.addChild(jp._simple_xml(muji))

    stream.send(presence)

    e = q.expect ('dbus-signal',
        signal='NewChannels',
        predicate=lambda e: \
            e.args[0][0][1][cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_CALL )

    (path, props) = e.args[0][0]

    assertContains((cs.CHANNEL_TYPE_CALL + '.InitialAudio', True),
        props.items())
    assertContains((cs.CHANNEL_TYPE_CALL + '.InitialVideo', False),
        props.items())

    general_tests (jp, q, bus, conn, stream, path, props)

    channel = bus.get_object (conn.bus_name, path)
    props = channel.GetAll (cs.CHANNEL_TYPE_CALL,
        dbus_interface = dbus.PROPERTIES_IFACE)

    content = bus.get_object (conn.bus_name, props['Contents'][0])

    check_state (q, channel, cs.CALL_STATE_PENDING_RECEIVER)

    md = jt.get_call_audio_md_dbus()
    check_and_accept_offer (q, bus, conn, self_handle,
            content, md)
    channel.Accept (dbus_interface=cs.CHANNEL_TYPE_CALL)

    # Preparing stanza
    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')

    # Codecs stanza
    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')

    # Gabble shouldn't send new presences for a while
    q.forbid_events(forbidden)

    e = q.expect ('dbus-signal', signal = 'StreamsAdded')
    cstream = bus.get_object (conn.bus_name, e.args[0][0])

    cstream.SetCredentials(jt.ufrag, jt.pwd,
        dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)

    candidates = jt.get_call_remote_transports_dbus ()
    cstream.AddCandidates (candidates,
        dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)

    e = q.expect('stream-iq',
        predicate=jp.action_predicate('session-initiate'))
    jt.parse_session_initiate (e.query)

    jt.accept()

   # Bob adds a Video content
    presence = make_muc_presence('owner', 'moderator', muc, 'bob')
    presence.addElement ((ns.MUJI, 'muji')).addElement('preparing')
    stream.send(presence)

    presence = make_muc_presence('owner', 'moderator', muc, 'bob')
    muji =  ('muji', ns.MUJI, {},
        [('content', ns.MUJI, { "name": "Voice" },
            [( 'description', ns.JINGLE_RTP, {"media": "audio"},
            jt.generate_payloads(jt.audio_codecs))]),
         ('content', ns.MUJI, { "name": "Camera" },
            [( 'description', ns.JINGLE_RTP, {"media": "video"},
            jt.generate_payloads(jt.video_codecs))]),
        ])
    presence.addChild(jp._simple_xml(muji))
    stream.send(presence)

    # Gabble noticed bob added a content
    e = q.expect('dbus-signal', signal = 'ContentAdded')

    q.unforbid_events (forbidden)
    content = bus.get_object (conn.bus_name, e.args[0])
    check_and_accept_offer (q, bus, conn, self_handle,
            content, jt.get_call_video_codecs_dbus(),
            check_codecs_changed = False)

    # Gabble sends a presence to prepare
    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')

    # Gabble sends a presence with the video codecs
    e = q.expect('stream-presence', to = muc + "/test")
    echo_muc_presence (q, stream, e.stanza, 'none', 'participant')

    # Gabble adds a content to the jingle session and thus a stream is added
    e = q.expect ('dbus-signal', signal = 'StreamsAdded')
    cstream = bus.get_object (conn.bus_name, e.args[0][0])

    candidates = jt.get_call_remote_transports_dbus ()
    cstream.AddCandidates (candidates,
        dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)

    # And now the content-add on the jingle streams
    e = q.expect('stream-iq', to = muc + "/bob",
        predicate = lambda x: \
        xpath.queryForNodes("/iq/jingle[@action='content-add']", x.stanza))

    # Bob leaves the call, bye bob
    if bob_leaves_room:
        presence = make_muc_presence('owner', 'moderator', muc, 'bob')
        presence['type'] = 'unavailable'
    else:
        presence = make_muc_presence('owner', 'moderator', muc, 'bob')

    stream.send(presence)
    (cmembers, _, _) = q.expect_many(
        EventPattern ('dbus-signal', signal = 'CallMembersChanged'),
        # Audio and video stream
        EventPattern ('dbus-signal', signal = 'StreamsRemoved'),
        EventPattern ('dbus-signal', signal = 'StreamsRemoved'))


    # Just bob left
    assertLength (1, cmembers.args[1])
def announce_common(q,
                    bus,
                    empathy,
                    kopete,
                    account,
                    conn,
                    cd_props,
                    urgent=False):
    if urgent:
        jid = 'friar.lawrence'
    else:
        jid = 'juliet'

    channel_properties = dbus.Dictionary(contact_text_fixed_properties,
                                         signature='sv')
    channel_properties[cs.CHANNEL + '.TargetID'] = jid
    channel_properties[cs.CHANNEL + '.TargetHandle'] = \
            conn.ensure_handle(cs.HT_CONTACT, jid)
    channel_properties[cs.CHANNEL + '.InitiatorID'] = jid
    channel_properties[cs.CHANNEL + '.InitiatorHandle'] = \
            conn.ensure_handle(cs.HT_CONTACT, jid)
    channel_properties[cs.CHANNEL + '.Requested'] = False
    channel_properties[cs.CHANNEL + '.Interfaces'] = dbus.Array(signature='s')

    if urgent:
        channel_properties['com.example.Urgency.Urgent'] = True

    chan = SimulatedChannel(conn, channel_properties)
    chan.announce()

    # A channel dispatch operation is created

    e = q.expect('dbus-signal',
                 path=cs.CD_PATH,
                 interface=cs.CD_IFACE_OP_LIST,
                 signal='NewDispatchOperation')

    cdo_path = e.args[0]
    cdo_properties = e.args[1]

    assert cdo_properties[cs.CDO + '.Account'] == account.object_path
    assert cdo_properties[cs.CDO + '.Connection'] == conn.object_path
    assert cs.CDO + '.Interfaces' in cdo_properties

    handlers = cdo_properties[cs.CDO + '.PossibleHandlers'][:]

    if urgent:
        # The handler with BypassApproval is first
        assert handlers[
            0] == cs.tp_name_prefix + '.Client.Kopete.BypassApproval'
        # Kopete's filter is more specific than Empathy's, so it comes next
        assert handlers[1] == cs.tp_name_prefix + '.Client.Kopete'
        # Empathy's filter is the least specific, so it's last
        assert handlers[2] == cs.tp_name_prefix + '.Client.Empathy'
        assert len(handlers) == 3
    else:
        handlers.sort()
        assert handlers == [
            cs.tp_name_prefix + '.Client.Empathy',
            cs.tp_name_prefix + '.Client.Kopete'
        ], handlers

    assert cs.CD_IFACE_OP_LIST in cd_props.Get(cs.CD, 'Interfaces')
    assert cd_props.Get(cs.CD_IFACE_OP_LIST, 'DispatchOperations') ==\
            [(cdo_path, cdo_properties)]

    cdo = bus.get_object(cs.CD, cdo_path)
    cdo_iface = dbus.Interface(cdo, cs.CDO)

    # Both Observers are told about the new channel

    e, k = q.expect_many(
        EventPattern('dbus-method-call',
                     path=empathy.object_path,
                     interface=cs.OBSERVER,
                     method='ObserveChannels',
                     handled=False),
        EventPattern('dbus-method-call',
                     path=kopete.object_path,
                     interface=cs.OBSERVER,
                     method='ObserveChannels',
                     handled=False),
    )
    assert e.args[0] == account.object_path, e.args
    assert e.args[1] == conn.object_path, e.args
    assert e.args[3] == cdo_path, e.args
    assert e.args[4] == [], e.args  # no requests satisfied
    channels = e.args[2]
    assert len(channels) == 1, channels
    assert channels[0][0] == chan.object_path, channels
    assert channels[0][1] == channel_properties, channels

    assert k.args == e.args

    return cdo_iface, chan, channel_properties, [e, k]
Пример #26
0
def test(q, bus, conn, stream):
    self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")

    romeo, juliet, duncan = conn.get_contact_handles_sync(
        ['*****@*****.**', '*****@*****.**', '*****@*****.**'])

    # receive some roster pushes for the "initial" state
    iq = IQ(stream, 'set')
    iq['id'] = 'roster-push'
    query = iq.addElement(('jabber:iq:roster', 'query'))
    item = query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'both'
    group = item.addElement('group', content='Still alive')
    group = item.addElement('group', content='Capulets')
    stream.send(iq)

    iq = IQ(stream, 'set')
    iq['id'] = 'roster-push'
    query = iq.addElement(('jabber:iq:roster', 'query'))
    item = query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'both'
    group = item.addElement('group', content='Still alive')
    stream.send(iq)

    iq = IQ(stream, 'set')
    iq['id'] = 'roster-push'
    query = iq.addElement(('jabber:iq:roster', 'query'))
    item = query.addElement('item')
    item['jid'] = '*****@*****.**'
    item['subscription'] = 'both'
    stream.send(iq)

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

    # the XMPP prpl puts people into some sort of group, probably called
    # Buddies
    groups = conn.Properties.Get(cs.CONN_IFACE_CONTACT_GROUPS, 'Groups')
    default_group = None

    for group in groups:
        if group in ('Capulets', 'Still alive'):
            continue

        if default_group is not None:
            raise AssertionError('Two unexplained groups: %s, %s' %
                                 (group, default_group))

        default_group = group

    call_async(q, conn.ContactList, 'GetContactListAttributes',
               [cs.CONN_IFACE_CONTACT_GROUPS], False)
    r = q.expect('dbus-return', method='GetContactListAttributes')

    assertSameSets(['Still alive'], r.value[0][romeo][cs.ATTR_GROUPS])
    assertSameSets(['Still alive', 'Capulets'],
                   r.value[0][juliet][cs.ATTR_GROUPS])
    assertSameSets([default_group], r.value[0][duncan][cs.ATTR_GROUPS])

    # We can't remove Duncan from the default group, because it's his only
    # group
    call_async(q, conn.ContactGroups, 'RemoveFromGroup', default_group,
               [duncan])
    q.expect('dbus-error', method='RemoveFromGroup', name=cs.NOT_AVAILABLE)
    call_async(q, conn.ContactGroups, 'SetGroupMembers', default_group, [])
    q.expect('dbus-error', method='SetGroupMembers', name=cs.NOT_AVAILABLE)
    # SetContactGroups just doesn't do anything in this situation
    call_async(q, conn.ContactGroups, 'SetContactGroups', duncan, [])
    q.expect('dbus-return', method='SetContactGroups')

    call_async(q, conn.ContactList, 'GetContactListAttributes',
               [cs.CONN_IFACE_CONTACT_GROUPS], False)
    r = q.expect('dbus-return', method='GetContactListAttributes')
    assertSameSets([default_group], r.value[0][duncan][cs.ATTR_GROUPS])

    # Make a new group and add Duncan to it
    call_async(q, conn.ContactGroups, 'AddToGroup', 'Scots', [duncan])
    iq, _, _ = q.expect_many(
        EventPattern('stream-iq',
                     iq_type='set',
                     query_name='query',
                     query_ns=ns.ROSTER),
        EventPattern('dbus-signal',
                     signal='GroupsChanged',
                     args=[[duncan], ['Scots'], []]),
        EventPattern('dbus-return', method='AddToGroup'),
    )
    assertEquals('*****@*****.**', iq.stanza.query.item['jid'])
    groups = set([
        str(x) for x in xpath.queryForNodes('/iq/query/item/group', iq.stanza)
    ])
    assertLength(2, groups)
    assertContains(default_group, groups)
    assertContains('Scots', groups)

    # Now we can remove him from the default group. Much rejoicing.
    call_async(q, conn.ContactGroups, 'RemoveFromGroup', default_group,
               [duncan])
    iq, _, _ = q.expect_many(
        EventPattern('stream-iq',
                     iq_type='set',
                     query_name='query',
                     query_ns=ns.ROSTER),
        EventPattern('dbus-signal',
                     signal='GroupsChanged',
                     args=[[duncan], [], [default_group]]),
        EventPattern('dbus-return', method='RemoveFromGroup'),
    )
    assertEquals('*****@*****.**', iq.stanza.query.item['jid'])
    groups = set([
        str(x) for x in xpath.queryForNodes('/iq/query/item/group', iq.stanza)
    ])
    assertLength(1, groups)
    assertContains('Scots', groups)

    # Test SetContactGroups, which didn't previously have proper coverage
    call_async(q, conn.ContactGroups, 'SetContactGroups', duncan,
               ['Scottish former kings'])
    iq, _, _, _ = q.expect_many(
        EventPattern('stream-iq',
                     iq_type='set',
                     query_name='query',
                     query_ns=ns.ROSTER),
        EventPattern('dbus-signal',
                     signal='GroupsChanged',
                     args=[[duncan], ['Scottish former kings'], []]),
        EventPattern('dbus-signal',
                     signal='GroupsChanged',
                     args=[[duncan], [], ['Scots']]),
        EventPattern('dbus-return', method='SetContactGroups'),
    )
    assertEquals('*****@*****.**', iq.stanza.query.item['jid'])
    groups = set([
        str(x) for x in xpath.queryForNodes('/iq/query/item/group', iq.stanza)
    ])
    assertLength(2, groups)
    assertContains('Scots', groups)
    assertContains('Scottish former kings', groups)
    iq, = q.expect_many(
        EventPattern('stream-iq',
                     iq_type='set',
                     query_name='query',
                     query_ns=ns.ROSTER), )
    assertEquals('*****@*****.**', iq.stanza.query.item['jid'])
    groups = set([
        str(x) for x in xpath.queryForNodes('/iq/query/item/group', iq.stanza)
    ])
    assertLength(1, groups)
    assertContains('Scottish former kings', groups)

    # Romeo dies. If he drops off the roster as a result, that would be
    # fd.o #21294. However, to fix that bug, Haze now puts him in the
    # default group.
    call_async(q, conn.ContactGroups, 'RemoveFromGroup', 'Still alive',
               [romeo])
    iq1, iq2, _, _, _ = q.expect_many(
        EventPattern('stream-iq',
                     iq_type='set',
                     query_name='query',
                     query_ns=ns.ROSTER),
        EventPattern('stream-iq',
                     iq_type='set',
                     query_name='query',
                     query_ns=ns.ROSTER),
        EventPattern('dbus-signal',
                     signal='GroupsChanged',
                     args=[[romeo], [default_group], []]),
        EventPattern('dbus-signal',
                     signal='GroupsChanged',
                     args=[[romeo], [], ['Still alive']]),
        EventPattern('dbus-return', method='RemoveFromGroup'),
    )

    assertEquals('*****@*****.**', iq1.stanza.query.item['jid'])
    groups = set([
        str(x) for x in xpath.queryForNodes('/iq/query/item/group', iq1.stanza)
    ])
    assertLength(2, groups)
    assertContains('Still alive', groups)
    assertContains(default_group, groups)

    assertEquals('*****@*****.**', iq2.stanza.query.item['jid'])
    groups = set([
        str(x) for x in xpath.queryForNodes('/iq/query/item/group', iq2.stanza)
    ])
    assertLength(1, groups)
    assertContains(default_group, groups)

    # Juliet dies. She's in another group already, so the workaround for
    # fd.o #21294 is not active.
    call_async(q, conn.ContactGroups, 'SetGroupMembers', 'Still alive', [])
    iq, _, _ = q.expect_many(
        EventPattern('stream-iq',
                     iq_type='set',
                     query_name='query',
                     query_ns=ns.ROSTER),
        EventPattern('dbus-signal',
                     signal='GroupsChanged',
                     args=[[juliet], [], ['Still alive']]),
        EventPattern('dbus-return', method='SetGroupMembers'),
    )
    assertEquals('*****@*****.**', iq.stanza.query.item['jid'])
    groups = set([
        str(x) for x in xpath.queryForNodes('/iq/query/item/group', iq.stanza)
    ])
    assertLength(1, groups)
    assertContains('Capulets', groups)

    # At the end of a tragedy, everyone dies, so there's no need for this
    # group.
    call_async(q, conn.ContactGroups, 'RemoveGroup', 'Still alive')
    q.expect('dbus-signal', signal='GroupsRemoved', args=[['Still alive']])

    # Deleting a non-empty group is allowed. (It removes everyone.)
    call_async(q, conn.ContactGroups, 'RemoveGroup', 'Capulets')
    q.expect_many(
        EventPattern('dbus-signal',
                     signal='GroupsRemoved',
                     args=[['Capulets']]),
        EventPattern('dbus-signal',
                     signal='GroupsChanged',
                     args=[[juliet], [default_group], []]),
        EventPattern('dbus-signal',
                     signal='GroupsChanged',
                     args=[[juliet], [], ['Capulets']]),
    )
def test(q, bus, mc):
    params = dbus.Dictionary(
        {
            "account": "yum yum network manager",
            "password": "******",
        },
        signature='sv')
    (simulated_cm, account) = create_fakecm_account(q, bus, mc, params)

    # While we're not connected to the internet, RequestConnection should not
    # be called.
    request_connection_event = [
        EventPattern('dbus-method-call', method='RequestConnection'),
    ]
    q.forbid_events(request_connection_event)

    account.Properties.Set(
        cs.ACCOUNT, 'RequestedPresence',
        (dbus.UInt32(cs.PRESENCE_BUSY), 'busy', 'hlaghalgh'))

    # Turn the account on, re-request an online presence, and even tell it to
    # connect automatically, to check that none of these make it sign in.
    call_async(q, account.Properties, 'Set', cs.ACCOUNT, 'Enabled', True)
    q.expect('dbus-return', method='Set')
    requested_presence = (dbus.UInt32(cs.PRESENCE_BUSY), 'busy', 'gtfo')
    call_async(q, account.Properties, 'Set', cs.ACCOUNT, 'RequestedPresence',
               requested_presence)
    q.expect('dbus-return', method='Set')
    call_async(q, account.Properties, 'Set', cs.ACCOUNT,
               'ConnectAutomatically', True)
    q.expect('dbus-return', method='Set')
    # (but actually let's turn ConnectAutomatically off: we want to check that
    # MC continues to try to apply RequestedPresence if the network connection
    # goes away and comes back again, regardless of this setting)
    call_async(q, account.Properties, 'Set', cs.ACCOUNT,
               'ConnectAutomatically', False)
    q.expect('dbus-return', method='Set')

    sync_dbus(bus, q, mc)
    q.unforbid_events(request_connection_event)

    # Okay, I'm satisfied. Turn the network on.
    mc.connectivity.go_online()

    expect_fakecm_connection(q,
                             bus,
                             mc,
                             account,
                             params,
                             has_presence=True,
                             expect_before_connect=[
                                 EventPattern('dbus-method-call',
                                              method='SetPresence',
                                              args=list(
                                                  requested_presence[1:])),
                             ])

    if config.HAVE_NM:
        # If NetworkManager tells us that it is going to disconnect soon,
        # the connection should be banished. GNetworkMonitor can't tell us
        # that; either it's online or it isn't.
        mc.connectivity.go_indeterminate()
        q.expect('dbus-method-call', method='Disconnect')

        mc.connectivity.go_offline()
        sync_connectivity_state(mc)

        # When we turn the network back on, MC should try to sign us back on.
        # In the process, our RequestedPresence should not have been
        # trampled on, as below.
        mc.connectivity.go_online()
        expect_fakecm_connection(q,
                                 bus,
                                 mc,
                                 account,
                                 params,
                                 has_presence=True,
                                 expect_before_connect=[
                                     EventPattern('dbus-method-call',
                                                  method='SetPresence',
                                                  args=list(
                                                      requested_presence[1:])),
                                 ])

        assertEquals(requested_presence,
                     account.Properties.Get(cs.ACCOUNT, 'RequestedPresence'))

    # If we turn the network off, the connection should be banished.
    mc.connectivity.go_offline()
    q.expect('dbus-method-call', method='Disconnect')

    # When we turn the network back on, MC should try to sign us back on.
    mc.connectivity.go_online()
    e = q.expect('dbus-method-call', method='RequestConnection')

    # In the process, our RequestedPresence should not have been trampled on.
    # (Historically, MC would replace it with the AutomaticPresence, but that
    # behaviour was unexpected: if the user explicitly set a status or message,
    # why should the network connection cutting out and coming back up cause
    # that to be lost?)
    assertEquals(requested_presence,
                 account.Properties.Get(cs.ACCOUNT, 'RequestedPresence'))

    # But if we get disconnected before RequestConnection returns, MC should
    # clean up the new connection when it does, rather than trying to sign it
    # in.
    connect_event = [
        EventPattern('dbus-method-call', method='Connect'),
    ]
    q.forbid_events(connect_event)

    mc.connectivity.go_offline()
    # Make sure that MC has noticed that the network connection has gone away.
    sync_connectivity_state(mc)

    conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol',
                               account.object_path.split('/')[-1], 'myself')
    q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so')

    q.expect('dbus-method-call', method='Disconnect')

    # So now the user gives up and sets their RequestedPresence to offline.
    # Because this account does not ConnectAutomatically, if the network
    # connection comes back up the account should not be brought back online.
    q.forbid_events(request_connection_event)
    account.Properties.Set(cs.ACCOUNT, 'RequestedPresence',
                           (dbus.UInt32(cs.PRESENCE_OFFLINE), 'offline', ''))
    mc.connectivity.go_online()
    # Make sure MC has noticed that the network connection has come back.
    sync_connectivity_state(mc)
Пример #28
0
def test_complex_success(q,
                         bus,
                         conn,
                         stream,
                         with_extra_data=True,
                         accept_early=False):
    chan, props = connect_and_get_sasl_channel(q, bus, conn)

    assertSameSets(MECHANISMS + ['X-TELEPATHY-PASSWORD'],
                   props.get(cs.SASL_AVAILABLE_MECHANISMS))

    call_async(q, chan.SASLAuthentication, 'StartMechanismWithData', "FOO", "")
    q.expect('dbus-error',
             method='StartMechanismWithData',
             name=cs.NOT_IMPLEMENTED)

    if with_extra_data:
        chan.SASLAuthentication.StartMechanismWithData("SCOTTISH-PLAY",
                                                       INITIAL_RESPONSE)
        e = q.expect('sasl-auth', initial_response=INITIAL_RESPONSE)
    else:
        chan.SASLAuthentication.StartMechanism("SCOTTISH-PLAY")
        e = q.expect('sasl-auth', has_initial_response=False)

    authenticator = e.authenticator

    q.expect('dbus-signal',
             signal='SASLStatusChanged',
             interface=cs.CHANNEL_IFACE_SASL_AUTH,
             args=[cs.SASL_STATUS_IN_PROGRESS, '', {}])

    if not with_extra_data:
        # send the stage directions in-band instead
        authenticator.challenge(b'')
        e = q.expect('dbus-signal',
                     signal='NewChallenge',
                     interface=cs.CHANNEL_IFACE_SASL_AUTH)
        # this ought to be '' but dbus-python has fd.o #28131
        assert e.args in ([b''], [b'None'])
        chan.SASLAuthentication.Respond(INITIAL_RESPONSE)
        q.expect('sasl-response', response=INITIAL_RESPONSE)

    for challenge, response in CR_PAIRS:
        authenticator.challenge(challenge)
        q.expect('dbus-signal',
                 signal='NewChallenge',
                 interface=cs.CHANNEL_IFACE_SASL_AUTH,
                 args=[challenge])
        chan.SASLAuthentication.Respond(response)
        q.expect('sasl-response', response=response)

    if with_extra_data:
        authenticator.success(SUCCESS_DATA)
    else:
        # The success data is sent in-band as a challenge
        authenticator.challenge(SUCCESS_DATA)

    q.expect('dbus-signal',
             signal='NewChallenge',
             interface=cs.CHANNEL_IFACE_SASL_AUTH,
             args=[SUCCESS_DATA])

    if accept_early:
        # the UI can tell that this challenge isn't actually a challenge,
        # it's a success in disguise
        chan.SASLAuthentication.AcceptSASL()
        q.expect('dbus-signal',
                 signal='SASLStatusChanged',
                 interface=cs.CHANNEL_IFACE_SASL_AUTH,
                 args=[cs.SASL_STATUS_CLIENT_ACCEPTED, '', {}])
    else:
        chan.SASLAuthentication.Respond(dbus.ByteArray(b''))

    if with_extra_data:
        # Wocky removes the distinction between a challenge containing
        # success data followed by a plain success, and a success
        # containing initial data, so we won't get to Server_Succeeded
        # til we "respond" to the "challenge". However, at the XMPP level,
        # we shouldn't get a response to a success.
        q.forbid_events([EventPattern('sasl-response')])
    else:
        q.expect('sasl-response', response=b'')
        authenticator.success(None)

    if not accept_early:
        # *now* we accept
        q.expect('dbus-signal',
                 signal='SASLStatusChanged',
                 interface=cs.CHANNEL_IFACE_SASL_AUTH,
                 args=[cs.SASL_STATUS_SERVER_SUCCEEDED, '', {}])
        # We're willing to accept this SASL transaction
        chan.SASLAuthentication.AcceptSASL()

    q.expect('dbus-signal',
             signal='SASLStatusChanged',
             interface=cs.CHANNEL_IFACE_SASL_AUTH,
             args=[cs.SASL_STATUS_SUCCEEDED, '', {}])

    q.expect('dbus-signal',
             signal='StatusChanged',
             args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])
    chan.Close()
    # ... and check that the Connection is still OK
    conn.Properties.Get(cs.CONN, "SelfHandle")
Пример #29
0
def test(q, bus, conn):
    self_name = 'testsuite' + '@' + avahitest.get_host_name()

    conn.Connect()

    q.expect('dbus-signal', signal='StatusChanged', args=[0L, 0L])

    # FIXME: this is a hack to be sure to have all the contact list channels
    # announced so they won't interfere with the roomlist ones announces.
    wait_for_contact_list(q, conn)

    # check if we can request roomlist channels
    properties = conn.GetAll(tp_name_prefix + '.Connection.Interface.Requests',
                             dbus_interface='org.freedesktop.DBus.Properties')
    assert ({tp_name_prefix + '.Channel.ChannelType':
                cs.CHANNEL_TYPE_ROOM_LIST,
             tp_name_prefix + '.Channel.TargetHandleType': 0,
             },
             [],
             ) in properties.get('RequestableChannelClasses'),\
                     properties['RequestableChannelClasses']

    requestotron = dbus.Interface(
        conn, tp_name_prefix + '.Connection.Interface.Requests')

    # create roomlist channel using new API
    call_async(
        q, requestotron, 'CreateChannel', {
            tp_name_prefix + '.Channel.ChannelType': cs.CHANNEL_TYPE_ROOM_LIST,
            tp_name_prefix + '.Channel.TargetHandleType': 0,
        })

    ret, new_sig = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'),
        EventPattern('dbus-signal', signal='NewChannels'),
    )
    path2 = ret.value[0]
    chan2 = wrap_channel(bus.get_object(conn.bus_name, path2), "RoomList")

    props = ret.value[1]
    assert props[tp_name_prefix + '.Channel.ChannelType'] ==\
            cs.CHANNEL_TYPE_ROOM_LIST
    assert props[tp_name_prefix + '.Channel.TargetHandleType'] == 0
    assert props[tp_name_prefix + '.Channel.TargetHandle'] == 0
    assert props[tp_name_prefix + '.Channel.TargetID'] == ''
    assert props[tp_name_prefix + '.Channel.Requested'] == True
    assert props[tp_name_prefix + '.Channel.InitiatorHandle'] \
            == conn.Properties.Get(cs.CONN, "SelfHandle")
    assert props[tp_name_prefix + '.Channel.InitiatorID'] \
            == self_name
    assert props[tp_name_prefix + '.Channel.Type.RoomList.Server'] == ''

    assert new_sig.args[0][0][0] == path2
    assert new_sig.args[0][0][1] == props

    assert chan2.Properties.Get(cs.CHANNEL_TYPE_ROOM_LIST, 'Server') == ''

    # ensure roomlist channel
    yours, ensured_path, ensured_props = requestotron.EnsureChannel({
        tp_name_prefix + '.Channel.ChannelType':
        cs.CHANNEL_TYPE_ROOM_LIST,
        tp_name_prefix + '.Channel.TargetHandleType':
        0,
    })

    assert not yours
    assert ensured_path == path2, (ensured_path, path2)

    # Closing roomlist channels crashed Salut for a while.
    chan2.Close()
    q.expect_many(
        EventPattern('dbus-signal', signal='Closed', path=path2),
        EventPattern('dbus-signal', signal='ChannelClosed', args=[path2]),
    )

    conn.Disconnect()

    q.expect_many(
        EventPattern('dbus-signal', signal='StatusChanged', args=[2, 1]), )
Пример #30
0
def test(q, bus, conn, stream):
    caps = {
        'node': client,
        'ver':  '0.1',
        }

    update_contact_caps(q, conn, stream, '[email protected]/Foo', caps)
    update_contact_caps(q, conn, stream, '[email protected]/Foo', caps)

    # Meredith signs in from one resource.
    update_contact_caps(q, conn, stream, '[email protected]/One', caps)
    # Meredith signs in from another resource with the same client. We don't
    # need to disco her, even though we don't trust this caps node in general
    # yet, because she's already told us what it means.
    meredith_two = '[email protected]/Two'
    q.forbid_events([
        EventPattern('stream-iq', to=meredith_two, query_ns=ns.DISCO_INFO)
        ])
    stream.send(make_presence(meredith_two, 'hello', caps=caps))
    sync_stream(q, stream)

    # Jens signs in from one resource, which is slow to answer the disco query.
    jens_one = '[email protected]/One'
    j = send_presence(q, conn, stream, jens_one, caps)
    j_stanza = expect_disco(q, jens_one, client, caps)

    # Jens now signs in elsewhere with the same client; we disco it (maybe
    # it'll reply sooner? Maybe his first client's network connection went away
    # and the server hasn't noticed yet?) and it replies immediately.
    update_contact_caps (q, conn, stream, '[email protected]/Two', caps,
        initial=False)

    # Jens' first client replies. We don't expect any caps changes here, and
    # this shouldn't count as a second point towards the five we need to trust
    # this caps node.
    send_disco_reply(stream, j_stanza, [], features)
    check_caps (conn, j)

    update_contact_caps (q, conn, stream, '[email protected]/Foo', caps)

    # Now five distinct contacts have told us what this caps node means, we
    # trust it.
    update_contact_caps (q, conn, stream, '[email protected]/Foo', caps,
        disco = False)
    update_contact_caps (q, conn, stream, '[email protected]/Foo', caps,
        disco = False)

    caps = {
        'node': client,
        'ver':  compute_caps_hash([], features, fake_client_dataforms),
        'hash': 'sha-1',
        }

    update_contact_caps(q, conn, stream, '[email protected]/Foo',
       caps,  dataforms = fake_client_dataforms)
    # We can verify the reply for these caps against the hash, and thus never
    # need to disco it again.
    update_contact_caps(q, conn, stream, '[email protected]/Foo', caps,
        disco = False, dataforms = fake_client_dataforms)
    update_contact_caps(q, conn, stream, '[email protected]/Foo', caps,
        disco = False, dataforms = fake_client_dataforms)