Line data Source code
1 : /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 : /* test-transaction.c: Test transaction functionality
3 :
4 : Copyright (C) 2008 Stefan Walter
5 :
6 : The Gnome Keyring Library is free software; you can redistribute it and/or
7 : modify it under the terms of the GNU Library General Public License as
8 : published by the Free Software Foundation; either version 2 of the
9 : License, or (at your option) any later version.
10 :
11 : The Gnome Keyring Library is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : Library General Public License for more details.
15 :
16 : You should have received a copy of the GNU Library General Public
17 : License along with the Gnome Library; see the file COPYING.LIB. If not,
18 : <http://www.gnu.org/licenses/>.
19 :
20 : Author: Stef Walter <stef@memberwebs.com>
21 : */
22 :
23 : #include "config.h"
24 :
25 : #include "gkm/gkm-transaction.h"
26 :
27 : #include <glib/gstdio.h>
28 :
29 : typedef struct {
30 : int unused;
31 : } Test;
32 :
33 : static void
34 22 : setup (Test* test, gconstpointer unused)
35 : {
36 : GDir *dir;
37 : const gchar *directory;
38 : const gchar *basename;
39 : gchar *filename;
40 :
41 22 : directory = "/tmp";
42 22 : dir = g_dir_open (directory, 0, NULL);
43 22 : g_assert (dir);
44 :
45 : for (;;) {
46 247 : basename = g_dir_read_name (dir);
47 247 : if (basename == NULL)
48 22 : break;
49 225 : if (g_str_has_prefix (basename, "transaction-")) {
50 13 : filename = g_build_filename (directory, basename, NULL);
51 13 : g_unlink (filename);
52 13 : g_free (filename);
53 : }
54 : }
55 :
56 22 : g_dir_close (dir);
57 22 : }
58 :
59 : static void
60 22 : teardown (Test *test, gconstpointer unused)
61 : {
62 :
63 22 : }
64 :
65 : static void
66 1 : test_transaction_empty (Test* test, gconstpointer unused)
67 : {
68 : GkmTransaction *transaction;
69 : gboolean completed, failed;
70 : CK_RV result;
71 :
72 1 : transaction = gkm_transaction_new ();
73 1 : g_assert (GKM_IS_TRANSACTION (transaction));
74 :
75 1 : g_assert (gkm_transaction_get_failed (transaction) == FALSE);
76 1 : g_assert (gkm_transaction_get_completed (transaction) == FALSE);
77 1 : g_assert (gkm_transaction_get_result (transaction) == CKR_OK);
78 :
79 1 : gkm_transaction_complete (transaction);
80 :
81 : /* Make sure values are actually set */
82 1 : result = (CK_RV)-1;
83 1 : completed = failed = FALSE;
84 :
85 1 : g_object_get (transaction, "completed", &completed, "failed", &failed, "result", &result, NULL);
86 1 : g_assert (result == CKR_OK);
87 1 : g_assert (completed == TRUE);
88 1 : g_assert (failed == FALSE);
89 :
90 1 : g_object_unref (transaction);
91 1 : }
92 :
93 : static void
94 1 : test_transaction_fail (Test* test, gconstpointer unused)
95 : {
96 : GkmTransaction *transaction;
97 :
98 1 : transaction = gkm_transaction_new ();
99 :
100 1 : gkm_transaction_fail (transaction, CKR_ARGUMENTS_BAD);
101 :
102 1 : g_assert (gkm_transaction_get_failed (transaction) == TRUE);
103 1 : g_assert (gkm_transaction_get_completed (transaction) == FALSE);
104 1 : g_assert (gkm_transaction_get_result (transaction) == CKR_ARGUMENTS_BAD);
105 :
106 1 : gkm_transaction_complete (transaction);
107 :
108 1 : g_assert (gkm_transaction_get_failed (transaction) == TRUE);
109 1 : g_assert (gkm_transaction_get_completed (transaction) == TRUE);
110 1 : g_assert (gkm_transaction_get_result (transaction) == CKR_ARGUMENTS_BAD);
111 :
112 1 : g_object_unref (transaction);
113 1 : }
114 :
115 :
116 : static gboolean
117 3 : completed_signal (GkmTransaction *transaction, gpointer data)
118 : {
119 3 : g_assert (GKM_IS_TRANSACTION (transaction));
120 3 : g_assert (data);
121 :
122 3 : *((guint*)data) = TRUE;
123 3 : return TRUE;
124 : }
125 :
126 : static gboolean
127 2 : completed_callback (GkmTransaction *transaction, GObject *object, gpointer data)
128 : {
129 2 : g_assert (GKM_IS_TRANSACTION (transaction));
130 2 : g_assert (data);
131 :
132 : /* In this case we set the object to the transaction for fun */
133 2 : g_assert (GKM_IS_TRANSACTION (transaction));
134 2 : g_assert (transaction == GKM_TRANSACTION (object));
135 :
136 2 : *((guint*)data) = gkm_transaction_get_failed (transaction);
137 2 : return TRUE;
138 : }
139 :
140 : static void
141 1 : test_transaction_signals_success (Test* test, gconstpointer unused)
142 : {
143 1 : GkmTransaction *transaction = gkm_transaction_new ();
144 :
145 : /* Initialize with some invalid values */
146 1 : guint completed = 3;
147 1 : guint failed = 3;
148 :
149 1 : g_signal_connect (transaction, "complete", G_CALLBACK (completed_signal), &completed);
150 1 : gkm_transaction_add (transaction, transaction, completed_callback, &failed);
151 :
152 : /* No callbacks called yet */
153 1 : g_assert (completed == 3);
154 1 : g_assert (failed == 3);
155 :
156 1 : gkm_transaction_complete (transaction);
157 :
158 1 : g_assert (completed == TRUE);
159 1 : g_assert (failed == FALSE);
160 :
161 1 : g_object_unref (transaction);
162 1 : }
163 :
164 : static void
165 1 : test_transaction_signals_failure (Test* test, gconstpointer unused)
166 : {
167 1 : GkmTransaction *transaction = gkm_transaction_new ();
168 :
169 : /* Initialize with some invalid values */
170 1 : guint completed = 3;
171 1 : guint failed = 3;
172 :
173 1 : g_signal_connect (transaction, "complete", G_CALLBACK (completed_signal), &completed);
174 1 : gkm_transaction_add (transaction, transaction, completed_callback, &failed);
175 :
176 1 : gkm_transaction_fail (transaction, CKR_ARGUMENTS_BAD);
177 :
178 : /* No callbacks called yet */
179 1 : g_assert (completed == 3);
180 1 : g_assert (failed == 3);
181 :
182 1 : gkm_transaction_complete (transaction);
183 :
184 1 : g_assert (completed == TRUE);
185 1 : g_assert (failed == TRUE);
186 :
187 1 : g_object_unref (transaction);
188 1 : }
189 :
190 : static guint order_value = 3;
191 :
192 : static gboolean
193 3 : order_callback (GkmTransaction *transaction, GObject *object, gpointer data)
194 : {
195 3 : g_assert (GKM_IS_TRANSACTION (transaction));
196 3 : g_assert (data);
197 3 : g_assert (GPOINTER_TO_UINT (data) == order_value);
198 3 : --order_value;
199 3 : return TRUE;
200 : }
201 :
202 : static void
203 1 : test_transaction_order_is_reverse (Test* test, gconstpointer unused)
204 : {
205 1 : GkmTransaction *transaction = gkm_transaction_new ();
206 :
207 1 : order_value = 3;
208 1 : gkm_transaction_add (transaction, transaction, order_callback, GUINT_TO_POINTER (1));
209 1 : gkm_transaction_add (transaction, transaction, order_callback, GUINT_TO_POINTER (2));
210 1 : gkm_transaction_add (transaction, transaction, order_callback, GUINT_TO_POINTER (3));
211 :
212 1 : gkm_transaction_complete (transaction);
213 1 : g_object_unref (transaction);
214 1 : }
215 :
216 : static void
217 1 : test_transaction_dispose_completes (Test* test, gconstpointer unused)
218 : {
219 1 : GkmTransaction *transaction = gkm_transaction_new ();
220 :
221 : /* Initialize with some invalid values */
222 1 : guint completed = 3;
223 :
224 1 : g_signal_connect (transaction, "complete", G_CALLBACK (completed_signal), &completed);
225 :
226 1 : g_object_run_dispose (G_OBJECT (transaction));
227 :
228 1 : g_assert (completed == TRUE);
229 :
230 1 : g_object_unref (transaction);
231 1 : }
232 :
233 : static void
234 1 : test_remove_file_success (Test* test, gconstpointer unused)
235 : {
236 1 : GkmTransaction *transaction = gkm_transaction_new ();
237 1 : const gchar *filename = "/tmp/transaction-remove";
238 :
239 1 : g_assert (g_file_set_contents (filename, "xxx", 3, NULL));
240 1 : g_assert (g_file_test (filename, G_FILE_TEST_IS_REGULAR));
241 :
242 1 : gkm_transaction_remove_file (transaction, filename);
243 1 : g_assert (!gkm_transaction_get_failed (transaction));
244 :
245 1 : g_assert (!g_file_test (filename, G_FILE_TEST_IS_REGULAR));
246 :
247 1 : gkm_transaction_complete (transaction);
248 1 : g_assert (!g_file_test (filename, G_FILE_TEST_IS_REGULAR));
249 :
250 1 : g_object_unref (transaction);
251 1 : }
252 :
253 : static void
254 1 : test_remove_file_abort (Test* test, gconstpointer unused)
255 : {
256 1 : GkmTransaction *transaction = gkm_transaction_new ();
257 1 : const gchar *filename = "/tmp/transaction-remove";
258 : gchar *data;
259 : gsize n_data;
260 :
261 1 : g_assert (g_file_set_contents (filename, "xxx", 3, NULL));
262 1 : g_assert (g_file_test (filename, G_FILE_TEST_IS_REGULAR));
263 :
264 1 : gkm_transaction_remove_file (transaction, filename);
265 1 : g_assert (!gkm_transaction_get_failed (transaction));
266 :
267 1 : g_assert (!g_file_test (filename, G_FILE_TEST_IS_REGULAR));
268 :
269 : /* Fail the transaction */
270 1 : gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
271 :
272 1 : gkm_transaction_complete (transaction);
273 1 : g_assert (gkm_transaction_get_failed (transaction));
274 1 : g_assert (g_file_test (filename, G_FILE_TEST_IS_REGULAR));
275 :
276 1 : g_assert (g_file_get_contents (filename, &data, &n_data, NULL));
277 1 : g_assert_cmpuint (n_data, ==, 3);
278 1 : g_assert_cmpstr (data, ==, "xxx");
279 1 : g_free (data);
280 :
281 1 : g_unlink (filename);
282 1 : g_object_unref (transaction);
283 1 : }
284 :
285 : static void
286 1 : test_remove_file_non_exist (Test* test, gconstpointer unused)
287 : {
288 1 : GkmTransaction *transaction = gkm_transaction_new ();
289 1 : const gchar *filename = "/tmp/transaction-non-existant";
290 :
291 1 : g_unlink (filename);
292 :
293 : /* Should succeed even though not exist */
294 1 : gkm_transaction_remove_file (transaction, filename);
295 1 : g_assert (!gkm_transaction_get_failed (transaction));
296 :
297 1 : gkm_transaction_complete (transaction);
298 1 : g_object_unref (transaction);
299 1 : }
300 :
301 : static void
302 2 : do_test_write_file (Test* test)
303 : {
304 2 : GkmTransaction *transaction = gkm_transaction_new ();
305 2 : const gchar *filename = "/tmp/transaction-test";
306 : gchar *data;
307 : gsize n_data;
308 :
309 2 : gkm_transaction_write_file (transaction, filename, (const guchar*)"value", 5);
310 2 : g_assert (!gkm_transaction_get_failed (transaction));
311 :
312 2 : g_assert (g_file_get_contents (filename, &data, &n_data, NULL));
313 2 : g_assert_cmpuint (n_data, ==, 5);
314 2 : g_assert_cmpstr (data, ==, "value");
315 2 : g_free (data);
316 :
317 2 : gkm_transaction_complete (transaction);
318 :
319 2 : g_assert (g_file_get_contents (filename, &data, &n_data, NULL));
320 2 : g_assert_cmpuint (n_data, ==, 5);
321 2 : g_assert_cmpstr (data, ==, "value");
322 2 : g_free (data);
323 :
324 2 : g_object_unref (transaction);
325 2 : }
326 :
327 : static void
328 1 : test_write_file (Test* test, gconstpointer unused)
329 : {
330 : /* Run it two times so that that the second one works on an
331 : existing file "/tmp/transaction-test". */
332 1 : do_test_write_file (test);
333 1 : do_test_write_file (test);
334 1 : }
335 :
336 : static void
337 7 : test_write_large_file (Test* test, gconstpointer test_data)
338 : {
339 7 : guint buffersize = GPOINTER_TO_UINT (test_data);
340 7 : GkmTransaction *transaction = gkm_transaction_new ();
341 7 : const gchar *filename = "/tmp/transaction-test";
342 : gchar *data;
343 : gsize n_data;
344 : guchar *buffer;
345 : int i;
346 :
347 7 : buffer = g_malloc (buffersize);
348 :
349 5591 : for (i=0; i < buffersize; i++)
350 5584 : buffer[i] = i;
351 :
352 7 : gkm_transaction_write_file (transaction, filename,
353 : buffer, buffersize);
354 7 : g_assert (!gkm_transaction_get_failed (transaction));
355 :
356 7 : g_assert (g_file_get_contents (filename, &data, &n_data, NULL));
357 7 : g_assert_cmpuint (n_data, ==, buffersize);
358 5591 : for (i=0; i < buffersize; i++)
359 5584 : g_assert_cmpuint (buffer[i], ==, ((guchar*)data)[i]);
360 7 : g_free (data);
361 :
362 7 : gkm_transaction_complete (transaction);
363 :
364 7 : g_assert (g_file_get_contents (filename, &data, &n_data, NULL));
365 7 : g_assert_cmpuint (n_data, ==, buffersize);
366 5591 : for (i=0; i < buffersize; i++)
367 5584 : g_assert_cmpuint (buffer[i], ==, ((guchar*)data)[i]);
368 7 : g_free (data);
369 :
370 7 : g_object_unref (transaction);
371 :
372 7 : g_free (buffer);
373 7 : }
374 :
375 :
376 : static void
377 2 : do_test_write_file_abort_gone (Test* test)
378 : {
379 2 : GkmTransaction *transaction = gkm_transaction_new ();
380 2 : const gchar *filename = "/tmp/transaction-test";
381 : gchar *data;
382 : gsize n_data;
383 :
384 2 : g_unlink (filename);
385 :
386 2 : gkm_transaction_write_file (transaction, filename, (const guchar*)"value", 5);
387 2 : g_assert (!gkm_transaction_get_failed (transaction));
388 :
389 2 : g_assert (g_file_get_contents (filename, &data, &n_data, NULL));
390 2 : g_assert_cmpuint (n_data, ==, 5);
391 2 : g_assert_cmpstr (data, ==, "value");
392 2 : g_free (data);
393 :
394 2 : gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
395 2 : gkm_transaction_complete (transaction);
396 :
397 2 : g_assert (!g_file_test (filename, G_FILE_TEST_IS_REGULAR));
398 :
399 2 : g_object_unref (transaction);
400 2 : }
401 :
402 : static void
403 1 : test_write_file_abort_gone (Test* test, gconstpointer unused)
404 : {
405 1 : do_test_write_file_abort_gone (test);
406 1 : do_test_write_file_abort_gone (test);
407 1 : }
408 :
409 : static void
410 2 : do_test_write_file_abort_revert (Test* test)
411 : {
412 2 : GkmTransaction *transaction = gkm_transaction_new ();
413 2 : const gchar *filename = "/tmp/transaction-test";
414 : gchar *data;
415 :
416 2 : g_assert (g_file_set_contents (filename, "my original", -1, NULL));
417 :
418 2 : gkm_transaction_write_file (transaction, filename, (const guchar*)"new value", 9);
419 2 : g_assert (!gkm_transaction_get_failed (transaction));
420 :
421 2 : g_assert (g_file_get_contents (filename, &data, NULL, NULL));
422 2 : g_assert_cmpstr (data, ==, "new value");
423 2 : g_free (data);
424 :
425 2 : gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
426 2 : gkm_transaction_complete (transaction);
427 :
428 2 : g_assert (g_file_get_contents (filename, &data, NULL, NULL));
429 2 : g_assert_cmpstr (data, ==, "my original");
430 2 : g_free (data);
431 :
432 2 : g_object_unref (transaction);
433 2 : }
434 :
435 : static void
436 1 : test_write_file_abort_revert (Test* test, gconstpointer unused)
437 : {
438 1 : do_test_write_file_abort_revert (test);
439 1 : do_test_write_file_abort_revert (test);
440 1 : }
441 :
442 : static void
443 1 : test_unique_file_conflict (Test* test, gconstpointer unused)
444 : {
445 1 : GkmTransaction *transaction = gkm_transaction_new ();
446 1 : const gchar *filename = "/tmp/transaction-test";
447 : gchar *dirname;
448 : gchar *basename;
449 : gchar *result;
450 :
451 1 : dirname = g_path_get_dirname (filename);
452 1 : basename = g_path_get_basename (filename);
453 :
454 1 : g_assert (g_file_set_contents (filename, "data", -1, NULL));
455 :
456 1 : result = gkm_transaction_unique_file (transaction, dirname, basename);
457 1 : g_assert (!gkm_transaction_get_failed (transaction));
458 :
459 1 : g_assert (result);
460 1 : g_assert_cmpstr (result, !=, basename);
461 1 : g_assert_cmpstr (result, ==, "transaction-test_1");
462 :
463 1 : g_free (dirname);
464 1 : g_free (basename);
465 1 : g_free (result);
466 :
467 1 : g_object_unref (transaction);
468 1 : }
469 :
470 : static void
471 1 : test_unique_file_conflict_with_ext (Test* test, gconstpointer unused)
472 : {
473 1 : GkmTransaction *transaction = gkm_transaction_new ();
474 1 : const gchar *filename = "/tmp/transaction-test.ext";
475 : gchar *dirname;
476 : gchar *basename;
477 : gchar *result;
478 :
479 1 : dirname = g_path_get_dirname (filename);
480 1 : basename = g_path_get_basename (filename);
481 :
482 1 : g_assert (g_file_set_contents (filename, "data", -1, NULL));
483 :
484 1 : result = gkm_transaction_unique_file (transaction, dirname, basename);
485 1 : g_assert (!gkm_transaction_get_failed (transaction));
486 :
487 1 : g_assert (result);
488 1 : g_assert_cmpstr (result, !=, basename);
489 1 : g_assert_cmpstr (result, ==, "transaction-test_1.ext");
490 :
491 1 : g_free (dirname);
492 1 : g_free (basename);
493 1 : g_free (result);
494 :
495 1 : g_object_unref (transaction);
496 1 : }
497 :
498 : static void
499 1 : test_unique_file_no_conflict (Test* test, gconstpointer unused)
500 : {
501 1 : GkmTransaction *transaction = gkm_transaction_new ();
502 1 : const gchar *dirname = "/tmp";
503 : gchar *result;
504 :
505 1 : result = gkm_transaction_unique_file (transaction, dirname, "transaction-another");
506 1 : g_assert (!gkm_transaction_get_failed (transaction));
507 :
508 1 : g_assert (result);
509 1 : g_assert_cmpstr (result, ==, "transaction-another");
510 :
511 1 : g_free (result);
512 :
513 1 : g_object_unref (transaction);
514 1 : }
515 :
516 : int
517 1 : main (int argc, char **argv)
518 : {
519 : #if !GLIB_CHECK_VERSION(2,35,0)
520 : g_type_init ();
521 : #endif
522 1 : g_test_init (&argc, &argv, NULL);
523 :
524 1 : g_test_add ("/gkm/transaction/transaction_empty", Test, NULL, setup, test_transaction_empty, teardown);
525 1 : g_test_add ("/gkm/transaction/transaction_fail", Test, NULL, setup, test_transaction_fail, teardown);
526 1 : g_test_add ("/gkm/transaction/transaction_signals_success", Test, NULL, setup, test_transaction_signals_success, teardown);
527 1 : g_test_add ("/gkm/transaction/transaction_signals_failure", Test, NULL, setup, test_transaction_signals_failure, teardown);
528 1 : g_test_add ("/gkm/transaction/transaction_order_is_reverse", Test, NULL, setup, test_transaction_order_is_reverse, teardown);
529 1 : g_test_add ("/gkm/transaction/transaction_dispose_completes", Test, NULL, setup, test_transaction_dispose_completes, teardown);
530 1 : g_test_add ("/gkm/transaction/remove_file_success", Test, NULL, setup, test_remove_file_success, teardown);
531 1 : g_test_add ("/gkm/transaction/remove_file_abort", Test, NULL, setup, test_remove_file_abort, teardown);
532 1 : g_test_add ("/gkm/transaction/remove_file_non_exist", Test, NULL, setup, test_remove_file_non_exist, teardown);
533 1 : g_test_add ("/gkm/transaction/write_file", Test, NULL, setup, test_write_file, teardown);
534 :
535 : {
536 : /* Several test runs at different sizes. Note that
537 : the copy function, used if hardlinks do not work,
538 : uses a 512 byte buffer. */
539 1 : guint buffersizes[] = {
540 : 2000, 1024, 510, 511, 512, 513, 514, 0
541 : };
542 : int i;
543 :
544 : gchar test_name[39];
545 8 : for (i = 0; buffersizes[i]; i++)
546 : {
547 7 : g_sprintf (test_name, "/gkm/transaction/write_large_file_%u", buffersizes[i]);
548 7 : g_test_add (test_name, Test, GUINT_TO_POINTER (buffersizes[i]),
549 : setup, test_write_large_file, teardown);
550 : }
551 : }
552 :
553 1 : g_test_add ("/gkm/transaction/write_file_abort_gone", Test, NULL, setup, test_write_file_abort_gone, teardown);
554 1 : g_test_add ("/gkm/transaction/write_file_abort_revert", Test, NULL, setup, test_write_file_abort_revert, teardown);
555 1 : g_test_add ("/gkm/transaction/unique_file_conflict", Test, NULL, setup, test_unique_file_conflict, teardown);
556 1 : g_test_add ("/gkm/transaction/unique_file_conflict_with_ext", Test, NULL, setup, test_unique_file_conflict_with_ext, teardown);
557 1 : g_test_add ("/gkm/transaction/unique_file_no_conflict", Test, NULL, setup, test_unique_file_no_conflict, teardown);
558 :
559 1 : return g_test_run ();
560 : }
|