def test_ensure(q, bus, account, conn, chan, expected_handler_path): """Tests that a client Ensure-ing the channel causes HandleChannels to be called on the current handler. (Previously, DelegateChannels() and PresentChannel() both broke this.)""" cd = ChannelDispatcher(bus) call_async(q, cd, 'EnsureChannel', account.object_path, REQUEST, 0, '') e = q.expect('dbus-return', method='EnsureChannel') cr = ChannelRequest(bus, e.value[0]) cr.Proceed() e = q.expect('dbus-method-call', interface=cs.CONN_IFACE_REQUESTS, method='EnsureChannel', path=conn.object_path, args=[REQUEST], handled=False) q.dbus_return(e.message, False, chan.object_path, chan.immutable, signature='boa{sv}') e = q.expect('dbus-method-call', interface=cs.HANDLER, method='HandleChannels', handled=False) assertEquals(expected_handler_path, e.path) 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') 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_channel_creation(q, bus, account, client, conn, ensure): user_action_time = dbus.Int64(1238582606) # chat UI calls ChannelDispatcher.EnsureChannel or 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') if ensure: method = cd.EnsureChannel else: method = cd.CreateChannel request_path = method(account.object_path, request, user_action_time, client.bus_name) 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 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 request_props = add_request.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'] == client.bus_name q.dbus_return(add_request.message, signature='') # 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=(ensure and 'EnsureChannel' or 'CreateChannel'), path=conn.object_path, args=[request], handled=False) # Time passes. A channel is returned. channel_immutable = dbus.Dictionary(request) channel_immutable[cs.CHANNEL + '.InitiatorID'] = conn.self_ident channel_immutable[cs.CHANNEL + '.InitiatorHandle'] = conn.self_handle channel_immutable[cs.CHANNEL + '.Requested'] = True channel_immutable[cs.CHANNEL + '.Interfaces'] = \ dbus.Array([], signature='s') channel_immutable[cs.CHANNEL + '.TargetHandle'] = \ conn.ensure_handle(cs.HT_CONTACT, 'juliet') channel = SimulatedChannel(conn, channel_immutable) # this order of events is guaranteed by telepathy-spec (since 0.17.14) if ensure: q.dbus_return(cm_request_call.message, True, # <- Yours channel.object_path, channel.immutable, signature='boa{sv}') else: # Create q.dbus_return(cm_request_call.message, channel.object_path, channel.immutable, signature='oa{sv}') channel.announce() # Observer should get told, processing waits for it e = q.expect('dbus-method-call', path=client.object_path, interface=cs.OBSERVER, method='ObserveChannels', handled=False) assert e.args[0] == account.object_path, e.args assert e.args[1] == conn.object_path, e.args assert e.args[3] == '/', e.args # no dispatch operation assert e.args[4] == [request_path], e.args channels = e.args[2] assert len(channels) == 1, channels assert channels[0][0] == channel.object_path, channels assert channels[0][1] == channel_immutable, channels # Observer says "OK, go" q.dbus_return(e.message, signature='') # Handler is next 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 # Handler accepts the Channels q.dbus_return(e.message, signature='') # CR emits Succeeded q.expect('dbus-signal', path=request_path, interface=cs.CR, signal='Succeeded') # Close the channel channel.close()
def test_channel_creation(q, bus, account, client, conn, ensure=False, prefer=None, channel_type=cs.CHANNEL_TYPE_TEXT): user_action_time = dbus.Int64(1238582606) hints = dbus.Dictionary({'badger': 42, 'snake': 'pony'}, signature='sv') if prefer is None: prefer = client cd = ChannelDispatcher(bus) assert cd.Properties.Get(cs.CD, "SupportsRequestHints") # chat UI calls ChannelDispatcher.EnsureChannelWithHints or # CreateChannelWithHints request = dbus.Dictionary( { cs.CHANNEL + '.ChannelType': channel_type, cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT, cs.CHANNEL + '.TargetID': 'juliet', }, signature='sv') call_async( q, cd, (ensure and 'EnsureChannelWithHints' or 'CreateChannelWithHints'), account.object_path, request, user_action_time, prefer.bus_name, hints, dbus_interface=cs.CD) ret = q.expect('dbus-return', method=(ensure and 'EnsureChannelWithHints' or 'CreateChannelWithHints')) request_path = ret.value[0] # chat UI connects to signals and calls ChannelRequest.Proceed() cr = bus.get_object(cs.AM, request_path) request_props = cr.GetAll(cs.CR, dbus_interface=cs.PROPERTIES_IFACE) assert request_props['Account'] == account.object_path assert request_props['Requests'] == [request] assert request_props['UserActionTime'] == user_action_time assert request_props['PreferredHandler'] == prefer.bus_name assert request_props['Interfaces'] == [] assertEquals(hints, request_props['Hints']) cr.Proceed(dbus_interface=cs.CR) # FIXME: should the EnsureChannel/CreateChannel call, and the AddRequest # call, be in a defined order? Probably not though, since CMs and Clients # aren't meant to be the same process! cm_request_call, add_request_call = q.expect_many( EventPattern('dbus-method-call', interface=cs.CONN_IFACE_REQUESTS, method=(ensure and 'EnsureChannel' or 'CreateChannel'), path=conn.object_path, args=[request], handled=False), EventPattern('dbus-method-call', handled=False, interface=cs.CLIENT_IFACE_REQUESTS, method='AddRequest'), ) assert add_request_call.args[0] == request_path assert add_request_call.path == prefer.object_path request_props = add_request_call.args[1] assert request_props[cs.CR + '.Account'] == account.object_path assert request_props[cs.CR + '.Requests'] == [request] assert request_props[cs.CR + '.UserActionTime'] == user_action_time assert request_props[cs.CR + '.PreferredHandler'] == prefer.bus_name assert request_props[cs.CR + '.Interfaces'] == [] q.dbus_return(add_request_call.message, signature='') # Time passes. A channel is returned. channel_immutable = dbus.Dictionary(request) channel_immutable[cs.CHANNEL + '.InitiatorID'] = conn.self_ident channel_immutable[cs.CHANNEL + '.InitiatorHandle'] = conn.self_handle channel_immutable[cs.CHANNEL + '.Requested'] = True channel_immutable[cs.CHANNEL + '.Interfaces'] = \ dbus.Array([], signature='s') channel_immutable[cs.CHANNEL + '.TargetHandle'] = \ conn.ensure_handle(cs.HT_CONTACT, 'juliet') channel = SimulatedChannel(conn, channel_immutable) # this order of events is guaranteed by telepathy-spec (since 0.17.14) if ensure: q.dbus_return( cm_request_call.message, True, # <- Yours channel.object_path, channel.immutable, signature='boa{sv}') else: # Create q.dbus_return(cm_request_call.message, channel.object_path, channel.immutable, signature='oa{sv}') channel.announce() if channel_type == cs.CHANNEL_TYPE_TEXT: # Observer should get told, processing waits for it e = q.expect('dbus-method-call', path=client.object_path, interface=cs.OBSERVER, method='ObserveChannels', handled=False) assert e.args[0] == account.object_path, e.args assert e.args[1] == conn.object_path, e.args assert e.args[3] == '/', e.args # no dispatch operation assert e.args[4] == [request_path], e.args channels = e.args[2] assert len(channels) == 1, channels assert channels[0][0] == channel.object_path, channels assert channels[0][1] == channel_immutable, channels info = e.args[5] assert info['request-properties'] == { request_path: request_props }, info # Observer says "OK, go" q.dbus_return(e.message, signature='') # Handler is next e = q.expect('dbus-method-call', path=prefer.object_path, interface=cs.HANDLER, method='HandleChannels', handled=False) assert e.args[0] == account.object_path, e.args assert e.args[1] == conn.object_path, e.args channels = e.args[2] assert len(channels) == 1, channels assert channels[0][0] == channel.object_path, channels assert channels[0][1] == channel_immutable, channels assert e.args[3] == [request_path], e.args assert e.args[4] == user_action_time assert isinstance(e.args[5], dict) assert len(e.args) == 6 # Handler accepts the Channels q.dbus_return(e.message, signature='') # SucceededWithChannel is fired first e = q.expect('dbus-signal', path=request_path, interface=cs.CR, signal='SucceededWithChannel') assertEquals(conn.object_path, e.args[0]) assert isinstance(e.args[1], dict), e.args[1] assertEquals(channel.object_path, e.args[2]) assertEquals(channel_immutable, e.args[3]) # CR emits Succeeded q.expect('dbus-signal', path=request_path, interface=cs.CR, signal='Succeeded') # Close the channel channel.close()
def test_delegate_channel(q, bus, mc, account, conn, chan, empathy, empathy_bus, gs): # Test that re-Ensure-ing works before we start Delegating and Presenting. test_ensure(q, bus, account, conn, chan, gs.object_path) # Now gnome-shell wants to give the channel to another handler gs_cd = ChannelDispatcher(bus) call_async(q, gs_cd, 'DelegateChannels', [chan.object_path], 0, "") # Empathy is asked to handle the channel and accept e = q.expect('dbus-method-call', path=empathy.object_path, interface=cs.HANDLER, method='HandleChannels', handled=False) q.dbus_return(e.message, signature='') e = q.expect('dbus-return', method='DelegateChannels') assertEquals(([chan.object_path], {}), e.value) # Test that re-Ensure-ing the channel still works, and sends it to # the right place. test_ensure(q, bus, account, conn, chan, empathy.object_path) # Let's play ping-pong with the channel! Empathy gives the channel # back to GS emp_cd = ChannelDispatcher(empathy_bus) call_async(q, emp_cd, 'DelegateChannels', [chan.object_path], 0, "") # gnome-shell is asked to handle the channel and accept e = q.expect('dbus-method-call', path=gs.object_path, interface=cs.HANDLER, method='HandleChannels', handled=False) q.dbus_return(e.message, signature='') e = q.expect('dbus-return', method='DelegateChannels') assertEquals(([chan.object_path], {}), e.value) # Test that re-Ensure-ing the channel sttill works, and sends it # to the right place. test_ensure(q, bus, account, conn, chan, gs.object_path) # gnome-shell wants to give it back, again call_async(q, gs_cd, 'DelegateChannels', [chan.object_path], 0, "") # Empathy is asked to handle the channel but refuses e = q.expect('dbus-method-call', path=empathy.object_path, interface=cs.HANDLER, method='HandleChannels', handled=False) q.dbus_raise(e.message, cs.NOT_AVAILABLE, "No thanks") # DelegateChannels failed so gnome-shell is still handling the channel e = q.expect('dbus-return', method='DelegateChannels') assertEquals(([], {chan.object_path: (cs.NOT_AVAILABLE, 'No thanks')}), e.value) # Test that re-Ensure-ing the channel sttill works, and sends it # to the right place. test_ensure(q, bus, account, conn, chan, gs.object_path) # Empathy doesn't handle the channel atm but tries to delegates it call_async(q, emp_cd, 'DelegateChannels', [chan.object_path], 0, "") q.expect('dbus-error', method='DelegateChannels', name=cs.NOT_YOURS) # gnome-shell which is handling the channel asks to re-ensure it call_async(q, gs_cd, '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') # empathy which is not handling the channel asks to re-ensure it call_async(q, emp_cd, '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') # Test that re-Ensure-ing the channel *still* works, and sends it # to the right place. test_ensure(q, bus, account, conn, chan, gs.object_path) # 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] == ''), ) # gnome-shell wants to delegate, but there is no other handler call_async(q, gs_cd, 'DelegateChannels', [chan.object_path], 0, "") e = q.expect('dbus-return', method='DelegateChannels') delegated, not_delegated = e.value assertEquals([], delegated) error = not_delegated[chan.object_path] assertEquals (error[0], cs.NOT_CAPABLE) 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.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_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)