[glib/wip/gapplication] Add some tests for GApplication



commit 2a04dfee3c17d6154a7d6aec74e8305270ca6cc0
Author: Matthias Clasen <mclasen redhat com>
Date:   Thu May 20 22:58:34 2010 -0400

    Add some tests for GApplication
    
    Test various aspects of GApplication behaviour with actual
    DBus calls.

 gio/tests/Makefile.am |    8 +
 gio/tests/testapp.c   |   61 +++++++
 gio/tests/testapps.c  |  453 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 522 insertions(+), 0 deletions(-)
---
diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am
index 0b1da7b..02fafc5 100644
--- a/gio/tests/Makefile.am
+++ b/gio/tests/Makefile.am
@@ -51,6 +51,7 @@ TEST_PROGS +=	 		\
 	gdbus-peer		\
 	gdbus-exit-on-close	\
 	application		\
+	testapps		\
 	$(NULL)
 
 SAMPLE_PROGS = 				\
@@ -69,6 +70,7 @@ SAMPLE_PROGS = 				\
 	gdbus-example-subtree		\
 	gdbus-example-peer		\
 	gdbus-example-proxy-subclass	\
+	testapp				\
 	$(NULL)
 
 
@@ -247,6 +249,12 @@ gdbus_example_export_LDADD   = $(progs_ldadd)
 application_SOURCES = application.c
 application_LDADD   = $(progs_ldadd)
 
+testapp_SOURCES = testapp.c
+testapp_LDADD   = $(progs_ldadd)
+
+testapps_SOURCES = testapps.c
+testapps_LDADD   = $(progs_ldadd)
+
 EXTRA_DIST += \
 	socket-common.c						\
 	org.gtk.test.gschema					\
diff --git a/gio/tests/testapp.c b/gio/tests/testapp.c
new file mode 100644
index 0000000..67927a0
--- /dev/null
+++ b/gio/tests/testapp.c
@@ -0,0 +1,61 @@
+#include <stdlib.h>
+#include <gio.h>
+#include <gstdio.h>
+#include <string.h>
+
+static void
+on_app_action (GApplication *application,
+               const gchar  *action_name,
+               guint         action_timestamp)
+{
+  if (strcmp (action_name, "action1") == 0)
+    exit (1);
+}
+
+static gboolean
+invoke_action1 (gpointer data)
+{
+  GApplication *app = data;
+
+  g_application_invoke_action (app, "action1", 0);
+
+  return FALSE;
+}
+
+int
+main (int argc, char *argv[])
+{
+  GApplication *app;
+  GMainLoop *loop;
+
+  if (argc > 1 && strcmp (argv[1], "--non-unique") == 0)
+    {
+      g_type_init ();
+
+      app = g_object_new (G_TYPE_APPLICATION,
+                          "appid", "org.gtk.test.app",
+                          "default-quit", FALSE,
+                          NULL);
+    }
+  else
+    {
+      app = g_application_new ("org.gtk.test.app");
+    }
+
+  if (g_application_is_remote (app))
+    {
+      g_timeout_add (1000, invoke_action1, app);
+      loop = g_main_loop_new (NULL, FALSE);
+      g_main_loop_run (loop);
+    }
+  else
+    {
+      g_application_add_action (app, "action1", "Action1");
+      g_application_add_action (app, "action2", "Action2");
+      g_signal_connect (app, "action",
+                        G_CALLBACK (on_app_action), NULL);
+      g_application_run (app);
+    }
+
+  return 0;
+}
diff --git a/gio/tests/testapps.c b/gio/tests/testapps.c
new file mode 100644
index 0000000..a31b4f9
--- /dev/null
+++ b/gio/tests/testapps.c
@@ -0,0 +1,453 @@
+#include <gio/gio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+static gint appeared;
+static gint disappeared;
+static gboolean died;
+static gboolean timed_out;
+GPid pid;
+
+static void
+name_appeared (GDBusConnection *connection,
+               const gchar     *name,
+               const gchar     *name_owner,
+               gpointer         user_data)
+{
+  GMainLoop *loop = user_data;
+
+  appeared++;
+
+  if (loop)
+    g_main_loop_quit (loop);
+}
+
+static void
+name_disappeared (GDBusConnection *connection,
+                  const gchar     *name,
+                  gpointer         user_data)
+{
+  GMainLoop *loop = user_data;
+
+  disappeared++;
+
+  if (loop)
+    g_main_loop_quit (loop);
+}
+
+static gboolean
+start_application (gpointer data)
+{
+  gchar *argv[] = { "./testapp", NULL };
+
+  g_assert (g_spawn_async (NULL, argv, NULL, 0, NULL, NULL, &pid, NULL));
+
+  return FALSE;
+}
+
+static gboolean
+run_application_sync (gpointer data)
+{
+  GMainLoop *loop = data;
+
+  g_assert (g_spawn_command_line_sync ("./testapp", NULL, NULL, NULL, NULL));
+
+  if (loop)
+    g_main_loop_quit (loop);
+
+  return FALSE;
+}
+
+static gboolean
+timeout (gpointer data)
+{
+  GMainLoop *loop = data;
+
+  timed_out = TRUE;
+
+  g_main_loop_quit (loop);
+
+  return TRUE;
+}
+
+/* This test starts an application, checks that its name appears
+ * on the bus, then starts it again and checks that the second
+ * instance exits right away.
+ */
+static void
+test_unique (void)
+{
+  GMainLoop *loop;
+  gint watch;
+  guint id1, id2, id3;
+
+  appeared = 0;
+  timed_out = FALSE;
+
+  loop = g_main_loop_new (NULL, FALSE);
+  id1 = g_timeout_add (5000, timeout, loop);
+
+  watch = g_bus_watch_name (G_BUS_TYPE_SESSION,
+                            "org.gtk.test.app",
+                            0,
+                            name_appeared,
+                            NULL,
+                            loop,
+                            NULL);
+
+  id2 = g_timeout_add (0, start_application, loop);
+
+  g_main_loop_run (loop);
+
+  g_assert_cmpint (appeared, ==, 1);
+
+  id3 = g_timeout_add (0, run_application_sync, loop);
+
+  g_main_loop_run (loop);
+
+  g_assert_cmpint (appeared, ==, 1);
+  g_assert_cmpint (timed_out, ==, FALSE);
+
+  g_bus_unwatch_name (watch);
+
+  kill (pid, SIGTERM);
+
+  g_main_loop_unref (loop);
+  g_source_remove (id1);
+  g_source_remove (id2);
+  g_source_remove (id3);
+}
+
+static gboolean
+quit_app (gpointer data)
+{
+  GDBusConnection *connection;
+  GVariant *res;
+
+  connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
+  res = g_dbus_connection_call_sync (connection,
+                                     "org.gtk.test.app",
+                                     "/org/freedesktop/Application",
+                                     "org.freedesktop.Application",
+                                     "Quit",
+                                     g_variant_new ("(u)", 0),
+                                     G_DBUS_CALL_FLAGS_NONE,
+                                     -1,
+                                     NULL,
+                                     NULL);
+  if (res)
+    g_variant_unref (res);
+  g_object_unref (connection);
+
+  return FALSE;
+}
+
+static void
+child_is_dead (GPid     pid,
+               gint     status,
+               gpointer data)
+{
+  GMainLoop *loop = data;
+
+  died++;
+
+  g_assert (WIFEXITED (status) && WEXITSTATUS(status) == 0);
+
+  if (loop)
+    g_main_loop_quit (loop);
+}
+
+/* This test start an application, checks that its name appears on
+ * the bus, then calls Quit, and verifies that the name disappears
+ * and the application exits.
+ */
+static void
+test_quit (void)
+{
+  GMainLoop *loop;
+  gint watch;
+  guint id1, id2, id3;
+  gchar *argv[] = { "./testapp", NULL };
+
+  appeared = 0;
+  disappeared = 0;
+  died = FALSE;
+  timed_out = FALSE;
+
+  loop = g_main_loop_new (NULL, FALSE);
+  watch = g_bus_watch_name (G_BUS_TYPE_SESSION,
+                            "org.gtk.test.app",
+                            0,
+                            name_appeared,
+                            name_disappeared,
+                            NULL,
+                            NULL);
+
+  g_assert (g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, NULL));
+
+  id1 = g_child_watch_add (pid, child_is_dead, loop);
+
+  id2 = g_timeout_add (500, quit_app, NULL);
+
+  id3 = g_timeout_add (5000, timeout, loop);
+
+  g_main_loop_run (loop);
+  g_assert_cmpint (timed_out, ==, FALSE);
+  g_assert_cmpint (appeared, ==, 1);
+  g_assert_cmpint (disappeared, >=, 1);
+  g_assert_cmpint (died, ==, TRUE);
+
+  g_bus_unwatch_name (watch);
+
+  g_main_loop_unref (loop);
+  g_source_remove (id1);
+  g_source_remove (id2);
+  g_source_remove (id3);
+}
+
+static gboolean
+_g_strv_has_string (const gchar* const * haystack,
+                    const gchar *needle)
+{
+  guint n;
+
+  for (n = 0; haystack != NULL && haystack[n] != NULL; n++)
+    {
+      if (g_strcmp0 (haystack[n], needle) == 0)
+        return TRUE;
+    }
+  return FALSE;
+}
+
+static gchar **
+list_actions (void)
+{
+  GDBusConnection *connection;
+  GVariant *res;
+  gchar **strv;
+  gchar *str;
+  GVariantIter *iter;
+  gint i;
+
+  connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
+  res = g_dbus_connection_call_sync (connection,
+                                     "org.gtk.test.app",
+                                     "/org/freedesktop/Application",
+                                     "org.freedesktop.Application",
+                                     "ListActions",
+                                     NULL,
+                                     G_DBUS_CALL_FLAGS_NONE,
+                                     -1,
+                                     NULL,
+                                     NULL);
+
+  strv = g_new0 (gchar *, 32);
+  g_variant_get (res, "(as)", &iter);
+  i = 0;
+  while (g_variant_iter_loop (iter, "s", &str))
+    {
+      strv[i] = g_strdup (str);
+      i++;
+      g_assert (i < 32);
+    }
+  g_variant_iter_free (iter);
+
+  strv[i] = NULL;
+
+  g_variant_unref (res);
+  g_object_unref (connection);
+
+  return strv;
+}
+
+/* This test start an application, waits for its name to appear on
+ * the bus, then calls ListActions, and verifies that it gets the expected
+ * actions back.
+ */
+static void
+test_list_actions (void)
+{
+  GMainLoop *loop;
+  gchar *argv[] = { "./testapp", NULL };
+  gchar **actions;
+  gint watch;
+
+  appeared = 0;
+
+  loop = g_main_loop_new (NULL, FALSE);
+  watch = g_bus_watch_name (G_BUS_TYPE_SESSION,
+                            "org.gtk.test.app",
+                            0,
+                            name_appeared,
+                            NULL,
+                            loop,
+                            NULL);
+
+  g_assert (g_spawn_async (NULL, argv, NULL, 0, NULL, NULL, &pid, NULL));
+  if (!appeared)
+    g_main_loop_run (loop);
+  g_main_loop_unref (loop);
+
+  actions = list_actions ();
+
+  g_assert (g_strv_length  (actions) == 2);
+  g_assert (_g_strv_has_string (actions, "action1"));
+  g_assert (_g_strv_has_string (actions, "action2"));
+
+  g_strfreev (actions);
+
+  kill (pid, SIGTERM);
+
+  g_bus_unwatch_name (watch);
+}
+
+static gboolean
+invoke_action1 (gpointer data)
+{
+  GDBusConnection *connection;
+  GVariant *res;
+
+  connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
+  res = g_dbus_connection_call_sync (connection,
+                                     "org.gtk.test.app",
+                                     "/org/freedesktop/Application",
+                                     "org.freedesktop.Application",
+                                     "InvokeAction",
+                                     g_variant_new ("(su)",
+                                                    "action1",
+                                                    0),
+                                     G_DBUS_CALL_FLAGS_NONE,
+                                     -1,
+                                     NULL,
+                                     NULL);
+  if (res)
+    g_variant_unref (res);
+  g_object_unref (connection);
+
+  return FALSE;
+}
+
+static void
+exit_with_code_1 (GPid     pid,
+                  gint     status,
+                  gpointer data)
+{
+  GMainLoop *loop = data;
+
+  died++;
+
+  g_assert (WIFEXITED (status) && WEXITSTATUS(status) == 1);
+
+  if (loop)
+    g_main_loop_quit (loop);
+}
+
+/* This test starts an application, waits for it to appear,
+ * then invokes 'action1' and checks that it causes the application
+ * to exit with an exit code of 1.
+ */
+static void
+test_invoke (void)
+{
+  GMainLoop *loop;
+  gint watch;
+  gchar *argv[] = { "./testapp", NULL };
+  guint id1, id2, id3;
+
+  appeared = 0;
+  disappeared = 0;
+  died = FALSE;
+  timed_out = FALSE;
+
+  loop = g_main_loop_new (NULL, FALSE);
+  watch = g_bus_watch_name (G_BUS_TYPE_SESSION,
+                            "org.gtk.test.app",
+                            0,
+                            name_appeared,
+                            name_disappeared,
+                            NULL,
+                            NULL);
+
+  g_assert (g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, NULL));
+
+  id1 = g_child_watch_add (pid, exit_with_code_1, loop);
+
+  id2 = g_timeout_add (500, invoke_action1, NULL);
+
+  id3 = g_timeout_add (5000, timeout, loop);
+
+  g_main_loop_run (loop);
+  g_assert_cmpint (timed_out, ==, FALSE);
+  g_assert_cmpint (appeared, >=, 1);
+  g_assert_cmpint (disappeared, >=, 1);
+  g_assert_cmpint (died, ==, TRUE);
+
+  g_bus_unwatch_name (watch);
+  g_main_loop_unref (loop);
+  g_source_remove (id1);
+  g_source_remove (id2);
+  g_source_remove (id3);
+
+  kill (pid, SIGTERM);
+}
+
+static void
+test_remote (void)
+{
+  GMainLoop *loop;
+  gint watch;
+  GPid pid1, pid2;
+  gchar *argv[] = { "./testapp", NULL, NULL };
+
+  appeared = 0;
+  timed_out = FALSE;
+
+  loop = g_main_loop_new (NULL, FALSE);
+  g_timeout_add (5000, timeout, loop);
+
+  watch = g_bus_watch_name (G_BUS_TYPE_SESSION,
+                            "org.gtk.test.app",
+                            0,
+                            name_appeared,
+                            NULL,
+                            loop,
+                            NULL);
+
+  g_assert (g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid1, NULL));
+  g_child_watch_add (pid1, exit_with_code_1, loop);
+
+  g_main_loop_run (loop);
+
+  g_assert_cmpint (appeared, ==, 1);
+
+  argv[1] = "--non-unique";
+  g_assert (g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid2, NULL));
+
+  g_main_loop_run (loop);
+
+  g_assert_cmpint (appeared, ==, 1);
+  g_assert_cmpint (timed_out, ==, FALSE);
+
+  g_main_loop_unref (loop);
+  g_bus_unwatch_name (watch);
+
+  kill (pid1, SIGTERM);
+  kill (pid2, SIGTERM);
+}
+
+int
+main (int argc, char *argv[])
+{
+  g_type_init ();
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add_func ("/application/unique", test_unique);
+  g_test_add_func ("/application/quit", test_quit);
+  g_test_add_func ("/application/list-actions", test_list_actions);
+  g_test_add_func ("/application/invoke", test_invoke);
+  g_test_add_func ("/application/remote", test_remote);
+
+  return g_test_run ();
+}
+



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]