summaryrefslogtreecommitdiff
path: root/tests/twisted/account-manager
diff options
context:
space:
mode:
Diffstat (limited to 'tests/twisted/account-manager')
-rw-r--r--tests/twisted/account-manager/account-basics.py248
-rw-r--r--tests/twisted/account-manager/auto-away.py208
-rw-r--r--tests/twisted/account-manager/auto-connect.py175
-rw-r--r--tests/twisted/account-manager/avatar-persist.py143
-rw-r--r--tests/twisted/account-manager/avatar-refresh.py124
-rw-r--r--tests/twisted/account-manager/avatar.py112
-rw-r--r--tests/twisted/account-manager/bad-cm.py79
-rw-r--r--tests/twisted/account-manager/create-auto-connect.py68
-rw-r--r--tests/twisted/account-manager/create-twice.py64
-rw-r--r--tests/twisted/account-manager/create-with-properties.py174
-rw-r--r--tests/twisted/account-manager/device-idle.py129
-rw-r--r--tests/twisted/account-manager/enable-auto-connect.py69
-rw-r--r--tests/twisted/account-manager/enable.py62
-rw-r--r--tests/twisted/account-manager/make-valid.py237
-rw-r--r--tests/twisted/account-manager/nickname.py93
-rw-r--r--tests/twisted/account-manager/param-types.py86
-rwxr-xr-xtests/twisted/account-manager/presence.py136
-rw-r--r--tests/twisted/account-manager/reconnect.py202
-rw-r--r--tests/twisted/account-manager/recover-from-disconnect.py197
-rw-r--r--tests/twisted/account-manager/request-online.py170
-rw-r--r--tests/twisted/account-manager/server-drops-us.py128
-rw-r--r--tests/twisted/account-manager/service.py112
-rw-r--r--tests/twisted/account-manager/update-parameters.py194
23 files changed, 3210 insertions, 0 deletions
diff --git a/tests/twisted/account-manager/account-basics.py b/tests/twisted/account-manager/account-basics.py
new file mode 100644
index 00000000..51328ce9
--- /dev/null
+++ b/tests/twisted/account-manager/account-basics.py
@@ -0,0 +1,248 @@
+# Copyright (C) 2009 Nokia Corporation
+# Copyright (C) 2009 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import dbus
+import dbus.service
+
+from servicetest import EventPattern, tp_name_prefix, tp_path_prefix, \
+ call_async
+from mctest import exec_test, create_fakecm_account, get_account_manager
+import constants as cs
+
+def test(q, bus, mc):
+ # Get the AccountManager interface
+ account_manager = get_account_manager(bus)
+ account_manager_iface = dbus.Interface(account_manager, cs.AM)
+
+ # Introspect AccountManager for debugging purpose
+ account_manager_introspected = account_manager.Introspect(
+ dbus_interface=cs.INTROSPECTABLE_IFACE)
+ #print account_manager_introspected
+
+ # Check AccountManager has D-Bus property interface
+ properties = account_manager.GetAll(cs.AM,
+ dbus_interface=cs.PROPERTIES_IFACE)
+ assert properties is not None
+ assert properties.get('ValidAccounts') == [], \
+ properties.get('ValidAccounts')
+ assert properties.get('InvalidAccounts') == [], \
+ properties.get('InvalidAccounts')
+ interfaces = properties.get('Interfaces')
+
+ # assert that current functionality exists
+ assert cs.AM_IFACE_NOKIA_QUERY in interfaces, interfaces
+
+ params = dbus.Dictionary({"account": "someguy@example.com",
+ "password": "secrecy"}, signature='sv')
+ (cm_name_ref, account) = create_fakecm_account(q, bus, mc, params)
+
+ account_path = account.__dbus_object_path__
+
+ # Check the account is correctly created
+ properties = account_manager.GetAll(cs.AM,
+ dbus_interface=cs.PROPERTIES_IFACE)
+ assert properties is not None
+ assert properties.get('ValidAccounts') == [account_path], properties
+ account_path = properties['ValidAccounts'][0]
+ assert isinstance(account_path, dbus.ObjectPath), repr(account_path)
+ assert properties.get('InvalidAccounts') == [], properties
+
+ account_iface = dbus.Interface(account, cs.ACCOUNT)
+ account_props = dbus.Interface(account, cs.PROPERTIES_IFACE)
+ # Introspect Account for debugging purpose
+ account_introspected = account.Introspect(
+ dbus_interface=cs.INTROSPECTABLE_IFACE)
+ #print account_introspected
+
+ # Check Account has D-Bus property interface
+ properties = account_props.GetAll(cs.ACCOUNT)
+ assert properties is not None
+
+ assert properties.get('DisplayName') == 'fakeaccount', \
+ properties.get('DisplayName')
+ assert properties.get('Icon') == '', properties.get('Icon')
+ assert properties.get('Valid') == True, properties.get('Valid')
+ assert properties.get('Enabled') == False, properties.get('Enabled')
+ #assert properties.get('Nickname') == 'fakenick', properties.get('Nickname')
+ assert properties.get('Parameters') == params, properties.get('Parameters')
+ assert properties.get('Connection') == '/', properties.get('Connection')
+ assert properties.get('NormalizedName') == '', \
+ properties.get('NormalizedName')
+
+ interfaces = properties.get('Interfaces')
+ assert cs.ACCOUNT_IFACE_AVATAR in interfaces, interfaces
+ assert cs.ACCOUNT_IFACE_NOKIA_COMPAT in interfaces, interfaces
+ assert cs.ACCOUNT_IFACE_NOKIA_CONDITIONS in interfaces, interfaces
+
+ # sanity check
+ for k in properties:
+ assert account_props.Get(cs.ACCOUNT, k) == properties[k], k
+
+ # Alter some miscellaneous r/w properties
+
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'DisplayName',
+ 'Work account')
+ q.expect_many(
+ EventPattern('dbus-signal',
+ path=account_path,
+ signal='AccountPropertyChanged',
+ interface=cs.ACCOUNT,
+ args=[{'DisplayName': 'Work account'}]),
+ EventPattern('dbus-return', method='Set'),
+ )
+ assert account_props.Get(cs.ACCOUNT, 'DisplayName') == 'Work account'
+
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'Icon', 'im-jabber')
+ q.expect_many(
+ EventPattern('dbus-signal',
+ path=account_path,
+ signal='AccountPropertyChanged',
+ interface=cs.ACCOUNT,
+ args=[{'Icon': 'im-jabber'}]),
+ EventPattern('dbus-return', method='Set'),
+ )
+ assert account_props.Get(cs.ACCOUNT, 'Icon') == 'im-jabber'
+
+ assert account_props.Get(cs.ACCOUNT, 'HasBeenOnline') == False
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'Nickname', 'Joe Bloggs')
+ q.expect_many(
+ EventPattern('dbus-signal',
+ path=account_path,
+ signal='AccountPropertyChanged',
+ interface=cs.ACCOUNT,
+ args=[{'Nickname': 'Joe Bloggs'}]),
+ EventPattern('dbus-return', method='Set'),
+ )
+ assert account_props.Get(cs.ACCOUNT, 'Nickname') == 'Joe Bloggs'
+
+ call_async(q, dbus.Interface(account, cs.ACCOUNT_IFACE_NOKIA_COMPAT),
+ 'SetHasBeenOnline')
+ q.expect_many(
+ EventPattern('dbus-signal',
+ path=account_path,
+ signal='AccountPropertyChanged',
+ interface=cs.ACCOUNT,
+ args=[{'HasBeenOnline': True}]),
+ EventPattern('dbus-return', method='SetHasBeenOnline'),
+ )
+ assert account_props.Get(cs.ACCOUNT, 'HasBeenOnline') == True
+
+ call_async(q, account_props, 'Set', cs.ACCOUNT_IFACE_NOKIA_COMPAT,
+ 'SecondaryVCardFields',
+ ['x-badger', 'x-mushroom'])
+ # there's no change notification for the Compat properties
+ q.expect_many(
+ EventPattern('dbus-return', method='Set'),
+ )
+ assert account_props.Get(cs.ACCOUNT_IFACE_NOKIA_COMPAT,
+ 'SecondaryVCardFields') == ['x-badger', 'x-mushroom']
+
+ call_async(q, account_props, 'Set', cs.ACCOUNT_IFACE_NOKIA_CONDITIONS,
+ 'Condition',
+ dbus.Dictionary({':foo': 'bar'}, signature='ss'))
+ # there's no change notification for the Condition
+ q.expect_many(
+ EventPattern('dbus-return', method='Set'),
+ )
+ assert account_props.Get(cs.ACCOUNT_IFACE_NOKIA_CONDITIONS,
+ 'Condition') == {':foo': 'bar'}
+
+ # Set some properties to invalidly typed values - this currently succeeds
+ # but is a no-op, although in future it should change to raising an
+ # exception
+
+ # this variable's D-Bus type must differ from the types of all known
+ # properties
+ badly_typed = dbus.Struct(('wrongly typed',), signature='s')
+
+ for p in ('DisplayName', 'Icon', 'Enabled', 'Nickname',
+ 'AutomaticPresence', 'ConnectAutomatically', 'RequestedPresence'):
+ try:
+ account_props.Set(cs.ACCOUNT, p, badly_typed)
+ except dbus.DBusException, e:
+ assert e.get_dbus_name() == cs.INVALID_ARGUMENT, \
+ (p, e.get_dbus_name())
+ else:
+ raise AssertionError('Setting %s with wrong type should fail' % p)
+
+ for p in ('Avatar',):
+ try:
+ account_props.Set(cs.ACCOUNT_IFACE_AVATAR, p, badly_typed)
+ except dbus.DBusException, e:
+ assert e.get_dbus_name() == cs.INVALID_ARGUMENT, \
+ (p, e.get_dbus_name())
+ else:
+ raise AssertionError('Setting %s with wrong type should fail' % p)
+
+ for p in ('Profile', 'SecondaryVCardFields'):
+ try:
+ account_props.Set(cs.ACCOUNT_IFACE_NOKIA_COMPAT, p, badly_typed)
+ except dbus.DBusException, e:
+ assert e.get_dbus_name() == cs.INVALID_ARGUMENT, \
+ (p, e.get_dbus_name())
+ else:
+ raise AssertionError('Setting %s with wrong type should fail' % p)
+
+ for p in ('Condition',):
+ try:
+ account_props.Set(cs.ACCOUNT_IFACE_NOKIA_CONDITIONS, p,
+ badly_typed)
+ except dbus.DBusException, e:
+ assert e.get_dbus_name() == cs.INVALID_ARGUMENT, \
+ (p, e.get_dbus_name())
+ else:
+ raise AssertionError('Setting %s with wrong type should fail' % p)
+
+ # Make sure MC hasn't crashed yet, and make sure some properties are what
+ # we expect them to be
+
+ properties = account_props.GetAll(cs.ACCOUNT)
+ assert properties['DisplayName'] == 'Work account'
+ assert properties['Icon'] == 'im-jabber'
+ properties = account_props.GetAll(cs.ACCOUNT_IFACE_AVATAR)
+ assert properties['Avatar'] == ([], '')
+ properties = account_props.GetAll(cs.ACCOUNT_IFACE_NOKIA_COMPAT)
+ assert properties['SecondaryVCardFields'] == ['x-badger', 'x-mushroom']
+
+ # Delete the account
+ assert account_iface.Remove() is None
+ account_event, account_manager_event = q.expect_many(
+ EventPattern('dbus-signal',
+ path=account_path,
+ signal='Removed',
+ interface=cs.ACCOUNT,
+ args=[]
+ ),
+ EventPattern('dbus-signal',
+ path=cs.AM_PATH,
+ signal='AccountRemoved',
+ interface=cs.AM,
+ args=[account_path]
+ ),
+ )
+
+ # Check the account is correctly deleted
+ properties = account_manager.GetAll(cs.AM,
+ dbus_interface=cs.PROPERTIES_IFACE)
+ assert properties is not None
+ assert properties.get('ValidAccounts') == [], properties
+ assert properties.get('InvalidAccounts') == [], properties
+
+
+if __name__ == '__main__':
+ exec_test(test, {})
diff --git a/tests/twisted/account-manager/auto-away.py b/tests/twisted/account-manager/auto-away.py
new file mode 100644
index 00000000..6d2fc81b
--- /dev/null
+++ b/tests/twisted/account-manager/auto-away.py
@@ -0,0 +1,208 @@
+# Copyright (C) 2009 Nokia Corporation
+# Copyright (C) 2009 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import dbus
+import dbus.service
+
+from servicetest import EventPattern, tp_name_prefix, tp_path_prefix
+from mctest import exec_test, SimulatedConnection, create_fakecm_account,\
+ SimulatedChannel
+import constants as cs
+
+def test(q, bus, mc):
+ cm_name_ref = dbus.service.BusName(
+ tp_name_prefix + '.ConnectionManager.fakecm', bus=bus)
+
+ # Create an account
+ params = dbus.Dictionary({"account": "someguy@example.com",
+ "password": "secrecy"}, signature='sv')
+ (cm_name_ref, account) = create_fakecm_account(q, bus, mc, params)
+
+ # The account is initially valid but disabled
+ assert not account.Get(cs.ACCOUNT, 'Enabled',
+ dbus_interface=cs.PROPERTIES_IFACE)
+ assert account.Get(cs.ACCOUNT, 'Valid',
+ dbus_interface=cs.PROPERTIES_IFACE)
+
+ # 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)
+
+ assert account.Get(cs.ACCOUNT, 'Enabled',
+ dbus_interface=cs.PROPERTIES_IFACE)
+ assert account.Get(cs.ACCOUNT, 'Valid',
+ dbus_interface=cs.PROPERTIES_IFACE)
+
+ # Check the requested presence is offline
+ properties = account.GetAll(cs.ACCOUNT,
+ dbus_interface=cs.PROPERTIES_IFACE)
+ assert properties is not None
+ assert properties.get('RequestedPresence') == \
+ dbus.Struct((dbus.UInt32(cs.PRESENCE_TYPE_OFFLINE),
+ 'offline', '')), \
+ properties.get('RequestedPresence')
+
+ # Go online
+ requested_presence = dbus.Struct((dbus.UInt32(cs.PRESENCE_TYPE_AVAILABLE),
+ dbus.String(u'available'), dbus.String(u'staring at the sea')))
+ 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', has_presence=True)
+ conn.statuses = dbus.Dictionary({
+ 'available': (cs.PRESENCE_TYPE_AVAILABLE, True, True),
+ 'away': (cs.PRESENCE_TYPE_AWAY, True, True),
+ 'busy': (cs.PRESENCE_TYPE_BUSY, True, True),
+ 'offline': (cs.PRESENCE_TYPE_OFFLINE, False, False),
+ }, signature='s(ubb)')
+
+ q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so')
+
+ # MC calls GetStatus (maybe) and then Connect
+
+ q.expect('dbus-method-call', method='Connect',
+ path=conn.object_path, handled=True)
+
+ # Connect succeeds
+ conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CONN_STATUS_REASON_NONE)
+ conn.presence = dbus.Struct((cs.PRESENCE_TYPE_AVAILABLE, 'available', ''),
+ signature='uss')
+
+ # MC does some setup, including fetching the list of Channels
+
+ get_statuses = q.expect('dbus-method-call',
+ interface=cs.PROPERTIES_IFACE, method='Get',
+ args=[cs.CONN_IFACE_SIMPLE_PRESENCE, 'Statuses'],
+ path=conn.object_path, handled=True)
+
+ call, signal = q.expect_many(
+ EventPattern('dbus-method-call',
+ path=conn.object_path,
+ interface=cs.CONN_IFACE_SIMPLE_PRESENCE, method='SetPresence',
+ args=['available', 'staring at the sea'],
+ handled=True),
+ EventPattern('dbus-signal',
+ path=account.object_path,
+ interface=cs.ACCOUNT, signal='AccountPropertyChanged',
+ predicate = lambda e: 'CurrentPresence' in e.args[0]),
+ )
+ assert signal.args[0]['CurrentPresence'] == (cs.PRESENCE_TYPE_AVAILABLE,
+ 'available', '')
+
+ e = q.expect('dbus-signal',
+ path=account.object_path,
+ interface=cs.ACCOUNT, signal='AccountPropertyChanged',
+ predicate = lambda e: 'CurrentPresence' in e.args[0])
+ assert e.args[0]['CurrentPresence'] == requested_presence
+
+ # Check the requested presence is online
+ properties = account.GetAll(cs.ACCOUNT,
+ dbus_interface=cs.PROPERTIES_IFACE)
+ assert properties is not None
+ assert properties.get('RequestedPresence') == requested_presence, \
+ properties.get('RequestedPresence')
+
+ # This is normally a C API, only exposed to D-Bus here for testing
+ secret_debug_api = dbus.Interface(bus.get_object(cs.AM, "/"),
+ 'org.freedesktop.Telepathy.MissionControl5.RegressionTests')
+ MCD_SYSTEM_IDLE = 32
+
+ # Set the idle flag
+ secret_debug_api.ChangeSystemFlags(dbus.UInt32(MCD_SYSTEM_IDLE),
+ dbus.UInt32(0))
+
+ e = q.expect('dbus-method-call',
+ path=conn.object_path,
+ interface=cs.CONN_IFACE_SIMPLE_PRESENCE, method='SetPresence',
+ args=['away', ''],
+ handled=True)
+
+ # Unset the idle flag
+ secret_debug_api.ChangeSystemFlags(dbus.UInt32(0),
+ dbus.UInt32(MCD_SYSTEM_IDLE))
+
+ # MC puts the account back online
+
+ e = q.expect('dbus-method-call',
+ path=conn.object_path,
+ interface=cs.CONN_IFACE_SIMPLE_PRESENCE, method='SetPresence',
+ args=['available', 'staring at the sea'],
+ handled=True)
+
+ # Go to a non-Available status
+ requested_presence = dbus.Struct((dbus.UInt32(cs.PRESENCE_TYPE_BUSY),
+ dbus.String(u'busy'), dbus.String(u'in the great below')))
+ account.Set(cs.ACCOUNT,
+ 'RequestedPresence', requested_presence,
+ dbus_interface=cs.PROPERTIES_IFACE)
+ e = q.expect('dbus-method-call',
+ path=conn.object_path,
+ interface=cs.CONN_IFACE_SIMPLE_PRESENCE, method='SetPresence',
+ args=['busy', 'in the great below'],
+ handled=True)
+
+ forbidden = [EventPattern('dbus-method-call',
+ path=conn.object_path,
+ interface=cs.CONN_IFACE_SIMPLE_PRESENCE, method='SetPresence')]
+ q.forbid_events(forbidden)
+
+ # Set the idle flag
+ secret_debug_api.ChangeSystemFlags(dbus.UInt32(MCD_SYSTEM_IDLE),
+ dbus.UInt32(0))
+
+ # MC does not put the account away
+
+ # Unset the idle flag
+ secret_debug_api.ChangeSystemFlags(dbus.UInt32(0),
+ dbus.UInt32(MCD_SYSTEM_IDLE))
+
+ # MC does not put the account back online
+
+ q.unforbid_events(forbidden)
+
+ # Put the account offline
+ requested_presence = (dbus.UInt32(cs.PRESENCE_TYPE_OFFLINE), 'offline', '')
+ account.Set(cs.ACCOUNT,
+ 'RequestedPresence', requested_presence,
+ dbus_interface=cs.PROPERTIES_IFACE)
+
+ # In response, MC tells us to Disconnect, and we do
+ q.expect('dbus-method-call', method='Disconnect',
+ path=conn.object_path, handled=True)
+
+ properties = account.GetAll(cs.ACCOUNT, dbus_interface=cs.PROPERTIES_IFACE)
+ assert properties['Connection'] == '/'
+ assert properties['ConnectionStatus'] == cs.CONN_STATUS_DISCONNECTED
+ assert properties['CurrentPresence'] == requested_presence
+ assert properties['RequestedPresence'] == requested_presence
+
+if __name__ == '__main__':
+ exec_test(test, {})
diff --git a/tests/twisted/account-manager/auto-connect.py b/tests/twisted/account-manager/auto-connect.py
new file mode 100644
index 00000000..badcf7fc
--- /dev/null
+++ b/tests/twisted/account-manager/auto-connect.py
@@ -0,0 +1,175 @@
+# Copyright (C) 2009 Nokia Corporation
+# Copyright (C) 2009 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import dbus
+"""Feature test for automatically signing in and setting presence etc.
+"""
+
+import os
+
+import dbus
+import dbus.service
+
+from servicetest import EventPattern, tp_name_prefix, tp_path_prefix, \
+ call_async, assertEquals
+from mctest import exec_test, SimulatedConnection, create_fakecm_account, \
+ make_mc
+import constants as cs
+
+cm_name_ref = dbus.service.BusName(
+ cs.tp_name_prefix + '.ConnectionManager.fakecm', bus=dbus.SessionBus())
+
+account_id = 'fakecm/fakeprotocol/jc_2edenton_40unatco_2eint'
+
+def preseed():
+
+ accounts_dir = os.environ['MC_ACCOUNT_DIR']
+
+ accounts_cfg = open(accounts_dir + '/accounts.cfg', 'w')
+
+ # As a regression test for part of fd.o #28557, the password starts and
+ # ends with a double backslash, which is represented in the file as a
+ # quadruple backslash.
+ accounts_cfg.write(r"""# Telepathy accounts
+[%s]
+manager=fakecm
+protocol=fakeprotocol
+DisplayName=Work account
+NormalizedName=jc.denton@unatco.int
+param-account=jc.denton@unatco.int
+param-password=\\\\ionstorm\\\\
+Enabled=1
+ConnectAutomatically=1
+AutomaticPresenceType=2
+AutomaticPresenceStatus=available
+AutomaticPresenceMessage=My vision is augmented
+Nickname=JC
+AvatarMime=image/jpeg
+""" % account_id)
+ accounts_cfg.close()
+
+ os.makedirs(accounts_dir + '/' + account_id)
+ avatar_bin = open(accounts_dir + '/' + account_id + '/avatar.bin', 'w')
+ avatar_bin.write('Deus Ex')
+ avatar_bin.close()
+
+ account_connections_file = open(accounts_dir + '/.mc_connections', 'w')
+ account_connections_file.write("")
+ account_connections_file.close()
+
+def test(q, bus, unused):
+
+ expected_params = {
+ 'account': 'jc.denton@unatco.int',
+ 'password': r'\\ionstorm\\',
+ }
+
+ mc = make_mc(bus, q.append)
+
+ 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])),
+ EventPattern('dbus-signal', signal='NameOwnerChanged',
+ predicate=lambda e: e.args[0] == cs.AM and e.args[2]),
+ )
+
+ 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.CONN_STATUS_REASON_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.CONN_STATUS_REASON_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.CONN_STATUS_REASON_REQUESTED
+
+ print "becoming connected"
+ conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CONN_STATUS_REASON_NONE)
+
+ 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.CONN_STATUS_REASON_REQUESTED,
+ prop_changed.args[0].get('ConnectionStatusReason'))
+
+ assert account.Get(cs.ACCOUNT, 'CurrentPresence',
+ dbus_interface=cs.PROPERTIES_IFACE) == (cs.PRESENCE_TYPE_AVAILABLE,
+ 'available', 'My vision is augmented')
+
+ q.dbus_return(set_aliases.message, signature='')
+
+if __name__ == '__main__':
+ preseed()
+ exec_test(test, {}, preload_mc=False)
diff --git a/tests/twisted/account-manager/avatar-persist.py b/tests/twisted/account-manager/avatar-persist.py
new file mode 100644
index 00000000..e1334435
--- /dev/null
+++ b/tests/twisted/account-manager/avatar-persist.py
@@ -0,0 +1,143 @@
+# Copyright (C) 2009 Nokia Corporation
+# Copyright (C) 2009 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import dbus
+"""Feature test for signing in and setting an avatar, on CMs like Gabble where
+the avatar is stored by the server.
+"""
+
+import os
+
+import dbus
+import dbus.service
+
+from servicetest import EventPattern, tp_name_prefix, tp_path_prefix, \
+ call_async
+from mctest import exec_test, SimulatedConnection, create_fakecm_account, \
+ make_mc
+import constants as cs
+
+cm_name_ref = dbus.service.BusName(
+ cs.tp_name_prefix + '.ConnectionManager.fakecm', bus=dbus.SessionBus())
+
+account_id = 'fakecm/fakeprotocol/jc_2edenton_40unatco_2eint'
+
+def preseed():
+
+ accounts_dir = os.environ['MC_ACCOUNT_DIR']
+
+ accounts_cfg = open(accounts_dir + '/accounts.cfg', 'w')
+ accounts_cfg.write("""# Telepathy accounts
+[%s]
+manager=fakecm
+protocol=fakeprotocol
+DisplayName=Work account
+NormalizedName=jc.denton@unatco.int
+param-account=jc.denton@unatco.int
+param-password=ionstorm
+Enabled=1
+ConnectAutomatically=1
+AutomaticPresenceType=2
+AutomaticPresenceStatus=available
+AutomaticPresenceMessage=My vision is augmented
+Nickname=JC
+AvatarMime=image/jpeg
+avatar_token=Deus Ex
+""" % account_id)
+ accounts_cfg.close()
+
+ os.makedirs(accounts_dir + '/' + account_id)
+ avatar_bin = open(accounts_dir + '/' + account_id + '/avatar.bin', 'w')
+ avatar_bin.write('Deus Ex')
+ avatar_bin.close()
+
+ account_connections_file = open(accounts_dir + '/.mc_connections', 'w')
+ account_connections_file.write("")
+ account_connections_file.close()
+
+def test(q, bus, unused):
+
+ expected_params = {
+ 'account': 'jc.denton@unatco.int',
+ 'password': 'ionstorm',
+ }
+
+ mc = make_mc(bus, q.append)
+
+ e, _ = 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='NameOwnerChanged',
+ predicate=lambda e: e.args[0] == cs.AM and e.args[2]),
+ )
+
+ conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', '_',
+ 'myself', has_avatars=True, avatars_persist=True)
+ conn.avatar = dbus.Struct((dbus.ByteArray('MJ12'), 'image/png'),
+ signature='ays')
+
+ q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so')
+
+ account_path = (cs.tp_path_prefix + '/Account/' + account_id)
+
+ q.expect('dbus-method-call', method='Connect',
+ path=conn.object_path, handled=True, interface=cs.CONN)
+
+ conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CONN_STATUS_REASON_NONE)
+
+ # We haven't changed the avatar since we last signed in, so we don't set
+ # it - on the contrary, we pick up the remote avatar (which has changed
+ # since we were last here) to store it in the Account
+ _, request_avatars_call, e = q.expect_many(
+ EventPattern('dbus-method-call',
+ interface=cs.CONN_IFACE_AVATARS, method='GetKnownAvatarTokens',
+ args=[[conn.self_handle]],
+ handled=True),
+ EventPattern('dbus-method-call',
+ interface=cs.CONN_IFACE_AVATARS, method='RequestAvatars',
+ args=[[conn.self_handle]],
+ handled=False),
+ EventPattern('dbus-signal', signal='AccountPropertyChanged',
+ path=account_path, interface=cs.ACCOUNT,
+ predicate=(lambda e:
+ e.args[0].get('ConnectionStatus') ==
+ cs.CONN_STATUS_CONNECTED),
+ ),
+ )
+
+ q.dbus_return(request_avatars_call.message, signature='')
+
+ q.dbus_emit(conn.object_path, cs.CONN_IFACE_AVATARS, 'AvatarRetrieved',
+ conn.self_handle, str(conn.avatar[0]),
+ dbus.ByteArray(conn.avatar[0]), conn.avatar[1], signature='usays')
+
+ q.expect('dbus-signal', path=account_path,
+ interface=cs.ACCOUNT_IFACE_AVATAR, signal='AvatarChanged'),
+
+ account = bus.get_object(cs.AM, account_path)
+ account_props = dbus.Interface(account, cs.PROPERTIES_IFACE)
+ assert account_props.Get(cs.ACCOUNT_IFACE_AVATAR, 'Avatar',
+ byte_arrays=True) == conn.avatar
+
+if __name__ == '__main__':
+ preseed()
+ exec_test(test, {}, preload_mc=False)
diff --git a/tests/twisted/account-manager/avatar-refresh.py b/tests/twisted/account-manager/avatar-refresh.py
new file mode 100644
index 00000000..7cc2d2c8
--- /dev/null
+++ b/tests/twisted/account-manager/avatar-refresh.py
@@ -0,0 +1,124 @@
+# Copyright (C) 2009 Nokia Corporation
+# Copyright (C) 2009 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import dbus
+"""Feature test for signing in and setting an avatar, on CMs like Salut where
+the avatar must be reset every time you sign in.
+"""
+
+import os
+
+import dbus
+import dbus.service
+
+from servicetest import EventPattern, tp_name_prefix, tp_path_prefix, \
+ call_async
+from mctest import exec_test, SimulatedConnection, create_fakecm_account, \
+ make_mc
+import constants as cs
+
+cm_name_ref = dbus.service.BusName(
+ cs.tp_name_prefix + '.ConnectionManager.fakecm', bus=dbus.SessionBus())
+
+account_id = 'fakecm/fakeprotocol/jc_2edenton_40unatco_2eint'
+
+def preseed():
+
+ accounts_dir = os.environ['MC_ACCOUNT_DIR']
+
+ accounts_cfg = open(accounts_dir + '/accounts.cfg', 'w')
+ accounts_cfg.write("""# Telepathy accounts
+[%s]
+manager=fakecm
+protocol=fakeprotocol
+DisplayName=Work account
+NormalizedName=jc.denton@unatco.int
+param-account=jc.denton@unatco.int
+param-password=ionstorm
+Enabled=1
+ConnectAutomatically=1
+AutomaticPresenceType=2
+AutomaticPresenceStatus=available
+AutomaticPresenceMessage=My vision is augmented
+Nickname=JC
+AvatarMime=image/jpeg
+avatar_token=Deus Ex
+""" % account_id)
+ accounts_cfg.close()
+
+ os.makedirs(accounts_dir + '/' + account_id)
+ avatar_bin = open(accounts_dir + '/' + account_id + '/avatar.bin', 'w')
+ avatar_bin.write('Deus Ex')
+ avatar_bin.close()
+
+ account_connections_file = open(accounts_dir + '/.mc_connections', 'w')
+ account_connections_file.write("")
+ account_connections_file.close()
+
+def test(q, bus, unused):
+
+ expected_params = {
+ 'account': 'jc.denton@unatco.int',
+ 'password': 'ionstorm',
+ }
+
+ mc = make_mc(bus, q.append)
+
+ e, _ = 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='NameOwnerChanged',
+ predicate=lambda e: e.args[0] == cs.AM and e.args[2]),
+ )
+
+ conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', '_',
+ 'myself', has_avatars=True, avatars_persist=False)
+
+ q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so')
+
+ account_path = (cs.tp_path_prefix + '/Account/' + account_id)
+
+ q.expect('dbus-method-call', method='Connect',
+ path=conn.object_path, handled=True, interface=cs.CONN)
+
+ conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CONN_STATUS_REASON_NONE)
+
+ _, _, e = q.expect_many(
+ EventPattern('dbus-method-call',
+ interface=cs.CONN_IFACE_AVATARS, method='GetKnownAvatarTokens',
+ args=[[conn.self_handle]],
+ 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),
+ ),
+ )
+
+if __name__ == '__main__':
+ preseed()
+ exec_test(test, {}, preload_mc=False)
diff --git a/tests/twisted/account-manager/avatar.py b/tests/twisted/account-manager/avatar.py
new file mode 100644
index 00000000..c616e146
--- /dev/null
+++ b/tests/twisted/account-manager/avatar.py
@@ -0,0 +1,112 @@
+# Copyright (C) 2009 Nokia Corporation
+# Copyright (C) 2009 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import dbus
+import dbus
+import dbus.service
+
+from servicetest import EventPattern, tp_name_prefix, tp_path_prefix, \
+ call_async, assertEquals
+from mctest import exec_test, create_fakecm_account, enable_fakecm_account
+import constants as cs
+
+def test(q, bus, mc):
+ params = dbus.Dictionary({"account": "me@example.com",
+ "password": "secrecy"}, signature='sv')
+ (cm_name_ref, account) = create_fakecm_account(q, bus, mc, params)
+
+ account_iface = dbus.Interface(account, cs.ACCOUNT)
+ account_props = dbus.Interface(account, cs.PROPERTIES_IFACE)
+
+ call_async(q, account_props, 'Set', cs.ACCOUNT_IFACE_AVATAR, 'Avatar',
+ dbus.Struct((dbus.ByteArray('AAAA'), 'image/jpeg')))
+ q.expect_many(
+ EventPattern('dbus-signal',
+ path=account.object_path,
+ signal='AvatarChanged',
+ interface=cs.ACCOUNT_IFACE_AVATAR,
+ args=[]),
+ EventPattern('dbus-return', method='Set'),
+ )
+ assert account_props.Get(cs.ACCOUNT_IFACE_AVATAR, 'Avatar',
+ byte_arrays=True) == ('AAAA', 'image/jpeg')
+
+ # OK, let's go online. The avatar is set regardless of the CM
+ conn, e = enable_fakecm_account(q, bus, mc, account, params,
+ has_avatars=True, avatars_persist=True,
+ expect_after_connect=[
+ EventPattern('dbus-method-call',
+ interface=cs.CONN_IFACE_AVATARS, method='SetAvatar',
+ handled=True, args=['AAAA', 'image/jpeg']),
+ ])
+
+ # Change avatar after going online
+ call_async(q, account_props, 'Set', cs.ACCOUNT_IFACE_AVATAR, 'Avatar',
+ (dbus.ByteArray('BBBB'), 'image/png'))
+
+ q.expect_many(
+ EventPattern('dbus-method-call',
+ interface=cs.CONN_IFACE_AVATARS, method='SetAvatar',
+ args=['BBBB', 'image/png'],
+ handled=True),
+ EventPattern('dbus-signal', path=account.object_path,
+ interface=cs.ACCOUNT_IFACE_AVATAR, signal='AvatarChanged'),
+ EventPattern('dbus-return', method='Set')
+ )
+
+ assert account_props.Get(cs.ACCOUNT_IFACE_AVATAR, 'Avatar',
+ byte_arrays=True) == ('BBBB', 'image/png')
+
+ someone_else = conn.ensure_handle(cs.HT_CONTACT, 'alberto@example.com')
+
+ # Another contact changes their avatar: ignored
+ q.dbus_emit(conn.object_path, cs.CONN_IFACE_AVATARS, 'AvatarUpdated',
+ someone_else, "mardy's avatar token", signature='us')
+
+ # Another client changes our avatar remotely
+ q.dbus_emit(conn.object_path, cs.CONN_IFACE_AVATARS, 'AvatarUpdated',
+ conn.self_handle, 'CCCC', signature='us')
+
+ e = q.expect('dbus-method-call',
+ interface=cs.CONN_IFACE_AVATARS, method='RequestAvatars',
+ args=[[conn.self_handle]],
+ handled=False)
+ q.dbus_return(e.message, signature='')
+
+ q.dbus_emit(conn.object_path, cs.CONN_IFACE_AVATARS,
+ 'AvatarRetrieved', conn.self_handle, 'CCCC',
+ dbus.ByteArray('CCCC'), 'image/svg', signature='usays')
+ q.expect('dbus-signal', path=account.object_path,
+ interface=cs.ACCOUNT_IFACE_AVATAR, signal='AvatarChanged'),
+
+ assert account_props.Get(cs.ACCOUNT_IFACE_AVATAR, 'Avatar',
+ byte_arrays=True) == ('CCCC', 'image/svg')
+
+ # empty avatar tests
+ conn.forget_avatar()
+ q.dbus_emit(conn.object_path, cs.CONN_IFACE_AVATARS, 'AvatarUpdated',
+ conn.self_handle, '', signature='us')
+ q.expect('dbus-method-call', method='GetKnownAvatarTokens')
+ q.expect('dbus-signal', path=account.object_path,
+ interface=cs.ACCOUNT_IFACE_AVATAR, signal='AvatarChanged')
+
+ assertEquals(account_props.Get(cs.ACCOUNT_IFACE_AVATAR, 'Avatar',
+ byte_arrays=False), ([], ''))
+
+if __name__ == '__main__':
+ exec_test(test, {})
diff --git a/tests/twisted/account-manager/bad-cm.py b/tests/twisted/account-manager/bad-cm.py
new file mode 100644
index 00000000..dea5860a
--- /dev/null
+++ b/tests/twisted/account-manager/bad-cm.py
@@ -0,0 +1,79 @@
+# Copyright (C) 2009 Nokia Corporation
+# Copyright (C) 2009 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+"""Regression test for https://bugs.freedesktop.org/show_bug.cgi?id=20880
+"""
+
+import dbus
+
+from servicetest import EventPattern, tp_name_prefix, tp_path_prefix, \
+ call_async
+from fakecm import start_fake_connection_manager
+from mctest import exec_test, get_account_manager
+import constants as cs
+
+FakeCM_bus_name = "com.example.FakeCM"
+ConnectionManager_object_path = "/com/example/FakeCM/ConnectionManager"
+
+
+def test(q, bus, mc):
+ # Get the AccountManager interface
+ account_manager = get_account_manager(bus)
+ account_manager_iface = dbus.Interface(account_manager, cs.AM)
+
+ # Create an account with a bad Connection_Manager - it should fail
+
+ params = dbus.Dictionary({"account": "someguy@example.com",
+ "password": "secrecy"}, signature='sv')
+ call_async(q, account_manager_iface, 'CreateAccount',
+ 'nonexistent_cm', # Connection_Manager
+ 'fakeprotocol', # Protocol
+ 'fakeaccount', #Display_Name
+ params, # Parameters
+ {}, # Properties
+ )
+ q.expect('dbus-error', method='CreateAccount')
+
+ # Create an account with a bad Protocol - it should fail
+
+ params = dbus.Dictionary({"account": "someguy@example.com",
+ "password": "secrecy"}, signature='sv')
+ call_async(q, account_manager_iface, 'CreateAccount',
+ 'fakecm', # Connection_Manager
+ 'nonexistent-protocol', # Protocol
+ 'fakeaccount', #Display_Name
+ params, # Parameters
+ {}, # Properties
+ )
+ q.expect('dbus-error', method='CreateAccount')
+
+ # Create an account with incomplete Parameters - it should fail
+
+ params = dbus.Dictionary({"account": "someguy@example.com"},
+ signature='sv')
+ call_async(q, account_manager_iface, 'CreateAccount',
+ 'fakecm', # Connection_Manager
+ 'fakeprotocol', # Protocol
+ 'fakeaccount', #Display_Name
+ params, # Parameters
+ {}, # Properties
+ )
+ q.expect('dbus-error', method='CreateAccount')
+
+if __name__ == '__main__':
+ exec_test(test, {})
diff --git a/tests/twisted/account-manager/create-auto-connect.py b/tests/twisted/account-manager/create-auto-connect.py
new file mode 100644
index 00000000..fa2cb470
--- /dev/null
+++ b/tests/twisted/account-manager/create-auto-connect.py
@@ -0,0 +1,68 @@
+# Copyright (C) 2009 Nokia Corporation
+# Copyright (C) 2009 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import dbus
+import dbus
+import dbus.service
+
+from servicetest import EventPattern, tp_name_prefix, tp_path_prefix, \
+ call_async
+from mctest import exec_test, create_fakecm_account
+import constants as cs
+
+def test(q, bus, mc):
+ params = dbus.Dictionary({"account": "smcv@example.com",
+ "password": "secrecy"}, signature='sv')
+ (cm_name_ref, 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
+
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'RequestedPresence',
+ (dbus.UInt32(cs.PRESENCE_TYPE_OFFLINE), 'offline', ''))
+ q.expect('dbus-return', method='Set')
+
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'AutomaticPresence',
+ (dbus.UInt32(cs.PRESENCE_TYPE_BUSY), 'busy',
+ 'Testing automatic presence'))
+ q.expect('dbus-return', method='Set')
+ q.expect('dbus-signal', signal='AccountPropertyChanged',
+ predicate=lambda e:
+ e.args[0].get('AutomaticPresence', (None, None, None))[1]
+ == 'busy')
+
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'Enabled', True)
+ q.expect('dbus-return', method='Set')
+ q.expect('dbus-signal', signal='AccountPropertyChanged',
+ predicate=lambda e: e.args[0].get('Enabled'))
+
+ # Go online by telling it to connect automatically
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'ConnectAutomatically',
+ 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)
+
+if __name__ == '__main__':
+ exec_test(test, {})
diff --git a/tests/twisted/account-manager/create-twice.py b/tests/twisted/account-manager/create-twice.py
new file mode 100644
index 00000000..2f0c0e0c
--- /dev/null
+++ b/tests/twisted/account-manager/create-twice.py
@@ -0,0 +1,64 @@
+# Copyright (C) 2009 Nokia Corporation
+# Copyright (C) 2009-2010 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import dbus
+import dbus
+import dbus.service
+
+from servicetest import EventPattern, tp_name_prefix, tp_path_prefix, \
+ call_async
+from mctest import exec_test, create_fakecm_account, get_account_manager
+import constants as cs
+
+def test(q, bus, mc):
+ account_manager = get_account_manager(bus)
+ account_manager_iface = dbus.Interface(account_manager, cs.AM)
+
+ # fd.o #25684: creating similarly-named accounts in very quick succession
+ # used to fail
+
+ params = dbus.Dictionary({"account": "create-twice",
+ "password": "secrecy"}, signature='sv')
+
+ cm_name_ref = dbus.service.BusName(cs.tp_name_prefix +
+ '.ConnectionManager.fakecm', bus=bus)
+ account_manager = bus.get_object(cs.AM, cs.AM_PATH)
+ am_iface = dbus.Interface(account_manager, cs.AM)
+
+ call_async(q, am_iface, 'CreateAccount',
+ 'fakecm',
+ 'fakeprotocol',
+ 'fakeaccount',
+ params,
+ {})
+ call_async(q, am_iface, 'CreateAccount',
+ 'fakecm',
+ 'fakeprotocol',
+ 'fakeaccount',
+ params,
+ {})
+
+ ret1 = q.expect('dbus-return', method='CreateAccount')
+ ret2 = q.expect('dbus-return', method='CreateAccount')
+
+ path1 = ret1.value[0]
+ path2 = ret2.value[0]
+ assert path1 != path2
+
+if __name__ == '__main__':
+ exec_test(test, {})
diff --git a/tests/twisted/account-manager/create-with-properties.py b/tests/twisted/account-manager/create-with-properties.py
new file mode 100644
index 00000000..5aabfc76
--- /dev/null
+++ b/tests/twisted/account-manager/create-with-properties.py
@@ -0,0 +1,174 @@
+# Copyright (C) 2009 Nokia Corporation
+# Copyright (C) 2009 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import dbus
+import dbus
+import dbus.service
+
+from servicetest import EventPattern, tp_name_prefix, tp_path_prefix, \
+ call_async
+from mctest import exec_test, create_fakecm_account, get_account_manager
+import constants as cs
+
+def test(q, bus, mc):
+ # Get the AccountManager interface
+ account_manager = get_account_manager(bus)
+ account_manager_iface = dbus.Interface(account_manager, cs.AM)
+
+ # Introspect AccountManager for debugging purpose
+ account_manager_introspected = account_manager.Introspect(
+ dbus_interface=cs.INTROSPECTABLE_IFACE)
+ #print account_manager_introspected
+
+ # Check AccountManager has D-Bus property interface
+ properties = account_manager.GetAll(cs.AM,
+ dbus_interface=cs.PROPERTIES_IFACE)
+ assert properties is not None
+ assert properties.get('ValidAccounts') == [], \
+ properties.get('ValidAccounts')
+ assert properties.get('InvalidAccounts') == [], \
+ properties.get('InvalidAccounts')
+ interfaces = properties.get('Interfaces')
+ supported = properties.get('SupportedAccountProperties')
+
+ # assert that current functionality exists
+ assert cs.AM_IFACE_NOKIA_QUERY in interfaces, interfaces
+
+ assert (cs.ACCOUNT + '.AutomaticPresence') in supported
+ assert (cs.ACCOUNT + '.Enabled') in supported
+ assert (cs.ACCOUNT + '.Icon') in supported
+ assert (cs.ACCOUNT + '.Nickname') in supported
+ assert (cs.ACCOUNT + '.ConnectAutomatically') in supported
+ assert (cs.ACCOUNT_IFACE_AVATAR + '.Avatar') in supported
+ assert (cs.ACCOUNT_IFACE_NOKIA_COMPAT + '.Profile') in supported
+ assert (cs.ACCOUNT_IFACE_NOKIA_COMPAT + '.SecondaryVCardFields') in supported
+ assert (cs.ACCOUNT_IFACE_NOKIA_CONDITIONS + '.Condition') in supported
+
+ assert (cs.ACCOUNT + '.RequestedPresence') in supported
+
+ params = dbus.Dictionary({"account": "anarki@example.com",
+ "password": "secrecy"}, signature='sv')
+
+ cm_name_ref = dbus.service.BusName(cs.tp_name_prefix +
+ '.ConnectionManager.fakecm', bus=bus)
+ account_manager = bus.get_object(cs.AM, cs.AM_PATH)
+ am_iface = dbus.Interface(account_manager, cs.AM)
+
+ creation_properties = dbus.Dictionary({
+ cs.ACCOUNT + '.Enabled': True,
+ cs.ACCOUNT + '.AutomaticPresence': dbus.Struct((
+ dbus.UInt32(cs.PRESENCE_TYPE_BUSY),
+ 'busy', 'Exploding'), signature='uss'),
+ cs.ACCOUNT + '.RequestedPresence': dbus.Struct((
+ dbus.UInt32(cs.PRESENCE_TYPE_AWAY),
+ 'away', 'Respawning'), signature='uss'),
+ cs.ACCOUNT + '.Icon': 'quake3arena',
+ cs.ACCOUNT + '.Nickname': 'AnArKi',
+ cs.ACCOUNT + '.ConnectAutomatically': True,
+ cs.ACCOUNT_IFACE_AVATAR + '.Avatar': (dbus.ByteArray('foo'),
+ 'image/jpeg'),
+ cs.ACCOUNT_IFACE_NOKIA_COMPAT + '.Profile': 'openarena',
+ cs.ACCOUNT_IFACE_NOKIA_COMPAT + '.SecondaryVCardFields':
+ dbus.Array(['x-ioquake3', 'x-quake3'], signature='s'),
+ cs.ACCOUNT_IFACE_NOKIA_CONDITIONS + '.Condition':
+ dbus.Dictionary({ 'has-quad-damage': ':y' }, signature='ss'),
+ }, signature='sv')
+
+ call_async(q, am_iface, 'CreateAccount',
+ 'fakecm',
+ 'fakeprotocol',
+ 'fakeaccount',
+ params,
+ creation_properties)
+
+ # The spec has no order guarantee here.
+ # FIXME: MC ought to also introspect the CM and find out that the params
+ # are in fact sufficient
+
+ am_signal, ret, rc = q.expect_many(
+ EventPattern('dbus-signal', path=cs.AM_PATH,
+ signal='AccountValidityChanged', interface=cs.AM),
+ EventPattern('dbus-return', method='CreateAccount'),
+ EventPattern('dbus-method-call', method='RequestConnection'),
+ )
+ account_path = ret.value[0]
+ assert am_signal.args == [account_path, True], am_signal.args
+
+ assert account_path is not None
+
+ account = bus.get_object(
+ cs.tp_name_prefix + '.AccountManager',
+ account_path)
+ account_props = dbus.Interface(account, cs.PROPERTIES_IFACE)
+
+ properties = account_props.GetAll(cs.ACCOUNT)
+ assert properties.get('AutomaticPresence') == (cs.PRESENCE_TYPE_BUSY,
+ 'busy', 'Exploding'), \
+ properties.get('AutomaticPresence')
+ assert properties.get('RequestedPresence') == (cs.PRESENCE_TYPE_AWAY,
+ 'away', 'Respawning'), \
+ properties.get('RequestedPresence')
+ assert properties.get('ConnectAutomatically') == True, \
+ properties.get('ConnectAutomatically')
+ assert properties.get('Enabled') == True, \
+ properties.get('Enabled')
+ assert properties.get('Valid') == True, \
+ properties.get('Valid')
+ assert properties.get('Icon') == 'quake3arena', \
+ properties.get('Icon')
+ assert properties.get('Nickname') == 'AnArKi', \
+ properties.get('Nickname')
+
+ properties = account_props.GetAll(cs.ACCOUNT_IFACE_AVATAR)
+ assert properties.get('Avatar') == ([ord('f'), ord('o'), ord('o')],
+ 'image/jpeg')
+
+ properties = account_props.GetAll(cs.ACCOUNT_IFACE_NOKIA_COMPAT)
+ assert properties.get('Profile') == 'openarena'
+ assert sorted(properties.get('SecondaryVCardFields')) == \
+ ['x-ioquake3', 'x-quake3']
+
+ properties = account_props.GetAll(cs.ACCOUNT_IFACE_NOKIA_CONDITIONS)
+ assert properties.get('Condition') == {
+ 'has-quad-damage': ':y',
+ }
+
+ # tests for errors when creating an account
+
+ creation_properties2 = creation_properties.copy()
+ creation_properties2[cs.ACCOUNT + '.NonExistent'] = 'foo'
+ call_async(q, am_iface, 'CreateAccount',
+ 'fakecm',
+ 'fakeprotocol',
+ 'fakeaccount',
+ params,
+ creation_properties2)
+ q.expect('dbus-error', method='CreateAccount')
+
+ params2 = params.copy()
+ params2['fake_param'] = 'foo'
+ call_async(q, am_iface, 'CreateAccount',
+ 'fakecm',
+ 'fakeprotocol',
+ 'fakeaccount',
+ params2,
+ creation_properties)
+ q.expect('dbus-error', method='CreateAccount')
+
+if __name__ == '__main__':
+ exec_test(test, {})
diff --git a/tests/twisted/account-manager/device-idle.py b/tests/twisted/account-manager/device-idle.py
new file mode 100644
index 00000000..089a0661
--- /dev/null
+++ b/tests/twisted/account-manager/device-idle.py
@@ -0,0 +1,129 @@
+# Copyright (C) 2009 Nokia Corporation
+# Copyright (C) 2009 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import config
+
+if config.HAVE_MCE:
+ print "NOTE: built with real MCE support; skipping idleness test"
+ raise SystemExit(77)
+
+import dbus.service
+
+from servicetest import EventPattern, tp_name_prefix, tp_path_prefix, \
+ call_async, unwrap, sync_dbus
+from mctest import exec_test, create_fakecm_account, SimulatedConnection, \
+ enable_fakecm_account
+import constants as cs
+
+# Fake MCE constants, cloned from mce-slacker.c
+MCE_SERVICE = "org.freedesktop.Telepathy.MissionControl.Tests.MCE"
+
+MCE_SIGNAL_IF = "org.freedesktop.Telepathy.MissionControl.Tests.MCE"
+
+MCE_REQUEST_IF = "org.freedesktop.Telepathy.MissionControl.Tests.MCE"
+MCE_REQUEST_PATH = "/org/freedesktop/Telepathy/MissionControl/Tests/MCE"
+
+class SimulatedMCE(object):
+ def __init__(self, q, bus, inactive=False):
+ self.bus = bus
+ self.q = q
+ self.inactive = inactive
+ self.object_path = MCE_REQUEST_PATH
+ self._name_ref = dbus.service.BusName(MCE_SERVICE, bus)
+
+ q.add_dbus_method_impl(self.GetInactivity,
+ path=self.object_path, interface=MCE_REQUEST_IF,
+ method='GetInactivity')
+
+
+ def GetInactivity(self, e):
+ self.q.dbus_return(e.message, self.inactive, signature='b')
+
+ def InactivityChanged(self, new_value):
+ self.inactive = new_value
+ self.q.dbus_emit(self.object_path, MCE_SIGNAL_IF, "InactivityChanged",
+ self.inactive, signature="b")
+
+ def release_name(self):
+ del self._name_ref
+
+def _create_and_enable(q, bus, mc, account_name, power_saving_supported,
+ expect_after_connect=[]):
+ extra_interfaces = []
+ if power_saving_supported:
+ extra_interfaces = [cs.CONN_IFACE_POWER_SAVING]
+ params = dbus.Dictionary({"account": account_name, "password": "secrecy"},
+ signature='sv')
+ cm_name_ref, account = create_fakecm_account(q, bus, mc, params)
+ conn = enable_fakecm_account(q, bus, mc, account, params, has_requests=False,
+ extra_interfaces=extra_interfaces,
+ expect_after_connect=expect_after_connect)
+
+ if isinstance(conn, tuple):
+ conn = conn[0]
+
+ return account, conn
+
+def _disable_account(q, bus, mc, account, conn):
+ account.Set(cs.ACCOUNT, 'Enabled', False,
+ dbus_interface=cs.PROPERTIES_IFACE)
+
+ q.expect('dbus-method-call', method='Disconnect',
+ path=conn.object_path, handled=True)
+
+def test(q, bus, mc):
+ mce = SimulatedMCE(q, bus, True)
+
+ account1, conn1 = _create_and_enable(
+ q, bus, mc, "first@example.com", True,
+ [EventPattern('dbus-method-call', method='SetPowerSaving', args=[True])])
+ account2, conn2 = _create_and_enable(q, bus, mc, "second@example.com", False)
+
+ # Second account does not support PowerSaving interface, don't call SetPowerSaving
+ forbid_no_iface =[EventPattern('dbus-method-call', method='SetPowerSaving',
+ path=conn2.object_path)]
+
+ q.forbid_events(forbid_no_iface)
+
+ for enabled in [False, True, False]:
+ mce.InactivityChanged(enabled)
+ q.expect('dbus-method-call', method='SetPowerSaving',
+ args=[enabled], interface=cs.CONN_IFACE_POWER_SAVING,
+ path=conn1.object_path)
+
+ _disable_account(q, bus, mc, account1, conn1)
+ _disable_account(q, bus, mc, account2, conn2)
+
+ q.unforbid_events(forbid_no_iface)
+
+ # Make sure we don't call SetPowerSaving on a disconnected connection.
+
+ forbid_when_disconnected =[EventPattern('dbus-method-call', method='SetPowerSaving')]
+
+ q.forbid_events(forbid_when_disconnected)
+
+ mce.InactivityChanged(True)
+
+ sync_dbus(bus, q, account1)
+
+ q.unforbid_events(forbid_when_disconnected)
+
+ mce.release_name()
+
+if __name__ == '__main__':
+ exec_test(test, {})
diff --git a/tests/twisted/account-manager/enable-auto-connect.py b/tests/twisted/account-manager/enable-auto-connect.py
new file mode 100644
index 00000000..2cb91c31
--- /dev/null
+++ b/tests/twisted/account-manager/enable-auto-connect.py
@@ -0,0 +1,69 @@
+# Copyright (C) 2009 Nokia Corporation
+# Copyright (C) 2009 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import dbus
+import dbus
+import dbus.service
+
+from servicetest import EventPattern, tp_name_prefix, tp_path_prefix, \
+ call_async
+from mctest import exec_test, create_fakecm_account
+import constants as cs
+
+def test(q, bus, mc):
+ params = dbus.Dictionary({"account": "smcv@example.com",
+ "password": "secrecy"}, signature='sv')
+ (cm_name_ref, 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
+
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'RequestedPresence',
+ (dbus.UInt32(cs.PRESENCE_TYPE_OFFLINE), 'offline', ''))
+ q.expect('dbus-return', method='Set')
+
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'AutomaticPresence',
+ (dbus.UInt32(cs.PRESENCE_TYPE_BUSY), 'busy',
+ 'Testing automatic presence'))
+ q.expect('dbus-return', method='Set')
+ q.expect('dbus-signal', signal='AccountPropertyChanged',
+ predicate=lambda e:
+ e.args[0].get('AutomaticPresence', (None, None, None))[1]
+ == 'busy')
+
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'Enabled', False)
+ q.expect('dbus-return', method='Set')
+
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'ConnectAutomatically',
+ True)
+ q.expect('dbus-return', method='Set')
+
+ # Go online by enabling the account
+ call_async(q, 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)
+
+if __name__ == '__main__':
+ exec_test(test, {})
diff --git a/tests/twisted/account-manager/enable.py b/tests/twisted/account-manager/enable.py
new file mode 100644
index 00000000..50e489d1
--- /dev/null
+++ b/tests/twisted/account-manager/enable.py
@@ -0,0 +1,62 @@
+# Copyright (C) 2009 Nokia Corporation
+# Copyright (C) 2009 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import dbus
+import dbus
+import dbus.service
+
+from servicetest import EventPattern, tp_name_prefix, tp_path_prefix, \
+ call_async
+from mctest import exec_test, create_fakecm_account
+import constants as cs
+
+def test(q, bus, mc):
+ params = dbus.Dictionary({"account": "smcv@example.com",
+ "password": "secrecy"}, signature='sv')
+ (cm_name_ref, account) = create_fakecm_account(q, bus, mc, params)
+
+ account_iface = dbus.Interface(account, cs.ACCOUNT)
+ account_props = dbus.Interface(account, cs.PROPERTIES_IFACE)
+
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'RequestedPresence',
+ (dbus.UInt32(cs.PRESENCE_TYPE_OFFLINE), 'offline', ''))
+ q.expect('dbus-return', method='Set')
+
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'Enabled', False)
+ q.expect('dbus-return', method='Set')
+
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'ConnectAutomatically',
+ False)
+ q.expect('dbus-return', method='Set')
+
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'RequestedPresence',
+ (dbus.UInt32(cs.PRESENCE_TYPE_BUSY), 'busy', 'Testing Enabled'))
+ q.expect('dbus-return', method='Set')
+
+ # Go online by setting Enabled
+ call_async(q, 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)
+
+if __name__ == '__main__':
+ exec_test(test, {})
diff --git a/tests/twisted/account-manager/make-valid.py b/tests/twisted/account-manager/make-valid.py
new file mode 100644
index 00000000..17d58049
--- /dev/null
+++ b/tests/twisted/account-manager/make-valid.py
@@ -0,0 +1,237 @@
+# Copyright (C) 2009 Nokia Corporation
+# Copyright (C) 2009 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import dbus
+"""Feature test for accounts becoming valid.
+"""
+
+import os
+
+import dbus
+import dbus.service
+
+from servicetest import EventPattern, tp_name_prefix, tp_path_prefix, \
+ call_async, sync_dbus
+from mctest import exec_test, SimulatedConnection, create_fakecm_account, \
+ make_mc
+import constants as cs
+
+cm_name_ref = dbus.service.BusName(
+ cs.tp_name_prefix + '.ConnectionManager.fakecm', bus=dbus.SessionBus())
+
+account1_id = 'fakecm/fakeprotocol/jc_2edenton_40unatco_2eint'
+account2_id = 'fakecm/fakeprotocol/jc_2edenton_40example_2ecom'
+
+def preseed():
+
+ accounts_dir = os.environ['MC_ACCOUNT_DIR']
+
+ # The passwords are missing, so the accounts can't connect yet.
+ accounts_cfg = open(accounts_dir + '/accounts.cfg', 'w')
+ accounts_cfg.write("""# Telepathy accounts
+[%s]
+manager=fakecm
+protocol=fakeprotocol
+DisplayName=Work account
+NormalizedName=jc.denton@unatco.int
+param-account=jc.denton@unatco.int
+Enabled=1
+ConnectAutomatically=1
+AutomaticPresenceType=2
+AutomaticPresenceStatus=available
+AutomaticPresenceMessage=My vision is augmented
+Nickname=JC
+AvatarMime=image/jpeg
+
+[%s]
+manager=fakecm
+protocol=fakeprotocol
+DisplayName=Personal account
+NormalizedName=jc.denton@example.com
+param-account=jc.denton@example.com
+Enabled=1
+ConnectAutomatically=0
+AutomaticPresenceType=2
+AutomaticPresenceStatus=available
+AutomaticPresenceMessage=My vision is augmented
+Nickname=JC
+AvatarMime=image/jpeg
+""" % (account1_id, account2_id))
+ accounts_cfg.close()
+
+ os.makedirs(accounts_dir + '/' + account1_id)
+ avatar_bin = open(accounts_dir + '/' + account1_id + '/avatar.bin', 'w')
+ avatar_bin.write('Deus Ex')
+ avatar_bin.close()
+
+ os.makedirs(accounts_dir + '/' + account2_id)
+ avatar_bin = open(accounts_dir + '/' + account2_id + '/avatar.bin', 'w')
+ avatar_bin.write('Invisible War')
+ avatar_bin.close()
+
+ account_connections_file = open(accounts_dir + '/.mc_connections', 'w')
+ account_connections_file.write("")
+ account_connections_file.close()
+
+def test(q, bus, unused):
+ # make sure RequestConnection doesn't get called yet
+ events = [EventPattern('dbus-method-call', method='RequestConnection')]
+ q.forbid_events(events)
+
+ # Wait for MC to load
+ mc = make_mc(bus, q.append)
+
+ q.expect_many(
+ EventPattern('dbus-signal', signal='NameOwnerChanged',
+ predicate=lambda e: e.args[0] == cs.AM),
+ EventPattern('dbus-signal', signal='NameOwnerChanged',
+ predicate=lambda e: e.args[0] == cs.CD),
+ )
+
+ # 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': 'nanotech'}, [],
+ dbus_interface=cs.ACCOUNT)
+
+ expected_params = {'password': 'nanotech',
+ 'account': 'jc.denton@unatco.int'}
+
+ 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', '_',
+ '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.CONN_STATUS_REASON_NONE)
+
+ 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_TYPE_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_TYPE_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': 'nanotech'}, [],
+ dbus_interface=cs.ACCOUNT)
+
+ expected_params = {'password': 'nanotech',
+ 'account': 'jc.denton@example.com'}
+
+ 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', '_',
+ '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.CONN_STATUS_REASON_NONE)
+
+ 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_TYPE_BUSY,
+ 'busy', 'Talking to Illuminati')
+
+if __name__ == '__main__':
+ preseed()
+ exec_test(test, {}, preload_mc=False)
diff --git a/tests/twisted/account-manager/nickname.py b/tests/twisted/account-manager/nickname.py
new file mode 100644
index 00000000..8e2fe799
--- /dev/null
+++ b/tests/twisted/account-manager/nickname.py
@@ -0,0 +1,93 @@
+# Copyright (C) 2009 Nokia Corporation
+# Copyright (C) 2009 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import dbus
+import dbus
+import dbus.service
+
+from servicetest import EventPattern, tp_name_prefix, tp_path_prefix, \
+ call_async
+from mctest import exec_test, create_fakecm_account, enable_fakecm_account
+import constants as cs
+
+def test(q, bus, mc):
+ params = dbus.Dictionary({"account": "wjt@example.com",
+ "password": "secrecy"}, signature='sv')
+ (cm_name_ref, account) = create_fakecm_account(q, bus, mc, params)
+
+ account_iface = dbus.Interface(account, cs.ACCOUNT)
+ account_props = dbus.Interface(account, cs.PROPERTIES_IFACE)
+
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'Nickname',
+ 'resiak')
+ q.expect_many(
+ EventPattern('dbus-signal',
+ path=account.object_path,
+ signal='AccountPropertyChanged',
+ interface=cs.ACCOUNT,
+ args=[{'Nickname': 'resiak'}]),
+ EventPattern('dbus-return', method='Set'),
+ )
+ assert account_props.Get(cs.ACCOUNT, 'Nickname') == 'resiak'
+
+ # OK, let's go online
+ conn, get_aliases, set_aliases = enable_fakecm_account(q, bus, mc,
+ account, params, has_aliasing=True,
+ expect_after_connect=[
+ EventPattern('dbus-method-call',
+ interface=cs.CONN_IFACE_ALIASING, method='GetAliases',
+ handled=False),
+ EventPattern('dbus-method-call',
+ interface=cs.CONN_IFACE_ALIASING, method='SetAliases',
+ handled=False),
+ ])
+
+ assert get_aliases.args[0] == [ conn.self_handle ]
+ q.dbus_return(get_aliases.message, { conn.self_handle: 'wjt@example.com' },
+ signature='a{us}')
+
+ assert set_aliases.args[0] == { conn.self_handle: 'resiak' }
+ q.dbus_return(set_aliases.message, signature='')
+
+ # Change alias after going online
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'Nickname',
+ 'Will Thomspon')
+
+ e = q.expect('dbus-method-call',
+ interface=cs.CONN_IFACE_ALIASING, method='SetAliases',
+ args=[{ conn.self_handle: 'Will Thomspon' }],
+ handled=False)
+
+ # Set returns immediately; the change happens asynchronously
+ q.expect('dbus-return', method='Set')
+
+ q.dbus_return(e.message, signature='')
+
+ someone_else = conn.ensure_handle(cs.HT_CONTACT, 'alberto@example.com')
+
+ # Another client changes our alias remotely
+ q.dbus_emit(conn.object_path, cs.CONN_IFACE_ALIASING, 'AliasesChanged',
+ dbus.Array([(conn.self_handle, 'wjt'), (someone_else, 'mardy')],
+ signature='(us)'), signature='a(us)')
+
+ q.expect('dbus-signal', path=account.object_path,
+ signal='AccountPropertyChanged', interface=cs.ACCOUNT,
+ args=[{'Nickname': 'wjt'}])
+
+if __name__ == '__main__':
+ exec_test(test, {})
diff --git a/tests/twisted/account-manager/param-types.py b/tests/twisted/account-manager/param-types.py
new file mode 100644
index 00000000..8dafd7f1
--- /dev/null
+++ b/tests/twisted/account-manager/param-types.py
@@ -0,0 +1,86 @@
+# Copyright (C) 2009 Nokia Corporation
+# Copyright (C) 2009 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import dbus
+import dbus
+import dbus.service
+
+from servicetest import EventPattern, tp_name_prefix, tp_path_prefix, \
+ call_async
+from mctest import exec_test, create_fakecm_account, get_account_manager
+import constants as cs
+
+def test(q, bus, mc):
+ cm_name_ref = dbus.service.BusName(
+ cs.tp_name_prefix + '.ConnectionManager.onewitheverything',
+ bus=bus)
+
+ # Get the AccountManager interface
+ account_manager = get_account_manager(bus)
+ account_manager_iface = dbus.Interface(account_manager, cs.AM)
+
+ params = dbus.Dictionary({
+ 's': 'lalala',
+ 'o': dbus.ObjectPath('/lalala'),
+ 'b': False,
+ 'q': dbus.UInt16(42),
+ 'u': dbus.UInt32(0xFFFFFFFFL),
+ 't': dbus.UInt64(0xFFFFffffFFFFffffL),
+ 'n': dbus.Int16(-42),
+ 'i': dbus.Int32(-42),
+ 'x': dbus.Int64(-1 * 0x7FFFffffFFFFffffL),
+ 'd': 4.5,
+ 'y': dbus.Byte(42),
+ 'as': dbus.Array(['one', 'two', 'three'], signature='s')
+ }, signature='sv')
+
+ # Create an account
+ call_async(q, account_manager_iface, 'CreateAccount',
+ 'onewitheverything', # Connection_Manager
+ 'serializable', # Protocol
+ 'fakeaccount', #Display_Name
+ params, # Parameters
+ {}, # Properties
+ )
+
+ am_signal, ret = q.expect_many(
+ EventPattern('dbus-signal', path=cs.AM_PATH,
+ interface=cs.AM, signal='AccountValidityChanged'),
+ EventPattern('dbus-return', method='CreateAccount'),
+ )
+ account_path = ret.value[0]
+ assert am_signal.args == [account_path, True], am_signal.args
+ assert account_path is not None
+
+ account = bus.get_object(
+ cs.tp_name_prefix + '.AccountManager',
+ account_path)
+ account_iface = dbus.Interface(account, cs.ACCOUNT)
+ account_props = dbus.Interface(account, cs.PROPERTIES_IFACE)
+
+ stored_params = account_props.Get(cs.ACCOUNT, 'Parameters')
+
+ for k in stored_params:
+ assert k in params, k
+
+ for k in params:
+ assert k in stored_params, k
+ assert stored_params[k] == params[k], (k, stored_params[k], params[k])
+
+if __name__ == '__main__':
+ exec_test(test, {})
diff --git a/tests/twisted/account-manager/presence.py b/tests/twisted/account-manager/presence.py
new file mode 100755
index 00000000..abef3b00
--- /dev/null
+++ b/tests/twisted/account-manager/presence.py
@@ -0,0 +1,136 @@
+# Copyright (C) 2009 Nokia Corporation
+# Copyright (C) 2009 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import dbus
+import dbus
+import dbus.service
+
+from servicetest import EventPattern, tp_name_prefix, tp_path_prefix, \
+ call_async, sync_dbus
+from mctest import exec_test, create_fakecm_account, enable_fakecm_account
+import constants as cs
+
+def test(q, bus, mc):
+ params = dbus.Dictionary({"account": "jc.denton@example.com",
+ "password": "ionstorm"}, signature='sv')
+ (cm_name_ref, account) = create_fakecm_account(q, bus, mc, params)
+
+ account_iface = dbus.Interface(account, cs.ACCOUNT)
+ account_props = dbus.Interface(account, cs.PROPERTIES_IFACE)
+
+ # Go online with a particular presence
+ presence = dbus.Struct((dbus.UInt32(cs.PRESENCE_TYPE_BUSY), 'busy',
+ 'Fighting conspiracies'), signature='uss')
+
+ log = []
+
+ # FIXME: using predicate for its side-effects here is weird
+
+ conn, _, _, _, _, _, _ = enable_fakecm_account(q, bus, mc, account, params,
+ has_presence=True,
+ requested_presence=presence,
+ expect_before_connect=[
+ EventPattern('dbus-method-call',
+ interface=cs.CONN, method='GetInterfaces',
+ args=[],
+ handled=True,
+ predicate=(lambda e: log.append('GetInterfaces') or True)),
+ EventPattern('dbus-method-call',
+ interface=cs.PROPERTIES_IFACE, method='Get',
+ args=[cs.CONN_IFACE_SIMPLE_PRESENCE, 'Statuses'],
+ handled=True,
+ predicate=(lambda e: log.append('Get(Statuses)[1]') or True)),
+ EventPattern('dbus-method-call',
+ interface=cs.CONN_IFACE_SIMPLE_PRESENCE,
+ method='SetPresence',
+ args=list(presence[1:]),
+ handled=True,
+ predicate=(lambda e: log.append('SetPresence[1]') or True)),
+ ],
+ expect_after_connect=[
+ EventPattern('dbus-method-call',
+ interface=cs.PROPERTIES_IFACE, method='Get',
+ args=[cs.CONN_IFACE_SIMPLE_PRESENCE, 'Statuses'],
+ handled=True,
+ predicate=(lambda e: log.append('Get(Statuses)[2]') or True)),
+ EventPattern('dbus-method-call',
+ interface=cs.CONN_IFACE_SIMPLE_PRESENCE,
+ method='SetPresence',
+ args=list(presence[1:]),
+ handled=True,
+ predicate=(lambda e: log.append('SetPresence[2]') or True)),
+ EventPattern('dbus-signal', path=account.object_path,
+ interface=cs.ACCOUNT, signal='AccountPropertyChanged',
+ predicate=lambda e:
+ e.args[0].get('CurrentPresence') == presence),
+ ])
+
+ # The events before Connect must happen in this order. GetInterfaces() may
+ # be called once or 2 times
+ if len(log) == 5:
+ assert log == ['GetInterfaces', 'Get(Statuses)[1]', 'SetPresence[1]',
+ 'Get(Statuses)[2]', 'SetPresence[2]'], log
+ else:
+ assert log == ['GetInterfaces', 'GetInterfaces', 'Get(Statuses)[1]', 'SetPresence[1]',
+ 'Get(Statuses)[2]', 'SetPresence[2]'], log
+
+ # Change requested presence after going online
+ presence = dbus.Struct((dbus.UInt32(cs.PRESENCE_TYPE_AWAY), 'away',
+ 'In Hong Kong'), signature='uss')
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'RequestedPresence',
+ presence)
+
+ e, _, _ = q.expect_many(
+ EventPattern('dbus-method-call',
+ interface=cs.CONN_IFACE_SIMPLE_PRESENCE, method='SetPresence',
+ args=list(presence[1:]),
+ handled=True),
+ EventPattern('dbus-signal', path=account.object_path,
+ interface=cs.ACCOUNT, signal='AccountPropertyChanged',
+ predicate=lambda e: e.args[0].get('ChangingPresence') == True and
+ e.args[0].get('RequestedPresence') == presence),
+ EventPattern('dbus-signal', path=account.object_path,
+ interface=cs.ACCOUNT, signal='AccountPropertyChanged',
+ predicate=lambda e: e.args[0].get('CurrentPresence') == presence and
+ e.args[0].get('ChangingPresence') == False))
+
+ # Setting RequestedPresence=RequestedPresence causes a (possibly redundant)
+ # call to the CM, so we get any side-effects there might be, either in the
+ # CM or in MC (e.g. asking connectivity services to go online). However,
+ # AccountPropertyChanged is not emitted for RequestedPresence.
+
+ sync_dbus(bus, q, mc)
+ events = [EventPattern('dbus-signal', signal='AccountPropertyChanged',
+ predicate=lambda e: e.args[0].get('RequestedPresence') is not None)]
+ q.forbid_events(events)
+
+ presence = dbus.Struct((dbus.UInt32(cs.PRESENCE_TYPE_AWAY), 'away',
+ 'In Hong Kong'), signature='uss')
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'RequestedPresence',
+ presence)
+
+ e = q.expect('dbus-method-call',
+ interface=cs.CONN_IFACE_SIMPLE_PRESENCE, method='SetPresence',
+ args=list(presence[1:]),
+ handled=True)
+
+ sync_dbus(bus, q, mc)
+ q.unforbid_events(events)
+
+if __name__ == '__main__':
+ exec_test(test, {})
diff --git a/tests/twisted/account-manager/reconnect.py b/tests/twisted/account-manager/reconnect.py
new file mode 100644
index 00000000..0c6ea3ad
--- /dev/null
+++ b/tests/twisted/account-manager/reconnect.py
@@ -0,0 +1,202 @@
+# Copyright (C) 2009 Nokia Corporation
+# Copyright (C) 2009 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import dbus
+import dbus
+import dbus.service
+
+from servicetest import EventPattern, tp_name_prefix, tp_path_prefix, \
+ call_async, sync_dbus
+from mctest import exec_test, SimulatedConnection, create_fakecm_account,\
+ SimulatedChannel
+import constants as cs
+
+def test(q, bus, mc):
+ cm_name_ref = dbus.service.BusName(
+ tp_name_prefix + '.ConnectionManager.fakecm', bus=bus)
+
+ # Create an account
+ params = dbus.Dictionary({"account": "someguy@example.com",
+ "password": "secrecy"}, signature='sv')
+ (cm_name_ref, account) = create_fakecm_account(q, bus, mc, params)
+
+ # Events that indicate that Reconnect might have done something
+ looks_like_reconnection = [
+ EventPattern('dbus-method-call', method='RequestConnection'),
+ EventPattern('dbus-method-call', method='Disconnect'),
+ ]
+
+ q.forbid_events(looks_like_reconnection)
+
+ # While we want to be online but the account is disabled, Reconnect is a
+ # no-op. Set Enabled to False explicitly, so we're less reliant on initial
+ # state.
+
+ call_async(q, account, 'Set', cs.ACCOUNT, 'Enabled', False,
+ dbus_interface=cs.PROPERTIES_IFACE)
+ q.expect('dbus-return', method='Set')
+
+ requested_presence = dbus.Struct((dbus.UInt32(cs.PRESENCE_TYPE_AVAILABLE),
+ dbus.String(u'available'), dbus.String(u'')))
+ call_async(q, account, 'Set', cs.ACCOUNT,
+ 'RequestedPresence', requested_presence,
+ dbus_interface=cs.PROPERTIES_IFACE)
+ q.expect('dbus-return', method='Set')
+
+ call_async(q, account, 'Reconnect', dbus_interface=cs.ACCOUNT)
+ q.expect('dbus-return', method='Reconnect')
+
+ sync_dbus(bus, q, account)
+
+ # While we want to be offline but the account is enabled, Reconnect is
+ # still a no-op.
+ requested_presence = dbus.Struct((dbus.UInt32(cs.PRESENCE_TYPE_OFFLINE),
+ dbus.String(u'offline'), dbus.String(u'')))
+ call_async(q, account, 'Set', cs.ACCOUNT,
+ 'RequestedPresence', requested_presence,
+ dbus_interface=cs.PROPERTIES_IFACE)
+ q.expect_many(
+ EventPattern('dbus-return', method='Set'),
+ EventPattern('dbus-signal',
+ path=account.object_path,
+ signal='AccountPropertyChanged',
+ interface=cs.ACCOUNT),
+ )
+
+ # Enable the account
+ call_async(q, account, 'Set', cs.ACCOUNT, 'Enabled', True,
+ dbus_interface=cs.PROPERTIES_IFACE)
+ q.expect_many(
+ EventPattern('dbus-return', method='Set'),
+ EventPattern('dbus-signal',
+ path=account.object_path,
+ signal='AccountPropertyChanged',
+ interface=cs.ACCOUNT),
+ )
+
+ call_async(q, account, 'Reconnect', dbus_interface=cs.ACCOUNT)
+ q.expect('dbus-return', method='Reconnect')
+
+ sync_dbus(bus, q, account)
+
+ # Actually go online now
+
+ q.unforbid_events(looks_like_reconnection)
+
+ requested_presence = dbus.Struct((dbus.UInt32(cs.PRESENCE_TYPE_AVAILABLE),
+ dbus.String(u'brb'), dbus.String(u'Be back soon!')))
+ account.Set(cs.ACCOUNT,
+ 'RequestedPresence', requested_presence,
+ dbus_interface=cs.PROPERTIES_IFACE)
+
+ e = q.expect('dbus-method-call', method='RequestConnection',
+ args=['fakeprotocol', params],
+ destination=tp_name_prefix + '.ConnectionManager.fakecm',
+ path=tp_path_prefix + '/ConnectionManager/fakecm',
+ interface=tp_name_prefix + '.ConnectionManager',
+ handled=False)
+
+ conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', '_',
+ 'myself')
+
+ q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so')
+
+ # MC does some setup, including fetching the list of Channels
+
+ q.expect_many(
+ EventPattern('dbus-method-call',
+ interface=cs.PROPERTIES_IFACE, method='GetAll',
+ args=[cs.CONN_IFACE_REQUESTS],
+ path=conn.object_path, handled=True),
+ )
+
+ # MC calls GetStatus (maybe) and then Connect
+
+ q.expect('dbus-method-call', method='Connect',
+ path=conn.object_path, handled=True)
+
+ # Connect succeeds
+ conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CONN_STATUS_REASON_NONE)
+
+ # Assert that the NormalizedName is harvested from the Connection at some
+ # point
+ while 1:
+ e = q.expect('dbus-signal',
+ interface=cs.ACCOUNT, signal='AccountPropertyChanged',
+ path=account.object_path)
+ if 'NormalizedName' in e.args[0]:
+ assert e.args[0]['NormalizedName'] == 'myself', e.args
+ break
+
+ # Check the requested presence is online
+ properties = account.GetAll(cs.ACCOUNT,
+ dbus_interface=cs.PROPERTIES_IFACE)
+ assert properties is not None
+ assert properties.get('RequestedPresence') == requested_presence, \
+ properties.get('RequestedPresence')
+
+ # Reconnect
+ account.Reconnect(dbus_interface=cs.ACCOUNT)
+
+ q.expect('dbus-method-call', method='Disconnect',
+ path=conn.object_path, handled=True)
+
+ e = q.expect('dbus-method-call', method='RequestConnection',
+ args=['fakeprotocol', params],
+ destination=tp_name_prefix + '.ConnectionManager.fakecm',
+ path=tp_path_prefix + '/ConnectionManager/fakecm',
+ interface=tp_name_prefix + '.ConnectionManager',
+ handled=False)
+ conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', '_',
+ 'myself')
+ q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so')
+
+ q.expect_many(
+ EventPattern('dbus-method-call',
+ interface=cs.PROPERTIES_IFACE, method='GetAll',
+ args=[cs.CONN_IFACE_REQUESTS],
+ path=conn.object_path, handled=True),
+ )
+
+ q.expect('dbus-method-call', method='Connect',
+ path=conn.object_path, handled=True)
+ conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CONN_STATUS_REASON_NONE)
+
+ # Put the account offline
+ requested_presence = (dbus.UInt32(cs.PRESENCE_TYPE_OFFLINE), 'offline', '')
+ account.Set(cs.ACCOUNT,
+ 'RequestedPresence', requested_presence,
+ dbus_interface=cs.PROPERTIES_IFACE)
+
+ # In response, MC tells us to Disconnect, and we do
+ q.expect('dbus-method-call', method='Disconnect',
+ path=conn.object_path, handled=True)
+
+ # MC terminates the channel
+ # FIXME: it shouldn't do this!
+ #q.expect('dbus-method-call', method='Close',
+ # path=chan.object_path, handled=True)
+
+ properties = account.GetAll(cs.ACCOUNT, dbus_interface=cs.PROPERTIES_IFACE)
+ assert properties['Connection'] == '/'
+ assert properties['ConnectionStatus'] == cs.CONN_STATUS_DISCONNECTED
+ assert properties['CurrentPresence'] == requested_presence
+ assert properties['RequestedPresence'] == requested_presence
+
+if __name__ == '__main__':
+ exec_test(test, {})
diff --git a/tests/twisted/account-manager/recover-from-disconnect.py b/tests/twisted/account-manager/recover-from-disconnect.py
new file mode 100644
index 00000000..aba60598
--- /dev/null
+++ b/tests/twisted/account-manager/recover-from-disconnect.py
@@ -0,0 +1,197 @@
+# Copyright (C) 2009 Nokia Corporation
+# Copyright (C) 2009-2010 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import dbus
+import dbus
+import dbus.service
+
+from servicetest import (EventPattern, tp_name_prefix, tp_path_prefix,
+ call_async, sync_dbus, assertEquals)
+from mctest import exec_test, SimulatedConnection, create_fakecm_account,\
+ SimulatedChannel
+import constants as cs
+
+def test(q, bus, mc):
+ cm_name_ref = dbus.service.BusName(
+ tp_name_prefix + '.ConnectionManager.fakecm', bus=bus)
+
+ # Create an account. We're setting register=True here to verify
+ # that after one successful connection, it'll be removed (fd.o #28118).
+ params = dbus.Dictionary({"account": "someguy@example.com",
+ "password": "secrecy",
+ "register": True}, signature='sv')
+ (cm_name_ref, account) = create_fakecm_account(q, bus, mc, params)
+
+ account_iface = dbus.Interface(account, cs.ACCOUNT)
+ account_props = dbus.Interface(account, cs.PROPERTIES_IFACE)
+
+ call_async(q, account, 'Set', cs.ACCOUNT, 'Enabled', False,
+ dbus_interface=cs.PROPERTIES_IFACE)
+ q.expect('dbus-return', method='Set')
+
+ # Enable the account
+ call_async(q, account, 'Set', cs.ACCOUNT, 'Enabled', True,
+ dbus_interface=cs.PROPERTIES_IFACE)
+
+ # Set online presence
+ presence = dbus.Struct((dbus.UInt32(cs.PRESENCE_TYPE_BUSY), 'busy',
+ 'Fixing MC bugs'), signature='uss')
+ call_async(q, account, 'Set', cs.ACCOUNT,
+ 'RequestedPresence', presence,
+ dbus_interface=cs.PROPERTIES_IFACE)
+
+ e = q.expect('dbus-method-call', method='RequestConnection',
+ args=['fakeprotocol', params],
+ destination=tp_name_prefix + '.ConnectionManager.fakecm',
+ path=tp_path_prefix + '/ConnectionManager/fakecm',
+ interface=tp_name_prefix + '.ConnectionManager',
+ handled=False)
+
+ conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', '_',
+ 'myself', has_presence=True)
+
+ q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so')
+
+ # MC calls GetStatus (maybe) and then Connect
+
+ q.expect('dbus-method-call', method='Connect',
+ path=conn.object_path, handled=True)
+
+ # Connect succeeds
+ conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CONN_STATUS_REASON_NONE)
+
+ q.expect('dbus-method-call',
+ interface=cs.CONN_IFACE_SIMPLE_PRESENCE,
+ method='SetPresence',
+ args=list(presence[1:]),
+ handled=True)
+
+ # Connection falls over for a miscellaneous reason
+ conn.ConnectionError('com.example.My.Network.Is.Full.Of.Eels',
+ {'eels': 23, 'capacity': 23, 'debug-message': 'Too many eels'})
+ conn.StatusChanged(cs.CONN_STATUS_DISCONNECTED,
+ cs.CONN_STATUS_REASON_NETWORK_ERROR)
+
+ # MC reconnects. This time, we expect it to have deleted the 'register'
+ # parameter.
+ del params['register']
+
+ disconnected, connecting, e = q.expect_many(
+ EventPattern('dbus-signal', signal='AccountPropertyChanged',
+ predicate=(lambda e:
+ e.args[0].get('ConnectionStatus') ==
+ cs.CONN_STATUS_DISCONNECTED),
+ ),
+ EventPattern('dbus-signal', signal='AccountPropertyChanged',
+ predicate=(lambda e:
+ e.args[0].get('ConnectionStatus') ==
+ cs.CONN_STATUS_CONNECTING),
+ ),
+ EventPattern('dbus-method-call', method='RequestConnection',
+ args=['fakeprotocol', params],
+ destination=tp_name_prefix + '.ConnectionManager.fakecm',
+ path=tp_path_prefix + '/ConnectionManager/fakecm',
+ interface=tp_name_prefix + '.ConnectionManager',
+ handled=False),
+ )
+
+ assertEquals('/', disconnected.args[0].get('Connection'))
+ assertEquals('com.example.My.Network.Is.Full.Of.Eels',
+ disconnected.args[0].get('ConnectionError'))
+ assertEquals(
+ {'eels': 23, 'capacity': 23, 'debug-message': 'Too many eels'},
+ disconnected.args[0].get('ConnectionErrorDetails'))
+ assertEquals(cs.CONN_STATUS_DISCONNECTED,
+ disconnected.args[0].get('ConnectionStatus'))
+ assertEquals(cs.CONN_STATUS_REASON_NETWORK_ERROR,
+ disconnected.args[0].get('ConnectionStatusReason'))
+
+ assertEquals('/', connecting.args[0].get('Connection'))
+ assertEquals('com.example.My.Network.Is.Full.Of.Eels',
+ connecting.args[0].get('ConnectionError'))
+ assertEquals(
+ {'eels': 23, 'capacity': 23, 'debug-message': 'Too many eels'},
+ connecting.args[0].get('ConnectionErrorDetails'))
+ assertEquals(cs.CONN_STATUS_CONNECTING,
+ connecting.args[0].get('ConnectionStatus'))
+ assertEquals(cs.CONN_STATUS_REASON_REQUESTED,
+ connecting.args[0].get('ConnectionStatusReason'))
+
+ conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', '_',
+ 'myself', has_presence=True)
+
+ q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so')
+
+ # MC calls GetStatus (maybe) and then Connect
+
+ connecting, _ = q.expect_many(
+ EventPattern('dbus-signal', signal='AccountPropertyChanged',
+ predicate=(lambda e:
+ e.args[0].get('ConnectionStatus') ==
+ cs.CONN_STATUS_CONNECTING),
+ ),
+ EventPattern('dbus-method-call', method='Connect',
+ path=conn.object_path, handled=True),
+ )
+
+ assertEquals(conn.object_path, connecting.args[0].get('Connection'))
+ assertEquals('com.example.My.Network.Is.Full.Of.Eels',
+ connecting.args[0].get('ConnectionError'))
+ assertEquals(
+ {'eels': 23, 'capacity': 23, 'debug-message': 'Too many eels'},
+ connecting.args[0].get('ConnectionErrorDetails'))
+ assertEquals(cs.CONN_STATUS_CONNECTING,
+ connecting.args[0].get('ConnectionStatus'))
+ assertEquals(cs.CONN_STATUS_REASON_REQUESTED,
+ connecting.args[0].get('ConnectionStatusReason'))
+
+ assertEquals('com.example.My.Network.Is.Full.Of.Eels',
+ account_props.Get(cs.ACCOUNT, 'ConnectionError'))
+ assertEquals(
+ {'eels': 23, 'capacity': 23, 'debug-message': 'Too many eels'},
+ account_props.Get(cs.ACCOUNT, 'ConnectionErrorDetails'))
+
+ # Connect succeeds
+ conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CONN_STATUS_REASON_NONE)
+
+ connected, _ = q.expect_many(
+ EventPattern('dbus-signal', signal='AccountPropertyChanged',
+ predicate=(lambda e:
+ e.args[0].get('ConnectionStatus') ==
+ cs.CONN_STATUS_CONNECTED),
+ ),
+ EventPattern('dbus-method-call',
+ interface=cs.CONN_IFACE_SIMPLE_PRESENCE,
+ method='SetPresence',
+ args=list(presence[1:]),
+ handled=True),
+ )
+
+ assertEquals(conn.object_path, connected.args[0].get('Connection'))
+ assertEquals('', connected.args[0].get('ConnectionError'))
+ assertEquals({}, connected.args[0].get('ConnectionErrorDetails'))
+ assertEquals(cs.CONN_STATUS_CONNECTED,
+ connected.args[0].get('ConnectionStatus'))
+ assertEquals(cs.CONN_STATUS_REASON_REQUESTED,
+ connected.args[0].get('ConnectionStatusReason'))
+
+ assertEquals('', account_props.Get(cs.ACCOUNT, 'ConnectionError'))
+ assertEquals({}, account_props.Get(cs.ACCOUNT, 'ConnectionErrorDetails'))
+
+if __name__ == '__main__':
+ exec_test(test, {})
diff --git a/tests/twisted/account-manager/request-online.py b/tests/twisted/account-manager/request-online.py
new file mode 100644
index 00000000..83f34f43
--- /dev/null
+++ b/tests/twisted/account-manager/request-online.py
@@ -0,0 +1,170 @@
+# Python is really rubbish. vim: set fileencoding=utf-8 :
+# Copyright © 2009–2010 Nokia Corporation
+# Copyright © 2009–2010 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import dbus
+import dbus.service
+
+from servicetest import (
+ EventPattern, tp_name_prefix, tp_path_prefix, assertEquals,
+)
+from mctest import (
+ exec_test, SimulatedConnection, create_fakecm_account,
+ SimulatedChannel, SimulatedClient, expect_client_setup,
+)
+import constants as cs
+
+def test(q, bus, mc):
+ cm_name_ref = dbus.service.BusName(
+ tp_name_prefix + '.ConnectionManager.fakecm', bus=bus)
+
+ 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": "someguy@example.com",
+ "password": "secrecy"}, signature='sv')
+ (cm_name_ref, 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_TYPE_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_TYPE_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 calls GetStatus (maybe) and then Connect
+
+ q.expect('dbus-method-call', method='Connect',
+ path=conn.object_path, handled=True)
+
+ # Connect succeeds
+ conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CONN_STATUS_REASON_NONE)
+
+ # 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_TYPE_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_TYPE_OFFLINE), 'offline', '')
+ account.Set(cs.ACCOUNT,
+ 'RequestedPresence', requested_presence,
+ dbus_interface=cs.PROPERTIES_IFACE)
+
+ # In response, MC tells us to Disconnect, and we do
+ q.expect('dbus-method-call', method='Disconnect',
+ path=conn.object_path, handled=True)
+
+ # MC terminates the channel
+ # FIXME: it shouldn't do this!
+ #q.expect('dbus-method-call', method='Close',
+ # path=chan.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'])
+
+if __name__ == '__main__':
+ exec_test(test, {})
diff --git a/tests/twisted/account-manager/server-drops-us.py b/tests/twisted/account-manager/server-drops-us.py
new file mode 100644
index 00000000..b4db423f
--- /dev/null
+++ b/tests/twisted/account-manager/server-drops-us.py
@@ -0,0 +1,128 @@
+# Copyright (C) 2009 Nokia Corporation
+# Copyright (C) 2009 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import dbus
+import dbus
+import dbus.service
+
+from servicetest import EventPattern, tp_name_prefix, tp_path_prefix, \
+ call_async, sync_dbus, TimeoutError
+from mctest import exec_test, SimulatedConnection, create_fakecm_account,\
+ SimulatedChannel
+import constants as cs
+
+params = dbus.Dictionary({"account": "someguy@example.com",
+ "password": "secrecy"}, signature='sv')
+
+def test(q, bus, mc):
+ cm_name_ref = dbus.service.BusName(
+ tp_name_prefix + '.ConnectionManager.fakecm', bus=bus)
+
+ # Create an account
+ (cm_name_ref, account) = create_fakecm_account(q, bus, mc, params)
+
+ account_iface = dbus.Interface(account, cs.ACCOUNT)
+ account_props = dbus.Interface(account, cs.PROPERTIES_IFACE)
+
+ call_async(q, account, 'Set', cs.ACCOUNT, 'Enabled', False,
+ dbus_interface=cs.PROPERTIES_IFACE)
+ q.expect('dbus-return', method='Set')
+
+ # Enable the account
+ call_async(q, account, 'Set', cs.ACCOUNT, 'Enabled', True,
+ dbus_interface=cs.PROPERTIES_IFACE)
+
+ # Set online presence
+ presence = dbus.Struct((dbus.UInt32(cs.PRESENCE_TYPE_BUSY), 'busy',
+ 'Fixing MC bugs'), signature='uss')
+ call_async(q, account, 'Set', cs.ACCOUNT,
+ 'RequestedPresence', presence,
+ dbus_interface=cs.PROPERTIES_IFACE)
+
+ e = q.expect('dbus-method-call', method='RequestConnection',
+ args=['fakeprotocol', params],
+ destination=tp_name_prefix + '.ConnectionManager.fakecm',
+ path=tp_path_prefix + '/ConnectionManager/fakecm',
+ interface=tp_name_prefix + '.ConnectionManager',
+ handled=False)
+
+ conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', '_',
+ 'myself', has_presence=True)
+
+ q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so')
+
+ # MC calls GetStatus (maybe) and then Connect
+
+ q.expect('dbus-method-call', method='Connect',
+ path=conn.object_path, handled=True)
+
+ # Connect succeeds
+ conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CONN_STATUS_REASON_NONE)
+
+ conn = drop_and_expect_reconnect(q, bus, conn)
+ conn = drop_and_expect_reconnect(q, bus, conn)
+ conn = drop_and_expect_reconnect(q, bus, conn)
+
+ forbidden = [EventPattern('dbus-method-call', method='RequestConnection')]
+ q.forbid_events(forbidden)
+
+ # Connection falls over for a miscellaneous reason
+ conn.StatusChanged(cs.CONN_STATUS_DISCONNECTED,
+ cs.CONN_STATUS_REASON_NETWORK_ERROR)
+ # Right, that's it, I'm giving up...
+
+ # This test can be considered to have succeeded if we don't
+ # RequestConnection again before the test fails due to timeout.
+ try:
+ q.expect('the end of the world')
+ except TimeoutError:
+ return
+ else:
+ raise AssertionError('An impossible event happened')
+
+def drop_and_expect_reconnect(q, bus, conn):
+ # Connection falls over for a miscellaneous reason
+ conn.StatusChanged(cs.CONN_STATUS_DISCONNECTED,
+ cs.CONN_STATUS_REASON_NETWORK_ERROR)
+
+ # MC reconnects
+
+ e = q.expect('dbus-method-call', method='RequestConnection',
+ args=['fakeprotocol', params],
+ destination=tp_name_prefix + '.ConnectionManager.fakecm',
+ path=tp_path_prefix + '/ConnectionManager/fakecm',
+ interface=tp_name_prefix + '.ConnectionManager',
+ handled=False)
+
+ conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', '_',
+ 'myself', has_presence=True)
+
+ q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so')
+
+ # MC calls GetStatus (maybe) and then Connect
+
+ q.expect('dbus-method-call', method='Connect',
+ path=conn.object_path, handled=True)
+
+ # Connect succeeds
+ conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CONN_STATUS_REASON_NONE)
+
+ return conn
+
+if __name__ == '__main__':
+ exec_test(test, {})
diff --git a/tests/twisted/account-manager/service.py b/tests/twisted/account-manager/service.py
new file mode 100644
index 00000000..f7df9903
--- /dev/null
+++ b/tests/twisted/account-manager/service.py
@@ -0,0 +1,112 @@
+# Copyright (C) 2010 Nokia Corporation
+# Copyright (C) 2010 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import dbus
+import dbus
+import dbus.service
+
+from servicetest import EventPattern, tp_name_prefix, call_async, assertEquals
+from mctest import exec_test, create_fakecm_account
+import constants as cs
+
+def test(q, bus, mc):
+ params = dbus.Dictionary({"account": "wjt@example.com",
+ "password": "secrecy"}, signature='sv')
+ (cm_name_ref, account) = create_fakecm_account(q, bus, mc, params)
+
+ srv_name = 'fu-bar-42'
+ account_iface = dbus.Interface(account, cs.ACCOUNT)
+ account_props = dbus.Interface(account, cs.PROPERTIES_IFACE)
+
+ # defaults to the empty string
+ assertEquals(account_props.Get(cs.ACCOUNT, 'Service'), '');
+
+ # set to a new value after creation
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'Service', srv_name);
+ q.expect_many(
+ EventPattern('dbus-signal',
+ path=account.object_path,
+ signal='AccountPropertyChanged',
+ interface=cs.ACCOUNT,
+ args=[{'Service': srv_name}]),
+ EventPattern('dbus-return', method='Set'),
+ )
+ assertEquals(account_props.Get(cs.ACCOUNT, 'Service'), srv_name)
+
+ # set to an invalid value (no actual change should occur)
+
+ # leading non-alphabetic (make sure _ isn't considered alphabetic)
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'Service', '_fu-bar');
+ q.expect_many(EventPattern('dbus-error', method='Set'))
+ assertEquals(account_props.Get(cs.ACCOUNT, 'Service'), srv_name)
+
+ # leading non-alphabetic
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'Service', '.moose');
+ q.expect_many(EventPattern('dbus-error', method='Set'))
+ assertEquals(account_props.Get(cs.ACCOUNT, 'Service'), srv_name)
+
+ # gregexes have an option to be lenient about trailing newlines:
+ # this makes sure we haven't made that mistake
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'Service', srv_name + '\n');
+ q.expect_many(EventPattern('dbus-error', method='Set'))
+ assertEquals(account_props.Get(cs.ACCOUNT, 'Service'), srv_name)
+
+ # set to an empty string
+ call_async(q, account_props, 'Set', cs.ACCOUNT, 'Service', '');
+ q.expect_many(EventPattern('dbus-return', method='Set'))
+ assertEquals(account_props.Get(cs.ACCOUNT, 'Service'), '')
+
+ # test creation with a service
+ account_manager = bus.get_object(cs.AM, cs.AM_PATH)
+ am_iface = dbus.Interface(account_manager, cs.AM)
+
+ service_prop = dbus.Dictionary({
+ cs.ACCOUNT + '.Service': "moomin-troll",
+ }, signature='sv')
+
+ call_async(q, am_iface, 'CreateAccount',
+ 'fakecm', # Connection_Manager
+ 'fakeprotocol', # Protocol
+ 'fakeaccount', # Display_Name
+ params, # Parameters
+ service_prop, # Properties
+ )
+
+ ret = q.expect('dbus-return', method='CreateAccount')
+ path = ret.value[0]
+ account = bus.get_object(cs.tp_name_prefix + '.AccountManager', path)
+ if_props = dbus.Interface(account, cs.PROPERTIES_IFACE)
+ props = if_props.GetAll(cs.ACCOUNT)
+ assertEquals(props.get('Service'), 'moomin-troll')
+
+ # attempt creation with a bogus service
+ service_prop = dbus.Dictionary({cs.ACCOUNT + '.Service': "1337"},
+ signature='sv')
+
+ call_async(q, am_iface, 'CreateAccount',
+ 'fakecm', # Connection_Manager
+ 'fakeprotocol', # Protocol
+ 'fakeaccount', # Display_Name
+ params, # Parameters
+ service_prop, # Properties
+ )
+
+ ret = q.expect('dbus-error', method='CreateAccount')
+
+if __name__ == '__main__':
+ exec_test(test, {})
diff --git a/tests/twisted/account-manager/update-parameters.py b/tests/twisted/account-manager/update-parameters.py
new file mode 100644
index 00000000..347a3135
--- /dev/null
+++ b/tests/twisted/account-manager/update-parameters.py
@@ -0,0 +1,194 @@
+# Copyright (C) 2009 Nokia Corporation
+# Copyright (C) 2009 Collabora Ltd.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import os
+import time
+
+import dbus
+import dbus.service
+
+from servicetest import EventPattern, tp_name_prefix, tp_path_prefix, \
+ call_async, assertEquals
+from mctest import exec_test, SimulatedConnection, create_fakecm_account,\
+ SimulatedChannel
+import constants as cs
+
+def test(q, bus, mc):
+ cm_name_ref = dbus.service.BusName(
+ tp_name_prefix + '.ConnectionManager.fakecm', bus=bus)
+
+ # Create an account
+ params = dbus.Dictionary({"account": "someguy@example.com",
+ "password": "secrecy", 'nickname': 'albinoblacksheep'}, signature='sv')
+ (cm_name_ref, account) = create_fakecm_account(q, bus, mc, params)
+
+ # Enable the account
+ account.Set(cs.ACCOUNT, 'Enabled', True,
+ dbus_interface=cs.PROPERTIES_IFACE)
+ q.expect('dbus-signal',
+ path=account.object_path,
+ signal='AccountPropertyChanged',
+ interface=cs.ACCOUNT)
+
+ # Go online
+ requested_presence = dbus.Struct((dbus.UInt32(2L), dbus.String(u'brb'),
+ dbus.String(u'Be back soon!')))
+ account.Set(cs.ACCOUNT,
+ 'RequestedPresence', requested_presence,
+ dbus_interface=cs.PROPERTIES_IFACE)
+
+ e = q.expect('dbus-method-call', method='RequestConnection',
+ args=['fakeprotocol', params],
+ destination=tp_name_prefix + '.ConnectionManager.fakecm',
+ path=tp_path_prefix + '/ConnectionManager/fakecm',
+ interface=tp_name_prefix + '.ConnectionManager',
+ handled=False)
+
+ conn = SimulatedConnection(q, bus, 'fakecm', 'fakeprotocol', '_',
+ 'myself')
+
+ q.dbus_return(e.message, conn.bus_name, conn.object_path, signature='so')
+
+ # MC does some setup, including fetching the list of Channels
+
+ q.expect_many(
+ EventPattern('dbus-method-call',
+ interface=cs.PROPERTIES_IFACE, method='GetAll',
+ args=[cs.CONN_IFACE_REQUESTS],
+ path=conn.object_path, handled=True),
+ )
+
+ # MC calls GetStatus (maybe) and then Connect
+
+ q.expect('dbus-method-call', method='Connect',
+ path=conn.object_path, handled=True)
+
+ # Connect succeeds
+ conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CONN_STATUS_REASON_NONE)
+
+ # Assert that the NormalizedName is harvested from the Connection at some
+ # point
+ while 1:
+ e = q.expect('dbus-signal',
+ interface=cs.ACCOUNT, signal='AccountPropertyChanged',
+ path=account.object_path)
+ if 'NormalizedName' in e.args[0]:
+ assert e.args[0]['NormalizedName'] == 'myself', e.args
+ break
+
+ # Check the requested presence is online
+ properties = account.GetAll(cs.ACCOUNT,
+ dbus_interface=cs.PROPERTIES_IFACE)
+ assert properties is not None
+ assert properties.get('RequestedPresence') == requested_presence, \
+ properties.get('RequestedPresence')
+
+ # Set some parameters. They include setting account to \\, as a regression
+ # test for part of fd.o #28557.
+ call_async(q, account, 'UpdateParameters',
+ {
+ 'account': r'\\',
+ 'secret-mushroom': '/Amanita muscaria/',
+ 'snakes': dbus.UInt32(42),
+ 'com.example.Badgerable.Badgered': True,
+ },
+ [],
+ dbus_interface=cs.ACCOUNT)
+
+ set_call, ret, _ = q.expect_many(
+ EventPattern('dbus-method-call',
+ path=conn.object_path,
+ interface=cs.PROPERTIES_IFACE, method='Set',
+ args=['com.example.Badgerable', 'Badgered', True],
+ handled=False),
+ EventPattern('dbus-return',
+ method='UpdateParameters'),
+ EventPattern('dbus-signal',
+ path=account.object_path,
+ interface=cs.ACCOUNT, signal='AccountPropertyChanged',
+ args=[{'Parameters': {
+ 'account': r'\\',
+ 'com.example.Badgerable.Badgered': True,
+ 'password': 'secrecy',
+ 'nickname': 'albinoblacksheep',
+ 'secret-mushroom': '/Amanita muscaria/',
+ 'snakes': 42,
+ }}]),
+ )
+
+ # the D-Bus property should be set instantly; the others will take effect
+ # on reconnection
+ not_yet = ret.value[0]
+ not_yet.sort()
+ assert not_yet == ['account', 'secret-mushroom', 'snakes'], not_yet
+
+ # Unset some parameters
+ call_async(q, account, 'UpdateParameters',
+ {},
+ ['nickname', 'com.example.Badgerable.Badgered'],
+ dbus_interface=cs.ACCOUNT)
+
+ ret, _ = q.expect_many(
+ EventPattern('dbus-return',
+ method='UpdateParameters'),
+ EventPattern('dbus-signal',
+ path=account.object_path,
+ interface=cs.ACCOUNT, signal='AccountPropertyChanged',
+ args=[{'Parameters': {
+ 'account': r'\\',
+ 'password': 'secrecy',
+ 'secret-mushroom': '/Amanita muscaria/',
+ 'snakes': 42,
+ }}]),
+ )
+
+ # there's no well-defined way to unset a D-Bus property, so it'll go back
+ # to its implied default value only after reconnection
+ #
+ # FIXME: in a perfect implementation, we know that this particular D-Bus
+ # property has a default, so maybe we should set it back to that?
+ not_yet = ret.value[0]
+ not_yet.sort()
+ assert not_yet == ['com.example.Badgerable.Badgered', 'nickname'], not_yet
+
+ accounts_dir = os.environ['MC_ACCOUNT_DIR']
+
+ # fd.o #28557: when the file has been updated, the account parameter
+ # has its two backslashes doubled to 4 (because of the .desktop encoding),
+ # but they are not doubled again.
+ i = 0
+ updated = False
+ while i < 500:
+
+ for line in open(accounts_dir +
+ '/mcp-test-diverted-account-plugin.conf', 'r'):
+ if line.startswith('param-account=') and '\\' in line:
+ assertEquals(r'param-account=\\\\' + '\n', line)
+ updated = True
+
+ if updated:
+ break
+
+ # just to not busy-wait
+ time.sleep(0.1)
+ i += 1
+
+ assert updated
+
+if __name__ == '__main__':
+ exec_test(test, {})