gio/tests/tls-interaction: fix two sporadic errors
[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   Test *test;
397 } ThreadLoop;
398
399 static gpointer
400 thread_loop (gpointer user_data)
401 {
402   GMainContext *context = g_main_context_default ();
403   ThreadLoop *closure = user_data;
404   Test *test = closure->test;
405
406   g_mutex_lock (closure->loop_mutex);
407
408   g_assert (test->loop_thread == g_thread_self ());
409   g_assert (test->loop == NULL);
410   test->loop = g_main_loop_new (context, TRUE);
411
412   g_main_context_acquire (context);
413   g_cond_signal (closure->loop_started);
414   g_mutex_unlock (closure->loop_mutex);
415
416   while (g_main_loop_is_running (test->loop))
417     g_main_context_iteration (context, TRUE);
418
419   g_main_context_release (context);
420   return test;
421 }
422
423 static void
424 setup_with_thread_loop (Test            *test,
425                         gconstpointer    user_data)
426 {
427   GError *error = NULL;
428   ThreadLoop closure;
429
430   setup_without_loop (test, user_data);
431
432   closure.loop_mutex = g_mutex_new ();
433   closure.loop_started = g_cond_new ();
434   closure.test = test;
435
436   g_mutex_lock (closure.loop_mutex);
437   test->loop_thread = g_thread_create (thread_loop, &closure, TRUE, &error);
438   g_cond_wait (closure.loop_started, closure.loop_mutex);
439   g_mutex_unlock (closure.loop_mutex);
440
441   /*
442    * When a loop is running then interaction should always occur in the main
443    * context of that loop.
444    */
445   test->interaction_thread = test->loop_thread;
446
447   g_mutex_free (closure.loop_mutex);
448   g_cond_free (closure.loop_started);
449 }
450
451 static void
452 teardown_with_thread_loop (Test            *test,
453                            gconstpointer    unused)
454 {
455   gpointer check;
456
457   g_assert (test->loop_thread);
458   check = g_thread_join (test->loop_thread);
459   g_assert (check == test);
460   test->loop_thread = NULL;
461
462   g_main_loop_unref (test->loop);
463
464   teardown_without_loop (test, unused);
465 }
466
467 static void
468 setup_with_normal_loop (Test            *test,
469                         gconstpointer    user_data)
470 {
471   GMainContext *context;
472
473   setup_without_loop (test, user_data);
474
475   context = g_main_context_default ();
476   if (!g_main_context_acquire (context))
477     g_assert_not_reached ();
478
479   test->loop = g_main_loop_new (context, TRUE);
480   g_assert (g_main_loop_is_running (test->loop));
481 }
482
483 static void
484 teardown_with_normal_loop (Test            *test,
485                            gconstpointer    unused)
486 {
487   GMainContext *context;
488
489   context = g_main_context_default ();
490   while (g_main_loop_is_running (test->loop))
491     g_main_context_iteration (context, TRUE);
492
493   g_main_context_release (context);
494
495   /* Run test until complete */
496   g_main_loop_unref (test->loop);
497   test->loop = NULL;
498
499   teardown_without_loop (test, unused);
500 }
501
502 typedef void (*TestFunc) (Test *test, gconstpointer data);
503
504 static void
505 test_with_async_ask_password_implementations (const gchar *name,
506                                               TestFunc     setup,
507                                               TestFunc     func,
508                                               TestFunc     teardown,
509                                               GPtrArray   *fixtures)
510 {
511   gchar *test_name;
512   Fixture *fixture;
513
514   /* Async implementation that succeeds */
515   fixture = g_new0 (Fixture, 1);
516   fixture->ask_password_async_func = test_interaction_ask_password_async_success;
517   fixture->ask_password_finish_func = test_interaction_ask_password_finish_success;
518   fixture->ask_password_func = NULL;
519   fixture->result = G_TLS_INTERACTION_HANDLED;
520   test_name = g_strdup_printf ("%s/async-implementation-success", name);
521   g_test_add (test_name, Test, fixture, setup, func, teardown);
522   g_free (test_name);
523   g_ptr_array_add (fixtures, fixture);
524
525   /* Async implementation that fails */
526   fixture = g_new0 (Fixture, 1);
527   fixture->ask_password_async_func = test_interaction_ask_password_async_failure;
528   fixture->ask_password_finish_func = test_interaction_ask_password_finish_failure;
529   fixture->ask_password_func = NULL;
530   fixture->result = G_TLS_INTERACTION_FAILED;
531   fixture->error_domain = G_FILE_ERROR;
532   fixture->error_code = G_FILE_ERROR_ACCES;
533   fixture->error_message = "The message";
534   test_name = g_strdup_printf ("%s/async-implementation-failure", name);
535   g_test_add (test_name, Test, fixture, setup, func, teardown);
536   g_free (test_name);
537   g_ptr_array_add (fixtures, fixture);
538 }
539 static void
540 test_with_unhandled_ask_password_implementations (const gchar *name,
541                                                   TestFunc     setup,
542                                                   TestFunc     func,
543                                                   TestFunc     teardown,
544                                                   GPtrArray   *fixtures)
545 {
546   gchar *test_name;
547   Fixture *fixture;
548
549   /* Unhandled implementation */
550   fixture = g_new0 (Fixture, 1);
551   fixture->ask_password_async_func = NULL;
552   fixture->ask_password_finish_func = NULL;
553   fixture->ask_password_func = NULL;
554   fixture->result = G_TLS_INTERACTION_UNHANDLED;
555   test_name = g_strdup_printf ("%s/unhandled-implementation", name);
556   g_test_add (test_name, Test, fixture, setup, func, teardown);
557   g_free (test_name);
558   g_ptr_array_add (fixtures, fixture);
559 }
560
561 static void
562 test_with_sync_ask_password_implementations (const gchar *name,
563                                              TestFunc     setup,
564                                              TestFunc     func,
565                                              TestFunc     teardown,
566                                              GPtrArray   *fixtures)
567 {
568   gchar *test_name;
569   Fixture *fixture;
570
571   /* Sync implementation that succeeds */
572   fixture = g_new0 (Fixture, 1);
573   fixture->ask_password_async_func = NULL;
574   fixture->ask_password_finish_func = NULL;
575   fixture->ask_password_func = test_interaction_ask_password_sync_success;
576   fixture->result = G_TLS_INTERACTION_HANDLED;
577   test_name = g_strdup_printf ("%s/sync-implementation-success", name);
578   g_test_add (test_name, Test, fixture, setup, func, teardown);
579   g_free (test_name);
580   g_ptr_array_add (fixtures, fixture);
581
582   /* Async implementation that fails */
583   fixture = g_new0 (Fixture, 1);
584   fixture->ask_password_async_func = NULL;
585   fixture->ask_password_finish_func = NULL;
586   fixture->ask_password_func = test_interaction_ask_password_sync_failure;
587   fixture->result = G_TLS_INTERACTION_FAILED;
588   fixture->error_domain = G_FILE_ERROR;
589   fixture->error_code = G_FILE_ERROR_ACCES;
590   fixture->error_message = "The message";
591   test_name = g_strdup_printf ("%s/sync-implementation-failure", name);
592   g_test_add (test_name, Test, fixture, setup, func, teardown);
593   g_free (test_name);
594   g_ptr_array_add (fixtures, fixture);
595 }
596
597 int
598 main (int   argc,
599       char *argv[])
600 {
601   GPtrArray *fixtures;
602   gint ret;
603
604   g_type_init ();
605   g_thread_init (NULL);
606   g_test_init (&argc, &argv, NULL);
607
608   fixtures = g_ptr_array_new_with_free_func (g_free);
609
610   /* Tests for g_tls_interaction_invoke_ask_password */
611
612   test_with_unhandled_ask_password_implementations ("/tls-interaction/ask-password/invoke-with-loop",
613                                                     setup_with_thread_loop, test_invoke_ask_password,
614                                                     teardown_with_thread_loop, fixtures);
615   test_with_async_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_sync_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
622   test_with_unhandled_ask_password_implementations ("/tls-interaction/ask-password/invoke-without-loop",
623                                                     setup_without_loop, test_invoke_ask_password,
624                                                     teardown_without_loop, fixtures);
625   test_with_async_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_sync_ask_password_implementations ("/tls-interaction/ask-password/invoke-without-loop",
629                                                setup_without_loop, test_invoke_ask_password,
630                                                teardown_without_loop, fixtures);
631
632   test_with_unhandled_ask_password_implementations ("/tls-interaction/ask-password/invoke-in-loop",
633                                                     setup_with_normal_loop, test_invoke_ask_password,
634                                                     teardown_with_normal_loop, fixtures);
635   test_with_async_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_sync_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
642   /* Tests for g_tls_interaction_ask_password */
643   test_with_unhandled_ask_password_implementations ("/tls-interaction/ask-password/sync",
644                                                     setup_without_loop, test_ask_password,
645                                                     teardown_without_loop, fixtures);
646   test_with_sync_ask_password_implementations ("/tls-interaction/ask-password/sync",
647                                                setup_without_loop, test_ask_password,
648                                                teardown_without_loop, fixtures);
649
650   /* Tests for g_tls_interaction_ask_password_async */
651   test_with_unhandled_ask_password_implementations ("/tls-interaction/ask-password/async",
652                                                     setup_with_normal_loop, test_ask_password_async,
653                                                     teardown_with_normal_loop, fixtures);
654   test_with_async_ask_password_implementations ("/tls-interaction/ask-password/async",
655                                                 setup_with_normal_loop, test_ask_password_async,
656                                                 teardown_with_normal_loop, fixtures);
657
658   ret = g_test_run();
659   g_ptr_array_free (fixtures, TRUE);
660   return ret;
661 }