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 <unistd.h> |
23 | #include <string.h> |
24 | |
25 | #include <sys/types.h> |
26 | |
27 | #include "gdbus-tests.h" |
28 | |
29 | /* all tests rely on a shared mainloop */ |
30 | static GMainLoop *loop = NULL; |
31 | |
32 | /* ---------------------------------------------------------------------------------------------------- */ |
33 | |
34 | static void |
35 | test_connection_flush_signal_handler (GDBusConnection *connection, |
36 | const gchar *sender_name, |
37 | const gchar *object_path, |
38 | const gchar *interface_name, |
39 | const gchar *signal_name, |
40 | GVariant *parameters, |
41 | gpointer user_data) |
42 | { |
43 | g_main_loop_quit (loop); |
44 | } |
45 | |
46 | static gboolean |
47 | test_connection_flush_on_timeout (gpointer user_data) |
48 | { |
49 | guint iteration = GPOINTER_TO_UINT (user_data); |
50 | g_printerr (format: "Timeout waiting 1000 msec on iteration %d\n" , iteration); |
51 | g_assert_not_reached (); |
52 | return G_SOURCE_REMOVE; |
53 | } |
54 | |
55 | static void |
56 | test_connection_flush (void) |
57 | { |
58 | GDBusConnection *connection; |
59 | GError *error; |
60 | guint n; |
61 | guint signal_handler_id; |
62 | const gchar *flush_helper; |
63 | |
64 | session_bus_up (); |
65 | |
66 | error = NULL; |
67 | connection = g_bus_get_sync (bus_type: G_BUS_TYPE_SESSION, NULL, error: &error); |
68 | g_assert_no_error (error); |
69 | g_assert (connection != NULL); |
70 | |
71 | signal_handler_id = g_dbus_connection_signal_subscribe (connection, |
72 | NULL, /* sender */ |
73 | interface_name: "org.gtk.GDBus.FlushInterface" , |
74 | member: "SomeSignal" , |
75 | object_path: "/org/gtk/GDBus/FlushObject" , |
76 | NULL, |
77 | flags: G_DBUS_SIGNAL_FLAGS_NONE, |
78 | callback: test_connection_flush_signal_handler, |
79 | NULL, |
80 | NULL); |
81 | g_assert_cmpint (signal_handler_id, !=, 0); |
82 | |
83 | flush_helper = g_test_get_filename (file_type: G_TEST_BUILT, first_path: "gdbus-connection-flush-helper" , NULL); |
84 | for (n = 0; n < 50; n++) |
85 | { |
86 | gboolean ret; |
87 | gint exit_status; |
88 | guint timeout_mainloop_id; |
89 | gchar *flush_helper_stdout = NULL; |
90 | gchar *flush_helper_stderr = NULL; |
91 | |
92 | error = NULL; |
93 | ret = g_spawn_command_line_sync (command_line: flush_helper, |
94 | standard_output: &flush_helper_stdout, |
95 | standard_error: &flush_helper_stderr, |
96 | exit_status: &exit_status, |
97 | error: &error) && |
98 | g_spawn_check_exit_status (exit_status, error: &error); |
99 | if (!ret) |
100 | g_test_message (format: "Child process ā%sā failed. stdout:\n%s\nstderr:\n%s" , |
101 | flush_helper, flush_helper_stdout, flush_helper_stderr); |
102 | |
103 | g_free (mem: flush_helper_stdout); |
104 | g_free (mem: flush_helper_stderr); |
105 | |
106 | g_assert_no_error (error); |
107 | g_assert_true (ret); |
108 | |
109 | timeout_mainloop_id = g_timeout_add (interval: 1000, function: test_connection_flush_on_timeout, GUINT_TO_POINTER (n)); |
110 | g_main_loop_run (loop); |
111 | g_source_remove (tag: timeout_mainloop_id); |
112 | } |
113 | |
114 | g_dbus_connection_signal_unsubscribe (connection, subscription_id: signal_handler_id); |
115 | g_object_unref (object: connection); |
116 | |
117 | session_bus_down (); |
118 | } |
119 | |
120 | /* ---------------------------------------------------------------------------------------------------- */ |
121 | |
122 | /* Message size > 20MiB ... should be enough to make sure the message |
123 | * is fragmented when shoved across any transport |
124 | */ |
125 | #define LARGE_MESSAGE_STRING_LENGTH (20*1024*1024) |
126 | /* the test will fail if the service name has not appeared after this amount of seconds */ |
127 | #define LARGE_MESSAGE_TIMEOUT_SECONDS 10 |
128 | |
129 | static gboolean |
130 | large_message_timeout_cb (gpointer data) |
131 | { |
132 | (void)data; |
133 | |
134 | g_error ("Error: timeout waiting for dbus name to appear" ); |
135 | |
136 | return G_SOURCE_REMOVE; |
137 | } |
138 | |
139 | static void |
140 | large_message_on_name_appeared (GDBusConnection *connection, |
141 | const gchar *name, |
142 | const gchar *name_owner, |
143 | gpointer user_data) |
144 | { |
145 | GError *error; |
146 | gchar *request; |
147 | const gchar *reply; |
148 | GVariant *result; |
149 | guint n; |
150 | |
151 | g_assert (g_source_remove (GPOINTER_TO_UINT (user_data))); |
152 | |
153 | request = g_new (gchar, LARGE_MESSAGE_STRING_LENGTH + 1); |
154 | for (n = 0; n < LARGE_MESSAGE_STRING_LENGTH; n++) |
155 | request[n] = '0' + (n%10); |
156 | request[n] = '\0'; |
157 | |
158 | error = NULL; |
159 | result = g_dbus_connection_call_sync (connection, |
160 | bus_name: "com.example.TestService" , /* bus name */ |
161 | object_path: "/com/example/TestObject" , /* object path */ |
162 | interface_name: "com.example.Frob" , /* interface name */ |
163 | method_name: "HelloWorld" , /* method name */ |
164 | parameters: g_variant_new (format_string: "(s)" , request), /* parameters */ |
165 | G_VARIANT_TYPE ("(s)" ), /* return type */ |
166 | flags: G_DBUS_CALL_FLAGS_NONE, |
167 | G_MAXINT, |
168 | NULL, |
169 | error: &error); |
170 | g_assert_no_error (error); |
171 | g_assert (result != NULL); |
172 | g_variant_get (value: result, format_string: "(&s)" , &reply); |
173 | g_assert_cmpint (strlen (reply), >, LARGE_MESSAGE_STRING_LENGTH); |
174 | g_assert (g_str_has_prefix (reply, "You greeted me with '01234567890123456789012" )); |
175 | g_assert (g_str_has_suffix (reply, "6789'. Thanks!" )); |
176 | g_variant_unref (value: result); |
177 | |
178 | g_free (mem: request); |
179 | |
180 | g_main_loop_quit (loop); |
181 | } |
182 | |
183 | static void |
184 | large_message_on_name_vanished (GDBusConnection *connection, |
185 | const gchar *name, |
186 | gpointer user_data) |
187 | { |
188 | } |
189 | |
190 | static void |
191 | test_connection_large_message (void) |
192 | { |
193 | guint watcher_id; |
194 | guint timeout_id; |
195 | |
196 | session_bus_up (); |
197 | |
198 | /* this is safe; testserver will exit once the bus goes away */ |
199 | g_assert (g_spawn_command_line_async (g_test_get_filename (G_TEST_BUILT, "gdbus-testserver" , NULL), NULL)); |
200 | |
201 | timeout_id = g_timeout_add_seconds (LARGE_MESSAGE_TIMEOUT_SECONDS, |
202 | function: large_message_timeout_cb, |
203 | NULL); |
204 | |
205 | watcher_id = g_bus_watch_name (bus_type: G_BUS_TYPE_SESSION, |
206 | name: "com.example.TestService" , |
207 | flags: G_BUS_NAME_WATCHER_FLAGS_NONE, |
208 | name_appeared_handler: large_message_on_name_appeared, |
209 | name_vanished_handler: large_message_on_name_vanished, |
210 | GUINT_TO_POINTER (timeout_id), /* user_data */ |
211 | NULL); /* GDestroyNotify */ |
212 | g_main_loop_run (loop); |
213 | g_bus_unwatch_name (watcher_id); |
214 | |
215 | session_bus_down (); |
216 | } |
217 | |
218 | /* ---------------------------------------------------------------------------------------------------- */ |
219 | |
220 | int |
221 | main (int argc, |
222 | char *argv[]) |
223 | { |
224 | gint ret; |
225 | |
226 | g_test_init (argc: &argc, argv: &argv, NULL); |
227 | |
228 | /* all the tests rely on a shared main loop */ |
229 | loop = g_main_loop_new (NULL, FALSE); |
230 | |
231 | g_test_dbus_unset (); |
232 | |
233 | g_test_add_func (testpath: "/gdbus/connection/flush" , test_func: test_connection_flush); |
234 | g_test_add_func (testpath: "/gdbus/connection/large_message" , test_func: test_connection_large_message); |
235 | |
236 | ret = g_test_run(); |
237 | g_main_loop_unref (loop); |
238 | return ret; |
239 | } |
240 | |