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