diff --git a/dbus/dbus-sysdeps-win.c b/dbus/dbus-sysdeps-win.c index 5b1feb90..508057e2 100644 --- a/dbus/dbus-sysdeps-win.c +++ b/dbus/dbus-sysdeps-win.c @@ -2895,6 +2895,44 @@ static const char *cDBusDaemonMutex = "DBusDaemonMutex"; // named shm for dbus adress info (per user) static const char *cDBusDaemonAddressInfo = "DBusDaemonAddressInfo"; +/* custom command line parameter for autolaunching daemon */ +static const char *autolaunch_custom_command_line_parameter = ""; + +/** + * Set command line parameters for the dbus daemon to start + * for an autolaunch session. + * + * The specified instance must be valid until the dbus-daemon + * is started. + * + * This function is not thread-safe, and can only be called from a + * single-threaded unit test. + * + * @param path string to use as command line parameter + */ +void _dbus_test_win_autolaunch_set_command_line_parameter (const char *path) +{ + autolaunch_custom_command_line_parameter = path; +} + +static HANDLE *autolaunch_handle_location; + +/** + * Set location where to store process handle of an autostarted server + * + * This function is not thread-safe, and can only be called from a + * single-threaded unit test. + * + * After using the handle it must be closed with @ref CloseHandle(). + * + * @param location Pointer where to store the handle + */ +void +_dbus_test_win_set_autolaunch_handle_location (HANDLE *location) +{ + autolaunch_handle_location = location; +} + /** * Return the hash of the installation root directory, which can be * used to construct a per-installation-root scope for autolaunching @@ -3235,41 +3273,53 @@ _dbus_daemon_unpublish_session_bus_address (void) return TRUE; } +/** + * Get server bus address from shared memory segment provided by running dbus-daemon + * + * @param address initialized DBusString instance to store the retrieved address + * @param shm_name the name of the shared memory segment + * @param wait if TRUE wait maximum 2 seconds for the presence of the shared memory segment + * @return #TRUE the bus address was fetched from the shared memory segment + * @return #FALSE error during execution + */ static dbus_bool_t -_dbus_get_autolaunch_shm (DBusString *address, DBusString *shm_name) +_dbus_get_autolaunch_shm (DBusString *address, DBusString *shm_name, dbus_bool_t wait) { - HANDLE sharedMem; + HANDLE sharedMem = NULL; char *shared_addr; int i; + int max = 20; /* max 2 seconds */ + dbus_bool_t retval = FALSE; + + if (!wait) + max = 1; // read shm - for(i=0;i<20;++i) { + for (i = 0; i < max; ++i) + { // we know that dbus-daemon is available, so we wait until shm is available sharedMem = OpenFileMappingA (FILE_MAP_READ, FALSE, _dbus_string_get_const_data (shm_name)); if (sharedMem == 0) - Sleep (100); - if ( sharedMem != 0) - break; - } + Sleep (100); + if (sharedMem != 0) + break; + } if (sharedMem == 0) - return FALSE; + return FALSE; shared_addr = MapViewOfFile (sharedMem, FILE_MAP_READ, 0, 0, 0); if (!shared_addr) - return FALSE; + goto out; - _dbus_string_init (address); + retval = _dbus_string_append (address, shared_addr); - _dbus_string_append (address, shared_addr); - - // cleanup UnmapViewOfFile (shared_addr); +out: CloseHandle (sharedMem); - - return TRUE; + return retval; } static dbus_bool_t @@ -3283,7 +3333,7 @@ _dbus_daemon_already_runs (DBusString *address, DBusString *shm_name, const char if (!_dbus_string_init (&mutex_name)) return FALSE; - if (!_dbus_get_mutex_name (&mutex_name,scope) || + if (!_dbus_get_mutex_name (&mutex_name, scope) || /* not determinable */ _dbus_string_get_length (&mutex_name) == 0) { @@ -3300,15 +3350,15 @@ _dbus_daemon_already_runs (DBusString *address, DBusString *shm_name, const char // do checks daemon = CreateMutexA (NULL, FALSE, _dbus_string_get_const_data (&mutex_name)); - if(WaitForSingleObject (daemon, 10) != WAIT_TIMEOUT) + if (WaitForSingleObject (daemon, 10) != WAIT_TIMEOUT) { ReleaseMutex (daemon); CloseHandle (daemon); goto out; } - // read shm - retval = _dbus_get_autolaunch_shm (address, shm_name); + // read shm, wait max 2 seconds + retval = _dbus_get_autolaunch_shm (address, shm_name, TRUE); // cleanup CloseHandle (daemon); @@ -3333,14 +3383,15 @@ _dbus_get_autolaunch_address (const char *scope, LPSTR lpFile; char dbus_exe_path[MAX_PATH]; DBusString dbus_args = _DBUS_STRING_INIT_INVALID; - const char * daemon_name = DBUS_DAEMON_NAME ".exe"; + const char *daemon_name = DBUS_DAEMON_NAME ".exe"; DBusString shm_name; + HANDLE ready_event_handle = NULL; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_string_init (&shm_name)) { - _DBUS_SET_OOM(error); + _DBUS_SET_OOM (error); return FALSE; } @@ -3365,12 +3416,12 @@ _dbus_get_autolaunch_address (const char *scope, if (_dbus_daemon_already_runs (address, &shm_name, scope)) { _dbus_verbose ("found running dbus daemon for scope '%s' at %s\n", - scope ? scope : "", _dbus_string_get_const_data (&shm_name) ); + scope ? scope : "", _dbus_string_get_const_data (&shm_name)); retval = TRUE; goto out; } - if (!SearchPathA (NULL, daemon_name, NULL, sizeof(dbus_exe_path), dbus_exe_path, &lpFile)) + if (!SearchPathA (NULL, daemon_name, NULL, sizeof (dbus_exe_path), dbus_exe_path, &lpFile)) { // Look in directory containing dbus shared library HMODULE hmod; @@ -3381,7 +3432,7 @@ _dbus_get_autolaunch_address (const char *scope, "trying path where dbus shared library is located"); hmod = _dbus_win_get_dll_hmodule (); - rc = GetModuleFileNameA (hmod, dbus_module_path, sizeof(dbus_module_path)); + rc = GetModuleFileNameA (hmod, dbus_module_path, sizeof (dbus_module_path)); if (rc <= 0) { dbus_set_error_const (error, DBUS_ERROR_FAILED, "could not retrieve dbus shared library file name"); @@ -3393,7 +3444,7 @@ _dbus_get_autolaunch_address (const char *scope, char *ext_idx = strrchr (dbus_module_path, '\\'); if (ext_idx) *ext_idx = '\0'; - if (!SearchPathA (dbus_module_path, daemon_name, NULL, sizeof(dbus_exe_path), dbus_exe_path, &lpFile)) + if (!SearchPathA (dbus_module_path, daemon_name, NULL, sizeof (dbus_exe_path), dbus_exe_path, &lpFile)) { dbus_set_error (error, DBUS_ERROR_FAILED, "Could not find dbus-daemon executable. " @@ -3407,11 +3458,10 @@ _dbus_get_autolaunch_address (const char *scope, } } - // Create process - ZeroMemory (&si, sizeof(si)); + ZeroMemory (&si, sizeof (si)); si.cb = sizeof (si); - ZeroMemory (&pi, sizeof(pi)); + ZeroMemory (&pi, sizeof (pi)); if (!_dbus_string_init (&dbus_args)) { @@ -3420,19 +3470,79 @@ _dbus_get_autolaunch_address (const char *scope, goto out; } - if (!_dbus_string_append_printf (&dbus_args, "\"%s\" --session", dbus_exe_path)) + if (!_dbus_string_append_printf (&dbus_args, "\"%s\" %s", dbus_exe_path, + autolaunch_custom_command_line_parameter ? autolaunch_custom_command_line_parameter : "--session")) { - dbus_set_error_const (error, DBUS_ERROR_NO_MEMORY, "Failed to append string to argument buffer"); + _DBUS_SET_OOM (error); retval = FALSE; goto out; } -// argv[i] = "--config-file=bus\\session.conf"; - if(CreateProcessA (dbus_exe_path, _dbus_string_get_data (&dbus_args), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) + ready_event_handle = _dbus_win_event_create_inheritable (error); + if (ready_event_handle == NULL) + goto out; + + _dbus_verbose ("Creating connection readiness event: handle=%p\n", ready_event_handle); + if (!_dbus_string_append_printf (&dbus_args, " \"--ready-event-handle=%p\"", ready_event_handle)) { + _DBUS_SET_OOM (error); + goto out; + } + + _dbus_verbose ("Starting dbus daemon with args: '%s'\n", _dbus_string_get_const_data (&dbus_args)); + if (CreateProcessA (dbus_exe_path, _dbus_string_get_data (&dbus_args), NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) + { + DWORD status; + HANDLE events[2]; + CloseHandle (pi.hThread); - CloseHandle (pi.hProcess); - retval = _dbus_get_autolaunch_shm (address, &shm_name); + + _dbus_verbose ("Wait until dbus-daemon is ready for connections (event handle %p)\n", ready_event_handle); + + events[0] = ready_event_handle; + events[1] = pi.hProcess; + status = WaitForMultipleObjects (2, events, FALSE, 30000); + + switch (status) + { + case WAIT_OBJECT_0: + /* ready event signalled, everything is okay */ + retval = TRUE; + break; + + case WAIT_OBJECT_0 + 1: + /* dbus-daemon process has exited */ + dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED, "dbus-daemon exited before signalling ready"); + goto out; + + case WAIT_FAILED: + _dbus_win_set_error_from_last_error (error, "Unable to wait for server readiness (handle %p)", ready_event_handle); + goto out; + + case WAIT_TIMEOUT: + /* GetLastError() is not set */ + dbus_set_error (error, DBUS_ERROR_TIMEOUT, "Timed out waiting for server readiness or exit (handle %p)", ready_event_handle); + goto out; + + default: + /* GetLastError() is probably not set? */ + dbus_set_error (error, DBUS_ERROR_FAILED, "Unknown result '%lu' while waiting for server readiness (handle %p)", status, ready_event_handle); + goto out; + } + _dbus_verbose ("Got signal that dbus-daemon with process id '%ld' is ready for connections\n", GetProcessId (pi.hProcess)); + + if (autolaunch_handle_location != NULL) + { + *autolaunch_handle_location = pi.hProcess; + _dbus_verbose ("Returning process handle of started server (handle=%p)\n", pi.hProcess); + } + else + { + CloseHandle (pi.hProcess); + } + + /* do not wait for the appearance of shm, we can assume that it is present */ + retval = _dbus_get_autolaunch_shm (address, &shm_name, FALSE); if (retval == FALSE) dbus_set_error_const (error, DBUS_ERROR_FAILED, "Failed to get autolaunch address from launched dbus-daemon"); } @@ -3448,10 +3558,12 @@ out: _dbus_platform_rmutex_free (lock); _dbus_string_free (&shm_name); _dbus_string_free (&dbus_args); + if (ready_event_handle) + _dbus_win_event_free (ready_event_handle, NULL); + _DBUS_ASSERT_ERROR_XOR_BOOL (error, retval); return retval; - } - +} /** Makes the file readable by every user in the system. * diff --git a/dbus/dbus-sysdeps-win.h b/dbus/dbus-sysdeps-win.h index 284bc796..5027f180 100644 --- a/dbus/dbus-sysdeps-win.h +++ b/dbus/dbus-sysdeps-win.h @@ -117,6 +117,10 @@ dbus_bool_t _dbus_daemon_publish_session_bus_address (const char *address, DBUS_PRIVATE_EXPORT DBusRMutex *_dbus_win_rmutex_named_new (const char* name); +DBUS_PRIVATE_EXPORT +void _dbus_test_win_autolaunch_set_command_line_parameter (const char *path); +DBUS_PRIVATE_EXPORT +void _dbus_test_win_set_autolaunch_handle_location (HANDLE *location); #endif /** @} end of sysdeps-win.h */ diff --git a/test/data/valid-config-files/listen-autolaunch-win.conf.in b/test/data/valid-config-files/listen-autolaunch-win.conf.in new file mode 100644 index 00000000..7557e526 --- /dev/null +++ b/test/data/valid-config-files/listen-autolaunch-win.conf.in @@ -0,0 +1,11 @@ + + + session + @TEST_LISTEN@ + + + + + + diff --git a/test/name-test/CMakeLists.txt b/test/name-test/CMakeLists.txt index 1b3c0e5c..098993ae 100644 --- a/test/name-test/CMakeLists.txt +++ b/test/name-test/CMakeLists.txt @@ -1,6 +1,10 @@ add_definitions(${DBUS_INTERNAL_CLIENT_DEFINITIONS}) -add_helper_executable(test-autolaunch test-autolaunch.c dbus-testutils) +if(WIN32) + add_test_executable(test-autolaunch-win test-autolaunch-win.c ${DBUS_INTERNAL_LIBRARIES} dbus-testutils) +else() + add_helper_executable(test-autolaunch test-autolaunch.c dbus-testutils) +endif() add_session_test_executable(test-ids test-ids.c ${DBUS_INTERNAL_LIBRARIES}) add_session_test_executable(test-pending-call-disconnected test-pending-call-disconnected.c ${DBUS_INTERNAL_LIBRARIES}) diff --git a/test/name-test/Makefile.am b/test/name-test/Makefile.am index 81938778..527dbbff 100644 --- a/test/name-test/Makefile.am +++ b/test/name-test/Makefile.am @@ -72,7 +72,7 @@ if DBUS_ENABLE_EMBEDDED_TESTS ## we use noinst_PROGRAMS not check_PROGRAMS for TESTS so that we ## build even when not doing "make check" -noinst_PROGRAMS=test-pending-call-dispatch test-pending-call-timeout test-pending-call-disconnected test-threads-init test-ids test-shutdown test-privserver-client test-autolaunch +noinst_PROGRAMS=test-pending-call-dispatch test-pending-call-timeout test-pending-call-disconnected test-threads-init test-ids test-shutdown test-privserver-client test_pending_call_dispatch_LDADD = \ $(CODE_COVERAGE_LIBS) \ @@ -103,9 +103,21 @@ test_privserver_client_LDADD = \ $(CODE_COVERAGE_LIBS) \ ../libdbus-testutils.la \ $(NULL) + +if DBUS_WIN +noinst_PROGRAMS += test-autolaunch-win +test_autolaunch_win_SOURCES = test-autolaunch-win.c +test_autolaunch_win_LDADD = \ + $(CODE_COVERAGE_LIBS) \ + ../libdbus-testutils.la \ + $(NULL) +TESTS += test-autolaunch-win +else +noinst_PROGRAMS += test-autolaunch +test_autolaunch_SOURCES = test-autolaunch.c test_autolaunch_LDADD = \ $(CODE_COVERAGE_LIBS) \ ../libdbus-testutils.la \ $(NULL) - +endif endif diff --git a/test/name-test/test-autolaunch-win.c b/test/name-test/test-autolaunch-win.c new file mode 100644 index 00000000..8a434e2c --- /dev/null +++ b/test/name-test/test-autolaunch-win.c @@ -0,0 +1,363 @@ +/* + * Copyright © 2018-2022 Ralf Habacker + * SPDX-License-Identifier: MIT + */ + +/** + * This test checks whether a client can connect to a dbus daemon configured + * for a default, user-defined and installation path related autostart and + * whether it can connect to a server having a different autolaunch + * configuration. + */ + +#include "config.h" + +#include "dbus/dbus-file.h" +#include "dbus/dbus-internals.h" +#include "dbus/dbus-sysdeps.h" +#include "dbus/dbus-test-tap.h" +#include "dbus/dbus-test.h" +#include "dbus/dbus.h" +#include "test/test-utils.h" + +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +/* dbus_bus_get does not work yet */ +static dbus_bool_t use_bus_get = FALSE; + +static int add_wait_time = 0; + +#define oom() _dbus_test_fatal ("Out of memory") + +/** + * helper function + */ +#define _dbus_error_set_from_message_with_location(a, b) __dbus_error_set_from_message_with_location (__FILE__, __LINE__, __FUNCTION__, a, b) + +static void +__dbus_error_set_from_message_with_location (const char *file, int line, const char *function, DBusError *error, DBusMessage *message) +{ + char *str = NULL; + dbus_message_get_args (message, NULL, + DBUS_TYPE_STRING, &str, + DBUS_TYPE_INVALID); + dbus_set_error (error, dbus_message_get_error_name (message), "[%s(%d):%s] %s", file, line, function, str ? str : ""); +} + +static dbus_bool_t +call_method (DBusConnection *conn, + DBusError *error, + int timeout, + const char *interface, + const char *method_str) +{ + DBusMessage *method; + DBusMessage *reply; + dbus_bool_t result = TRUE; + + dbus_error_init (error); + + method = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + interface, + method_str); + + reply = dbus_connection_send_with_reply_and_block (conn, method, timeout, error); + dbus_message_unref (method); + if (reply == NULL) + { + dbus_set_error (error, DBUS_ERROR_FAILED, "Got no reply"); + result = FALSE; + goto out; + } + + if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR) + { + _dbus_error_set_from_message_with_location (error, reply); + result = FALSE; + goto out; + } + result = TRUE; + +out: + _DBUS_ASSERT_ERROR_XOR_BOOL (error, result); + dbus_message_unref (reply); + return result; +} + +static dbus_bool_t +_server_check_connection (DBusConnection *conn, + DBusError *error) +{ + if (use_bus_get) + return call_method (conn, error, -1, DBUS_INTERFACE_PEER, "GetMachineId"); + else + return call_method (conn, error, -1, DBUS_INTERFACE_DBUS, "Hello"); +} + +static HANDLE autolaunch_handle = NULL; + +static dbus_bool_t +_server_shutdown (DBusConnection *conn, + const char *scope, + int timeout, + DBusError *error) +{ + _dbus_assert (autolaunch_handle != NULL); + + _dbus_test_diag ("Shutting down dbus-daemon (handle=%p)", autolaunch_handle); + if (!TerminateProcess (autolaunch_handle, 1)) + _dbus_test_fatal ("Unable to terminate dbus-daemon (handle=%p) : %s", + /* this string is leaked, but we're crashing anyway */ + autolaunch_handle, _dbus_win_error_string (GetLastError ())); + + _dbus_test_diag ("Return value from closing autolaunch_handle is %d", CloseHandle (autolaunch_handle)); + autolaunch_handle = NULL; + _dbus_test_win_set_autolaunch_handle_location (NULL); + return TRUE; +} + +typedef enum +{ + RUN_TEST_DEFAULT = 0, + RUN_TEST_EXPECT_CONNECTION_TO_FAIL = (1 << 0), +} RunTestFlags; + +static dbus_bool_t +check_results (DBusConnection *conn, + DBusString *server_address, + DBusString *address, + const char *scope, + RunTestFlags flags, + DBusError *error) +{ + if (add_wait_time) + _dbus_sleep_milliseconds (add_wait_time); + + if (dbus_error_is_set (error)) + _dbus_test_diag ("Error is set: %s %s", error->name, error->message); + + if (conn == NULL) + { + if (!dbus_error_is_set (error)) + _dbus_test_fatal ("Failed to autolaunch session bus and no error was set"); + + if (flags & RUN_TEST_EXPECT_CONNECTION_TO_FAIL) + return TRUE; + + _dbus_test_diag ("autolaunch unexpectedly failed: %s: %s", error->name, error->message); + return FALSE; + } + else + { + if (dbus_error_is_set (error)) + _dbus_test_fatal ("Successfully autolaunched session bus but error was set: %s: %s", error->name, error->message); + + if (flags & RUN_TEST_EXPECT_CONNECTION_TO_FAIL) + { + _dbus_test_diag ("autolaunch unexpectedly succeeded"); + return FALSE; + } + _dbus_test_diag ("Client connection succeeded - uses '%s'", _dbus_string_get_const_data (address)); + } + + if (add_wait_time) + _dbus_sleep_milliseconds (add_wait_time); + + _dbus_test_diag ("Server returned bus address '%s'", _dbus_string_get_const_data (server_address)); + if (!_server_check_connection (conn, error)) + { + _dbus_test_diag ("Could not execute server function"); + return FALSE; + } + else + _dbus_test_diag ("Calling server function succeeded"); + + return TRUE; +} + +static dbus_bool_t +run_test (const char *server_scope, const char *scope, const char *test_data_dir, RunTestFlags flags) +{ + DBusConnection *conn = NULL; + DBusError error; + DBusString server_address = _DBUS_STRING_INIT_INVALID; + DBusString address = _DBUS_STRING_INIT_INVALID; + DBusString session_parameter = _DBUS_STRING_INIT_INVALID; + dbus_bool_t result = FALSE; + TestMainContext *ctx; + _dbus_assert (test_data_dir); + + ctx = test_main_context_get (); + + dbus_error_init (&error); + + if (!_dbus_string_init (&server_address)) + oom (); + + if (!_dbus_string_init (&address)) + oom (); + + _dbus_test_diag ("run test"); + + if (*server_scope != '\0') + { + if (!_dbus_string_append_printf (&server_address, "autolaunch:scope=%s", server_scope)) + oom (); + } + else if (!_dbus_string_append_printf (&server_address, "autolaunch:")) + { + oom (); + } + + if (*scope != '\0') + { + if (!_dbus_string_append_printf (&address, "autolaunch:scope=%s", scope)) + oom (); + } + else if (!_dbus_string_append_printf (&address, "autolaunch:")) + { + oom (); + } + + if (!_dbus_string_init (&session_parameter)) + oom (); + + /* We haven't implemented any form of escaping quotes, + * but Windows doesn't allow filenames to contain quotes + * so it shouldn't matter. */ + _dbus_test_check (strchr (test_data_dir, '"') == NULL); + + _dbus_test_check (strchr (_dbus_string_get_const_data (&server_address), '"') == NULL); + + if (!_dbus_string_append_printf (&session_parameter, "\"--config-file=%s/%s\" \"--address=%s\"", test_data_dir, "valid-config-files/listen-autolaunch-win.conf", _dbus_string_get_const_data (&server_address))) + { + oom (); + } + + _dbus_test_win_autolaunch_set_command_line_parameter (_dbus_string_get_const_data (&session_parameter)); + + _dbus_test_diag ("Autolaunch handle initially %p", autolaunch_handle); + _dbus_test_win_set_autolaunch_handle_location (&autolaunch_handle); + + if (use_bus_get) + { + dbus_setenv ("DBUS_SESSION_BUS_ADDRESS", _dbus_string_get_const_data (&address)); + _dbus_test_diag ("got env %s", getenv ("DBUS_SESSION_BUS_ADDRESS")); + conn = dbus_bus_get_private (DBUS_BUS_SESSION, &error); + dbus_connection_set_exit_on_disconnect (conn, FALSE); + } + else + { + conn = dbus_connection_open_private (_dbus_string_get_const_data (&address), &error); + } + + _dbus_test_diag ("After attempting to connect: autolaunch handle is %p", autolaunch_handle); + if (conn) + test_connection_setup (ctx, conn); + + result = check_results (conn, &server_address, &address, scope, flags, &error); + + if (conn) + { + _dbus_test_diag("Shutdown connection '%p'", conn); + test_connection_shutdown (ctx, conn); + dbus_connection_close (conn); + dbus_connection_unref (conn); + } + + _server_shutdown (conn, scope, -1, &error); + _dbus_test_diag ("server has been shut down"); + + _dbus_string_free (&address); + _dbus_string_free (&server_address); + _dbus_string_free (&session_parameter); + + test_main_context_unref (ctx); + + return result; +} + +static dbus_bool_t +run_test_okay (const char *scope, const char *test_data_dir) +{ + return run_test (scope, scope, test_data_dir, RUN_TEST_DEFAULT); +} + +static dbus_bool_t +_dbus_autolaunch_default_test (const char *test_data_dir) +{ + return run_test_okay ("", test_data_dir); +} + +static dbus_bool_t +_dbus_autolaunch_custom_scope_test (const char *test_data_dir) +{ + return run_test_okay ("123", test_data_dir); +} + +static dbus_bool_t +_dbus_autolaunch_install_path_scope_test (const char *test_data_dir) +{ + return run_test_okay ("*install-path", test_data_dir); +} + +static dbus_bool_t +_dbus_autolaunch_user_scope_test (const char *test_data_dir) +{ + return run_test_okay ("*user", test_data_dir); +} + +static dbus_bool_t +_dbus_autolaunch_loop_test (const char *test_data_dir, dbus_bool_t same_scope) +{ + int i; + int max = 10; + + for (i = 0; i < max; i++) + { + char s[2] = { i+'A', 0 }; + if (!run_test_okay (same_scope ? "A" : s, test_data_dir)) + _dbus_test_not_ok ("%d", max); + else + _dbus_test_ok ("%d", max); + if (add_wait_time) + _dbus_sleep_milliseconds (add_wait_time); + } + return TRUE; +} + +static dbus_bool_t +_dbus_autolaunch_same_scope_loop_test (const char *test_data_dir) +{ + return _dbus_autolaunch_loop_test (test_data_dir, TRUE); +} + +static dbus_bool_t +_dbus_autolaunch_different_scope_loop_test (const char *test_data_dir) +{ + return _dbus_autolaunch_loop_test (test_data_dir, FALSE); +} + +static DBusTestCase tests[] = { + { "default", _dbus_autolaunch_default_test }, + { "custom", _dbus_autolaunch_custom_scope_test }, + { "install-path", _dbus_autolaunch_install_path_scope_test }, + { "user", _dbus_autolaunch_user_scope_test }, + { "loop", _dbus_autolaunch_same_scope_loop_test }, + { "different-scope-loop", _dbus_autolaunch_different_scope_loop_test }, +}; + +int +main (int argc, + char **argv) +{ + return _dbus_test_main (argc, argv, _DBUS_N_ELEMENTS (tests), tests, + DBUS_TEST_FLAGS_CHECK_MEMORY_LEAKS, + NULL, NULL); +}