1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * This program is free software: you can redistribute it and/or modify it
4  * under the terms of the GNU Lesser General Public License as published by
5  * the Free Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful, but
8  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
9  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
10  * for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public License
13  * along with this program. If not, see <http://www.gnu.org/licenses/>.
14  *
15  */
16 
17 #include <stdlib.h>
18 #include <libecal/libecal.h>
19 
20 #include "e-test-server-utils.h"
21 
22 static ETestServerClosure cal_closure =
23 	{ E_TEST_SERVER_CALENDAR, NULL, E_CAL_CLIENT_SOURCE_TYPE_EVENTS };
24 
25 #define NB_COMPONENTS 5
26 
27 static void
test_icomps(ICalComponent * icomp1,ICalComponent * icomp2)28 test_icomps (ICalComponent *icomp1,
29 	     ICalComponent *icomp2)
30 {
31 	ICalTime *t1, *t2;
32 
33 	if (!icomp2)
34 		g_error ("Failure: get object returned NULL");
35 
36 	g_assert_cmpstr (i_cal_component_get_uid (icomp1), ==, i_cal_component_get_uid (icomp2));
37 	g_assert_cmpstr (i_cal_component_get_summary (icomp1), ==, i_cal_component_get_summary (icomp2));
38 
39 	t1 = i_cal_component_get_dtstart (icomp1);
40 	t2 = i_cal_component_get_dtstart (icomp2);
41 
42 	if (i_cal_time_compare (t1, t2) != 0) {
43 		gchar *str1, *str2;
44 
45 		str1 = i_cal_time_as_ical_string (t1);
46 		str2 = i_cal_time_as_ical_string (t2);
47 
48 		g_error ("Failure: dtend doesn't match, expected '%s', got '%s'\n", str1, str2);
49 
50 		g_free (str1);
51 		g_free (str2);
52 	}
53 
54 	g_clear_object (&t1);
55 	g_clear_object (&t2);
56 
57 	t1 = i_cal_component_get_dtend (icomp1);
58 	t2 = i_cal_component_get_dtend (icomp2);
59 
60 	if (i_cal_time_compare (t1, t2) != 0) {
61 		gchar *str1, *str2;
62 
63 		str1 = i_cal_time_as_ical_string (t1);
64 		str2 = i_cal_time_as_ical_string (t2);
65 
66 		g_error ("Failure: dtend doesn't match, expected '%s', got '%s'\n", str1, str2);
67 
68 		g_free (str1);
69 		g_free (str2);
70 	}
71 
72 	g_clear_object (&t1);
73 	g_clear_object (&t2);
74 }
75 
76 static void
check_removed(ECalClient * cal_client,const GSList * uids)77 check_removed (ECalClient *cal_client,
78                const GSList *uids)
79 {
80 	g_assert (cal_client != NULL);
81 	g_assert (uids != NULL);
82 
83 	while (uids) {
84 		GError *error = NULL;
85 		ICalComponent *icomp = NULL;
86 
87 		if (!e_cal_client_get_object_sync (cal_client, uids->data, NULL, &icomp, NULL, &error) &&
88 		    g_error_matches (error, E_CAL_CLIENT_ERROR, E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND)) {
89 			g_clear_error (&error);
90 		} else if (error) {
91 			g_error ("check objects removed sync: %s", error->message);
92 			g_clear_error (&error);
93 		} else {
94 			g_clear_object (&icomp);
95 
96 			g_error ("check objects removed sync: object found in the backend");
97 		}
98 
99 		uids = uids->next;
100 	}
101 }
102 
103 static GSList *
uid_slist_to_ecalcomponentid_slist(GSList * uids)104 uid_slist_to_ecalcomponentid_slist (GSList *uids)
105 {
106 	GSList *ids = NULL;
107 	const GSList *l;
108 
109 	for (l = uids; l; l = l->next) {
110 		ids = g_slist_append (ids, e_cal_component_id_new (l->data, NULL));
111 	}
112 
113 	return ids;
114 }
115 
116 static void
check_icomps_exist(ECalClient * cal_client,GSList * icomps)117 check_icomps_exist (ECalClient *cal_client,
118 		    GSList *icomps)
119 {
120 	GSList *link;
121 
122 	for (link = icomps; link; link = g_slist_next (link)) {
123 		GError *error = NULL;
124 		ICalComponent *icomp = link->data;
125 		ICalComponent *icomp2 = NULL;
126 		const gchar *uid = i_cal_component_get_uid (icomp);
127 
128 		if (!e_cal_client_get_object_sync (cal_client, uid, NULL, &icomp2, NULL, &error))
129 			g_error ("get object sync: %s", error->message);
130 
131 		g_assert_nonnull (icomp2);
132 
133 		test_icomps (icomp, icomp2);
134 
135 		g_object_unref (icomp2);
136 	}
137 }
138 
139 static void
test_bulk_methods_sync(ECalClient * cal_client,GSList * icomps)140 test_bulk_methods_sync (ECalClient *cal_client,
141 			GSList *icomps)
142 {
143 	GError *error = NULL;
144 	GSList *uids = NULL, *ids = NULL;
145 	const GSList *lcomp, *luid;
146 	gint i = 0;
147 
148 	g_assert_nonnull (icomps);
149 
150 	/* Create all the objects in bulk */
151 	if (!e_cal_client_create_objects_sync (cal_client, icomps, E_CAL_OPERATION_FLAG_NONE, &uids, NULL, &error))
152 		g_error ("create objects sync: %s", error->message);
153 
154 	g_assert (uids != NULL);
155 	g_assert_cmpint (g_slist_length (uids), ==, NB_COMPONENTS);
156 
157 	/* Update ICalComponents uids */
158 	luid = uids;
159 	lcomp = icomps;
160 	while (luid && lcomp) {
161 		i_cal_component_set_uid (lcomp->data, luid->data);
162 		luid = luid->next;
163 		lcomp = lcomp->next;
164 	}
165 
166 	/* Retrieve all the objects and check that they are the same */
167 	check_icomps_exist (cal_client, icomps);
168 
169 	/* Modify the objects */
170 	for (lcomp = icomps; lcomp; lcomp = lcomp->next) {
171 		gchar *summary;
172 		ICalComponent *icomp = lcomp->data;
173 
174 		summary = g_strdup_printf ("Edited test summary %d", i);
175 		i_cal_component_set_summary (icomp, summary);
176 
177 		g_free (summary);
178 		++i;
179 	}
180 
181 	/* Save the modified objects in bulk */
182 	if (!e_cal_client_modify_objects_sync (cal_client, icomps, E_CAL_OBJ_MOD_ALL, E_CAL_OPERATION_FLAG_NONE, NULL, &error))
183 		g_error ("modify objects sync: %s", error->message);
184 
185 	/* Retrieve all the objects and check that they have been modified */
186 	check_icomps_exist (cal_client, icomps);
187 
188 	/* Remove all the objects in bulk */
189 	ids = uid_slist_to_ecalcomponentid_slist (uids);
190 
191 	if (!e_cal_client_remove_objects_sync (cal_client, ids, E_CAL_OBJ_MOD_ALL, E_CAL_OPERATION_FLAG_NONE, NULL, &error))
192 		g_error ("remove objects sync: %s", error->message);
193 
194 	g_slist_free_full (ids, e_cal_component_id_free);
195 
196 	/* Check that the objects don't exist anymore */
197 	check_removed (cal_client, uids);
198 
199 	g_slist_free_full (uids, g_free);
200 }
201 
202 typedef struct _AsyncContext {
203 	ECalClient *cal_client;
204 	GSList *icomps; /* ICalComponent * */
205 	GSList *ids; /* ECalComponentId * */
206 	GSList *uids; /* gchar * */
207 	GMainLoop *main_loop;
208 } AsyncContext;
209 
210 static void
bulk_async_remove_objects_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)211 bulk_async_remove_objects_cb (GObject *source_object,
212 			      GAsyncResult *result,
213 			      gpointer user_data)
214 {
215 	AsyncContext *async_context = user_data;
216 	gboolean success;
217 	GError *error = NULL;
218 
219 	g_assert_nonnull (async_context);
220 	g_assert (E_IS_CAL_CLIENT (source_object));
221 	g_assert (async_context->cal_client == E_CAL_CLIENT (source_object));
222 
223 	success = e_cal_client_remove_objects_finish (async_context->cal_client, result, &error);
224 	g_assert_no_error (error);
225 	g_assert (success);
226 
227 	/* Check that the objects don't exist anymore */
228 	check_removed (async_context->cal_client, async_context->uids);
229 
230 	g_main_loop_quit (async_context->main_loop);
231 }
232 
233 static void
bulk_async_modify_objects_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)234 bulk_async_modify_objects_cb (GObject *source_object,
235 			      GAsyncResult *result,
236 			      gpointer user_data)
237 {
238 	AsyncContext *async_context = user_data;
239 	gboolean success;
240 	GError *error = NULL;
241 
242 	g_assert_nonnull (async_context);
243 	g_assert (E_IS_CAL_CLIENT (source_object));
244 	g_assert (async_context->cal_client == E_CAL_CLIENT (source_object));
245 
246 	success = e_cal_client_modify_objects_finish (async_context->cal_client, result, &error);
247 	g_assert_no_error (error);
248 	g_assert (success);
249 
250 	/* Retrieve all the objects and check that they have been modified */
251 	check_icomps_exist (async_context->cal_client, async_context->icomps);
252 
253 	/* Remove all the objects in bulk */
254 	async_context->ids = uid_slist_to_ecalcomponentid_slist (async_context->uids);
255 
256 	e_cal_client_remove_objects (async_context->cal_client, async_context->ids, E_CAL_OBJ_MOD_ALL, E_CAL_OPERATION_FLAG_NONE,
257 		NULL, bulk_async_remove_objects_cb, async_context);
258 }
259 
260 static void
bulk_async_create_objects_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)261 bulk_async_create_objects_cb (GObject *source_object,
262 			      GAsyncResult *result,
263 			      gpointer user_data)
264 {
265 	AsyncContext *async_context = user_data;
266 	GSList *luid, *lcomp;
267 	gboolean success;
268 	gint ii;
269 	GError *error = NULL;
270 
271 	g_assert_nonnull (async_context);
272 	g_assert (E_IS_CAL_CLIENT (source_object));
273 	g_assert (async_context->cal_client == E_CAL_CLIENT (source_object));
274 
275 	success = e_cal_client_create_objects_finish (async_context->cal_client, result, &async_context->uids, &error);
276 	g_assert_no_error (error);
277 	g_assert (success);
278 	g_assert_nonnull (async_context->uids);
279 	g_assert_cmpint (g_slist_length (async_context->uids), ==, NB_COMPONENTS);
280 
281 	/* Update ICalComponents uids */
282 	for (luid = async_context->uids, lcomp = async_context->icomps;
283 	     luid && lcomp;
284 	     luid = g_slist_next (luid), lcomp = g_slist_next (lcomp)) {
285 		i_cal_component_set_uid (lcomp->data, luid->data);
286 	}
287 
288 	/* Retrieve all the objects and check that they are the same */
289 	check_icomps_exist (async_context->cal_client, async_context->icomps);
290 
291 	/* Modify the objects */
292 	for (ii = 0, lcomp = async_context->icomps; lcomp; ii++, lcomp = g_slist_next (lcomp)) {
293 		gchar *summary;
294 		ICalComponent *icomp = lcomp->data;
295 
296 		summary = g_strdup_printf ("Edited test summary %d", ii);
297 		i_cal_component_set_summary (icomp, summary);
298 
299 		g_free (summary);
300 	}
301 
302 	e_cal_client_modify_objects (async_context->cal_client, async_context->icomps, E_CAL_OBJ_MOD_ALL, E_CAL_OPERATION_FLAG_NONE,
303 		NULL, bulk_async_modify_objects_cb, async_context);
304 }
305 
306 static void
test_bulk_methods_async(ECalClient * cal_client,GSList * icomps)307 test_bulk_methods_async (ECalClient *cal_client,
308 			 GSList *icomps)
309 {
310 	AsyncContext async_context;
311 
312 	g_assert_nonnull (icomps);
313 
314 	async_context.cal_client = cal_client;
315 	async_context.icomps = icomps;
316 	async_context.ids = NULL;
317 	async_context.uids = NULL;
318 	async_context.main_loop = g_main_loop_new (NULL, FALSE);
319 
320 	e_cal_client_create_objects (async_context.cal_client, async_context.icomps, E_CAL_OPERATION_FLAG_NONE, NULL,
321 		bulk_async_create_objects_cb, &async_context);
322 
323 	g_main_loop_run (async_context.main_loop);
324 
325 	g_slist_free_full (async_context.ids, e_cal_component_id_free);
326 	g_slist_free_full (async_context.uids, g_free);
327 	g_main_loop_unref (async_context.main_loop);
328 }
329 
330 static void
run_test_bulk_methods_wrapper(ETestServerFixture * fixture,void (* func)(ECalClient * cal_client,GSList * icomps))331 run_test_bulk_methods_wrapper (ETestServerFixture *fixture,
332 			       void (* func)(ECalClient *cal_client,
333 					     GSList *icomps))
334 {
335 	ECalClient *cal_client;
336 	GSList *icomps = NULL;
337 	ICalTime *dtstart, *dtend;
338 	gint ii;
339 
340 	cal_client = E_TEST_SERVER_UTILS_SERVICE (fixture, ECalClient);
341 
342 	dtstart = i_cal_time_new_current_with_zone (i_cal_timezone_get_utc_timezone ());
343 	dtend = i_cal_time_clone (dtstart);
344 	i_cal_time_adjust (dtend, 0, 1, 0, 0);
345 
346 	/* Build up new components */
347 	for (ii = 0; ii < NB_COMPONENTS; ++ii) {
348 		ICalComponent *icomp;
349 		gchar *summary;
350 
351 		icomp = i_cal_component_new (I_CAL_VEVENT_COMPONENT);
352 		summary = g_strdup_printf ("Test summary %d", ii);
353 		i_cal_component_set_summary (icomp, summary);
354 		i_cal_component_set_dtstart (icomp, dtstart);
355 		i_cal_component_set_dtend (icomp, dtend);
356 
357 		icomps = g_slist_append (icomps, icomp);
358 		g_free (summary);
359 	}
360 
361 	g_clear_object (&dtstart);
362 	g_clear_object (&dtend);
363 
364 	/* Test synchronous bulk methods */
365 	func (cal_client, icomps);
366 
367 	g_slist_free_full (icomps, g_object_unref);
368 }
369 
370 static void
run_test_bulk_methods_sync(ETestServerFixture * fixture,gconstpointer user_data)371 run_test_bulk_methods_sync (ETestServerFixture *fixture,
372 			    gconstpointer user_data)
373 {
374 	run_test_bulk_methods_wrapper (fixture, test_bulk_methods_sync);
375 }
376 
377 static void
run_test_bulk_methods_async(ETestServerFixture * fixture,gconstpointer user_data)378 run_test_bulk_methods_async (ETestServerFixture *fixture,
379 			     gconstpointer user_data)
380 {
381 	run_test_bulk_methods_wrapper (fixture, test_bulk_methods_async);
382 }
383 
384 gint
main(gint argc,gchar ** argv)385 main (gint argc,
386       gchar **argv)
387 {
388 	g_test_init (&argc, &argv, NULL);
389 	g_test_bug_base ("http://bugzilla.gnome.org/");
390 
391 	g_test_add (
392 		"/ECalClient/BulkMethods/Sync",
393 		ETestServerFixture,
394 		&cal_closure,
395 		e_test_server_utils_setup,
396 		run_test_bulk_methods_sync,
397 		e_test_server_utils_teardown);
398 	g_test_add (
399 		"/ECalClient/BulkMethods/Async",
400 		ETestServerFixture,
401 		&cal_closure,
402 		e_test_server_utils_setup,
403 		run_test_bulk_methods_async,
404 		e_test_server_utils_teardown);
405 
406 	return e_test_server_utils_run (argc, argv);
407 }
408