gtestutils: deprecate g_test_trap_fork()
[platform/upstream/glib.git] / gio / tests / tls-interaction.c
1 /* GLib testing framework examples and tests
2  *
3  * Copyright (C) 2011 Collabora Ltd.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: Stef Walter <stefw@collobora.co.uk>
21  */
22
23 #include "config.h"
24
25 #include <gio/gio.h>
26
27 typedef struct {
28   /* Class virtual interaction methods */
29   gpointer ask_password_func;
30   gpointer ask_password_async_func;
31   gpointer ask_password_finish_func;
32
33   /* Expected results */
34   GTlsInteractionResult result;
35   GQuark error_domain;
36   gint error_code;
37   const gchar *error_message;
38 } Fixture;
39
40 typedef struct {
41   GTlsInteraction *interaction;
42   GTlsPassword *password;
43   GMainLoop *loop;
44   GThread *interaction_thread;
45   GThread *test_thread;
46   GThread *loop_thread;
47   const Fixture *fixture;
48 } Test;
49
50 typedef struct {
51   GTlsInteraction parent;
52   Test *test;
53 } TestInteraction;
54
55 typedef struct {
56   GTlsInteractionClass parent;
57 } TestInteractionClass;
58
59 static GType test_interaction_get_type (void);
60 G_DEFINE_TYPE (TestInteraction, test_interaction, G_TYPE_TLS_INTERACTION);
61
62 #define TEST_TYPE_INTERACTION         (test_interaction_get_type ())
63 #define TEST_INTERACTION(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), TEST_TYPE_INTERACTION, TestInteraction))
64 #define TEST_IS_INTERACTION(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), TEST_TYPE_INTERACTION))
65
66 static void
67 test_interaction_init (TestInteraction *self)
68 {
69
70 }
71
72 static void
73 test_interaction_class_init (TestInteractionClass *klass)
74 {
75   /* By default no virtual methods */
76 }
77
78 static void
79 test_interaction_ask_password_async_success (GTlsInteraction    *interaction,
80                                              GTlsPassword       *password,
81                                              GCancellable       *cancellable,
82                                              GAsyncReadyCallback callback,
83                                              gpointer            user_data)
84 {
85   GTask *task;
86   TestInteraction *self;
87
88   g_assert (TEST_IS_INTERACTION (interaction));
89   self = TEST_INTERACTION (interaction);
90
91   g_assert (g_thread_self () == self->test->interaction_thread);
92
93   g_assert (G_IS_TLS_PASSWORD (password));
94   g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
95
96   task = g_task_new (self, cancellable, callback, user_data);
97
98   /* Don't do this in real life. Include a null terminator for testing */
99   g_tls_password_set_value (password, (const guchar *)"the password", 13);
100   g_task_return_int (task, G_TLS_INTERACTION_HANDLED);
101   g_object_unref (task);
102 }
103
104
105 static GTlsInteractionResult
106 test_interaction_ask_password_finish_success (GTlsInteraction    *interaction,
107                                               GAsyncResult       *result,
108                                               GError            **error)
109 {
110   TestInteraction *self;
111
112   g_assert (TEST_IS_INTERACTION (interaction));
113   self = TEST_INTERACTION (interaction);
114
115   g_assert (g_thread_self () == self->test->interaction_thread);
116
117   g_assert (g_task_is_valid (result, interaction));
118   g_assert (error != NULL);
119   g_assert (*error == NULL);
120
121   return g_task_propagate_int (G_TASK (result), error);
122 }
123
124 static void
125 test_interaction_ask_password_async_failure (GTlsInteraction    *interaction,
126                                              GTlsPassword       *password,
127                                              GCancellable       *cancellable,
128                                              GAsyncReadyCallback callback,
129                                              gpointer            user_data)
130 {
131   GTask *task;
132   TestInteraction *self;
133
134   g_assert (TEST_IS_INTERACTION (interaction));
135   self = TEST_INTERACTION (interaction);
136
137   g_assert (g_thread_self () == self->test->interaction_thread);
138
139   g_assert (G_IS_TLS_PASSWORD (password));
140   g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
141
142   task = g_task_new (self, cancellable, callback, user_data);
143
144   g_task_return_new_error (task, G_FILE_ERROR, G_FILE_ERROR_ACCES, "The message");
145   g_object_unref (task);
146 }
147
148 static GTlsInteractionResult
149 test_interaction_ask_password_finish_failure (GTlsInteraction    *interaction,
150                                               GAsyncResult       *result,
151                                               GError            **error)
152 {
153   TestInteraction *self;
154
155   g_assert (TEST_IS_INTERACTION (interaction));
156   self = TEST_INTERACTION (interaction);
157
158   g_assert (g_thread_self () == self->test->interaction_thread);
159
160   g_assert (g_task_is_valid (result, interaction));
161   g_assert (error != NULL);
162   g_assert (*error == NULL);
163
164   if (g_task_propagate_int (G_TASK (result), error) != -1)
165     g_assert_not_reached ();
166
167   return G_TLS_INTERACTION_FAILED;
168 }
169
170
171 static GTlsInteractionResult
172 test_interaction_ask_password_sync_success (GTlsInteraction    *interaction,
173                                             GTlsPassword       *password,
174                                             GCancellable       *cancellable,
175                                             GError            **error)
176 {
177   TestInteraction *self;
178
179   g_assert (TEST_IS_INTERACTION (interaction));
180   self = TEST_INTERACTION (interaction);
181
182   g_assert (g_thread_self () == self->test->interaction_thread);
183
184   g_assert (G_IS_TLS_PASSWORD (password));
185   g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
186   g_assert (error != NULL);
187   g_assert (*error == NULL);
188
189   /* Don't do this in real life. Include a null terminator for testing */
190   g_tls_password_set_value (password, (const guchar *)"the password", 13);
191   return G_TLS_INTERACTION_HANDLED;
192 }
193
194 static GTlsInteractionResult
195 test_interaction_ask_password_sync_failure (GTlsInteraction    *interaction,
196                                             GTlsPassword       *password,
197                                             GCancellable       *cancellable,
198                                             GError            **error)
199 {
200   TestInteraction *self;
201
202   g_assert (TEST_IS_INTERACTION (interaction));
203   self = TEST_INTERACTION (interaction);
204
205   g_assert (g_thread_self () == self->test->interaction_thread);
206
207   g_assert (G_IS_TLS_PASSWORD (password));
208   g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
209   g_assert (error != NULL);
210   g_assert (*error == NULL);
211
212   g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_ACCES, "The message");
213   return G_TLS_INTERACTION_FAILED;
214 }
215
216 /* ----------------------------------------------------------------------------
217  * ACTUAL TESTS
218  */
219
220 static void
221 on_ask_password_async_call (GObject      *source,
222                             GAsyncResult *result,
223                             gpointer      user_data)
224 {
225   Test *test = user_data;
226   GTlsInteractionResult res;
227   GError *error = NULL;
228
229   g_assert (G_IS_TLS_INTERACTION (source));
230   g_assert (G_TLS_INTERACTION (source) == test->interaction);
231
232   /* Check that this callback is being run in the right place */
233   g_assert (g_thread_self () == test->interaction_thread);
234
235   res = g_tls_interaction_ask_password_finish (test->interaction, result,
236                                                &error);
237
238   /* Check that the results match the fixture */
239   g_assert_cmpuint (test->fixture->result, ==, res);
240   switch (test->fixture->result)
241     {
242       case G_TLS_INTERACTION_HANDLED:
243         g_assert_no_error (error);
244         g_assert_cmpstr ((const gchar *)g_tls_password_get_value (test->password, NULL), ==, "the password");
245         break;
246       case G_TLS_INTERACTION_FAILED:
247         g_assert_error (error, test->fixture->error_domain, test->fixture->error_code);
248         g_assert_cmpstr (error->message, ==, test->fixture->error_message);
249         g_clear_error (&error);
250         break;
251       case G_TLS_INTERACTION_UNHANDLED:
252         g_assert_no_error (error);
253         break;
254       default:
255         g_assert_not_reached ();
256     }
257
258   /* Signal the end of the test */
259   g_main_loop_quit (test->loop);
260 }
261
262 static void
263 test_ask_password_async (Test            *test,
264                          gconstpointer    unused)
265 {
266   /* This test only works with a main loop */
267   g_assert (test->loop);
268
269   g_tls_interaction_ask_password_async (test->interaction,
270                                         test->password, NULL,
271                                         on_ask_password_async_call,
272                                         test);
273
274   /* teardown waits until g_main_loop_quit(). called from callback */
275 }
276
277 static void
278 test_invoke_ask_password (Test         *test,
279                           gconstpointer unused)
280 {
281   GTlsInteractionResult res;
282   GError *error = NULL;
283
284   res = g_tls_interaction_invoke_ask_password (test->interaction, test->password,
285                                                NULL, &error);
286
287   /* Check that the results match the fixture */
288   g_assert_cmpuint (test->fixture->result, ==, res);
289   switch (test->fixture->result)
290     {
291       case G_TLS_INTERACTION_HANDLED:
292         g_assert_no_error (error);
293         g_assert_cmpstr ((const gchar *)g_tls_password_get_value (test->password, NULL), ==, "the password");
294         break;
295       case G_TLS_INTERACTION_FAILED:
296         g_assert_error (error, test->fixture->error_domain, test->fixture->error_code);
297         g_assert_cmpstr (error->message, ==, test->fixture->error_message);
298         g_clear_error (&error);
299         break;
300       case G_TLS_INTERACTION_UNHANDLED:
301         g_assert_no_error (error);
302         break;
303       default:
304         g_assert_not_reached ();
305     }
306
307   /* This allows teardown to stop if running with loop */
308   if (test->loop)
309     g_main_loop_quit (test->loop);
310 }
311
312 static void
313 test_ask_password (Test         *test,
314                    gconstpointer unused)
315 {
316   GTlsInteractionResult res;
317   GError *error = NULL;
318
319   res = g_tls_interaction_ask_password (test->interaction, test->password,
320                                         NULL, &error);
321
322   /* Check that the results match the fixture */
323   g_assert_cmpuint (test->fixture->result, ==, res);
324   switch (test->fixture->result)
325     {
326       case G_TLS_INTERACTION_HANDLED:
327         g_assert_no_error (error);
328         g_assert_cmpstr ((const gchar *)g_tls_password_get_value (test->password, NULL), ==, "the password");
329         break;
330       case G_TLS_INTERACTION_FAILED:
331         g_assert_error (error, test->fixture->error_domain, test->fixture->error_code);
332         g_assert_cmpstr (error->message, ==, test->fixture->error_message);
333         g_clear_error (&error);
334         break;
335       case G_TLS_INTERACTION_UNHANDLED:
336         g_assert_no_error (error);
337         break;
338       default:
339         g_assert_not_reached ();
340     }
341
342   /* This allows teardown to stop if running with loop */
343   if (test->loop)
344     g_main_loop_quit (test->loop);
345 }
346
347 /* ----------------------------------------------------------------------------
348  * TEST SETUP
349  */
350
351 static void
352 setup_without_loop (Test           *test,
353                     gconstpointer   user_data)
354 {
355   const Fixture *fixture = user_data;
356   GTlsInteractionClass *klass;
357   test->fixture = fixture;
358
359   test->interaction = g_object_new (TEST_TYPE_INTERACTION, NULL);
360   g_assert (TEST_IS_INTERACTION (test->interaction));
361
362   TEST_INTERACTION (test->interaction)->test = test;
363
364   klass =  G_TLS_INTERACTION_GET_CLASS (test->interaction);
365   klass->ask_password = fixture->ask_password_func;
366   klass->ask_password_async = fixture->ask_password_async_func;
367   klass->ask_password_finish = fixture->ask_password_finish_func;
368
369   test->password = g_tls_password_new (0, "Description");
370   test->test_thread = g_thread_self ();
371
372   /*
373    * If no loop is running then interaction should happen in the same
374    * thread that the tests are running in.
375    */
376   test->interaction_thread = test->test_thread;
377 }
378
379 static void
380 teardown_without_loop (Test            *test,
381                        gconstpointer    unused)
382 {
383   gpointer weak_pointer = test->interaction;
384
385   g_object_add_weak_pointer (weak_pointer, &weak_pointer);
386
387   g_object_unref (test->password);
388
389   g_object_unref (test->interaction);
390
391   g_assert (weak_pointer == NULL);
392
393 }
394
395 typedef struct {
396   GMutex loop_mutex;
397   GCond loop_started;
398   gboolean started;
399   Test *test;
400 } ThreadLoop;
401
402 static gpointer
403 thread_loop (gpointer user_data)
404 {
405   GMainContext *context = g_main_context_default ();
406   ThreadLoop *closure = user_data;
407   Test *test = closure->test;
408
409   g_mutex_lock (&closure->loop_mutex);
410
411   g_assert (test->loop_thread == g_thread_self ());
412   g_assert (test->loop == NULL);
413   test->loop = g_main_loop_new (context, TRUE);
414
415   g_main_context_acquire (context);
416   closure->started = TRUE;
417   g_cond_signal (&closure->loop_started);
418   g_mutex_unlock (&closure->loop_mutex);
419
420   while (g_main_loop_is_running (test->loop))
421     g_main_context_iteration (context, TRUE);
422
423   g_main_context_release (context);
424   return test;
425 }
426
427 static void
428 setup_with_thread_loop (Test            *test,
429                         gconstpointer    user_data)
430 {
431   ThreadLoop closure;
432
433   setup_without_loop (test, user_data);
434
435   g_mutex_init (&closure.loop_mutex);
436   g_cond_init (&closure.loop_started);
437   closure.started = FALSE;
438   closure.test = test;
439
440   g_mutex_lock (&closure.loop_mutex);
441   test->loop_thread = g_thread_new ("loop", thread_loop, &closure);
442   while (!closure.started)
443     g_cond_wait (&closure.loop_started, &closure.loop_mutex);
444   g_mutex_unlock (&closure.loop_mutex);
445
446   /*
447    * When a loop is running then interaction should always occur in the main
448    * context of that loop.
449    */
450   test->interaction_thread = test->loop_thread;
451
452   g_mutex_clear (&closure.loop_mutex);
453   g_cond_clear (&closure.loop_started);
454 }
455
456 static void
457 teardown_with_thread_loop (Test            *test,
458                            gconstpointer    unused)
459 {
460   gpointer check;
461
462   g_assert (test->loop_thread);
463   check = g_thread_join (test->loop_thread);
464   g_assert (check == test);
465   test->loop_thread = NULL;
466
467   g_main_loop_unref (test->loop);
468
469   teardown_without_loop (test, unused);
470 }
471
472 static void
473 setup_with_normal_loop (Test            *test,
474                         gconstpointer    user_data)
475 {
476   GMainContext *context;
477
478   setup_without_loop (test, user_data);
479
480   context = g_main_context_default ();
481   if (!g_main_context_acquire (context))
482     g_assert_not_reached ();
483
484   test->loop = g_main_loop_new (context, TRUE);
485   g_assert (g_main_loop_is_running (test->loop));
486 }
487
488 static void
489 teardown_with_normal_loop (Test            *test,
490                            gconstpointer    unused)
491 {
492   GMainContext *context;
493
494   context = g_main_context_default ();
495   while (g_main_loop_is_running (test->loop))
496     g_main_context_iteration (context, TRUE);
497
498   g_main_context_release (context);
499
500   /* Run test until complete */
501   g_main_loop_unref (test->loop);
502   test->loop = NULL;
503
504   teardown_without_loop (test, unused);
505 }
506
507 typedef void (*TestFunc) (Test *test, gconstpointer data);
508
509 static void
510 test_with_async_ask_password_implementations (const gchar *name,
511                                               TestFunc     setup,
512                                               TestFunc     func,
513                                               TestFunc     teardown,
514                                               GPtrArray   *fixtures)
515 {
516   gchar *test_name;
517   Fixture *fixture;
518
519   /* Async implementation that succeeds */
520   fixture = g_new0 (Fixture, 1);
521   fixture->ask_password_async_func = test_interaction_ask_password_async_success;
522   fixture->ask_password_finish_func = test_interaction_ask_password_finish_success;
523   fixture->ask_password_func = NULL;
524   fixture->result = G_TLS_INTERACTION_HANDLED;
525   test_name = g_strdup_printf ("%s/async-implementation-success", name);
526   g_test_add (test_name, Test, fixture, setup, func, teardown);
527   g_free (test_name);
528   g_ptr_array_add (fixtures, fixture);
529
530   /* Async implementation that fails */
531   fixture = g_new0 (Fixture, 1);
532   fixture->ask_password_async_func = test_interaction_ask_password_async_failure;
533   fixture->ask_password_finish_func = test_interaction_ask_password_finish_failure;
534   fixture->ask_password_func = NULL;
535   fixture->result = G_TLS_INTERACTION_FAILED;
536   fixture->error_domain = G_FILE_ERROR;
537   fixture->error_code = G_FILE_ERROR_ACCES;
538   fixture->error_message = "The message";
539   test_name = g_strdup_printf ("%s/async-implementation-failure", name);
540   g_test_add (test_name, Test, fixture, setup, func, teardown);
541   g_free (test_name);
542   g_ptr_array_add (fixtures, fixture);
543 }
544 static void
545 test_with_unhandled_ask_password_implementations (const gchar *name,
546                                                   TestFunc     setup,
547                                                   TestFunc     func,
548                                                   TestFunc     teardown,
549                                                   GPtrArray   *fixtures)
550 {
551   gchar *test_name;
552   Fixture *fixture;
553
554   /* Unhandled implementation */
555   fixture = g_new0 (Fixture, 1);
556   fixture->ask_password_async_func = NULL;
557   fixture->ask_password_finish_func = NULL;
558   fixture->ask_password_func = NULL;
559   fixture->result = G_TLS_INTERACTION_UNHANDLED;
560   test_name = g_strdup_printf ("%s/unhandled-implementation", name);
561   g_test_add (test_name, Test, fixture, setup, func, teardown);
562   g_free (test_name);
563   g_ptr_array_add (fixtures, fixture);
564 }
565
566 static void
567 test_with_sync_ask_password_implementations (const gchar *name,
568                                              TestFunc     setup,
569                                              TestFunc     func,
570                                              TestFunc     teardown,
571                                              GPtrArray   *fixtures)
572 {
573   gchar *test_name;
574   Fixture *fixture;
575
576   /* Sync implementation that succeeds */
577   fixture = g_new0 (Fixture, 1);
578   fixture->ask_password_async_func = NULL;
579   fixture->ask_password_finish_func = NULL;
580   fixture->ask_password_func = test_interaction_ask_password_sync_success;
581   fixture->result = G_TLS_INTERACTION_HANDLED;
582   test_name = g_strdup_printf ("%s/sync-implementation-success", name);
583   g_test_add (test_name, Test, fixture, setup, func, teardown);
584   g_free (test_name);
585   g_ptr_array_add (fixtures, fixture);
586
587   /* Async implementation that fails */
588   fixture = g_new0 (Fixture, 1);
589   fixture->ask_password_async_func = NULL;
590   fixture->ask_password_finish_func = NULL;
591   fixture->ask_password_func = test_interaction_ask_password_sync_failure;
592   fixture->result = G_TLS_INTERACTION_FAILED;
593   fixture->error_domain = G_FILE_ERROR;
594   fixture->error_code = G_FILE_ERROR_ACCES;
595   fixture->error_message = "The message";
596   test_name = g_strdup_printf ("%s/sync-implementation-failure", name);
597   g_test_add (test_name, Test, fixture, setup, func, teardown);
598   g_free (test_name);
599   g_ptr_array_add (fixtures, fixture);
600 }
601
602 int
603 main (int   argc,
604       char *argv[])
605 {
606   GPtrArray *fixtures;
607   gint ret;
608
609   g_test_init (&argc, &argv, NULL);
610
611   fixtures = g_ptr_array_new_with_free_func (g_free);
612
613   /* Tests for g_tls_interaction_invoke_ask_password */
614
615   test_with_unhandled_ask_password_implementations ("/tls-interaction/ask-password/invoke-with-loop",
616                                                     setup_with_thread_loop, test_invoke_ask_password,
617                                                     teardown_with_thread_loop, fixtures);
618   test_with_async_ask_password_implementations ("/tls-interaction/ask-password/invoke-with-loop",
619                                                 setup_with_thread_loop, test_invoke_ask_password,
620                                                 teardown_with_thread_loop, fixtures);
621   test_with_sync_ask_password_implementations ("/tls-interaction/ask-password/invoke-with-loop",
622                                                setup_with_thread_loop, test_invoke_ask_password,
623                                                teardown_with_thread_loop, fixtures);
624
625   test_with_unhandled_ask_password_implementations ("/tls-interaction/ask-password/invoke-without-loop",
626                                                     setup_without_loop, test_invoke_ask_password,
627                                                     teardown_without_loop, fixtures);
628   test_with_async_ask_password_implementations ("/tls-interaction/ask-password/invoke-without-loop",
629                                                 setup_without_loop, test_invoke_ask_password,
630                                                 teardown_without_loop, fixtures);
631   test_with_sync_ask_password_implementations ("/tls-interaction/ask-password/invoke-without-loop",
632                                                setup_without_loop, test_invoke_ask_password,
633                                                teardown_without_loop, fixtures);
634
635   test_with_unhandled_ask_password_implementations ("/tls-interaction/ask-password/invoke-in-loop",
636                                                     setup_with_normal_loop, test_invoke_ask_password,
637                                                     teardown_with_normal_loop, fixtures);
638   test_with_async_ask_password_implementations ("/tls-interaction/ask-password/invoke-in-loop",
639                                                 setup_with_normal_loop, test_invoke_ask_password,
640                                                 teardown_with_normal_loop, fixtures);
641   test_with_sync_ask_password_implementations ("/tls-interaction/ask-password/invoke-in-loop",
642                                                setup_with_normal_loop, test_invoke_ask_password,
643                                                teardown_with_normal_loop, fixtures);
644
645   /* Tests for g_tls_interaction_ask_password */
646   test_with_unhandled_ask_password_implementations ("/tls-interaction/ask-password/sync",
647                                                     setup_without_loop, test_ask_password,
648                                                     teardown_without_loop, fixtures);
649   test_with_sync_ask_password_implementations ("/tls-interaction/ask-password/sync",
650                                                setup_without_loop, test_ask_password,
651                                                teardown_without_loop, fixtures);
652
653   /* Tests for g_tls_interaction_ask_password_async */
654   test_with_unhandled_ask_password_implementations ("/tls-interaction/ask-password/async",
655                                                     setup_with_normal_loop, test_ask_password_async,
656                                                     teardown_with_normal_loop, fixtures);
657   test_with_async_ask_password_implementations ("/tls-interaction/ask-password/async",
658                                                 setup_with_normal_loop, test_ask_password_async,
659                                                 teardown_with_normal_loop, fixtures);
660
661   ret = g_test_run();
662   g_ptr_array_free (fixtures, TRUE);
663   return ret;
664 }