/* Feature test for handle reference tracking. * * Code missing coverage in connection-handles.c: * - having two connections, one of them becoming invalid * - unreffing handles on a dead connection * - failing to request handles * - inconsistent CMs * * Copyright (C) 2008 Collabora Ltd. * Copyright (C) 2008 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include #include #include #include "tests/lib/debug.h" #include "tests/lib/myassert.h" #include "tests/lib/simple-conn.h" #include "tests/lib/util.h" typedef struct { GMainLoop *loop; GError *error /* initialized to 0 */; GArray *handles; gchar **ids; } Result; static void requested (TpConnection *connection, TpHandleType handle_type, guint n_handles, const TpHandle *handles, const gchar * const *ids, const GError *error, gpointer user_data, GObject *weak_object) { Result *result = user_data; g_assert (result->ids == NULL); g_assert (result->handles == NULL); g_assert (result->error == NULL); if (error == NULL) { DEBUG ("got %u handles", n_handles); result->ids = g_strdupv ((GStrv) ids); result->handles = g_array_sized_new (FALSE, FALSE, sizeof (TpHandle), n_handles); g_array_append_vals (result->handles, handles, n_handles); } else { DEBUG ("got an error"); result->error = g_error_copy (error); } } static void held (TpConnection *connection, TpHandleType handle_type, guint n_handles, const TpHandle *handles, const GError *error, gpointer user_data, GObject *weak_object) { Result *result = user_data; g_assert (result->ids == NULL); g_assert (result->handles == NULL); g_assert (result->error == NULL); if (error == NULL) { DEBUG ("got %u handles", n_handles); result->handles = g_array_sized_new (FALSE, FALSE, sizeof (TpHandle), n_handles); g_array_append_vals (result->handles, handles, n_handles); } else { DEBUG ("got an error"); result->error = g_error_copy (error); } } static void finish (gpointer r) { Result *result = r; g_main_loop_quit (result->loop); } /* * Assert that RequestHandles + unref doesn't crash. (It doesn't * do anything any more, however.) */ static void test_request_and_release (TpTestsSimpleConnection *service_conn, TpConnection *client_conn) { Result result = { g_main_loop_new (NULL, FALSE), NULL, NULL, NULL }; const gchar * const ids[] = { "alice", "bob", "chris", NULL }; TpHandleRepoIface *service_repo = tp_base_connection_get_handles ( (TpBaseConnection *) service_conn, TP_HANDLE_TYPE_CONTACT); guint i; g_message (G_STRFUNC); /* request three handles */ tp_connection_request_handles (client_conn, -1, TP_HANDLE_TYPE_CONTACT, ids, requested, &result, finish, NULL); g_main_loop_run (result.loop); g_assert_no_error (result.error); MYASSERT (result.ids != NULL, ""); MYASSERT (result.handles != NULL, ""); for (i = 0; i < 3; i++) { MYASSERT (result.ids[i] != NULL, " [%u]", i); MYASSERT (!tp_strdiff (result.ids[i], ids[i]), " [%u] %s != %s", i, result.ids[i], ids[i]); } MYASSERT (result.ids[3] == NULL, ""); MYASSERT (result.handles->len == 3, ": %u != 3", result.handles->len); /* check that the service and the client agree */ MYASSERT (tp_handles_are_valid (service_repo, result.handles, FALSE, NULL), ""); for (i = 0; i < 3; i++) { TpHandle handle = g_array_index (result.handles, TpHandle, i); MYASSERT (!tp_strdiff (tp_handle_inspect (service_repo, handle), ids[i]), "%s != %s", tp_handle_inspect (service_repo, handle), ids[i]); } /* release the handles (but don't assert that it isn't a no-op) */ tp_connection_unref_handles (client_conn, TP_HANDLE_TYPE_CONTACT, result.handles->len, (const TpHandle *) result.handles->data); tp_tests_proxy_run_until_dbus_queue_processed (client_conn); /* clean up */ g_strfreev (result.ids); g_array_free (result.handles, TRUE); g_assert (result.error == NULL); g_main_loop_unref (result.loop); } /* * Assert that RequestHandles + HoldHandles + unref does not release the * handles, but a second unref does. */ static void test_request_hold_release (TpTestsSimpleConnection *service_conn, TpConnection *client_conn) { Result result = { g_main_loop_new (NULL, FALSE), NULL, NULL, NULL }; const gchar * const ids[] = { "alice", "bob", "chris", NULL }; TpHandleRepoIface *service_repo = tp_base_connection_get_handles ( (TpBaseConnection *) service_conn, TP_HANDLE_TYPE_CONTACT); guint i; GArray *saved_handles; g_message (G_STRFUNC); /* request three handles */ tp_connection_request_handles (client_conn, -1, TP_HANDLE_TYPE_CONTACT, ids, requested, &result, finish, NULL); g_main_loop_run (result.loop); g_assert_no_error (result.error); MYASSERT (result.ids != NULL, ""); MYASSERT (result.handles != NULL, ""); for (i = 0; i < 3; i++) { MYASSERT (result.ids[i] != NULL, " [%u]", i); MYASSERT (!tp_strdiff (result.ids[i], ids[i]), " [%u] %s != %s", i, result.ids[i], ids[i]); } MYASSERT (result.ids[3] == NULL, ""); MYASSERT (result.handles->len == 3, ": %u != 3", result.handles->len); /* check that the service and the client agree */ MYASSERT (tp_handles_are_valid (service_repo, result.handles, FALSE, NULL), ""); for (i = 0; i < 3; i++) { TpHandle handle = g_array_index (result.handles, TpHandle, i); MYASSERT (!tp_strdiff (tp_handle_inspect (service_repo, handle), ids[i]), "%s != %s", tp_handle_inspect (service_repo, handle), ids[i]); } /* hold the handles */ g_strfreev (result.ids); result.ids = NULL; saved_handles = result.handles; result.handles = NULL; g_assert (result.error == NULL); tp_connection_hold_handles (client_conn, -1, TP_HANDLE_TYPE_CONTACT, saved_handles->len, (const TpHandle *) saved_handles->data, held, &result, finish, NULL); g_main_loop_run (result.loop); g_assert_no_error (result.error); MYASSERT (result.ids == NULL, ""); MYASSERT (result.handles != NULL, ""); for (i = 0; i < 3; i++) { TpHandle want = g_array_index (saved_handles, TpHandle, i); TpHandle got = g_array_index (result.handles, TpHandle, i); MYASSERT (want == got, "%u != %u", want, got); } g_array_free (saved_handles, TRUE); /* unref the handles */ tp_connection_unref_handles (client_conn, TP_HANDLE_TYPE_CONTACT, result.handles->len, (const TpHandle *) result.handles->data); tp_tests_proxy_run_until_dbus_queue_processed (client_conn); /* check that the handles have not been released */ MYASSERT (tp_handles_are_valid (service_repo, result.handles, FALSE, NULL), ""); for (i = 0; i < 3; i++) { TpHandle handle = g_array_index (result.handles, TpHandle, i); MYASSERT (!tp_strdiff (tp_handle_inspect (service_repo, handle), ids[i]), "%s != %s", tp_handle_inspect (service_repo, handle), ids[i]); } /* release the handles (but don't assert that it isn't a no-op) */ tp_connection_unref_handles (client_conn, TP_HANDLE_TYPE_CONTACT, result.handles->len, (const TpHandle *) result.handles->data); tp_tests_proxy_run_until_dbus_queue_processed (client_conn); /* clean up */ g_main_loop_unref (result.loop); g_strfreev (result.ids); g_array_free (result.handles, TRUE); g_assert (result.error == NULL); } int main (int argc, char **argv) { TpDBusDaemon *dbus; TpTestsSimpleConnection *service_conn; TpBaseConnection *service_conn_as_base; gchar *name; gchar *conn_path; GError *error = NULL; TpConnection *client_conn; /* Setup */ tp_tests_abort_after (10); g_type_init (); tp_debug_set_flags ("all"); dbus = tp_tests_dbus_daemon_dup_or_die (); service_conn = TP_TESTS_SIMPLE_CONNECTION (tp_tests_object_new_static_class ( TP_TESTS_TYPE_SIMPLE_CONNECTION, "account", "me@example.com", "protocol", "simple", NULL)); service_conn_as_base = TP_BASE_CONNECTION (service_conn); MYASSERT (service_conn != NULL, ""); MYASSERT (service_conn_as_base != NULL, ""); MYASSERT (tp_base_connection_register (service_conn_as_base, "simple", &name, &conn_path, &error), ""); g_assert_no_error (error); client_conn = tp_connection_new (dbus, name, conn_path, &error); MYASSERT (client_conn != NULL, ""); /* It does in fact have immortal handles, but we can't know that yet */ g_assert (!tp_connection_has_immortal_handles (client_conn)); g_assert_no_error (error); MYASSERT (tp_connection_run_until_ready (client_conn, TRUE, &error, NULL), ""); g_assert_no_error (error); /* now we know */ g_assert (tp_connection_has_immortal_handles (client_conn)); /* Tests */ test_request_and_release (service_conn, client_conn); test_request_hold_release (service_conn, client_conn); /* Teardown */ MYASSERT (tp_cli_connection_run_disconnect (client_conn, -1, &error, NULL), ""); g_assert_no_error (error); service_conn_as_base = NULL; g_object_unref (service_conn); g_free (name); g_free (conn_path); g_object_unref (dbus); return 0; }