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 | #ifndef _MSC_VER |
23 | #include <unistd.h> |
24 | #endif |
25 | |
26 | #include "gdbus-tests.h" |
27 | |
28 | /* ---------------------------------------------------------------------------------------------------- */ |
29 | |
30 | typedef struct |
31 | { |
32 | GMainLoop *loop; |
33 | gboolean timed_out; |
34 | } PropertyNotifyData; |
35 | |
36 | static void |
37 | on_property_notify (GObject *object, |
38 | GParamSpec *pspec, |
39 | gpointer user_data) |
40 | { |
41 | PropertyNotifyData *data = user_data; |
42 | g_main_loop_quit (loop: data->loop); |
43 | } |
44 | |
45 | static gboolean |
46 | on_property_notify_timeout (gpointer user_data) |
47 | { |
48 | PropertyNotifyData *data = user_data; |
49 | data->timed_out = TRUE; |
50 | g_main_loop_quit (loop: data->loop); |
51 | return G_SOURCE_CONTINUE; |
52 | } |
53 | |
54 | gboolean |
55 | _g_assert_property_notify_run (gpointer object, |
56 | const gchar *property_name) |
57 | { |
58 | gchar *s; |
59 | gulong handler_id; |
60 | guint timeout_id; |
61 | PropertyNotifyData data; |
62 | |
63 | data.loop = g_main_loop_new (context: g_main_context_get_thread_default (), FALSE); |
64 | data.timed_out = FALSE; |
65 | s = g_strdup_printf (format: "notify::%s" , property_name); |
66 | handler_id = g_signal_connect (object, |
67 | s, |
68 | G_CALLBACK (on_property_notify), |
69 | &data); |
70 | g_free (mem: s); |
71 | timeout_id = g_timeout_add_seconds (interval: 30, |
72 | function: on_property_notify_timeout, |
73 | data: &data); |
74 | g_main_loop_run (loop: data.loop); |
75 | g_signal_handler_disconnect (instance: object, handler_id); |
76 | g_source_remove (tag: timeout_id); |
77 | g_main_loop_unref (loop: data.loop); |
78 | |
79 | return data.timed_out; |
80 | } |
81 | |
82 | static gboolean |
83 | _give_up (gpointer data) |
84 | { |
85 | g_error ("%s" , (const gchar *) data); |
86 | g_return_val_if_reached (G_SOURCE_CONTINUE); |
87 | } |
88 | |
89 | typedef struct |
90 | { |
91 | GMainContext *context; |
92 | gboolean name_appeared; |
93 | gboolean unwatch_complete; |
94 | } WatchData; |
95 | |
96 | static void |
97 | name_appeared_cb (GDBusConnection *connection, |
98 | const gchar *name, |
99 | const gchar *name_owner, |
100 | gpointer user_data) |
101 | { |
102 | WatchData *data = user_data; |
103 | |
104 | g_assert (name_owner != NULL); |
105 | data->name_appeared = TRUE; |
106 | g_main_context_wakeup (context: data->context); |
107 | } |
108 | |
109 | static void |
110 | watch_free_cb (gpointer user_data) |
111 | { |
112 | WatchData *data = user_data; |
113 | |
114 | data->unwatch_complete = TRUE; |
115 | g_main_context_wakeup (context: data->context); |
116 | } |
117 | |
118 | void |
119 | ensure_gdbus_testserver_up (GDBusConnection *connection, |
120 | GMainContext *context) |
121 | { |
122 | GSource *timeout_source = NULL; |
123 | guint watch_id; |
124 | WatchData data = { context, FALSE, FALSE }; |
125 | |
126 | g_main_context_push_thread_default (context); |
127 | |
128 | watch_id = g_bus_watch_name_on_connection (connection, |
129 | name: "com.example.TestService" , |
130 | flags: G_BUS_NAME_WATCHER_FLAGS_NONE, |
131 | name_appeared_handler: name_appeared_cb, |
132 | NULL, |
133 | user_data: &data, |
134 | user_data_free_func: watch_free_cb); |
135 | |
136 | timeout_source = g_timeout_source_new_seconds (interval: 60); |
137 | g_source_set_callback (source: timeout_source, func: _give_up, |
138 | data: "waited more than ~ 60s for gdbus-testserver to take its bus name" , |
139 | NULL); |
140 | g_source_attach (source: timeout_source, context); |
141 | |
142 | while (!data.name_appeared) |
143 | g_main_context_iteration (context, TRUE); |
144 | |
145 | g_bus_unwatch_name (watcher_id: watch_id); |
146 | watch_id = 0; |
147 | |
148 | while (!data.unwatch_complete) |
149 | g_main_context_iteration (context, TRUE); |
150 | |
151 | g_source_destroy (source: timeout_source); |
152 | g_source_unref (source: timeout_source); |
153 | |
154 | g_main_context_pop_thread_default (context); |
155 | } |
156 | |
157 | /* ---------------------------------------------------------------------------------------------------- */ |
158 | |
159 | typedef struct |
160 | { |
161 | GMainLoop *loop; |
162 | gboolean timed_out; |
163 | } SignalReceivedData; |
164 | |
165 | static void |
166 | on_signal_received (gpointer user_data) |
167 | { |
168 | SignalReceivedData *data = user_data; |
169 | g_main_loop_quit (loop: data->loop); |
170 | } |
171 | |
172 | static gboolean |
173 | on_signal_received_timeout (gpointer user_data) |
174 | { |
175 | SignalReceivedData *data = user_data; |
176 | data->timed_out = TRUE; |
177 | g_main_loop_quit (loop: data->loop); |
178 | return G_SOURCE_CONTINUE; |
179 | } |
180 | |
181 | gboolean |
182 | _g_assert_signal_received_run (gpointer object, |
183 | const gchar *signal_name) |
184 | { |
185 | gulong handler_id; |
186 | guint timeout_id; |
187 | SignalReceivedData data; |
188 | |
189 | data.loop = g_main_loop_new (context: g_main_context_get_thread_default (), FALSE); |
190 | data.timed_out = FALSE; |
191 | handler_id = g_signal_connect_swapped (object, |
192 | signal_name, |
193 | G_CALLBACK (on_signal_received), |
194 | &data); |
195 | timeout_id = g_timeout_add_seconds (interval: 30, |
196 | function: on_signal_received_timeout, |
197 | data: &data); |
198 | g_main_loop_run (loop: data.loop); |
199 | g_signal_handler_disconnect (instance: object, handler_id); |
200 | g_source_remove (tag: timeout_id); |
201 | g_main_loop_unref (loop: data.loop); |
202 | |
203 | return data.timed_out; |
204 | } |
205 | |
206 | /* ---------------------------------------------------------------------------------------------------- */ |
207 | |
208 | GDBusConnection * |
209 | _g_bus_get_priv (GBusType bus_type, |
210 | GCancellable *cancellable, |
211 | GError **error) |
212 | { |
213 | gchar *address; |
214 | GDBusConnection *ret; |
215 | |
216 | ret = NULL; |
217 | |
218 | address = g_dbus_address_get_for_bus_sync (bus_type, cancellable, error); |
219 | if (address == NULL) |
220 | goto out; |
221 | |
222 | ret = g_dbus_connection_new_for_address_sync (address, |
223 | flags: G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT | |
224 | G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION, |
225 | NULL, /* GDBusAuthObserver */ |
226 | cancellable, |
227 | error); |
228 | g_free (mem: address); |
229 | |
230 | out: |
231 | return ret; |
232 | } |
233 | |
234 | /* ---------------------------------------------------------------------------------------------------- */ |
235 | |