/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* e-test-server-utils.c - Test scaffolding to run tests with in-tree data server.
*
* Copyright (C) 2012 Intel Corporation
*
* This library is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see .
*
* Authors: Tristan Van Berkom
*/
/**
* SECTION: e-test-server-utils
* @short_description: A utility for unit testing EDS
*
* This test fixture provides an encapsulated testing environment for test
* cases to test #EBookClient and #ECalClient.
*
* The #ETestServerFixture should be used as a fixture and must be coupled
* with the #ETestServerClosure to configure how the test fixture will operate.
*
* Both the #ETestServerFixture and #ETestServerClosure can be extended with
* more complex test fixtures, which must remember to call e_test_server_utils_setup()
* and e_test_server_utils_teardown() in thier fixture's setup and teardown routines.
**/
#include "evolution-data-server-config.h"
#include "e-test-server-utils.h"
#ifdef HAVE_SYS_WAIT_H
#include
#endif
#define ADDRESS_BOOK_SOURCE_UID "test-address-book"
#define CALENDAR_SOURCE_UID "test-calendar"
#define FINALIZE_SECONDS 30
/* FIXME, currently we are unable to achieve server activation
* twice in a single test case, so we're using one D-Bus server
* throughout an entire test suite.
*
* When this is fixed we can migrate the D-Bus initialization
* and teardown from e_test_server_utils_run() to
* e_test_server_utils_setup() and e_test_server_utils_teardown()
* and this will transparantly change the way tests run using
* this test framework.
*/
#define GLOBAL_DBUS_DAEMON 1
#if GLOBAL_DBUS_DAEMON
static GTestDBus *global_test_dbus = NULL;
#endif
/* The ESource identifier numerical component, this should
* not be needed (and should probably be removed) once we
* can get rid of the GLOBAL_DBUS_DAEMON hack.
*/
static gint global_test_source_id = 0;
/*****************************************************************
* Reference management *
*****************************************************************
*
* We need to test that an EClient actually finalizes properly
* at the end of every test, however these EClient's have a
* habit of finalizing asynchronously, not even in the same thread
* in which they were created.
*
* This is why we do this crazy stuff below to ensure asyncrhonous
* finalization of the client actually happens.
*/
static void
add_weak_ref (ETestServerFixture *fixture,
ETestServiceType service_type)
{
GObject *object;
switch (service_type) {
case E_TEST_SERVER_NONE:
g_weak_ref_set (&fixture->registry_ref, fixture->registry);
break;
case E_TEST_SERVER_ADDRESS_BOOK:
case E_TEST_SERVER_DIRECT_ADDRESS_BOOK:
case E_TEST_SERVER_CALENDAR:
case E_TEST_SERVER_DEPRECATED_ADDRESS_BOOK:
/* They're all the same object pointer */
object = E_TEST_SERVER_UTILS_SERVICE (fixture, GObject);
g_weak_ref_set (&fixture->client_ref, object);
break;
}
}
static gboolean
object_finalize_timeout (gpointer user_data)
{
const gchar *message = (const gchar *) user_data;
g_error ("%s", message);
return FALSE;
}
static gboolean
object_unref_idle (gpointer user_data)
{
g_object_unref (user_data);
return FALSE;
}
static void
weak_notify_loop_quit (gpointer data,
GObject *where_the_object_was)
{
ETestServerFixture *fixture = (ETestServerFixture *) data;
g_main_loop_quit (fixture->loop);
}
static void
assert_object_finalized (ETestServerFixture *fixture,
ETestServiceType service_type)
{
const gchar *message = NULL;
GObject *object = NULL;
GWeakRef *ref = NULL;
switch (service_type) {
case E_TEST_SERVER_NONE:
message = "Timed out waiting for source registery to finalize";
ref = &fixture->registry_ref;
break;
case E_TEST_SERVER_ADDRESS_BOOK:
case E_TEST_SERVER_DIRECT_ADDRESS_BOOK:
case E_TEST_SERVER_DEPRECATED_ADDRESS_BOOK:
message = "Timed out waiting for addressbook client to finalize";
ref = &fixture->client_ref;
break;
case E_TEST_SERVER_CALENDAR:
message = "Timed out waiting for calendar client to finalize";
ref = &fixture->client_ref;
break;
}
/* Give her a second chance */
object = g_weak_ref_get (ref);
if (object) {
guint timeout_id;
/* Add a finalize callback while we have a strong reference */
g_object_weak_ref (object, weak_notify_loop_quit, fixture);
/* Fail the test if we reach the timeout */
timeout_id = g_timeout_add_seconds (
FINALIZE_SECONDS,
object_finalize_timeout,
(gpointer) message);
/* We can't release the strong reference yet, it might try
* to quit the main loop before we've started it.
*
* Instead release it in the loop (no need to track the source id,
* it's guaranteed to be removed in the scope of this test).
*/
g_idle_add (object_unref_idle, object);
/* Wait for asynchronous finalization, if this loop
* returns then we finalized properly, if the timeout
* is reached then we've aborted with an error message
*/
g_main_loop_run (fixture->loop);
/* If we reached here, better remove the timeout source to
* avoid it timing out in following tests
*/
g_source_remove (timeout_id);
}
}
/*****************************************************************
* Bootstrapping, manage work directory and create test ESource *
*****************************************************************/
typedef struct {
ETestServerFixture *fixture;
ETestServerClosure *closure;
guint retries;
} FixturePair;
static gboolean
test_installed_services (void)
{
static gint use_installed_services = -1;
if (use_installed_services < 0) {
if (g_getenv ("TEST_INSTALLED_SERVICES") != NULL)
use_installed_services = 1;
else
use_installed_services = 0;
}
return use_installed_services;
}
static gchar *
generate_source_name (void)
{
gchar *source_name = NULL;
if (test_installed_services ()) {
gchar buffer[128] = "eds-source-XXXXXX";
gint fd;
fd = g_mkstemp (buffer);
if (fd < 0)
g_error ("Failed to generate source ID with temporary file");
close (fd);
source_name = g_strdup (buffer);
} else {
source_name = g_strdup_printf (
"%s-%d",
ADDRESS_BOOK_SOURCE_UID,
global_test_source_id++);
}
return source_name;
}
static const gchar *args_build_dir = NULL;
static void
eds_test_utils_read_args (gint argc,
gchar *argv[])
{
gint ii;
for (ii = 0; ii < argc; ii++) {
if (g_strcmp0 (argv[ii], "--build-dir") == 0) {
if (ii + 1 < argc)
args_build_dir = argv[ii + 1];
break;
}
}
g_assert_nonnull (args_build_dir);
g_assert_true (g_file_test (args_build_dir, G_FILE_TEST_IS_DIR));
}
#define EDS_TEST_WORK_DIR_SUFFIX "tests/test-server-utils/cache"
#define EDS_TEST_DBUS_SERVICE_DIR_SUFFIX "tests/test-server-utils/services"
static gchar *
eds_test_utils_create_build_path (const gchar *suffix)
{
g_assert_nonnull (args_build_dir);
g_assert_nonnull (suffix);
return g_strconcat (args_build_dir, G_DIR_SEPARATOR_S, suffix, NULL);
}
static void
eds_test_utils_setenv (const gchar *envvar,
const gchar *suffix)
{
gchar *path;
path = eds_test_utils_create_build_path (suffix);
g_assert_true (g_setenv (envvar, path, TRUE));
g_free (path);
}
static void
setup_environment (gint argc,
gchar *argv[])
{
GString *libs_dir;
const gchar *libs_dir_env;
eds_test_utils_read_args (argc, argv);
libs_dir_env = g_getenv ("LD_LIBRARY_PATH");
libs_dir = g_string_new ("");
#define add_lib_path(x) G_STMT_START { \
if (libs_dir->len) \
g_string_append_c (libs_dir, ':'); \
g_string_append_printf (libs_dir, "%s" G_DIR_SEPARATOR_S "%s", args_build_dir, x); \
} G_STMT_END
add_lib_path ("/addressbook/libebook");
add_lib_path ("/addressbook/libebook-contacts");
add_lib_path ("/addressbook/libedata-book");
add_lib_path ("/calendar/libecal");
add_lib_path ("/calendar/libedata-cal");
add_lib_path ("/camel");
add_lib_path ("/libebackend");
add_lib_path ("/libedataserver");
add_lib_path ("/libedataserverui");
add_lib_path ("/private");
add_lib_path ("/../tests/test-server-utils");
#undef add_lib_path
if (libs_dir_env && *libs_dir_env) {
if (libs_dir->len)
g_string_append_c (libs_dir, ':');
g_string_append (libs_dir, libs_dir_env);
}
g_assert_true (g_setenv ("LD_LIBRARY_PATH", libs_dir->str, TRUE));
eds_test_utils_setenv ("XDG_DATA_HOME", EDS_TEST_WORK_DIR_SUFFIX);
eds_test_utils_setenv ("XDG_CACHE_HOME", EDS_TEST_WORK_DIR_SUFFIX);
eds_test_utils_setenv ("XDG_CONFIG_HOME", EDS_TEST_WORK_DIR_SUFFIX);
eds_test_utils_setenv ("GSETTINGS_SCHEMA_DIR", "data");
eds_test_utils_setenv ("EDS_CALENDAR_MODULES", "src/calendar/backends/file");
eds_test_utils_setenv ("EDS_ADDRESS_BOOK_MODULES", "src/addressbook/backends/file");
eds_test_utils_setenv ("EDS_REGISTRY_MODULES", "src/modules/cache-reaper");
eds_test_utils_setenv ("EDS_CAMEL_PROVIDER_DIR", "src/camel/providers/local");
eds_test_utils_setenv ("EDS_SUBPROCESS_CAL_PATH", "src/calendar/libedata-cal/evolution-calendar-factory-subprocess");
eds_test_utils_setenv ("EDS_SUBPROCESS_BOOK_PATH", "src/addressbook/libedata-book/evolution-addressbook-factory-subprocess");
g_assert_true (g_setenv ("GIO_USE_VFS", "local", TRUE));
g_assert_true (g_setenv ("EDS_TESTING", "1", TRUE));
g_assert_true (g_setenv ("GSETTINGS_BACKEND", "memory", TRUE));
g_unsetenv ("DISPLAY");
g_string_free (libs_dir, TRUE);
}
static void
delete_work_directory (void)
{
/* XXX Instead of complex error checking here, we should ideally use
* a recursive GDir / g_unlink() function.
*
* We cannot use GFile and the recursive delete function without
* corrupting our contained D-Bus environment with service files
* from the OS.
*/
gchar *workdir = eds_test_utils_create_build_path (EDS_TEST_WORK_DIR_SUFFIX);
const gchar *argv[] = { "/bin/rm", "-rf", workdir, NULL };
gboolean spawn_succeeded;
gint exit_status;
spawn_succeeded = g_spawn_sync (
NULL, (gchar **) argv, NULL, 0, NULL, NULL,
NULL, NULL, &exit_status, NULL);
g_assert_true (spawn_succeeded);
#ifndef G_OS_WIN32
g_assert_true (WIFEXITED (exit_status));
g_assert_cmpint (WEXITSTATUS (exit_status), ==, 0);
#else
g_assert_cmpint (exit_status, ==, 0);
#endif
g_free (workdir);
}
static gboolean
e_test_server_utils_bootstrap_timeout (FixturePair *pair)
{
g_error ("Timed out while waiting for ESource creation from the registry");
pair->fixture->timeout_source_id = 0;
return FALSE;
}
static gboolean e_test_server_utils_retry_open_client_cb (gpointer user_data);
static void
e_test_server_utils_client_ready (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
FixturePair *pair = (FixturePair *) user_data;
gboolean need_retry = FALSE;
GError *error = NULL;
switch (pair->closure->type) {
case E_TEST_SERVER_ADDRESS_BOOK:
pair->fixture->service.book_client = (EBookClient *)
e_book_client_connect_finish (res, &error);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) &&
pair->retries < 3)
need_retry = TRUE;
else if (!pair->fixture->service.book_client)
g_error ("Unable to create the test book: %s", error->message);
break;
case E_TEST_SERVER_DIRECT_ADDRESS_BOOK:
pair->fixture->service.book_client = (EBookClient *)
e_book_client_connect_direct_finish (res, &error);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) &&
pair->retries < 3)
need_retry = TRUE;
else if (!pair->fixture->service.book_client)
g_error ("Unable to create the test book: %s", error->message);
break;
case E_TEST_SERVER_CALENDAR:
pair->fixture->service.calendar_client = (ECalClient *)
e_cal_client_connect_finish (res, &error);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) &&
pair->retries < 3)
need_retry = TRUE;
else if (!pair->fixture->service.calendar_client)
g_error ("Unable to create the test calendar: %s", error->message);
break;
case E_TEST_SERVER_DEPRECATED_ADDRESS_BOOK:
case E_TEST_SERVER_NONE:
g_assert_not_reached ();
}
g_clear_error (&error);
if (need_retry) {
pair->retries++;
g_timeout_add_seconds (1, e_test_server_utils_retry_open_client_cb, pair);
return;
}
/* Track ref counts now that we have a client */
add_weak_ref (pair->fixture, pair->closure->type);
g_main_loop_quit (pair->fixture->loop);
}
static void
e_test_server_utils_source_added (ESourceRegistry *registry,
ESource *source,
FixturePair *pair)
{
gboolean need_retry = FALSE;
GError *error = NULL;
if (g_strcmp0 (e_source_get_uid (source), pair->fixture->source_name) != 0)
return;
switch (pair->closure->type) {
case E_TEST_SERVER_ADDRESS_BOOK:
case E_TEST_SERVER_DIRECT_ADDRESS_BOOK:
if (pair->closure->type == E_TEST_SERVER_DIRECT_ADDRESS_BOOK) {
if (pair->closure->use_async_connect)
e_book_client_connect_direct (source, (guint32) -1, NULL, e_test_server_utils_client_ready, pair);
else
pair->fixture->service.book_client = (EBookClient *)
e_book_client_connect_direct_sync (
pair->fixture->registry,
source, (guint32) -1, NULL, &error);
} else {
if (pair->closure->use_async_connect)
e_book_client_connect (source, (guint32) -1, NULL, e_test_server_utils_client_ready, pair);
else
pair->fixture->service.book_client = (EBookClient *)
e_book_client_connect_sync (source, (guint32) -1, NULL, &error);
}
if (!pair->closure->use_async_connect &&
!pair->fixture->service.book_client) {
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) &&
pair->retries < 3)
need_retry = TRUE;
else
g_error ("Unable to create the test book: %s", error ? error->message : "Unknown error");
}
break;
case E_TEST_SERVER_DEPRECATED_ADDRESS_BOOK:
/* Dont bother testing the Async apis for deprecated APIs */
pair->fixture->service.book = e_book_new (source, &error);
if (!pair->fixture->service.book) {
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) &&
pair->retries < 3)
need_retry = TRUE;
else
g_error ("Unable to create the test book: %s", error->message);
break;
}
if (!e_book_open (pair->fixture->service.book, FALSE, &error)) {
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) &&
pair->retries < 3)
need_retry = TRUE;
else
g_error ("Unable to open book: %s", error->message);
}
break;
case E_TEST_SERVER_CALENDAR:
if (pair->closure->use_async_connect) {
e_cal_client_connect (
source, pair->closure->calendar_source_type, (guint32) -1,
NULL, e_test_server_utils_client_ready, pair);
} else {
pair->fixture->service.calendar_client = (ECalClient *)
e_cal_client_connect_sync (
source,
pair->closure->calendar_source_type, (guint32) -1, NULL, &error);
if (!pair->fixture->service.calendar_client) {
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) &&
pair->retries < 3)
need_retry = TRUE;
else
g_error ("Unable to create the test calendar: %s", error->message);
}
}
break;
case E_TEST_SERVER_NONE:
return;
}
g_clear_error (&error);
if (need_retry) {
pair->retries++;
g_timeout_add_seconds (1, e_test_server_utils_retry_open_client_cb, pair);
return;
}
/* Add the weak ref now if we just created it */
if (pair->closure->type != E_TEST_SERVER_NONE &&
pair->closure->use_async_connect == FALSE)
add_weak_ref (pair->fixture, pair->closure->type);
if (!pair->closure->use_async_connect)
g_main_loop_quit (pair->fixture->loop);
}
static gboolean
e_test_server_utils_retry_open_client_cb (gpointer user_data)
{
FixturePair *pair = user_data;
ESource *source;
source = e_source_registry_ref_source (pair->fixture->registry, pair->fixture->source_name);
g_assert_true (E_IS_SOURCE (source));
e_test_server_utils_source_added (pair->fixture->registry, source, pair);
g_object_unref (source);
return FALSE;
}
static gboolean
e_test_server_utils_bootstrap_idle (FixturePair *pair)
{
ESourceBackend *backend = NULL;
ESource *scratch = NULL;
GError *error = NULL;
pair->fixture->registry = e_source_registry_new_sync (NULL, &error);
if (!pair->fixture->registry)
g_error ("Unable to create the test registry: %s", error->message);
/* Add weak ref for the registry */
add_weak_ref (pair->fixture, E_TEST_SERVER_NONE);
g_signal_connect (
pair->fixture->registry, "source-added",
G_CALLBACK (e_test_server_utils_source_added), pair);
/* Create an address book */
switch (pair->closure->type) {
case E_TEST_SERVER_ADDRESS_BOOK:
case E_TEST_SERVER_DIRECT_ADDRESS_BOOK:
case E_TEST_SERVER_DEPRECATED_ADDRESS_BOOK:
if (!pair->fixture->source_name)
pair->fixture->source_name = generate_source_name ();
scratch = e_source_new_with_uid (pair->fixture->source_name, NULL, &error);
if (!scratch)
g_error ("Failed to create scratch source for an addressbook: %s", error->message);
/* Ensure Book type */
backend = e_source_get_extension (scratch, E_SOURCE_EXTENSION_ADDRESS_BOOK);
e_source_backend_set_backend_name (backend, "local");
break;
case E_TEST_SERVER_CALENDAR:
if (!pair->fixture->source_name)
pair->fixture->source_name = generate_source_name ();
scratch = e_source_new_with_uid (pair->fixture->source_name, NULL, &error);
if (!scratch)
g_error ("Failed to create scratch source for a calendar: %s", error->message);
/* Ensure Calendar type source (how to specify the backend here ?? */
backend = e_source_get_extension (scratch, E_SOURCE_EXTENSION_CALENDAR);
e_source_backend_set_backend_name (backend, "local");
break;
case E_TEST_SERVER_NONE:
break;
}
if (scratch) {
if (pair->closure->customize)
pair->closure->customize (scratch, pair->closure);
if (!e_source_registry_commit_source_sync (pair->fixture->registry, scratch, NULL, &error)) {
/* Allow sources to carry from one test to the next, if the keep_work_directory
* semantics are used then that's what we want (to reuse a source from the
* previous test case).
*/
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS)) {
ESource *source = e_source_registry_ref_source (
pair->fixture->registry,
pair->fixture->source_name);
g_clear_error (&error);
g_assert_true (E_IS_SOURCE (source));
e_test_server_utils_source_added (pair->fixture->registry, source, pair);
g_object_unref (source);
} else
g_error ("Unable to add new addressbook source to the registry: %s", error->message);
}
g_object_unref (scratch);
}
if (pair->closure->type != E_TEST_SERVER_NONE)
pair->fixture->timeout_source_id =
g_timeout_add_seconds (20, (GSourceFunc) e_test_server_utils_bootstrap_timeout, pair);
else
g_main_loop_quit (pair->fixture->loop);
return FALSE;
}
/*****************************************************************
* Fixture setup and teardown *
*****************************************************************/
/**
* e_test_server_utils_setup:
* @fixture: An #ETestServerFixture
* @user_data: An #ETestServerClosure or derived structure provided by the test.
*
* A setup function for the #ETestServerFixture fixture
*/
void
e_test_server_utils_setup (ETestServerFixture *fixture,
gconstpointer user_data)
{
ETestServerClosure *closure = (ETestServerClosure *) user_data;
FixturePair pair = { fixture, closure, 0 };
/* Create work directory */
if (!test_installed_services ()) {
gchar *workdir = eds_test_utils_create_build_path (EDS_TEST_WORK_DIR_SUFFIX);
g_assert_true (g_mkdir_with_parents (workdir, 0755) == 0);
g_free (workdir);
}
/* Init refs */
g_weak_ref_init (&fixture->registry_ref, NULL);
g_weak_ref_init (&fixture->client_ref, NULL);
fixture->loop = g_main_loop_new (NULL, FALSE);
if (!test_installed_services ()) {
#if !GLOBAL_DBUS_DAEMON
gchar *servicedir = eds_test_utils_create_build_path (EDS_TEST_DBUS_SERVICE_DIR_SUFFIX);
/* Create the global dbus-daemon for this test suite */
fixture->dbus = g_test_dbus_new (G_TEST_DBUS_NONE);
/* Add the private directory with our in-tree service files */
g_test_dbus_add_service_dir (fixture->dbus, servicedir);
/* Start the private D-Bus daemon */
g_test_dbus_up (fixture->dbus);
g_free (servicedir);
#else
fixture->dbus = global_test_dbus;
#endif
}
g_idle_add ((GSourceFunc) e_test_server_utils_bootstrap_idle, &pair);
g_main_loop_run (fixture->loop);
/* This needs to be explicitly removed, otherwise the timeout source
* stays in the default GMainContext and after running tests for 20 seconds
* in the same test suite... the tests bail out.
*/
if (fixture->timeout_source_id) {
g_source_remove (fixture->timeout_source_id);
fixture->timeout_source_id = 0;
}
g_signal_handlers_disconnect_by_func (fixture->registry, e_test_server_utils_source_added, &pair);
}
/**
* e_test_server_utils_teardown:
* @fixture: An #ETestServerFixture
* @user_data: An #ETestServerClosure or derived structure provided by the test.
*
* A teardown function for the #ETestServerFixture fixture
*/
void
e_test_server_utils_teardown (ETestServerFixture *fixture,
gconstpointer user_data)
{
ETestServerClosure *closure = (ETestServerClosure *) user_data;
GError *error = NULL;
/* Try to finalize the EClient */
switch (closure->type) {
case E_TEST_SERVER_ADDRESS_BOOK:
case E_TEST_SERVER_DIRECT_ADDRESS_BOOK:
if (!closure->keep_work_directory &&
!e_client_remove_sync (E_CLIENT (fixture->service.book_client), NULL, &error)) {
g_message ("Failed to remove test book: %s (ignoring)", error->message);
g_clear_error (&error);
}
g_object_unref (fixture->service.book_client);
fixture->service.book_client = NULL;
break;
case E_TEST_SERVER_DEPRECATED_ADDRESS_BOOK:
if (!closure->keep_work_directory &&
!e_book_remove (fixture->service.book, &error)) {
g_message ("Failed to remove test book: %s (ignoring)", error->message);
g_clear_error (&error);
}
g_object_unref (fixture->service.book);
fixture->service.book = NULL;
break;
case E_TEST_SERVER_CALENDAR:
if (!closure->keep_work_directory &&
!e_client_remove_sync (E_CLIENT (fixture->service.calendar_client), NULL, &error)) {
g_message ("Failed to remove test calendar: %s (ignoring)", error->message);
g_clear_error (&error);
}
g_object_unref (fixture->service.calendar_client);
fixture->service.calendar_client = NULL;
break;
case E_TEST_SERVER_NONE:
break;
}
/* Assert that our EClient has finalized */
if (closure->type != E_TEST_SERVER_NONE)
assert_object_finalized (fixture, closure->type);
/* Try to finalize the registry now */
g_object_run_dispose (G_OBJECT (fixture->registry));
g_object_unref (fixture->registry);
/* Assert that the registry finalizes */
assert_object_finalized (fixture, E_TEST_SERVER_NONE);
g_free (fixture->source_name);
g_main_loop_unref (fixture->loop);
fixture->registry = NULL;
fixture->loop = NULL;
fixture->service.generic = NULL;
/* Clear refs */
g_weak_ref_clear (&fixture->registry_ref);
g_weak_ref_clear (&fixture->client_ref);
if (!test_installed_services ()) {
#if !GLOBAL_DBUS_DAEMON
/* Teardown the D-Bus Daemon
*
* Note that we intentionally leak the TestDBus daemon
* in this case, presumably this is due to some leaked
* GDBusConnection reference counting
*/
g_test_dbus_down (fixture->dbus);
g_object_unref (fixture->dbus);
fixture->dbus = NULL;
#else
fixture->dbus = NULL;
#endif
}
/* Cleanup work directory
*
* XXX This is avoided for now since we are currently using
* a separate ESource UID for each test, removing the work directory
* would cause the cache-reaper module to spew error messages when
* attempting to move missing removed ESources to the trash.
*
* This should probably be all completely removed once the
* GLOBAL_DBUS_DAEMON clauses can be removed.
*/
/* if (!closure->keep_work_directory && !test_installed_services ()) */
/* delete_work_directory (); */
/* Destroy dynamically allocated closure */
if (closure->destroy_closure_func)
closure->destroy_closure_func (closure);
}
gint
e_test_server_utils_run (gint argc,
gchar *argv[])
{
return e_test_server_utils_run_full (argc, argv, 0);
}
void
e_test_server_utils_prepare_run (gint argc,
gchar *argv[],
ETestServerFlags flags)
{
/* Cleanup work directory */
if (!test_installed_services ()) {
/* Do this first, to have 'args_build_dir' set */
setup_environment (argc, argv);
if ((flags & E_TEST_SERVER_KEEP_WORK_DIRECTORY) == 0)
delete_work_directory ();
}
#if GLOBAL_DBUS_DAEMON
if (!test_installed_services ()) {
gchar *servicedir = eds_test_utils_create_build_path (EDS_TEST_DBUS_SERVICE_DIR_SUFFIX);
/* Create the global dbus-daemon for this test suite */
global_test_dbus = g_test_dbus_new (G_TEST_DBUS_NONE);
/* Add the private directory with our in-tree service files */
g_test_dbus_add_service_dir (global_test_dbus, servicedir);
/* Start the private D-Bus daemon */
g_test_dbus_up (global_test_dbus);
g_free (servicedir);
}
#endif
}
void
e_test_server_utils_finish_run (void)
{
#if GLOBAL_DBUS_DAEMON
if (!test_installed_services ()) {
/* Teardown the D-Bus Daemon */
g_test_dbus_down (global_test_dbus);
g_object_unref (global_test_dbus);
global_test_dbus = NULL;
}
#endif
}
gint
e_test_server_utils_run_full (gint argc,
gchar *argv[],
ETestServerFlags flags)
{
gint tests_ret;
e_test_server_utils_prepare_run (argc, argv, flags);
/* Run the GTest suite */
tests_ret = g_test_run ();
e_test_server_utils_finish_run ();
return tests_ret;
}