• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
_assert_no_error(const DBusError * e,const char * file,int line)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 *
spawn_dbus_daemon(gchar * binary,gchar * configuration,GPid * daemon_pid)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 *
connect_to_bus(const gchar * address)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
echo_filter(DBusConnection * connection,DBusMessage * message,void * user_data)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
setup(Fixture * f,gconstpointer context)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
add_echo_filter(Fixture * f)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
pc_count(DBusPendingCall * pc,void * data)244 pc_count (DBusPendingCall *pc,
245     void *data)
246 {
247   guint *received_p = data;
248 
249   (*received_p)++;
250 }
251 
252 static void
test_echo(Fixture * f,gconstpointer context)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
teardown(Fixture * f,gconstpointer context G_GNUC_UNUSED)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
main(int argc,char ** argv)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 }
369