6cb03c44bffea39f5064b999960963c770a061d6
[platform/upstream/evolution-data-server.git] / tests / test-server-utils / e-test-server-utils.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /* e-test-server-utils.c - Test scaffolding to run tests with in-tree data server.
4  *
5  * Copyright (C) 2012 Intel Corporation
6  *
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.
11  *
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.
16  *
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/>
19  *
20  * Authors: Tristan Van Berkom <tristanvb@openismus.com>
21  */
22
23 #include "e-test-server-utils.h"
24
25 #define ADDRESS_BOOK_SOURCE_UID "test-address-book"
26 #define CALENDAR_SOURCE_UID     "test-calendar"
27
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.
31  *
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.
37  */
38 #define GLOBAL_DBUS_DAEMON 1
39
40 #if GLOBAL_DBUS_DAEMON
41 static GTestDBus *global_test_dbus = NULL;
42 #endif
43
44 typedef struct {
45         ETestServerFixture *fixture;
46         ETestServerClosure *closure;
47 } FixturePair;
48
49 static void
50 setup_environment (void)
51 {
52         g_assert (g_setenv ("XDG_DATA_HOME", EDS_TEST_WORK_DIR, TRUE));
53         g_assert (g_setenv ("XDG_CACHE_HOME", EDS_TEST_WORK_DIR, TRUE));
54         g_assert (g_setenv ("XDG_CONFIG_HOME", EDS_TEST_WORK_DIR, TRUE));
55         g_assert (g_setenv ("GSETTINGS_SCHEMA_DIR", EDS_TEST_SCHEMA_DIR, TRUE));
56         g_assert (g_setenv ("EDS_CALENDAR_MODULES", EDS_TEST_CALENDAR_DIR, TRUE));
57         g_assert (g_setenv ("EDS_ADDRESS_BOOK_MODULES", EDS_TEST_ADDRESS_BOOK_DIR, TRUE));
58 }
59
60 static void
61 delete_work_directory (void)
62 {
63         /* XXX Instead of complex error checking here, we should ideally use
64          * a recursive GDir / g_unlink() function.
65          *
66          * We cannot use GFile and the recursive delete function without
67          * corrupting our contained D-Bus environment with service files
68          * from the OS.
69          */
70         const gchar *argv[] = { "/bin/rm", "-rf", EDS_TEST_WORK_DIR, NULL };
71         gboolean spawn_succeeded;
72         gint exit_status;
73
74         spawn_succeeded = g_spawn_sync (
75                 NULL, (gchar **) argv, NULL, 0, NULL, NULL,
76                                         NULL, NULL, &exit_status, NULL);
77
78         g_assert (spawn_succeeded);
79         g_assert (WIFEXITED (exit_status));
80         g_assert_cmpint (WEXITSTATUS (exit_status), ==, 0);
81 }
82
83 static gboolean
84 e_test_server_utils_bootstrap_timeout (FixturePair *pair)
85 {
86         ESource *source = NULL;
87         GError  *error = NULL;
88
89         switch (pair->closure->type) {
90         case E_TEST_SERVER_ADDRESS_BOOK:
91                 source = e_source_registry_ref_source (pair->fixture->registry, ADDRESS_BOOK_SOURCE_UID);
92                 if (!source)
93                         g_error ("Unable to fetch newly created addressbook source from the registry");
94
95                 pair->fixture->service.book_client = e_book_client_new (source, &error);
96                 if (!pair->fixture->service.book_client)
97                         g_error ("Unable to create the test book: %s", error->message);
98
99                 if (!e_client_open_sync (E_CLIENT (pair->fixture->service.book_client), FALSE, NULL, &error))
100                         g_error ("Unable to open book client: %s", error->message);
101
102                 break;
103
104         case E_TEST_SERVER_DEPRECATED_ADDRESS_BOOK:
105                 source = e_source_registry_ref_source (pair->fixture->registry, ADDRESS_BOOK_SOURCE_UID);
106                 if (!source)
107                         g_error ("Unable to fetch newly created addressbook source from the registry");
108
109                 pair->fixture->service.book = e_book_new (source, &error);
110                 if (!pair->fixture->service.book)
111                         g_error ("Unable to create the test book: %s", error->message);
112
113                 if (!e_book_open (pair->fixture->service.book, FALSE, &error))
114                         g_error ("Unable to open book: %s", error->message);
115
116                 break;
117
118         case E_TEST_SERVER_CALENDAR:
119                 source = e_source_registry_ref_source (pair->fixture->registry, CALENDAR_SOURCE_UID);
120                 if (!source)
121                         g_error ("Unable to fetch newly created addressbook source from the registry");
122
123                 pair->fixture->service.calendar_client = e_cal_client_new (source,
124                         pair->closure->calendar_source_type,
125                         &error);
126                 if (!pair->fixture->service.calendar_client)
127                         g_error ("Unable to create the test calendar: %s", error->message);
128
129                 if (!e_client_open_sync (E_CLIENT (pair->fixture->service.calendar_client), FALSE, NULL, &error))
130                         g_error ("Unable to open calendar client: %s", error->message);
131
132                 break;
133
134         case E_TEST_SERVER_DEPRECATED_CALENDAR:
135                 source = e_source_registry_ref_source (pair->fixture->registry, CALENDAR_SOURCE_UID);
136                 if (!source)
137                         g_error ("Unable to fetch newly created addressbook source from the registry");
138
139                 pair->fixture->service.calendar = e_cal_new (source, pair->closure->calendar_source_type);
140                 if (!pair->fixture->service.calendar)
141                         g_error ("Unable to create the test calendar");
142
143                 if (!e_cal_open (pair->fixture->service.calendar, FALSE, &error))
144                         g_error ("Unable to open calendar: %s", error->message);
145
146                 break;
147
148         case E_TEST_SERVER_NONE:
149                 break;
150         }
151
152         if (source)
153                 g_object_unref (source);
154
155         g_main_loop_quit (pair->fixture->loop);
156
157         return FALSE;
158 }
159
160 static gboolean
161 e_test_server_utils_bootstrap_idle (FixturePair *pair)
162 {
163         ESourceBackend *backend = NULL;
164         ESource *scratch = NULL;
165         GError  *error = NULL;
166
167         pair->fixture->registry = e_source_registry_new_sync (NULL, &error);
168
169         if (!pair->fixture->registry)
170                 g_error ("Unable to create the test registry: %s", error->message);
171
172         /* Create an address book */
173         switch (pair->closure->type) {
174         case E_TEST_SERVER_ADDRESS_BOOK:
175         case E_TEST_SERVER_DEPRECATED_ADDRESS_BOOK:
176
177                 scratch = e_source_new_with_uid (ADDRESS_BOOK_SOURCE_UID, NULL, &error);
178                 if (!scratch)
179                         g_error ("Failed to create scratch source for an addressbook: %s", error->message);
180
181                 /* Ensure Book type */
182                 backend = e_source_get_extension (scratch, E_SOURCE_EXTENSION_ADDRESS_BOOK);
183                 e_source_backend_set_backend_name (backend, "local");
184
185                 break;
186         case E_TEST_SERVER_CALENDAR:
187         case E_TEST_SERVER_DEPRECATED_CALENDAR:
188
189                 scratch = e_source_new_with_uid (CALENDAR_SOURCE_UID, NULL, &error);
190                 if (!scratch)
191                         g_error ("Failed to create scratch source for a calendar: %s", error->message);
192
193                 /* Ensure Calendar type source (how to specify the backend here ?? */
194                 backend = e_source_get_extension (scratch, E_SOURCE_EXTENSION_CALENDAR);
195                 e_source_backend_set_backend_name (backend, "local");
196
197                 break;
198
199         case E_TEST_SERVER_NONE:
200                 break;
201         }
202
203         if (scratch) {
204                 if (pair->closure->customize)
205                         pair->closure->customize (scratch, pair->closure);
206
207                 if (!e_source_registry_commit_source_sync (pair->fixture->registry, scratch, NULL, &error))
208                         g_error ("Unable to add new addressbook source to the registry: %s", error->message);
209
210                 g_object_unref (scratch);
211         }
212
213         if (pair->closure->type != E_TEST_SERVER_NONE)
214                 g_timeout_add (20, (GSourceFunc) e_test_server_utils_bootstrap_timeout, pair);
215         else
216                 g_main_loop_quit (pair->fixture->loop);
217
218         return FALSE;
219 }
220
221 /**
222  * e_test_server_utils_setup:
223  * @fixture: A #ETestServerFixture
224  * @user_data: A #ETestServerClosure or derived structure provided by the test.
225  *
226  * A setup function for the #ETestServerFixture fixture
227  */
228 void
229 e_test_server_utils_setup (ETestServerFixture *fixture,
230                            gconstpointer user_data)
231 {
232         ETestServerClosure *closure = (ETestServerClosure *) user_data;
233         FixturePair         pair    = { fixture, closure };
234
235         /* Create work directory */
236         g_assert (g_mkdir_with_parents (EDS_TEST_WORK_DIR, 0755) == 0);
237
238         fixture->loop = g_main_loop_new (NULL, FALSE);
239
240 #if !GLOBAL_DBUS_DAEMON
241         /* Create the global dbus-daemon for this test suite */
242         fixture->dbus = g_test_dbus_new (G_TEST_DBUS_NONE);
243
244         /* Add the private directory with our in-tree service files */
245         g_test_dbus_add_service_dir (fixture->dbus, EDS_TEST_DBUS_SERVICE_DIR);
246
247         /* Start the private D-Bus daemon */
248         g_test_dbus_up (fixture->dbus);
249 #else
250         fixture->dbus = global_test_dbus;
251 #endif
252
253         g_idle_add ((GSourceFunc) e_test_server_utils_bootstrap_idle, &pair);
254         g_main_loop_run (fixture->loop);
255 }
256
257 /**
258  * e_test_server_utils_teardown:
259  * @fixture: A #ETestServerFixture
260  * @user_data: A #ETestServerClosure or derived structure provided by the test.
261  *
262  * A teardown function for the #ETestServerFixture fixture
263  */
264 void
265 e_test_server_utils_teardown (ETestServerFixture *fixture,
266                               gconstpointer user_data)
267 {
268         ETestServerClosure *closure = (ETestServerClosure *) user_data;
269         GError             *error = NULL;
270
271         switch (closure->type) {
272         case E_TEST_SERVER_ADDRESS_BOOK:
273                 if (!e_client_remove_sync (E_CLIENT (fixture->service.book_client), NULL, &error)) {
274                         g_message ("Failed to remove test book: %s (ignoring)", error->message);
275                         g_clear_error (&error);
276                 }
277                 g_object_unref (fixture->service.book_client);
278                 fixture->service.book_client = NULL;
279                 break;
280
281         case E_TEST_SERVER_DEPRECATED_ADDRESS_BOOK:
282                 if (!e_book_remove (fixture->service.book, &error)) {
283                         g_message ("Failed to remove test book: %s (ignoring)", error->message);
284                         g_clear_error (&error);
285                 }
286                 g_object_unref (fixture->service.book);
287                 fixture->service.book = NULL;
288                 break;
289
290         case E_TEST_SERVER_CALENDAR:
291                 if (!e_client_remove_sync (E_CLIENT (fixture->service.calendar_client), NULL, &error)) {
292                         g_message ("Failed to remove test calendar: %s (ignoring)", error->message);
293                         g_clear_error (&error);
294                 }
295                 g_object_unref (fixture->service.calendar_client);
296                 fixture->service.calendar_client = NULL;
297                 break;
298
299         case E_TEST_SERVER_DEPRECATED_CALENDAR:
300                 if (!e_cal_remove (fixture->service.calendar, &error)) {
301                         g_message ("Failed to remove test calendar: %s (ignoring)", error->message);
302                         g_clear_error (&error);
303                 }
304                 g_object_unref (fixture->service.calendar);
305                 fixture->service.calendar = NULL;
306
307         case E_TEST_SERVER_NONE:
308                 break;
309         }
310
311         g_object_run_dispose (G_OBJECT (fixture->registry));
312         g_object_unref (fixture->registry);
313         fixture->registry = NULL;
314
315         g_main_loop_unref (fixture->loop);
316         fixture->loop = NULL;
317
318 #if !GLOBAL_DBUS_DAEMON
319         /* Teardown the D-Bus Daemon
320          *
321          * Note that we intentionally leak the TestDBus daemon
322          * in this case, presumably this is due to some leaked
323          * GDBusConnection reference counting
324          */
325         g_test_dbus_down (fixture->dbus);
326         g_object_unref (fixture->dbus);
327         fixture->dbus = NULL;
328 #else
329         fixture->dbus = NULL;
330 #endif
331
332         /* Cleanup work directory */
333         if (!closure->keep_work_directory)
334                 delete_work_directory ();
335 }
336
337 gint
338 e_test_server_utils_run (void)
339 {
340         gint tests_ret;
341
342         /* Cleanup work directory */
343         delete_work_directory ();
344
345         setup_environment ();
346
347 #if GLOBAL_DBUS_DAEMON
348
349         /* Create the global dbus-daemon for this test suite */
350         global_test_dbus = g_test_dbus_new (G_TEST_DBUS_NONE);
351
352         /* Add the private directory with our in-tree service files */
353         g_test_dbus_add_service_dir (global_test_dbus, EDS_TEST_DBUS_SERVICE_DIR);
354
355         /* Start the private D-Bus daemon */
356         g_test_dbus_up (global_test_dbus);
357 #endif
358
359         /* Run the GTest suite */
360         tests_ret = g_test_run ();
361
362 #if GLOBAL_DBUS_DAEMON
363         /* Teardown the D-Bus Daemon
364          *
365          * Note that we intentionally leak the TestDBus daemon
366          * in this case, presumably this is due to some leaked
367          * GDBusConnection reference counting
368          */
369         g_test_dbus_stop (global_test_dbus);
370         /* g_object_unref (global_test_dbus); */
371         global_test_dbus = NULL;
372 #endif
373
374   return tests_ret;
375 }