No issues found
1 /*
2 * Copyright (C) 2010, Nokia <ivan.frade@nokia.com>
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 <libtracker-sparql/tracker-sparql.h>
23
24 typedef struct {
25 const gchar *input ;
26 const gchar *output;
27 } ESCAPE_TEST_DATA;
28
29 ESCAPE_TEST_DATA test_data [] = {
30 { "SELECT \"a\"", "SELECT \\\"a\\\"" },
31 { "SELECT ?u \t \n \r \b \f", "SELECT ?u \\t \\n \\r \\b \\f" },
32 { NULL, NULL }
33 };
34
35 /* Used for the cursor_next_async test */
36 static TrackerSparqlConnection *connection;
37 static GMainLoop *main_loop;
38
39 #if HAVE_TRACKER_FTS
40
41 static GCancellable *cancellables[6] = { NULL, NULL, NULL, NULL };
42
43 /* OK: query 0 with either query 4 or 5.
44 * FAIL: query 4 and 5 together (requires data to exist)
45 */
46 static const gchar *queries[6] = {
47 /* #1 */
48 "SELECT ?p WHERE { ?p tracker:indexed true }",
49 /* #2 */
50 "SELECT ?prefix ?ns WHERE { ?ns a tracker:Namespace ; tracker:prefix ?prefix }",
51 /* #3 */
52 "SELECT ?p WHERE { ?p tracker:fulltextIndexed true }",
53 /* #4 */
54 "SELECT"
55 " ?u nie:url(?u)"
56 " tracker:coalesce(nie:title(?u), nfo:fileName(?u), \"Unknown\")"
57 " nfo:fileLastModified(?u)"
58 " nfo:fileSize(?u)"
59 " nie:url(?c) "
60 "WHERE { "
61 " ?u fts:match \"love\" . "
62 " ?u nfo:belongsToContainer ?c ; "
63 " tracker:available true . "
64 "} "
65 "ORDER BY DESC(fts:rank(?u)) "
66 "OFFSET 0 LIMIT 100",
67 /* #5 */
68 "SELECT"
69 " ?song"
70 " nie:url(?song)"
71 " tracker:coalesce(nie:title(?song), nfo:fileName(?song), \"Unknown\")"
72 " fn:string-join((?performer, ?album), \" - \")"
73 " nfo:duration(?song)"
74 " ?tooltip "
75 "WHERE {"
76 " ?match fts:match \"love\""
77 " {"
78 " ?song nmm:musicAlbum ?match"
79 " } UNION {"
80 " ?song nmm:performer ?match"
81 " } UNION {"
82 " ?song a nfo:Audio ."
83 " ?match a nfo:Audio"
84 " FILTER (?song = ?match)"
85 " }"
86 " ?song nmm:performer [ nmm:artistName ?performer ] ;"
87 " nmm:musicAlbum [ nie:title ?album ] ;"
88 " nfo:belongsToContainer [ nie:url ?tooltip ]"
89 "} "
90 "ORDER BY DESC(fts:rank(?song)) DESC(nie:title(?song)) "
91 "OFFSET 0 LIMIT 100",
92 NULL
93 };
94
95 #endif /* HAVE_TRACKER_FTS */
96
97 static void
98 test_tracker_sparql_escape_string (void)
99 {
100 gint i;
101 gchar *result;
102
103 for (i = 0; test_data[i].input != NULL; i++) {
104 result = tracker_sparql_escape_string (test_data[i].input);
105 g_assert_cmpstr (result, ==, test_data[i].output);
106 g_free (result);
107 }
108 }
109
110 static void
111 test_tracker_sparql_escape_uri_vprintf (void)
112 {
113 gchar *result;
114
115 result = tracker_sparql_escape_uri_printf ("test:uri:contact-%d", 14, NULL);
116 g_assert_cmpstr (result, ==, "test:uri:contact-14");
117 g_free (result);
118 }
119
120 #if HAVE_TRACKER_FTS
121
122 static void test_tracker_sparql_cursor_next_async_query (gint query);
123
124 static void
125 test_tracker_sparql_cursor_next_async_cb (GObject *source,
126 GAsyncResult *result,
127 gpointer user_data)
128 {
129 TrackerSparqlCursor *cursor;
130 GError *error = NULL;
131 gboolean success;
132 static gint finished = 0;
133 static gint next = 0;
134 gint next_to_cancel = 1;
135 gint query;
136
137 query = GPOINTER_TO_INT(user_data);
138
139 g_assert (result != NULL);
140 success = tracker_sparql_cursor_next_finish (TRACKER_SPARQL_CURSOR (source),
141 result,
142 &error);
143
144 if (finished == 1 && next == next_to_cancel) {
145 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
146 g_print ("Got Cancellation GError\n");
147 } else {
148 g_assert_no_error (error);
149 }
150
151 cursor = TRACKER_SPARQL_CURSOR (source);
152 g_assert (cursor != NULL);
153
154 g_print (" %d: %s\n",
155 query,
156 tracker_sparql_cursor_get_string (cursor, 0, NULL));
157
158 if (!success) {
159 finished++;
160 next = 0;
161
162 g_print ("Finished %d\n", finished);
163
164 if (finished == 1 || finished == 2) {
165 test_tracker_sparql_cursor_next_async_query (finished);
166 } else if (finished == 3) {
167 g_main_loop_quit (main_loop);
168 }
169 } else {
170 tracker_sparql_cursor_next_async (cursor,
171 cancellables[query],
172 test_tracker_sparql_cursor_next_async_cb,
173 user_data);
174
175 next++;
176
177 /* Random number here for next_count_to_cancel is "2",
178 * just want to do this mid-cursor iteration
179 */
180 if (next == next_to_cancel && finished == 1) {
181 /* Cancel */
182 g_print ("Cancelling cancellable:%p at count:%d\n",
183 cancellables[query],
184 next);
185 g_cancellable_cancel (cancellables[query]);
186 }
187 }
188 }
189
190 static void
191 test_tracker_sparql_cursor_next_async_query (gint query)
192 {
193 TrackerSparqlCursor *cursor;
194 GError *error = NULL;
195
196 g_print ("ASYNC query %d starting:\n", query);
197
198 cancellables[query] = g_cancellable_new ();
199 g_assert (cancellables[query] != NULL);
200
201 cursor = tracker_sparql_connection_query (connection,
202 queries[query],
203 NULL,
204 &error);
205 g_assert_no_error (error);
206 g_assert (cursor != NULL);
207
208 tracker_sparql_cursor_next_async (cursor,
209 cancellables[query],
210 test_tracker_sparql_cursor_next_async_cb,
211 GINT_TO_POINTER(query));
212 }
213
214 static void
215 test_tracker_sparql_cursor_next_async (void)
216 {
217 GError *error = NULL;
218
219 /* So, the idea here:
220 * 1. Test async cursor_next() call.
221 * 2. Make sure we can cancel a cursor_next() call and start a new query (was failing)
222 * 3. Handle multiple async queries + async cursor_next() calls.
223 */
224
225 if (G_UNLIKELY (connection == NULL)) {
226 connection = tracker_sparql_connection_get (NULL, &error);
227 g_assert_no_error (error);
228 g_assert (connection != NULL);
229 }
230
231 test_tracker_sparql_cursor_next_async_query (0);
232 }
233
234 #endif /* HAVE_TRACKER_FTS */
235
236 static void
237 test_tracker_sparql_connection_locking_sync (void)
238 {
239 TrackerSparqlConnection *c1, *c2, *c3;
240
241 c1 = tracker_sparql_connection_get (NULL, NULL);
242 c2 = tracker_sparql_connection_get (NULL, NULL);
243 c3 = tracker_sparql_connection_get (NULL, NULL);
244 g_assert (c1 == c2);
245 g_assert (c2 == c3);
246
247 g_object_unref (c1);
248 g_object_unref (c2);
249 g_object_unref (c3);
250 }
251
252 static TrackerSparqlConnection *c1 = NULL;
253 static TrackerSparqlConnection *c2 = NULL;
254 static TrackerSparqlConnection *c3 = NULL;
255
256 static void
257 test_tracker_sparql_connection_locking_async_cb (GObject *source,
258 GAsyncResult *result,
259 gpointer user_data)
260 {
261 TrackerSparqlConnection *connection;
262 TrackerSparqlConnection *connection_waiting;
263 GError *error = NULL;
264
265 g_assert (result != NULL);
266 connection = tracker_sparql_connection_get_finish (result, &error);
267 g_assert_no_error (error);
268 g_assert (connection != NULL);
269
270 if (!c1) {
271 g_print ("GOT connection #1, waiting connection:%p (expecting NULL)\n", user_data);
272 c1 = connection;
273 } else if (!c2) {
274 g_print ("GOT connection #2, waiting connection:%p (expecting NULL)\n", user_data);
275 c2 = connection;
276 }
277
278 connection_waiting = user_data;
279 g_assert (connection_waiting == NULL);
280 }
281
282 static void
283 test_tracker_sparql_connection_locking_async (void)
284 {
285 tracker_sparql_connection_get_async (NULL, test_tracker_sparql_connection_locking_async_cb, c2);
286 tracker_sparql_connection_get_async (NULL, test_tracker_sparql_connection_locking_async_cb, c3);
287 c3 = tracker_sparql_connection_get (NULL, NULL);
288 g_assert (c3 != NULL);
289 }
290
291 static void
292 test_tracker_sparql_nb237150_cb (GObject *source_object,
293 GAsyncResult *result,
294 gpointer user_data)
295 {
296 /* Not actually worried about this being called */
297 g_print ("Called back for #%d\n", GPOINTER_TO_INT(user_data));
298 }
299
300 static void
301 test_tracker_sparql_nb237150 (void)
302 {
303 /* Test NB#237150 - Second tracker_sparql_connection_get_async never returns */
304 if (g_test_trap_fork (G_USEC_PER_SEC * 2, G_TEST_TRAP_SILENCE_STDOUT)) {
305 g_print ("\n");
306 g_print ("Calling #1 - tracker_sparql_connection_get_async()\n");
307 tracker_sparql_connection_get_async (NULL, test_tracker_sparql_nb237150_cb, GINT_TO_POINTER(1));
308
309 g_print ("Calling #2 - tracker_sparql_connection_get_async()\n");
310 tracker_sparql_connection_get_async (NULL, test_tracker_sparql_nb237150_cb, GINT_TO_POINTER(2));
311
312 g_print ("Calling both finished\n");
313
314 exit (0); /* successful test run */
315 }
316
317 g_test_trap_assert_passed ();
318 g_test_trap_assert_stdout ("*Calling #1*");
319 g_test_trap_assert_stdout ("*Calling #2*");
320 g_test_trap_assert_stdout ("*Calling both finished*");
321 }
322
323 static void
324 test_tracker_sparql_connection_interleaved (void)
325 {
326 GError *error = NULL;
327
328 TrackerSparqlCursor *cursor1;
329 TrackerSparqlCursor *cursor2;
330 TrackerSparqlConnection *connection;
331
332 const gchar* query = "select ?u {?u a rdfs:Resource .}";
333
334 connection = tracker_sparql_connection_get (NULL, &error);
335 g_assert_no_error (error);
336
337 cursor1 = tracker_sparql_connection_query (connection, query, 0, &error);
338 g_assert_no_error (error);
339
340 /* intentionally not freeing cursor1 here */
341 g_object_unref(connection);
342
343 connection = tracker_sparql_connection_get (NULL, &error);
344 g_assert_no_error (error);
345
346 cursor2 = tracker_sparql_connection_query (connection, query, 0, &error);
347 g_assert_no_error (error);
348
349 g_object_unref(connection);
350
351 g_object_unref(cursor2);
352 g_object_unref(cursor1);
353 }
354
355 gint
356 main (gint argc, gchar **argv)
357 {
358 int result;
359
360 g_test_init (&argc, &argv, NULL);
361
362 #if HAVE_TRACKER_FTS
363 main_loop = g_main_loop_new (NULL, FALSE);
364 g_assert (main_loop != NULL);
365 #endif
366
367 /* NOTE: this first test must come BEFORE any others because
368 * connections are cached by libtracker-sparql.
369 */
370 g_test_add_func ("/libtracker-sparql/tracker/test_tracker_sparql_nb237150",
371 test_tracker_sparql_nb237150);
372 g_test_add_func ("/libtracker-sparql/tracker/tracker_sparql_escape_string",
373 test_tracker_sparql_escape_string);
374 g_test_add_func ("/libtracker-sparql/tracker/tracker_sparql_escape_uri_vprintf",
375 test_tracker_sparql_escape_uri_vprintf);
376 g_test_add_func ("/libtracker-sparql/tracker/tracker_sparql_connection_interleaved",
377 test_tracker_sparql_connection_interleaved);
378 g_test_add_func ("/libtracker-sparql/tracker/tracker_sparql_connection_locking_sync",
379 test_tracker_sparql_connection_locking_sync);
380 g_test_add_func ("/libtracker-sparql/tracker/tracker_sparql_connection_locking_async",
381 test_tracker_sparql_connection_locking_async);
382
383 #if HAVE_TRACKER_FTS
384 g_test_add_func ("/libtracker-sparql/tracker/tracker_sparql_cursor_next_async",
385 test_tracker_sparql_cursor_next_async);
386 #endif
387
388 result = g_test_run ();
389
390 #if HAVE_TRACKER_FTS
391 g_main_loop_run (main_loop);
392
393 if (connection) {
394 g_object_unref (connection);
395 }
396 #endif
397
398 return result;
399 }