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 <windows.h>
38 #else
39 # include <signal.h>
40 # include <unistd.h>
41 #endif
42
43 typedef struct {
44     gboolean skip;
45
46     DBusError e;
47     GError *ge;
48
49     gint daemon_pid;
50
51     DBusConnection *left_conn;
52
53     DBusConnection *right_conn;
54     gboolean right_conn_echo;
55 } Fixture;
56
57 #define assert_no_error(e) _assert_no_error (e, __FILE__, __LINE__)
58 static void
59 _assert_no_error (const DBusError *e,
60     const char *file,
61     int line)
62 {
63   if (G_UNLIKELY (dbus_error_is_set (e)))
64     g_error ("%s:%d: expected success but got error: %s: %s",
65         file, line, e->name, e->message);
66 }
67
68 static gchar *
69 spawn_dbus_daemon (gchar *binary,
70     gchar *configuration,
71     gint *daemon_pid)
72 {
73   GError *error = NULL;
74   GString *address;
75   gint address_fd;
76   gchar *argv[] = {
77       binary,
78       configuration,
79       "--nofork",
80       "--print-address=1", /* stdout */
81       NULL
82   };
83
84   g_spawn_async_with_pipes (NULL, /* working directory */
85       argv,
86       NULL, /* envp */
87       G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
88       NULL, /* child_setup */
89       NULL, /* user data */
90       daemon_pid,
91       NULL, /* child's stdin = /dev/null */
92       &address_fd,
93       NULL, /* child's stderr = our stderr */
94       &error);
95   g_assert_no_error (error);
96
97   address = g_string_new (NULL);
98
99   /* polling until the dbus-daemon writes out its address is a bit stupid,
100    * but at least it's simple, unlike dbus-launch... in principle we could
101    * use select() here, but life's too short */
102   while (1)
103     {
104       gssize bytes;
105       gchar buf[4096];
106       gchar *newline;
107
108       bytes = read (address_fd, buf, sizeof (buf));
109
110       if (bytes > 0)
111         g_string_append_len (address, buf, bytes);
112
113       newline = strchr (address->str, '\n');
114
115       if (newline != NULL)
116         {
117           g_string_truncate (address, newline - address->str);
118           break;
119         }
120
121       g_usleep (G_USEC_PER_SEC / 10);
122     }
123
124   return g_string_free (address, FALSE);
125 }
126
127 static DBusConnection *
128 connect_to_bus (const gchar *address)
129 {
130   DBusConnection *conn;
131   DBusError error = DBUS_ERROR_INIT;
132   dbus_bool_t ok;
133
134   conn = dbus_connection_open_private (address, &error);
135   assert_no_error (&error);
136   g_assert (conn != NULL);
137
138   ok = dbus_bus_register (conn, &error);
139   assert_no_error (&error);
140   g_assert (ok);
141   g_assert (dbus_bus_get_unique_name (conn) != NULL);
142
143   dbus_connection_setup_with_g_main (conn, NULL);
144   return conn;
145 }
146
147 static DBusHandlerResult
148 echo_filter (DBusConnection *connection,
149     DBusMessage *message,
150     void *user_data)
151 {
152   DBusMessage *reply;
153
154   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
155     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
156
157   reply = dbus_message_new_method_return (message);
158
159   if (reply == NULL)
160     g_error ("OOM");
161
162   if (!dbus_connection_send (connection, reply, NULL))
163     g_error ("OOM");
164
165   dbus_message_unref (reply);
166
167   return DBUS_HANDLER_RESULT_HANDLED;
168 }
169
170 typedef struct {
171     const char *bug_ref;
172     guint min_messages;
173     const char *config_file;
174 } Config;
175
176 static void
177 setup (Fixture *f,
178     gconstpointer context)
179 {
180   const Config *config = context;
181   gchar *dbus_daemon;
182   gchar *arg;
183   gchar *address;
184
185   f->ge = NULL;
186   dbus_error_init (&f->e);
187
188   if (config != NULL && config->config_file != NULL)
189     {
190       if (g_getenv ("DBUS_TEST_DATA") == NULL)
191         {
192           g_message ("SKIP: set DBUS_TEST_DATA to a directory containing %s",
193               config->config_file);
194           f->skip = TRUE;
195           return;
196         }
197
198       arg = g_strdup_printf (
199           "--config-file=%s/%s",
200           g_getenv ("DBUS_TEST_DATA"), config->config_file);
201     }
202   else if (g_getenv ("DBUS_TEST_SYSCONFDIR") != NULL)
203     {
204       arg = g_strdup_printf ("--config-file=%s/dbus-1/session.conf",
205           g_getenv ("DBUS_TEST_SYSCONFDIR"));
206     }
207   else if (g_getenv ("DBUS_TEST_DATA") != NULL)
208     {
209       arg = g_strdup_printf (
210           "--config-file=%s/valid-config-files/session.conf",
211           g_getenv ("DBUS_TEST_DATA"));
212     }
213   else
214     {
215       arg = g_strdup ("--session");
216     }
217
218   dbus_daemon = g_strdup (g_getenv ("DBUS_TEST_DAEMON"));
219
220   if (dbus_daemon == NULL)
221     dbus_daemon = g_strdup ("dbus-daemon");
222
223   address = spawn_dbus_daemon (dbus_daemon, arg, &f->daemon_pid);
224
225   g_free (dbus_daemon);
226   g_free (arg);
227
228   f->left_conn = connect_to_bus (address);
229   f->right_conn = connect_to_bus (address);
230   g_free (address);
231 }
232
233 static void
234 add_echo_filter (Fixture *f)
235 {
236   if (!dbus_connection_add_filter (f->right_conn, echo_filter, NULL, NULL))
237     g_error ("OOM");
238
239   f->right_conn_echo = TRUE;
240 }
241
242 static void
243 pc_count (DBusPendingCall *pc,
244     void *data)
245 {
246   guint *received_p = data;
247
248   (*received_p)++;
249 }
250
251 static void
252 test_echo (Fixture *f,
253     gconstpointer context)
254 {
255   const Config *config = context;
256   guint count = 2000;
257   guint sent;
258   guint received = 0;
259   double elapsed;
260
261   if (f->skip)
262     return;
263
264   if (config != NULL && config->bug_ref != NULL)
265     g_test_bug (config->bug_ref);
266
267   if (g_test_perf ())
268     count = 100000;
269
270   if (config != NULL)
271     count = MAX (config->min_messages, count);
272
273   add_echo_filter (f);
274
275   g_test_timer_start ();
276
277   for (sent = 0; sent < count; sent++)
278     {
279       DBusMessage *m = dbus_message_new_method_call (
280           dbus_bus_get_unique_name (f->right_conn), "/",
281           "com.example", "Spam");
282       DBusPendingCall *pc;
283
284       if (m == NULL)
285         g_error ("OOM");
286
287       if (!dbus_connection_send_with_reply (f->left_conn, m, &pc,
288                                             DBUS_TIMEOUT_INFINITE) ||
289           pc == NULL)
290         g_error ("OOM");
291
292       if (dbus_pending_call_get_completed (pc))
293         pc_count (pc, &received);
294       else if (!dbus_pending_call_set_notify (pc, pc_count, &received,
295             NULL))
296         g_error ("OOM");
297
298       dbus_pending_call_unref (pc);
299       dbus_message_unref (m);
300     }
301
302   while (received < count)
303     g_main_context_iteration (NULL, TRUE);
304
305   elapsed = g_test_timer_elapsed ();
306
307   g_test_maximized_result (count / elapsed, "%u messages / %f seconds",
308       count, elapsed);
309 }
310
311 static void
312 teardown (Fixture *f,
313     gconstpointer context G_GNUC_UNUSED)
314 {
315   dbus_error_free (&f->e);
316   g_clear_error (&f->ge);
317
318   if (f->left_conn != NULL)
319     {
320       dbus_connection_close (f->left_conn);
321       dbus_connection_unref (f->left_conn);
322       f->left_conn = NULL;
323     }
324
325   if (f->right_conn != NULL)
326     {
327       if (f->right_conn_echo)
328         {
329           dbus_connection_remove_filter (f->right_conn, echo_filter, NULL);
330           f->right_conn_echo = FALSE;
331         }
332
333       dbus_connection_close (f->right_conn);
334       dbus_connection_unref (f->right_conn);
335       f->right_conn = NULL;
336     }
337
338   if (f->daemon_pid != 0)
339     {
340 #ifdef DBUS_WIN
341       TerminateProcess (f->daemon_pid, 1);
342 #else
343       kill (f->daemon_pid, SIGTERM);
344 #endif
345
346       g_spawn_close_pid (f->daemon_pid);
347       f->daemon_pid = 0;
348     }
349 }
350
351 static Config limited_config = {
352     "34393", 10000, "valid-config-files/incoming-limit.conf"
353 };
354
355 int
356 main (int argc,
357     char **argv)
358 {
359   g_test_init (&argc, &argv, NULL);
360   g_test_bug_base ("https://bugs.freedesktop.org/show_bug.cgi?id=");
361
362   g_test_add ("/echo/session", Fixture, NULL, setup, test_echo, teardown);
363   g_test_add ("/echo/limited", Fixture, &limited_config,
364       setup, test_echo, teardown);
365
366   return g_test_run ();
367 }