mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-11-04 01:58:54 +01:00 
			
		
		
		
	This makes no functional changes, but does tidy the code up a bit and means `g_steal_handle_id()` gets a bit more testing. Signed-off-by: Philip Withnall <pwithnall@gnome.org>
		
			
				
	
	
		
			412 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			412 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* GLib testing framework examples and tests
 | 
						|
 *
 | 
						|
 * Copyright © 2022 Endless OS Foundation, LLC
 | 
						|
 *
 | 
						|
 * SPDX-License-Identifier: LGPL-2.1-or-later
 | 
						|
 *
 | 
						|
 * 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, see <http://www.gnu.org/licenses/>.
 | 
						|
 *
 | 
						|
 * SPDX-License-Identifier: LGPL-2.1-or-later
 | 
						|
 * Author: Philip Withnall <pwithnall@endlessos.org>
 | 
						|
 */
 | 
						|
 | 
						|
#include <gio/gio.h>
 | 
						|
#include <locale.h>
 | 
						|
 | 
						|
#include "gdbusprivate.h"
 | 
						|
 | 
						|
static void
 | 
						|
test_dbus_basic (void)
 | 
						|
{
 | 
						|
  GTestDBus *bus;
 | 
						|
  GDBusConnection *connection = NULL, *connection2 = NULL;
 | 
						|
  GDebugControllerDBus *controller = NULL;
 | 
						|
  gboolean old_value;
 | 
						|
  gboolean debug_enabled;
 | 
						|
  GError *local_error = NULL;
 | 
						|
 | 
						|
  g_test_summary ("Smoketest for construction and setting of a #GDebugControllerDBus.");
 | 
						|
 | 
						|
  /* Set up a test session bus and connection. */
 | 
						|
  bus = g_test_dbus_new (G_TEST_DBUS_NONE);
 | 
						|
  g_test_dbus_up (bus);
 | 
						|
 | 
						|
  connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &local_error);
 | 
						|
  g_assert_no_error (local_error);
 | 
						|
 | 
						|
  /* Create a controller for this process. */
 | 
						|
  controller = g_debug_controller_dbus_new (connection, NULL, &local_error);
 | 
						|
  g_assert_no_error (local_error);
 | 
						|
  g_assert_nonnull (controller);
 | 
						|
  g_assert_true (G_IS_DEBUG_CONTROLLER_DBUS (controller));
 | 
						|
 | 
						|
  /* Try enabling and disabling debug output from within the process. */
 | 
						|
  old_value = g_debug_controller_get_debug_enabled (G_DEBUG_CONTROLLER (controller));
 | 
						|
 | 
						|
  g_debug_controller_set_debug_enabled (G_DEBUG_CONTROLLER (controller), TRUE);
 | 
						|
  g_assert_true (g_debug_controller_get_debug_enabled (G_DEBUG_CONTROLLER (controller)));
 | 
						|
 | 
						|
  g_debug_controller_set_debug_enabled (G_DEBUG_CONTROLLER (controller), FALSE);
 | 
						|
  g_assert_false (g_debug_controller_get_debug_enabled (G_DEBUG_CONTROLLER (controller)));
 | 
						|
 | 
						|
  /* Reset the debug state and check using g_object_get(), to exercise that. */
 | 
						|
  g_debug_controller_set_debug_enabled (G_DEBUG_CONTROLLER (controller), old_value);
 | 
						|
 | 
						|
  g_object_get (G_OBJECT (controller),
 | 
						|
                "debug-enabled", &debug_enabled,
 | 
						|
                "connection", &connection2,
 | 
						|
                NULL);
 | 
						|
  g_assert_true (debug_enabled == old_value);
 | 
						|
  g_assert_true (connection2 == connection);
 | 
						|
  g_clear_object (&connection2);
 | 
						|
 | 
						|
  g_debug_controller_dbus_stop (controller);
 | 
						|
  while (g_main_context_iteration (NULL, FALSE));
 | 
						|
  g_assert_finalize_object (controller);
 | 
						|
  g_clear_object (&connection);
 | 
						|
 | 
						|
  g_test_dbus_down (bus);
 | 
						|
  g_clear_object (&bus);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
test_dbus_duplicate (void)
 | 
						|
{
 | 
						|
  GTestDBus *bus;
 | 
						|
  GDBusConnection *connection = NULL;
 | 
						|
  GDebugControllerDBus *controller1 = NULL, *controller2 = NULL;
 | 
						|
  GError *local_error = NULL;
 | 
						|
 | 
						|
  g_test_summary ("Test that creating a second #GDebugControllerDBus on the same D-Bus connection fails.");
 | 
						|
 | 
						|
  /* Set up a test session bus and connection. */
 | 
						|
  bus = g_test_dbus_new (G_TEST_DBUS_NONE);
 | 
						|
  g_test_dbus_up (bus);
 | 
						|
 | 
						|
  connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &local_error);
 | 
						|
  g_assert_no_error (local_error);
 | 
						|
 | 
						|
  /* Create a controller for this process. */
 | 
						|
  controller1 = g_debug_controller_dbus_new (connection, NULL, &local_error);
 | 
						|
  g_assert_no_error (local_error);
 | 
						|
  g_assert_nonnull (controller1);
 | 
						|
 | 
						|
  /* And try creating a second one. */
 | 
						|
  controller2 = g_debug_controller_dbus_new (connection, NULL, &local_error);
 | 
						|
  g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_EXISTS);
 | 
						|
  g_assert_null (controller2);
 | 
						|
  g_clear_error (&local_error);
 | 
						|
 | 
						|
  g_debug_controller_dbus_stop (controller1);
 | 
						|
  while (g_main_context_iteration (NULL, FALSE));
 | 
						|
  g_assert_finalize_object (controller1);
 | 
						|
  g_clear_object (&connection);
 | 
						|
 | 
						|
  g_test_dbus_down (bus);
 | 
						|
  g_clear_object (&bus);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
async_result_cb (GObject      *source_object,
 | 
						|
                 GAsyncResult *result,
 | 
						|
                 gpointer      user_data)
 | 
						|
{
 | 
						|
  GAsyncResult **result_out = user_data;
 | 
						|
 | 
						|
  g_assert_null (*result_out);
 | 
						|
  *result_out = g_object_ref (result);
 | 
						|
 | 
						|
  g_main_context_wakeup (g_main_context_get_thread_default ());
 | 
						|
}
 | 
						|
 | 
						|
static gboolean
 | 
						|
authorize_false_cb (GDebugControllerDBus  *debug_controller,
 | 
						|
                    GDBusMethodInvocation *invocation,
 | 
						|
                    gpointer               user_data)
 | 
						|
{
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static gboolean
 | 
						|
authorize_true_cb (GDebugControllerDBus  *debug_controller,
 | 
						|
                   GDBusMethodInvocation *invocation,
 | 
						|
                   gpointer               user_data)
 | 
						|
{
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
notify_debug_enabled_cb (GObject    *object,
 | 
						|
                         GParamSpec *pspec,
 | 
						|
                         gpointer    user_data)
 | 
						|
{
 | 
						|
  guint *notify_count_out = user_data;
 | 
						|
 | 
						|
  *notify_count_out = *notify_count_out + 1;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
properties_changed_cb (GDBusConnection *connection,
 | 
						|
                       const gchar     *sender_name,
 | 
						|
                       const gchar     *object_path,
 | 
						|
                       const gchar     *interface_name,
 | 
						|
                       const gchar     *signal_name,
 | 
						|
                       GVariant        *parameters,
 | 
						|
                       gpointer         user_data)
 | 
						|
{
 | 
						|
  guint *properties_changed_count_out = user_data;
 | 
						|
 | 
						|
  *properties_changed_count_out = *properties_changed_count_out + 1;
 | 
						|
  g_main_context_wakeup (g_main_context_get_thread_default ());
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
test_dbus_properties (void)
 | 
						|
{
 | 
						|
  GTestDBus *bus;
 | 
						|
  GDBusConnection *controller_connection = NULL;
 | 
						|
  GDBusConnection *remote_connection = NULL;
 | 
						|
  GDebugControllerDBus *controller = NULL;
 | 
						|
  gboolean old_value;
 | 
						|
  GAsyncResult *result = NULL;
 | 
						|
  GVariant *reply = NULL;
 | 
						|
  GVariant *debug_enabled_variant = NULL;
 | 
						|
  gboolean debug_enabled;
 | 
						|
  GError *local_error = NULL;
 | 
						|
  gulong handler_id;
 | 
						|
  gulong notify_id;
 | 
						|
  guint notify_count = 0;
 | 
						|
  guint properties_changed_id;
 | 
						|
  guint properties_changed_count = 0;
 | 
						|
 | 
						|
  g_test_summary ("Test getting and setting properties on a #GDebugControllerDBus.");
 | 
						|
 | 
						|
  /* Set up a test session bus and connection. Set up a separate second
 | 
						|
   * connection to simulate a remote peer. */
 | 
						|
  bus = g_test_dbus_new (G_TEST_DBUS_NONE);
 | 
						|
  g_test_dbus_up (bus);
 | 
						|
 | 
						|
  controller_connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &local_error);
 | 
						|
  g_assert_no_error (local_error);
 | 
						|
 | 
						|
  remote_connection = g_dbus_connection_new_for_address_sync (g_test_dbus_get_bus_address (bus),
 | 
						|
                                                              G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
 | 
						|
                                                              G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
 | 
						|
                                                              NULL,
 | 
						|
                                                              NULL,
 | 
						|
                                                              &local_error);
 | 
						|
  g_assert_no_error (local_error);
 | 
						|
 | 
						|
  /* Create a controller for this process. */
 | 
						|
  controller = g_debug_controller_dbus_new (controller_connection, NULL, &local_error);
 | 
						|
  g_assert_no_error (local_error);
 | 
						|
  g_assert_nonnull (controller);
 | 
						|
  g_assert_true (G_IS_DEBUG_CONTROLLER_DBUS (controller));
 | 
						|
 | 
						|
  old_value = g_debug_controller_get_debug_enabled (G_DEBUG_CONTROLLER (controller));
 | 
						|
  notify_id = g_signal_connect (controller, "notify::debug-enabled", G_CALLBACK (notify_debug_enabled_cb), ¬ify_count);
 | 
						|
 | 
						|
  properties_changed_id = g_dbus_connection_signal_subscribe (remote_connection,
 | 
						|
                                                              g_dbus_connection_get_unique_name (controller_connection),
 | 
						|
                                                              DBUS_INTERFACE_PROPERTIES,
 | 
						|
                                                              "PropertiesChanged",
 | 
						|
                                                              "/org/gtk/Debugging",
 | 
						|
                                                              NULL,
 | 
						|
                                                              G_DBUS_SIGNAL_FLAGS_NONE,
 | 
						|
                                                              properties_changed_cb,
 | 
						|
                                                              &properties_changed_count,
 | 
						|
                                                              NULL);
 | 
						|
 | 
						|
  /* Get the debug status remotely. */
 | 
						|
  g_dbus_connection_call (remote_connection,
 | 
						|
                          g_dbus_connection_get_unique_name (controller_connection),
 | 
						|
                          "/org/gtk/Debugging",
 | 
						|
                          DBUS_INTERFACE_PROPERTIES,
 | 
						|
                          "Get",
 | 
						|
                          g_variant_new ("(ss)", "org.gtk.Debugging", "DebugEnabled"),
 | 
						|
                          G_VARIANT_TYPE ("(v)"),
 | 
						|
                          G_DBUS_CALL_FLAGS_NONE,
 | 
						|
                          -1,
 | 
						|
                          NULL,
 | 
						|
                          async_result_cb,
 | 
						|
                          &result);
 | 
						|
  g_assert_no_error (local_error);
 | 
						|
 | 
						|
  while (result == NULL)
 | 
						|
    g_main_context_iteration (NULL, TRUE);
 | 
						|
 | 
						|
  reply = g_dbus_connection_call_finish (remote_connection, result, &local_error);
 | 
						|
  g_assert_no_error (local_error);
 | 
						|
  g_clear_object (&result);
 | 
						|
 | 
						|
  g_variant_get (reply, "(v)", &debug_enabled_variant);
 | 
						|
  debug_enabled = g_variant_get_boolean (debug_enabled_variant);
 | 
						|
  g_assert_true (debug_enabled == old_value);
 | 
						|
  g_assert_cmpuint (notify_count, ==, 0);
 | 
						|
  g_assert_cmpuint (properties_changed_count, ==, 0);
 | 
						|
 | 
						|
  g_clear_pointer (&debug_enabled_variant, g_variant_unref);
 | 
						|
  g_clear_pointer (&reply, g_variant_unref);
 | 
						|
 | 
						|
  /* Set the debug status remotely. The first attempt should fail due to no
 | 
						|
   * authorisation handler being connected. The second should fail due to the
 | 
						|
   * now-connected handler returning %FALSE. The third attempt should
 | 
						|
   * succeed. */
 | 
						|
  g_dbus_connection_call (remote_connection,
 | 
						|
                          g_dbus_connection_get_unique_name (controller_connection),
 | 
						|
                          "/org/gtk/Debugging",
 | 
						|
                          "org.gtk.Debugging",
 | 
						|
                          "SetDebugEnabled",
 | 
						|
                          g_variant_new ("(b)", !old_value),
 | 
						|
                          NULL,
 | 
						|
                          G_DBUS_CALL_FLAGS_NONE,
 | 
						|
                          -1,
 | 
						|
                          NULL,
 | 
						|
                          async_result_cb,
 | 
						|
                          &result);
 | 
						|
 | 
						|
  while (result == NULL)
 | 
						|
    g_main_context_iteration (NULL, TRUE);
 | 
						|
 | 
						|
  reply = g_dbus_connection_call_finish (remote_connection, result, &local_error);
 | 
						|
  g_assert_error (local_error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED);
 | 
						|
  g_clear_object (&result);
 | 
						|
  g_clear_error (&local_error);
 | 
						|
 | 
						|
  g_assert_true (g_debug_controller_get_debug_enabled (G_DEBUG_CONTROLLER (controller)) == old_value);
 | 
						|
  g_assert_cmpuint (notify_count, ==, 0);
 | 
						|
  g_assert_cmpuint (properties_changed_count, ==, 0);
 | 
						|
 | 
						|
  g_clear_pointer (&debug_enabled_variant, g_variant_unref);
 | 
						|
  g_clear_pointer (&reply, g_variant_unref);
 | 
						|
 | 
						|
  /* Attach an authorisation handler and try again. */
 | 
						|
  handler_id = g_signal_connect (controller, "authorize", G_CALLBACK (authorize_false_cb), NULL);
 | 
						|
 | 
						|
  g_dbus_connection_call (remote_connection,
 | 
						|
                          g_dbus_connection_get_unique_name (controller_connection),
 | 
						|
                          "/org/gtk/Debugging",
 | 
						|
                          "org.gtk.Debugging",
 | 
						|
                          "SetDebugEnabled",
 | 
						|
                          g_variant_new ("(b)", !old_value),
 | 
						|
                          NULL,
 | 
						|
                          G_DBUS_CALL_FLAGS_NONE,
 | 
						|
                          -1,
 | 
						|
                          NULL,
 | 
						|
                          async_result_cb,
 | 
						|
                          &result);
 | 
						|
 | 
						|
  while (result == NULL)
 | 
						|
    g_main_context_iteration (NULL, TRUE);
 | 
						|
 | 
						|
  reply = g_dbus_connection_call_finish (remote_connection, result, &local_error);
 | 
						|
  g_assert_error (local_error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED);
 | 
						|
  g_clear_object (&result);
 | 
						|
  g_clear_error (&local_error);
 | 
						|
 | 
						|
  g_assert_true (g_debug_controller_get_debug_enabled (G_DEBUG_CONTROLLER (controller)) == old_value);
 | 
						|
  g_assert_cmpuint (notify_count, ==, 0);
 | 
						|
  g_assert_cmpuint (properties_changed_count, ==, 0);
 | 
						|
 | 
						|
  g_clear_pointer (&debug_enabled_variant, g_variant_unref);
 | 
						|
  g_clear_pointer (&reply, g_variant_unref);
 | 
						|
 | 
						|
  g_signal_handler_disconnect (controller, handler_id);
 | 
						|
  handler_id = 0;
 | 
						|
 | 
						|
  /* Attach another signal handler which will grant access, and try again. */
 | 
						|
  handler_id = g_signal_connect (controller, "authorize", G_CALLBACK (authorize_true_cb), NULL);
 | 
						|
 | 
						|
  g_dbus_connection_call (remote_connection,
 | 
						|
                          g_dbus_connection_get_unique_name (controller_connection),
 | 
						|
                          "/org/gtk/Debugging",
 | 
						|
                          "org.gtk.Debugging",
 | 
						|
                          "SetDebugEnabled",
 | 
						|
                          g_variant_new ("(b)", !old_value),
 | 
						|
                          NULL,
 | 
						|
                          G_DBUS_CALL_FLAGS_NONE,
 | 
						|
                          -1,
 | 
						|
                          NULL,
 | 
						|
                          async_result_cb,
 | 
						|
                          &result);
 | 
						|
 | 
						|
  while (result == NULL)
 | 
						|
    g_main_context_iteration (NULL, TRUE);
 | 
						|
 | 
						|
  reply = g_dbus_connection_call_finish (remote_connection, result, &local_error);
 | 
						|
  g_assert_no_error (local_error);
 | 
						|
  g_clear_object (&result);
 | 
						|
 | 
						|
  g_assert_true (g_debug_controller_get_debug_enabled (G_DEBUG_CONTROLLER (controller)) == !old_value);
 | 
						|
  g_assert_cmpuint (notify_count, ==, 1);
 | 
						|
  g_assert_cmpuint (properties_changed_count, ==, 1);
 | 
						|
 | 
						|
  g_clear_pointer (&debug_enabled_variant, g_variant_unref);
 | 
						|
  g_clear_pointer (&reply, g_variant_unref);
 | 
						|
 | 
						|
  g_signal_handler_disconnect (controller, handler_id);
 | 
						|
  handler_id = 0;
 | 
						|
 | 
						|
  /* Set the debug status locally. */
 | 
						|
  g_debug_controller_set_debug_enabled (G_DEBUG_CONTROLLER (controller), old_value);
 | 
						|
  g_assert_true (g_debug_controller_get_debug_enabled (G_DEBUG_CONTROLLER (controller)) == old_value);
 | 
						|
  g_assert_cmpuint (notify_count, ==, 2);
 | 
						|
 | 
						|
  while (properties_changed_count != 2)
 | 
						|
    g_main_context_iteration (NULL, TRUE);
 | 
						|
 | 
						|
  g_assert_cmpuint (properties_changed_count, ==, 2);
 | 
						|
 | 
						|
  g_signal_handler_disconnect (controller, notify_id);
 | 
						|
  notify_id = 0;
 | 
						|
 | 
						|
  g_dbus_connection_signal_unsubscribe (remote_connection, g_steal_handle_id (&properties_changed_id));
 | 
						|
 | 
						|
  g_debug_controller_dbus_stop (controller);
 | 
						|
  while (g_main_context_iteration (NULL, FALSE));
 | 
						|
  g_assert_finalize_object (controller);
 | 
						|
  g_clear_object (&controller_connection);
 | 
						|
  g_clear_object (&remote_connection);
 | 
						|
 | 
						|
  g_test_dbus_down (bus);
 | 
						|
  g_clear_object (&bus);
 | 
						|
}
 | 
						|
 | 
						|
static GLogWriterOutput
 | 
						|
noop_log_writer_cb (GLogLevelFlags   log_level,
 | 
						|
                    const GLogField *fields,
 | 
						|
                    gsize            n_fields,
 | 
						|
                    gpointer         user_data)
 | 
						|
{
 | 
						|
  return G_LOG_WRITER_HANDLED;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
main (int   argc,
 | 
						|
      char *argv[])
 | 
						|
{
 | 
						|
  setlocale (LC_ALL, "");
 | 
						|
  g_test_init (&argc, &argv, NULL);
 | 
						|
 | 
						|
  /* Ignore the log messages, as the debug controller prints one when debug is
 | 
						|
   * enabled/disabled, and if debug is enabled then that will escape to stdout. */
 | 
						|
  g_log_set_writer_func (noop_log_writer_cb, NULL, NULL);
 | 
						|
 | 
						|
  g_test_add_func ("/debug-controller/dbus/basic", test_dbus_basic);
 | 
						|
  g_test_add_func ("/debug-controller/dbus/duplicate", test_dbus_duplicate);
 | 
						|
  g_test_add_func ("/debug-controller/dbus/properties", test_dbus_properties);
 | 
						|
 | 
						|
  return g_test_run ();
 | 
						|
}
 |