1 | /* GLib testing framework examples and tests |
2 | * |
3 | * Copyright (C) 2008-2010 Red Hat, Inc. |
4 | * |
5 | * This library is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Lesser General Public |
7 | * License as published by the Free Software Foundation; either |
8 | * version 2.1 of the License, or (at your option) any later version. |
9 | * |
10 | * This library is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Lesser General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU Lesser General |
16 | * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. |
17 | * |
18 | * Author: David Zeuthen <davidz@redhat.com> |
19 | */ |
20 | |
21 | #include <gio/gio.h> |
22 | #include <stdlib.h> |
23 | #include <unistd.h> |
24 | #include <string.h> |
25 | |
26 | #include "gdbus-tests.h" |
27 | |
28 | /* all tests rely on a shared mainloop */ |
29 | static GMainLoop *loop = NULL; |
30 | |
31 | /* ---------------------------------------------------------------------------------------------------- */ |
32 | |
33 | typedef struct { |
34 | const gchar *name; |
35 | const gchar *bug; |
36 | enum { |
37 | EXPLICITLY_FALSE = FALSE, |
38 | EXPLICITLY_TRUE = TRUE, |
39 | IMPLICITLY_TRUE |
40 | } exit_on_close; |
41 | enum { |
42 | LOCAL, |
43 | REMOTE |
44 | } who_closes; |
45 | } TestData; |
46 | |
47 | static const TestData cases[] = { |
48 | { "default" , NULL, IMPLICITLY_TRUE, REMOTE }, |
49 | { "true" , NULL, EXPLICITLY_TRUE, REMOTE }, |
50 | { "false" , NULL, EXPLICITLY_FALSE, REMOTE }, |
51 | { "we-close" , "662100" , EXPLICITLY_TRUE, LOCAL }, |
52 | { NULL } |
53 | }; |
54 | |
55 | static gboolean |
56 | quit_later_cb (gpointer data G_GNUC_UNUSED) |
57 | { |
58 | g_main_loop_quit (loop); |
59 | |
60 | return G_SOURCE_REMOVE; |
61 | } |
62 | |
63 | static void |
64 | closed_cb (GDBusConnection *c G_GNUC_UNUSED, |
65 | gboolean remote_peer_vanished, |
66 | GError *error, |
67 | gpointer test_data) |
68 | { |
69 | const TestData *td = test_data; |
70 | |
71 | if (error == NULL) |
72 | g_debug ("closed (%d, no error)" , remote_peer_vanished); |
73 | else |
74 | g_debug ("closed (%d, %s %d \"%s\")" , remote_peer_vanished, |
75 | g_quark_to_string (error->domain), error->code, error->message); |
76 | |
77 | g_assert_cmpint (remote_peer_vanished, ==, (td->who_closes == REMOTE)); |
78 | g_assert_cmpint ((error == NULL), ==, (td->who_closes == LOCAL)); |
79 | |
80 | /* we delay this so that if exit-on-close was going to happen, it will |
81 | * win the race |
82 | */ |
83 | g_timeout_add (interval: 50, function: quit_later_cb, NULL); |
84 | } |
85 | |
86 | static void |
87 | close_async_cb (GObject *source G_GNUC_UNUSED, |
88 | GAsyncResult *res G_GNUC_UNUSED, |
89 | gpointer nil G_GNUC_UNUSED) |
90 | { |
91 | GError *error = NULL; |
92 | |
93 | if (g_dbus_connection_close_finish (G_DBUS_CONNECTION (source), |
94 | res, |
95 | error: &error)) |
96 | { |
97 | g_debug ("closed connection" ); |
98 | } |
99 | else |
100 | { |
101 | g_warning ("failed to close connection: %s (%s #%d)" , |
102 | error->message, g_quark_to_string (error->domain), |
103 | error->code); |
104 | } |
105 | } |
106 | |
107 | static void |
108 | test_exit_on_close_subprocess (gconstpointer test_data) |
109 | { |
110 | const TestData *td = test_data; |
111 | GDBusConnection *c; |
112 | |
113 | loop = g_main_loop_new (NULL, FALSE); |
114 | |
115 | session_bus_up (); |
116 | c = g_bus_get_sync (bus_type: G_BUS_TYPE_SESSION, NULL, NULL); |
117 | |
118 | g_assert (c != NULL); |
119 | |
120 | /* the default is meant to be TRUE */ |
121 | if (td->exit_on_close != IMPLICITLY_TRUE) |
122 | g_dbus_connection_set_exit_on_close (connection: c, exit_on_close: td->exit_on_close); |
123 | |
124 | g_assert_cmpint (g_dbus_connection_get_exit_on_close (c), ==, |
125 | (td->exit_on_close != EXPLICITLY_FALSE)); |
126 | g_assert (!g_dbus_connection_is_closed (c)); |
127 | |
128 | g_timeout_add (interval: 50, function: quit_later_cb, NULL); |
129 | g_main_loop_run (loop); |
130 | |
131 | g_signal_connect (c, "closed" , G_CALLBACK (closed_cb), (gpointer) td); |
132 | |
133 | if (td->who_closes == LOCAL) |
134 | { |
135 | GVariant *v; |
136 | GError *error = NULL; |
137 | |
138 | v = g_dbus_connection_call_sync (connection: c, bus_name: "org.freedesktop.DBus" , |
139 | object_path: "/org/freedesktop/DBus" , |
140 | interface_name: "org.freedesktop.DBus" , |
141 | method_name: "ListNames" , |
142 | NULL, |
143 | G_VARIANT_TYPE ("(as)" ), |
144 | flags: G_DBUS_CALL_FLAGS_NONE, |
145 | timeout_msec: -1, |
146 | NULL, |
147 | error: &error); |
148 | g_assert_no_error (error); |
149 | g_assert (v != NULL); |
150 | g_variant_unref (value: v); |
151 | |
152 | g_dbus_connection_close (connection: c, NULL, callback: close_async_cb, NULL); |
153 | } |
154 | else |
155 | { |
156 | session_bus_stop (); |
157 | } |
158 | |
159 | g_main_loop_run (loop); |
160 | /* this is only reached when we turn off exit-on-close */ |
161 | g_main_loop_unref (loop); |
162 | g_object_unref (object: c); |
163 | |
164 | session_bus_down (); |
165 | |
166 | exit (status: 0); |
167 | } |
168 | |
169 | static void |
170 | test_exit_on_close (gconstpointer test_data) |
171 | { |
172 | const TestData *td = test_data; |
173 | GTestSubprocessFlags flags; |
174 | char *child_name; |
175 | |
176 | g_test_dbus_unset (); |
177 | |
178 | if (g_test_verbose ()) |
179 | flags = G_TEST_SUBPROCESS_INHERIT_STDOUT | G_TEST_SUBPROCESS_INHERIT_STDERR; |
180 | else |
181 | flags = 0; |
182 | |
183 | child_name = g_strdup_printf (format: "/gdbus/exit-on-close/%s/subprocess" , td->name); |
184 | g_test_trap_subprocess (test_path: child_name, usec_timeout: 0, test_flags: flags); |
185 | g_free (mem: child_name); |
186 | |
187 | if (td->exit_on_close == EXPLICITLY_FALSE || |
188 | td->who_closes == LOCAL) |
189 | g_test_trap_assert_passed (); |
190 | else |
191 | g_test_trap_assert_failed(); |
192 | } |
193 | |
194 | /* ---------------------------------------------------------------------------------------------------- */ |
195 | |
196 | int |
197 | main (int argc, |
198 | char *argv[]) |
199 | { |
200 | gint i; |
201 | |
202 | g_test_init (argc: &argc, argv: &argv, NULL); |
203 | |
204 | for (i = 0; cases[i].name != NULL; i++) |
205 | { |
206 | gchar *name; |
207 | |
208 | name = g_strdup_printf (format: "/gdbus/exit-on-close/%s" , cases[i].name); |
209 | g_test_add_data_func (testpath: name, test_data: &cases[i], test_func: test_exit_on_close); |
210 | g_free (mem: name); |
211 | |
212 | name = g_strdup_printf (format: "/gdbus/exit-on-close/%s/subprocess" , cases[i].name); |
213 | g_test_add_data_func (testpath: name, test_data: &cases[i], test_func: test_exit_on_close_subprocess); |
214 | g_free (mem: name); |
215 | } |
216 | |
217 | return g_test_run(); |
218 | } |
219 | |