[telepathy-mission-control/master] McdConnection: fetch the initial self-presence on connection

Simon McVittie simon.mcvittie at collabora.co.uk
Mon Jun 1 11:28:18 PDT 2009


This should mean that the previous hack (assuming that SetStatus set
exactly the requested status) is no longer necessary - by downloading the
initial state, we've caught up with any missed signal emissions.

This requires some alterations to account-manager/auto-away.py to make its
Presence implementation more realistic. While there, alter it to assert
that the initial presence (available with no message) is correctly
signalled.

Some minor alterations to other presence-related tests were also needed.
---
 src/mcd-connection.c                         |   50 ++++++++++--------
 test/twisted/account-manager/auto-away.py    |   69 +++++++++++++-------------
 test/twisted/account-manager/auto-connect.py |    8 ++--
 test/twisted/account-manager/presence.py     |   13 +----
 test/twisted/mctest.py                       |   39 ++++++++++++++
 5 files changed, 107 insertions(+), 72 deletions(-)

diff --git a/src/mcd-connection.c b/src/mcd-connection.c
index 682680a..2d7bed2 100644
--- a/src/mcd-connection.c
+++ b/src/mcd-connection.c
@@ -191,28 +191,6 @@ presence_set_status_cb (TpConnection *proxy, const GError *error,
 		   G_STRFUNC, mcd_account_get_unique_name (priv->account),
                    error->message);
     }
-    /* We rely on the PresenceChanged signal to update our presence, but:
-     * - it is not emitted if the presence doesn't change
-     * - we miss a few emissions, while we wait for the readiness
-     *
-     * For this reasons, until we don't get the first PresenceChanged for our
-     * self handle, just copy the account requested presence as current
-     * presence.
-     * FIXME: remove this code is things in things in SimplePresence interface
-     * are changed.
-     */
-    if (!priv->got_presences_changed)
-    {
-        TpConnectionPresenceType presence;
-        const gchar *status, *message;
-
-        /* this is not really correct, as the requested presence might have
-         * been changed -- but we hope it didn't */
-        mcd_account_get_requested_presence (priv->account,
-                                            &presence, &status, &message);
-        g_signal_emit (weak_object, signals[SELF_PRESENCE_CHANGED], 0,
-                       presence, status, message);
-    }
 }
 
 static gboolean
@@ -385,13 +363,41 @@ on_presences_changed (TpConnection *proxy, GHashTable *presences,
 }
 
 static void
+mcd_connection_initial_presence_cb (TpConnection *proxy,
+                                    GHashTable *presences,
+                                    const GError *error,
+                                    gpointer user_data,
+                                    GObject *weak_object)
+{
+    if (error != NULL)
+    {
+        DEBUG ("GetPresences([SelfHandle]) failed: %s", error->message);
+        return;
+    }
+
+    on_presences_changed (proxy, presences, user_data, weak_object);
+}
+
+static void
 _mcd_connection_setup_presence (McdConnection *connection)
 {
     McdConnectionPrivate *priv =  connection->priv;
+    GArray *self_handle_array;
+    guint self_handle;
 
     tp_cli_connection_interface_simple_presence_connect_to_presences_changed
         (priv->tp_conn, on_presences_changed, priv, NULL,
          (GObject *)connection, NULL);
+
+    self_handle_array = g_array_new (FALSE, FALSE, sizeof (guint));
+    self_handle = tp_connection_get_self_handle (priv->tp_conn);
+    g_array_append_val (self_handle_array, self_handle);
+    tp_cli_connection_interface_simple_presence_call_get_presences
+        (priv->tp_conn, -1, self_handle_array,
+         mcd_connection_initial_presence_cb, priv, NULL,
+         (GObject *) connection);
+    g_array_free (self_handle_array, TRUE);
+
     tp_cli_dbus_properties_call_get
         (priv->tp_conn, -1, TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
          "Statuses", presence_get_statuses_cb, priv, NULL,
diff --git a/test/twisted/account-manager/auto-away.py b/test/twisted/account-manager/auto-away.py
index 6c00ea2..98fc095 100644
--- a/test/twisted/account-manager/auto-away.py
+++ b/test/twisted/account-manager/auto-away.py
@@ -6,11 +6,6 @@ from mctest import exec_test, SimulatedConnection, create_fakecm_account,\
         SimulatedChannel
 import constants as cs
 
-class PresenceConnection(SimulatedConnection):
-    def GetInterfaces(self, e):
-        self.q.dbus_return(e.message, [cs.CONN_IFACE_REQUESTS,
-            cs.CONN_IFACE_SIMPLE_PRESENCE], signature='as')
-
 def test(q, bus, mc):
     cm_name_ref = dbus.service.BusName(
             tp_name_prefix + '.ConnectionManager.fakecm', bus=bus)
@@ -65,8 +60,14 @@ def test(q, bus, mc):
             interface=tp_name_prefix + '.ConnectionManager',
             handled=False)
 
-    conn = PresenceConnection(q, bus, 'fakecm', 'fakeprotocol', '_',
-            'myself')
+    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')
 
@@ -77,34 +78,35 @@ def test(q, bus, mc):
 
     # 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_many(
-            EventPattern('dbus-method-call',
-                interface=cs.PROPERTIES_IFACE, method='GetAll',
-                args=[cs.CONN_IFACE_REQUESTS],
-                path=conn.object_path, handled=True),
+    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',
-                interface=cs.PROPERTIES_IFACE, method='Get',
-                args=[cs.CONN_IFACE_SIMPLE_PRESENCE, 'Statuses'],
-                path=conn.object_path, handled=False),
+                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]),
             )
-    q.dbus_return(get_statuses.message,
-            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)'),
-            signature='v')
+    assert signal.args[0]['CurrentPresence'] == (cs.PRESENCE_TYPE_AVAILABLE,
+        'available', '')
 
-    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=False)
-    q.dbus_return(e.message, signature='')
+    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,
@@ -126,8 +128,7 @@ def test(q, bus, mc):
             path=conn.object_path,
             interface=cs.CONN_IFACE_SIMPLE_PRESENCE, method='SetPresence',
             args=['away', ''],
-            handled=False)
-    q.dbus_return(e.message, signature='')
+            handled=True)
 
     # Unset the idle flag
     secret_debug_api.ChangeSystemFlags(dbus.UInt32(0),
@@ -139,8 +140,7 @@ def test(q, bus, mc):
             path=conn.object_path,
             interface=cs.CONN_IFACE_SIMPLE_PRESENCE, method='SetPresence',
             args=['available', 'staring at the sea'],
-            handled=False)
-    q.dbus_return(e.message, signature='')
+            handled=True)
 
     # Go to a non-Available status
     requested_presence = dbus.Struct((dbus.UInt32(cs.PRESENCE_TYPE_BUSY),
@@ -152,8 +152,7 @@ def test(q, bus, mc):
             path=conn.object_path,
             interface=cs.CONN_IFACE_SIMPLE_PRESENCE, method='SetPresence',
             args=['busy', 'in the great below'],
-            handled=False)
-    q.dbus_return(e.message, signature='')
+            handled=True)
 
     forbidden = [EventPattern('dbus-method-call',
             path=conn.object_path,
diff --git a/test/twisted/account-manager/auto-connect.py b/test/twisted/account-manager/auto-connect.py
index 90abbae..7e20dbd 100644
--- a/test/twisted/account-manager/auto-connect.py
+++ b/test/twisted/account-manager/auto-connect.py
@@ -83,7 +83,7 @@ def test(q, bus, mc):
                 handled=False),
             EventPattern('dbus-method-call', path=conn.object_path,
                 interface=cs.CONN_IFACE_SIMPLE_PRESENCE, method='SetPresence',
-                handled=False),
+                handled=True),
             EventPattern('dbus-signal', signal='AccountPropertyChanged',
                 path=account_path, interface=cs.ACCOUNT,
                 predicate=lambda e: 'ConnectionStatus' in e.args[0]),
@@ -91,11 +91,11 @@ def test(q, bus, mc):
 
     assert e.args[0]['ConnectionStatus'] == cs.CONN_STATUS_CONNECTED
 
-    q.dbus_return(set_presence.message, signature='')
-
     e = q.expect('dbus-signal', signal='AccountPropertyChanged',
             path=account_path, interface=cs.ACCOUNT,
-            predicate=lambda e: 'CurrentPresence' in e.args[0])
+            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')
 
diff --git a/test/twisted/account-manager/presence.py b/test/twisted/account-manager/presence.py
index c7967da..b68cff0 100644
--- a/test/twisted/account-manager/presence.py
+++ b/test/twisted/account-manager/presence.py
@@ -28,10 +28,9 @@ def test(q, bus, mc):
                     interface=cs.CONN_IFACE_SIMPLE_PRESENCE,
                     method='SetPresence',
                     args=list(presence[1:]),
-                    handled=False),
+                    handled=True),
                 ])
 
-    q.dbus_return(e.message, signature='')
     q.dbus_emit(conn.object_path, cs.CONN_IFACE_SIMPLE_PRESENCE,
             'PresencesChanged', {conn.self_handle: presence},
             signature='a{u(uss)}')
@@ -49,15 +48,7 @@ def test(q, bus, mc):
     e = q.expect('dbus-method-call',
         interface=cs.CONN_IFACE_SIMPLE_PRESENCE, method='SetPresence',
         args=list(presence[1:]),
-        handled=False)
-
-    # Set returns immediately; the change happens asynchronously
-    q.expect('dbus-return', method='Set')
-
-    q.dbus_return(e.message, signature='')
-    q.dbus_emit(conn.object_path, cs.CONN_IFACE_SIMPLE_PRESENCE,
-            'PresencesChanged', {conn.self_handle: presence},
-            signature='a{u(uss)}')
+        handled=True)
 
     q.expect('dbus-signal', path=account.object_path,
             interface=cs.ACCOUNT, signal='AccountPropertyChanged',
diff --git a/test/twisted/mctest.py b/test/twisted/mctest.py
index 0ad08d3..5c88df0 100644
--- a/test/twisted/mctest.py
+++ b/test/twisted/mctest.py
@@ -192,6 +192,12 @@ class SimulatedConnection(object):
                     method='ListChannels')
 
         if has_presence:
+            q.add_dbus_method_impl(self.SetPresence, path=self.object_path,
+                    interface=cs.CONN_IFACE_SIMPLE_PRESENCE,
+                    method='SetPresence')
+            q.add_dbus_method_impl(self.GetPresences, path=self.object_path,
+                    interface=cs.CONN_IFACE_SIMPLE_PRESENCE,
+                    method='GetPresences')
             q.add_dbus_method_impl(self.Get_SimplePresenceStatuses,
                     path=self.object_path, interface=cs.PROPERTIES_IFACE,
                     method='Get',
@@ -225,6 +231,8 @@ class SimulatedConnection(object):
             'error': (cs.PRESENCE_TYPE_ERROR, False, False),
             'unknown': (cs.PRESENCE_TYPE_UNKNOWN, False, False),
             }, signature='s(ubb)')
+        self.presence = dbus.Struct((cs.PRESENCE_TYPE_OFFLINE, 'offline', ''),
+                signature='uss')
 
     # not actually very relevant for MC so hard-code 0 for now
     def GetAliasFlags(self, e):
@@ -246,6 +254,35 @@ class SimulatedConnection(object):
             'MaximumAvatarBytes': 8192,
             }, signature='a{sv}')
 
+    def GetPresences(self, e):
+        ret = dbus.Dictionary(signature='u(uss)')
+        contacts = e.args[0]
+        for contact in contacts:
+            if contact == self.self_handle:
+                ret[contact] = self.presence
+            else:
+                # stub - MC doesn't care
+                ret[contact] = dbus.Struct(
+                        (cs.PRESENCE_TYPE_UNKNOWN, 'unknown', ''),
+                        signature='uss')
+        self.q.dbus_return(e.message, ret, signature='a{u(uss)}')
+
+    def SetPresence(self, e):
+        if e.args[0] in self.statuses:
+            presence = dbus.Struct((self.statuses[e.args[0]][0],
+                    e.args[0], e.args[1]), signature='uss')
+
+            if presence != self.presence:
+                self.presence = presence
+                self.q.dbus_emit(self.object_path,
+                        cs.CONN_IFACE_SIMPLE_PRESENCE, 'PresencesChanged',
+                        { self.self_handle : presence },
+                        signature='a{u(uss)}')
+
+            self.q.dbus_return(e.message, signature='')
+        else:
+            self.q.dbus_raise(cs.INVALID_ARGUMENT, 'Unknown status')
+
     def Get_SimplePresenceStatuses(self, e):
         self.q.dbus_return(e.message, self.statuses, signature='v')
 
@@ -639,6 +676,8 @@ def enable_fakecm_account(q, bus, mc, account, expected_params,
     q.expect('dbus-method-call', method='Connect',
             path=conn.object_path, handled=True)
     conn.StatusChanged(cs.CONN_STATUS_CONNECTED, cs.CONN_STATUS_REASON_NONE)
+    conn.presence = dbus.Struct((cs.PRESENCE_TYPE_AVAILABLE, 'available', ''),
+            signature='uss')
 
     expect_after_connect = list(expect_after_connect)
 
-- 
1.5.6.5



More information about the telepathy-commits mailing list