1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /* e-test-server-utils.c - Test scaffolding to run tests with in-tree data server.
5 * Copyright (C) 2012 Intel Corporation
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) version 3.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with the program; if not, see <http://www.gnu.org/licenses/>
20 * Authors: Tristan Van Berkom <tristanvb@openismus.com>
23 #include "e-test-server-utils.h"
25 #define ADDRESS_BOOK_SOURCE_UID "test-address-book"
26 #define CALENDAR_SOURCE_UID "test-calendar"
28 /* FIXME, currently we are unable to achieve server activation
29 * twice in a single test case, so we're using one D-Bus server
30 * throughout an entire test suite.
32 * When this is fixed we can migrate the D-Bus initialization
33 * and teardown from e_test_server_utils_run() to
34 * e_test_server_utils_setup() and e_test_server_utils_teardown()
35 * and this will transparantly change the way tests run using
36 * this test framework.
38 #define GLOBAL_DBUS_DAEMON 1
40 #if GLOBAL_DBUS_DAEMON
41 static GTestDBus *global_test_dbus = NULL;
45 ETestServerFixture *fixture;
46 ETestServerClosure *closure;
50 test_installed_services (void)
52 static gint use_installed_services = -1;
54 if (use_installed_services < 0) {
55 if (g_getenv ("TEST_INSTALLED_SERVICES") != NULL)
56 use_installed_services = 1;
58 use_installed_services = 0;
60 return use_installed_services;
64 setup_environment (void)
66 g_assert (g_setenv ("XDG_DATA_HOME", EDS_TEST_WORK_DIR, TRUE));
67 g_assert (g_setenv ("XDG_CACHE_HOME", EDS_TEST_WORK_DIR, TRUE));
68 g_assert (g_setenv ("XDG_CONFIG_HOME", EDS_TEST_WORK_DIR, TRUE));
69 g_assert (g_setenv ("GSETTINGS_SCHEMA_DIR", EDS_TEST_SCHEMA_DIR, TRUE));
70 g_assert (g_setenv ("EDS_CALENDAR_MODULES", EDS_TEST_CALENDAR_DIR, TRUE));
71 g_assert (g_setenv ("EDS_ADDRESS_BOOK_MODULES", EDS_TEST_ADDRESS_BOOK_DIR, TRUE));
72 g_assert (g_setenv ("GIO_USE_VFS", "local", TRUE));
76 delete_work_directory (void)
78 /* XXX Instead of complex error checking here, we should ideally use
79 * a recursive GDir / g_unlink() function.
81 * We cannot use GFile and the recursive delete function without
82 * corrupting our contained D-Bus environment with service files
85 const gchar *argv[] = { "/bin/rm", "-rf", EDS_TEST_WORK_DIR, NULL };
86 gboolean spawn_succeeded;
89 spawn_succeeded = g_spawn_sync (
90 NULL, (gchar **) argv, NULL, 0, NULL, NULL,
91 NULL, NULL, &exit_status, NULL);
93 g_assert (spawn_succeeded);
94 g_assert (WIFEXITED (exit_status));
95 g_assert_cmpint (WEXITSTATUS (exit_status), ==, 0);
99 e_test_server_utils_bootstrap_timeout (FixturePair *pair)
101 g_error ("Timed out while waiting for ESource creation from the registry");
103 pair->fixture->timeout_source_id = 0;
108 e_test_server_utils_source_added (ESourceRegistry *registry,
112 GError *error = NULL;
114 switch (pair->closure->type) {
115 case E_TEST_SERVER_ADDRESS_BOOK:
116 case E_TEST_SERVER_DIRECT_ADDRESS_BOOK:
117 if (g_strcmp0 (e_source_get_uid (source), ADDRESS_BOOK_SOURCE_UID) != 0)
120 if (pair->closure->type == E_TEST_SERVER_DIRECT_ADDRESS_BOOK)
121 pair->fixture->service.book_client = (EBookClient *)
122 e_book_client_connect_direct_sync (pair->fixture->registry, source, NULL, &error);
124 pair->fixture->service.book_client = (EBookClient *)
125 e_book_client_connect_sync (source, NULL, &error);
127 if (!pair->fixture->service.book_client)
128 g_error ("Unable to create the test book: %s", error->message);
132 case E_TEST_SERVER_DEPRECATED_ADDRESS_BOOK:
133 if (g_strcmp0 (e_source_get_uid (source), ADDRESS_BOOK_SOURCE_UID) != 0)
136 pair->fixture->service.book = e_book_new (source, &error);
137 if (!pair->fixture->service.book)
138 g_error ("Unable to create the test book: %s", error->message);
140 if (!e_book_open (pair->fixture->service.book, FALSE, &error))
141 g_error ("Unable to open book: %s", error->message);
145 case E_TEST_SERVER_CALENDAR:
146 if (g_strcmp0 (e_source_get_uid (source), CALENDAR_SOURCE_UID) != 0)
149 pair->fixture->service.calendar_client = (ECalClient *)
150 e_cal_client_connect_sync (source,
151 pair->closure->calendar_source_type, NULL, &error);
152 if (!pair->fixture->service.calendar_client)
153 g_error ("Unable to create the test calendar: %s", error->message);
157 case E_TEST_SERVER_DEPRECATED_CALENDAR:
158 if (g_strcmp0 (e_source_get_uid (source), CALENDAR_SOURCE_UID) != 0)
161 pair->fixture->service.calendar = e_cal_new (source, pair->closure->calendar_source_type);
162 if (!pair->fixture->service.calendar)
163 g_error ("Unable to create the test calendar");
165 if (!e_cal_open (pair->fixture->service.calendar, FALSE, &error))
166 g_error ("Unable to open calendar: %s", error->message);
170 case E_TEST_SERVER_NONE:
174 g_main_loop_quit (pair->fixture->loop);
178 e_test_server_utils_bootstrap_idle (FixturePair *pair)
180 ESourceBackend *backend = NULL;
181 ESource *scratch = NULL;
182 GError *error = NULL;
184 pair->fixture->registry = e_source_registry_new_sync (NULL, &error);
186 if (!pair->fixture->registry)
187 g_error ("Unable to create the test registry: %s", error->message);
189 g_signal_connect (pair->fixture->registry, "source-added",
190 G_CALLBACK (e_test_server_utils_source_added), pair);
192 /* Create an address book */
193 switch (pair->closure->type) {
194 case E_TEST_SERVER_ADDRESS_BOOK:
195 case E_TEST_SERVER_DIRECT_ADDRESS_BOOK:
196 case E_TEST_SERVER_DEPRECATED_ADDRESS_BOOK:
198 scratch = e_source_new_with_uid (ADDRESS_BOOK_SOURCE_UID, NULL, &error);
200 g_error ("Failed to create scratch source for an addressbook: %s", error->message);
202 /* Ensure Book type */
203 backend = e_source_get_extension (scratch, E_SOURCE_EXTENSION_ADDRESS_BOOK);
204 e_source_backend_set_backend_name (backend, "local");
207 case E_TEST_SERVER_CALENDAR:
208 case E_TEST_SERVER_DEPRECATED_CALENDAR:
210 scratch = e_source_new_with_uid (CALENDAR_SOURCE_UID, NULL, &error);
212 g_error ("Failed to create scratch source for a calendar: %s", error->message);
214 /* Ensure Calendar type source (how to specify the backend here ?? */
215 backend = e_source_get_extension (scratch, E_SOURCE_EXTENSION_CALENDAR);
216 e_source_backend_set_backend_name (backend, "local");
220 case E_TEST_SERVER_NONE:
225 if (pair->closure->customize)
226 pair->closure->customize (scratch, pair->closure);
228 if (!e_source_registry_commit_source_sync (pair->fixture->registry, scratch, NULL, &error))
229 g_error ("Unable to add new addressbook source to the registry: %s", error->message);
231 g_object_unref (scratch);
234 if (pair->closure->type != E_TEST_SERVER_NONE)
235 pair->fixture->timeout_source_id =
236 g_timeout_add (20 * 1000, (GSourceFunc) e_test_server_utils_bootstrap_timeout, pair);
238 g_main_loop_quit (pair->fixture->loop);
244 * e_test_server_utils_setup:
245 * @fixture: A #ETestServerFixture
246 * @user_data: A #ETestServerClosure or derived structure provided by the test.
248 * A setup function for the #ETestServerFixture fixture
251 e_test_server_utils_setup (ETestServerFixture *fixture,
252 gconstpointer user_data)
254 ETestServerClosure *closure = (ETestServerClosure *) user_data;
255 FixturePair pair = { fixture, closure };
257 /* Create work directory */
258 g_assert (g_mkdir_with_parents (EDS_TEST_WORK_DIR, 0755) == 0);
260 fixture->loop = g_main_loop_new (NULL, FALSE);
262 if (!test_installed_services ()) {
263 #if !GLOBAL_DBUS_DAEMON
264 /* Create the global dbus-daemon for this test suite */
265 fixture->dbus = g_test_dbus_new (G_TEST_DBUS_NONE);
267 /* Add the private directory with our in-tree service files */
268 g_test_dbus_add_service_dir (fixture->dbus, EDS_TEST_DBUS_SERVICE_DIR);
270 /* Start the private D-Bus daemon */
271 g_test_dbus_up (fixture->dbus);
273 fixture->dbus = global_test_dbus;
277 g_idle_add ((GSourceFunc) e_test_server_utils_bootstrap_idle, &pair);
278 g_main_loop_run (fixture->loop);
280 /* This needs to be explicitly removed, otherwise the timeout source
281 * stays in the default GMainContext and after running tests for 20 seconds
282 * in the same test suite... the tests bail out.
284 if (fixture->timeout_source_id) {
285 g_source_remove (fixture->timeout_source_id);
286 fixture->timeout_source_id = 0;
289 g_signal_handlers_disconnect_by_func (fixture->registry, e_test_server_utils_source_added, &pair);
293 * e_test_server_utils_teardown:
294 * @fixture: A #ETestServerFixture
295 * @user_data: A #ETestServerClosure or derived structure provided by the test.
297 * A teardown function for the #ETestServerFixture fixture
300 e_test_server_utils_teardown (ETestServerFixture *fixture,
301 gconstpointer user_data)
303 ETestServerClosure *closure = (ETestServerClosure *) user_data;
304 GError *error = NULL;
306 switch (closure->type) {
307 case E_TEST_SERVER_ADDRESS_BOOK:
308 case E_TEST_SERVER_DIRECT_ADDRESS_BOOK:
309 if (!e_client_remove_sync (E_CLIENT (fixture->service.book_client), NULL, &error)) {
310 g_message ("Failed to remove test book: %s (ignoring)", error->message);
311 g_clear_error (&error);
313 g_object_unref (fixture->service.book_client);
314 fixture->service.book_client = NULL;
317 case E_TEST_SERVER_DEPRECATED_ADDRESS_BOOK:
318 if (!e_book_remove (fixture->service.book, &error)) {
319 g_message ("Failed to remove test book: %s (ignoring)", error->message);
320 g_clear_error (&error);
322 g_object_unref (fixture->service.book);
323 fixture->service.book = NULL;
326 case E_TEST_SERVER_CALENDAR:
327 if (!e_client_remove_sync (E_CLIENT (fixture->service.calendar_client), NULL, &error)) {
328 g_message ("Failed to remove test calendar: %s (ignoring)", error->message);
329 g_clear_error (&error);
331 g_object_unref (fixture->service.calendar_client);
332 fixture->service.calendar_client = NULL;
335 case E_TEST_SERVER_DEPRECATED_CALENDAR:
336 if (!e_cal_remove (fixture->service.calendar, &error)) {
337 g_message ("Failed to remove test calendar: %s (ignoring)", error->message);
338 g_clear_error (&error);
340 g_object_unref (fixture->service.calendar);
341 fixture->service.calendar = NULL;
343 case E_TEST_SERVER_NONE:
347 g_object_run_dispose (G_OBJECT (fixture->registry));
348 g_object_unref (fixture->registry);
349 fixture->registry = NULL;
351 g_main_loop_unref (fixture->loop);
352 fixture->loop = NULL;
354 if (!test_installed_services ()) {
355 #if !GLOBAL_DBUS_DAEMON
356 /* Teardown the D-Bus Daemon
358 * Note that we intentionally leak the TestDBus daemon
359 * in this case, presumably this is due to some leaked
360 * GDBusConnection reference counting
362 g_test_dbus_down (fixture->dbus);
363 g_object_unref (fixture->dbus);
364 fixture->dbus = NULL;
366 fixture->dbus = NULL;
370 /* Cleanup work directory */
371 if (!closure->keep_work_directory && !test_installed_services ())
372 delete_work_directory ();
374 /* Destroy dynamically allocated closure */
375 if (closure->destroy_closure_func)
376 closure->destroy_closure_func (closure);
380 e_test_server_utils_run (void)
384 /* Cleanup work directory */
385 delete_work_directory ();
387 setup_environment ();
389 #if GLOBAL_DBUS_DAEMON
390 if (!test_installed_services ()) {
391 /* Create the global dbus-daemon for this test suite */
392 global_test_dbus = g_test_dbus_new (G_TEST_DBUS_NONE);
394 /* Add the private directory with our in-tree service files */
395 g_test_dbus_add_service_dir (global_test_dbus, EDS_TEST_DBUS_SERVICE_DIR);
397 /* Start the private D-Bus daemon */
398 g_test_dbus_up (global_test_dbus);
402 /* Run the GTest suite */
403 tests_ret = g_test_run ();
405 #if GLOBAL_DBUS_DAEMON
406 if (!test_installed_services ()) {
407 /* Teardown the D-Bus Daemon
409 * Note that we intentionally leak the TestDBus daemon
410 * in this case, presumably this is due to some leaked
411 * GDBusConnection reference counting
413 g_test_dbus_stop (global_test_dbus);
414 /* g_object_unref (global_test_dbus); */
415 global_test_dbus = NULL;