diff options
author | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2011-03-11 13:13:17 +0000 |
---|---|---|
committer | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2011-06-10 18:32:02 +0100 |
commit | ba9c274f33eaa6c642a2e63f8191c483fcd941b9 (patch) | |
tree | ecb0bb779ce3e39188d148a99c092e81e51eefa1 /test/dbus-daemon.c | |
parent | 7f25b33f1f3155424bfbc555b81c6b651aa5cecb (diff) | |
download | dbus-ba9c274f33eaa6c642a2e63f8191c483fcd941b9.tar.gz |
Add a simple integration test for dbus-daemon
This just pushes 2000 messages (or 100000 in performance-testing mode)
through the dbus-daemon, to an echo service and back.
Reviewed-by: Will Thompson <will.thompson@collabora.co.uk>
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=34570
Diffstat (limited to 'test/dbus-daemon.c')
-rw-r--r-- | test/dbus-daemon.c | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/test/dbus-daemon.c b/test/dbus-daemon.c new file mode 100644 index 00000000..04955e03 --- /dev/null +++ b/test/dbus-daemon.c @@ -0,0 +1,320 @@ +/* Integration tests for the dbus-daemon + * + * Author: Simon McVittie <simon.mcvittie@collabora.co.uk> + * Copyright © 2010 Nokia Corporation + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <config.h> + +#include <glib.h> + +#include <dbus/dbus.h> +#include <dbus/dbus-glib-lowlevel.h> + +#include <string.h> + +#ifdef DBUS_WIN +# include <windows.h> +#else +# include <signal.h> +# include <unistd.h> +#endif + +typedef struct { + DBusError e; + GError *ge; + + gint daemon_pid; + + DBusConnection *left_conn; + + DBusConnection *right_conn; + gboolean right_conn_echo; +} Fixture; + +#define assert_no_error(e) _assert_no_error (e, __FILE__, __LINE__) +static void +_assert_no_error (const DBusError *e, + const char *file, + int line) +{ + if (G_UNLIKELY (dbus_error_is_set (e))) + g_error ("%s:%d: expected success but got error: %s: %s", + file, line, e->name, e->message); +} + +static gchar * +spawn_dbus_daemon (gchar *binary, + gchar *configuration, + gint *daemon_pid) +{ + GError *error = NULL; + GString *address; + gint address_fd; + gchar *argv[] = { + binary, + configuration, + "--nofork", + "--print-address=1", /* stdout */ + NULL + }; + + g_spawn_async_with_pipes (NULL, /* working directory */ + argv, + NULL, /* envp */ + G_SPAWN_DO_NOT_REAP_CHILD, + NULL, /* child_setup */ + NULL, /* user data */ + daemon_pid, + NULL, /* child's stdin = /dev/null */ + &address_fd, + NULL, /* child's stderr = our stderr */ + &error); + g_assert_no_error (error); + + address = g_string_new (NULL); + + /* polling until the dbus-daemon writes out its address is a bit stupid, + * but at least it's simple, unlike dbus-launch... in principle we could + * use select() here, but life's too short */ + while (1) + { + gssize bytes; + gchar buf[4096]; + gchar *newline; + + bytes = read (address_fd, buf, sizeof (buf)); + + if (bytes > 0) + g_string_append_len (address, buf, bytes); + + newline = strchr (address->str, '\n'); + + if (newline != NULL) + { + g_string_truncate (address, newline - address->str); + break; + } + + g_usleep (G_USEC_PER_SEC / 10); + } + + return g_string_free (address, FALSE); +} + +static DBusConnection * +connect_to_bus (const gchar *address) +{ + DBusConnection *conn; + DBusError error = DBUS_ERROR_INIT; + dbus_bool_t ok; + + conn = dbus_connection_open_private (address, &error); + assert_no_error (&error); + g_assert (conn != NULL); + + ok = dbus_bus_register (conn, &error); + assert_no_error (&error); + g_assert (ok); + g_assert (dbus_bus_get_unique_name (conn) != NULL); + + dbus_connection_setup_with_g_main (conn, NULL); + return conn; +} + +static DBusHandlerResult +echo_filter (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + DBusMessage *reply; + DBusError error = DBUS_ERROR_INIT; + int *sleep_ms = user_data; + + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + reply = dbus_message_new_method_return (message); + + if (reply == NULL) + g_error ("OOM"); + + if (!dbus_connection_send (connection, reply, NULL)) + g_error ("OOM"); + + dbus_message_unref (reply); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static void +setup (Fixture *f, + gconstpointer context G_GNUC_UNUSED) +{ + gchar *dbus_daemon; + gchar *config; + gchar *address; + + f->ge = NULL; + dbus_error_init (&f->e); + + g_assert (g_getenv ("DBUS_TEST_DAEMON") != NULL); + + dbus_daemon = g_strdup (g_getenv ("DBUS_TEST_DAEMON")); + + if (g_getenv ("DBUS_TEST_USE_INSTALLED") != NULL) + { + config = g_strdup ("--session"); + } + else + { + g_assert (g_getenv ("DBUS_TEST_DATA") != NULL); + config = g_strdup_printf ( + "--config-file=%s/valid-config-files/session.conf", + g_getenv ("DBUS_TEST_DATA")); + } + + address = spawn_dbus_daemon (dbus_daemon, config, &f->daemon_pid); + + g_free (dbus_daemon); + g_free (config); + + f->left_conn = connect_to_bus (address); + f->right_conn = connect_to_bus (address); + g_free (address); +} + +static void +add_echo_filter (Fixture *f) +{ + if (!dbus_connection_add_filter (f->right_conn, echo_filter, NULL, NULL)) + g_error ("OOM"); + + f->right_conn_echo = TRUE; +} + +static void +pc_count (DBusPendingCall *pc, + void *data) +{ + guint *received_p = data; + + (*received_p)++; +} + +static void +test_echo (Fixture *f, + gconstpointer context G_GNUC_UNUSED) +{ + guint count = 2000; + guint sent; + guint received = 0; + double elapsed; + + if (g_test_perf ()) + count = 100000; + + add_echo_filter (f); + + g_test_timer_start (); + + for (sent = 0; sent < count; sent++) + { + DBusMessage *m = dbus_message_new_method_call ( + dbus_bus_get_unique_name (f->right_conn), "/", + "com.example", "Spam"); + DBusPendingCall *pc; + + if (m == NULL) + g_error ("OOM"); + + if (!dbus_connection_send_with_reply (f->left_conn, m, &pc, 0x7FFFFFFF) + || pc == NULL) + g_error ("OOM"); + + if (dbus_pending_call_get_completed (pc)) + pc_count (pc, &received); + else if (!dbus_pending_call_set_notify (pc, pc_count, &received, + NULL)) + g_error ("OOM"); + + dbus_pending_call_unref (pc); + dbus_message_unref (m); + } + + while (received < count) + g_main_context_iteration (NULL, TRUE); + + elapsed = g_test_timer_elapsed (); + + g_test_maximized_result (count / elapsed, "%u messages / %f seconds", + count, elapsed); +} + +static void +teardown (Fixture *f, + gconstpointer context G_GNUC_UNUSED) +{ + dbus_error_free (&f->e); + g_clear_error (&f->ge); + + if (f->left_conn != NULL) + { + dbus_connection_close (f->left_conn); + dbus_connection_unref (f->left_conn); + f->left_conn = NULL; + } + + if (f->right_conn != NULL) + { + if (f->right_conn_echo) + { + dbus_connection_remove_filter (f->right_conn, echo_filter, NULL); + f->right_conn_echo = FALSE; + } + + dbus_connection_close (f->right_conn); + dbus_connection_unref (f->right_conn); + f->right_conn = NULL; + } + +#ifdef DBUS_WIN + TerminateProcess (f->daemon_pid, 1); +#else + kill (f->daemon_pid, SIGTERM); +#endif + + g_spawn_close_pid (f->daemon_pid); +} + +int +main (int argc, + char **argv) +{ + g_test_init (&argc, &argv, NULL); + g_test_bug_base ("https://bugs.freedesktop.org/show_bug.cgi?id="); + + g_test_add ("/echo/session", Fixture, NULL, setup, test_echo, teardown); + + return g_test_run (); +} |