Merge branch 'dbus-1.4'
[platform/upstream/dbus.git] / test / dbus-daemon.c
1 /* Integration tests for the dbus-daemon
2  *
3  * Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
4  * Copyright © 2010-2011 Nokia Corporation
5  *
6  * Permission is hereby granted, free of charge, to any person
7  * obtaining a copy of this software and associated documentation files
8  * (the "Software"), to deal in the Software without restriction,
9  * including without limitation the rights to use, copy, modify, merge,
10  * publish, distribute, sublicense, and/or sell copies of the Software,
11  * and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24  * SOFTWARE.
25  */
26
27 #include <config.h>
28
29 #include <glib.h>
30
31 #include <dbus/dbus.h>
32 #include <dbus/dbus-glib-lowlevel.h>
33
34 #include <string.h>
35
36 #ifdef DBUS_WIN
37 # include <io.h>
38 # include <windows.h>
39 #else
40 # include <signal.h>
41 # include <unistd.h>
42 #endif
43
44 typedef struct {
45     gboolean skip;
46
47     DBusError e;
48     GError *ge;
49
50     GPid daemon_pid;
51
52     DBusConnection *left_conn;
53
54     DBusConnection *right_conn;
55     gboolean right_conn_echo;
56 } Fixture;
57
58 #define assert_no_error(e) _assert_no_error (e, __FILE__, __LINE__)
59 static void
60 _assert_no_error (const DBusError *e,
61     const char *file,
62     int line)
63 {
64   if (G_UNLIKELY (dbus_error_is_set (e)))
65     g_error ("%s:%d: expected success but got error: %s: %s",
66         file, line, e->name, e->message);
67 }
68
69 static gchar *
70 spawn_dbus_daemon (gchar *binary,
71     gchar *configuration,
72     GPid *daemon_pid)
73 {
74   GError *error = NULL;
75   GString *address;
76   gint address_fd;
77   gchar *argv[] = {
78       binary,
79       configuration,
80       "--nofork",
81       "--print-address=1", /* stdout */
82       NULL
83   };
84
85   g_spawn_async_with_pipes (NULL, /* working directory */
86       argv,
87       NULL, /* envp */
88       G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
89       NULL, /* child_setup */
90       NULL, /* user data */
91       daemon_pid,
92       NULL, /* child's stdin = /dev/null */
93       &address_fd,
94       NULL, /* child's stderr = our stderr */
95       &error);
96   g_assert_no_error (error);
97
98   address = g_string_new (NULL);
99
100   /* polling until the dbus-daemon writes out its address is a bit stupid,
101    * but at least it's simple, unlike dbus-launch... in principle we could
102    * use select() here, but life's too short */
103   while (1)
104     {
105       gssize bytes;
106       gchar buf[4096];
107       gchar *newline;
108
109       bytes = read (address_fd, buf, sizeof (buf));
110
111       if (bytes > 0)
112         g_string_append_len (address, buf, bytes);
113
114       newline = strchr (address->str, '\n');
115
116       if (newline != NULL)
117         {
118           g_string_truncate (address, newline - address->str);
119           break;
120         }
121
122       g_usleep (G_USEC_PER_SEC / 10);
123     }
124
125   return g_string_free (address, FALSE);
126 }
127
128 static DBusConnection *
129 connect_to_bus (const gchar *address)
130 {
131   DBusConnection *conn;
132   DBusError error = DBUS_ERROR_INIT;
133   dbus_bool_t ok;
134
135   conn = dbus_connection_open_private (address, &error);
136   assert_no_error (&error);
137   g_assert (conn != NULL);
138
139   ok = dbus_bus_register (conn, &error);
140   assert_no_error (&error);
141   g_assert (ok);
142   g_assert (dbus_bus_get_unique_name (conn) != NULL);
143
144   dbus_connection_setup_with_g_main (conn, NULL);
145   return conn;
146 }
147
148 static DBusHandlerResult
149 echo_filter (DBusConnection *connection,
150     DBusMessage *message,
151     void *user_data)
152 {
153   DBusMessage *reply;
154
155   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
156     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
157
158   reply = dbus_message_new_method_return (message);
159
160   if (reply == NULL)
161     g_error ("OOM");
162
163   if (!dbus_connection_send (connection, reply, NULL))
164     g_error ("OOM");
165
166   dbus_message_unref (reply);
167
168   return DBUS_HANDLER_RESULT_HANDLED;
169 }
170
171 typedef struct {
172     const char *bug_ref;
173     guint min_messages;
174     const char *config_file;
175 } Config;
176
177 static void
178 setup (Fixture *f,
179     gconstpointer context)
180 {
181   const Config *config = context;
182   gchar *dbus_daemon;
183   gchar *arg;
184   gchar *address;
185
186   f->ge = NULL;
187   dbus_error_init (&f->e);
188
189   if (config != NULL && config->config_file != NULL)
190     {
191       if (g_getenv ("DBUS_TEST_DATA") == NULL)
192         {
193           g_message ("SKIP: set DBUS_TEST_DATA to a directory containing %s",
194               config->config_file);
195           f->skip = TRUE;
196           return;
197         }
198
199       arg = g_strdup_printf (
200           "--config-file=%s/%s",
201           g_getenv ("DBUS_TEST_DATA"), config->config_file);
202     }
203   else if (g_getenv ("DBUS_TEST_SYSCONFDIR") != NULL)
204     {
205       arg = g_strdup_printf ("--config-file=%s/dbus-1/session.conf",
206           g_getenv ("DBUS_TEST_SYSCONFDIR"));
207     }
208   else if (g_getenv ("DBUS_TEST_DATA") != NULL)
209     {
210       arg = g_strdup_printf (
211           "--config-file=%s/valid-config-files/session.conf",
212           g_getenv ("DBUS_TEST_DATA"));
213     }
214   else
215     {
216       arg = g_strdup ("--session");
217     }
218
219   dbus_daemon = g_strdup (g_getenv ("DBUS_TEST_DAEMON"));
220
221   if (dbus_daemon == NULL)
222     dbus_daemon = g_strdup ("dbus-daemon");
223
224   address = spawn_dbus_daemon (dbus_daemon, arg, &f->daemon_pid);
225
226   g_free (dbus_daemon);
227   g_free (arg);
228
229   f->left_conn = connect_to_bus (address);
230   f->right_conn = connect_to_bus (address);
231   g_free (address);
232 }
233
234 static void
235 add_echo_filter (Fixture *f)
236 {
237   if (!dbus_connection_add_filter (f->right_conn, echo_filter, NULL, NULL))
238     g_error ("OOM");
239
240   f->right_conn_echo = TRUE;
241 }
242
243 static void
244 pc_count (DBusPendingCall *pc,
245     void *data)
246 {
247   guint *received_p = data;
248
249   (*received_p)++;
250 }
251
252 static void
253 test_echo (Fixture *f,
254     gconstpointer context)
255 {
256   const Config *config = context;
257   guint count = 2000;
258   guint sent;
259   guint received = 0;
260   double elapsed;
261
262   if (f->skip)
263     return;
264
265   if (config != NULL && config->bug_ref != NULL)
266     g_test_bug (config->bug_ref);
267
268   if (g_test_perf ())
269     count = 100000;
270
271   if (config != NULL)
272     count = MAX (config->min_messages, count);
273
274   add_echo_filter (f);
275
276   g_test_timer_start ();
277
278   for (sent = 0; sent < count; sent++)
279     {
280       DBusMessage *m = dbus_message_new_method_call (
281           dbus_bus_get_unique_name (f->right_conn), "/",
282           "com.example", "Spam");
283       DBusPendingCall *pc;
284
285       if (m == NULL)
286         g_error ("OOM");
287
288       if (!dbus_connection_send_with_reply (f->left_conn, m, &pc,
289                                             DBUS_TIMEOUT_INFINITE) ||
290           pc == NULL)
291         g_error ("OOM");
292
293       if (dbus_pending_call_get_completed (pc))
294         pc_count (pc, &received);
295       else if (!dbus_pending_call_set_notify (pc, pc_count, &received,
296             NULL))
297         g_error ("OOM");
298
299       dbus_pending_call_unref (pc);
300       dbus_message_unref (m);
301     }
302
303   while (received < count)
304     g_main_context_iteration (NULL, TRUE);
305
306   elapsed = g_test_timer_elapsed ();
307
308   g_test_maximized_result (count / elapsed, "%u messages / %f seconds",
309       count, elapsed);
310 }
311
312 static void
313 teardown (Fixture *f,
314     gconstpointer context G_GNUC_UNUSED)
315 {
316   dbus_error_free (&f->e);
317   g_clear_error (&f->ge);
318
319   if (f->left_conn != NULL)
320     {
321       dbus_connection_close (f->left_conn);
322       dbus_connection_unref (f->left_conn);
323       f->left_conn = NULL;
324     }
325
326   if (f->right_conn != NULL)
327     {
328       if (f->right_conn_echo)
329         {
330           dbus_connection_remove_filter (f->right_conn, echo_filter, NULL);
331           f->right_conn_echo = FALSE;
332         }
333
334       dbus_connection_close (f->right_conn);
335       dbus_connection_unref (f->right_conn);
336       f->right_conn = NULL;
337     }
338
339   if (f->daemon_pid != 0)
340     {
341 #ifdef DBUS_WIN
342       TerminateProcess (f->daemon_pid, 1);
343 #else
344       kill (f->daemon_pid, SIGTERM);
345 #endif
346
347       g_spawn_close_pid (f->daemon_pid);
348       f->daemon_pid = 0;
349     }
350 }
351
352 static Config limited_config = {
353     "34393", 10000, "valid-config-files/incoming-limit.conf"
354 };
355
356 int
357 main (int argc,
358     char **argv)
359 {
360   g_test_init (&argc, &argv, NULL);
361   g_test_bug_base ("https://bugs.freedesktop.org/show_bug.cgi?id=");
362
363   g_test_add ("/echo/session", Fixture, NULL, setup, test_echo, teardown);
364   g_test_add ("/echo/limited", Fixture, &limited_config,
365       setup, test_echo, teardown);
366
367   return g_test_run ();
368 }