No issues found
1 /*
2 * Copyright (C) 2010, Codeminded BVBA <abustany@gnome.org>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #include "config.h"
21
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include <libtracker-sparql/tracker-sparql.h>
26
27 /* This MUST be larger than TRACKER_STEROIDS_BUFFER_SIZE */
28 #define LONG_NAME_SIZE 128 * 1024 * sizeof(char)
29
30 typedef struct {
31 GMainLoop *main_loop;
32 const gchar *query;
33 } AsyncData;
34
35 static TrackerSparqlConnection *connection;
36
37 static void
38 insert_test_data ()
39 {
40 GError *error = NULL;
41 const char *delete_query = "DELETE { "
42 "<urn:testdata1> a rdfs:Resource ."
43 "<urn:testdata2> a rdfs:Resource ."
44 "<urn:testdata3> a rdfs:Resource ."
45 "<urn:testdata4> a rdfs:Resource ."
46 "}";
47 char *longName = g_malloc (LONG_NAME_SIZE);
48 char *filled_query;
49
50 memset (longName, 'a', LONG_NAME_SIZE);
51
52 longName[LONG_NAME_SIZE - 1] = '\0';
53
54 filled_query = g_strdup_printf ("INSERT {"
55 " <urn:testdata1> a nfo:FileDataObject ; nie:url \"/foo/bar\" ."
56 " <urn:testdata2> a nfo:FileDataObject ; nie:url \"/plop/coin\" ."
57 " <urn:testdata3> a nmm:Artist ; nmm:artistName \"testArtist\" ."
58 " <urn:testdata4> a nmm:Photo ; nao:identifier \"%s\" ."
59 "}", longName);
60
61 tracker_sparql_connection_update (connection, delete_query, 0, NULL, &error);
62 g_assert_no_error (error);
63
64 tracker_sparql_connection_update (connection, filled_query, 0, NULL, &error);
65 g_assert_no_error (error);
66
67 g_free (filled_query);
68 g_free (longName);
69 }
70
71 /*
72 * I comment that part out because I don't know how anonymous node hashing
73 * works, but if we know two SparqlUpdate calls are going to return the same
74 * urns we could use those functions to compare the results between the normal
75 * and fast method. I wrote them before realizing I wouldn't know how to use
76 * them.
77 */
78 /*
79 static gboolean
80 compare_hash_tables (GHashTable *h1, GHashTable *h2)
81 {
82 GHashTableIter i1, i2;
83 gpointer k1, v1, k2, v2;
84
85 if (g_hash_table_size (h1) != g_hash_table_size (h2)) {
86 return FALSE;
87 }
88
89 g_hash_table_iter_init (&i1, h1);
90 g_hash_table_iter_init (&i2, h2);
91
92 while (g_hash_table_iter_next (&i1, &k1, &v1)) {
93 g_hash_table_iter_next (&i2, &k2, &v2);
94
95 if (g_strcmp0 (k1, k2)) {
96 return FALSE;
97 }
98
99 if (g_strcmp0 (v1, v2)) {
100 return FALSE;
101 }
102 }
103
104 return TRUE;
105 }
106
107 static gboolean
108 compare_results (GPtrArray *r1, GPtrArray *r2)
109 {
110 int i, j;
111
112 if (!r1 || !r2) {
113 return FALSE;
114 }
115
116 if (r1->len != r2->len) {
117 return FALSE;
118 }
119
120 for (i = 0; i < r1->len; i++) {
121 GPtrArray *inner1, *inner2;
122
123 inner1 = g_ptr_array_index (r1, i);
124 inner2 = g_ptr_array_index (r2, i);
125
126 if (inner1->len != inner2->len) {
127 return FALSE;
128 }
129
130 for (j = 0; j < inner1->len; j++) {
131 GHashTable *h1, *h2;
132
133 h1 = g_ptr_array_index (inner1, j);
134 h2 = g_ptr_array_index (inner2, j);
135
136 if (!compare_hash_tables (h1, h2)) {
137 return FALSE;
138 }
139 }
140 }
141
142 return TRUE;
143 }
144 */
145
146 static void
147 query_and_compare_results (const char *query)
148 {
149 TrackerSparqlCursor *cursor_glib;
150 TrackerSparqlCursor *cursor_fd;
151 GError *error = NULL;
152
153 cursor_glib = tracker_sparql_connection_query (connection, query, NULL, &error);
154
155 g_assert_no_error (error);
156
157 cursor_fd = tracker_sparql_connection_query (connection, query, NULL, &error);
158
159 g_assert_no_error (error);
160
161 while (tracker_sparql_cursor_next (cursor_glib, NULL, NULL) && tracker_sparql_cursor_next (cursor_fd, NULL, NULL)) {
162 g_assert_cmpstr (tracker_sparql_cursor_get_string (cursor_glib, 0, NULL),
163 ==,
164 tracker_sparql_cursor_get_string (cursor_fd, 0, NULL));
165 }
166
167 /* Check that both cursors are at the end (same number of rows) */
168 g_assert (!tracker_sparql_cursor_next (cursor_glib, NULL, NULL));
169 g_assert (!tracker_sparql_cursor_next (cursor_fd, NULL, NULL));
170
171 g_object_unref (cursor_glib);
172 g_object_unref (cursor_fd);
173 }
174
175 static void
176 test_tracker_sparql_query_iterate () {
177 query_and_compare_results ("SELECT ?r nie:url(?r) WHERE {?r a nfo:FileDataObject}");
178 }
179
180 static void
181 test_tracker_sparql_query_iterate_largerow ()
182 {
183 query_and_compare_results ("SELECT nao:identifier(?r) WHERE {?r a nmm:Photo}");
184 }
185
186 /* Runs an invalid query */
187 static void
188 test_tracker_sparql_query_iterate_error ()
189 {
190 TrackerSparqlCursor *cursor;
191 GError *error = NULL;
192 const gchar *query = "bork bork bork";
193
194 cursor = tracker_sparql_connection_query (connection, query, NULL, &error);
195
196 /* tracker_sparql_query_iterate should return null on error */
197 g_assert (!cursor);
198
199 /* error should be set, along with its message, note: we don't
200 * use g_assert_error() because the code does not match the
201 * enum values for TRACKER_SPARQL_ERROR_*, this is due to
202 * dbus/error matching between client/server. This should be
203 * fixed in gdbus.
204 */
205 g_assert (error != NULL && error->domain == TRACKER_SPARQL_ERROR);
206
207 g_error_free (error);
208 }
209
210 /* Runs a query returning an empty set */
211 static void
212 test_tracker_sparql_query_iterate_empty ()
213 {
214 TrackerSparqlCursor *cursor;
215 GError *error = NULL;
216 const gchar *query = "SELECT ?r WHERE {?r a nfo:FileDataObject; nao:identifier \"thisannotationdoesnotexist\"}";
217
218 cursor = tracker_sparql_connection_query (connection, query, NULL, &error);
219
220 g_assert (cursor);
221 g_assert_no_error (error);
222
223 g_assert (!tracker_sparql_cursor_next (cursor, NULL, NULL));
224 /* This should be 1, the original test had it wrong: there's one column,
225 * no matter if there are no results*/
226 g_assert (tracker_sparql_cursor_get_n_columns (cursor) == 1);
227 if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR)) {
228 tracker_sparql_cursor_get_string (cursor, 0, NULL);
229 exit (0);
230 }
231 g_test_trap_assert_failed ();
232
233 g_object_unref (cursor);
234 }
235
236 /* Closes the cursor before all results are read */
237 static void
238 test_tracker_sparql_query_iterate_sigpipe ()
239 {
240 TrackerSparqlCursor *cursor;
241 GError *error = NULL;
242 const gchar *query = "SELECT ?r WHERE {?r a nfo:FileDataObject}";
243
244 cursor = tracker_sparql_connection_query (connection, query, NULL, &error);
245
246 g_assert (cursor);
247 g_assert_no_error (error);
248
249 tracker_sparql_cursor_next (cursor, NULL, NULL);
250
251 g_object_unref (cursor);
252 }
253
254 static void
255 test_tracker_sparql_update_fast_small ()
256 {
257 GError *error = NULL;
258 const gchar *query = "INSERT { _:x a nmo:Message }";
259
260 tracker_sparql_connection_update (connection, query, 0, NULL, &error);
261
262 g_assert_no_error (error);
263 }
264
265 static void
266 test_tracker_sparql_update_fast_large ()
267 {
268 GError *error = NULL;
269 gchar *lots;
270 gchar *query;
271
272 lots = g_malloc (LONG_NAME_SIZE);
273 memset (lots, 'a', LONG_NAME_SIZE);
274 lots[LONG_NAME_SIZE-1] = '\0';
275
276 query = g_strdup_printf ("INSERT { _:x a nmo:Message; nao:identifier \"%s\" }", lots);
277
278 tracker_sparql_connection_update (connection, query, 0, NULL, &error);
279
280 g_free (lots);
281 g_free (query);
282
283 g_assert_no_error (error);
284 }
285
286 static void
287 async_update_array_callback (GObject *source_object,
288 GAsyncResult *result,
289 gpointer user_data)
290 {
291 GError *error = NULL;
292 AsyncData *data = user_data;
293 GPtrArray *errors;
294
295 errors = tracker_sparql_connection_update_array_finish (connection, result, &error);
296
297 /* main error is only set on fatal (D-Bus) errors that apply to the whole update */
298 g_assert_no_error (error);
299
300 g_assert (errors->len == 6);
301
302 g_assert (g_ptr_array_index (errors, 0) == NULL);
303 g_assert (g_ptr_array_index (errors, 1) == NULL);
304 g_assert (g_ptr_array_index (errors, 2) == NULL);
305 g_assert (g_ptr_array_index (errors, 3) != NULL);
306 g_assert (g_ptr_array_index (errors, 4) == NULL);
307 g_assert (g_ptr_array_index (errors, 5) == NULL);
308
309 g_ptr_array_unref (errors);
310
311 g_main_loop_quit (data->main_loop);
312 }
313
314
315 static void
316 test_tracker_sparql_update_array_async (void)
317 {
318 const gchar *queries[6] = { "INSERT { _:a a nmo:Message }",
319 "INSERT { _:b a nmo:Message }",
320 "INSERT { _:c a nmo:Message }",
321 "INSERT { _:d syntax error a nmo:Message }",
322 "INSERT { _:e a nmo:Message }",
323 "INSERT { _:f a nmo:Message }" };
324
325 GMainLoop *main_loop;
326 AsyncData *data;
327
328 main_loop = g_main_loop_new (NULL, FALSE);
329
330 data = g_slice_new (AsyncData);
331 data->main_loop = main_loop;
332
333 /* Cast here is because vala doesn't make const-char-** possible :( */
334 tracker_sparql_connection_update_array_async (connection,
335 (char**) queries,
336 6,
337 0,
338 NULL,
339 async_update_array_callback,
340 data);
341
342 g_main_loop_run (main_loop);
343
344 g_slice_free (AsyncData, data);
345 g_main_loop_unref (main_loop);
346
347 }
348
349 static void
350 test_tracker_sparql_update_fast_error ()
351 {
352 GError *error = NULL;
353 const gchar *query = "blork blork blork";
354
355 tracker_sparql_connection_update (connection, query, 0, NULL, &error);
356
357 g_assert (error != NULL && error->domain == TRACKER_SPARQL_ERROR);
358 g_error_free (error);
359 }
360
361 static void
362 test_tracker_sparql_update_blank_fast_small ()
363 {
364 GError *error = NULL;
365 const gchar *query = "INSERT { _:x a nmo:Message }";
366 GVariant *results;
367
368 results = tracker_sparql_connection_update_blank (connection, query, 0, NULL, &error);
369
370 g_assert_no_error (error);
371 g_assert (results);
372
373 /* FIXME: Properly test once we get update_blank implemented */
374 }
375
376 static void
377 test_tracker_sparql_update_blank_fast_large ()
378 {
379 GError *error = NULL;
380 gchar *lots;
381 gchar *query;
382 GVariant *results;
383
384 lots = g_malloc (LONG_NAME_SIZE);
385 memset (lots, 'a', LONG_NAME_SIZE);
386 lots[LONG_NAME_SIZE-1] = '\0';
387
388 query = g_strdup_printf ("INSERT { _:x a nmo:Message; nao:identifier \"%s\" }", lots);
389
390 results = tracker_sparql_connection_update_blank (connection, query, 0, NULL, &error);
391
392 g_free (lots);
393 g_free (query);
394
395 g_assert_no_error (error);
396 g_assert (results);
397
398 /* FIXME: Properly test once we get update_blank implemented */
399 }
400
401 static void
402 test_tracker_sparql_update_blank_fast_error (void)
403 {
404 GError *error = NULL;
405 const gchar *query = "blork blork blork";
406 GVariant *results;
407
408 results = tracker_sparql_connection_update_blank (connection, query, 0, NULL, &error);
409
410 g_assert (error != NULL && error->domain == TRACKER_SPARQL_ERROR);
411 g_assert (!results);
412
413 g_error_free (error);
414 }
415
416 static void
417 test_tracker_sparql_update_blank_fast_no_blanks (void)
418 {
419 GError *error = NULL;
420 const gchar *query = "INSERT { <urn:not_blank> a nmo:Message }";
421 GVariant *results;
422
423 results = tracker_sparql_connection_update_blank (connection, query, 0, NULL, &error);
424
425 /* FIXME: Properly test once we get update_blank implemented */
426
427 g_assert_no_error (error);
428 g_assert (results);
429 }
430
431 static void
432 test_tracker_batch_sparql_update_fast (void)
433 {
434 /* GError *error = NULL; */
435 /* const gchar *query = "INSERT { _:x a nmo:Message }"; */
436
437 /* FIXME: batch update is missing so far
438 * tracker_sparql_connection_batch_update (connection, query, NULL, &error); */
439
440 /* g_assert (!error); */
441 }
442
443 static void
444 async_query_cb (GObject *source_object,
445 GAsyncResult *result,
446 gpointer user_data)
447 {
448 TrackerSparqlCursor *cursor_fd;
449 TrackerSparqlCursor *cursor_glib;
450 AsyncData *data = user_data;
451 GError *error = NULL;
452
453 g_main_loop_quit (data->main_loop);
454
455 cursor_fd = tracker_sparql_connection_query_finish (connection, result, &error);
456
457 g_assert_no_error (error);
458 g_assert (cursor_fd != NULL);
459
460 cursor_glib = tracker_sparql_connection_query (connection, data->query, NULL, &error);
461
462 g_assert_no_error (error);
463 g_assert (cursor_glib != NULL);
464
465 while (tracker_sparql_cursor_next (cursor_fd, NULL, NULL) &&
466 tracker_sparql_cursor_next (cursor_glib, NULL, NULL)) {
467 g_assert_cmpstr (tracker_sparql_cursor_get_string (cursor_fd, 0, NULL),
468 ==,
469 tracker_sparql_cursor_get_string (cursor_glib, 0, NULL));
470 }
471
472 g_assert (!tracker_sparql_cursor_next (cursor_fd, NULL, NULL));
473 g_assert (!tracker_sparql_cursor_next (cursor_glib, NULL, NULL));
474
475 g_object_unref (cursor_fd);
476 g_object_unref (cursor_glib);
477 }
478
479 static void
480 test_tracker_sparql_query_iterate_async (void)
481 {
482 const gchar *query = "SELECT ?r nie:url(?r) WHERE {?r a nfo:FileDataObject}";
483 GMainLoop *main_loop;
484 AsyncData *data;
485
486 main_loop = g_main_loop_new (NULL, FALSE);
487
488 data = g_slice_new (AsyncData);
489 data->main_loop = main_loop;
490 data->query = query;
491
492 tracker_sparql_connection_query_async (connection,
493 query,
494 NULL,
495 async_query_cb,
496 data);
497
498 g_main_loop_run (main_loop);
499
500 g_slice_free (AsyncData, data);
501 g_main_loop_unref (main_loop);
502 }
503
504 static void
505 cancel_query_cb (GObject *source_object,
506 GAsyncResult *result,
507 gpointer user_data)
508 {
509 GMainLoop *main_loop = user_data;
510 GError *error = NULL;
511
512 g_main_loop_quit (main_loop);
513
514 tracker_sparql_connection_query_finish (connection, result, &error);
515
516 /* An error should be returned (cancelled!) */
517 g_assert (error);
518 }
519
520 static void
521 test_tracker_sparql_query_iterate_async_cancel (void)
522 {
523 const gchar *query = "SELECT ?r nie:url(?r) WHERE {?r a nfo:FileDataObject}";
524 GMainLoop *main_loop;
525 GCancellable *cancellable = g_cancellable_new ();
526
527 main_loop = g_main_loop_new (NULL, FALSE);
528
529 tracker_sparql_connection_query_async (connection,
530 query,
531 cancellable,
532 cancel_query_cb,
533 main_loop);
534
535 g_cancellable_cancel (cancellable);
536
537 g_main_loop_run (main_loop);
538
539 g_main_loop_unref (main_loop);
540 }
541
542 static void
543 async_update_callback (GObject *source_object,
544 GAsyncResult *result,
545 gpointer user_data)
546 {
547 AsyncData *data = user_data;
548 GError *error = NULL;
549
550 tracker_sparql_connection_update_finish (connection, result, &error);
551
552 g_assert_no_error (error);
553
554 g_main_loop_quit (data->main_loop);
555 }
556
557 static void
558 test_tracker_sparql_update_async (void)
559 {
560 const gchar *query = "INSERT { _:x a nmo:Message }";
561 GMainLoop *main_loop;
562 AsyncData *data;
563
564 main_loop = g_main_loop_new (NULL, FALSE);
565
566 data = g_slice_new (AsyncData);
567 data->main_loop = main_loop;
568
569 tracker_sparql_connection_update_async (connection,
570 query,
571 0,
572 NULL,
573 async_update_callback,
574 data);
575
576 g_main_loop_run (main_loop);
577
578 g_slice_free (AsyncData, data);
579 g_main_loop_unref (main_loop);
580 }
581
582 static void
583 cancel_update_cb (GObject *source_object,
584 GAsyncResult *result,
585 gpointer user_data)
586 {
587 GMainLoop *main_loop = user_data;
588 GError *error = NULL;
589
590 g_main_loop_quit (main_loop);
591
592 tracker_sparql_connection_update_finish (connection, result, &error);
593
594 /* An error should be returned (cancelled!) */
595 g_assert (error);
596 }
597
598 static void
599 test_tracker_sparql_update_async_cancel (void)
600 {
601 GCancellable *cancellable = g_cancellable_new ();
602 const gchar *query = "INSERT { _:x a nmo:Message }";
603 GMainLoop *main_loop;
604
605 main_loop = g_main_loop_new (NULL, FALSE);
606
607 tracker_sparql_connection_update_async (connection,
608 query,
609 0,
610 cancellable,
611 cancel_update_cb,
612 main_loop);
613 g_cancellable_cancel (cancellable);
614
615 g_main_loop_run (main_loop);
616
617 g_main_loop_unref (main_loop);
618 }
619
620 static void
621 async_update_blank_callback (GObject *source_object,
622 GAsyncResult *result,
623 gpointer user_data)
624 {
625 AsyncData *data = user_data;
626 GVariant *results;
627 GError *error = NULL;
628
629 g_main_loop_quit (data->main_loop);
630
631 results = tracker_sparql_connection_update_blank_finish (connection, result, &error);
632
633 g_assert_no_error (error);
634 g_assert (results != NULL);
635 }
636
637 static void
638 test_tracker_sparql_update_blank_async (void)
639 {
640 const gchar *query = "INSERT { _:x a nmo:Message }";
641 GMainLoop *main_loop;
642 AsyncData *data;
643
644 main_loop = g_main_loop_new (NULL, FALSE);
645
646 data = g_slice_new (AsyncData);
647 data->main_loop = main_loop;
648
649 tracker_sparql_connection_update_blank_async (connection,
650 query,
651 0,
652 NULL,
653 async_update_blank_callback,
654 data);
655
656 g_main_loop_run (main_loop);
657
658 g_slice_free (AsyncData, data);
659 g_main_loop_unref (main_loop);
660 }
661
662 gint
663 main (gint argc, gchar **argv)
664 {
665 g_test_init (&argc, &argv, NULL);
666
667 /* test D-Bus backend */
668 g_setenv ("TRACKER_SPARQL_BACKEND", "bus", TRUE);
669
670 connection = tracker_sparql_connection_get (NULL, NULL);
671
672 insert_test_data ();
673
674 g_test_add_func ("/steroids/tracker/tracker_sparql_query_iterate", test_tracker_sparql_query_iterate);
675 g_test_add_func ("/steroids/tracker/tracker_sparql_query_iterate_largerow", test_tracker_sparql_query_iterate_largerow);
676 g_test_add_func ("/steroids/tracker/tracker_sparql_query_iterate_error", test_tracker_sparql_query_iterate_error);
677 g_test_add_func ("/steroids/tracker/tracker_sparql_query_iterate_empty", test_tracker_sparql_query_iterate_empty);
678 g_test_add_func ("/steroids/tracker/tracker_sparql_query_iterate_sigpipe", test_tracker_sparql_query_iterate_sigpipe);
679 g_test_add_func ("/steroids/tracker/tracker_sparql_update_fast_small", test_tracker_sparql_update_fast_small);
680 g_test_add_func ("/steroids/tracker/tracker_sparql_update_fast_large", test_tracker_sparql_update_fast_large);
681 g_test_add_func ("/steroids/tracker/tracker_sparql_update_fast_error", test_tracker_sparql_update_fast_error);
682 g_test_add_func ("/steroids/tracker/tracker_sparql_update_blank_fast_small", test_tracker_sparql_update_blank_fast_small);
683 g_test_add_func ("/steroids/tracker/tracker_sparql_update_blank_fast_large", test_tracker_sparql_update_blank_fast_large);
684 g_test_add_func ("/steroids/tracker/tracker_sparql_update_blank_fast_error", test_tracker_sparql_update_blank_fast_error);
685 g_test_add_func ("/steroids/tracker/tracker_sparql_update_blank_fast_no_blanks", test_tracker_sparql_update_blank_fast_no_blanks);
686 g_test_add_func ("/steroids/tracker/tracker_batch_sparql_update_fast", test_tracker_batch_sparql_update_fast);
687 g_test_add_func ("/steroids/tracker/tracker_sparql_query_iterate_async", test_tracker_sparql_query_iterate_async);
688 g_test_add_func ("/steroids/tracker/tracker_sparql_query_iterate_async_cancel", test_tracker_sparql_query_iterate_async_cancel);
689 g_test_add_func ("/steroids/tracker/tracker_sparql_update_async", test_tracker_sparql_update_async);
690 g_test_add_func ("/steroids/tracker/tracker_sparql_update_async_cancel", test_tracker_sparql_update_async_cancel);
691 g_test_add_func ("/steroids/tracker/tracker_sparql_update_blank_async", test_tracker_sparql_update_blank_async);
692 g_test_add_func ("/steroids/tracker/tracker_sparql_update_array_async", test_tracker_sparql_update_array_async);
693
694 return g_test_run ();
695 }