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

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

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

    # No Approver should be invoked at any point during this test, because the
    # Channel was Requested
    def fail_on_approval(e):
        raise AssertionError('Approver should not be invoked')
    q.add_dbus_method_impl(fail_on_approval, path=client.object_path,
            interface=cs.APPROVER, method='AddDispatchOperation')

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

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

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

    client = SimulatedClient(q, bus, 'Empathy',
            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, [client])

    channel = test_channel_creation(q, bus, account, client, conn,
            yours_first=True, swap_requests=False)
    channel.close()

    channel = test_channel_creation(q, bus, account, client, conn,
            yours_first=True, swap_requests=True)
    channel.close()

    channel = test_channel_creation(q, bus, account, client, conn,
            yours_first=False, swap_requests=False)
    channel.close()

    channel = test_channel_creation(q, bus, account, client, conn,
            yours_first=False, swap_requests=True)
    channel.close()
def test(q, bus, mc):
    params = dbus.Dictionary({"account": "*****@*****.**",
        "password": "******"}, signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

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

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

    # No Approver should be invoked at any point during this test, because the
    # Channel was Requested
    def fail_on_approval(e):
        raise AssertionError('Approver should not be invoked')
    q.add_dbus_method_impl(fail_on_approval, path=client.object_path,
            interface=cs.APPROVER, method='AddDispatchOperation')

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

    test_channel_creation(q, bus, account, client, conn, False)
    test_channel_creation(q, bus, account, client, conn, True)
예제 #4
0
def test(q, bus, mc):
    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******"
        },
        signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

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

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

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

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

    text_fixed_properties = dbus.Dictionary({
        cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT,
        cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_TEXT,
        }, signature='sv')
    # Emulate a handler that only wants to get outgoing channels, as a
    # regression test for <http://bugs.freedesktop.org/show_bug.cgi?id=23935>,
    # in which those didn't work
    text_requested = dbus.Dictionary(text_fixed_properties, signature='sv')
    text_requested[cs.CHANNEL + '.Requested'] = True

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

    # No Approver should be invoked at any point during this test, because the
    # Channel was Requested
    def fail_on_approval(e):
        raise AssertionError('Approver should not be invoked')
    q.add_dbus_method_impl(fail_on_approval, path=client.object_path,
            interface=cs.APPROVER, method='AddDispatchOperation')

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

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

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

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

    # This client doesn't say it can handle channels, but if it requests one
    # for itself, we'll at least try dispatching to it.
    #
    # A real-world use case for this is if a client wants to request channels,
    # and handle the channels that it, itself, requested, but not handle
    # anything requested by others: for instance, nautilus-sendto behaves
    # like this. See fd.o #23651
    unsuitable = SimulatedClient(q,
                                 bus,
                                 'Unsuitable',
                                 observe=[],
                                 approve=[],
                                 handle=[],
                                 is_handler=True,
                                 bypass_approval=False)

    # No Approver should be invoked at any point during this test, because the
    # Channel was Requested
    def fail_on_approval(e):
        raise AssertionError('Approver should not be invoked')

    q.add_dbus_method_impl(fail_on_approval,
                           path=client.object_path,
                           interface=cs.APPROVER,
                           method='AddDispatchOperation')

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

    test_channel_creation(q, bus, account, client, conn, False)
    test_channel_creation(q, bus, account, client, conn, True)
    test_channel_creation(q, bus, account, client, conn, False, unsuitable)
    test_channel_creation(q, bus, account, client, conn, False, unsuitable,
                          cs.CHANNEL_TYPE_CALL)
예제 #7
0
def test(q, bus, mc):
    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******"
        },
        signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

    text_fixed_properties = dbus.Dictionary(
        {
            cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT,
            cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_TEXT,
        },
        signature='sv')
    # Emulate a handler that only wants to get outgoing channels, as a
    # regression test for <http://bugs.freedesktop.org/show_bug.cgi?id=23935>,
    # in which those didn't work
    text_requested = dbus.Dictionary(text_fixed_properties, signature='sv')
    text_requested[cs.CHANNEL + '.Requested'] = True

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

    # No Approver should be invoked at any point during this test, because the
    # Channel was Requested
    def fail_on_approval(e):
        raise AssertionError('Approver should not be invoked')

    q.add_dbus_method_impl(fail_on_approval,
                           path=client.object_path,
                           interface=cs.APPROVER,
                           method='AddDispatchOperation')

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

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

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

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

    # This client doesn't say it can handle channels, but if it requests one
    # for itself, we'll at least try dispatching to it.
    #
    # A real-world use case for this is if a client wants to request channels,
    # and handle the channels that it, itself, requested, but not handle
    # anything requested by others: for instance, nautilus-sendto behaves
    # like this. See fd.o #23651
    unsuitable = SimulatedClient(q, bus, 'Unsuitable',
            observe=[], approve=[], handle=[], is_handler=True,
            bypass_approval=False)

    # No Approver should be invoked at any point during this test, because the
    # Channel was Requested
    def fail_on_approval(e):
        raise AssertionError('Approver should not be invoked')
    q.add_dbus_method_impl(fail_on_approval, path=client.object_path,
            interface=cs.APPROVER, method='AddDispatchOperation')

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

    test_channel_creation(q, bus, account, client, conn, False)
    test_channel_creation(q, bus, account, client, conn, True)
    test_channel_creation(q, bus, account, client, conn, False, unsuitable)
    test_channel_creation(q, bus, account, client, conn, False, unsuitable,
            cs.CHANNEL_TYPE_CALL)
def test(q, bus, mc):
    params = dbus.Dictionary({"account": "*****@*****.**",
        "password": "******"}, signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

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

    client = SimulatedClient(q, bus, 'Empathy',
            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, [client])

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

    # chat UI calls ChannelDispatcher.EnsureChannel or CreateChannel
    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, dbus.Int64(1234),
            'grr.arg',      # a valid bus name, but the wrong prefix
            dbus_interface=cs.CD)
    ret = q.expect('dbus-error', method='CreateChannel')
    assert ret.error.get_dbus_name() == cs.INVALID_ARGUMENT

    call_async(q, cd, 'CreateChannel',
            account.object_path, request, dbus.Int64(1234),
            'can has cheeseburger?',      # a totally invalid bus name
            dbus_interface=cs.CD)
    ret = q.expect('dbus-error', method='CreateChannel')
    assert ret.error.get_dbus_name() == cs.INVALID_ARGUMENT
def test(q, bus, mc):
    policy_bus_name_ref = dbus.service.BusName('com.example.Policy', bus)

    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******"
        },
        signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn, e = enable_fakecm_account(
        q,
        bus,
        mc,
        account,
        params,
        extra_interfaces=[cs.CONN_IFACE_SERVICE_POINT],
        expect_after_connect=[
            EventPattern(
                'dbus-method-call',
                method='Get',
                args=[cs.CONN_IFACE_SERVICE_POINT, 'KnownServicePoints']),
        ])

    e_numbers = ['911', '112']
    points = dbus.Array(
        [((cs.SERVICE_POINT_TYPE_EMERGENCY, 'urn:service:sos'), e_numbers)],
        signature='((us)as)')

    q.dbus_return(e.message, points, signature='v')

    # the service points change
    e_numbers = ['911', '112', '999']
    points = dbus.Array(
        [((cs.SERVICE_POINT_TYPE_EMERGENCY, 'urn:service:sos'), e_numbers)],
        signature='((us)as)')
    q.dbus_emit(conn.object_path,
                cs.CONN_IFACE_SERVICE_POINT,
                'ServicePointsChanged',
                points,
                signature='a((us)as)')

    # MC used to critical if more than one emergency service point was
    # given by the CM. That's silly, so let's test it.
    e_numbers1 = ['911']
    e_numbers2 = ['999']
    points = dbus.Array(
        [((cs.SERVICE_POINT_TYPE_EMERGENCY, 'urn:service:sos'), e_numbers1),
         ((cs.SERVICE_POINT_TYPE_EMERGENCY, 'urn:service:sos'), e_numbers2)],
        signature='((us)as)')
    q.dbus_emit(conn.object_path,
                cs.CONN_IFACE_SERVICE_POINT,
                'ServicePointsChanged',
                points,
                signature='a((us)as)')

    e_numbers = e_numbers1 + e_numbers2

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

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

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

    user_action_time = dbus.Int64(1238582606)

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

    for emergency in False, True:
        if emergency:
            target_id = '112'
            forbidden = [
                EventPattern('dbus-method-call', method='RequestRequest'),
            ]

        else:
            target_id = 'juliet'
            # For now, we should never actually be asked to make a channel.
            forbidden = [
                EventPattern('dbus-method-call', method='CreateChannel'),
                EventPattern('dbus-method-call', method='EnsureChannel'),
                EventPattern('dbus-method-call', method='ObserveChannels'),
                EventPattern('dbus-method-call',
                             method='AddDispatchOperation'),
                EventPattern('dbus-method-call', method='HandleChannels'),
            ]

        q.forbid_events(forbidden)

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

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

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

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

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

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

        if emergency:
            # The CM is asked to create the channel anyway, because this
            # looks a bit like an emergency call
            cm_request_call = q.expect('dbus-method-call',
                                       interface=cs.CONN_IFACE_REQUESTS,
                                       method='CreateChannel',
                                       path=conn.object_path,
                                       args=[request],
                                       handled=False)
            q.dbus_raise(cm_request_call.message, cs.INVALID_ARGUMENT, 'No')

            sync_dbus(bus, q, account)
            q.unforbid_events(forbidden)
        else:
            # What does the policy service think?
            permission = q.expect('dbus-method-call',
                                  path='/com/example/Policy',
                                  interface='com.example.Policy',
                                  method='RequestRequest')

            # Think about it for a bit, then allow dispatching to continue
            sync_dbus(bus, q, account)
            q.unforbid_events(forbidden)
            q.dbus_return(permission.message, signature='')

            # Only now does the CM's CreateChannel method get called
            cm_request_call = q.expect('dbus-method-call',
                                       interface=cs.CONN_IFACE_REQUESTS,
                                       method='CreateChannel',
                                       path=conn.object_path,
                                       args=[request],
                                       handled=False)
            q.dbus_raise(cm_request_call.message, cs.INVALID_ARGUMENT, 'No')
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, mc):
    params = dbus.Dictionary({"account": "*****@*****.**",
        "password": "******"}, signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

    # One client (Kopete) has less specific filters than the other (Empathy),
    # to make sure that the dispatcher would normally prefer Empathy; this
    # means that when we use Kopete as the preferred handler, we know that
    # if Kopete is invoked, then preferring the preferred handler correctly
    # took precedence over the normal logic.
    vague_fixed_properties = dbus.Dictionary({
        cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_TEXT,
        }, signature='sv')
    text_fixed_properties = dbus.Dictionary({
        cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT,
        cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_TEXT,
        }, signature='sv')

    empathy_bus = dbus.bus.BusConnection()
    kopete_bus = dbus.bus.BusConnection()
    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=[vague_fixed_properties], approve=[vague_fixed_properties],
            handle=[vague_fixed_properties], bypass_approval=False)

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

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

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

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

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

    # A channel dispatch operation is created

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

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

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

    handlers = cdo_properties[cs.CDO + '.PossibleHandlers'][:]
    # Empathy has a more specific filter, so it comes first
    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)
    cdo_props_iface = dbus.Interface(cdo, cs.PROPERTIES_IFACE)

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

    # 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, bus=empathy_bus, signature='')
    q.dbus_return(e.message, bus=kopete_bus, 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, bus=empathy_bus, signature='')
    q.dbus_return(k.message, bus=kopete_bus, signature='')

    # Both Approvers now have a flashing icon or something, trying to get the
    # user's attention. However, the user is busy looking through the address
    # book, and independently decides to talk to Juliet. The address book
    # is from KDE so wants Kopete to be used.

    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, 'EnsureChannel',
            account.object_path, request, user_action_time, kopete.bus_name,
            dbus_interface=cs.CD)
    ret, add_request_call = q.expect_many(
            EventPattern('dbus-return', method='EnsureChannel'),
            EventPattern('dbus-method-call', handled=False,
                interface=cs.CLIENT_IFACE_REQUESTS,
                method='AddRequest', path=kopete.object_path),
            )
    request_path = ret.value[0]

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

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

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

    cr.Proceed(dbus_interface=cs.CR)

    cm_request_call = q.expect('dbus-method-call',
            interface=cs.CONN_IFACE_REQUESTS,
            method='EnsureChannel',
            path=conn.object_path, args=[request], handled=False)

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

    # Time passes. The CM returns the existing channel

    q.dbus_return(cm_request_call.message, False,
            chan.object_path, chan.immutable, signature='boa{sv}')

    # EnsureChannel constitutes approval, so Kopete is told to handle the
    # channel

    e = q.expect('dbus-method-call',
            path=kopete.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] == chan.object_path, channels
    assert channels[0][1] == chan.immutable, channels
    assert e.args[3] == [request_path], e.args
    assert e.args[4] == user_action_time, (e.args[4], user_action_time)
    assert isinstance(e.args[5], dict)
    assert len(e.args) == 6

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

    q.expect_many(
            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, mc):
    params = dbus.Dictionary({"account": "*****@*****.**",
        "password": "******"}, signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

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

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

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

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

    # First, a non-urgent channel is created

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

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

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

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

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

    q.forbid_events(approval)

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

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

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

    q.unforbid_events(approval)

    # Regression test for fd.o #22670

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

    q.forbid_events(closure)

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

    q.unforbid_events(closure)

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

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

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

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

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

    # MC recovers by running the approvers and doing what they say
    expect_and_exercise_approval(q, bus, chan, channel_properties,
            empathy, kopete, cdo_iface, cd_props)
def test(q, bus, mc):
    # For this test, we should never actually be asked to make a channel.
    forbidden = [
            EventPattern('dbus-method-call', method='CreateChannel'),
            EventPattern('dbus-method-call', method='EnsureChannel'),
            EventPattern('dbus-method-call', method='ObserveChannels'),
            EventPattern('dbus-method-call', method='AddDispatchOperation'),
            EventPattern('dbus-method-call', method='HandleChannels'),
            ]
    q.forbid_events(forbidden)

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

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

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

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

    user_action_time = dbus.Int64(1238582606)

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

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

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

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

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

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

    q.expect('dbus-return', method='Proceed')
    q.expect('dbus-signal',
            path=cr.object_path, interface=cs.CR, signal='Failed',
            args=[cs.PERMISSION_DENIED, "No, you don't"])
def test(q, bus, mc):
    params = dbus.Dictionary({"account": "*****@*****.**",
        "password": "******"}, signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

    text_fixed_properties = dbus.Dictionary({
        cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
        }, signature='sv')

    # Logger is a text observer wanting recovery
    logger = SimulatedClient(q, bus, 'LoggerChat',
            observe=[text_fixed_properties],
            bypass_approval=False,
            wants_recovery=True)

    # gnome-shell is a text approver and handler
    gs = SimulatedClient(q, bus, 'GnomeShell',
            approve=[text_fixed_properties],
            handle=[text_fixed_properties],
            bypass_approval=False)

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

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

    # incoming text channel
    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()

    # gnome-shell's approver and logger's observer are notified
    e, k = q.expect_many(
            EventPattern('dbus-method-call',
                path=logger.object_path,
                interface=cs.OBSERVER, method='ObserveChannels',
                handled=False),
            EventPattern('dbus-method-call',
                path=gs.object_path,
                interface=cs.APPROVER, method='AddDispatchOperation',
                handled=False),
            )

    channels, cdo_path, props = k.args

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

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

    # gnome-shell claims the channel
    call_async(q, cdo_iface, 'Claim')
    e = q.expect('dbus-return', method='Claim')

    # Logger crash
    logger.release_name()

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

    bus.flush()

    # Logger gets restarted
    logger.reacquire_name()

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

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

    # gnome-shell which is handling the channel asks to re-ensure it
    cd_iface = dbus.Interface(cd, cs.CD)
    call_async(q, cd_iface, 'PresentChannel',
        chan.object_path, 0)

    # gnome-shell is asked to re-handle the channel
    e = q.expect('dbus-method-call',
            path=gs.object_path,
            interface=cs.HANDLER, method='HandleChannels',
            handled=False)

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

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

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

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

    client = SimulatedClient(q, bus, 'Empathy',
            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, [client])

    user_action_time = dbus.Int64(1238582606)

    # chat UI calls ChannelDispatcher.CreateChannel
    cd = ChannelDispatcher(bus)
    request = dbus.Dictionary({
            cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_TEXT,
            cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT,
            cs.CHANNEL + '.TargetID': 'juliet',
            }, signature='sv')
    request_path = cd.CreateChannel(account.object_path, request,
        user_action_time, client.bus_name)

    add_request = q.expect('dbus-method-call', handled=False,
        interface=cs.CLIENT_IFACE_REQUESTS, method='AddRequest',
        path=client.object_path)
    assert add_request.args[0] == request_path
    q.dbus_return(add_request.message, signature='')

    # chat UI connects to signals and calls ChannelRequest.Proceed()
    cr = bus.get_object(cs.CD, request_path)
    cr.Proceed()
    cm_request_call = q.expect('dbus-method-call',
                interface=cs.CONN_IFACE_REQUESTS, method='CreateChannel',
                path=conn.object_path, args=[request], handled=False)

    # Before the channel is returned, we delete the account

    account_iface = dbus.Interface(account, cs.ACCOUNT)
    assert account_iface.Remove() is None
    account_event, account_manager_event = q.expect_many(
        EventPattern('dbus-signal',
            path=account.object_path,
            signal='Removed',
            interface=cs.ACCOUNT,
            args=[]
            ),
        EventPattern('dbus-signal',
            path=cs.AM_PATH,
            signal='AccountRemoved',
            interface=cs.AM,
            args=[account.object_path]
            ),
        )

    # You know that request I told you about? Not going to happen.
    remove_request = q.expect('dbus-method-call',
            interface=cs.CLIENT_IFACE_REQUESTS,
            method='RemoveRequest',
            handled=False)
    assert remove_request.args[0] == request_path
    # FIXME: the spec should maybe define what error this will be. Currently,
    # it's Disconnected
    assert remove_request.args[1].startswith(tp_name_prefix + '.Error.')

    q.expect('dbus-signal',
                path=request_path, interface=cs.CR, signal='Failed',
                args=remove_request.args[1:])

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

    # ... and the Connection is told to disconnect, hopefully before the
    # Channel has actually been established
    e = q.expect('dbus-method-call',
            path=conn.object_path,
            interface=cs.CONN,
            method='Disconnect',
            args=[],
            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": "*****@*****.**",
            "password": "******"
        },
        signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

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

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

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

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

    # First, a non-urgent channel is created

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

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

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

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

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

    q.forbid_events(approval)

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

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

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

    q.unforbid_events(approval)

    # Regression test for fd.o #22670

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

    q.forbid_events(closure)

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

    q.unforbid_events(closure)

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

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

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

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

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

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

    text_fixed_properties = dbus.Dictionary({
        cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
        cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
        }, signature='sv')

    # Empathy Chat is a text handler
    empathy_bus = dbus.bus.BusConnection()
    empathy = SimulatedClient(q, empathy_bus, 'EmpathyChat',
            handle=[text_fixed_properties], bypass_approval=False)
    q.attach_to_bus(empathy_bus)

    # gnome-shell is a text approver and handler
    gs = SimulatedClient(q, bus, 'GnomeShell',
           approve=[text_fixed_properties],
            handle=[text_fixed_properties], bypass_approval=False)

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

    cd = ChannelDispatcher(bus)

    # incoming text channel
    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()

    # gnome-shell's approver is notified
    e = q.expect('dbus-method-call', path=gs.object_path,
        interface=cs.APPROVER, method='AddDispatchOperation',
        handled=False)

    channels, cdo_path,props = e.args

    cdo = ChannelDispatchOperation(bus, cdo_path)

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

    # gnome-shell handles the channel itself first
    call_async(q, cdo, 'HandleWith',
            cs.tp_name_prefix + '.Client.GnomeShell')

    e = q.expect('dbus-method-call',
            path=gs.object_path,
            interface=cs.HANDLER, method='HandleChannels',
            handled=False)

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

    # test delegating an incoming channel
    test_delegate_channel(q, bus, mc, account, conn, chan, empathy, empathy_bus, gs)

    # Empathy is back
    empathy = SimulatedClient(q, empathy_bus, 'EmpathyChat',
            handle=[text_fixed_properties], bypass_approval=False)

    expect_client_setup(q, [empathy])

    # gnome-shell requests a channel for itself
    call_async(q, cd, 'CreateChannelWithHints',
            account.object_path, REQUEST, 0,
            cs.tp_name_prefix + '.Client.GnomeShell',
            {})
    e = q.expect('dbus-return', method='CreateChannelWithHints')

    cr = ChannelRequest(bus, e.value[0])
    cr.Proceed()

    e = q.expect('dbus-method-call', interface=cs.CONN_IFACE_REQUESTS,
        method='CreateChannel',
        path=conn.object_path, args=[REQUEST], handled=False)

    # channel is created
    chan = SimulatedChannel(conn, REQUEST)

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

    # gnome-shell handles the channel
    e = q.expect('dbus-method-call',
            path=gs.object_path,
            interface=cs.HANDLER, method='HandleChannels',
            handled=False)

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

    # test delegating an outgoing channel
    test_delegate_channel(q, bus, mc, account, conn, chan, empathy, empathy_bus, gs)
def test(q, bus, mc):
    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******"
        },
        signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

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

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

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

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

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

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

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

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

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

    # A channel dispatch operation is created

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    # The Approver (Kopete) is next

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

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

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

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

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

    # Logger crashes
    logger.release_name()

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

    logger_bus.flush()

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

    # Logger gets restarted
    logger.reacquire_name()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    handlers = cdo_properties[cs.CDO + '.PossibleHandlers'][:]
    assertEquals([], handlers)

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

    sync_dbus(bus, q, mc)

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

    # now (but only now) MC kills the channel
    q.expect_many(
            EventPattern('dbus-signal', path=cdo_path, signal='Finished'),
            EventPattern('dbus-method-call', path=chan.object_path,
                method='Close', handled=True),
            )

    # There are no active channel dispatch operations
    assert cd_props.Get(cs.CD_IFACE_OP_LIST, 'DispatchOperations') == []
def test(q, bus, mc):
    params = dbus.Dictionary({"account": "*****@*****.**",
        "password": "******"}, signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

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

    empathy_bus = dbus.bus.BusConnection()
    q.attach_to_bus(empathy_bus)
    empathy = SimulatedClient(q, empathy_bus, 'Empathy',
            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])

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

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

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

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

    # A channel dispatch operation is created

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

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

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

    handlers = cdo_properties[cs.CDO + '.PossibleHandlers'][:]
    assert handlers == [cs.tp_name_prefix + '.Client.Empathy'], handlers

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

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

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

    e = q.expect('dbus-method-call',
            path=empathy.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

    q.dbus_return(e.message, bus=empathy_bus, signature='')

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

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

    # Empathy rejects the channels
    q.dbus_raise(e.message, cs.NOT_AVAILABLE, 'Blind drunk', bus=empathy_bus)

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

    # Empathy rejects the channels
    q.dbus_raise(e.message, cs.NOT_AVAILABLE, 'Still drunk', bus=empathy_bus)

    q.expect_many(
            EventPattern('dbus-method-call', path=chan.object_path,
                interface=cs.CHANNEL, method='Close', handled=True),
            EventPattern('dbus-signal', path=cdo.object_path,
                interface=cs.CDO, signal='Finished'),
            EventPattern('dbus-signal', path=cd.object_path,
                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') == []
예제 #23
0
def test(q, bus, mc):
    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******"
        },
        signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

    text_fixed_properties = dbus.Dictionary(
        {
            cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT,
            cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_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])

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

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

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

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

    # A channel dispatch operation is created

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

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

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

    handlers = cdo_properties[cs.CDO + '.PossibleHandlers'][:]
    handlers.sort()
    assert handlers == [
        cs.tp_name_prefix + '.Client.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
    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='')

    # The channel closes before Kopete has said yes. As a result, MC isn't
    # allowed to emit ChannelLost or Finished yet.
    chan.close()

    # Empathy wants to handle the channel, but is too late
    call_async(q, cdo_iface, 'HandleWith',
               cs.tp_name_prefix + '.Client.Empathy')
    e = q.expect('dbus-error')
    # FIXME: e.error.get_dbus_name() == [...Disconnected] which doesn't
    #   seem like the most appropriate thing for MC to do (but at least it's
    # consistent with ChannelLost)

    # *Now* Kopete is happy...

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

    # ... and in response, the channel dispatch operation finishes

    e = q.expect('dbus-signal', path=cdo_path, signal='ChannelLost')
    assert e.args[0] == chan.object_path
    # FIXME: e.args[1:] == [...Disconnected, 'Channel aborted'] which doesn't
    #   seem like the most appropriate thing for MC to do

    q.expect('dbus-signal', path=cdo_path, signal='Finished')
    q.expect('dbus-signal',
             path=cs.CD_PATH,
             signal='DispatchOperationFinished',
             args=[cdo_path])

    # Now there are no more active channel dispatch operations
    assert cd_props.Get(cs.CD_IFACE_OP_LIST, 'DispatchOperations') == []
def test(q, bus, mc):
    params = dbus.Dictionary({"account": "*****@*****.**",
        "password": "******"}, signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

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

    # We have more than one Client "head" on the same unique name, to test
    # fd.o #24645 - we want the same "head" to be reinvoked if at all possible

    # This one is first in alphabetical order, is discovered first, and can
    # handle all channels, but is not the one we want
    empathy_worse_match = SimulatedClient(q, bus, 'A.Temporary.Handler',
            observe=[], approve=[],
            handle=[[]], bypass_approval=False)

    # This is the one we actually want
    empathy = SimulatedClient(q, bus, 'Empathy',
            observe=[text_fixed_properties], approve=[text_fixed_properties],
            handle=[text_fixed_properties], bypass_approval=False)

    # this one is a closer match, but not the preferred handler
    closer_match = dbus.Dictionary(text_fixed_properties)
    closer_match[cs.CHANNEL + '.TargetID'] = 'juliet'
    empathy_better_match = SimulatedClient(q, bus, 'Empathy.BetterMatch',
            observe=[], approve=[],
            handle=[closer_match], bypass_approval=False)

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

    channel = test_channel_creation(q, bus, account, empathy, conn)

    # After the channel has been dispatched, a handler that would normally
    # be a closer match turns up. Regardless, we should not redispatch to it.
    # For the better client to be treated as if it's in a different process,
    # it needs its own D-Bus connection.
    closer_match = dbus.Dictionary(text_fixed_properties)
    closer_match[cs.CHANNEL + '.TargetID'] = 'juliet'
    closer_match[cs.CHANNEL + '.InitiatorID'] = conn.self_ident
    better_bus = dbus.bus.BusConnection()
    q.attach_to_bus(better_bus)
    better = SimulatedClient(q, better_bus, 'BetterMatch',
            observe=[], approve=[],
            handle=[closer_match], bypass_approval=False)
    expect_client_setup(q, [better])

    test_channel_redispatch(q, bus, account, empathy, conn, channel)
    test_channel_redispatch(q, bus, account, empathy, conn, channel,
            ungrateful_handler=True)
    empathy.release_name()
    empathy_better_match.release_name()
    empathy_worse_match.release_name()
    test_channel_redispatch(q, bus, account, empathy, conn, channel,
            client_gone=True)
    channel.close()
def test(q, bus, mc):
    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******"
        },
        signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

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

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

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

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

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

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

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

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

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

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

    handlers = cdo_properties[cs.CDO + '.PossibleHandlers'][:]
    assertEquals([], handlers)

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

    sync_dbus(bus, q, mc)

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

    # now (but only now) MC kills the channel
    q.expect_many(
        EventPattern('dbus-signal', path=cdo_path, signal='Finished'),
        EventPattern('dbus-method-call',
                     path=chan.object_path,
                     method='Close',
                     handled=True),
    )

    # There are no active channel dispatch operations
    assert cd_props.Get(cs.CD_IFACE_OP_LIST, 'DispatchOperations') == []
예제 #26
0
def test(q, bus, mc):
    # Because the channels are handled by another process, we should never be
    # asked to approve or handle them.
    forbidden = [
        EventPattern('dbus-method-call', method='HandleChannels'),
        EventPattern('dbus-method-call', method='AddDispatchOperation'),
    ]
    q.forbid_events(forbidden)

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

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

    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)

    expect_client_setup(q, [empathy, kopete])

    # a non-MC-using client goes behind our back to call CreateChannel or
    # EnsureChannel on the Connection directly
    #
    # (This is not simulated here: we just behave as though it had happened)

    channel_immutable = dbus.Dictionary(text_fixed_properties)
    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_immutable[cs.CHANNEL + '.TargetID'] = 'juliet'
    channel = SimulatedChannel(conn, channel_immutable)

    channel.announce()

    # Observer should get told, processing waits for it
    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] == '/', e.args  # no dispatch operation
    assert e.args[4] == [], 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 == k.args

    # Observers say "OK, go"
    q.dbus_return(k.message, signature='')
    q.dbus_return(e.message, signature='')

    sync_dbus(bus, q, mc)
예제 #27
0
def test(q, bus, mc):
    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******"
        },
        signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

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

    # Throughout this entire test, we should never be asked to approve or
    # handle a channel.
    forbidden = [
        EventPattern('dbus-method-call', method='AddDispatchOperation'),
        EventPattern('dbus-method-call', method='HandleChannels'),
    ]
    q.forbid_events(forbidden)

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

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

    # This ID is special-cased by the mcp-plugin plugin, which rejects
    # channels to or from it by destroying them, without waiting for observers
    # to return
    target = '*****@*****.**'
    channel_properties = dbus.Dictionary(text_fixed_properties, signature='sv')
    channel_properties[cs.CHANNEL + '.TargetID'] = target
    channel_properties[cs.CHANNEL + '.TargetHandle'] = \
            conn.ensure_handle(cs.HT_CONTACT, target)
    channel_properties[cs.CHANNEL + '.InitiatorID'] = target
    channel_properties[cs.CHANNEL + '.InitiatorHandle'] = \
            conn.ensure_handle(cs.HT_CONTACT, target)
    channel_properties[cs.CHANNEL + '.Requested'] = False
    channel_properties[cs.CHANNEL + '.Interfaces'] = \
            dbus.Array([cs.CHANNEL_IFACE_DESTROYABLE, cs.CHANNEL_IFACE_GROUP,
                ],signature='s')

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

    # A channel dispatch operation is created

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

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

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

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

    # The plugin realises we've been rickrolled, and responds. It calls Destroy
    # even though neither Empathy nor Kopete has returned from ObserveChannels
    # yet
    destruction, e, k = q.expect_many(
        EventPattern('dbus-method-call',
                     path=chan.object_path,
                     interface=cs.CHANNEL_IFACE_DESTROYABLE,
                     method='Destroy',
                     args=[],
                     handled=False),
        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),
    )
    # treat the destruction like Close
    chan.Close(destruction)

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

    # When the Observers have returned, the CDO finishes
    q.expect_many(
        EventPattern('dbus-signal',
                     path=cdo_path,
                     interface=cs.CDO,
                     signal='Finished'),
        EventPattern('dbus-signal',
                     path=cs.CD_PATH,
                     interface=cs.CD_IFACE_OP_LIST,
                     signal='DispatchOperationFinished',
                     args=[cdo_path]),
    )

    # This ID is also special-cased
    target = '*****@*****.**'
    channel_properties = dbus.Dictionary(text_fixed_properties, signature='sv')
    channel_properties[cs.CHANNEL + '.TargetID'] = target
    channel_properties[cs.CHANNEL + '.TargetHandle'] = \
            conn.ensure_handle(cs.HT_CONTACT, target)
    channel_properties[cs.CHANNEL + '.InitiatorID'] = target
    channel_properties[cs.CHANNEL + '.InitiatorHandle'] = \
            conn.ensure_handle(cs.HT_CONTACT, target)
    channel_properties[cs.CHANNEL + '.Requested'] = False
    channel_properties[cs.CHANNEL + '.Interfaces'] = \
            dbus.Array([cs.CHANNEL_IFACE_DESTROYABLE, cs.CHANNEL_IFACE_GROUP,
                ],signature='s')

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

    # A channel dispatch operation is created

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

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

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

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

    # The plugin realises it's MC Hammer, and responds, but its response waits
    # for the observers to return
    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),
    )

    sync_dbus(bus, q, account)

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

    _, _, e = q.expect_many(
        EventPattern('dbus-signal',
                     path=cdo_path,
                     interface=cs.CDO,
                     signal='Finished'),
        EventPattern('dbus-signal',
                     path=cs.CD_PATH,
                     interface=cs.CD_IFACE_OP_LIST,
                     signal='DispatchOperationFinished',
                     args=[cdo_path]),
        EventPattern('dbus-method-call',
                     path=chan.object_path,
                     interface=cs.CHANNEL_IFACE_DESTROYABLE,
                     method='Destroy',
                     handled=False),
    )
    q.dbus_return(e.message, signature='')
    chan.close()
예제 #28
0
def test(q, bus, mc):
    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******"
        },
        signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

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

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

    # No Approver should be invoked at any point during this test, because the
    # Channel was Requested
    def fail_on_approval(e):
        raise AssertionError('Approver should not be invoked')

    q.add_dbus_method_impl(fail_on_approval,
                           path=client.object_path,
                           interface=cs.APPROVER,
                           method='AddDispatchOperation')

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

    user_action_time = dbus.Int64(1238582606)

    # chat UI calls ChannelDispatcher.CreateChannel
    cd = ChannelDispatcher(bus)
    request = dbus.Dictionary(
        {
            cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_TEXT,
            cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT,
            cs.CHANNEL + '.TargetID': 'juliet',
        },
        signature='sv')
    request_path = cd.CreateChannel(account.object_path, request,
                                    user_action_time, client.bus_name)

    add_request = q.expect('dbus-method-call',
                           handled=False,
                           interface=cs.CLIENT_IFACE_REQUESTS,
                           method='AddRequest',
                           path=client.object_path)
    assert add_request.args[0] == request_path
    q.dbus_return(add_request.message, signature='')

    cr = bus.get_object(cs.CD, 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

    # chat UI connects to signals and calls ChannelRequest.Proceed()
    cr.Proceed()
    cm_request_call = q.expect('dbus-method-call',
                               interface=cs.CONN_IFACE_REQUESTS,
                               method='CreateChannel',
                               path=conn.object_path,
                               args=[request],
                               handled=False)

    # Actually, never mind.
    cr.Cancel()

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

    # Channel is unwanted now, MC stabs it in the face
    stdsig, _ = q.expect_many(
        EventPattern('dbus-signal',
                     path=request_path,
                     interface=cs.CR,
                     signal='Failed'),
        EventPattern('dbus-method-call',
                     path=channel.object_path,
                     interface=cs.CHANNEL,
                     method='Close',
                     handled=True),
    )
예제 #29
0
def test(q, bus, mc):
    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******"
        },
        signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

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

    # Empathy is an Observers who will crash
    empathy_bus = dbus.bus.BusConnection()
    empathy_bus.set_exit_on_disconnect(False)  # we'll disconnect later

    # Kopete is an Approver, Handler and will not crash
    kopete_bus = dbus.bus.BusConnection()
    q.attach_to_bus(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=[],
                              handle=[],
                              wants_recovery=True)
    kopete = SimulatedClient(q,
                             kopete_bus,
                             'Kopete',
                             observe=[],
                             approve=[text_fixed_properties],
                             handle=[text_fixed_properties],
                             bypass_approval=False)

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

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

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

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

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

    # A channel dispatch operation is created

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

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

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

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

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

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

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

    # The Observer (Empathy) is told about the new channel

    e = q.expect('dbus-method-call',
                 path=empathy.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

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

    # The Approver (Kopete) is next

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

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

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

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

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

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

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

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

    # Another channel: this one will remain unapproved

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

    chan2 = SimulatedChannel(conn, channel2_properties)
    chan2.announce()

    # A channel dispatch operation is created

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

    cdo2_path = e.args[0]
    cdo2_properties = e.args[1]

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

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

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

    cdo2 = bus.get_object(cs.CD, cdo2_path)
    cdo2_iface = dbus.Interface(cdo2, cs.CDO)
    cdo2_props_iface = dbus.Interface(cdo2, cs.PROPERTIES_IFACE)

    assert cdo2_props_iface.Get(cs.CDO, 'Interfaces') == \
            cdo2_properties[cs.CDO + '.Interfaces']
    assert cdo2_props_iface.Get(cs.CDO, 'Connection') == conn.object_path
    assert cdo2_props_iface.Get(cs.CDO, 'Account') == account.object_path
    assert cdo2_props_iface.Get(cs.CDO, 'Channels') == [(chan2.object_path,
                                                         channel2_properties)]
    assert cdo2_props_iface.Get(cs.CDO, 'PossibleHandlers') == \
            cdo2_properties[cs.CDO + '.PossibleHandlers']

    # The Observer (Empathy) is told about the new channel

    e = q.expect('dbus-method-call',
                 path=empathy.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] == cdo2_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] == chan2.object_path, channels
    assert channels[0][1] == channel2_properties, channels

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

    # The Approver (Kopete) is next; this time, we don't approve

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

    assert k.args == [[(chan2.object_path, channel2_properties)], cdo2_path,
                      cdo2_properties]

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

    # Empathy crashes
    empathy.release_name()

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

    empathy_bus.flush()

    # Empathy gets restarted
    empathy.reacquire_name()

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

    e1, e2 = q.expect_many(
        EventPattern('dbus-method-call',
                     path=empathy.object_path,
                     interface=cs.OBSERVER,
                     method='ObserveChannels',
                     predicate=lambda e: e.args[2][0][0] == chan.object_path,
                     handled=False),
        EventPattern('dbus-method-call',
                     path=empathy.object_path,
                     interface=cs.OBSERVER,
                     method='ObserveChannels',
                     predicate=lambda e: e.args[2][0][0] == chan2.object_path,
                     handled=False),
    )

    assert e1.args[0] == account.object_path, e1.args
    assert e1.args[1] == conn.object_path, e1.args
    assert e1.args[4] == [], e1.args  # no requests satisfied
    assert e1.args[5]['recovering'] == 1, e1.args  # due to observer recovery
    channels = e1.args[2]
    assert len(channels) == 1, channels
    assert channels[0][0] == chan.object_path, channels
    assert channels[0][1] == channel_properties, channels

    assert e2.args[0] == account.object_path, e2.args
    assert e2.args[1] == conn.object_path, e2.args
    assert e2.args[4] == [], e2.args  # no requests satisfied
    assert e2.args[5]['recovering'] == 1, e2.args  # due to observer recovery
    channels = e2.args[2]
    assert len(channels) == 1, channels
    assert channels[0][0] == chan2.object_path, channels
    assert channels[0][1] == channel2_properties, channels

    # Empathy indicates that it is ready to proceed
    q.dbus_return(e1.message, bus=empathy_bus, signature='')
    q.dbus_return(e2.message, bus=empathy_bus, signature='')

    sync_dbus(bus, q, mc)
예제 #30
0
def test(q, bus, mc):
    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******"
        },
        signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

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

    empathy_bus = dbus.bus.BusConnection()
    empathy_bus.set_exit_on_disconnect(False)  # we'll disconnect later
    kopete_bus = dbus.bus.BusConnection()
    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])

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

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

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

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

    # A channel dispatch operation is created

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

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

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

    handlers = cdo_properties[cs.CDO + '.PossibleHandlers'][:]
    handlers.sort()
    assert handlers == [
        cs.tp_name_prefix + '.Client.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)
    cdo_props_iface = dbus.Interface(cdo, cs.PROPERTIES_IFACE)

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

    # 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, bus=empathy_bus, signature='')
    q.dbus_return(e.message, bus=kopete_bus, 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, bus=empathy_bus, signature='')
    q.dbus_return(k.message, bus=kopete_bus, signature='')

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

    # Using an invalid Handler name should fail
    call_async(q, cdo_iface, 'HandleWith',
               cs.tp_name_prefix + '.The.Moon.On.A.Stick')
    q.expect('dbus-error', method='HandleWith')
    call_async(q, cdo_iface, 'HandleWith',
               cs.tp_name_prefix + '.Client.the moon on a stick')
    q.expect('dbus-error', method='HandleWith')

    # 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, bus=empathy_bus, signature='')

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

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

    # Approve another channel using HandleWithTime()
    channel_properties = dbus.Dictionary(text_fixed_properties, signature='sv')
    channel_properties[cs.CHANNEL + '.TargetID'] = 'lucien'
    channel_properties[cs.CHANNEL + '.TargetHandle'] = \
            conn.ensure_handle(cs.HT_CONTACT, 'lucien')
    channel_properties[cs.CHANNEL + '.InitiatorID'] = 'lucien'
    channel_properties[cs.CHANNEL + '.InitiatorHandle'] = \
            conn.ensure_handle(cs.HT_CONTACT, 'lucien')
    channel_properties[cs.CHANNEL + '.Requested'] = False
    channel_properties[cs.CHANNEL + '.Interfaces'] = dbus.Array(signature='s')

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

    # A channel dispatch operation is created

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

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

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

    handlers = cdo_properties[cs.CDO + '.PossibleHandlers'][:]
    handlers.sort()
    assert handlers == [
        cs.tp_name_prefix + '.Client.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)
    cdo_props_iface = dbus.Interface(cdo, cs.PROPERTIES_IFACE)

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

    # 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, bus=empathy_bus, signature='')
    q.dbus_return(e.message, bus=kopete_bus, 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, bus=empathy_bus, signature='')
    q.dbus_return(k.message, bus=kopete_bus, 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, 'HandleWithTime',
               cs.tp_name_prefix + '.Client.Empathy', 13)

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

    account_path, conn_path, channels, requests, action_time, info = e.args
    assert action_time == 13

    # Empathy accepts the channels
    q.dbus_return(e.message, bus=empathy_bus, signature='')

    q.expect_many(
        EventPattern('dbus-return', method='HandleWithTime'),
        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') == []

    # From now on, it is an error to get HandleChannels (because we're
    # testing Claim())
    forbidden = [
        EventPattern('dbus-method-call', method='HandleChannels'),
    ]
    q.forbid_events(forbidden)

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

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

    # A channel dispatch operation is created

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

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

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

    handlers = cdo_properties[cs.CDO + '.PossibleHandlers'][:]
    handlers.sort()
    assert handlers == [
        cs.tp_name_prefix + '.Client.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] == claimed_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, bus=kopete_bus, signature='')
    q.dbus_return(e.message, bus=empathy_bus, 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 == [[(claimed_chan.object_path, channel_properties)],
                      cdo_path, cdo_properties]
    assert k.args == e.args

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

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

    # The user responds to Empathy first, and Empathy decides it wants the
    # channel for itself
    empathy_cdo = empathy_bus.get_object(cdo.bus_name, cdo.object_path)
    empathy_cdo_iface = dbus.Interface(empathy_cdo, cs.CDO)
    call_async(q, empathy_cdo_iface, 'Claim')

    q.expect_many(
        EventPattern('dbus-signal', path=cdo_path, signal='Finished'),
        EventPattern('dbus-signal',
                     path=cs.CD_PATH,
                     signal='DispatchOperationFinished',
                     args=[cdo_path]),
        EventPattern('dbus-return', method='Claim'),
    )

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

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

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

    # third_chan should not be closed
    q.unforbid_events(forbidden)
    forbidden.append(
        EventPattern('dbus-method-call',
                     method='Close',
                     path=third_chan.object_path))
    q.forbid_events(forbidden)

    # A channel dispatch operation is created

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

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

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

    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),
    )
    q.dbus_return(k.message, bus=kopete_bus, signature='')
    q.dbus_return(e.message, bus=empathy_bus, signature='')

    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),
    )
    q.dbus_return(e.message, bus=empathy_bus, signature='')
    q.dbus_return(k.message, bus=kopete_bus, signature='')

    # Kopete closes this one
    kopete_cdo = kopete_bus.get_object(cdo.bus_name, cdo.object_path)
    kopete_cdo_iface = dbus.Interface(kopete_cdo, cs.CDO)
    call_async(q, kopete_cdo_iface, 'Claim')

    q.expect_many(
        EventPattern('dbus-signal', path=cdo_path, signal='Finished'),
        EventPattern('dbus-signal',
                     path=cs.CD_PATH,
                     signal='DispatchOperationFinished',
                     args=[cdo_path]),
        EventPattern('dbus-return', method='Claim'),
    )

    # Empathy crashes
    empathy.release_name()

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

    empathy_bus.flush()
    empathy_bus.close()

    # In response, the channels that were being handled by Empathy are closed.
    # Kopete's channel is *not* closed.
    q.expect_many(
        EventPattern('dbus-signal',
                     signal='NameOwnerChanged',
                     predicate=(lambda e: e.args[0] == empathy_unique_name and
                                e.args[2] == '')),
        EventPattern('dbus-method-call', path=chan.object_path,
                     method='Close'),
        EventPattern('dbus-method-call',
                     path=claimed_chan.object_path,
                     method='Close'),
    )

    sync_dbus(bus, q, mc)
    q.unforbid_events(forbidden)
예제 #31
0
def test(q, bus, mc):
    # For this test, we should never actually be asked to make a channel.
    forbidden = [
        EventPattern('dbus-method-call', method='CreateChannel'),
        EventPattern('dbus-method-call', method='EnsureChannel'),
        EventPattern('dbus-method-call', method='ObserveChannels'),
        EventPattern('dbus-method-call', method='AddDispatchOperation'),
        EventPattern('dbus-method-call', method='HandleChannels'),
    ]
    q.forbid_events(forbidden)

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

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

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

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

    user_action_time = dbus.Int64(1238582606)

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

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

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

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

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

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

    q.expect('dbus-return', method='Proceed')
    q.expect('dbus-signal',
             path=cr.object_path,
             interface=cs.CR,
             signal='Failed',
             args=[cs.PERMISSION_DENIED, "No, you don't"])
def test(q, bus, mc):
    params = dbus.Dictionary({"account": "*****@*****.**",
        "password": "******"}, signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

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

    empathy_bus = dbus.bus.BusConnection()
    q.attach_to_bus(empathy_bus)
    empathy = SimulatedClient(q, empathy_bus, 'Empathy',
            observe=[text_fixed_properties], approve=[text_fixed_properties],
            handle=[text_fixed_properties], bypass_approval=False)

    # Kopete's filter is less specific than Empathy's, so we'll prefer Empathy
    kopete_bus = dbus.bus.BusConnection()
    q.attach_to_bus(kopete_bus)
    kopete = SimulatedClient(q, kopete_bus, 'Kopete',
            observe=[], approve=[],
            handle=[vague_fixed_properties], bypass_approval=False)

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

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

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

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

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

    # A channel dispatch operation is created

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

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

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

    # In this test Empathy's filter has more things in it than Kopete's, so
    # MC will prefer Empathy
    handlers = cdo_properties[cs.CDO + '.PossibleHandlers'][:]
    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)
    cdo_props_iface = dbus.Interface(cdo, cs.PROPERTIES_IFACE)

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

    e = q.expect('dbus-method-call',
            path=empathy.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

    q.dbus_return(e.message, bus=empathy_bus, signature='')

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

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

    q.dbus_return(e.message, bus=empathy_bus, signature='')

    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 rejects the channels
    q.dbus_raise(e.message, cs.NOT_AVAILABLE, 'Blind drunk', bus=empathy_bus)

    e = q.expect('dbus-error', method='HandleWith')
    assert e.error.get_dbus_name() == cs.NOT_AVAILABLE
    assert e.error.get_dbus_message() == 'Blind drunk'

    # The channels no longer count as having been approved. Check that MC
    # doesn't carry on regardless
    forbidden = [EventPattern('dbus-method-call', method='HandleChannels')]
    q.forbid_events(forbidden)
    sync_dbus(bus, q, mc)
    q.unforbid_events(forbidden)

    # I'm Feeling Lucky. It might work if I try again? Maybe?
    call_async(q, cdo_iface, 'HandleWith',
            cs.tp_name_prefix + '.Client.Empathy')

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

    # Empathy rejects the channels, again
    q.dbus_raise(e.message, cs.NOT_CAPABLE, 'Still drunk', bus=empathy_bus)

    e = q.expect('dbus-error', method='HandleWith')
    assert e.error.get_dbus_name() == cs.NOT_CAPABLE
    assert e.error.get_dbus_message() == 'Still drunk'

    # OK, OK, is anyone else competent enough to handle them?
    # (Also, assert that MC doesn't offer them back to Empathy, knowing that
    # it already tried and failed)
    forbidden = [EventPattern('dbus-method-call', method='HandleChannels',
        path=empathy.object_path)]
    q.forbid_events(forbidden)
    call_async(q, cdo_iface, 'HandleWith', '')

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

    # Kopete rejects the channels too
    q.dbus_raise(k.message, cs.NOT_AVAILABLE, 'Also blind drunk',
            bus=kopete_bus)

    e = q.expect('dbus-error', method='HandleWith')

    assert e.error.get_dbus_name() == cs.NOT_AVAILABLE
    assert e.error.get_dbus_message() == 'Also blind drunk'

    # MC gives up and closes the channel. This is the end of the CDO.
    q.expect_many(
            EventPattern('dbus-method-call', path=chan.object_path,
                interface=cs.CHANNEL, method='Close', args=[]),
            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, mc):
    params = dbus.Dictionary({"account": "*****@*****.**",
        "password": "******"}, signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

    text_fixed_properties = dbus.Dictionary({
        cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT,
        cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_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])

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

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

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

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

    # A channel dispatch operation is created

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

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

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

    handlers = cdo_properties[cs.CDO + '.PossibleHandlers'][:]
    handlers.sort()
    assert handlers == [cs.tp_name_prefix + '.Client.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
    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='')

    # The channel closes before Kopete has said yes. As a result, MC isn't
    # allowed to emit ChannelLost or Finished yet.
    chan.close()

    # Empathy wants to handle the channel, but is too late
    call_async(q, cdo_iface, 'HandleWith',
            cs.tp_name_prefix + '.Client.Empathy')
    e = q.expect('dbus-error')
    # FIXME: e.error.get_dbus_name() == [...Disconnected] which doesn't
    #   seem like the most appropriate thing for MC to do (but at least it's
    # consistent with ChannelLost)

    # *Now* Kopete is happy...

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

    # ... and in response, the channel dispatch operation finishes

    e = q.expect('dbus-signal', path=cdo_path, signal='ChannelLost')
    assert e.args[0] == chan.object_path
    # FIXME: e.args[1:] == [...Disconnected, 'Channel aborted'] which doesn't
    #   seem like the most appropriate thing for MC to do

    q.expect('dbus-signal', path=cdo_path, signal='Finished')
    q.expect('dbus-signal', path=cs.CD_PATH,
        signal='DispatchOperationFinished', args=[cdo_path])

    # Now there are no more active channel dispatch operations
    assert cd_props.Get(cs.CD_IFACE_OP_LIST, 'DispatchOperations') == []
예제 #34
0
def test(q, bus, mc):
    params = dbus.Dictionary({"account": "*****@*****.**",
        "password": "******"}, signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

    policy_bus_name_ref = dbus.service.BusName('com.example.Policy', bus)

    # For the beginning of this test, we should never be asked to handle
    # a channel.
    forbidden = [
            EventPattern('dbus-method-call', method='HandleChannels'),
            ]
    q.forbid_events(forbidden)

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

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

    e, chan, cdo_path = signal_channel_expect_query(q, bus, account, conn,
            empathy, kopete)

    # No.
    q.dbus_raise(e.message, 'com.example.Errors.No', 'Denied!')

    # The plugin responds
    _, _, e = q.expect_many(
            EventPattern('dbus-signal', path=cdo_path,
                interface=cs.CDO, signal='Finished'),
            EventPattern('dbus-signal', path=cs.CD_PATH,
                interface=cs.CD_IFACE_OP_LIST,
                signal='DispatchOperationFinished',
                args=[cdo_path]),
            EventPattern('dbus-method-call',
                path=chan.object_path,
                interface=cs.CHANNEL_IFACE_DESTROYABLE,
                method='Destroy',
                handled=False),
            )
    q.dbus_return(e.message, signature='')
    chan.close()

    # Try again
    e, chan, cdo_path = signal_channel_expect_query(q, bus, account, conn,
            empathy, kopete)

    # Yes.
    q.dbus_return(e.message, signature='')

    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),
            )
    q.dbus_return(e.message, signature='')
    q.dbus_return(k.message, signature='')

    empathy_cdo = bus.get_object(cs.CD, cdo_path)
    empathy_cdo_iface = dbus.Interface(empathy_cdo, cs.CDO)
    call_async(q, empathy_cdo_iface, 'Claim')

    check_handler = q.expect('dbus-method-call', path='/com/example/Policy',
            interface='com.example.Policy', method='CheckHandler')
    q.dbus_raise(check_handler.message, 'com.example.Errors.No',
            "That handler doesn't have enough options")
    q.expect('dbus-error', method='Claim', name=cs.PERMISSION_DENIED)

    kopete_cdo = bus.get_object(cs.CD, cdo_path)
    kopete_cdo_iface = dbus.Interface(kopete_cdo, cs.CDO)
    call_async(q, kopete_cdo_iface, 'Claim')

    check_handler = q.expect('dbus-method-call', path='/com/example/Policy',
            interface='com.example.Policy', method='CheckHandler')
    q.dbus_return(check_handler.message, signature='')

    q.expect_many(
            EventPattern('dbus-signal', path=cdo_path, signal='Finished'),
            EventPattern('dbus-signal', path=cs.CD_PATH,
                signal='DispatchOperationFinished', args=[cdo_path]),
            EventPattern('dbus-return', method='Claim'),
            )

    sync_dbus(bus, q, mc)

    # Try again; this time we'll reject a selected handler
    e, chan, cdo_path = signal_channel_expect_query(q, bus, account, conn,
            empathy, kopete)

    # The request is fine, continue...
    q.dbus_return(e.message, signature='')

    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),
            )
    q.dbus_return(e.message, signature='')
    q.dbus_return(k.message, signature='')

    kopete_cdo = bus.get_object(cs.CD, cdo_path)
    kopete_cdo_iface = dbus.Interface(kopete_cdo, cs.CDO)
    call_async(q, kopete_cdo_iface, 'HandleWith',
            cs.tp_name_prefix + '.Client.Kopete')

    check_handler = q.expect('dbus-method-call', path='/com/example/Policy',
            interface='com.example.Policy', method='CheckHandler')
    q.dbus_raise(check_handler.message, 'com.example.Errors.No',
            'That handler is not good enough')
    q.expect('dbus-error', method='HandleWith', name=cs.PERMISSION_DENIED)

    # well, let's try *something*... Kopete has been marked as failed,
    # so this will try Empathy
    call_async(q, kopete_cdo_iface, 'HandleWith', '')

    check_handler = q.expect('dbus-method-call', path='/com/example/Policy',
            interface='com.example.Policy', method='CheckHandler')
    q.dbus_raise(check_handler.message, 'com.example.Errors.No',
            'That handler is no good either')

    # Oops... we ran out of handlers
    _, _, _, e = q.expect_many(
            EventPattern('dbus-error', method='HandleWith',
                name=cs.PERMISSION_DENIED),
            EventPattern('dbus-signal', path=cdo_path,
                interface=cs.CDO, signal='Finished'),
            EventPattern('dbus-signal', path=cs.CD_PATH,
                interface=cs.CD_IFACE_OP_LIST,
                signal='DispatchOperationFinished',
                args=[cdo_path]),
            EventPattern('dbus-method-call',
                path=chan.object_path,
                interface=cs.CHANNEL_IFACE_DESTROYABLE,
                method='Destroy',
                handled=False),
            )
    q.dbus_return(e.message, signature='')
    chan.close()

    sync_dbus(bus, q, mc)

    # From now on we no longer want to forbid HandleChannels, but we do want
    # to forbid AddDispatchOperation
    q.unforbid_events(forbidden)
    forbidden = [
            EventPattern('dbus-method-call', method='AddDispatchOperation'),
            ]
    q.forbid_events(forbidden)

    # Try yet again
    policy_request, chan, cdo_path = signal_channel_expect_query(q, bus,
            account, conn, empathy, kopete)

    # Before the policy service replies, someone requests the same channel

    user_action_time = dbus.Int64(1238582606)
    call_async(q, cd, 'EnsureChannel',
            account.object_path, chan.immutable, user_action_time,
            kopete.bus_name, dbus_interface=cs.CD)
    ret, add_request_call = q.expect_many(
            EventPattern('dbus-return', method='EnsureChannel'),
            EventPattern('dbus-method-call', handled=False,
                interface=cs.CLIENT_IFACE_REQUESTS,
                method='AddRequest', path=kopete.object_path),
            )
    request_path = ret.value[0]

    cr = bus.get_object(cs.CD, request_path)
    cr.Proceed(dbus_interface=cs.CR)

    cm_request_call = q.expect('dbus-method-call',
            interface=cs.CONN_IFACE_REQUESTS,
            method='EnsureChannel',
            path=conn.object_path, args=[chan.immutable], handled=False)

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

    # Time passes. The CM returns the existing channel, and the policy
    # service gets round to replying

    q.dbus_return(cm_request_call.message, False,
            chan.object_path, chan.immutable, signature='boa{sv}')

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

    # Now we want to pass the channel to the selected handler.
    # What does the policy service think about that?
    check_handler = q.expect('dbus-method-call', path='/com/example/Policy',
            interface='com.example.Policy', method='CheckHandler')

    # Yeah, we're OK with that.
    q.dbus_return(check_handler.message, signature='')

    e = q.expect('dbus-method-call',
            path=kopete.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] == chan.object_path, channels
    assert channels[0][1] == chan.immutable, channels
    assert e.args[3] == [request_path], e.args
    assert e.args[4] == user_action_time, (e.args[4], user_action_time)
    assert isinstance(e.args[5], dict)
    assert len(e.args) == 6

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

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

    sync_dbus(bus, q, mc)
예제 #35
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'])
예제 #36
0
def test(q, bus, mc):
    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******"
        },
        signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

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

    client = SimulatedClient(q,
                             bus,
                             'Empathy',
                             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, [client])

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

    # chat UI calls ChannelDispatcher.EnsureChannel or CreateChannel
    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,
        dbus.Int64(1234),
        'grr.arg',  # a valid bus name, but the wrong prefix
        dbus_interface=cs.CD)
    ret = q.expect('dbus-error', method='CreateChannel')
    assert ret.error.get_dbus_name() == cs.INVALID_ARGUMENT

    call_async(
        q,
        cd,
        'CreateChannel',
        account.object_path,
        request,
        dbus.Int64(1234),
        'can has cheeseburger?',  # a totally invalid bus name
        dbus_interface=cs.CD)
    ret = q.expect('dbus-error', method='CreateChannel')
    assert ret.error.get_dbus_name() == cs.INVALID_ARGUMENT
def test(q, bus, mc):
    params = dbus.Dictionary({"account": "*****@*****.**",
        "password": "******"}, signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

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

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

    # No Approver should be invoked at any point during this test, because the
    # Channel was Requested
    def fail_on_approval(e):
        raise AssertionError('Approver should not be invoked')
    q.add_dbus_method_impl(fail_on_approval, path=client.object_path,
            interface=cs.APPROVER, method='AddDispatchOperation')

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

    user_action_time = dbus.Int64(1238582606)

    # chat UI calls ChannelDispatcher.CreateChannel
    cd = ChannelDispatcher(bus)
    request = dbus.Dictionary({
            cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_TEXT,
            cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT,
            cs.CHANNEL + '.TargetID': 'juliet',
            }, signature='sv')
    request_path = cd.CreateChannel(account.object_path, request,
        user_action_time, client.bus_name)

    add_request = q.expect('dbus-method-call', handled=False,
        interface=cs.CLIENT_IFACE_REQUESTS, method='AddRequest',
        path=client.object_path)
    assert add_request.args[0] == request_path
    q.dbus_return(add_request.message, signature='')

    cr = bus.get_object(cs.CD, 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

    # chat UI connects to signals and calls ChannelRequest.Proceed()
    cr.Proceed()
    cm_request_call = q.expect('dbus-method-call',
                interface=cs.CONN_IFACE_REQUESTS, method='CreateChannel',
                path=conn.object_path, args=[request], handled=False)

    # Actually, never mind.
    cr.Cancel()

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

    # Channel is unwanted now, MC stabs it in the face
    stdsig, _ = q.expect_many(
            EventPattern('dbus-signal', path=request_path,
                interface=cs.CR, signal='Failed'),
            EventPattern('dbus-method-call', path=channel.object_path,
                interface=cs.CHANNEL, method='Close', handled=True),
            )
def test(q, bus, mc):
    policy_bus_name_ref = dbus.service.BusName('com.example.Policy', bus)

    params = dbus.Dictionary({"account": "*****@*****.**",
        "password": "******"}, signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn, e = enable_fakecm_account(q, bus, mc, account, params,
            extra_interfaces=[cs.CONN_IFACE_SERVICE_POINT],
            expect_after_connect=[
                EventPattern('dbus-method-call', method='Get',
                    args=[cs.CONN_IFACE_SERVICE_POINT, 'KnownServicePoints']),
                ])

    e_numbers = ['911', '112']
    points = dbus.Array([((cs.SERVICE_POINT_TYPE_EMERGENCY, 'urn:service:sos'),
                          e_numbers)], signature='((us)as)')

    q.dbus_return(e.message, points, signature='v')

    # the service points change
    e_numbers = ['911', '112', '999']
    points = dbus.Array([((cs.SERVICE_POINT_TYPE_EMERGENCY, 'urn:service:sos'),
                          e_numbers)], signature='((us)as)')
    q.dbus_emit(conn.object_path, cs.CONN_IFACE_SERVICE_POINT,
                'ServicePointsChanged', points, signature='a((us)as)')

    # MC used to critical if more than one emergency service point was
    # given by the CM. That's silly, so let's test it.
    e_numbers1 = ['911']
    e_numbers2 = ['999']
    points = dbus.Array([((cs.SERVICE_POINT_TYPE_EMERGENCY, 'urn:service:sos'),
                          e_numbers1),
                         ((cs.SERVICE_POINT_TYPE_EMERGENCY, 'urn:service:sos'),
                          e_numbers2)], signature='((us)as)')
    q.dbus_emit(conn.object_path, cs.CONN_IFACE_SERVICE_POINT,
                'ServicePointsChanged', points, signature='a((us)as)')

    e_numbers = e_numbers1 + e_numbers2

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

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

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

    user_action_time = dbus.Int64(1238582606)

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

    for emergency in False, True:
        if emergency:
            target_id = '112'
            forbidden = [
                    EventPattern('dbus-method-call', method='RequestRequest'),
                    ]

        else:
            target_id = 'juliet'
            # For now, we should never actually be asked to make a channel.
            forbidden = [
                    EventPattern('dbus-method-call', method='CreateChannel'),
                    EventPattern('dbus-method-call', method='EnsureChannel'),
                    EventPattern('dbus-method-call', method='ObserveChannels'),
                    EventPattern('dbus-method-call', method='AddDispatchOperation'),
                    EventPattern('dbus-method-call', method='HandleChannels'),
                    ]

        q.forbid_events(forbidden)

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

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

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

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

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

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

        if emergency:
            # The CM is asked to create the channel anyway, because this
            # looks a bit like an emergency call
            cm_request_call = q.expect('dbus-method-call',
                    interface=cs.CONN_IFACE_REQUESTS,
                    method='CreateChannel',
                    path=conn.object_path, args=[request], handled=False)
            q.dbus_raise(cm_request_call.message, cs.INVALID_ARGUMENT, 'No')

            sync_dbus(bus, q, account)
            q.unforbid_events(forbidden)
        else:
            # What does the policy service think?
            permission = q.expect('dbus-method-call', path='/com/example/Policy',
                    interface='com.example.Policy', method='RequestRequest')

            # Think about it for a bit, then allow dispatching to continue
            sync_dbus(bus, q, account)
            q.unforbid_events(forbidden)
            q.dbus_return(permission.message, signature='')

            # Only now does the CM's CreateChannel method get called
            cm_request_call = q.expect('dbus-method-call',
                    interface=cs.CONN_IFACE_REQUESTS,
                    method='CreateChannel',
                    path=conn.object_path, args=[request], handled=False)
            q.dbus_raise(cm_request_call.message, cs.INVALID_ARGUMENT, 'No')
def test(q, bus, mc):
    # Two clients want to handle channels: MediaCall is running, and AbiWord
    # is activatable.

    # this must match the .client file
    abi_contact_fixed_properties = dbus.Dictionary({
        cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_STREAM_TUBE,
        cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT,
        cs.CHANNEL_TYPE_STREAM_TUBE + '.Service': 'x-abiword',
        }, signature='sv')
    abi_room_fixed_properties = dbus.Dictionary({
        cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_STREAM_TUBE,
        cs.CHANNEL + '.TargetHandleType': cs.HT_ROOM,
        cs.CHANNEL_TYPE_STREAM_TUBE + '.Service': 'x-abiword',
        }, signature='sv')

    media_fixed_properties = dbus.Dictionary({
        cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_CALL,
        }, signature='sv')
    media_call = SimulatedClient(q, bus, 'MediaCall',
            observe=[], approve=[], handle=[media_fixed_properties],
            cap_tokens=[cs.CHANNEL_TYPE_CALL + '/ice',
                cs.CHANNEL_TYPE_CALL + '/audio/speex',
                cs.CHANNEL_TYPE_CALL + '/video/theora'],
            bypass_approval=False)

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

    def check_contact_caps(e):
        structs = e.args[0]

        filters = {}
        tokens = {}

        assert len(structs) == 3

        for struct in structs:
            assert struct[0] not in filters
            filters[struct[0]] = sorted(struct[1])
            tokens[struct[0]] = sorted(struct[2])

        assert media_fixed_properties in filters[cs.CLIENT + '.MediaCall']
        assert len(filters[cs.CLIENT + '.MediaCall']) == 1

        assert abi_room_fixed_properties in filters[cs.CLIENT + '.AbiWord']
        assert abi_contact_fixed_properties in filters[cs.CLIENT + '.AbiWord']
        assert len(filters[cs.CLIENT + '.AbiWord']) == 2

        assert len(tokens[cs.CLIENT + '.MediaCall']) == 3
        assert cs.CHANNEL_TYPE_CALL + '/ice' in \
                tokens[cs.CLIENT + '.MediaCall']
        assert cs.CHANNEL_TYPE_CALL + '/audio/speex' in \
                tokens[cs.CLIENT + '.MediaCall']
        assert cs.CHANNEL_TYPE_CALL + '/video/theora' in \
                tokens[cs.CLIENT + '.MediaCall']

        assert len(tokens[cs.CLIENT + '.AbiWord']) == 2
        assert 'com.example.Foo' in tokens[cs.CLIENT + '.AbiWord']
        assert 'com.example.Bar' in tokens[cs.CLIENT + '.AbiWord']

        return True

    params = dbus.Dictionary({"account": "*****@*****.**",
        "password": "******"}, signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn, before = enable_fakecm_account(q, bus, mc, account, params,
            extra_interfaces=[cs.CONN_IFACE_CONTACT_CAPS],
            expect_before_connect=[
                EventPattern('dbus-method-call', handled=False,
                    interface=cs.CONN_IFACE_CONTACT_CAPS,
                    method='UpdateCapabilities',
                    predicate=check_contact_caps),
                ])
    q.dbus_return(before.message, signature='')

    irssi_bus = dbus.bus.BusConnection()
    irssi_bus.set_exit_on_disconnect(False)   # we'll disconnect later
    q.attach_to_bus(irssi_bus)
    irssi_fixed_properties = dbus.Dictionary({
        cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_TEXT,
        cs.CHANNEL + '.TargetHandleType': cs.HT_ROOM,
        }, signature='sv')
    irssi = SimulatedClient(q, irssi_bus, 'Irssi',
            observe=[], approve=[], handle=[irssi_fixed_properties],
            cap_tokens=[],
            bypass_approval=False)

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

    e = q.expect('dbus-method-call', handled=False,
        interface=cs.CONN_IFACE_CONTACT_CAPS,
        method='UpdateCapabilities')

    assert len(e.args[0]) == 1
    struct = e.args[0][0]
    assert struct[0] == cs.CLIENT + '.Irssi'
    assert struct[1] == [irssi_fixed_properties]
    assert struct[2] == []

    # When Irssi exits, the CM is told it has gone
    irssi.release_name()
    del irssi
    irssi_bus.flush()
    irssi_bus.close()

    e = q.expect('dbus-method-call', handled=False,
        interface=cs.CONN_IFACE_CONTACT_CAPS,
        method='UpdateCapabilities')

    assert len(e.args[0]) == 1
    struct = e.args[0][0]
    assert struct[0] == cs.CLIENT + '.Irssi'
    assert struct[1] == []
    assert struct[2] == []
예제 #40
0
def test(q, bus, mc):
    params = dbus.Dictionary({"account": "*****@*****.**",
        "password": "******"}, signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

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

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

    misc_fixed_properties = dbus.Dictionary({
        cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT,
        cs.CHANNEL + '.ChannelType': 'com.example.Extension',
        }, signature='sv')

    # Two clients want to observe, approve and handle channels. Empathy handles
    # VoIP, Kopete does not.
    empathy = SimulatedClient(q, bus, 'org.gnome.Empathy',
            observe=[text_fixed_properties, media_fixed_properties],
            approve=[text_fixed_properties, media_fixed_properties],
            handle=[text_fixed_properties, media_fixed_properties],
            bypass_approval=False)

    kopete = SimulatedClient(q, bus, 'org.kde.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])

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

    # Part 1. A bundle that Empathy, but not Kopete, can handle

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

    text_chan = SimulatedChannel(conn, text_channel_properties,
            destroyable=True)

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

    media_chan = SimulatedChannel(conn, media_channel_properties,
            destroyable=False)

    conn.NewChannels([text_chan, media_chan])

    # A channel dispatch operation is created for the Text channel first.

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

    text_cdo_path = e.args[0]
    text_cdo_properties = e.args[1]

    assert text_cdo_properties[cs.CDO + '.Account'] == account.object_path
    assert text_cdo_properties[cs.CDO + '.Connection'] == conn.object_path

    handlers = text_cdo_properties[cs.CDO + '.PossibleHandlers'][:]
    assert (sorted(handlers) ==
        [cs.tp_name_prefix + '.Client.org.gnome.Empathy',
            cs.tp_name_prefix + '.Client.org.kde.Kopete']), handlers

    text_cdo = bus.get_object(cs.CD, text_cdo_path)
    text_cdo_iface = dbus.Interface(text_cdo, cs.CDO)

    # Both Observers are told about the new Text channel

    e_observe_text, k_observe_text = 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_observe_text.args[0] == account.object_path, e_observe_text.args
    assert e_observe_text.args[1] == conn.object_path, e_observe_text.args
    assert e_observe_text.args[3] == text_cdo_path, e_observe_text.args
    assert e_observe_text.args[4] == [], e_observe_text.args
    channels = e_observe_text.args[2]
    assert len(channels) == 1, channels
    assert (text_chan.object_path, text_channel_properties) in channels

    assert k_observe_text.args[0] == e_observe_text.args[0], k_observe_text.args
    assert k_observe_text.args[1] == e_observe_text.args[1], k_observe_text.args
    assert (k_observe_text.args[2] ==
            [(text_chan.object_path, text_channel_properties)])

    # Now a separate CDO is created for the media channel.

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

    media_cdo_path = e.args[0]
    media_cdo_properties = e.args[1]

    assert media_cdo_properties[cs.CDO + '.Account'] == account.object_path
    assert media_cdo_properties[cs.CDO + '.Connection'] == conn.object_path

    handlers = media_cdo_properties[cs.CDO + '.PossibleHandlers'][:]
    # only Empathy can handle it
    assert (sorted(handlers) ==
        [cs.tp_name_prefix + '.Client.org.gnome.Empathy']), handlers

    assert cs.CD_IFACE_OP_LIST in cd_props.Get(cs.CD, 'Interfaces')
    assert (sorted(cd_props.Get(cs.CD_IFACE_OP_LIST, 'DispatchOperations')) ==
            [(text_cdo_path, text_cdo_properties),
                (media_cdo_path, media_cdo_properties)])

    media_cdo = bus.get_object(cs.CD, media_cdo_path)
    media_cdo_iface = dbus.Interface(media_cdo, cs.CDO)

    # Only Empathy is told about the new media channel

    e_observe_media = q.expect('dbus-method-call',
            path=empathy.object_path,
            interface=cs.OBSERVER, method='ObserveChannels',
            handled=False)
    assert e_observe_media.args[0] == account.object_path, e_observe_media.args
    assert e_observe_media.args[1] == conn.object_path, e_observe_media.args
    assert e_observe_media.args[3] == media_cdo_path, e_observe_media.args
    assert e_observe_media.args[4] == [], e_observe_media.args
    channels = e_observe_media.args[2]
    assert len(channels) == 1, channels
    assert (media_chan.object_path, media_channel_properties) in channels

    # All Observers reply.

    q.dbus_return(e_observe_text.message, signature='')
    q.dbus_return(k_observe_text.message, signature='')
    q.dbus_return(e_observe_media.message, signature='')

    # The Approvers are next
    e_approve_text, k_approve_text, e_approve_media = q.expect_many(
            EventPattern('dbus-method-call',
                path=empathy.object_path,
                interface=cs.APPROVER, method='AddDispatchOperation',
                predicate=lambda e: e.args[1] == text_cdo_path,
                handled=False),
            EventPattern('dbus-method-call',
                path=kopete.object_path,
                interface=cs.APPROVER, method='AddDispatchOperation',
                handled=False),
            EventPattern('dbus-method-call',
                path=empathy.object_path,
                interface=cs.APPROVER, method='AddDispatchOperation',
                predicate=lambda e: e.args[1] == media_cdo_path,
                handled=False)
            )
    assert len(e_approve_text.args[0]) == 1
    assert ((text_chan.object_path, text_channel_properties) in
            e_approve_text.args[0])
    assert e_approve_text.args[1:] == [text_cdo_path, text_cdo_properties]
    assert k_approve_text.args == e_approve_text.args

    assert len(e_approve_media.args[0]) == 1
    assert ((media_chan.object_path, media_channel_properties) in
            e_approve_media.args[0])
    assert e_approve_media.args[1:] == [media_cdo_path, media_cdo_properties]

    q.dbus_return(e_approve_text.message, signature='')
    q.dbus_return(k_approve_text.message, signature='')
    q.dbus_return(e_approve_media.message, signature='')

    # Both Approvers now have a flashing icon or something, trying to get the
    # user's attention. The user clicks on Empathy
    call_async(q, text_cdo_iface, 'HandleWith',
        cs.tp_name_prefix + '.Client.org.gnome.Empathy')

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

    # Empathy accepts the channel
    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'),
            )

    # The user doesn't care which client will handle the channel - because
    # Empathy is the only possibility, it will be chosen (this is also a
    # regression test for the ability to leave the handler unspecified).
    call_async(q, media_cdo_iface, 'HandleWith', '')

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

    # Empathy accepts the channel
    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') == []

    text_chan.close()
    media_chan.close()

    # Part 2. A bundle that neither client can handle in its entirety

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

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

    text_chan = SimulatedChannel(conn, text_channel_properties,
            destroyable=True)
    media_chan = SimulatedChannel(conn, media_channel_properties,
            destroyable=False)
    respawning_chan = SimulatedChannel(conn, respawning_channel_properties,
            destroyable=True)
    ext_chan = SimulatedChannel(conn, ext_channel_properties,
            destroyable=False)

    conn.NewChannels([text_chan, media_chan, ext_chan, respawning_chan])

    # No client can handle all four channels, so the bundle explodes into
    # two dispatch operations and two failures. We can only match the first
    # CDO here - we look at the others later.
    e_observe_media, e_observe_text, k_observe_text, \
    e_approve_media, e_approve_text, k_approve_text, \
    _, _, _ = q.expect_many(
            EventPattern('dbus-method-call',
                path=empathy.object_path,
                interface=cs.OBSERVER, method='ObserveChannels',
                predicate=(lambda e: e.args[2][0][0] == media_chan.object_path),
                handled=False),
            EventPattern('dbus-method-call',
                path=empathy.object_path,
                interface=cs.OBSERVER, method='ObserveChannels',
                predicate=(lambda e: e.args[2][0][0] == text_chan.object_path),
                handled=False),
            EventPattern('dbus-method-call',
                path=kopete.object_path,
                interface=cs.OBSERVER, method='ObserveChannels',
                predicate=(lambda e: e.args[2][0][0] == text_chan.object_path),
                handled=False),
            EventPattern('dbus-method-call',
                path=empathy.object_path,
                interface=cs.APPROVER, method='AddDispatchOperation',
                predicate=(lambda e:
                    e.args[0][0][0] ==
                    media_chan.object_path),
                handled=False),
            EventPattern('dbus-method-call',
                path=empathy.object_path,
                interface=cs.APPROVER, method='AddDispatchOperation',
                predicate=(lambda e:
                    e.args[0][0][0] ==
                    text_chan.object_path),
                handled=False),
            EventPattern('dbus-method-call',
                path=kopete.object_path,
                interface=cs.APPROVER, method='AddDispatchOperation',
                predicate=(lambda e:
                    e.args[0][0][0] ==
                    text_chan.object_path),
                handled=False),
            EventPattern('dbus-method-call',
                interface=cs.CHANNEL_IFACE_DESTROYABLE,
                method='Destroy',
                path=respawning_chan.object_path,
                handled=True),
            EventPattern('dbus-method-call',
                interface=cs.CHANNEL,
                method='Close',
                path=ext_chan.object_path,
                handled=True),
            # we can't distinguish between the two NewDispatchOperation signals
            # since we no longer see the Channels property (it's mutable)
            EventPattern('dbus-signal',
                path=cs.CD_PATH,
                interface=cs.CD_IFACE_OP_LIST,
                signal='NewDispatchOperation'),
            )

    q.dbus_return(e_observe_media.message, signature='')
    q.dbus_return(e_observe_text.message, signature='')
    q.dbus_return(k_observe_text.message, signature='')
    q.dbus_return(e_approve_media.message, signature='')
    q.dbus_return(e_approve_text.message, signature='')
    q.dbus_return(k_approve_text.message, signature='')
예제 #41
0
def test(q, bus, mc):
    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******"
        },
        signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

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

    # We have more than one Client "head" on the same unique name, to test
    # fd.o #24645 - we want the same "head" to be reinvoked if at all possible

    # This one is first in alphabetical order, is discovered first, and can
    # handle all channels, but is not the one we want
    empathy_worse_match = SimulatedClient(q,
                                          bus,
                                          'A.Temporary.Handler',
                                          observe=[],
                                          approve=[],
                                          handle=[[]],
                                          bypass_approval=False)

    # This is the one we actually want
    empathy = SimulatedClient(q,
                              bus,
                              'Empathy',
                              observe=[text_fixed_properties],
                              approve=[text_fixed_properties],
                              handle=[text_fixed_properties],
                              bypass_approval=False)

    # this one is a closer match, but not the preferred handler
    closer_match = dbus.Dictionary(text_fixed_properties)
    closer_match[cs.CHANNEL + '.TargetID'] = 'juliet'
    empathy_better_match = SimulatedClient(q,
                                           bus,
                                           'Empathy.BetterMatch',
                                           observe=[],
                                           approve=[],
                                           handle=[closer_match],
                                           bypass_approval=False)

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

    channel = test_channel_creation(q, bus, account, empathy, conn)

    # After the channel has been dispatched, a handler that would normally
    # be a closer match turns up. Regardless, we should not redispatch to it.
    # For the better client to be treated as if it's in a different process,
    # it needs its own D-Bus connection.
    closer_match = dbus.Dictionary(text_fixed_properties)
    closer_match[cs.CHANNEL + '.TargetID'] = 'juliet'
    closer_match[cs.CHANNEL + '.InitiatorID'] = conn.self_ident
    better_bus = dbus.bus.BusConnection()
    q.attach_to_bus(better_bus)
    better = SimulatedClient(q,
                             better_bus,
                             'BetterMatch',
                             observe=[],
                             approve=[],
                             handle=[closer_match],
                             bypass_approval=False)
    expect_client_setup(q, [better])

    test_channel_redispatch(q, bus, account, empathy, conn, channel)
    test_channel_redispatch(q,
                            bus,
                            account,
                            empathy,
                            conn,
                            channel,
                            ungrateful_handler=True)
    empathy.release_name()
    empathy_better_match.release_name()
    empathy_worse_match.release_name()
    test_channel_redispatch(q,
                            bus,
                            account,
                            empathy,
                            conn,
                            channel,
                            client_gone=True)
    channel.close()
def test(q, bus, mc):
    params = dbus.Dictionary({"account": "*****@*****.**",
        "password": "******"}, signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

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

    # Empathy is an observer for text channels with
    # DelayApprovers=TRUE.
    empathy = SimulatedClient(q, bus, 'Empathy',
        observe=[text_fixed_properties], approve=[],
        handle=[], delay_approvers=True)

    # Kopete is an approver and handler for text channels.
    kopete = SimulatedClient(q, bus, 'Kopete',
        observe=[], approve=[text_fixed_properties],
        handle=[text_fixed_properties])

    expect_client_setup(q, [empathy, kopete])

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

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

    # A text channel appears!
    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()

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

    cdo_path = e.args[0]
    cdo = bus.get_object(cs.CD, cdo_path)
    cdo_iface = dbus.Interface(cdo, cs.CDO)
    cdo_props_iface = dbus.Interface(cdo, cs.PROPERTIES_IFACE)

    # Empathy, the observer, gets the channel to observe. Because it
    # has DelayApprovers=TRUE, Kopete should not have
    # AddDispatchOperation called on it until Empathy returns from
    # ObserveChannels.
    forbidden = [EventPattern('dbus-method-call',
            path=kopete.object_path,
            interface=cs.APPROVER, method='AddDispatchOperation')]
    q.forbid_events(forbidden)

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

    # Waste a little time here and there.  We can't call sync_dbus
    # here because it calls Ping and libdbus returns from Ping
    # synchronously and doesn't turn the main loop handle enough.
    call_async(q, cd_props, 'Get', cs.CD_IFACE_OP_LIST, 'DispatchOperations')
    event = q.expect('dbus-return', method='Get')

    # Finally return from ObserveChannels, so now we expect ADO to be
    # called on Kopete.
    q.dbus_return(o.message, bus=bus, signature='')
    q.unforbid_events(forbidden)

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

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

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

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

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

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

    # Now there are no more active channel dispatch operations
    assert cd_props.Get(cs.CD_IFACE_OP_LIST, 'DispatchOperations') == []
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)
    conn = enable_fakecm_account(q, bus, mc, account, params)

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

    # Empathy is an observer for text channels with
    # DelayApprovers=TRUE.
    empathy = SimulatedClient(q, bus, 'Empathy',
        observe=[text_fixed_properties], approve=[],
        handle=[], delay_approvers=True)

    # Loggy is an observer for text channels with
    # DelayApprovers=FALSE.
    loggy = SimulatedClient(q, bus, 'Loggy',
        observe=[text_fixed_properties], approve=[],
        handle=[], delay_approvers=False)

    # Kopete is an approver and handler for text channels.
    kopete = SimulatedClient(q, bus, 'Kopete',
        observe=[], approve=[text_fixed_properties],
        handle=[text_fixed_properties])

    expect_client_setup(q, [empathy, loggy, kopete])

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

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

    # A text channel appears!
    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()

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

    cdo_path = e.args[0]
    cdo = bus.get_object(cs.CD, cdo_path)
    cdo_iface = dbus.Interface(cdo, cs.CDO)
    cdo_props_iface = dbus.Interface(cdo, cs.PROPERTIES_IFACE)

    # Empathy, the observer, gets the channel to observe. Because it
    # has DelayApprovers=TRUE, Kopete should not have
    # AddDispatchOperation called on it until Empathy returns from
    # ObserveChannels. Because Loggy has DelayApprovers=False,
    # however, ADO can be called on Kopete before Loggy returns, but
    # again, only after Empathy returns.
    forbidden = [EventPattern('dbus-method-call',
            path=kopete.object_path,
            interface=cs.APPROVER, method='AddDispatchOperation')]
    q.forbid_events(forbidden)

    e, l = q.expect_many(EventPattern('dbus-method-call',
                 path=empathy.object_path,
                 interface=cs.OBSERVER, method='ObserveChannels',
                 handled=False),
             EventPattern('dbus-method-call',
                 path=loggy.object_path,
                 interface=cs.OBSERVER, method='ObserveChannels',
                 handled=False),
             )

    # Waste a little time here and there.  We can't call sync_dbus
    # here because it calls Ping and libdbus returns from Ping
    # synchronously and doesn't turn the main loop handle enough.
    call_async(q, cd_props, 'Get', cs.CD_IFACE_OP_LIST, 'DispatchOperations')
    event = q.expect('dbus-return', method='Get')

    # Finally return from ObserveChannels from Empathy, so now we
    # expect ADO to be called on Kopete.
    q.dbus_return(e.message, bus=bus, signature='')
    q.unforbid_events(forbidden)

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

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

    # Return from loggy's ObserveChannels.
    q.dbus_return(l.message, bus=bus, signature='')

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

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

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

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

    # Now there are no more active channel dispatch operations
    assert cd_props.Get(cs.CD_IFACE_OP_LIST, 'DispatchOperations') == []
예제 #45
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, mc):
    params = dbus.Dictionary({"account": "*****@*****.**",
        "password": "******"}, signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

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

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

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

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

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

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

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

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

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

    # A channel dispatch operation is created

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

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

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

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

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

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

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

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

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

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


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

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

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

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

    # The Approver (Kopete) is next

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

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

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

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

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

    # Logger crashes
    logger.release_name()

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

    logger_bus.flush()

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

    # Logger gets restarted
    logger.reacquire_name()

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

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

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

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

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

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

    # Two clients want to observe, approve and handle text and VoIP channels.
    empathy = SimulatedClient(q, bus, 'Empathy',
            observe=[text_fixed_properties, voip_fixed_properties],
            approve=[text_fixed_properties, voip_fixed_properties],
            handle=[text_fixed_properties, voip_fixed_properties],
            bypass_approval=False)
    kopete = SimulatedClient(q, bus, 'Kopete',
            observe=[text_fixed_properties, voip_fixed_properties],
            approve=[text_fixed_properties, voip_fixed_properties],
            handle=[text_fixed_properties, voip_fixed_properties],
            bypass_approval=False)

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

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

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

    # First, a VoIP channel is created

    BUNDLE = '/8de0d29d-83e1-40f5-b24f-748c0aa86c82'

    channel_properties = dbus.Dictionary(voip_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')
    channel_properties[cs.CHANNEL + '.FUTURE.Bundle'] = BUNDLE

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

    # A channel dispatch operation is created

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

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

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

    handlers = cdo_properties[cs.CDO + '.PossibleHandlers'][:]
    handlers.sort()
    assert handlers == [cs.tp_name_prefix + '.Client.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') == []

    # Now that Empathy has the VoIP channel, it wants to steal incoming Text
    # channels from the same bundle

    same_bundle_properties = dbus.Dictionary(text_fixed_properties,
            signature='sv')
    same_bundle_properties[cs.CHANNEL + '.FUTURE.Bundle'] = BUNDLE

    bypass = SimulatedClient(q, bus, 'Empathy._1_42.Window2',
            observe=[],
            approve=[],
            handle=[same_bundle_properties],
            bypass_approval=True)

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

    # From now on, this test must fail if we're asked to approve anything
    approval = [
            EventPattern('dbus-method-call', method='AddDispatchOperation'),
            ]
    q.forbid_events(approval)

    channel_properties = dbus.Dictionary(text_fixed_properties,
            signature='sv')
    channel_properties[cs.CHANNEL + '.TargetHandleType'] = cs.HT_CONTACT
    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 + '.FUTURE.Bundle'] = BUNDLE
    channel_properties[cs.CHANNEL + '.Interfaces'] = dbus.Array(signature='s')

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

    # Again, there's a CDO

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

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

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

    handlers = cdo_properties[cs.CDO + '.PossibleHandlers'][:]
    # The handler with BypassApproval is first
    assert handlers[0] == bypass.bus_name
    # The other two handlers are still possibilities
    assert len(handlers) == 3

    # Observers are invoked as usual

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

    # Empathy's BypassApproval part is asked to handle the channels
    e = q.expect('dbus-method-call',
            path=bypass.object_path,
            interface=cs.HANDLER, method='HandleChannels',
            handled=False)
    # Empathy accepts the 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)
    conn = enable_fakecm_account(q, bus, mc, account, params)

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

    empathy_bus = dbus.bus.BusConnection()
    empathy_bus.set_exit_on_disconnect(False)   # we'll disconnect later
    kopete_bus = dbus.bus.BusConnection()
    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])

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

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

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

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

    # A channel dispatch operation is created

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

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

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

    handlers = cdo_properties[cs.CDO + '.PossibleHandlers'][:]
    handlers.sort()
    assert handlers == [cs.tp_name_prefix + '.Client.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)
    cdo_props_iface = dbus.Interface(cdo, cs.PROPERTIES_IFACE)

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

    # 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, bus=empathy_bus, signature='')
    q.dbus_return(e.message, bus=kopete_bus, 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, bus=empathy_bus, signature='')
    q.dbus_return(k.message, bus=kopete_bus, signature='')

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

    # Using an invalid Handler name should fail
    call_async(q, cdo_iface, 'HandleWith',
            cs.tp_name_prefix + '.The.Moon.On.A.Stick')
    q.expect('dbus-error', method='HandleWith')
    call_async(q, cdo_iface, 'HandleWith',
            cs.tp_name_prefix + '.Client.the moon on a stick')
    q.expect('dbus-error', method='HandleWith')

    # 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, bus=empathy_bus, signature='')

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

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

    # Approve another channel using HandleWithTime()
    channel_properties = dbus.Dictionary(text_fixed_properties,
            signature='sv')
    channel_properties[cs.CHANNEL + '.TargetID'] = 'lucien'
    channel_properties[cs.CHANNEL + '.TargetHandle'] = \
            conn.ensure_handle(cs.HT_CONTACT, 'lucien')
    channel_properties[cs.CHANNEL + '.InitiatorID'] = 'lucien'
    channel_properties[cs.CHANNEL + '.InitiatorHandle'] = \
            conn.ensure_handle(cs.HT_CONTACT, 'lucien')
    channel_properties[cs.CHANNEL + '.Requested'] = False
    channel_properties[cs.CHANNEL + '.Interfaces'] = dbus.Array(signature='s')

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

    # A channel dispatch operation is created

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

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

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

    handlers = cdo_properties[cs.CDO + '.PossibleHandlers'][:]
    handlers.sort()
    assert handlers == [cs.tp_name_prefix + '.Client.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)
    cdo_props_iface = dbus.Interface(cdo, cs.PROPERTIES_IFACE)

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

    # 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, bus=empathy_bus, signature='')
    q.dbus_return(e.message, bus=kopete_bus, 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, bus=empathy_bus, signature='')
    q.dbus_return(k.message, bus=kopete_bus, 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, 'HandleWithTime',
            cs.tp_name_prefix + '.Client.Empathy', 13)

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

    account_path, conn_path, channels, requests, action_time, info = e.args
    assert action_time == 13

    # Empathy accepts the channels
    q.dbus_return(e.message, bus=empathy_bus, signature='')

    q.expect_many(
            EventPattern('dbus-return', method='HandleWithTime'),
            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') == []

    # From now on, it is an error to get HandleChannels (because we're
    # testing Claim())
    forbidden = [
            EventPattern('dbus-method-call', method='HandleChannels'),
            ]
    q.forbid_events(forbidden)

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

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

    # A channel dispatch operation is created

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

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

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

    handlers = cdo_properties[cs.CDO + '.PossibleHandlers'][:]
    handlers.sort()
    assert handlers == [cs.tp_name_prefix + '.Client.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] == claimed_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, bus=kopete_bus, signature='')
    q.dbus_return(e.message, bus=empathy_bus, 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 == [[(claimed_chan.object_path, channel_properties)],
            cdo_path, cdo_properties]
    assert k.args == e.args

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

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

    # The user responds to Empathy first, and Empathy decides it wants the
    # channel for itself
    empathy_cdo = empathy_bus.get_object(cdo.bus_name, cdo.object_path)
    empathy_cdo_iface = dbus.Interface(empathy_cdo, cs.CDO)
    call_async(q, empathy_cdo_iface, 'Claim')

    q.expect_many(
            EventPattern('dbus-signal', path=cdo_path, signal='Finished'),
            EventPattern('dbus-signal', path=cs.CD_PATH,
                signal='DispatchOperationFinished', args=[cdo_path]),
            EventPattern('dbus-return', method='Claim'),
            )

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

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

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

    # third_chan should not be closed
    q.unforbid_events(forbidden)
    forbidden.append(EventPattern('dbus-method-call', method='Close',
        path=third_chan.object_path))
    q.forbid_events(forbidden)

    # A channel dispatch operation is created

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

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

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

    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),
            )
    q.dbus_return(k.message, bus=kopete_bus, signature='')
    q.dbus_return(e.message, bus=empathy_bus, signature='')

    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),
            )
    q.dbus_return(e.message, bus=empathy_bus, signature='')
    q.dbus_return(k.message, bus=kopete_bus, signature='')

    # Kopete closes this one
    kopete_cdo = kopete_bus.get_object(cdo.bus_name, cdo.object_path)
    kopete_cdo_iface = dbus.Interface(kopete_cdo, cs.CDO)
    call_async(q, kopete_cdo_iface, 'Claim')

    q.expect_many(
            EventPattern('dbus-signal', path=cdo_path, signal='Finished'),
            EventPattern('dbus-signal', path=cs.CD_PATH,
                signal='DispatchOperationFinished', args=[cdo_path]),
            EventPattern('dbus-return', method='Claim'),
            )

    # Empathy crashes
    empathy.release_name()

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

    empathy_bus.flush()
    empathy_bus.close()

    # In response, the channels that were being handled by Empathy are closed.
    # Kopete's channel is *not* closed.
    q.expect_many(
            EventPattern('dbus-signal',
                signal='NameOwnerChanged',
                predicate=(lambda e:
                    e.args[0] == empathy_unique_name and e.args[2] == '')),
            EventPattern('dbus-method-call',
                path=chan.object_path, method='Close'),
            EventPattern('dbus-method-call',
                path=claimed_chan.object_path, method='Close'),
            )

    sync_dbus(bus, q, mc)
    q.unforbid_events(forbidden)
예제 #49
0
def test(q, bus, mc):
    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******"
        },
        signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

    text_fixed_properties = dbus.Dictionary(
        {
            cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
            cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
        },
        signature='sv')

    # Logger is a text observer wanting recovery
    logger = SimulatedClient(q,
                             bus,
                             'LoggerChat',
                             observe=[text_fixed_properties],
                             bypass_approval=False,
                             wants_recovery=True)

    # gnome-shell is a text approver and handler
    gs = SimulatedClient(q,
                         bus,
                         'GnomeShell',
                         approve=[text_fixed_properties],
                         handle=[text_fixed_properties],
                         bypass_approval=False)

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

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

    # incoming text channel
    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()

    # gnome-shell's approver and logger's observer are notified
    e, k = q.expect_many(
        EventPattern('dbus-method-call',
                     path=logger.object_path,
                     interface=cs.OBSERVER,
                     method='ObserveChannels',
                     handled=False),
        EventPattern('dbus-method-call',
                     path=gs.object_path,
                     interface=cs.APPROVER,
                     method='AddDispatchOperation',
                     handled=False),
    )

    channels, cdo_path, props = k.args

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

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

    # gnome-shell claims the channel
    call_async(q, cdo_iface, 'Claim')
    e = q.expect('dbus-return', method='Claim')

    # Logger crash
    logger.release_name()

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

    bus.flush()

    # Logger gets restarted
    logger.reacquire_name()

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

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

    # gnome-shell which is handling the channel asks to re-ensure it
    cd_iface = dbus.Interface(cd, cs.CD)
    call_async(q, cd_iface, 'PresentChannel', chan.object_path, 0)

    # gnome-shell is asked to re-handle the channel
    e = q.expect('dbus-method-call',
                 path=gs.object_path,
                 interface=cs.HANDLER,
                 method='HandleChannels',
                 handled=False)

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

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

    chan.close()
예제 #50
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, mc):
    params = dbus.Dictionary(
        {
            "account": "*****@*****.**",
            "password": "******"
        },
        signature='sv')
    simulated_cm, account = create_fakecm_account(q, bus, mc, params)
    conn = enable_fakecm_account(q, bus, mc, account, params)

    # One client (Kopete) has less specific filters than the other (Empathy),
    # to make sure that the dispatcher would normally prefer Empathy; this
    # means that when we use Kopete as the preferred handler, we know that
    # if Kopete is invoked, then preferring the preferred handler correctly
    # took precedence over the normal logic.
    vague_fixed_properties = dbus.Dictionary(
        {
            cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_TEXT,
        }, signature='sv')
    text_fixed_properties = dbus.Dictionary(
        {
            cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT,
            cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_TEXT,
        },
        signature='sv')

    empathy_bus = dbus.bus.BusConnection()
    kopete_bus = dbus.bus.BusConnection()
    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=[vague_fixed_properties],
                             approve=[vague_fixed_properties],
                             handle=[vague_fixed_properties],
                             bypass_approval=False)

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

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

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

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

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

    # A channel dispatch operation is created

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

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

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

    handlers = cdo_properties[cs.CDO + '.PossibleHandlers'][:]
    # Empathy has a more specific filter, so it comes first
    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)
    cdo_props_iface = dbus.Interface(cdo, cs.PROPERTIES_IFACE)

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

    # 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, bus=empathy_bus, signature='')
    q.dbus_return(e.message, bus=kopete_bus, 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, bus=empathy_bus, signature='')
    q.dbus_return(k.message, bus=kopete_bus, signature='')

    # Both Approvers now have a flashing icon or something, trying to get the
    # user's attention. However, the user is busy looking through the address
    # book, and independently decides to talk to Juliet. The address book
    # is from KDE so wants Kopete to be used.

    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,
               'EnsureChannel',
               account.object_path,
               request,
               user_action_time,
               kopete.bus_name,
               dbus_interface=cs.CD)
    ret, add_request_call = q.expect_many(
        EventPattern('dbus-return', method='EnsureChannel'),
        EventPattern('dbus-method-call',
                     handled=False,
                     interface=cs.CLIENT_IFACE_REQUESTS,
                     method='AddRequest',
                     path=kopete.object_path),
    )
    request_path = ret.value[0]

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

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

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

    cr.Proceed(dbus_interface=cs.CR)

    cm_request_call = q.expect('dbus-method-call',
                               interface=cs.CONN_IFACE_REQUESTS,
                               method='EnsureChannel',
                               path=conn.object_path,
                               args=[request],
                               handled=False)

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

    # Time passes. The CM returns the existing channel

    q.dbus_return(cm_request_call.message,
                  False,
                  chan.object_path,
                  chan.immutable,
                  signature='boa{sv}')

    # EnsureChannel constitutes approval, so Kopete is told to handle the
    # channel

    e = q.expect('dbus-method-call',
                 path=kopete.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] == chan.object_path, channels
    assert channels[0][1] == chan.immutable, channels
    assert e.args[3] == [request_path], e.args
    assert e.args[4] == user_action_time, (e.args[4], user_action_time)
    assert isinstance(e.args[5], dict)
    assert len(e.args) == 6

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

    q.expect_many(
        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') == []