diff options
author | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2014-03-14 18:53:53 +0000 |
---|---|---|
committer | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2014-03-14 18:53:53 +0000 |
commit | 7f1c862760f371f66b0483f2dae11cd23be2de39 (patch) | |
tree | 352e5e65ac599c765f0a8574bd5d793c37c88b66 | |
parent | 881e23643166d7519969f6ab53dda2231035fbc1 (diff) | |
parent | d30d68dbb9e013cd002923608d34b8af3e1fe522 (diff) |
Merge branch 'gdbus-prep2' into next
Reviewed-by: Guillaume Desmottes
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=76120
-rw-r--r-- | telepathy-glib/Makefile.am | 1 | ||||
-rw-r--r-- | telepathy-glib/core-util.c | 183 | ||||
-rw-r--r-- | telepathy-glib/proxy.c | 6 | ||||
-rw-r--r-- | telepathy-glib/util.c | 148 | ||||
-rw-r--r-- | tests/dbus/call-cancellation.c | 333 | ||||
-rw-r--r-- | tests/dbus/connection.c | 7 | ||||
-rw-r--r-- | tests/dbus/disconnection.c | 356 | ||||
-rw-r--r-- | tests/dbus/unsupported-interface.c | 5 | ||||
-rw-r--r-- | tests/dbus/with-properties.xml | 9 | ||||
-rw-r--r-- | tests/lib/util.c | 6 | ||||
-rw-r--r-- | tools/glib-client-gen.py | 50 | ||||
-rw-r--r-- | tools/glib-ginterface-gen.py | 12 | ||||
-rw-r--r-- | tools/libglibcodegen.py | 22 | ||||
-rw-r--r-- | tools/libtpcodegen.py | 10 |
14 files changed, 650 insertions, 498 deletions
diff --git a/telepathy-glib/Makefile.am b/telepathy-glib/Makefile.am index 4d2ba3438..fd16a958c 100644 --- a/telepathy-glib/Makefile.am +++ b/telepathy-glib/Makefile.am @@ -190,6 +190,7 @@ libtelepathy_glib_core_internal_la_LIBADD = $(ALL_LIBS) libtelepathy_glib_core_internal_la_SOURCES = \ core-dbus.c \ core-proxy.c \ + core-util.c \ errors.c \ $(NULL) diff --git a/telepathy-glib/core-util.c b/telepathy-glib/core-util.c new file mode 100644 index 000000000..91f4cb610 --- /dev/null +++ b/telepathy-glib/core-util.c @@ -0,0 +1,183 @@ +/* + * util.c - Source for telepathy-glib utility functions + * Copyright © 2006-2014 Collabora Ltd. <http://www.collabora.co.uk/> + * Copyright © 2006-2008 Nokia Corporation + * + * 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 + */ + +#include <config.h> +#include <telepathy-glib/util.h> + +#include <string.h> +#include <gobject/gvaluecollector.h> + +#include <telepathy-glib/defs.h> + +/* this is the core library, we don't have debug infrastructure yet */ +#define CRITICAL(format, ...) \ + g_log (G_LOG_DOMAIN "/misc", G_LOG_LEVEL_CRITICAL, "%s: " format, \ + G_STRFUNC, ##__VA_ARGS__) +#define WARNING(format, ...) \ + g_log (G_LOG_DOMAIN "/misc", G_LOG_LEVEL_WARNING, "%s: " format, \ + G_STRFUNC, ##__VA_ARGS__) + +/** + * tp_value_array_build: (skip) + * @length: The number of elements that should be in the array + * @type: The type of the first argument. + * @...: The value of the first item in the struct followed by a list of type, + * value pairs terminated by G_TYPE_INVALID. + * + * Creates a new #GValueArray for use with structs, containing the values + * passed in as parameters. The values are copied or reffed as appropriate for + * their type. + * + * <example> + * <title> using tp_value_array_build</title> + * <programlisting> + * GValueArray *array = tp_value_array_build (2, + * G_TYPE_STRING, host, + * G_TYPE_UINT, port, + * G_TYPE_INVALID); + * </programlisting> + * </example> + * + * Returns: a newly created #GValueArray, free with tp_value_array_free() + * + * Since: 0.9.2 + */ +GValueArray * +tp_value_array_build (gsize length, + GType type, + ...) +{ + GValueArray *arr; + GType t; + va_list var_args; + char *error = NULL; + + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + arr = g_value_array_new (length); + G_GNUC_END_IGNORE_DEPRECATIONS + + va_start (var_args, type); + + for (t = type; t != G_TYPE_INVALID; t = va_arg (var_args, GType)) + { + GValue *v = arr->values + arr->n_values; + + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + g_value_array_append (arr, NULL); + G_GNUC_END_IGNORE_DEPRECATIONS + + g_value_init (v, t); + + G_VALUE_COLLECT (v, var_args, 0, &error); + + if (error != NULL) + { + CRITICAL ("%s", error); + g_free (error); + + tp_value_array_free (arr); + va_end (var_args); + return NULL; + } + } + + g_warn_if_fail (arr->n_values == length); + + va_end (var_args); + return arr; +} + +/** + * tp_value_array_unpack: (skip) + * @array: the array to unpack + * @len: The number of elements that should be in the array + * @...: a list of correctly typed pointers to store the values in + * + * Unpacks a #GValueArray into separate variables. + * + * The contents of the values aren't copied into the variables, and so become + * invalid when @array is freed. + * + * <example> + * <title>using tp_value_array_unpack</title> + * <programlisting> + * const gchar *host; + * guint port; + * + * tp_value_array_unpack (array, 2, + * &host, + * &port); + * </programlisting> + * </example> + * + * Since: 0.11.0 + */ +void +tp_value_array_unpack (GValueArray *array, + gsize len, + ...) +{ + va_list var_args; + guint i; + + va_start (var_args, len); + + for (i = 0; i < len; i++) + { + GValue *value; + char *error = NULL; + + if (G_UNLIKELY (i > array->n_values)) + { + WARNING ("More parameters than entries in the struct!"); + break; + } + + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + value = g_value_array_get_nth (array, i); + G_GNUC_END_IGNORE_DEPRECATIONS + + G_VALUE_LCOPY (value, var_args, G_VALUE_NOCOPY_CONTENTS, &error); + if (error != NULL) + { + WARNING ("%s", error); + g_free (error); + break; + } + } + + va_end (var_args); +} + +/** + * tp_value_array_free: + * @va: a #GValueArray + * + * Free @va. This is exactly the same as g_value_array_free(), but does not + * provoke deprecation warnings from GLib when used in conjunction with + * tp_value_array_build() and tp_value_array_unpack(). + * + * Since: 0.23.0 + */ +void +(tp_value_array_free) (GValueArray *va) +{ + _tp_value_array_free_inline (va); +} diff --git a/telepathy-glib/proxy.c b/telepathy-glib/proxy.c index 8db1cf461..ed57d80b2 100644 --- a/telepathy-glib/proxy.c +++ b/telepathy-glib/proxy.c @@ -383,8 +383,6 @@ struct _TpProxyPrivate { * completed */ guint pending_will_announce_calls; - gboolean dispose_has_run; - TpClientFactory *factory; }; @@ -1114,10 +1112,6 @@ tp_proxy_dispose (GObject *object) GError e = { TP_DBUS_ERRORS, TP_DBUS_ERROR_PROXY_UNREFERENCED, "Proxy unreferenced" }; - if (self->priv->dispose_has_run) - return; - self->priv->dispose_has_run = TRUE; - DEBUG ("%p", self); tp_proxy_invalidate (self, &e); diff --git a/telepathy-glib/util.c b/telepathy-glib/util.c index 0018a38a7..6f5f5110c 100644 --- a/telepathy-glib/util.c +++ b/telepathy-glib/util.c @@ -919,138 +919,6 @@ _tp_quark_array_copy (const GQuark *quarks) } /** - * tp_value_array_build: (skip) - * @length: The number of elements that should be in the array - * @type: The type of the first argument. - * @...: The value of the first item in the struct followed by a list of type, - * value pairs terminated by G_TYPE_INVALID. - * - * Creates a new #GValueArray for use with structs, containing the values - * passed in as parameters. The values are copied or reffed as appropriate for - * their type. - * - * <example> - * <title> using tp_value_array_build</title> - * <programlisting> - * GValueArray *array = tp_value_array_build (2, - * G_TYPE_STRING, host, - * G_TYPE_UINT, port, - * G_TYPE_INVALID); - * </programlisting> - * </example> - * - * Returns: a newly created #GValueArray, free with tp_value_array_free() - * - * Since: 0.9.2 - */ -GValueArray * -tp_value_array_build (gsize length, - GType type, - ...) -{ - GValueArray *arr; - GType t; - va_list var_args; - char *error = NULL; - - G_GNUC_BEGIN_IGNORE_DEPRECATIONS - arr = g_value_array_new (length); - G_GNUC_END_IGNORE_DEPRECATIONS - - va_start (var_args, type); - - for (t = type; t != G_TYPE_INVALID; t = va_arg (var_args, GType)) - { - GValue *v = arr->values + arr->n_values; - - G_GNUC_BEGIN_IGNORE_DEPRECATIONS - g_value_array_append (arr, NULL); - G_GNUC_END_IGNORE_DEPRECATIONS - - g_value_init (v, t); - - G_VALUE_COLLECT (v, var_args, 0, &error); - - if (error != NULL) - { - CRITICAL ("%s", error); - g_free (error); - - tp_value_array_free (arr); - va_end (var_args); - return NULL; - } - } - - g_warn_if_fail (arr->n_values == length); - - va_end (var_args); - return arr; -} - -/** - * tp_value_array_unpack: (skip) - * @array: the array to unpack - * @len: The number of elements that should be in the array - * @...: a list of correctly typed pointers to store the values in - * - * Unpacks a #GValueArray into separate variables. - * - * The contents of the values aren't copied into the variables, and so become - * invalid when @array is freed. - * - * <example> - * <title>using tp_value_array_unpack</title> - * <programlisting> - * const gchar *host; - * guint port; - * - * tp_value_array_unpack (array, 2, - * &host, - * &port); - * </programlisting> - * </example> - * - * Since: 0.11.0 - */ -void -tp_value_array_unpack (GValueArray *array, - gsize len, - ...) -{ - va_list var_args; - guint i; - - va_start (var_args, len); - - for (i = 0; i < len; i++) - { - GValue *value; - char *error = NULL; - - if (G_UNLIKELY (i > array->n_values)) - { - WARNING ("More parameters than entries in the struct!"); - break; - } - - G_GNUC_BEGIN_IGNORE_DEPRECATIONS - value = g_value_array_get_nth (array, i); - G_GNUC_END_IGNORE_DEPRECATIONS - - G_VALUE_LCOPY (value, var_args, G_VALUE_NOCOPY_CONTENTS, &error); - if (error != NULL) - { - WARNING ("%s", error); - g_free (error); - break; - } - } - - va_end (var_args); -} - -/** * TpWeakRef: * * A simple wrapper for a weak reference to a #GObject, suitable for use in @@ -1935,19 +1803,3 @@ _tp_g_list_copy_deep (GList *list, return ret; } - -/** - * tp_value_array_free: - * @va: a #GValueArray - * - * Free @va. This is exactly the same as g_value_array_free(), but does not - * provoke deprecation warnings from GLib when used in conjunction with - * tp_value_array_build() and tp_value_array_unpack(). - * - * Since: 0.23.0 - */ -void -(tp_value_array_free) (GValueArray *va) -{ - _tp_value_array_free_inline (va); -} diff --git a/tests/dbus/call-cancellation.c b/tests/dbus/call-cancellation.c index b54223d21..8b4ab3245 100644 --- a/tests/dbus/call-cancellation.c +++ b/tests/dbus/call-cancellation.c @@ -1,5 +1,8 @@ #include "config.h" +#include <dbus/dbus.h> +#include <dbus/dbus-glib-lowlevel.h> + #include <telepathy-glib/cli-misc.h> #include <telepathy-glib/dbus.h> #include <telepathy-glib/debug.h> @@ -10,6 +13,7 @@ #include <telepathy-glib/util.h> #include "tests/lib/myassert.h" +#include "tests/lib/simple-channel-dispatcher.h" #include "tests/lib/stub-object.h" #include "tests/lib/util.h" @@ -17,19 +21,6 @@ #define PTR(ui) GUINT_TO_POINTER(ui) /* state tracking */ -static GMainLoop *mainloop; -static TpDBusDaemon *a; -static TpDBusDaemon *b; -static TpDBusDaemon *c; -static TpDBusDaemon *d; -static TpDBusDaemon *e; -static TpDBusDaemon *f; -static TpDBusDaemon *g; -static TpDBusDaemon *h; -static TpDBusDaemon *i; -static TpDBusDaemon *j; -static TpDBusDaemon *k; -static TpDBusDaemon *z; static TpIntset *method_ok; static TpIntset *method_error; static TpIntset *freed_user_data; @@ -51,9 +42,23 @@ enum { TEST_J, TEST_K, TEST_Z = 25, - N_DAEMONS + N_PROXIES }; +typedef struct { + TpDBusDaemon *dbus_daemon; + TpProxy *proxies[N_PROXIES]; + GObject *cd_service; + + DBusConnection *private_libdbus; + DBusGConnection *private_dbusglib; + TpDBusDaemon *private_dbus_daemon; + + gboolean had_last_reply; +} Fixture; + +static Fixture *f; + static void destroy_user_data (gpointer user_data) { @@ -79,30 +84,30 @@ k_stub_destroyed (gpointer data, } static void -listed_names (TpDBusDaemon *proxy, - const gchar **names, - const GError *error, - gpointer user_data, - GObject *weak_object) +method_cb (TpProxy *proxy, + GHashTable *props, + const GError *error, + gpointer user_data, + GObject *weak_object) { guint which = GPOINTER_TO_UINT (user_data); - TpDBusDaemon *want_proxy = NULL; + TpProxy *want_proxy = NULL; GObject *want_object = NULL; if (error == NULL) { - g_message ("ListNames() succeeded (first name: %s), according to " - "user_data this was on proxy #%d '%c'", *names, which, 'a' + which); + g_message ("GetAll() succeeded, according to " + "user_data this was on proxy #%d '%c'", which, 'a' + which); tp_intset_add (method_ok, which); + want_proxy = f->proxies[which]; + switch (which) { case TEST_A: - want_proxy = a; - want_object = (GObject *) z; + want_object = (GObject *) f->proxies[TEST_Z]; break; case TEST_C: - want_proxy = c; want_object = NULL; break; case TEST_D: @@ -114,8 +119,7 @@ listed_names (TpDBusDaemon *proxy, want_object = (GObject *) copy_of_g; break; case TEST_Z: - want_proxy = z; - want_object = (GObject *) a; + want_object = (GObject *) f->proxies[TEST_A]; break; default: MYASSERT (FALSE, ": %c (%p) method call succeeded, which shouldn't " @@ -125,20 +129,19 @@ listed_names (TpDBusDaemon *proxy, } else { - g_message ("ListNames() failed (%s), according to " - "user_data this was on proxy #%d '%c'", error->message, + g_message ("GetAll() failed, according to " + "user_data this was on proxy #%d '%c'", which, 'a' + which); tp_intset_add (method_error, which); + want_proxy = f->proxies[which]; + want_object = NULL; + switch (which) { case TEST_C: - want_proxy = c; - want_object = NULL; break; case TEST_F: - want_proxy = f; - want_object = NULL; break; default: MYASSERT (FALSE, ": %c (%p) method call failed, which shouldn't " @@ -152,70 +155,120 @@ listed_names (TpDBusDaemon *proxy, weak_object, want_object); if (which == TEST_Z) - g_main_loop_quit (mainloop); + f->had_last_reply = TRUE; } static void -noc (TpDBusDaemon *proxy, - const gchar *name, - const gchar *old, - const gchar *new, +signal_cb (TpProxy *proxy, + const gchar *iface, + GHashTable *changed, + const gchar **invalidated, gpointer user_data, GObject *weak_object) { /* do nothing */ } +static void +setup (void) +{ + f->dbus_daemon = tp_tests_dbus_daemon_dup_or_die (); + + /* Any random object with an interface: what matters is that it can + * accept a method call and emit a signal. We use the Properties + * interface here. */ + f->cd_service = tp_tests_object_new_static_class ( + TP_TESTS_TYPE_SIMPLE_CHANNEL_DISPATCHER, + NULL); + tp_dbus_daemon_register_object (f->dbus_daemon, "/", f->cd_service); + + f->private_libdbus = dbus_bus_get_private (DBUS_BUS_STARTER, NULL); + g_assert (f->private_libdbus != NULL); + dbus_connection_setup_with_g_main (f->private_libdbus, NULL); + dbus_connection_set_exit_on_disconnect (f->private_libdbus, FALSE); + f->private_dbusglib = dbus_connection_get_g_connection ( + f->private_libdbus); + dbus_g_connection_ref (f->private_dbusglib); + f->private_dbus_daemon = tp_dbus_daemon_new (f->private_dbusglib); + g_assert (f->private_dbus_daemon != NULL); +} + +static void +drop_private_connection (void) +{ + dbus_g_connection_unref (f->private_dbusglib); + f->private_dbusglib = NULL; + dbus_connection_close (f->private_libdbus); + dbus_connection_unref (f->private_libdbus); + f->private_libdbus = NULL; +} + +static void +teardown (void) +{ + tp_tests_assert_last_unref (&f->cd_service); + tp_tests_assert_last_unref (&f->dbus_daemon); + + tp_tests_assert_last_unref (&f->private_dbus_daemon); +} + +static TpProxy * +new_proxy (int which) +{ + TpDBusDaemon *local_dbus_daemon; + + if (which == TEST_F) + local_dbus_daemon = f->private_dbus_daemon; + else + local_dbus_daemon = f->dbus_daemon; + + return tp_tests_object_new_static_class (TP_TYPE_PROXY, + "dbus-daemon", local_dbus_daemon, + "bus-name", tp_dbus_daemon_get_unique_name (f->dbus_daemon), + "object-path", "/", + NULL); +} + int main (int argc, char **argv) { + Fixture fixture = { NULL }; GObject *b_stub, *i_stub, *j_stub, *k_stub; GError err = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Because I said so" }; TpProxyPendingCall *pc; - gpointer tmp_obj; + guint i; tp_tests_abort_after (10); tp_debug_set_flags ("all"); - freed_user_data = tp_intset_sized_new (N_DAEMONS); - method_ok = tp_intset_sized_new (N_DAEMONS); - method_error = tp_intset_sized_new (N_DAEMONS); + freed_user_data = tp_intset_sized_new (N_PROXIES); + method_ok = tp_intset_sized_new (N_PROXIES); + method_error = tp_intset_sized_new (N_PROXIES); - mainloop = g_main_loop_new (NULL, FALSE); + /* it's on the stack, but it's valid until we leave main(), which will + * do for now... one day this test should use GTest, but this might + * not be that day */ + f = &fixture; + + setup (); - /* We use TpDBusDaemon because it's a convenient concrete subclass of - * TpProxy. */ g_message ("Creating proxies"); - a = tp_tests_dbus_daemon_dup_or_die (); - g_message ("a=%p", a); - b = tp_dbus_daemon_new (tp_proxy_get_dbus_connection (a)); - g_message ("b=%p", b); - c = tp_dbus_daemon_new (tp_proxy_get_dbus_connection (a)); - g_message ("c=%p", c); - d = tp_dbus_daemon_new (tp_proxy_get_dbus_connection (a)); - g_message ("d=%p", d); - e = tp_dbus_daemon_new (tp_proxy_get_dbus_connection (a)); - g_message ("e=%p", e); - f = tp_dbus_daemon_new (tp_proxy_get_dbus_connection (a)); - g_message ("f=%p", f); - g = tp_dbus_daemon_new (tp_proxy_get_dbus_connection (a)); - g_message ("g=%p", g); - h = tp_dbus_daemon_new (tp_proxy_get_dbus_connection (a)); - g_message ("h=%p", h); - i = tp_dbus_daemon_new (tp_proxy_get_dbus_connection (a)); - g_message ("i=%p", i); - j = tp_dbus_daemon_new (tp_proxy_get_dbus_connection (a)); - g_message ("j=%p", j); - k = tp_dbus_daemon_new (tp_proxy_get_dbus_connection (a)); - g_message ("k=%p", k); - z = tp_dbus_daemon_new (tp_proxy_get_dbus_connection (a)); - g_message ("z=%p", z); + + for (i = TEST_A; i <= TEST_K; i++) + { + f->proxies[i] = new_proxy (i); + g_message ("%c=%p", 'a' + i, f->proxies[i]); + } + + f->proxies[TEST_Z] = new_proxy (TEST_Z); + g_message ("z=%p", f->proxies[TEST_Z]); /* a survives */ g_message ("Starting call on a"); - tp_cli_dbus_daemon_call_list_names (a, -1, listed_names, PTR (TEST_A), - destroy_user_data, (GObject *) z); + tp_cli_dbus_properties_call_get_all (f->proxies[TEST_A], -1, + TP_IFACE_CHANNEL_DISPATCHER, method_cb, PTR (TEST_A), + destroy_user_data, (GObject *) f->proxies[TEST_Z]); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_A), ""); MYASSERT (!tp_intset_is_member (method_ok, TEST_A), ""); MYASSERT (!tp_intset_is_member (method_error, TEST_A), ""); @@ -225,21 +278,23 @@ main (int argc, b_stub = tp_tests_object_new_static_class (tp_tests_stub_object_get_type (), NULL); g_message ("Starting call on b"); - tp_cli_dbus_daemon_call_list_names (b, -1, listed_names, PTR (TEST_B), + tp_cli_dbus_properties_call_get_all (f->proxies[TEST_B], -1, + TP_IFACE_CHANNEL_DISPATCHER, method_cb, PTR (TEST_B), destroy_user_data, b_stub); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_B), ""); - g_object_unref (b_stub); + tp_tests_assert_last_unref (&b_stub); MYASSERT (!tp_intset_is_member (method_ok, TEST_B), ""); MYASSERT (!tp_intset_is_member (method_error, TEST_B), ""); /* c is explicitly invalidated for an application-specific reason, * but its call still proceeds */ g_message ("Starting call on c"); - tp_cli_dbus_daemon_call_list_names (c, -1, listed_names, PTR (TEST_C), + tp_cli_dbus_properties_call_get_all (f->proxies[TEST_C], -1, + TP_IFACE_CHANNEL_DISPATCHER, method_cb, PTR (TEST_C), destroy_user_data, NULL); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_C), ""); g_message ("Forcibly invalidating c"); - tp_proxy_invalidate ((TpProxy *) c, &err); + tp_proxy_invalidate (f->proxies[TEST_C], &err); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_C), ""); MYASSERT (!tp_intset_is_member (method_ok, TEST_C), ""); MYASSERT (!tp_intset_is_member (method_error, TEST_C), ""); @@ -247,14 +302,14 @@ main (int argc, /* d gets unreferenced, but survives long enough for the call to complete * successfully later, because the pending call holds a reference */ g_message ("Starting call on d"); - tp_cli_dbus_daemon_call_list_names (d, -1, listed_names, PTR (TEST_D), + tp_cli_dbus_properties_call_get_all (f->proxies[TEST_D], -1, + TP_IFACE_CHANNEL_DISPATCHER, method_cb, PTR (TEST_D), destroy_user_data, NULL); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_D), ""); g_message ("Unreferencing d"); - copy_of_d = d; + copy_of_d = f->proxies[TEST_D]; g_object_add_weak_pointer (copy_of_d, ©_of_d); - g_object_unref (d); - d = NULL; + g_clear_object (&f->proxies[TEST_D]); MYASSERT (copy_of_d != NULL, ""); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_D), ""); MYASSERT (!tp_intset_is_member (method_ok, TEST_D), ""); @@ -262,7 +317,8 @@ main (int argc, /* e gets its method call cancelled explicitly */ g_message ("Starting call on e"); - pc = tp_cli_dbus_daemon_call_list_names (e, -1, listed_names, PTR (TEST_E), + pc = tp_cli_dbus_properties_call_get_all (f->proxies[TEST_E], -1, + TP_IFACE_CHANNEL_DISPATCHER, method_cb, PTR (TEST_E), destroy_user_data, NULL); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_E), ""); g_message ("Cancelling call on e"); @@ -271,24 +327,12 @@ main (int argc, MYASSERT (!tp_intset_is_member (method_error, TEST_E), ""); /* f's method call fails with an error, because it's implicitly - * invalidated by its DBusGProxy being destroyed. - * - * Note that this test case exploits implementation details of dbus-glib. - * If it stops working after a dbus-glib upgrade, that's probably why. */ + * invalidated by its own connection disconnecting. */ g_message ("Starting call on f"); - tp_cli_dbus_daemon_call_list_names (f, -1, listed_names, PTR (TEST_F), + tp_cli_dbus_properties_call_get_all (f->proxies[TEST_F], -1, + TP_IFACE_CHANNEL_DISPATCHER, method_cb, PTR (TEST_F), destroy_user_data, NULL); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_F), ""); - g_message ("Forcibly disposing f's DBusGProxy to simulate name owner loss"); - tmp_obj = tp_proxy_get_interface_by_id ((TpProxy *) f, - TP_IFACE_QUARK_DBUS_DAEMON, NULL); - MYASSERT (tmp_obj != NULL, ""); - g_object_run_dispose (tmp_obj); - /* the callback will be queued (to avoid reentrancy), so we don't get it - * until the main loop runs */ - MYASSERT (!tp_intset_is_member (freed_user_data, TEST_F), ""); - MYASSERT (!tp_intset_is_member (method_ok, TEST_F), ""); - MYASSERT (!tp_intset_is_member (method_error, TEST_F), ""); /* g gets unreferenced, but survives long enough for the call to complete * successfully later, because the pending call holds a reference; @@ -296,14 +340,14 @@ main (int argc, * proxy. This is never necessary, but is an interesting corner case that * should be tested. */ g_message ("Starting call on g"); - tp_cli_dbus_daemon_call_list_names (g, -1, listed_names, PTR (TEST_G), - destroy_user_data, (GObject *) g); + tp_cli_dbus_properties_call_get_all (f->proxies[TEST_G], -1, + TP_IFACE_CHANNEL_DISPATCHER, method_cb, PTR (TEST_G), + destroy_user_data, (GObject *) f->proxies[TEST_G]); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_G), ""); g_message ("Unreferencing g"); - copy_of_g = g; + copy_of_g = f->proxies[TEST_G]; g_object_add_weak_pointer (copy_of_g, ©_of_g); - g_object_unref (g); - g = NULL; + g_clear_object (&f->proxies[TEST_G]); MYASSERT (copy_of_g != NULL, ""); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_G), ""); MYASSERT (!tp_intset_is_member (method_ok, TEST_G), ""); @@ -312,14 +356,14 @@ main (int argc, /* h gets unreferenced, *and* the call is cancelled (regression test for * fd.o #14576) */ g_message ("Starting call on h"); - pc = tp_cli_dbus_daemon_call_list_names (h, -1, listed_names, PTR (TEST_H), + pc = tp_cli_dbus_properties_call_get_all (f->proxies[TEST_H], -1, + TP_IFACE_CHANNEL_DISPATCHER, method_cb, PTR (TEST_H), destroy_user_data, NULL); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_H), ""); g_message ("Unreferencing h"); - copy_of_h = h; + copy_of_h = f->proxies[TEST_H]; g_object_add_weak_pointer (copy_of_h, ©_of_h); - g_object_unref (h); - h = NULL; + g_clear_object (&f->proxies[TEST_H]); MYASSERT (copy_of_h != NULL, ""); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_H), ""); MYASSERT (!tp_intset_is_member (method_ok, TEST_H), ""); @@ -336,24 +380,24 @@ main (int argc, * for the minimal regression test) */ i_stub = tp_tests_object_new_static_class (tp_tests_stub_object_get_type (), NULL); - tp_cli_dbus_daemon_connect_to_name_owner_changed (i, noc, PTR (TEST_I), - NULL, i_stub, NULL); + tp_cli_dbus_properties_connect_to_properties_changed (f->proxies[TEST_I], + signal_cb, PTR (TEST_I), NULL, i_stub, NULL); g_message ("Starting call on i"); - tp_cli_dbus_daemon_call_list_names (i, -1, listed_names, PTR (TEST_I), + tp_cli_dbus_properties_call_get_all (f->proxies[TEST_I], -1, + TP_IFACE_CHANNEL_DISPATCHER, method_cb, PTR (TEST_I), destroy_user_data, i_stub); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_I), ""); - tp_cli_dbus_daemon_connect_to_name_owner_changed (i, noc, PTR (TEST_I), - NULL, i_stub, NULL); + tp_cli_dbus_properties_connect_to_properties_changed (f->proxies[TEST_I], + signal_cb, PTR (TEST_I), NULL, i_stub, NULL); g_message ("Unreferencing i"); - copy_of_i = i; + copy_of_i = f->proxies[TEST_I]; g_object_add_weak_pointer (copy_of_i, ©_of_i); - g_object_unref (i); - i = NULL; + g_clear_object (&f->proxies[TEST_I]); MYASSERT (copy_of_i != NULL, ""); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_I), ""); MYASSERT (!tp_intset_is_member (method_ok, TEST_I), ""); MYASSERT (!tp_intset_is_member (method_error, TEST_I), ""); - g_object_unref (i_stub); + tp_tests_assert_last_unref (&i_stub); MYASSERT (!tp_intset_is_member (method_ok, TEST_I), ""); MYASSERT (!tp_intset_is_member (method_error, TEST_I), ""); @@ -363,7 +407,8 @@ main (int argc, NULL); g_object_weak_ref (j_stub, j_stub_destroyed, PTR (TEST_J)); g_message ("Starting call on j"); - pc = tp_cli_dbus_daemon_call_list_names (j, -1, listed_names, j_stub, + pc = tp_cli_dbus_properties_call_get_all (f->proxies[TEST_J], -1, + TP_IFACE_CHANNEL_DISPATCHER, method_cb, j_stub, g_object_unref, j_stub); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_J), ""); g_message ("Cancelling call on j"); @@ -379,27 +424,41 @@ main (int argc, NULL); g_message ("Starting call on k"); g_object_weak_ref (k_stub, k_stub_destroyed, &pc); - tp_cli_dbus_daemon_call_list_names (k, -1, listed_names, PTR (TEST_K), + tp_cli_dbus_properties_call_get_all (f->proxies[TEST_K], -1, + TP_IFACE_CHANNEL_DISPATCHER, method_cb, PTR (TEST_K), destroy_user_data, k_stub); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_K), ""); MYASSERT (!tp_intset_is_member (method_ok, TEST_K), ""); MYASSERT (!tp_intset_is_member (method_error, TEST_K), ""); - g_object_unref (k_stub); + tp_tests_assert_last_unref (&k_stub); MYASSERT (!tp_intset_is_member (method_ok, TEST_K), ""); MYASSERT (!tp_intset_is_member (method_error, TEST_K), ""); /* z survives too; we assume that method calls succeed in order, * so when z has had its reply, we can stop the main loop */ g_message ("Starting call on z"); - tp_cli_dbus_daemon_call_list_names (z, -1, listed_names, PTR (TEST_Z), - destroy_user_data, (GObject *) a); + tp_cli_dbus_properties_call_get_all (f->proxies[TEST_Z], -1, + TP_IFACE_CHANNEL_DISPATCHER, method_cb, PTR (TEST_Z), + destroy_user_data, (GObject *) f->proxies[TEST_A]); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_Z), ""); MYASSERT (!tp_intset_is_member (method_ok, TEST_Z), ""); MYASSERT (!tp_intset_is_member (method_error, TEST_Z), ""); + g_message ("Dropping private D-Bus connection"); + drop_private_connection (); + /* the callback will be queued (to avoid reentrancy), so we don't get it + * until the main loop runs */ + MYASSERT (!tp_intset_is_member (freed_user_data, TEST_F), ""); + MYASSERT (!tp_intset_is_member (method_ok, TEST_F), ""); + MYASSERT (!tp_intset_is_member (method_error, TEST_F), ""); + g_message ("Running main loop"); - g_main_loop_run (mainloop); - g_main_loop_unref (mainloop); + + /* There's no guarantee that proxy F will detect that its socket closed + * in any particular order relative to the signals, so wait for both. */ + while (!f->had_last_reply || + tp_proxy_get_invalidated (f->proxies[TEST_F]) == NULL) + g_main_context_iteration (NULL, TRUE); /* now that the calls have been delivered, d will finally have gone away */ MYASSERT (tp_intset_is_member (freed_user_data, TEST_D), ""); @@ -445,26 +504,18 @@ main (int argc, MYASSERT (!tp_intset_is_member (method_error, TEST_Z), ""); g_message ("Dereferencing remaining proxies"); - g_object_unref (a); - a = NULL; - g_object_unref (b); - b = NULL; - g_object_unref (c); - c = NULL; - MYASSERT (d == NULL, ""); - g_object_unref (e); - e = NULL; - g_object_unref (f); - f = NULL; - MYASSERT (g == NULL, ""); - MYASSERT (h == NULL, ""); - MYASSERT (i == NULL, ""); - g_object_unref (j); - j = NULL; - g_object_unref (k); - k = NULL; - g_object_unref (z); - z = NULL; + tp_tests_assert_last_unref (&f->proxies[TEST_A]); + tp_tests_assert_last_unref (&f->proxies[TEST_B]); + tp_tests_assert_last_unref (&f->proxies[TEST_C]); + g_assert (f->proxies[TEST_D] == NULL); + tp_tests_assert_last_unref (&f->proxies[TEST_E]); + tp_tests_assert_last_unref (&f->proxies[TEST_F]); + g_assert (f->proxies[TEST_G] == NULL); + g_assert (f->proxies[TEST_H] == NULL); + g_assert (f->proxies[TEST_I] == NULL); + tp_tests_assert_last_unref (&f->proxies[TEST_J]); + tp_tests_assert_last_unref (&f->proxies[TEST_K]); + tp_tests_assert_last_unref (&f->proxies[TEST_Z]); /* we should already have checked each of these at least once, but just to * make sure we have a systematic test that all user data is freed... */ @@ -485,5 +536,7 @@ main (int argc, tp_intset_destroy (method_ok); tp_intset_destroy (method_error); + teardown (); + return 0; } diff --git a/tests/dbus/connection.c b/tests/dbus/connection.c index 33f77fcd1..1441c48ca 100644 --- a/tests/dbus/connection.c +++ b/tests/dbus/connection.c @@ -280,6 +280,7 @@ test_object_path (Test *test, "simple_protocol"); /* Register the same connection with an invalid object path */ + tp_dbus_daemon_unregister_object (test->dbus, test->service_conn); tp_dbus_daemon_register_object (test->dbus, invalid_path, test->service_conn); tp_dbus_daemon_request_name (test->dbus, invalid_name, FALSE, &error); g_assert_no_error (error); @@ -289,6 +290,12 @@ test_object_path (Test *test, g_assert (connection == NULL); g_assert_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_INVALID_OBJECT_PATH); g_clear_error (&error); + + /* Put it back where it was meant to be so we can do teardown. */ + tp_dbus_daemon_unregister_object (test->dbus, test->service_conn); + tp_dbus_daemon_register_object (test->dbus, + tp_base_connection_get_object_path (test->service_conn_as_base), + test->service_conn); } int diff --git a/tests/dbus/disconnection.c b/tests/dbus/disconnection.c index d2efcfa76..edf2dfe44 100644 --- a/tests/dbus/disconnection.c +++ b/tests/dbus/disconnection.c @@ -1,5 +1,8 @@ #include "config.h" +#include <dbus/dbus.h> +#include <dbus/dbus-glib-lowlevel.h> + #include <telepathy-glib/cli-misc.h> #include <telepathy-glib/dbus.h> #include <telepathy-glib/debug.h> @@ -7,9 +10,11 @@ #include <telepathy-glib/interfaces.h> #include <telepathy-glib/intset.h> #include <telepathy-glib/proxy-subclass.h> /* for _invalidated etc. */ +#include <telepathy-glib/svc-generic.h> #include <telepathy-glib/util.h> #include "tests/lib/myassert.h" +#include "tests/lib/simple-channel-dispatcher.h" #include "tests/lib/stub-object.h" #include "tests/lib/util.h" @@ -17,16 +22,6 @@ #define PTR(ui) GUINT_TO_POINTER(ui) /* state tracking */ -static GMainLoop *mainloop; -static TpDBusDaemon *a; -static TpDBusDaemon *b; -static TpDBusDaemon *c; -static TpDBusDaemon *d; -static TpDBusDaemon *e; -static TpDBusDaemon *f; -static TpDBusDaemon *g; -static TpDBusDaemon *h; -static TpDBusDaemon *z; static TpIntset *caught_signal; static TpIntset *freed_user_data; @@ -40,9 +35,21 @@ enum { TEST_G, TEST_H, TEST_Z = 25, - N_DAEMONS + N_PROXIES }; +typedef struct { + TpDBusDaemon *dbus_daemon; + TpProxy *proxies[N_PROXIES]; + GObject *cd_service; + + DBusConnection *private_libdbus; + DBusGConnection *private_dbusglib; + TpDBusDaemon *private_dbus_daemon; +} Fixture; + +static Fixture *f; + static void h_stub_destroyed (gpointer data, GObject *stub) @@ -62,58 +69,44 @@ destroy_user_data (gpointer user_data) } static void -requested_name (TpDBusDaemon *proxy, - guint result, - const GError *error, - gpointer user_data, - GObject *weak_object) +unwanted_signal_cb (TpProxy *proxy, + const gchar *iface, + GHashTable *changed, + const gchar **invalidated, + gpointer user_data, + GObject *weak_object) { - g_message ("RequestName raised %s", - (error == NULL ? "no error" : error->message)); - /* we're on a private bus, so certainly nobody else should own this name */ - g_assert_no_error ((GError *) error); - MYASSERT (result == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER, ": %u", result); -} - -static void -dummy_noc (TpDBusDaemon *proxy, - const gchar *name, - const gchar *old, - const gchar *new, - gpointer user_data, - GObject *weak_object) -{ - g_error ("dummy_noc called - a signal connection which should have " + g_error ("unwanted_signal_cb called - a signal connection which should have " "failed has succeeded. Args: proxy=%p user_data=%p", proxy, user_data); } static void -noc (TpDBusDaemon *proxy, - const gchar *name, - const gchar *old, - const gchar *new, - gpointer user_data, - GObject *weak_object) +signal_cb (TpProxy *proxy, + const gchar *iface, + GHashTable *changed, + const gchar **invalidated, + gpointer user_data, + GObject *weak_object) { guint which = GPOINTER_TO_UINT (user_data); - TpDBusDaemon *want_proxy = NULL; + TpProxy *want_proxy = NULL; GObject *want_object = NULL; - g_message ("Caught signal (%s: %s -> %s) with proxy #%d '%c' according to " - "user_data", name, old, new, which, 'a' + which); + g_message ("Caught signal with proxy #%d '%c' according to " + "user_data", which, 'a' + which); g_message ("Proxy is %p, weak object is %p", proxy, weak_object); tp_intset_add (caught_signal, which); + want_proxy = f->proxies[which]; + switch (which) { case TEST_A: - want_proxy = a; - want_object = (GObject *) z; + want_object = (GObject *) f->proxies[TEST_Z]; break; case TEST_Z: - want_proxy = z; - want_object = (GObject *) a; + want_object = (GObject *) f->proxies[TEST_A]; break; default: g_error ("%c (%p) got the signal, which shouldn't have happened", @@ -125,13 +118,6 @@ noc (TpDBusDaemon *proxy, MYASSERT (proxy == want_proxy, ": %p != %p", proxy, want_proxy); MYASSERT (weak_object == want_object, ": %p != %p", weak_object, want_object); - - if (tp_intset_is_member (caught_signal, TEST_A) && - tp_intset_is_member (caught_signal, TEST_Z)) - { - /* we've had all the signals we're going to */ - g_main_loop_quit (mainloop); - } } static void @@ -143,51 +129,108 @@ set_freed (gpointer user_data) *boolptr = TRUE; } +static void +setup (void) +{ + f->dbus_daemon = tp_tests_dbus_daemon_dup_or_die (); + + /* Any random object with an interface: what matters is that it can + * accept a method call and emit a signal. We use the Properties + * interface here. */ + f->cd_service = tp_tests_object_new_static_class ( + TP_TESTS_TYPE_SIMPLE_CHANNEL_DISPATCHER, + NULL); + tp_dbus_daemon_register_object (f->dbus_daemon, "/", f->cd_service); + + f->private_libdbus = dbus_bus_get_private (DBUS_BUS_STARTER, NULL); + g_assert (f->private_libdbus != NULL); + dbus_connection_setup_with_g_main (f->private_libdbus, NULL); + dbus_connection_set_exit_on_disconnect (f->private_libdbus, FALSE); + f->private_dbusglib = dbus_connection_get_g_connection ( + f->private_libdbus); + dbus_g_connection_ref (f->private_dbusglib); + f->private_dbus_daemon = tp_dbus_daemon_new (f->private_dbusglib); + g_assert (f->private_dbus_daemon != NULL); +} + +static void +drop_private_connection (void) +{ + dbus_g_connection_unref (f->private_dbusglib); + f->private_dbusglib = NULL; + dbus_connection_close (f->private_libdbus); + dbus_connection_unref (f->private_libdbus); + f->private_libdbus = NULL; +} + +static void +teardown (void) +{ + tp_tests_assert_last_unref (&f->cd_service); + tp_tests_assert_last_unref (&f->dbus_daemon); + + tp_tests_assert_last_unref (&f->private_dbus_daemon); +} + +static TpProxy * +new_proxy (int which) +{ + TpDBusDaemon *local_dbus_daemon; + + if (which == TEST_F) + local_dbus_daemon = f->private_dbus_daemon; + else + local_dbus_daemon = f->dbus_daemon; + + return tp_tests_object_new_static_class (TP_TYPE_PROXY, + "dbus-daemon", local_dbus_daemon, + "bus-name", tp_dbus_daemon_get_unique_name (f->dbus_daemon), + "object-path", "/", + NULL); +} + int main (int argc, char **argv) { + Fixture fixture = { NULL }; GObject *stub; GError *error_out = NULL; GError err = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Because I said so" }; TpProxySignalConnection *sc; - gpointer tmp_obj; gboolean freed = FALSE; + GHashTable *empty_asv; + int i; tp_tests_abort_after (10); tp_debug_set_flags ("all"); - freed_user_data = tp_intset_sized_new (N_DAEMONS); - caught_signal = tp_intset_sized_new (N_DAEMONS); + freed_user_data = tp_intset_sized_new (N_PROXIES); + caught_signal = tp_intset_sized_new (N_PROXIES); + + /* it's on the stack, but it's valid until we leave main(), which will + * do for now... one day this test should use GTest, but this might + * not be that day */ + f = &fixture; - mainloop = g_main_loop_new (NULL, FALSE); + setup (); - /* We use TpDBusDaemon because it's a convenient concrete subclass of - * TpProxy. */ g_message ("Creating proxies"); - a = tp_tests_dbus_daemon_dup_or_die (); - g_message ("a=%p", a); - b = tp_dbus_daemon_new (tp_proxy_get_dbus_connection (a)); - g_message ("b=%p", b); - c = tp_dbus_daemon_new (tp_proxy_get_dbus_connection (a)); - g_message ("c=%p", c); - d = tp_dbus_daemon_new (tp_proxy_get_dbus_connection (a)); - g_message ("d=%p", d); - e = tp_dbus_daemon_new (tp_proxy_get_dbus_connection (a)); - g_message ("e=%p", e); - f = tp_dbus_daemon_new (tp_proxy_get_dbus_connection (a)); - g_message ("f=%p", f); - g = tp_dbus_daemon_new (tp_proxy_get_dbus_connection (a)); - g_message ("g=%p", g); - h = tp_dbus_daemon_new (tp_proxy_get_dbus_connection (a)); - g_message ("h=%p", h); - z = tp_dbus_daemon_new (tp_proxy_get_dbus_connection (a)); - g_message ("z=%p", z); + + for (i = TEST_A; i <= TEST_H; i++) + { + f->proxies[i] = new_proxy (i); + g_message ("%c=%p", 'a' + i, f->proxies[i]); + } + + f->proxies[TEST_Z] = new_proxy (TEST_Z); + g_message ("z=%p", f->proxies[TEST_Z]); /* a survives */ g_message ("Connecting signal to a"); - tp_cli_dbus_daemon_connect_to_name_owner_changed (a, noc, PTR (TEST_A), - destroy_user_data, (GObject *) z, &error_out); + tp_cli_dbus_properties_connect_to_properties_changed (f->proxies[TEST_A], + signal_cb, PTR (TEST_A), + destroy_user_data, (GObject *) f->proxies[TEST_Z], &error_out); g_assert_no_error (error_out); /* b gets its signal connection cancelled because stub is @@ -195,24 +238,27 @@ main (int argc, stub = tp_tests_object_new_static_class (tp_tests_stub_object_get_type (), NULL); g_message ("Connecting signal to b"); - tp_cli_dbus_daemon_connect_to_name_owner_changed (b, noc, PTR (TEST_B), + tp_cli_dbus_properties_connect_to_properties_changed (f->proxies[TEST_B], + signal_cb, PTR (TEST_B), destroy_user_data, stub, &error_out); g_assert_no_error (error_out); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_B), ""); - g_object_unref (stub); + tp_tests_assert_last_unref (&stub); /* c gets its signal connection cancelled because it's explicitly * invalidated */ g_message ("Connecting signal to c"); - tp_cli_dbus_daemon_connect_to_name_owner_changed (c, noc, PTR (TEST_C), + tp_cli_dbus_properties_connect_to_properties_changed (f->proxies[TEST_C], + signal_cb, PTR (TEST_C), destroy_user_data, NULL, &error_out); g_assert_no_error (error_out); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_C), ""); g_message ("Forcibly invalidating c"); - tp_proxy_invalidate ((TpProxy *) c, &err); + tp_proxy_invalidate ((TpProxy *) f->proxies[TEST_C], &err); /* assert that connecting to a signal on an invalid proxy fails */ freed = FALSE; - tp_cli_dbus_daemon_connect_to_name_owner_changed (c, dummy_noc, &freed, + tp_cli_dbus_properties_connect_to_properties_changed (f->proxies[TEST_C], + unwanted_signal_cb, &freed, set_freed, NULL, &error_out); MYASSERT (freed, ""); MYASSERT (error_out != NULL, ""); @@ -226,20 +272,18 @@ main (int argc, /* d gets its signal connection cancelled because it's * implicitly invalidated by being destroyed */ g_message ("Connecting signal to d"); - tp_cli_dbus_daemon_connect_to_name_owner_changed (d, noc, PTR (TEST_D), + tp_cli_dbus_properties_connect_to_properties_changed (f->proxies[TEST_D], + signal_cb, PTR (TEST_D), destroy_user_data, NULL, &error_out); g_assert_no_error (error_out); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_D), ""); g_message ("Destroying d"); - tmp_obj = d; - g_object_add_weak_pointer (tmp_obj, &tmp_obj); - g_object_unref (d); - MYASSERT (tmp_obj == NULL, ""); - d = NULL; + tp_tests_assert_last_unref (&f->proxies[TEST_D]); /* e gets its signal connection cancelled explicitly */ g_message ("Connecting signal to e"); - sc = tp_cli_dbus_daemon_connect_to_name_owner_changed (e, noc, PTR (TEST_E), + sc = tp_cli_dbus_properties_connect_to_properties_changed ( + f->proxies[TEST_E], signal_cb, PTR (TEST_E), destroy_user_data, NULL, &error_out); g_assert_no_error (error_out); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_E), ""); @@ -247,45 +291,26 @@ main (int argc, tp_proxy_signal_connection_disconnect (sc); /* f gets its signal connection cancelled because it's implicitly - * invalidated by its DBusGProxy being destroyed. - * - * Note that this test case exploits implementation details of dbus-glib. - * If it stops working after a dbus-glib upgrade, that's probably why. */ + * invalidated by its own connection disconnecting. */ g_message ("Connecting signal to f"); - tp_cli_dbus_daemon_connect_to_name_owner_changed (f, noc, PTR (TEST_F), + tp_cli_dbus_properties_connect_to_properties_changed (f->proxies[TEST_F], + signal_cb, PTR (TEST_F), destroy_user_data, NULL, &error_out); g_assert_no_error (error_out); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_F), ""); - g_message ("Forcibly disposing f's DBusGProxy to simulate name owner loss"); - tmp_obj = tp_proxy_get_interface_by_id ((TpProxy *) f, - TP_IFACE_QUARK_DBUS_DAEMON, NULL); - MYASSERT (tmp_obj != NULL, ""); - g_object_run_dispose (tmp_obj); - /* assert that connecting to a signal on an invalid proxy fails */ - freed = FALSE; - tp_cli_dbus_daemon_connect_to_name_owner_changed (f, dummy_noc, &freed, - set_freed, NULL, &error_out); - MYASSERT (freed, ""); - MYASSERT (error_out != NULL, ""); - MYASSERT (error_out->code == DBUS_GERROR_NAME_HAS_NO_OWNER, ""); - g_error_free (error_out); - error_out = NULL; /* g gets its signal connection cancelled because it's * implicitly invalidated by being destroyed; unlike d, the signal * connection weakly references the proxy. This is never necessary, but is * an interesting corner case that should be tested. */ g_message ("Connecting signal to g"); - tp_cli_dbus_daemon_connect_to_name_owner_changed (g, noc, PTR (TEST_G), - destroy_user_data, (GObject *) g, &error_out); + tp_cli_dbus_properties_connect_to_properties_changed (f->proxies[TEST_G], + signal_cb, PTR (TEST_G), + destroy_user_data, (GObject *) f->proxies[TEST_G], &error_out); g_assert_no_error (error_out); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_G), ""); g_message ("Destroying g"); - tmp_obj = g; - g_object_add_weak_pointer (tmp_obj, &tmp_obj); - g_object_unref (g); - MYASSERT (tmp_obj == NULL, ""); - g = NULL; + tp_tests_assert_last_unref (&f->proxies[TEST_G]); /* h gets its signal connection cancelled because its weak object is * destroyed, meaning there are simultaneously two reasons for it to become @@ -294,38 +319,74 @@ main (int argc, NULL); g_object_weak_ref (stub, h_stub_destroyed, &sc); g_message ("Connecting signal to h"); - tp_cli_dbus_daemon_connect_to_name_owner_changed (h, noc, PTR (TEST_H), + tp_cli_dbus_properties_connect_to_properties_changed (f->proxies[TEST_H], + signal_cb, PTR (TEST_H), destroy_user_data, stub, &error_out); g_assert_no_error (error_out); MYASSERT (!tp_intset_is_member (freed_user_data, TEST_H), ""); - g_object_unref (stub); + tp_tests_assert_last_unref (&stub); /* z survives; we assume that the signals are delivered in either * forward or reverse order, so if both a and z have had their signal, we * can stop the main loop */ g_message ("Connecting signal to z"); - tp_cli_dbus_daemon_connect_to_name_owner_changed (z, noc, PTR (TEST_Z), - destroy_user_data, (GObject *) a, &error_out); + tp_cli_dbus_properties_connect_to_properties_changed (f->proxies[TEST_Z], + signal_cb, PTR (TEST_Z), + destroy_user_data, (GObject *) f->proxies[TEST_A], &error_out); g_assert_no_error (error_out); - /* make sure a NameOwnerChanged signal occurs */ - g_message ("Requesting name"); - tp_cli_dbus_daemon_call_request_name (a, -1, "com.example.NameTest", - 0, requested_name, NULL, NULL, NULL); + g_message ("Emitting signal"); + empty_asv = tp_asv_new (NULL, NULL); + tp_svc_dbus_properties_emit_properties_changed (f->cd_service, + TP_IFACE_CHANNEL_DISPATCHER, empty_asv, NULL); + g_hash_table_unref (empty_asv); + + g_message ("Dropping private D-Bus connection"); + drop_private_connection (); + /* wait for everything to happen */ g_message ("Running main loop"); - g_main_loop_run (mainloop); - g_main_loop_unref (mainloop); - /* Now that the main loop has run, cancelled signal connections have been - * freed */ - MYASSERT (tp_intset_is_member (freed_user_data, TEST_B), ""); - MYASSERT (tp_intset_is_member (freed_user_data, TEST_C), ""); - MYASSERT (tp_intset_is_member (freed_user_data, TEST_D), ""); - MYASSERT (tp_intset_is_member (freed_user_data, TEST_E), ""); - MYASSERT (tp_intset_is_member (freed_user_data, TEST_F), ""); - MYASSERT (tp_intset_is_member (freed_user_data, TEST_G), ""); - MYASSERT (tp_intset_is_member (freed_user_data, TEST_H), ""); + /* There's no guarantee that proxy F will detect that its socket closed + * in any particular order relative to the signals, so wait for both. */ + while (!tp_intset_is_member (caught_signal, TEST_A) || + !tp_intset_is_member (caught_signal, TEST_Z) || + tp_proxy_get_invalidated (f->proxies[TEST_F]) == NULL) + g_main_context_iteration (NULL, TRUE); + + /* assert that connecting to a signal on an invalid proxy fails */ + freed = FALSE; + tp_cli_dbus_properties_connect_to_properties_changed (f->proxies[TEST_F], + unwanted_signal_cb, &freed, set_freed, NULL, &error_out); + MYASSERT (freed, ""); + MYASSERT (error_out != NULL, ""); + MYASSERT (error_out->code == DBUS_GERROR_NAME_HAS_NO_OWNER, ""); + g_error_free (error_out); + error_out = NULL; + + /* It might take a little longer to free all the user-data, because it + * happens in an idle */ + + while (!tp_intset_is_member (freed_user_data, TEST_B)) + g_main_context_iteration (NULL, TRUE); + + while (!tp_intset_is_member (freed_user_data, TEST_C)) + g_main_context_iteration (NULL, TRUE); + + while (!tp_intset_is_member (freed_user_data, TEST_D)) + g_main_context_iteration (NULL, TRUE); + + while (!tp_intset_is_member (freed_user_data, TEST_E)) + g_main_context_iteration (NULL, TRUE); + + while (!tp_intset_is_member (freed_user_data, TEST_F)) + g_main_context_iteration (NULL, TRUE); + + while (!tp_intset_is_member (freed_user_data, TEST_G)) + g_main_context_iteration (NULL, TRUE); + + while (!tp_intset_is_member (freed_user_data, TEST_H)) + g_main_context_iteration (NULL, TRUE); /* both A and Z are still listening for signals, so their user data is * still held */ @@ -333,14 +394,21 @@ main (int argc, MYASSERT (!tp_intset_is_member (freed_user_data, TEST_Z), ""); g_message ("Dereferencing remaining proxies"); - g_object_unref (a); - g_object_unref (b); - g_object_unref (c); - MYASSERT (d == NULL, ""); - g_object_unref (e); - g_object_unref (f); - MYASSERT (g == NULL, ""); - g_object_unref (z); + tp_tests_assert_last_unref (&f->proxies[TEST_A]); + tp_tests_assert_last_unref (&f->proxies[TEST_B]); + tp_tests_assert_last_unref (&f->proxies[TEST_C]); + g_assert (f->proxies[TEST_D] == NULL); + tp_tests_assert_last_unref (&f->proxies[TEST_E]); + tp_tests_assert_last_unref (&f->proxies[TEST_F]); + g_assert (f->proxies[TEST_G] == NULL); + tp_tests_assert_last_unref (&f->proxies[TEST_H]); + tp_tests_assert_last_unref (&f->proxies[TEST_Z]); + + while (!tp_intset_is_member (freed_user_data, TEST_A)) + g_main_context_iteration (NULL, TRUE); + + while (!tp_intset_is_member (freed_user_data, TEST_Z)) + g_main_context_iteration (NULL, TRUE); /* we should already have checked each of these at least once, but just to * make sure we have a systematic test that all user data is freed... */ @@ -357,5 +425,7 @@ main (int argc, tp_intset_destroy (freed_user_data); tp_intset_destroy (caught_signal); + teardown (); + return 0; } diff --git a/tests/dbus/unsupported-interface.c b/tests/dbus/unsupported-interface.c index 818e40f2e..7ff94d777 100644 --- a/tests/dbus/unsupported-interface.c +++ b/tests/dbus/unsupported-interface.c @@ -196,7 +196,10 @@ test_supported_signal (Fixture *f, g_assert (!f->freed); tp_proxy_signal_connection_disconnect (sc); - g_assert (f->freed); + + /* GDBus invokes destructors in an idle */ + while (!f->freed) + g_main_context_iteration (NULL, TRUE); } static void diff --git a/tests/dbus/with-properties.xml b/tests/dbus/with-properties.xml index 5047a737e..b2befb12b 100644 --- a/tests/dbus/with-properties.xml +++ b/tests/dbus/with-properties.xml @@ -10,9 +10,12 @@ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/> - <property name="ReadOnly" access="read" type="u"/> - <property name="WriteOnly" access="write" type="u"/> - <property name="ReadWrite" access="readwrite" type="u"> + <property name="ReadOnly" access="read" type="u" + tp:name-for-bindings="Read_Only"/> + <property name="WriteOnly" access="write" type="u" + tp:name-for-bindings="Write_Only"/> + <property name="ReadWrite" access="readwrite" type="u" + tp:name-for-bindings="Read_Write"> <!-- … and that this overrides the global annotation. --> <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/> diff --git a/tests/lib/util.c b/tests/lib/util.c index 7f23fd4b9..f1c0fc464 100644 --- a/tests/lib/util.c +++ b/tests/lib/util.c @@ -265,6 +265,7 @@ tp_tests_create_conn (GType conn_type, gchar *name; gchar *conn_path; GError *error = NULL; + gboolean ok; g_assert (service_conn != NULL); g_assert (client_conn != NULL); @@ -278,9 +279,10 @@ tp_tests_create_conn (GType conn_type, NULL); g_assert (*service_conn != NULL); - g_assert (tp_base_connection_register (*service_conn, "simple", - &name, &conn_path, &error)); + ok = tp_base_connection_register (*service_conn, "simple", + &name, &conn_path, &error); g_assert_no_error (error); + g_assert (ok); *client_conn = tp_tests_connection_new (dbus, NULL, conn_path, &error); g_assert (*client_conn != NULL); diff --git a/tools/glib-client-gen.py b/tools/glib-client-gen.py index cd420a16a..db87741d6 100644 --- a/tools/glib-client-gen.py +++ b/tools/glib-client-gen.py @@ -29,8 +29,8 @@ from getopt import gnu_getopt from libtpcodegen import file_set_contents, key_by_name, u from libglibcodegen import (Signature, type_to_gtype, - get_docstring, xml_escape, get_deprecated, copy_into_gvalue) - + get_docstring, xml_escape, get_deprecated, copy_into_gvalue, + value_getter) NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" @@ -236,31 +236,12 @@ class Generator(object): self.b(' if (callback != NULL)') self.b(' callback (g_object_ref (tpproxy),') - # FIXME: factor out into a function for i, arg in enumerate(args): name, info, tp_type, elt = arg ctype, gtype, marshaller, pointer = info - if marshaller == 'BOXED': - self.b(' g_value_get_boxed (args->values + %d),' % i) - elif gtype == 'G_TYPE_STRING': - self.b(' g_value_get_string (args->values + %d),' % i) - elif gtype == 'G_TYPE_UCHAR': - self.b(' g_value_get_uchar (args->values + %d),' % i) - elif gtype == 'G_TYPE_BOOLEAN': - self.b(' g_value_get_boolean (args->values + %d),' % i) - elif gtype == 'G_TYPE_UINT': - self.b(' g_value_get_uint (args->values + %d),' % i) - elif gtype == 'G_TYPE_INT': - self.b(' g_value_get_int (args->values + %d),' % i) - elif gtype == 'G_TYPE_UINT64': - self.b(' g_value_get_uint64 (args->values + %d),' % i) - elif gtype == 'G_TYPE_INT64': - self.b(' g_value_get_int64 (args->values + %d),' % i) - elif gtype == 'G_TYPE_DOUBLE': - self.b(' g_value_get_double (args->values + %d),' % i) - else: - assert False, "Don't know how to get %s from a GValue" % gtype + getter = value_getter(gtype, marshaller) + self.b(' %s (args->values + %d),' % (getter, i)) self.b(' user_data,') self.b(' weak_object);') @@ -623,31 +604,12 @@ class Generator(object): self.b(' callback ((%s) self,' % self.proxy_cls) - # FIXME: factor out into a function for i, arg in enumerate(out_args): name, info, tp_type, elt = arg ctype, gtype, marshaller, pointer = info - if marshaller == 'BOXED': - self.b(' g_value_get_boxed (args->values + %d),' % i) - elif gtype == 'G_TYPE_STRING': - self.b(' g_value_get_string (args->values + %d),' % i) - elif gtype == 'G_TYPE_UCHAR': - self.b(' g_value_get_uchar (args->values + %d),' % i) - elif gtype == 'G_TYPE_BOOLEAN': - self.b(' g_value_get_boolean (args->values + %d),' % i) - elif gtype == 'G_TYPE_UINT': - self.b(' g_value_get_uint (args->values + %d),' % i) - elif gtype == 'G_TYPE_INT': - self.b(' g_value_get_int (args->values + %d),' % i) - elif gtype == 'G_TYPE_UINT64': - self.b(' g_value_get_uint64 (args->values + %d),' % i) - elif gtype == 'G_TYPE_INT64': - self.b(' g_value_get_int64 (args->values + %d),' % i) - elif gtype == 'G_TYPE_DOUBLE': - self.b(' g_value_get_double (args->values + %d),' % i) - else: - assert False, "Don't know how to get %s from a GValue" % gtype + getter = value_getter(gtype, marshaller) + self.b(' %s (args->values + %d),' % (getter, i)) self.b(' error, user_data, weak_object);') self.b('') diff --git a/tools/glib-ginterface-gen.py b/tools/glib-ginterface-gen.py index 6ef9f4a02..8cdb18fdb 100644 --- a/tools/glib-ginterface-gen.py +++ b/tools/glib-ginterface-gen.py @@ -26,23 +26,13 @@ import sys import os.path import xml.dom.minidom -from libtpcodegen import file_set_contents, key_by_name, u +from libtpcodegen import file_set_contents, key_by_name, u, get_emits_changed from libglibcodegen import Signature, type_to_gtype, \ NS_TP, dbus_gutils_wincaps_to_uscore NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" -def get_emits_changed(node): - try: - return [ - annotation.getAttribute('value') - for annotation in node.getElementsByTagName('annotation') - if annotation.getAttribute('name') == 'org.freedesktop.DBus.Property.EmitsChangedSignal' - ][0] - except IndexError: - return None - class Generator(object): def __init__(self, dom, prefix, basename, signal_marshal_prefix, diff --git a/tools/libglibcodegen.py b/tools/libglibcodegen.py index 0b703a5a8..c03544fe2 100644 --- a/tools/libglibcodegen.py +++ b/tools/libglibcodegen.py @@ -193,3 +193,25 @@ def copy_into_gvalue(gvaluep, gtype, marshaller, name): return 'g_value_set_double (%s, %s);' % (gvaluep, name) else: raise AssertionError("Don't know how to put %s in a GValue" % gtype) + +def value_getter(gtype, marshaller): + if marshaller == 'BOXED': + return 'g_value_get_boxed' + elif gtype == 'G_TYPE_STRING': + return 'g_value_get_string' + elif gtype == 'G_TYPE_UCHAR': + return 'g_value_get_uchar' + elif gtype == 'G_TYPE_BOOLEAN': + return 'g_value_get_boolean' + elif gtype == 'G_TYPE_UINT': + return 'g_value_get_uint' + elif gtype == 'G_TYPE_INT': + return 'g_value_get_int' + elif gtype == 'G_TYPE_UINT64': + return 'g_value_get_uint64' + elif gtype == 'G_TYPE_INT64': + return 'g_value_get_int64' + elif gtype == 'G_TYPE_DOUBLE': + return 'g_value_get_double' + else: + raise AssertionError("Don't know how to get %s from a GValue" % marshaller) diff --git a/tools/libtpcodegen.py b/tools/libtpcodegen.py index 99de66340..021a82be4 100644 --- a/tools/libtpcodegen.py +++ b/tools/libtpcodegen.py @@ -245,3 +245,13 @@ class Signature(str): def xml_escape(s): s = s.replace('&', '&').replace("'", ''').replace('"', '"') return s.replace('<', '<').replace('>', '>') + +def get_emits_changed(node): + try: + return [ + annotation.getAttribute('value') + for annotation in node.getElementsByTagName('annotation') + if annotation.getAttribute('name') == 'org.freedesktop.DBus.Property.EmitsChangedSignal' + ][0] + except IndexError: + return None |