[telepathy-gabble/master] Test ensuring a sidecar which pings a server first

Will Thompson will.thompson at collabora.co.uk
Thu Nov 19 07:25:32 PST 2009


---
 plugins/test.c            |  207 +++++++++++++++++++++++++++++++++++++++++++++
 plugins/test.h            |   34 ++++++++
 tests/twisted/sidecars.py |   32 +++++++-
 3 files changed, 271 insertions(+), 2 deletions(-)

diff --git a/plugins/test.c b/plugins/test.c
index 3be25da..ecc1af5 100644
--- a/plugins/test.c
+++ b/plugins/test.c
@@ -24,11 +24,13 @@ static void plugin_iface_init (
 #define IFACE_TEST "org.freedesktop.Telepathy.Gabble.Plugin.Test"
 #define IFACE_TEST_PROPS IFACE_TEST ".Props"
 #define IFACE_TEST_BUGGY IFACE_TEST ".Buggy"
+#define IFACE_TEST_IQ IFACE_TEST ".IQ"
 
 static const gchar * const sidecar_interfaces[] = {
     IFACE_TEST,
     IFACE_TEST_PROPS,
     IFACE_TEST_BUGGY,
+    IFACE_TEST_IQ,
     NULL
 };
 
@@ -48,6 +50,33 @@ test_plugin_class_init (TestPluginClass *klass)
 }
 
 static void
+sidecar_iq_created_cb (
+    GObject *source,
+    GAsyncResult *new_result,
+    gpointer user_data)
+{
+  GSimpleAsyncResult *result = user_data;
+  GabbleSidecar *sidecar = GABBLE_SIDECAR (source);
+  GError *error = NULL;
+
+  if (g_async_initable_init_finish (G_ASYNC_INITABLE (source),
+          new_result, &error))
+    {
+      g_simple_async_result_set_op_res_gpointer (result, sidecar,
+          g_object_unref);
+    }
+  else
+    {
+      g_simple_async_result_set_from_error (result, error);
+      g_clear_error (&error);
+      g_object_unref (sidecar);
+    }
+
+  g_simple_async_result_complete (result);
+  g_object_unref (result);
+}
+
+static void
 test_plugin_create_sidecar (
     GabblePlugin *plugin,
     const gchar *sidecar_interface,
@@ -72,6 +101,12 @@ test_plugin_create_sidecar (
     {
       sidecar = g_object_new (TEST_TYPE_SIDECAR_PROPS, NULL);
     }
+  else if (!tp_strdiff (sidecar_interface, IFACE_TEST_IQ))
+    {
+      g_async_initable_new_async (TEST_TYPE_SIDECAR_IQ, G_PRIORITY_DEFAULT,
+          NULL, sidecar_iq_created_cb, result, "session", session, NULL);
+      return;
+    }
   else
     {
       /* This deliberately doesn't check for IFACE_TEST_BUGGY, to test Gabble's
@@ -202,5 +237,177 @@ static void sidecar_props_iface_init (
   iface->get_immutable_properties = sidecar_props_get_immutable_properties;
 }
 
+/********************************
+ * TestSidecarIQ implementation *
+ ********************************/
+
+static void sidecar_iq_iface_init (
+    gpointer g_iface,
+    gpointer data);
+static void async_initable_iface_init (
+    gpointer g_iface,
+    gpointer data);
+
+G_DEFINE_TYPE_WITH_CODE (TestSidecarIQ, test_sidecar_iq, G_TYPE_OBJECT,
+    G_IMPLEMENT_INTERFACE (GABBLE_TYPE_SIDECAR, sidecar_iq_iface_init);
+    G_IMPLEMENT_INTERFACE (GABBLE_TYPE_SVC_GABBLE_PLUGIN_TEST, NULL);
+    G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init);
+    )
+
+enum {
+    PROP_SESSION = 1
+};
+
+static void
+test_sidecar_iq_init (TestSidecarIQ *object)
+{
+  DEBUG ("%p", object);
+}
+
+static void
+test_sidecar_iq_set_property (
+    GObject *object,
+    guint property_id,
+    const GValue *value,
+    GParamSpec *pspec)
+{
+  TestSidecarIQ *self = TEST_SIDECAR_IQ (object);
+
+  switch (property_id)
+    {
+      case PROP_SESSION:
+        self->session = g_value_dup_object (value);
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+    }
+}
+
+static void
+test_sidecar_iq_dispose (GObject *object)
+{
+  TestSidecarIQ *self = TEST_SIDECAR_IQ (object);
+
+  DEBUG ("called for %p", object);
+
+  if (self->session != NULL)
+    {
+      g_object_unref (self->session);
+      self->session = NULL;
+    }
+}
+
+static void
+test_sidecar_iq_class_init (TestSidecarIQClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->set_property = test_sidecar_iq_set_property;
+  object_class->dispose = test_sidecar_iq_dispose;
+
+  g_object_class_install_property (object_class, PROP_SESSION,
+      g_param_spec_object ("session", "SESSION",
+          "THIS IS A WOCKY SESSION YOU CAN TELL BY THE TYPE",
+          WOCKY_TYPE_SESSION,
+          G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+sidecar_iq_iface_init (
+    gpointer g_iface,
+    gpointer data)
+{
+  GabbleSidecarInterface *iface = g_iface;
+
+  iface->interface = IFACE_TEST_IQ;
+  iface->get_immutable_properties = NULL;
+}
+
+static void
+iq_cb (
+    GObject *source,
+    GAsyncResult *nested_result,
+    gpointer user_data)
+{
+  GSimpleAsyncResult *result = user_data;
+  GError *error = NULL;
+  WockyXmppStanza *reply;
+
+  reply = wocky_porter_send_iq_finish (WOCKY_PORTER (source),
+      nested_result, &error);
+
+  if (reply == NULL)
+    {
+      g_simple_async_result_set_from_error (result, error);
+      g_clear_error (&error);
+    }
+  else
+    {
+      WockyStanzaSubType t;
 
+      wocky_xmpp_stanza_get_type_info (reply, NULL, &t);
 
+      if (t == WOCKY_STANZA_SUB_TYPE_RESULT)
+        g_simple_async_result_set_op_res_gboolean (result, TRUE);
+      else
+        g_simple_async_result_set_error (result, TP_ERRORS,
+            TP_ERROR_NOT_AVAILABLE, "server said no!");
+
+      g_object_unref (reply);
+    }
+
+  g_simple_async_result_complete (result);
+}
+
+static void
+sidecar_iq_init_async (
+    GAsyncInitable *initable,
+    int io_priority,
+    GCancellable *cancellable,
+    GAsyncReadyCallback callback,
+    gpointer user_data)
+{
+  TestSidecarIQ *self = TEST_SIDECAR_IQ (initable);
+  GSimpleAsyncResult *result = g_simple_async_result_new (G_OBJECT (self),
+      callback, user_data, sidecar_iq_init_async);
+  WockyPorter *porter = wocky_session_get_porter (self->session);
+  WockyXmppStanza *iq;
+
+  iq = wocky_xmpp_stanza_build (WOCKY_STANZA_TYPE_IQ,
+      WOCKY_STANZA_SUB_TYPE_GET, NULL, "sidecar.example.com",
+        WOCKY_NODE, "query",
+          WOCKY_NODE_XMLNS, "http://example.com/sidecar",
+          WOCKY_NODE, "oh-hai",
+          WOCKY_NODE_END,
+        WOCKY_NODE_END,
+      WOCKY_STANZA_END);
+  wocky_porter_send_iq_async (porter, iq, cancellable, iq_cb, result);
+}
+
+static gboolean
+sidecar_iq_init_finish (
+    GAsyncInitable *initable,
+    GAsyncResult *result,
+    GError **error)
+{
+  GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
+
+  if (g_simple_async_result_propagate_error (simple, error))
+    return FALSE;
+
+  g_return_val_if_fail (g_simple_async_result_is_valid (result,
+      G_OBJECT (initable), sidecar_iq_init_async), FALSE);
+
+  return g_simple_async_result_get_op_res_gboolean (simple);
+}
+
+static void
+async_initable_iface_init (
+    gpointer g_iface,
+    gpointer data)
+{
+  GAsyncInitableIface *iface = g_iface;
+
+  iface->init_async = sidecar_iq_init_async;
+  iface->init_finish = sidecar_iq_init_finish;
+}
diff --git a/plugins/test.h b/plugins/test.h
index d71c484..8d4d25e 100644
--- a/plugins/test.h
+++ b/plugins/test.h
@@ -1,5 +1,8 @@
 #include <glib-object.h>
 
+#include <gio/gio.h>
+#include <wocky/wocky-session.h>
+
 /* Plugin */
 typedef struct _TestPluginClass TestPluginClass;
 typedef struct _TestPlugin TestPlugin;
@@ -87,3 +90,34 @@ GType test_sidecar_props_get_type (void);
 #define TEST_SIDECAR_PROPS_GET_CLASS(obj) \
   (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_TYPE_SIDECAR_PROPS, \
                               TestSidecarPropsClass))
+
+/* Sidecar which sends an IQ and waits for a reply before being ready. */
+typedef struct _TestSidecarIQClass TestSidecarIQClass;
+typedef struct _TestSidecarIQ TestSidecarIQ;
+
+struct _TestSidecarIQClass {
+    GObjectClass parent;
+};
+
+struct _TestSidecarIQ {
+    GObject parent;
+    GSimpleAsyncResult *result;
+    WockySession *session;
+};
+
+GType test_sidecar_iq_get_type (void);
+
+#define TEST_TYPE_SIDECAR_IQ \
+  (test_sidecar_iq_get_type ())
+#define TEST_SIDECAR_IQ(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), TEST_TYPE_SIDECAR_IQ, TestSidecarIQ))
+#define TEST_SIDECAR_IQ_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), TEST_TYPE_SIDECAR_IQ, \
+                           TestSidecarIQClass))
+#define TEST_IS_SIDECAR_IQ(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), TEST_TYPE_SIDECAR_IQ))
+#define TEST_IS_SIDECAR_IQ_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), TEST_TYPE_SIDECAR_IQ))
+#define TEST_SIDECAR_IQ_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_TYPE_SIDECAR_IQ, \
+                              TestSidecarIQClass))
diff --git a/tests/twisted/sidecars.py b/tests/twisted/sidecars.py
index 6c70bef..0141fe3 100644
--- a/tests/twisted/sidecars.py
+++ b/tests/twisted/sidecars.py
@@ -2,8 +2,10 @@
 Test Gabble's implementation of sidecars, using the test plugin.
 """
 
-from servicetest import call_async, EventPattern, assertEquals, assertContains
-from gabbletest import exec_test
+from servicetest import (
+    sync_dbus, call_async, EventPattern, assertEquals, assertContains,
+    )
+from gabbletest import exec_test, send_error_reply, acknowledge_iq, sync_stream
 import constants as cs
 
 TEST_PLUGIN_IFACE = "org.freedesktop.Telepathy.Gabble.Plugin.Test"
@@ -46,6 +48,32 @@ def test(q, bus, conn, stream):
     call_async(q, conn.Future, 'EnsureSidecar', TEST_PLUGIN_IFACE + ".Buggy")
     q.expect('dbus-error', name=cs.NOT_IMPLEMENTED)
 
+    # This sidecar sends a stanza, and waits for a reply, before being created.
+    pattern = EventPattern('stream-iq', to='sidecar.example.com',
+        query_ns='http://example.com/sidecar')
+    call_async(q, conn.Future, 'EnsureSidecar', TEST_PLUGIN_IFACE + ".IQ")
+    e = q.expect_many(pattern)[0]
+
+    sync_dbus(bus, q, conn)
+
+    # If the server says no, EnsureSidecar should fail.
+    send_error_reply(stream, e.stanza)
+    q.expect('dbus-error', method='EnsureSidecar', name=cs.NOT_AVAILABLE)
+
+    # Let's try again. The plugin should get a chance to ping the server again.
+    call_async(q, conn.Future, 'EnsureSidecar', TEST_PLUGIN_IFACE + ".IQ")
+    e = q.expect_many(pattern)[0]
+
+    # The server said yes, so we should get a sidecar back!
+    acknowledge_iq(stream, e.stanza)
+    q.expect('dbus-return', method='EnsureSidecar')
+
+    # If we ask again once the plugin has been created, it should return at
+    # once without any more network traffic.
+    q.forbid_events([pattern])
+    conn.Future.EnsureSidecar(TEST_PLUGIN_IFACE + ".IQ")
+    sync_stream(q, stream)
+
     # TODO: test ensuring a sidecar that waits for something from the network,
     # disconnecting while it's waiting, and ensuring that nothing breaks
     # regardless of whether the network replies before </stream:stream> or not.
-- 
1.5.6.5




More information about the telepathy-commits mailing list