Пример #1
0
def drop_and_expect_reconnect(q, bus, conn):
    # Connection falls over for a miscellaneous reason
    conn.StatusChanged(cs.CONN_STATUS_DISCONNECTED, cs.CSR_NETWORK_ERROR)

    # MC reconnects

    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)

    return conn
Пример #2
0
def test(q, bus, mc):
    cm_bus = dbus.bus.BusConnection()
    cm_bus.set_exit_on_disconnect(False)   # we'll disconnect later
    q.attach_to_bus(cm_bus)

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

    account.Properties.Set(cs.ACCOUNT, 'Enabled', True)

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

    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, cm_bus, 'fakecm', 'fakeprotocol', '_',
            'myself', has_presence=True)

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

    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)

    # CM crashes
    conn.release_name()
    simulated_cm.release_name()
    cm_bus.flush()
    cm_bus.close()

    # MC should report the connection dying.
    e = q.expect('dbus-signal', signal='AccountPropertyChanged',
        predicate=lambda e: 'ConnectionError' in e.args[0])
    changed, = e.args
    assertEquals('/', changed['Connection'])
    assertEquals(cs.CONN_STATUS_DISCONNECTED, changed['ConnectionStatus'])
    # In the absence of a better code, None will have to do.
    assertEquals(cs.CSR_NONE_SPECIFIED, changed['ConnectionStatusReason'])
    # And NoReply will do as “it crashed”.
    assertEquals(cs.DBUS_ERROR_NO_REPLY, changed['ConnectionError'])
def test(q, bus, unused, **kwargs):
    simulated_cm = SimulatedConnectionManager(q, bus)

    # make sure RequestConnection doesn't get called yet
    events = [EventPattern('dbus-method-call', method='RequestConnection')]
    q.forbid_events(events)

    fake_accounts_service = kwargs['fake_accounts_service']
    preseed(q, bus, fake_accounts_service)

    # Wait for MC to load
    mc = MC(q, bus)

    # Trying to make a channel on account 1 doesn't work, because it's
    # not valid

    account_path = (cs.tp_path_prefix + '/Account/' + account1_id)

    cd = bus.get_object(cs.CD, cs.CD_PATH)

    user_action_time = dbus.Int64(1238582606)
    request = dbus.Dictionary(
        {
            cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_TEXT,
            cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT,
            cs.CHANNEL + '.TargetID': 'juliet',
        },
        signature='sv')
    call_async(q,
               cd,
               'CreateChannel',
               account_path,
               request,
               user_action_time,
               "",
               dbus_interface=cs.CD)
    ret = q.expect('dbus-return', method='CreateChannel')
    request_path = ret.value[0]

    cr = bus.get_object(cs.CD, request_path)
    request_props = cr.GetAll(cs.CR, dbus_interface=cs.PROPERTIES_IFACE)
    assert request_props['Account'] == account_path
    assert request_props['Requests'] == [request]
    assert request_props['UserActionTime'] == user_action_time
    assert request_props['PreferredHandler'] == ""
    assert request_props['Interfaces'] == []

    sync_dbus(bus, q, mc)

    cr.Proceed(dbus_interface=cs.CR)

    # FIXME: error isn't specified (NotAvailable perhaps?)
    q.expect('dbus-signal',
             path=cr.object_path,
             interface=cs.CR,
             signal='Failed')

    # Make account 1 valid: it should connect automatically

    account_path = (cs.tp_path_prefix + '/Account/' + account1_id)
    account = bus.get_object(cs.MC, account_path)

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

    call_async(q,
               account,
               'UpdateParameters', {'password': '******'}, [],
               dbus_interface=cs.ACCOUNT)

    expected_params = {
        'password': '******',
        'account': '*****@*****.**'
    }

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

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

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

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

    set_presence, e = q.expect_many(
        EventPattern('dbus-method-call',
                     path=conn.object_path,
                     interface=cs.CONN_IFACE_SIMPLE_PRESENCE,
                     method='SetPresence',
                     handled=True),
        EventPattern('dbus-signal',
                     signal='AccountPropertyChanged',
                     path=account_path,
                     interface=cs.ACCOUNT,
                     predicate=lambda e: 'CurrentPresence' in e.args[0] and e.
                     args[0]['CurrentPresence'][2] != ''),
    )

    assert e.args[0]['CurrentPresence'] == (cs.PRESENCE_AVAILABLE, 'available',
                                            'My vision is augmented')

    # Request an online presence on account 2, then make it valid

    q.forbid_events(events)

    account_path = (cs.tp_path_prefix + '/Account/' + account2_id)
    account = bus.get_object(cs.MC, account_path)

    requested_presence = dbus.Struct(
        (dbus.UInt32(cs.PRESENCE_BUSY), 'busy', 'Talking to Illuminati'))
    account.Set(cs.ACCOUNT,
                'RequestedPresence',
                dbus.Struct(requested_presence, variant_level=1),
                dbus_interface=cs.PROPERTIES_IFACE)

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

    # Make the account valid
    call_async(q,
               account,
               'UpdateParameters', {'password': '******'}, [],
               dbus_interface=cs.ACCOUNT)

    expected_params = {
        'password': '******',
        'account': '*****@*****.**'
    }

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

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

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

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

    set_presence = q.expect('dbus-method-call',
                            path=conn.object_path,
                            interface=cs.CONN_IFACE_SIMPLE_PRESENCE,
                            method='SetPresence',
                            handled=True)

    e = q.expect('dbus-signal',
                 signal='AccountPropertyChanged',
                 path=account_path,
                 interface=cs.ACCOUNT,
                 predicate=lambda e: 'CurrentPresence' in e.args[0] and e.args[
                     0]['CurrentPresence'][1] == 'busy')

    assert e.args[0]['CurrentPresence'] == (cs.PRESENCE_BUSY, 'busy',
                                            'Talking to Illuminati')
    def test(self, q, bus, mc):
        expected_params = {
            'account': self.id,
            'password': self.id,
        }

        account_path = (cs.ACCOUNT_PATH_PREFIX + self.id)
        account_proxy = bus.get_object(cs.AM, account_path)

        account_proxy.Set(cs.ACCOUNT,
                          'Enabled',
                          True,
                          dbus_interface=cs.PROPERTIES_IFACE)

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

        if self.remote_avatar is None:
            initial_avatar = None
        elif self.remote_avatar:
            initial_avatar = dbus.Struct(
                (dbus.ByteArray(self.remote_avatar), 'text/plain'),
                signature='ays')
        else:
            initial_avatar = dbus.Struct((dbus.ByteArray(''), ''),
                                         signature='ays')

        conn = SimulatedConnection(
            q,
            bus,
            'fakecm',
            'fakeprotocol',
            self.id.replace('fakecm/fakeprotocol/', ''),
            'myself',
            has_avatars=True,
            avatars_persist=self.avatars_persist,
            server_delays_avatar=self.server_delays,
            initial_avatar=initial_avatar,
        )

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

        if self.winner != 'MC':
            q.forbid_events([
                EventPattern('dbus-method-call', method='SetAvatar'),
            ])

        if self.winner != 'service':
            q.forbid_events([
                EventPattern('dbus-signal',
                             signal='AvatarChanged',
                             path=account_path),
            ])

        q.expect('dbus-method-call',
                 method='Connect',
                 path=conn.object_path,
                 handled=True,
                 interface=cs.CONN)

        conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CSR_NONE_SPECIFIED)

        if self.winner == 'MC':
            # MC should upload the avatar.
            _, e = q.expect_many(
                EventPattern('dbus-method-call',
                             interface=cs.CONN_IFACE_AVATARS,
                             method='SetAvatar',
                             args=[self.local_avatar, 'image/jpeg'],
                             handled=True),
                EventPattern(
                    'dbus-signal',
                    signal='AccountPropertyChanged',
                    path=account_path,
                    interface=cs.ACCOUNT,
                    predicate=(lambda e: e.args[0].get('ConnectionStatus') ==
                               cs.CONN_STATUS_CONNECTED),
                ),
            )
        elif self.winner == 'service':
            # We haven't changed the avatar since we last signed in, so we
            # don't set it - on the contrary, we pick up the remote avatar
            # (which has changed since we were last here) to store it in the
            # Account, unless the token says there is no avatar.
            if conn.avatar[0]:
                request_avatars_call, e = q.expect_many(
                    EventPattern('dbus-method-call',
                                 interface=cs.CONN_IFACE_AVATARS,
                                 method='RequestAvatars',
                                 args=[[conn.self_handle]],
                                 handled=False),
                    EventPattern(
                        'dbus-signal',
                        signal='AccountPropertyChanged',
                        path=account_path,
                        interface=cs.ACCOUNT,
                        predicate=(lambda e: e.args[0].get('ConnectionStatus')
                                   == cs.CONN_STATUS_CONNECTED),
                    ),
                )

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

                q.dbus_emit(conn.object_path,
                            cs.CONN_IFACE_AVATARS,
                            'AvatarRetrieved',
                            conn.self_handle,
                            str(conn.avatar[0]),
                            dbus.ByteArray(conn.avatar[0]),
                            conn.avatar[1],
                            signature='usays')

            q.expect('dbus-signal',
                     path=account_path,
                     interface=cs.ACCOUNT_IFACE_AVATAR,
                     signal='AvatarChanged'),

            account_props = dbus.Interface(account_proxy, cs.PROPERTIES_IFACE)
            assert account_props.Get(cs.ACCOUNT_IFACE_AVATAR,
                                     'Avatar',
                                     byte_arrays=True) == conn.avatar

        sync_dbus(bus, q, mc)
        q.unforbid_all()

        if self.local_avatar:
            self.test_migration(bus, q, conn, account_proxy)
def test(q, bus, mc, **kwargs):
    # Create an account
    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******",
            "nickname": "albinoblacksheep",
        },
        signature='sv')
    (simulated_cm, account) = create_fakecm_account(q, bus, mc, params)

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

    # Go online
    requested_presence = dbus.Struct(
        (dbus.UInt32(2L), 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')

    # Set some parameters. They include setting account to \\, as a regression
    # test for part of fd.o #28557.
    call_async(q,
               account,
               'UpdateParameters', {
                   'account': r'\\',
                   'secret-mushroom': '/Amanita muscaria/',
                   'snakes': dbus.UInt32(42),
                   'com.example.Badgerable.Badgered': True,
               }, [],
               dbus_interface=cs.ACCOUNT)

    set_call, ret, _ = q.expect_many(
        EventPattern('dbus-method-call',
                     path=conn.object_path,
                     interface=cs.PROPERTIES_IFACE,
                     method='Set',
                     args=['com.example.Badgerable', 'Badgered', True],
                     handled=False),
        EventPattern('dbus-return', method='UpdateParameters'),
        EventPattern('dbus-signal',
                     path=account.object_path,
                     interface=cs.ACCOUNT,
                     signal='AccountPropertyChanged',
                     args=[{
                         'Parameters': {
                             'account': r'\\',
                             'com.example.Badgerable.Badgered': True,
                             'password': '******',
                             'nickname': 'albinoblacksheep',
                             'secret-mushroom': '/Amanita muscaria/',
                             'snakes': 42,
                         }
                     }]),
    )

    # the D-Bus property should be set instantly; the others will take effect
    # on reconnection
    not_yet = ret.value[0]
    not_yet.sort()
    assert not_yet == ['account', 'secret-mushroom', 'snakes'], not_yet

    # Try to update 'account' to a value of the wrong type; MC should complain,
    # without having changed the value of 'snakes'.
    call_async(q,
               account,
               'UpdateParameters', {
                   'account': dbus.UInt32(39),
                   'snakes': dbus.UInt32(39),
               }, [],
               dbus_interface=cs.ACCOUNT)
    q.expect('dbus-error', name=cs.INVALID_ARGUMENT)

    props = account.Get(cs.ACCOUNT,
                        'Parameters',
                        dbus_interface=cs.PROPERTIES_IFACE)
    assertEquals(42, props['snakes'])

    # Try to update a parameter that doesn't exist; again, 'snakes' should not
    # be changed.
    call_async(q,
               account,
               'UpdateParameters', {
                   'accccccount': dbus.UInt32(39),
                   'snakes': dbus.UInt32(39),
               }, [],
               dbus_interface=cs.ACCOUNT)
    q.expect('dbus-error', name=cs.INVALID_ARGUMENT)

    props = account.Get(cs.ACCOUNT,
                        'Parameters',
                        dbus_interface=cs.PROPERTIES_IFACE)
    assertEquals(42, props['snakes'])

    # Unset some parameters, including a parameter which doesn't exist at all.
    # The spec says that “If the given parameters […] do not exist at all, the
    # account manager MUST accept this without error.”
    call_async(q,
               account,
               'UpdateParameters', {},
               ['nickname', 'com.example.Badgerable.Badgered', 'froufrou'],
               dbus_interface=cs.ACCOUNT)

    ret, _, _ = q.expect_many(
        EventPattern('dbus-return', method='UpdateParameters'),
        EventPattern('dbus-signal',
                     path=account.object_path,
                     interface=cs.ACCOUNT,
                     signal='AccountPropertyChanged',
                     args=[{
                         'Parameters': {
                             'account': r'\\',
                             'password': '******',
                             'secret-mushroom': '/Amanita muscaria/',
                             'snakes': 42,
                         }
                     }]),
        EventPattern('dbus-method-call',
                     path=conn.object_path,
                     interface=cs.PROPERTIES_IFACE,
                     method='Set',
                     args=['com.example.Badgerable', 'Badgered', False],
                     handled=False),
    )

    # Because com.example.Badgerable.Badgered has a default value (namely
    # False), unsetting that parameter should cause the default value to be set
    # on the CM.
    not_yet = ret.value[0]
    assertEquals(['nickname'], not_yet)

    # Set contrived-example to its default value; since there's been no
    # practical change, we shouldn't be told we need to reconnect to apply it.
    call_async(q, account, 'UpdateParameters',
               {'contrived-example': dbus.UInt32(5)}, [])
    ret, _ = q.expect_many(
        EventPattern('dbus-return', method='UpdateParameters'),
        EventPattern('dbus-signal',
                     path=account.object_path,
                     interface=cs.ACCOUNT,
                     signal='AccountPropertyChanged',
                     args=[{
                         'Parameters': {
                             'account': r'\\',
                             'password': '******',
                             'secret-mushroom': '/Amanita muscaria/',
                             'snakes': 42,
                             "contrived-example": 5,
                         }
                     }]),
    )
    not_yet = ret.value[0]
    assertEquals([], not_yet)

    # Unset contrived-example; again, MC should be smart enough to know we
    # don't need to do anything.
    call_async(q, account, 'UpdateParameters', {}, ['contrived-example'])
    ret, _ = q.expect_many(
        EventPattern('dbus-return', method='UpdateParameters'),
        EventPattern('dbus-signal',
                     path=account.object_path,
                     interface=cs.ACCOUNT,
                     signal='AccountPropertyChanged',
                     args=[{
                         'Parameters': {
                             'account': r'\\',
                             'password': '******',
                             'secret-mushroom': '/Amanita muscaria/',
                             'snakes': 42,
                         }
                     }]),
    )
    not_yet = ret.value[0]
    assertEquals([], not_yet)

    # Unset contrived-example again; the spec decrees that “If the given
    # parameters were not, in fact, stored, […] the account manager MUST accept
    # this without error.”
    call_async(q, account, 'UpdateParameters', {}, ['contrived-example'])
    ret = q.expect('dbus-return', method='UpdateParameters')
    not_yet = ret.value[0]
    assertEquals([], not_yet)

    cache_dir = os.environ['XDG_CACHE_HOME']

    # Now that we're using GVariant-based storage, the backslashes aren't
    # escaped.
    assertEquals(
        r'\\', kwargs['fake_accounts_service'].accounts[account.object_path[
            len(cs.ACCOUNT_PATH_PREFIX):]].params['account'])
    assertEquals(
        None, kwargs['fake_accounts_service'].accounts[account.object_path[
            len(cs.ACCOUNT_PATH_PREFIX):]].untyped_params.get('account', None))
def test(q, bus, mc):
    q.attach_to_bus(empathy_bus)
    q.attach_to_bus(kopete_bus)
    # Two clients want to observe, approve and handle channels
    empathy = SimulatedClient(q,
                              empathy_bus,
                              'Empathy',
                              observe=[text_fixed_properties],
                              approve=[text_fixed_properties],
                              handle=[text_fixed_properties],
                              bypass_approval=False)
    kopete = SimulatedClient(q,
                             kopete_bus,
                             'Kopete',
                             observe=[text_fixed_properties],
                             approve=[text_fixed_properties],
                             handle=[text_fixed_properties],
                             bypass_approval=False)

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

    # Create an account
    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******"
        },
        signature='sv')
    (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', 'first',
                               '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), )

    # 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)

    test_dispatching(q, bus, conn, account, empathy, kopete)

    # Connection falls over for a miscellaneous reason
    conn.StatusChanged(cs.CONN_STATUS_DISCONNECTED, cs.CSR_NETWORK_ERROR)

    # MC reconnects

    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', '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), )

    # 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)

    test_dispatching(q, bus, conn, account, empathy, kopete)
Пример #7
0
def test(q, bus, mc):
    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******"
        },
        signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)

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

    # Two clients want to observe, approve and handle channels
    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=[text_fixed_properties],
                             approve=[text_fixed_properties],
                             handle=[text_fixed_properties],
                             bypass_approval=False)

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

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

    requested_presence = dbus.Struct(
        (dbus.UInt32(2L), dbus.String(u'available'), dbus.String(u'')))
    account.Set(cs.ACCOUNT,
                'RequestedPresence',
                requested_presence,
                dbus_interface=cs.PROPERTIES_IFACE)

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

    # Don't allow the Connection to have its list of channels
    # until we want it to, by avoiding a return from GetAll(Requests).
    conn = SimulatedConnection(q,
                               bus,
                               'fakecm',
                               'fakeprotocol',
                               '_',
                               'myself',
                               implement_get_channels=False)

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

    get_all_requests_call = q.expect('dbus-method-call',
                                     method='GetAll',
                                     args=[cs.CONN_IFACE_REQUESTS])

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

    # 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') == []

    # Before returning from GetAll(Requests), make a Channel spring into
    # existence

    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()

    # Now reply to GetAll(Requests)
    conn.GetAll_Requests(get_all_requests_call)

    # A channel dispatch operation is created for the channel we already had

    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

    handlers = cdo_properties[cs.CDO + '.PossibleHandlers'][:]
    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

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

    # The Approvers are next

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

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

    q.dbus_return(e.message, signature='')
    q.dbus_return(k.message, signature='')

    # Both Approvers now have a flashing icon or something, trying to get the
    # user's attention

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

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

    # Empathy accepts the channels
    q.dbus_return(e.message, 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') == []
def test(q, bus, unused, **kwargs):
    fake_accounts_service = kwargs['fake_accounts_service']
    preseed(q, bus, fake_accounts_service)

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

    user_action_time = dbus.Int64(1238582606)

    # A client and a CM are already running
    client = SimulatedClient(q, bus, 'Empathy',
            observe=[text_fixed_properties], approve=[text_fixed_properties],
            handle=[text_fixed_properties], bypass_approval=False,
            implement_get_interfaces=False)
    simulated_cm = SimulatedConnectionManager(q, bus)

    # service-activate MC; it will try to introspect the running client.
    mc = MC(q, bus, wait_for_names=False)
    get_interfaces, = mc.wait_for_names(
        EventPattern('dbus-method-call', path=client.object_path,
            interface=cs.PROPERTIES_IFACE, method='Get',
            args=[cs.CLIENT, 'Interfaces'],
            handled=False))

    # The client doesn't reply just yet; meanwhile, immediately make a channel
    # request
    account = bus.get_object(cs.MC,
            cs.tp_path_prefix +
            '/Account/fakecm/fakeprotocol/jc_2edenton_40unatco_2eint')
    cd = bus.get_object(cs.MC, cs.CD_PATH)
    cd_props = dbus.Interface(cd, cs.PROPERTIES_IFACE)

    request = dbus.Dictionary({
            cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_TEXT,
            cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT,
            cs.CHANNEL + '.TargetID': '*****@*****.**',
            }, 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]

    # chat UI connects to signals and calls ChannelRequest.Proceed()
    cr = bus.get_object(cs.MC, 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)

    e = q.expect('dbus-method-call', method='RequestConnection',
            args=['fakeprotocol', {
                'account': '*****@*****.**',
                'password': '******',
                }],
            destination=cs.tp_name_prefix + '.ConnectionManager.fakecm',
            path=cs.tp_path_prefix + '/ConnectionManager/fakecm',
            interface=cs.tp_name_prefix + '.ConnectionManager',
            handled=False)
    conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', 'the_conn',
            '*****@*****.**')
    q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so')

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

    # A channel appears spontaneously

    announcement_immutable = dbus.Dictionary(text_fixed_properties)
    announcement_immutable[cs.CHANNEL + '.TargetID'] = '*****@*****.**'
    announcement_immutable[cs.CHANNEL + '.TargetHandle'] = \
            conn.ensure_handle(cs.HT_CONTACT, '*****@*****.**')
    announcement_immutable[cs.CHANNEL + '.InitiatorHandle'] = \
        announcement_immutable[cs.CHANNEL + '.TargetHandle']
    announcement_immutable[cs.CHANNEL + '.InitiatorID'] = \
        announcement_immutable[cs.CHANNEL + '.TargetID']
    announcement_immutable[cs.CHANNEL + '.Interfaces'] = \
            dbus.Array([], signature='s')
    announcement_immutable[cs.CHANNEL + '.Requested'] = False
    announcement = SimulatedChannel(conn, announcement_immutable)
    announcement.announce()

    # Now the Client returns its info
    q.dbus_return(get_interfaces.message,
            dbus.Array([cs.HANDLER, cs.OBSERVER, cs.APPROVER,
                cs.CLIENT_IFACE_REQUESTS], signature='s'), signature='v')

    expect_client_setup(q, [client], got_interfaces_already=True)

    # Now that the dispatcher is ready to go, we start looking for channels,
    # and also make the actual request
    # Empathy observes the channel we originally requested.
    _, a, cm_request_call = q.expect_many(
            EventPattern('dbus-method-call',
                interface=cs.PROPERTIES_IFACE, method='GetAll',
                args=[cs.CONN_IFACE_REQUESTS],
                path=conn.object_path, handled=True),
            EventPattern('dbus-method-call',
                path=client.object_path,
                interface=cs.OBSERVER, method='ObserveChannels',
                handled=False),
            EventPattern('dbus-method-call',
                interface=cs.CONN_IFACE_REQUESTS, method='CreateChannel',
                path=conn.object_path, args=[request], handled=False),
            )

    assert a.args[0] == account.object_path, a.args
    assert a.args[1] == conn.object_path, a.args
    assert a.args[3] != '/', a.args         # there is a dispatch operation
    assert a.args[4] == [], a.args
    channels = a.args[2]
    assert len(channels) == 1, channels
    assert channels[0][0] == announcement.object_path, channels
    assert channels[0][1] == announcement_immutable, channels

    # 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, '*****@*****.**')
    channel = SimulatedChannel(conn, channel_immutable)

    q.dbus_return(cm_request_call.message,
            channel.object_path, channel.immutable, signature='oa{sv}')
    channel.announce()

    # Empathy observes the newly-created channel.
    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

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

    # Empathy is asked to handle the channel
    e = q.expect('dbus-method-call',
            path=client.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
def test(q, bus, mc):
    params = dbus.Dictionary({"account": "*****@*****.**",
        "password": "******"}, signature='sv')
    (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)

    # Ensure that it's enabled but has offline RP and doesn't connect
    # automatically

    call_async(q, account_props, 'Set', cs.ACCOUNT, 'RequestedPresence',
            (dbus.UInt32(cs.PRESENCE_OFFLINE), 'offline', ''))
    q.expect('dbus-return', method='Set')

    call_async(q, account_props, 'Set', cs.ACCOUNT, 'AutomaticPresence',
            (dbus.UInt32(cs.PRESENCE_BUSY), 'busy',
                'Testing automatic presence'))
    q.expect('dbus-return', method='Set')
    q.expect('dbus-signal', signal='AccountPropertyChanged',
            predicate=lambda e:
                e.args[0].get('AutomaticPresence', (None, None, None))[1]
                    == 'busy')

    call_async(q, account_props, 'Set', cs.ACCOUNT, 'ConnectAutomatically',
            False)
    q.expect('dbus-return', method='Set')

    call_async(q, account_props, 'Set', cs.ACCOUNT, 'Enabled', True)
    q.expect('dbus-return', method='Set')
    q.expect('dbus-signal', signal='AccountPropertyChanged',
            predicate=lambda e: e.args[0].get('Enabled'))

    # Requesting a channel will put us online

    user_action_time = dbus.Int64(1238582606)

    cd = bus.get_object(cs.CD, cs.CD_PATH)

    request = dbus.Dictionary({
            cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_TEXT,
            cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT,
            cs.CHANNEL + '.TargetID': 'juliet',
            }, signature='sv')
    call_async(q, cd, 'CreateChannel',
            account.object_path, request, user_action_time, "",
            dbus_interface=cs.CD)
    ret = q.expect('dbus-return', method='CreateChannel')
    request_path = ret.value[0]

    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'] == ""
    assert request_props['Interfaces'] == []

    # make sure RequestConnection doesn't get called until we Proceed
    events = [EventPattern('dbus-method-call', method='RequestConnection')]
    q.forbid_events(events)

    sync_dbus(bus, q, mc)

    q.unforbid_events(events)

    cr.Proceed(dbus_interface=cs.CR)

    e = q.expect('dbus-method-call', method='RequestConnection',
            args=['fakeprotocol', params],
            destination=cs.tp_name_prefix + '.ConnectionManager.fakecm',
            path=cs.tp_path_prefix + '/ConnectionManager/fakecm',
            interface=cs.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')

    q.expect('dbus-method-call', method='Connect',
            path=conn.object_path, handled=True)
    conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CSR_NONE_SPECIFIED)
    conn.presence = dbus.Struct((cs.PRESENCE_AVAILABLE, 'available', ''),
            signature='uss')

    _, cm_request_call = q.expect_many(
            EventPattern('dbus-method-call', path=conn.object_path,
                interface=cs.CONN_IFACE_SIMPLE_PRESENCE, method='SetPresence',
                args=['busy', 'Testing automatic presence'], handled=True),
            EventPattern('dbus-method-call', path=conn.object_path,
                interface=cs.CONN_IFACE_REQUESTS, method='CreateChannel',
                args=[request], handled=False),
            )

    q.dbus_emit(conn.object_path, cs.CONN_IFACE_SIMPLE_PRESENCE,
            'PresencesChanged',
            {conn.self_handle: (dbus.UInt32(cs.PRESENCE_BUSY), 'busy',
                'Testing automatic presence')},
            signature='a{u(uss)}')

    # 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)
    q.dbus_return(cm_request_call.message,
            channel.object_path, channel.immutable, signature='oa{sv}')
    channel.announce()

    # there's no handler, so it gets shot down

    q.expect('dbus-method-call', path=channel.object_path, method='Close',
            handled=True)
def test(q, bus, mc):
    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******"
        },
        signature='sv')
    (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)

    # Ensure that it's enabled but has offline RP and doesn't connect
    # automatically

    verification_filter = dbus.Dictionary(
        {
            cs.CHANNEL + '.TargetHandleType': 0,
            cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_SERVER_TLS_CONNECTION,
        },
        signature='sv')

    verifier_bus = dbus.bus.BusConnection()
    q.attach_to_bus(verifier_bus)
    verifier = SimulatedClient(q,
                               verifier_bus,
                               'Verifier',
                               handle=[verification_filter])

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

    account_props.Set(cs.ACCOUNT, 'RequestedPresence',
                      (dbus.UInt32(cs.PRESENCE_AVAILABLE), 'available', ''))

    account_props.Set(cs.ACCOUNT, 'Enabled', True)

    e = q.expect('dbus-method-call',
                 method='RequestConnection',
                 args=['fakeprotocol', params],
                 destination=cs.tp_name_prefix + '.ConnectionManager.fakecm',
                 path=cs.tp_path_prefix + '/ConnectionManager/fakecm',
                 interface=cs.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')

    e = q.expect('dbus-method-call',
                 method='Connect',
                 path=conn.object_path,
                 interface=cs.CONN)

    channel_properties = dbus.Dictionary(verification_filter, signature='sv')
    channel_properties[cs.CHANNEL + '.TargetID'] = ''
    channel_properties[cs.CHANNEL + '.TargetHandle'] = 0
    channel_properties[cs.CHANNEL + '.InitiatorID'] = ''
    channel_properties[cs.CHANNEL + '.InitiatorHandle'] = 0
    channel_properties[cs.CHANNEL + '.Requested'] = False
    channel_properties[cs.CHANNEL + '.Interfaces'] = dbus.Array([],
                                                                signature='s')

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

    e = q.expect('dbus-method-call',
                 path=verifier.object_path,
                 interface=cs.HANDLER,
                 method='HandleChannels',
                 handled=False)
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)
Пример #12
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')
Пример #13
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
def test(q, bus, mc, fake_accounts_service=None, **kwargs):
    simulated_cm = SimulatedConnectionManager(q, bus)

    for enabled in (True, False):
        for online in (True, False):
            account_tail = ('fakecm/fakeprotocol/ezio_2efirenze_40fic' +
                            (enabled and '_enabled' or '_disabled') +
                            (online and '_online' or '_offline'))
            account_path = cs.ACCOUNT_PATH_PREFIX + account_tail

            try_to_connect = [
                EventPattern(
                    'dbus-method-call',
                    method='RequestConnection',
                    destination=cs.tp_name_prefix +
                    '.ConnectionManager.fakecm',
                    path=cs.tp_path_prefix + '/ConnectionManager/fakecm',
                    interface=cs.tp_name_prefix + '.ConnectionManager',
                    predicate=lambda e: e.args[1]['account'] == account_tail,
                    handled=False)
            ]

            if enabled and online:
                also_expected = try_to_connect[:]
            else:
                also_expected = []
                q.forbid_events(try_to_connect)

            args = (
                {
                    'Enabled':
                    enabled,
                    'ConnectAutomatically':
                    online,
                    'manager':
                    'fakecm',
                    'protocol':
                    'fakeprotocol',
                    'AutomaticPresence':
                    dbus.Struct((dbus.UInt32(
                        cs.PRESENCE_HIDDEN), 'hidden', 'press X to blend'),
                                signature='uss'),
                },
                {
                    'Enabled': 0,
                    'ConnectAutomatically': 0,
                    'manager': 0,
                    'protocol': 0,
                    'AutomaticPresence': 0,
                },
                {
                    'account': account_tail,
                    'password': '******'
                },
                {},  # untyped parameters
                {
                    'account': 0,
                    'password': cs.PARAM_SECRET
                },
                cs.StorageRestrictionFlags.CANNOT_SET_PRESENCE
                | cs.StorageRestrictionFlags.CANNOT_SET_ENABLED,
            )

            fake_accounts_service.create_account(account_tail, *args)

            events = q.expect_many(
                EventPattern('dbus-signal',
                             path=cs.TEST_DBUS_ACCOUNT_SERVICE_PATH,
                             signal='AccountCreated',
                             args=[account_tail] + list(args)),
                EventPattern('dbus-signal',
                             path=cs.AM_PATH,
                             signal='AccountValidityChanged',
                             args=[account_path, True]), *also_expected)
            account = Account(bus, account_path)

            if enabled and online:
                conn = SimulatedConnection(q,
                                           bus,
                                           'fakecm',
                                           'fakeprotocol',
                                           account_tail.replace('/', '_'),
                                           'ezio',
                                           has_presence=True)
                q.dbus_return(events[-1].message,
                              conn.bus_name,
                              conn.object_path,
                              signature='so')
                q.expect(
                    'dbus-method-call',
                    method='SetPresence',
                    # the fake CM doesn't support 'hidden' by default
                    args=['busy', 'press X to blend'])

                requested_presence = (dbus.UInt32(cs.PRESENCE_HIDDEN),
                                      'hidden', 'press X to blend')
            else:
                requested_presence = (dbus.UInt32(cs.PRESENCE_OFFLINE),
                                      'offline', '')

            call_async(q, account.Properties, 'Get', cs.ACCOUNT,
                       'RequestedPresence')
            q.expect('dbus-return', method='Get', value=(requested_presence, ))

            # changes that are not really changes are fine
            call_async(q, account.Properties, 'Set', cs.ACCOUNT, 'Enabled',
                       enabled)
            q.expect('dbus-return', method='Set')
            call_async(q, account.Properties, 'Set', cs.ACCOUNT,
                       'ConnectAutomatically', online)
            q.expect('dbus-return', method='Set')

            # changes that actually change the restrictive properties
            # are not allowed
            call_async(q, account.Properties, 'Set', cs.ACCOUNT,
                       'RequestedPresence',
                       ((dbus.UInt32(cs.PRESENCE_AVAILABLE), 'available',
                         'highly conspicuous')))
            q.expect('dbus-error', method='Set')
            call_async(q, account.Properties, 'Set', cs.ACCOUNT,
                       'AutomaticPresence',
                       ((dbus.UInt32(cs.PRESENCE_AVAILABLE), 'available',
                         'highly conspicuous')))
            q.expect('dbus-error', method='Set')
            call_async(q, account.Properties, 'Set', cs.ACCOUNT, 'Enabled',
                       not enabled)
            q.expect('dbus-error', method='Set')
            call_async(q, account.Properties, 'Set', cs.ACCOUNT,
                       'ConnectAutomatically', not online)
            q.expect('dbus-error', method='Set')

            call_async(q, account, 'Remove')
            q.expect('dbus-error', method='Remove')

            # ... but the backend can still change them
            if enabled and online:
                q.forbid_events(try_to_connect)
                fake_accounts_service.update_attributes(
                    account_tail, {
                        'Enabled': False,
                        'ConnectAutomatically': False,
                    })
                q.expect('dbus-method-call', method='Disconnect')
                q.unforbid_events(try_to_connect)
            else:
                q.unforbid_events(try_to_connect)
                fake_accounts_service.update_attributes(
                    account_tail, {
                        'Enabled': True,
                        'ConnectAutomatically': True,
                    })

                events = q.expect_many(*try_to_connect)
                conn = SimulatedConnection(q,
                                           bus,
                                           'fakecm',
                                           'fakeprotocol',
                                           account_tail.replace('/', '_'),
                                           'ezio',
                                           has_presence=True)
                q.dbus_return(events[-1].message,
                              conn.bus_name,
                              conn.object_path,
                              signature='so')

                # we are connected: deleting the account should
                # disconnect us
                fake_accounts_service.delete_account(account_tail)
                q.expect_many(
                    EventPattern('dbus-signal',
                                 signal='AccountRemoved',
                                 args=[account_path]),
                    EventPattern('dbus-signal',
                                 signal='Removed',
                                 path=account_path),
                    EventPattern('dbus-method-call', method='Disconnect'),
                )
Пример #15
0
def test(q, bus, mc):
    http_fixed_properties = dbus.Dictionary({
        cs.CHANNEL + '.TargetHandleType': 1L,
        cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_STREAM_TUBE,
        cs.CHANNEL_TYPE_STREAM_TUBE + '.Service':
            'http'
        }, signature='sv')
    caps = dbus.Array([http_fixed_properties], signature='a{sv}')

    # Be a Client
    client = SimulatedClient(q, bus, 'downloader',
            observe=[], approve=[], handle=[http_fixed_properties],
            bypass_approval=False)
    expect_client_setup(q, [client])

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

    # The account is initially valid but disabled, and hence offline
    props = account.GetAll(cs.ACCOUNT, dbus_interface=cs.PROPERTIES_IFACE)
    assert not props['Enabled']
    assert props['Valid']
    # The spec says it should be (Offline, "", "") but I don't think the
    # strings really matter. If anything, the second one should start out at
    # "offline".
    assertEquals(cs.PRESENCE_OFFLINE, props['CurrentPresence'][0])

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

    props = account.GetAll(cs.ACCOUNT, dbus_interface=cs.PROPERTIES_IFACE)
    assert props['Enabled']
    assert props['Valid']
    # Ditto above re. string fields.
    assertEquals(cs.PRESENCE_OFFLINE, props['CurrentPresence'][0])

    # Go online
    requested_presence = dbus.Struct((dbus.UInt32(2L), 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('HasBeenOnline')
    assertEquals(requested_presence, properties.get('RequestedPresence'))

    # Since this Connection doesn't support SimplePresence, but it's online,
    # the spec says that CurrentPresence should be Unset.
    assertEquals((cs.PRESENCE_UNSET, "", ""),
        properties.get('CurrentPresence'))

    new_channel = http_fixed_properties
    buddy_handle = conn.ensure_handle(cs.HT_CONTACT, "buddy")
    new_channel[cs.CHANNEL + '.TargetID'] = "buddy"
    new_channel[cs.CHANNEL + '.TargetHandle'] = buddy_handle
    new_channel[cs.CHANNEL + '.Requested'] = False
    new_channel[cs.CHANNEL + '.Interfaces'] = dbus.Array(signature='s')

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

    e = q.expect('dbus-method-call', method='HandleChannels')
    q.dbus_return(e.message, signature='')

    # 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. But it should not
    # Close() the open channel.
    q.forbid_events([
        EventPattern('dbus-method-call', method='Close', path=conn.object_path),
        ])
    q.expect('dbus-method-call', method='Disconnect',
            path=conn.object_path, handled=True)

    properties = account.GetAll(cs.ACCOUNT, dbus_interface=cs.PROPERTIES_IFACE)
    assertEquals('/', properties['Connection'])
    assertEquals(cs.CONN_STATUS_DISCONNECTED, properties['ConnectionStatus'])
    assertEquals(requested_presence, properties['CurrentPresence'])
    assertEquals(requested_presence, properties['RequestedPresence'])
def test(q, bus, mc):
    params = dbus.Dictionary({"account": "*****@*****.**",
        "password": "******"}, signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)

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

    # Two clients want to observe, approve and handle channels
    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=[text_fixed_properties], approve=[text_fixed_properties],
            handle=[text_fixed_properties], bypass_approval=False)

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

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

    requested_presence = dbus.Struct((dbus.UInt32(2L),
        dbus.String(u'available'), dbus.String(u'')))
    account.Set(cs.ACCOUNT,
            'RequestedPresence', requested_presence,
            dbus_interface=cs.PROPERTIES_IFACE)

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

    # Don't allow the Connection to have its list of channels
    # until we want it to, by avoiding a return from GetAll(Requests).
    conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', '_',
            'myself', implement_get_channels=False)

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

    get_all_requests_call = q.expect('dbus-method-call',
            method='GetAll', args=[cs.CONN_IFACE_REQUESTS])

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

    # 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') == []

    # Before returning from GetAll(Requests), make a Channel spring into
    # existence

    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()

    # Now reply to GetAll(Requests)
    conn.GetAll_Requests(get_all_requests_call)

    # A channel dispatch operation is created for the channel we already had

    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

    handlers = cdo_properties[cs.CDO + '.PossibleHandlers'][:]
    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

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

    # The Approvers are next

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

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

    q.dbus_return(e.message, signature='')
    q.dbus_return(k.message, signature='')

    # Both Approvers now have a flashing icon or something, trying to get the
    # user's attention

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

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

    # Empathy accepts the channels
    q.dbus_return(e.message, 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') == []
Пример #17
0
def test(q, bus, unused, **kwargs):
    simulated_cm = SimulatedConnectionManager(q, bus)

    fake_accounts_service = kwargs['fake_accounts_service']
    preseed(q, bus, fake_accounts_service)

    expected_params = {
        'account': '*****@*****.**',
        'password': r'\\ionstorm\\',
    }

    mc = MC(q, bus, wait_for_names=False)
    mc.wait_for_names(
        # Migration step: the three separate attributes get combined
        # (before the names are taken, so we need to expect it here)
        EventPattern(
            'dbus-method-call',
            interface=cs.TEST_DBUS_ACCOUNT_SERVICE_IFACE,
            method='UpdateAttributes',
            predicate=(
                lambda e: e.args[0] == account_id and e.args[1] == {
                    'AutomaticPresence':
                    (2, 'available', 'My vision is augmented')
                } and e.args[2] == {
                    'AutomaticPresence': 0
                } and  # flags
                set(e.args[3]) == set([  # no particular order
                    'AutomaticPresenceType',
                    'AutomaticPresenceStatus',
                    'AutomaticPresenceMessage',
                ]))))

    request_conn, prop_changed = q.expect_many(
        EventPattern('dbus-method-call',
                     method='RequestConnection',
                     args=['fakeprotocol', expected_params],
                     destination=cs.tp_name_prefix +
                     '.ConnectionManager.fakecm',
                     path=cs.tp_path_prefix + '/ConnectionManager/fakecm',
                     interface=cs.tp_name_prefix + '.ConnectionManager',
                     handled=False),
        EventPattern('dbus-signal',
                     signal='AccountPropertyChanged',
                     predicate=(lambda e: 'ConnectionStatus' in e.args[0])),
    )

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

    assertEquals('/', prop_changed.args[0].get('Connection'))
    assertEquals('', prop_changed.args[0].get('ConnectionError'))
    assertEquals({}, prop_changed.args[0].get('ConnectionErrorDetails'))
    assertEquals(cs.CONN_STATUS_CONNECTING,
                 prop_changed.args[0].get('ConnectionStatus'))
    assertEquals(cs.CSR_REQUESTED,
                 prop_changed.args[0].get('ConnectionStatusReason'))

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

    account_path = (cs.tp_path_prefix + '/Account/' + account_id)
    account = bus.get_object(cs.tp_name_prefix + '.AccountManager',
                             account_path)

    prop_changed, _ = q.expect_many(
        EventPattern('dbus-signal',
                     signal='AccountPropertyChanged',
                     predicate=(lambda e: 'ConnectionStatus' in e.args[0])),
        EventPattern('dbus-method-call',
                     method='Connect',
                     path=conn.object_path,
                     handled=True,
                     interface=cs.CONN),
    )

    assertEquals(conn.object_path, prop_changed.args[0].get('Connection'))
    assertEquals('', prop_changed.args[0].get('ConnectionError'))
    assertEquals({}, prop_changed.args[0].get('ConnectionErrorDetails'))
    assertEquals(cs.CONN_STATUS_CONNECTING,
                 prop_changed.args[0].get('ConnectionStatus'))
    assertEquals(cs.CSR_REQUESTED,
                 prop_changed.args[0].get('ConnectionStatusReason'))

    props = account.GetAll(cs.ACCOUNT, dbus_interface=cs.PROPERTIES_IFACE)
    assert props['Connection'] == conn.object_path
    assert props['ConnectionStatus'] == cs.CONN_STATUS_CONNECTING
    assert props['ConnectionStatusReason'] == cs.CSR_REQUESTED

    print "becoming connected"
    conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CSR_NONE_SPECIFIED)

    set_aliases, set_presence, set_avatar, prop_changed = q.expect_many(
        EventPattern('dbus-method-call',
                     interface=cs.CONN_IFACE_ALIASING,
                     method='SetAliases',
                     args=[{
                         conn.self_handle: 'JC'
                     }],
                     handled=False),
        EventPattern('dbus-method-call',
                     path=conn.object_path,
                     interface=cs.CONN_IFACE_SIMPLE_PRESENCE,
                     method='SetPresence',
                     handled=True),
        EventPattern('dbus-method-call',
                     interface=cs.CONN_IFACE_AVATARS,
                     method='SetAvatar',
                     args=['Deus Ex', 'image/jpeg'],
                     handled=True),
        EventPattern(
            'dbus-signal',
            signal='AccountPropertyChanged',
            path=account_path,
            interface=cs.ACCOUNT,
            predicate=(lambda e: e.args[0].get('ConnectionStatus') == cs.
                       CONN_STATUS_CONNECTED),
        ),
    )

    assertEquals(conn.object_path, prop_changed.args[0].get('Connection'))
    assertEquals('', prop_changed.args[0].get('ConnectionError'))
    assertEquals({}, prop_changed.args[0].get('ConnectionErrorDetails'))
    assertEquals(cs.CONN_STATUS_CONNECTED,
                 prop_changed.args[0].get('ConnectionStatus'))
    assertEquals(cs.CSR_REQUESTED,
                 prop_changed.args[0].get('ConnectionStatusReason'))

    assert account.Get(
        cs.ACCOUNT, 'CurrentPresence',
        dbus_interface=cs.PROPERTIES_IFACE) == (cs.PRESENCE_AVAILABLE,
                                                'available',
                                                'My vision is augmented')

    q.dbus_return(set_aliases.message, signature='')
Пример #18
0
def test(q, bus, unused, **kwargs):
    fake_accounts_service = kwargs['fake_accounts_service']
    preseed(q, bus, fake_accounts_service)

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

    user_action_time = dbus.Int64(1238582606)

    # A client and a CM are already running
    client = SimulatedClient(q,
                             bus,
                             'Empathy',
                             observe=[text_fixed_properties],
                             approve=[text_fixed_properties],
                             handle=[text_fixed_properties],
                             bypass_approval=False,
                             implement_get_interfaces=False)
    simulated_cm = SimulatedConnectionManager(q, bus)

    # service-activate MC; it will try to introspect the running client.
    mc = MC(q, bus, wait_for_names=False)
    get_interfaces, = mc.wait_for_names(
        EventPattern('dbus-method-call',
                     path=client.object_path,
                     interface=cs.PROPERTIES_IFACE,
                     method='Get',
                     args=[cs.CLIENT, 'Interfaces'],
                     handled=False))

    # The client doesn't reply just yet; meanwhile, immediately make a channel
    # request
    account = bus.get_object(
        cs.MC, cs.tp_path_prefix +
        '/Account/fakecm/fakeprotocol/jc_2edenton_40unatco_2eint')
    cd = bus.get_object(cs.MC, cs.CD_PATH)
    cd_props = dbus.Interface(cd, cs.PROPERTIES_IFACE)

    request = dbus.Dictionary(
        {
            cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_TEXT,
            cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT,
            cs.CHANNEL + '.TargetID': '*****@*****.**',
        },
        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]

    # chat UI connects to signals and calls ChannelRequest.Proceed()
    cr = bus.get_object(cs.MC, 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)

    e = q.expect('dbus-method-call',
                 method='RequestConnection',
                 args=[
                     'fakeprotocol', {
                         'account': '*****@*****.**',
                         'password': '******',
                     }
                 ],
                 destination=cs.tp_name_prefix + '.ConnectionManager.fakecm',
                 path=cs.tp_path_prefix + '/ConnectionManager/fakecm',
                 interface=cs.tp_name_prefix + '.ConnectionManager',
                 handled=False)
    conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', 'the_conn',
                               '*****@*****.**')
    q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so')

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

    # A channel appears spontaneously

    announcement_immutable = dbus.Dictionary(text_fixed_properties)
    announcement_immutable[cs.CHANNEL + '.TargetID'] = '*****@*****.**'
    announcement_immutable[cs.CHANNEL + '.TargetHandle'] = \
            conn.ensure_handle(cs.HT_CONTACT, '*****@*****.**')
    announcement_immutable[cs.CHANNEL + '.InitiatorHandle'] = \
        announcement_immutable[cs.CHANNEL + '.TargetHandle']
    announcement_immutable[cs.CHANNEL + '.InitiatorID'] = \
        announcement_immutable[cs.CHANNEL + '.TargetID']
    announcement_immutable[cs.CHANNEL + '.Interfaces'] = \
            dbus.Array([], signature='s')
    announcement_immutable[cs.CHANNEL + '.Requested'] = False
    announcement = SimulatedChannel(conn, announcement_immutable)
    announcement.announce()

    # Now the Client returns its info
    q.dbus_return(
        get_interfaces.message,
        dbus.Array(
            [cs.HANDLER, cs.OBSERVER, cs.APPROVER, cs.CLIENT_IFACE_REQUESTS],
            signature='s'),
        signature='v')

    expect_client_setup(q, [client], got_interfaces_already=True)

    # Now that the dispatcher is ready to go, we start looking for channels,
    # and also make the actual request
    # Empathy observes the channel we originally requested.
    _, a, cm_request_call = q.expect_many(
        EventPattern('dbus-method-call',
                     interface=cs.PROPERTIES_IFACE,
                     method='GetAll',
                     args=[cs.CONN_IFACE_REQUESTS],
                     path=conn.object_path,
                     handled=True),
        EventPattern('dbus-method-call',
                     path=client.object_path,
                     interface=cs.OBSERVER,
                     method='ObserveChannels',
                     handled=False),
        EventPattern('dbus-method-call',
                     interface=cs.CONN_IFACE_REQUESTS,
                     method='CreateChannel',
                     path=conn.object_path,
                     args=[request],
                     handled=False),
    )

    assert a.args[0] == account.object_path, a.args
    assert a.args[1] == conn.object_path, a.args
    assert a.args[3] != '/', a.args  # there is a dispatch operation
    assert a.args[4] == [], a.args
    channels = a.args[2]
    assert len(channels) == 1, channels
    assert channels[0][0] == announcement.object_path, channels
    assert channels[0][1] == announcement_immutable, channels

    # 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, '*****@*****.**')
    channel = SimulatedChannel(conn, channel_immutable)

    q.dbus_return(cm_request_call.message,
                  channel.object_path,
                  channel.immutable,
                  signature='oa{sv}')
    channel.announce()

    # Empathy observes the newly-created channel.
    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

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

    # Empathy is asked to handle the channel
    e = q.expect('dbus-method-call',
                 path=client.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
def test(q, bus, unused, **kwargs):
    fake_accounts_service = kwargs['fake_accounts_service']
    preseed(q, bus, fake_accounts_service)

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

    conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', 'jc',
                               '*****@*****.**')
    conn.StatusChanged(cs.CONN_STATUS_CONNECTED, 0)

    unhandled_properties = dbus.Dictionary(text_fixed_properties,
                                           signature='sv')
    unhandled_properties[cs.CHANNEL +
                         '.Interfaces'] = dbus.Array(signature='s')
    unhandled_properties[cs.CHANNEL + '.TargetID'] = '*****@*****.**'
    unhandled_properties[cs.CHANNEL + '.TargetHandle'] = \
            dbus.UInt32(conn.ensure_handle(cs.HT_CONTACT, '*****@*****.**'))
    unhandled_properties[cs.CHANNEL + '.InitiatorHandle'] = dbus.UInt32(
        conn.self_handle)
    unhandled_properties[cs.CHANNEL + '.InitiatorID'] = conn.self_ident
    unhandled_properties[cs.CHANNEL + '.Requested'] = True
    unhandled_chan = SimulatedChannel(conn, unhandled_properties)
    unhandled_chan.announce()

    handled_properties = dbus.Dictionary(text_fixed_properties, signature='sv')
    handled_properties[cs.CHANNEL + '.Interfaces'] = dbus.Array(signature='s')
    handled_properties[cs.CHANNEL + '.TargetID'] = '*****@*****.**'
    handled_properties[cs.CHANNEL + '.TargetHandle'] = \
            dbus.UInt32(conn.ensure_handle(cs.HT_CONTACT, '*****@*****.**'))
    handled_properties[cs.CHANNEL + '.InitiatorHandle'] = dbus.UInt32(
        conn.self_handle)
    handled_properties[cs.CHANNEL + '.InitiatorID'] = conn.self_ident
    handled_properties[cs.CHANNEL + '.Requested'] = True
    handled_chan = SimulatedChannel(conn, handled_properties)
    handled_chan.announce()

    client = SimulatedClient(q,
                             bus,
                             'Empathy',
                             observe=[text_fixed_properties],
                             approve=[text_fixed_properties],
                             handle=[text_fixed_properties],
                             bypass_approval=False)
    client.handled_channels.append(handled_chan.object_path)

    # Service-activate MC.
    # We're told about the other channel as an observer...
    mc = MC(q, bus, wait_for_names=False)
    e, = mc.wait_for_names(
        EventPattern('dbus-method-call',
                     path=client.object_path,
                     interface=cs.OBSERVER,
                     method='ObserveChannels',
                     handled=False), )

    assert e.args[1] == conn.object_path, e.args
    channels = e.args[2]
    assert channels[0][0] == unhandled_chan.object_path, channels
    q.dbus_return(e.message, signature='')

    # ... and as a handler
    e = q.expect('dbus-method-call',
                 path=client.object_path,
                 interface=cs.HANDLER,
                 method='HandleChannels',
                 handled=False)
    assert e.args[1] == conn.object_path, e.args
    channels = e.args[2]
    assert channels[0][0] == unhandled_chan.object_path, channels
    q.dbus_return(e.message, signature='')
def test(q, bus, mc):
    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******"
        }, signature='sv')
    (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)

    # Ensure that it's enabled but has offline RP and doesn't connect
    # automatically

    call_async(q, account_props, 'Set', cs.ACCOUNT, 'RequestedPresence',
               (dbus.UInt32(cs.PRESENCE_OFFLINE), 'offline', ''))
    q.expect('dbus-return', method='Set')

    call_async(
        q, account_props, 'Set', cs.ACCOUNT, 'AutomaticPresence',
        (dbus.UInt32(cs.PRESENCE_BUSY), 'busy', 'Testing automatic presence'))
    q.expect('dbus-return', method='Set')
    q.expect(
        'dbus-signal',
        signal='AccountPropertyChanged',
        predicate=lambda e: e.args[0].get('AutomaticPresence',
                                          (None, None, None))[1] == 'busy')

    call_async(q, account_props, 'Set', cs.ACCOUNT, 'ConnectAutomatically',
               False)
    q.expect('dbus-return', method='Set')

    call_async(q, account_props, 'Set', cs.ACCOUNT, 'Enabled', True)
    q.expect('dbus-return', method='Set')
    q.expect('dbus-signal',
             signal='AccountPropertyChanged',
             predicate=lambda e: e.args[0].get('Enabled'))

    # Requesting a channel will put us online

    user_action_time = dbus.Int64(1238582606)

    cd = bus.get_object(cs.CD, cs.CD_PATH)

    request = dbus.Dictionary(
        {
            cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_TEXT,
            cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT,
            cs.CHANNEL + '.TargetID': 'juliet',
        },
        signature='sv')
    call_async(q,
               cd,
               'CreateChannel',
               account.object_path,
               request,
               user_action_time,
               "",
               dbus_interface=cs.CD)
    ret = q.expect('dbus-return', method='CreateChannel')
    request_path = ret.value[0]

    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'] == ""
    assert request_props['Interfaces'] == []

    # make sure RequestConnection doesn't get called until we Proceed
    events = [EventPattern('dbus-method-call', method='RequestConnection')]
    q.forbid_events(events)

    sync_dbus(bus, q, mc)

    q.unforbid_events(events)

    cr.Proceed(dbus_interface=cs.CR)

    e = q.expect('dbus-method-call',
                 method='RequestConnection',
                 args=['fakeprotocol', params],
                 destination=cs.tp_name_prefix + '.ConnectionManager.fakecm',
                 path=cs.tp_path_prefix + '/ConnectionManager/fakecm',
                 interface=cs.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')

    q.expect('dbus-method-call',
             method='Connect',
             path=conn.object_path,
             handled=True)
    conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CSR_NONE_SPECIFIED)
    conn.presence = dbus.Struct((cs.PRESENCE_AVAILABLE, 'available', ''),
                                signature='uss')

    _, cm_request_call = q.expect_many(
        EventPattern('dbus-method-call',
                     path=conn.object_path,
                     interface=cs.CONN_IFACE_SIMPLE_PRESENCE,
                     method='SetPresence',
                     args=['busy', 'Testing automatic presence'],
                     handled=True),
        EventPattern('dbus-method-call',
                     path=conn.object_path,
                     interface=cs.CONN_IFACE_REQUESTS,
                     method='CreateChannel',
                     args=[request],
                     handled=False),
    )

    q.dbus_emit(conn.object_path,
                cs.CONN_IFACE_SIMPLE_PRESENCE,
                'PresencesChanged', {
                    conn.self_handle: (dbus.UInt32(cs.PRESENCE_BUSY), 'busy',
                                       'Testing automatic presence')
                },
                signature='a{u(uss)}')

    # 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)
    q.dbus_return(cm_request_call.message,
                  channel.object_path,
                  channel.immutable,
                  signature='oa{sv}')
    channel.announce()

    # there's no handler, so it gets shot down

    q.expect('dbus-method-call',
             path=channel.object_path,
             method='Close',
             handled=True)
def test(q, bus, mc):
    # Create an account. We're setting register=True here to verify
    # that after one successful connection, it'll be removed (fd.o #28118).
    params = dbus.Dictionary({"account": "*****@*****.**",
        "password": "******",
        "register": True}, signature='sv')
    (simulated_cm, account) = create_fakecm_account(q, bus, mc, params)

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

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

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

    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)

    q.expect('dbus-method-call',
             interface=cs.CONN_IFACE_SIMPLE_PRESENCE,
             method='SetPresence',
             args=list(presence[1:]),
             handled=True)

    # Connection falls over for a miscellaneous reason
    conn.ConnectionError('com.example.My.Network.Is.Full.Of.Eels',
            {'eels': 23, 'capacity': 23, 'debug-message': 'Too many eels'})
    conn.StatusChanged(cs.CONN_STATUS_DISCONNECTED,
            cs.CSR_NETWORK_ERROR)

    # MC reconnects. This time, we expect it to have deleted the 'register'
    # parameter.
    del params['register']

    disconnected, connecting, e = q.expect_many(
            EventPattern('dbus-signal', signal='AccountPropertyChanged',
                predicate=(lambda e:
                    e.args[0].get('ConnectionStatus') ==
                        cs.CONN_STATUS_DISCONNECTED),
                ),
            EventPattern('dbus-signal', signal='AccountPropertyChanged',
                predicate=(lambda e:
                    e.args[0].get('ConnectionStatus') ==
                        cs.CONN_STATUS_CONNECTING),
                ),
            EventPattern('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),
            )

    assertEquals('/', disconnected.args[0].get('Connection'))
    assertEquals('com.example.My.Network.Is.Full.Of.Eels',
            disconnected.args[0].get('ConnectionError'))
    assertEquals(
            {'eels': 23, 'capacity': 23, 'debug-message': 'Too many eels'},
            disconnected.args[0].get('ConnectionErrorDetails'))
    assertEquals(cs.CONN_STATUS_DISCONNECTED,
        disconnected.args[0].get('ConnectionStatus'))
    assertEquals(cs.CSR_NETWORK_ERROR,
        disconnected.args[0].get('ConnectionStatusReason'))

    assertEquals('/', connecting.args[0].get('Connection'))
    assertEquals('com.example.My.Network.Is.Full.Of.Eels',
            connecting.args[0].get('ConnectionError'))
    assertEquals(
            {'eels': 23, 'capacity': 23, 'debug-message': 'Too many eels'},
            connecting.args[0].get('ConnectionErrorDetails'))
    assertEquals(cs.CONN_STATUS_CONNECTING,
        connecting.args[0].get('ConnectionStatus'))
    assertEquals(cs.CSR_REQUESTED,
        connecting.args[0].get('ConnectionStatusReason'))

    # 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', 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
    connecting, _ = q.expect_many(
            EventPattern('dbus-signal', signal='AccountPropertyChanged',
                predicate=(lambda e:
                    e.args[0].get('ConnectionStatus') ==
                        cs.CONN_STATUS_CONNECTING),
                ),
            EventPattern('dbus-method-call', method='Connect',
                path=conn.object_path, handled=True),
            )

    assertEquals(conn.object_path, connecting.args[0].get('Connection'))
    assertEquals('com.example.My.Network.Is.Full.Of.Eels',
            connecting.args[0].get('ConnectionError'))
    assertEquals(
            {'eels': 23, 'capacity': 23, 'debug-message': 'Too many eels'},
            connecting.args[0].get('ConnectionErrorDetails'))
    assertEquals(cs.CONN_STATUS_CONNECTING,
        connecting.args[0].get('ConnectionStatus'))
    assertEquals(cs.CSR_REQUESTED,
        connecting.args[0].get('ConnectionStatusReason'))

    assertEquals('com.example.My.Network.Is.Full.Of.Eels',
            account.Properties.Get(cs.ACCOUNT, 'ConnectionError'))
    assertEquals(
            {'eels': 23, 'capacity': 23, 'debug-message': 'Too many eels'},
            account.Properties.Get(cs.ACCOUNT, 'ConnectionErrorDetails'))

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

    connected, _ = q.expect_many(
            EventPattern('dbus-signal', signal='AccountPropertyChanged',
                predicate=(lambda e:
                    e.args[0].get('ConnectionStatus') ==
                        cs.CONN_STATUS_CONNECTED),
                ),
            EventPattern('dbus-method-call',
                interface=cs.CONN_IFACE_SIMPLE_PRESENCE,
                method='SetPresence',
                args=list(presence[1:]),
                handled=True),
            )

    assertEquals(conn.object_path, connected.args[0].get('Connection'))
    assertEquals('', connected.args[0].get('ConnectionError'))
    assertEquals({}, connected.args[0].get('ConnectionErrorDetails'))
    assertEquals(cs.CONN_STATUS_CONNECTED,
        connected.args[0].get('ConnectionStatus'))
    assertEquals(cs.CSR_REQUESTED,
        connected.args[0].get('ConnectionStatusReason'))

    assertEquals('', account.Properties.Get(cs.ACCOUNT, 'ConnectionError'))
    assertEquals({}, account.Properties.Get(cs.ACCOUNT, 'ConnectionErrorDetails'))