def test(q, bus, unused, **kwargs): simulated_cm = SimulatedConnectionManager(q, bus) fake_accounts_service = kwargs['fake_accounts_service'] accounts = preseed(q, bus, fake_accounts_service) mc = MC(q, bus) for account in accounts: account.test(q, bus, mc)
def test(q, bus, unused, **kwargs): fake_accounts_service = kwargs['fake_accounts_service'] preseed(q, bus, fake_accounts_service) text_fixed_properties = dbus.Dictionary( { cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT, cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_TEXT, }, signature='sv') user_action_time = dbus.Int64(1238582606) # A client and a CM are already running client = SimulatedClient(q, bus, 'Empathy', observe=[text_fixed_properties], approve=[text_fixed_properties], handle=[text_fixed_properties], bypass_approval=False, implement_get_interfaces=False) simulated_cm = SimulatedConnectionManager(q, bus) # service-activate MC; it will try to introspect the running client. mc = MC(q, bus, wait_for_names=False) get_interfaces, = mc.wait_for_names( EventPattern('dbus-method-call', path=client.object_path, interface=cs.PROPERTIES_IFACE, method='Get', args=[cs.CLIENT, 'Interfaces'], handled=False)) # The client doesn't reply just yet; meanwhile, immediately make a channel # request account = bus.get_object( cs.MC, cs.tp_path_prefix + '/Account/fakecm/fakeprotocol/jc_2edenton_40unatco_2eint') cd = bus.get_object(cs.MC, cs.CD_PATH) cd_props = dbus.Interface(cd, cs.PROPERTIES_IFACE) request = dbus.Dictionary( { cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_TEXT, cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT, cs.CHANNEL + '.TargetID': '*****@*****.**', }, signature='sv') call_async(q, cd, 'CreateChannel', account.object_path, request, user_action_time, client.bus_name, dbus_interface=cs.CD) ret = q.expect('dbus-return', method='CreateChannel') request_path = ret.value[0] # chat UI connects to signals and calls ChannelRequest.Proceed() cr = bus.get_object(cs.MC, request_path) request_props = cr.GetAll(cs.CR, dbus_interface=cs.PROPERTIES_IFACE) assert request_props['Account'] == account.object_path assert request_props['Requests'] == [request] assert request_props['UserActionTime'] == user_action_time assert request_props['PreferredHandler'] == client.bus_name assert request_props['Interfaces'] == [] call_async(q, cr, 'Proceed', dbus_interface=cs.CR) e = q.expect('dbus-method-call', method='RequestConnection', args=[ 'fakeprotocol', { 'account': '*****@*****.**', 'password': '******', } ], destination=cs.tp_name_prefix + '.ConnectionManager.fakecm', path=cs.tp_path_prefix + '/ConnectionManager/fakecm', interface=cs.tp_name_prefix + '.ConnectionManager', handled=False) conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', 'the_conn', '*****@*****.**') q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so') q.expect('dbus-method-call', method='Connect', path=conn.object_path, handled=True) conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CSR_NONE_SPECIFIED) # A channel appears spontaneously announcement_immutable = dbus.Dictionary(text_fixed_properties) announcement_immutable[cs.CHANNEL + '.TargetID'] = '*****@*****.**' announcement_immutable[cs.CHANNEL + '.TargetHandle'] = \ conn.ensure_handle(cs.HT_CONTACT, '*****@*****.**') announcement_immutable[cs.CHANNEL + '.InitiatorHandle'] = \ announcement_immutable[cs.CHANNEL + '.TargetHandle'] announcement_immutable[cs.CHANNEL + '.InitiatorID'] = \ announcement_immutable[cs.CHANNEL + '.TargetID'] announcement_immutable[cs.CHANNEL + '.Interfaces'] = \ dbus.Array([], signature='s') announcement_immutable[cs.CHANNEL + '.Requested'] = False announcement = SimulatedChannel(conn, announcement_immutable) announcement.announce() # Now the Client returns its info q.dbus_return( get_interfaces.message, dbus.Array( [cs.HANDLER, cs.OBSERVER, cs.APPROVER, cs.CLIENT_IFACE_REQUESTS], signature='s'), signature='v') expect_client_setup(q, [client], got_interfaces_already=True) # Now that the dispatcher is ready to go, we start looking for channels, # and also make the actual request # Empathy observes the channel we originally requested. _, a, cm_request_call = q.expect_many( EventPattern('dbus-method-call', interface=cs.PROPERTIES_IFACE, method='GetAll', args=[cs.CONN_IFACE_REQUESTS], path=conn.object_path, handled=True), EventPattern('dbus-method-call', path=client.object_path, interface=cs.OBSERVER, method='ObserveChannels', handled=False), EventPattern('dbus-method-call', interface=cs.CONN_IFACE_REQUESTS, method='CreateChannel', path=conn.object_path, args=[request], handled=False), ) assert a.args[0] == account.object_path, a.args assert a.args[1] == conn.object_path, a.args assert a.args[3] != '/', a.args # there is a dispatch operation assert a.args[4] == [], a.args channels = a.args[2] assert len(channels) == 1, channels assert channels[0][0] == announcement.object_path, channels assert channels[0][1] == announcement_immutable, channels # Time passes. A channel is returned. channel_immutable = dbus.Dictionary(request) channel_immutable[cs.CHANNEL + '.InitiatorID'] = conn.self_ident channel_immutable[cs.CHANNEL + '.InitiatorHandle'] = conn.self_handle channel_immutable[cs.CHANNEL + '.Requested'] = True channel_immutable[cs.CHANNEL + '.Interfaces'] = \ dbus.Array([], signature='s') channel_immutable[cs.CHANNEL + '.TargetHandle'] = \ conn.ensure_handle(cs.HT_CONTACT, '*****@*****.**') channel = SimulatedChannel(conn, channel_immutable) q.dbus_return(cm_request_call.message, channel.object_path, channel.immutable, signature='oa{sv}') channel.announce() # Empathy observes the newly-created channel. e = q.expect('dbus-method-call', path=client.object_path, interface=cs.OBSERVER, method='ObserveChannels', handled=False) assert e.args[0] == account.object_path, e.args assert e.args[1] == conn.object_path, e.args assert e.args[3] == '/', e.args # no dispatch operation assert e.args[4] == [request_path], e.args channels = e.args[2] assert len(channels) == 1, channels assert channels[0][0] == channel.object_path, channels assert channels[0][1] == channel_immutable, channels # Observer says "OK, go" q.dbus_return(a.message, signature='') q.dbus_return(e.message, signature='') # Empathy is asked to handle the channel e = q.expect('dbus-method-call', path=client.object_path, interface=cs.HANDLER, method='HandleChannels', handled=False) assert e.args[0] == account.object_path, e.args assert e.args[1] == conn.object_path, e.args channels = e.args[2] assert len(channels) == 1, channels assert channels[0][0] == channel.object_path, channels assert channels[0][1] == channel_immutable, channels assert e.args[3] == [request_path], e.args assert e.args[4] == user_action_time assert isinstance(e.args[5], dict) assert len(e.args) == 6
def test(q, bus, unused, **kwargs): fake_accounts_service = kwargs['fake_accounts_service'] preseed(q, bus, fake_accounts_service) text_fixed_properties = dbus.Dictionary({ cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT, cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_TEXT, }, signature='sv') user_action_time = dbus.Int64(1238582606) # A client and a CM are already running client = SimulatedClient(q, bus, 'Empathy', observe=[text_fixed_properties], approve=[text_fixed_properties], handle=[text_fixed_properties], bypass_approval=False, implement_get_interfaces=False) simulated_cm = SimulatedConnectionManager(q, bus) # service-activate MC; it will try to introspect the running client. mc = MC(q, bus, wait_for_names=False) get_interfaces, = mc.wait_for_names( EventPattern('dbus-method-call', path=client.object_path, interface=cs.PROPERTIES_IFACE, method='Get', args=[cs.CLIENT, 'Interfaces'], handled=False)) # The client doesn't reply just yet; meanwhile, immediately make a channel # request account = bus.get_object(cs.MC, cs.tp_path_prefix + '/Account/fakecm/fakeprotocol/jc_2edenton_40unatco_2eint') cd = bus.get_object(cs.MC, cs.CD_PATH) cd_props = dbus.Interface(cd, cs.PROPERTIES_IFACE) request = dbus.Dictionary({ cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_TEXT, cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT, cs.CHANNEL + '.TargetID': '*****@*****.**', }, signature='sv') call_async(q, cd, 'CreateChannel', account.object_path, request, user_action_time, client.bus_name, dbus_interface=cs.CD) ret = q.expect('dbus-return', method='CreateChannel') request_path = ret.value[0] # chat UI connects to signals and calls ChannelRequest.Proceed() cr = bus.get_object(cs.MC, request_path) request_props = cr.GetAll(cs.CR, dbus_interface=cs.PROPERTIES_IFACE) assert request_props['Account'] == account.object_path assert request_props['Requests'] == [request] assert request_props['UserActionTime'] == user_action_time assert request_props['PreferredHandler'] == client.bus_name assert request_props['Interfaces'] == [] call_async(q, cr, 'Proceed', dbus_interface=cs.CR) e = q.expect('dbus-method-call', method='RequestConnection', args=['fakeprotocol', { 'account': '*****@*****.**', 'password': '******', }], destination=cs.tp_name_prefix + '.ConnectionManager.fakecm', path=cs.tp_path_prefix + '/ConnectionManager/fakecm', interface=cs.tp_name_prefix + '.ConnectionManager', handled=False) conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', 'the_conn', '*****@*****.**') q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so') q.expect('dbus-method-call', method='Connect', path=conn.object_path, handled=True) conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CSR_NONE_SPECIFIED) # A channel appears spontaneously announcement_immutable = dbus.Dictionary(text_fixed_properties) announcement_immutable[cs.CHANNEL + '.TargetID'] = '*****@*****.**' announcement_immutable[cs.CHANNEL + '.TargetHandle'] = \ conn.ensure_handle(cs.HT_CONTACT, '*****@*****.**') announcement_immutable[cs.CHANNEL + '.InitiatorHandle'] = \ announcement_immutable[cs.CHANNEL + '.TargetHandle'] announcement_immutable[cs.CHANNEL + '.InitiatorID'] = \ announcement_immutable[cs.CHANNEL + '.TargetID'] announcement_immutable[cs.CHANNEL + '.Interfaces'] = \ dbus.Array([], signature='s') announcement_immutable[cs.CHANNEL + '.Requested'] = False announcement = SimulatedChannel(conn, announcement_immutable) announcement.announce() # Now the Client returns its info q.dbus_return(get_interfaces.message, dbus.Array([cs.HANDLER, cs.OBSERVER, cs.APPROVER, cs.CLIENT_IFACE_REQUESTS], signature='s'), signature='v') expect_client_setup(q, [client], got_interfaces_already=True) # Now that the dispatcher is ready to go, we start looking for channels, # and also make the actual request # Empathy observes the channel we originally requested. _, a, cm_request_call = q.expect_many( EventPattern('dbus-method-call', interface=cs.PROPERTIES_IFACE, method='GetAll', args=[cs.CONN_IFACE_REQUESTS], path=conn.object_path, handled=True), EventPattern('dbus-method-call', path=client.object_path, interface=cs.OBSERVER, method='ObserveChannels', handled=False), EventPattern('dbus-method-call', interface=cs.CONN_IFACE_REQUESTS, method='CreateChannel', path=conn.object_path, args=[request], handled=False), ) assert a.args[0] == account.object_path, a.args assert a.args[1] == conn.object_path, a.args assert a.args[3] != '/', a.args # there is a dispatch operation assert a.args[4] == [], a.args channels = a.args[2] assert len(channels) == 1, channels assert channels[0][0] == announcement.object_path, channels assert channels[0][1] == announcement_immutable, channels # Time passes. A channel is returned. channel_immutable = dbus.Dictionary(request) channel_immutable[cs.CHANNEL + '.InitiatorID'] = conn.self_ident channel_immutable[cs.CHANNEL + '.InitiatorHandle'] = conn.self_handle channel_immutable[cs.CHANNEL + '.Requested'] = True channel_immutable[cs.CHANNEL + '.Interfaces'] = \ dbus.Array([], signature='s') channel_immutable[cs.CHANNEL + '.TargetHandle'] = \ conn.ensure_handle(cs.HT_CONTACT, '*****@*****.**') channel = SimulatedChannel(conn, channel_immutable) q.dbus_return(cm_request_call.message, channel.object_path, channel.immutable, signature='oa{sv}') channel.announce() # Empathy observes the newly-created channel. e = q.expect('dbus-method-call', path=client.object_path, interface=cs.OBSERVER, method='ObserveChannels', handled=False) assert e.args[0] == account.object_path, e.args assert e.args[1] == conn.object_path, e.args assert e.args[3] == '/', e.args # no dispatch operation assert e.args[4] == [request_path], e.args channels = e.args[2] assert len(channels) == 1, channels assert channels[0][0] == channel.object_path, channels assert channels[0][1] == channel_immutable, channels # Observer says "OK, go" q.dbus_return(a.message, signature='') q.dbus_return(e.message, signature='') # Empathy is asked to handle the channel e = q.expect('dbus-method-call', path=client.object_path, interface=cs.HANDLER, method='HandleChannels', handled=False) assert e.args[0] == account.object_path, e.args assert e.args[1] == conn.object_path, e.args channels = e.args[2] assert len(channels) == 1, channels assert channels[0][0] == channel.object_path, channels assert channels[0][1] == channel_immutable, channels assert e.args[3] == [request_path], e.args assert e.args[4] == user_action_time assert isinstance(e.args[5], dict) assert len(e.args) == 6
def test(q, bus, unused, **kwargs): simulated_cm = SimulatedConnectionManager(q, bus) # make sure RequestConnection doesn't get called yet events = [EventPattern('dbus-method-call', method='RequestConnection')] q.forbid_events(events) fake_accounts_service = kwargs['fake_accounts_service'] preseed(q, bus, fake_accounts_service) # Wait for MC to load mc = MC(q, bus) # Trying to make a channel on account 1 doesn't work, because it's # not valid account_path = (cs.tp_path_prefix + '/Account/' + account1_id) cd = bus.get_object(cs.CD, cs.CD_PATH) user_action_time = dbus.Int64(1238582606) request = dbus.Dictionary( { cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_TEXT, cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT, cs.CHANNEL + '.TargetID': 'juliet', }, signature='sv') call_async(q, cd, 'CreateChannel', account_path, request, user_action_time, "", dbus_interface=cs.CD) ret = q.expect('dbus-return', method='CreateChannel') request_path = ret.value[0] cr = bus.get_object(cs.CD, request_path) request_props = cr.GetAll(cs.CR, dbus_interface=cs.PROPERTIES_IFACE) assert request_props['Account'] == account_path assert request_props['Requests'] == [request] assert request_props['UserActionTime'] == user_action_time assert request_props['PreferredHandler'] == "" assert request_props['Interfaces'] == [] sync_dbus(bus, q, mc) cr.Proceed(dbus_interface=cs.CR) # FIXME: error isn't specified (NotAvailable perhaps?) q.expect('dbus-signal', path=cr.object_path, interface=cs.CR, signal='Failed') # Make account 1 valid: it should connect automatically account_path = (cs.tp_path_prefix + '/Account/' + account1_id) account = bus.get_object(cs.MC, account_path) sync_dbus(bus, q, mc) q.unforbid_events(events) call_async(q, account, 'UpdateParameters', {'password': '******'}, [], dbus_interface=cs.ACCOUNT) expected_params = { 'password': '******', 'account': '*****@*****.**' } e = q.expect('dbus-method-call', method='RequestConnection', args=['fakeprotocol', expected_params], destination=cs.tp_name_prefix + '.ConnectionManager.fakecm', path=cs.tp_path_prefix + '/ConnectionManager/fakecm', interface=cs.tp_name_prefix + '.ConnectionManager', handled=False) conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', 'account1', 'myself', has_presence=True) q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so') q.expect('dbus-method-call', method='Connect', path=conn.object_path, handled=True, interface=cs.CONN) conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CSR_NONE_SPECIFIED) set_presence, e = q.expect_many( EventPattern('dbus-method-call', path=conn.object_path, interface=cs.CONN_IFACE_SIMPLE_PRESENCE, method='SetPresence', handled=True), EventPattern('dbus-signal', signal='AccountPropertyChanged', path=account_path, interface=cs.ACCOUNT, predicate=lambda e: 'CurrentPresence' in e.args[0] and e. args[0]['CurrentPresence'][2] != ''), ) assert e.args[0]['CurrentPresence'] == (cs.PRESENCE_AVAILABLE, 'available', 'My vision is augmented') # Request an online presence on account 2, then make it valid q.forbid_events(events) account_path = (cs.tp_path_prefix + '/Account/' + account2_id) account = bus.get_object(cs.MC, account_path) requested_presence = dbus.Struct( (dbus.UInt32(cs.PRESENCE_BUSY), 'busy', 'Talking to Illuminati')) account.Set(cs.ACCOUNT, 'RequestedPresence', dbus.Struct(requested_presence, variant_level=1), dbus_interface=cs.PROPERTIES_IFACE) sync_dbus(bus, q, mc) q.unforbid_events(events) # Make the account valid call_async(q, account, 'UpdateParameters', {'password': '******'}, [], dbus_interface=cs.ACCOUNT) expected_params = { 'password': '******', 'account': '*****@*****.**' } e = q.expect('dbus-method-call', method='RequestConnection', args=['fakeprotocol', expected_params], destination=cs.tp_name_prefix + '.ConnectionManager.fakecm', path=cs.tp_path_prefix + '/ConnectionManager/fakecm', interface=cs.tp_name_prefix + '.ConnectionManager', handled=False) conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', 'account2', 'myself', has_presence=True) q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so') q.expect('dbus-method-call', method='Connect', path=conn.object_path, handled=True, interface=cs.CONN) conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CSR_NONE_SPECIFIED) set_presence = q.expect('dbus-method-call', path=conn.object_path, interface=cs.CONN_IFACE_SIMPLE_PRESENCE, method='SetPresence', handled=True) e = q.expect('dbus-signal', signal='AccountPropertyChanged', path=account_path, interface=cs.ACCOUNT, predicate=lambda e: 'CurrentPresence' in e.args[0] and e.args[ 0]['CurrentPresence'][1] == 'busy') assert e.args[0]['CurrentPresence'] == (cs.PRESENCE_BUSY, 'busy', 'Talking to Illuminati')
def test(q, bus, unused, **kwargs): fake_accounts_service = kwargs['fake_accounts_service'] preseed(q, bus, fake_accounts_service) text_fixed_properties = dbus.Dictionary( { cs.CHANNEL + '.TargetHandleType': cs.HT_CONTACT, cs.CHANNEL + '.ChannelType': cs.CHANNEL_TYPE_TEXT, }, signature='sv') conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', 'jc', '*****@*****.**') conn.StatusChanged(cs.CONN_STATUS_CONNECTED, 0) unhandled_properties = dbus.Dictionary(text_fixed_properties, signature='sv') unhandled_properties[cs.CHANNEL + '.Interfaces'] = dbus.Array(signature='s') unhandled_properties[cs.CHANNEL + '.TargetID'] = '*****@*****.**' unhandled_properties[cs.CHANNEL + '.TargetHandle'] = \ dbus.UInt32(conn.ensure_handle(cs.HT_CONTACT, '*****@*****.**')) unhandled_properties[cs.CHANNEL + '.InitiatorHandle'] = dbus.UInt32( conn.self_handle) unhandled_properties[cs.CHANNEL + '.InitiatorID'] = conn.self_ident unhandled_properties[cs.CHANNEL + '.Requested'] = True unhandled_chan = SimulatedChannel(conn, unhandled_properties) unhandled_chan.announce() handled_properties = dbus.Dictionary(text_fixed_properties, signature='sv') handled_properties[cs.CHANNEL + '.Interfaces'] = dbus.Array(signature='s') handled_properties[cs.CHANNEL + '.TargetID'] = '*****@*****.**' handled_properties[cs.CHANNEL + '.TargetHandle'] = \ dbus.UInt32(conn.ensure_handle(cs.HT_CONTACT, '*****@*****.**')) handled_properties[cs.CHANNEL + '.InitiatorHandle'] = dbus.UInt32( conn.self_handle) handled_properties[cs.CHANNEL + '.InitiatorID'] = conn.self_ident handled_properties[cs.CHANNEL + '.Requested'] = True handled_chan = SimulatedChannel(conn, handled_properties) handled_chan.announce() client = SimulatedClient(q, bus, 'Empathy', observe=[text_fixed_properties], approve=[text_fixed_properties], handle=[text_fixed_properties], bypass_approval=False) client.handled_channels.append(handled_chan.object_path) # Service-activate MC. # We're told about the other channel as an observer... mc = MC(q, bus, wait_for_names=False) e, = mc.wait_for_names( EventPattern('dbus-method-call', path=client.object_path, interface=cs.OBSERVER, method='ObserveChannels', handled=False), ) assert e.args[1] == conn.object_path, e.args channels = e.args[2] assert channels[0][0] == unhandled_chan.object_path, channels q.dbus_return(e.message, signature='') # ... and as a handler e = q.expect('dbus-method-call', path=client.object_path, interface=cs.HANDLER, method='HandleChannels', handled=False) assert e.args[1] == conn.object_path, e.args channels = e.args[2] assert channels[0][0] == unhandled_chan.object_path, channels q.dbus_return(e.message, signature='')
def test(q, bus, unused, **kwargs): simulated_cm = SimulatedConnectionManager(q, bus) fake_accounts_service = kwargs['fake_accounts_service'] preseed(q, bus, fake_accounts_service) expected_params = { 'account': '*****@*****.**', 'password': r'\\ionstorm\\', } mc = MC(q, bus, wait_for_names=False) mc.wait_for_names( # Migration step: the three separate attributes get combined # (before the names are taken, so we need to expect it here) EventPattern( 'dbus-method-call', interface=cs.TEST_DBUS_ACCOUNT_SERVICE_IFACE, method='UpdateAttributes', predicate=( lambda e: e.args[0] == account_id and e.args[1] == { 'AutomaticPresence': (2, 'available', 'My vision is augmented') } and e.args[2] == { 'AutomaticPresence': 0 } and # flags set(e.args[3]) == set([ # no particular order 'AutomaticPresenceType', 'AutomaticPresenceStatus', 'AutomaticPresenceMessage', ])))) request_conn, prop_changed = q.expect_many( EventPattern('dbus-method-call', method='RequestConnection', args=['fakeprotocol', expected_params], destination=cs.tp_name_prefix + '.ConnectionManager.fakecm', path=cs.tp_path_prefix + '/ConnectionManager/fakecm', interface=cs.tp_name_prefix + '.ConnectionManager', handled=False), EventPattern('dbus-signal', signal='AccountPropertyChanged', predicate=(lambda e: 'ConnectionStatus' in e.args[0])), ) conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', '_', 'myself', has_presence=True, has_aliasing=True, has_avatars=True) assertEquals('/', prop_changed.args[0].get('Connection')) assertEquals('', prop_changed.args[0].get('ConnectionError')) assertEquals({}, prop_changed.args[0].get('ConnectionErrorDetails')) assertEquals(cs.CONN_STATUS_CONNECTING, prop_changed.args[0].get('ConnectionStatus')) assertEquals(cs.CSR_REQUESTED, prop_changed.args[0].get('ConnectionStatusReason')) q.dbus_return(request_conn.message, conn.bus_name, conn.object_path, signature='so') account_path = (cs.tp_path_prefix + '/Account/' + account_id) account = bus.get_object(cs.tp_name_prefix + '.AccountManager', account_path) prop_changed, _ = q.expect_many( EventPattern('dbus-signal', signal='AccountPropertyChanged', predicate=(lambda e: 'ConnectionStatus' in e.args[0])), EventPattern('dbus-method-call', method='Connect', path=conn.object_path, handled=True, interface=cs.CONN), ) assertEquals(conn.object_path, prop_changed.args[0].get('Connection')) assertEquals('', prop_changed.args[0].get('ConnectionError')) assertEquals({}, prop_changed.args[0].get('ConnectionErrorDetails')) assertEquals(cs.CONN_STATUS_CONNECTING, prop_changed.args[0].get('ConnectionStatus')) assertEquals(cs.CSR_REQUESTED, prop_changed.args[0].get('ConnectionStatusReason')) props = account.GetAll(cs.ACCOUNT, dbus_interface=cs.PROPERTIES_IFACE) assert props['Connection'] == conn.object_path assert props['ConnectionStatus'] == cs.CONN_STATUS_CONNECTING assert props['ConnectionStatusReason'] == cs.CSR_REQUESTED print "becoming connected" conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CSR_NONE_SPECIFIED) set_aliases, set_presence, set_avatar, prop_changed = q.expect_many( EventPattern('dbus-method-call', interface=cs.CONN_IFACE_ALIASING, method='SetAliases', args=[{ conn.self_handle: 'JC' }], handled=False), EventPattern('dbus-method-call', path=conn.object_path, interface=cs.CONN_IFACE_SIMPLE_PRESENCE, method='SetPresence', handled=True), EventPattern('dbus-method-call', interface=cs.CONN_IFACE_AVATARS, method='SetAvatar', args=['Deus Ex', 'image/jpeg'], handled=True), EventPattern( 'dbus-signal', signal='AccountPropertyChanged', path=account_path, interface=cs.ACCOUNT, predicate=(lambda e: e.args[0].get('ConnectionStatus') == cs. CONN_STATUS_CONNECTED), ), ) assertEquals(conn.object_path, prop_changed.args[0].get('Connection')) assertEquals('', prop_changed.args[0].get('ConnectionError')) assertEquals({}, prop_changed.args[0].get('ConnectionErrorDetails')) assertEquals(cs.CONN_STATUS_CONNECTED, prop_changed.args[0].get('ConnectionStatus')) assertEquals(cs.CSR_REQUESTED, prop_changed.args[0].get('ConnectionStatusReason')) assert account.Get( cs.ACCOUNT, 'CurrentPresence', dbus_interface=cs.PROPERTIES_IFACE) == (cs.PRESENCE_AVAILABLE, 'available', 'My vision is augmented') q.dbus_return(set_aliases.message, signature='')
def test(q, bus, unused, **kwargs): simulated_cm = SimulatedConnectionManager(q, bus) fake_accounts_service = kwargs['fake_accounts_service'] preseed(q, bus, fake_accounts_service) expected_params = { 'account': '*****@*****.**', 'password': r'\\ionstorm\\', } mc = MC(q, bus, wait_for_names=False) mc.wait_for_names( # Migration step: the three separate attributes get combined # (before the names are taken, so we need to expect it here) EventPattern('dbus-method-call', interface=cs.TEST_DBUS_ACCOUNT_SERVICE_IFACE, method='UpdateAttributes', predicate=(lambda e: e.args[0] == account_id and e.args[1] == {'AutomaticPresence': (2, 'available', 'My vision is augmented')} and e.args[2] == {'AutomaticPresence': 0} and # flags set(e.args[3]) == set([ # no particular order 'AutomaticPresenceType', 'AutomaticPresenceStatus', 'AutomaticPresenceMessage', ]))) ) request_conn, prop_changed = q.expect_many( EventPattern('dbus-method-call', method='RequestConnection', args=['fakeprotocol', expected_params], destination=cs.tp_name_prefix + '.ConnectionManager.fakecm', path=cs.tp_path_prefix + '/ConnectionManager/fakecm', interface=cs.tp_name_prefix + '.ConnectionManager', handled=False), EventPattern('dbus-signal', signal='AccountPropertyChanged', predicate=(lambda e: 'ConnectionStatus' in e.args[0])), ) conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', '_', 'myself', has_presence=True, has_aliasing=True, has_avatars=True) assertEquals('/', prop_changed.args[0].get('Connection')) assertEquals('', prop_changed.args[0].get('ConnectionError')) assertEquals({}, prop_changed.args[0].get('ConnectionErrorDetails')) assertEquals(cs.CONN_STATUS_CONNECTING, prop_changed.args[0].get('ConnectionStatus')) assertEquals(cs.CSR_REQUESTED, prop_changed.args[0].get('ConnectionStatusReason')) q.dbus_return(request_conn.message, conn.bus_name, conn.object_path, signature='so') account_path = (cs.tp_path_prefix + '/Account/' + account_id) account = bus.get_object( cs.tp_name_prefix + '.AccountManager', account_path) prop_changed, _ = q.expect_many( EventPattern('dbus-signal', signal='AccountPropertyChanged', predicate=(lambda e: 'ConnectionStatus' in e.args[0])), EventPattern('dbus-method-call', method='Connect', path=conn.object_path, handled=True, interface=cs.CONN), ) assertEquals(conn.object_path, prop_changed.args[0].get('Connection')) assertEquals('', prop_changed.args[0].get('ConnectionError')) assertEquals({}, prop_changed.args[0].get('ConnectionErrorDetails')) assertEquals(cs.CONN_STATUS_CONNECTING, prop_changed.args[0].get('ConnectionStatus')) assertEquals(cs.CSR_REQUESTED, prop_changed.args[0].get('ConnectionStatusReason')) props = account.GetAll(cs.ACCOUNT, dbus_interface=cs.PROPERTIES_IFACE) assert props['Connection'] == conn.object_path assert props['ConnectionStatus'] == cs.CONN_STATUS_CONNECTING assert props['ConnectionStatusReason'] == cs.CSR_REQUESTED print "becoming connected" conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CSR_NONE_SPECIFIED) set_aliases, set_presence, set_avatar, prop_changed = q.expect_many( EventPattern('dbus-method-call', interface=cs.CONN_IFACE_ALIASING, method='SetAliases', args=[{ conn.self_handle: 'JC' }], handled=False), EventPattern('dbus-method-call', path=conn.object_path, interface=cs.CONN_IFACE_SIMPLE_PRESENCE, method='SetPresence', handled=True), EventPattern('dbus-method-call', interface=cs.CONN_IFACE_AVATARS, method='SetAvatar', args=['Deus Ex', 'image/jpeg'], handled=True), EventPattern('dbus-signal', signal='AccountPropertyChanged', path=account_path, interface=cs.ACCOUNT, predicate=(lambda e: e.args[0].get('ConnectionStatus') == cs.CONN_STATUS_CONNECTED), ), ) assertEquals(conn.object_path, prop_changed.args[0].get('Connection')) assertEquals('', prop_changed.args[0].get('ConnectionError')) assertEquals({}, prop_changed.args[0].get('ConnectionErrorDetails')) assertEquals(cs.CONN_STATUS_CONNECTED, prop_changed.args[0].get('ConnectionStatus')) assertEquals(cs.CSR_REQUESTED, prop_changed.args[0].get('ConnectionStatusReason')) assert account.Get(cs.ACCOUNT, 'CurrentPresence', dbus_interface=cs.PROPERTIES_IFACE) == (cs.PRESENCE_AVAILABLE, 'available', 'My vision is augmented') q.dbus_return(set_aliases.message, signature='')
def test(q, bus, mc): simulated_cm = SimulatedConnectionManager(q, bus) ctl_dir = os.environ['MC_ACCOUNT_DIR'] old_key_file_name = os.path.join(ctl_dir, 'accounts.cfg') newer_key_file_name = os.path.join(os.environ['XDG_DATA_HOME'], 'telepathy', 'mission-control', 'accounts.cfg') # We do several scenarios in one MC run, to speed up testing a bit. scenarios = ('low', 'priority', 'masked', 'migration', 'absentcm') variant_file_names = {} low_prio_variant_file_names = {} account_paths = {} tails = {} for s in scenarios: variant_file_names[s] = os.path.join( os.environ['XDG_DATA_HOME'], 'telepathy', 'mission-control', 'fakecm-fakeprotocol-dontdivert%s_40example_2ecom0.account' % s) tails[s] = ('fakecm/fakeprotocol/dontdivert%s_40example_2ecom0' % s) account_paths[s] = cs.ACCOUNT_PATH_PREFIX + tails[s] low_prio_variant_file_names[s] = os.path.join( os.environ['XDG_DATA_DIRS'].split(':')[0], 'telepathy', 'mission-control', 'fakecm-fakeprotocol-dontdivert%s_40example_2ecom0.account' % s) try: os.makedirs(os.path.dirname(variant_file_names[s]), 0700) except OSError as e: if e.errno != errno.EEXIST: raise try: os.makedirs(os.path.dirname(low_prio_variant_file_names[s]), 0700) except OSError as e: if e.errno != errno.EEXIST: raise # This is deliberately a lower-priority location open(low_prio_variant_file_names['low'], 'w').write("""{ 'manager': <'fakecm'>, 'protocol': <'fakeprotocol'>, 'DisplayName': <'Account in a low-priority location'>, 'AutomaticPresence': <(uint32 2, 'available', '')>, 'Parameters': <{ 'account': <'*****@*****.**'>, 'password': <'password_in_variant_file'>, 'snakes': <uint32 42> }> } """) # This is in a lower-priority location and we don't know the # parameters' types yet open(low_prio_variant_file_names['migration'], 'w').write("""{ 'manager': <'fakecm'>, 'protocol': <'fakeprotocol'>, 'DisplayName': <'Account in a low-priority location with KeyFileParameters'>, 'AutomaticPresence': <(uint32 2, 'available', '')>, 'KeyFileParameters': <{ 'account': '*****@*****.**', 'password': '******', 'snakes': '42' }> } """) # This is in a lower-priority location, and we don't know the # parameters' types, and we can't learn them by asking the CM # because it isn't installed open(low_prio_variant_file_names['absentcm'], 'w').write("""{ 'manager': <'absentcm'>, 'protocol': <'absentprotocol'>, 'DisplayName': <'Account in a low-priority location with absent CM'>, 'AutomaticPresence': <(uint32 2, 'available', '')>, 'KeyFileParameters': <{ 'account': '*****@*****.**', 'password': '******', 'snakes': '42' }> } """) # This version of this account will be used open(variant_file_names['priority'], 'w').write("""{ 'manager': <'fakecm'>, 'protocol': <'fakeprotocol'>, 'DisplayName': <'Visible'>, 'AutomaticPresence': <(uint32 2, 'available', '')>, 'KeyFileParameters': <{'account': '*****@*****.**', 'password': '******', 'snakes': '42' }> } """) # This one won't, because it's "masked" by the higher-priority one open(low_prio_variant_file_names['priority'], 'w').write("""{ 'manager': <'fakecm'>, 'protocol': <'fakeprotocol'>, 'DisplayName': <'Hidden'>, 'Nickname': <'Hidden'>, 'AutomaticPresence': <(uint32 2, 'available', '')>, 'KeyFileParameters': <{'account': '*****@*****.**', 'password': '******', 'snakes': '42' }> } """) # This empty file is considered to "mask" the lower-priority one open(variant_file_names['masked'], 'w').write('') open(low_prio_variant_file_names['masked'], 'w').write("""{ 'manager': <'fakecm'>, 'protocol': <'fakeprotocol'>, 'AutomaticPresence': <(uint32 2, 'available', '')>, 'KeyFileParameters': <{'account': '*****@*****.**', 'password': '******', 'snakes': '42' }> } """) mc = MC(q, bus) account_manager, properties, interfaces = connect_to_mc(q, bus, mc) for s in scenarios: if s == 'masked': assertDoesNotContain(account_paths[s], properties['ValidAccounts']) assertDoesNotContain(account_paths[s], properties['InvalidAccounts']) elif s == 'absentcm': assertContains(account_paths[s], properties['InvalidAccounts']) assertDoesNotContain(account_paths[s], properties['ValidAccounts']) else: assertContains(account_paths[s], properties['ValidAccounts']) assertDoesNotContain(account_paths[s], properties['InvalidAccounts']) accounts = {} account_ifaces = {} for s in scenarios: if s != 'masked': accounts[s] = get_fakecm_account(bus, mc, account_paths[s]) account_ifaces[s] = dbus.Interface(accounts[s], cs.ACCOUNT) if s not in ('masked', 'absentcm'): # We can't get untyped parameters if we don't know what types # the CM gives them. assertEquals( 42, accounts[s].Properties.Get(cs.ACCOUNT, 'Parameters')['snakes']) assertEquals( dbus.UInt32, type(accounts[s].Properties.Get(cs.ACCOUNT, 'Parameters')['snakes'])) # Files in lower-priority XDG locations aren't copied until something # actually changes, and they aren't deleted. if s == 'low': assert os.path.exists(low_prio_variant_file_names[s]) # Delete the password (only), like Empathy 3.0-3.4 do when migrating. # This results in the higher-priority file being written out. account_ifaces['low'].UpdateParameters({}, ['password']) q.expect( 'dbus-signal', path=account_paths['low'], signal='AccountPropertyChanged', interface=cs.ACCOUNT, predicate=(lambda e: 'Parameters' in e.args[0]), ) # Check the account has copied (not moved! XDG_DATA_DIRS are, # conceptually, read-only) 'low' from the old to the new name assert not os.path.exists(old_key_file_name) assert not os.path.exists(newer_key_file_name) assert os.path.exists(low_prio_variant_file_names['low']) assert os.path.exists(variant_file_names['low']) # test that priority works assertContains(account_paths["priority"], properties['ValidAccounts']) assertEquals('', accounts['priority'].Properties.Get(cs.ACCOUNT, 'Nickname')) assertEquals( 'Visible', accounts['priority'].Properties.Get(cs.ACCOUNT, 'DisplayName')) # test what happens when we delete an account that has a lower-priority # "other self": it becomes masked assert accounts['priority'].Remove() is None assert not os.path.exists(old_key_file_name) assert not os.path.exists(newer_key_file_name) assert os.path.exists(low_prio_variant_file_names['priority']) assert os.path.exists(variant_file_names['priority']) assert open(variant_file_names['priority'], 'r').read() == '' assertContains('password_in_variant_file', open(low_prio_variant_file_names['priority'], 'r').read()) # The masked account is still masked assert open(variant_file_names['masked'], 'r').read() == '' # Because the CM exists, we can work out the correct types # for the 'migration' account's parameters. This triggers a commit # even though nothing has conceptually changed, so we have the type # for later. The file is copied, not moved, because XDG_DATA_DIRS are, # conceptually, read-only. assert not os.path.exists(old_key_file_name) assert not os.path.exists(newer_key_file_name) assert os.path.exists(low_prio_variant_file_names['migration']) assert os.path.exists(variant_file_names['migration']) assertEquals( "'password_in_variant_file'", account_store('get', 'variant-file', 'param-password', account=tails['migration'])) assertEquals( "uint32 42", account_store('get', 'variant-file', 'param-snakes', account=tails['migration'])) # Setting the password still does the right thing. account_ifaces['migration'].UpdateParameters({'password': '******'}, []) q.expect( 'dbus-signal', path=account_paths['migration'], signal='AccountPropertyChanged', interface=cs.ACCOUNT, predicate=(lambda e: 'Parameters' in e.args[0]), ) assert not os.path.exists(old_key_file_name) assert not os.path.exists(newer_key_file_name) assert os.path.exists(low_prio_variant_file_names['migration']) assert os.path.exists(variant_file_names['migration']) assertEquals( "'hello'", account_store('get', 'variant-file', 'param-password', account=tails['migration'])) # 'absentcm' is still only in the low-priority location: we can't # known the types of its parameters, so it doesn't get migrated. assert not os.path.exists(old_key_file_name) assert not os.path.exists(newer_key_file_name) assert os.path.exists(low_prio_variant_file_names['absentcm']) assert not os.path.exists(variant_file_names['absentcm'])
def test_keyfile(q, bus, mc, how_old='5.12'): simulated_cm = SimulatedConnectionManager(q, bus) if how_old == '5.12': # This is not actually ~/.mission-control, but it uses the same # code paths. dot_mission_control = os.environ['MC_ACCOUNT_DIR'] old_key_file_name = os.path.join(dot_mission_control, 'accounts.cfg') os.makedirs(dot_mission_control + '/fakecm/fakeprotocol/dontdivert1_40example_2ecom0') avatar_bin = open( dot_mission_control + '/fakecm/fakeprotocol/dontdivert1_40example_2ecom0/avatar.bin', 'w') avatar_bin.write('hello, world') avatar_bin.close() elif how_old == '5.14': # Same format, different location. old_key_file_name = os.path.join(os.environ['XDG_DATA_HOME'], 'telepathy', 'mission-control', 'accounts.cfg') # exercise override of an avatar in XDG_DATA_DIRS avatar_dir = (os.environ['XDG_DATA_DIRS'].split(':')[0] + '/telepathy/mission-control') os.makedirs(avatar_dir) avatar_bin = open( avatar_dir + '/fakecm-fakeprotocol-dontdivert1_40example_2ecom0.avatar', 'w') avatar_bin.write('hello, world') avatar_bin.close() else: raise AssertionError('Unsupported value for how_old') a1_new_variant_file_name = os.path.join( os.environ['XDG_DATA_HOME'], 'telepathy', 'mission-control', 'fakecm-fakeprotocol-dontdivert1_40example_2ecom0.account') a1_tail = 'fakecm/fakeprotocol/dontdivert1_40example_2ecom0' a2_new_variant_file_name = os.path.join( os.environ['XDG_DATA_HOME'], 'telepathy', 'mission-control', 'fakecm-fakeprotocol-dontdivert2_40example_2ecom0.account') a2_tail = 'fakecm/fakeprotocol/dontdivert2_40example_2ecom0' try: os.makedirs(os.path.dirname(old_key_file_name), 0700) except OSError as e: if e.errno != errno.EEXIST: raise open(old_key_file_name, 'w').write(r"""# Telepathy accounts [%s] manager=fakecm protocol=fakeprotocol [email protected] param-password=1 DisplayName=First among equals AutomaticPresence=2;available;; AvatarMime=text/plain avatar_token=hello, world [%s] manager=fakecm protocol=fakeprotocol [email protected] param-password=2 DisplayName=Second to none AutomaticPresence=2;available;; """ % (a1_tail, a2_tail)) mc = MC(q, bus) account_manager, properties, interfaces = connect_to_mc(q, bus, mc) # During MC startup, it moved the old keyfile's contents into # variant-based files, and deleted the old keyfile. assert not os.path.exists(old_key_file_name) assert os.path.exists(a1_new_variant_file_name) assert os.path.exists(a2_new_variant_file_name) assertEquals( "'First among equals'", account_store('get', 'variant-file', 'DisplayName', account=a1_tail)) assertEquals( "'Second to none'", account_store('get', 'variant-file', 'DisplayName', account=a2_tail)) # Because the CM is installed, we can work out the right types # for the parameters, too. assertEquals( "'*****@*****.**'", account_store('get', 'variant-file', 'param-account', account=a1_tail)) assertEquals( "'*****@*****.**'", account_store('get', 'variant-file', 'param-account', account=a2_tail)) # Also, MC has both accounts in memory... assertContains(cs.ACCOUNT_PATH_PREFIX + a1_tail, properties['ValidAccounts']) account = get_fakecm_account(bus, mc, cs.ACCOUNT_PATH_PREFIX + a1_tail) assertEquals('*****@*****.**', account.Properties.Get(cs.ACCOUNT, 'Parameters')['account']) assertEquals('First among equals', account.Properties.Get(cs.ACCOUNT, 'DisplayName')) assertEquals((dbus.ByteArray('hello, world'), 'text/plain'), account.Properties.Get(cs.ACCOUNT_IFACE_AVATAR, 'Avatar', byte_arrays=True)) assertContains(cs.ACCOUNT_PATH_PREFIX + a2_tail, properties['ValidAccounts']) account = get_fakecm_account(bus, mc, cs.ACCOUNT_PATH_PREFIX + a2_tail) assertEquals('*****@*****.**', account.Properties.Get(cs.ACCOUNT, 'Parameters')['account']) assertEquals('Second to none', account.Properties.Get(cs.ACCOUNT, 'DisplayName')) # ... and no other accounts. assertLength(2, properties['ValidAccounts'])