gkdbus: Fix underflow and unreachable code bug
[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  * SPDX-License-Identifier: LGPL-2.1-or-later
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General
18  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  *
20  * Author: Stef Walter <stefw@collobora.co.uk>
21  */
22
23 #include "config.h"
24
25 #include <gio/gio.h>
26
27 #include "gtesttlsbackend.h"
28
29 static GPtrArray *fixtures = NULL;
30
31 typedef struct {
32   /* Class virtual interaction methods */
33   gpointer ask_password_func;
34   gpointer ask_password_async_func;
35   gpointer ask_password_finish_func;
36   gpointer request_certificate_func;
37   gpointer request_certificate_async_func;
38   gpointer request_certificate_finish_func;
39
40   /* Expected results */
41   GTlsInteractionResult result;
42   GQuark error_domain;
43   gint error_code;
44   const gchar *error_message;
45 } Fixture;
46
47 typedef struct {
48   GTlsInteraction *interaction;
49   GTlsPassword *password;
50   GTlsConnection *connection;
51   GMainLoop *loop;
52   GThread *interaction_thread;
53   GThread *test_thread;
54   GThread *loop_thread;
55   const Fixture *fixture;
56 } Test;
57
58 typedef struct {
59   GTlsInteraction parent;
60   Test *test;
61 } TestInteraction;
62
63 typedef struct {
64   GTlsInteractionClass parent;
65 } TestInteractionClass;
66
67 static GType test_interaction_get_type (void);
68 G_DEFINE_TYPE (TestInteraction, test_interaction, G_TYPE_TLS_INTERACTION)
69
70 #define TEST_TYPE_INTERACTION         (test_interaction_get_type ())
71 #define TEST_INTERACTION(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), TEST_TYPE_INTERACTION, TestInteraction))
72 #define TEST_IS_INTERACTION(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), TEST_TYPE_INTERACTION))
73
74 static void
75 test_interaction_init (TestInteraction *self)
76 {
77
78 }
79
80 static void
81 test_interaction_class_init (TestInteractionClass *klass)
82 {
83   /* By default no virtual methods */
84 }
85
86 static void
87 test_interaction_ask_password_async_success (GTlsInteraction    *interaction,
88                                              GTlsPassword       *password,
89                                              GCancellable       *cancellable,
90                                              GAsyncReadyCallback callback,
91                                              gpointer            user_data)
92 {
93   GTask *task;
94   TestInteraction *self;
95
96   g_assert (TEST_IS_INTERACTION (interaction));
97   self = TEST_INTERACTION (interaction);
98
99   g_assert (g_thread_self () == self->test->interaction_thread);
100
101   g_assert (G_IS_TLS_PASSWORD (password));
102   g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
103
104   task = g_task_new (self, cancellable, callback, user_data);
105
106   /* Don't do this in real life. Include a null terminator for testing */
107   g_tls_password_set_value (password, (const guchar *)"the password", 13);
108   g_task_return_int (task, G_TLS_INTERACTION_HANDLED);
109   g_object_unref (task);
110 }
111
112
113 static GTlsInteractionResult
114 test_interaction_ask_password_finish_success (GTlsInteraction    *interaction,
115                                               GAsyncResult       *result,
116                                               GError            **error)
117 {
118   TestInteraction *self;
119
120   g_assert (TEST_IS_INTERACTION (interaction));
121   self = TEST_INTERACTION (interaction);
122
123   g_assert (g_thread_self () == self->test->interaction_thread);
124
125   g_assert (g_task_is_valid (result, interaction));
126   g_assert (error != NULL);
127   g_assert (*error == NULL);
128
129   return g_task_propagate_int (G_TASK (result), error);
130 }
131
132 static void
133 test_interaction_ask_password_async_failure (GTlsInteraction    *interaction,
134                                              GTlsPassword       *password,
135                                              GCancellable       *cancellable,
136                                              GAsyncReadyCallback callback,
137                                              gpointer            user_data)
138 {
139   GTask *task;
140   TestInteraction *self;
141
142   g_assert (TEST_IS_INTERACTION (interaction));
143   self = TEST_INTERACTION (interaction);
144
145   g_assert (g_thread_self () == self->test->interaction_thread);
146
147   g_assert (G_IS_TLS_PASSWORD (password));
148   g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
149
150   task = g_task_new (self, cancellable, callback, user_data);
151
152   g_task_return_new_error (task, G_FILE_ERROR, G_FILE_ERROR_ACCES, "The message");
153   g_object_unref (task);
154 }
155
156 static GTlsInteractionResult
157 test_interaction_ask_password_finish_failure (GTlsInteraction    *interaction,
158                                               GAsyncResult       *result,
159                                               GError            **error)
160 {
161   TestInteraction *self;
162
163   g_assert (TEST_IS_INTERACTION (interaction));
164   self = TEST_INTERACTION (interaction);
165
166   g_assert (g_thread_self () == self->test->interaction_thread);
167
168   g_assert (g_task_is_valid (result, interaction));
169   g_assert (error != NULL);
170   g_assert (*error == NULL);
171
172   if (g_task_propagate_int (G_TASK (result), error) != -1)
173     g_assert_not_reached ();
174
175   return G_TLS_INTERACTION_FAILED;
176 }
177
178
179 /* Return a copy of @str that is allocated in a silly way, to exercise
180  * custom free-functions. The returned pointer points to a copy of @str
181  * in a buffer of the form "BEFORE \0 str \0 AFTER". */
182 static guchar *
183 special_dup (const char *str)
184 {
185   GString *buf = g_string_new ("BEFORE");
186   guchar *ret;
187
188   g_string_append_c (buf, '\0');
189   g_string_append (buf, str);
190   g_string_append_c (buf, '\0');
191   g_string_append (buf, "AFTER");
192   ret = (guchar *) g_string_free (buf, FALSE);
193   return ret + strlen ("BEFORE") + 1;
194 }
195
196
197 /* Free a copy of @str that was made with special_dup(), after asserting
198  * that it has not been corrupted. */
199 static void
200 special_free (gpointer p)
201 {
202   gchar *s = p;
203   gchar *buf = s - strlen ("BEFORE") - 1;
204
205   g_assert_cmpstr (buf, ==, "BEFORE");
206   g_assert_cmpstr (s + strlen (s) + 1, ==, "AFTER");
207   g_free (buf);
208 }
209
210
211 static GTlsInteractionResult
212 test_interaction_ask_password_sync_success (GTlsInteraction    *interaction,
213                                             GTlsPassword       *password,
214                                             GCancellable       *cancellable,
215                                             GError            **error)
216 {
217   TestInteraction *self;
218   const guchar *value;
219   gsize len;
220
221   g_assert (TEST_IS_INTERACTION (interaction));
222   self = TEST_INTERACTION (interaction);
223
224   g_assert (g_thread_self () == self->test->interaction_thread);
225
226   g_assert (G_IS_TLS_PASSWORD (password));
227   g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
228   g_assert (error != NULL);
229   g_assert (*error == NULL);
230
231   /* Exercise different ways to set the value */
232   g_tls_password_set_value (password, (const guchar *) "foo", 4);
233   len = 0;
234   value = g_tls_password_get_value (password, &len);
235   g_assert_cmpmem (value, len, "foo", 4);
236
237   g_tls_password_set_value (password, (const guchar *) "bar", -1);
238   len = 0;
239   value = g_tls_password_get_value (password, &len);
240   g_assert_cmpmem (value, len, "bar", 3);
241
242   g_tls_password_set_value_full (password, special_dup ("baa"), 4, special_free);
243   len = 0;
244   value = g_tls_password_get_value (password, &len);
245   g_assert_cmpmem (value, len, "baa", 4);
246
247   g_tls_password_set_value_full (password, special_dup ("baz"), -1, special_free);
248   len = 0;
249   value = g_tls_password_get_value (password, &len);
250   g_assert_cmpmem (value, len, "baz", 3);
251
252   /* Don't do this in real life. Include a null terminator for testing */
253   g_tls_password_set_value (password, (const guchar *)"the password", 13);
254   return G_TLS_INTERACTION_HANDLED;
255 }
256
257 static GTlsInteractionResult
258 test_interaction_ask_password_sync_failure (GTlsInteraction    *interaction,
259                                             GTlsPassword       *password,
260                                             GCancellable       *cancellable,
261                                             GError            **error)
262 {
263   TestInteraction *self;
264
265   g_assert (TEST_IS_INTERACTION (interaction));
266   self = TEST_INTERACTION (interaction);
267
268   g_assert (g_thread_self () == self->test->interaction_thread);
269
270   g_assert (G_IS_TLS_PASSWORD (password));
271   g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
272   g_assert (error != NULL);
273   g_assert (*error == NULL);
274
275   g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_ACCES, "The message");
276   return G_TLS_INTERACTION_FAILED;
277 }
278
279 static void
280 test_interaction_request_certificate_async_success (GTlsInteraction    *interaction,
281                                                     GTlsConnection     *connection,
282                                                     gint                unused_flags,
283                                                     GCancellable       *cancellable,
284                                                     GAsyncReadyCallback callback,
285                                                     gpointer            user_data)
286 {
287   GTask *task;
288   TestInteraction *self;
289
290   g_assert (TEST_IS_INTERACTION (interaction));
291   self = TEST_INTERACTION (interaction);
292
293   g_assert (g_thread_self () == self->test->interaction_thread);
294
295   g_assert (G_IS_TLS_CONNECTION (connection));
296   g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
297   g_assert (unused_flags == 0);
298
299   task = g_task_new (self, cancellable, callback, user_data);
300
301   /*
302    * IRL would call g_tls_connection_set_certificate(). But here just touch
303    * the connection in a detectable way.
304    */
305   g_object_set_data (G_OBJECT (connection), "chosen-certificate", "my-certificate");
306   g_task_return_int (task, G_TLS_INTERACTION_HANDLED);
307   g_object_unref (task);
308 }
309
310 static GTlsInteractionResult
311 test_interaction_request_certificate_finish_success (GTlsInteraction    *interaction,
312                                                      GAsyncResult       *result,
313                                                      GError            **error)
314 {
315   TestInteraction *self;
316
317   g_assert (TEST_IS_INTERACTION (interaction));
318   self = TEST_INTERACTION (interaction);
319
320   g_assert (g_thread_self () == self->test->interaction_thread);
321
322   g_assert (g_task_is_valid (result, interaction));
323   g_assert (error != NULL);
324   g_assert (*error == NULL);
325
326   return g_task_propagate_int (G_TASK (result), error);
327 }
328
329 static void
330 test_interaction_request_certificate_async_failure (GTlsInteraction    *interaction,
331                                                     GTlsConnection     *connection,
332                                                     gint                unused_flags,
333                                                     GCancellable       *cancellable,
334                                                     GAsyncReadyCallback callback,
335                                                     gpointer            user_data)
336 {
337   GTask *task;
338   TestInteraction *self;
339
340   g_assert (TEST_IS_INTERACTION (interaction));
341   self = TEST_INTERACTION (interaction);
342
343   g_assert (g_thread_self () == self->test->interaction_thread);
344
345   g_assert (G_IS_TLS_CONNECTION (connection));
346   g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
347   g_assert (unused_flags == 0);
348
349   task = g_task_new (self, cancellable, callback, user_data);
350
351   g_task_return_new_error (task, G_FILE_ERROR, G_FILE_ERROR_NOENT, "Another message");
352   g_object_unref (task);
353 }
354
355 static GTlsInteractionResult
356 test_interaction_request_certificate_finish_failure (GTlsInteraction    *interaction,
357                                                      GAsyncResult       *result,
358                                                      GError            **error)
359 {
360   TestInteraction *self;
361
362   g_assert (TEST_IS_INTERACTION (interaction));
363   self = TEST_INTERACTION (interaction);
364
365   g_assert (g_thread_self () == self->test->interaction_thread);
366
367   g_assert (g_task_is_valid (result, interaction));
368   g_assert (error != NULL);
369   g_assert (*error == NULL);
370
371   if (g_task_propagate_int (G_TASK (result), error) != -1)
372     g_assert_not_reached ();
373
374   return G_TLS_INTERACTION_FAILED;
375 }
376
377 static GTlsInteractionResult
378 test_interaction_request_certificate_sync_success (GTlsInteraction    *interaction,
379                                                    GTlsConnection      *connection,
380                                                    gint                 unused_flags,
381                                                    GCancellable        *cancellable,
382                                                    GError             **error)
383 {
384   TestInteraction *self;
385
386   g_assert (TEST_IS_INTERACTION (interaction));
387   self = TEST_INTERACTION (interaction);
388
389   g_assert (g_thread_self () == self->test->interaction_thread);
390
391   g_assert (G_IS_TLS_CONNECTION (connection));
392   g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
393   g_assert (error != NULL);
394   g_assert (*error == NULL);
395
396   /*
397    * IRL would call g_tls_connection_set_certificate(). But here just touch
398    * the connection in a detectable way.
399    */
400   g_object_set_data (G_OBJECT (connection), "chosen-certificate", "my-certificate");
401   return G_TLS_INTERACTION_HANDLED;
402 }
403
404 static GTlsInteractionResult
405 test_interaction_request_certificate_sync_failure (GTlsInteraction    *interaction,
406                                                    GTlsConnection     *connection,
407                                                    gint                unused_flags,
408                                                    GCancellable       *cancellable,
409                                                    GError            **error)
410 {
411   TestInteraction *self;
412
413   g_assert (TEST_IS_INTERACTION (interaction));
414   self = TEST_INTERACTION (interaction);
415
416   g_assert (g_thread_self () == self->test->interaction_thread);
417
418   g_assert (G_IS_TLS_CONNECTION (connection));
419   g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
420   g_assert (unused_flags == 0);
421   g_assert (error != NULL);
422   g_assert (*error == NULL);
423
424   g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOENT, "Another message");
425   return G_TLS_INTERACTION_FAILED;
426 }
427
428 /* ----------------------------------------------------------------------------
429  * ACTUAL TESTS
430  */
431
432 static void
433 on_ask_password_async_call (GObject      *source,
434                             GAsyncResult *result,
435                             gpointer      user_data)
436 {
437   Test *test = user_data;
438   GTlsInteractionResult res;
439   GError *error = NULL;
440
441   g_assert (G_IS_TLS_INTERACTION (source));
442   g_assert (G_TLS_INTERACTION (source) == test->interaction);
443
444   /* Check that this callback is being run in the right place */
445   g_assert (g_thread_self () == test->interaction_thread);
446
447   res = g_tls_interaction_ask_password_finish (test->interaction, result,
448                                                &error);
449
450   /* Check that the results match the fixture */
451   g_assert_cmpuint (test->fixture->result, ==, res);
452   switch (test->fixture->result)
453     {
454       case G_TLS_INTERACTION_HANDLED:
455         g_assert_no_error (error);
456         g_assert_cmpstr ((const gchar *)g_tls_password_get_value (test->password, NULL), ==, "the password");
457         break;
458       case G_TLS_INTERACTION_FAILED:
459         g_assert_error (error, test->fixture->error_domain, test->fixture->error_code);
460         g_assert_cmpstr (error->message, ==, test->fixture->error_message);
461         g_clear_error (&error);
462         break;
463       case G_TLS_INTERACTION_UNHANDLED:
464         g_assert_no_error (error);
465         break;
466       default:
467         g_assert_not_reached ();
468     }
469
470   /* Signal the end of the test */
471   g_main_loop_quit (test->loop);
472 }
473
474 static void
475 test_ask_password_async (Test            *test,
476                          gconstpointer    unused)
477 {
478   /* This test only works with a main loop */
479   g_assert (test->loop);
480
481   g_tls_interaction_ask_password_async (test->interaction,
482                                         test->password, NULL,
483                                         on_ask_password_async_call,
484                                         test);
485
486   /* teardown waits until g_main_loop_quit(). called from callback */
487 }
488
489 static void
490 test_invoke_ask_password (Test         *test,
491                           gconstpointer unused)
492 {
493   GTlsInteractionResult res;
494   GError *error = NULL;
495
496   res = g_tls_interaction_invoke_ask_password (test->interaction, test->password,
497                                                NULL, &error);
498
499   /* Check that the results match the fixture */
500   g_assert_cmpuint (test->fixture->result, ==, res);
501   switch (test->fixture->result)
502     {
503       case G_TLS_INTERACTION_HANDLED:
504         g_assert_no_error (error);
505         g_assert_cmpstr ((const gchar *)g_tls_password_get_value (test->password, NULL), ==, "the password");
506         break;
507       case G_TLS_INTERACTION_FAILED:
508         g_assert_error (error, test->fixture->error_domain, test->fixture->error_code);
509         g_assert_cmpstr (error->message, ==, test->fixture->error_message);
510         g_clear_error (&error);
511         break;
512       case G_TLS_INTERACTION_UNHANDLED:
513         g_assert_no_error (error);
514         break;
515       default:
516         g_assert_not_reached ();
517     }
518
519   /* This allows teardown to stop if running with loop */
520   if (test->loop)
521     g_main_loop_quit (test->loop);
522 }
523
524 static void
525 test_ask_password (Test         *test,
526                    gconstpointer unused)
527 {
528   GTlsInteractionResult res;
529   GError *error = NULL;
530
531   res = g_tls_interaction_ask_password (test->interaction, test->password,
532                                         NULL, &error);
533
534   /* Check that the results match the fixture */
535   g_assert_cmpuint (test->fixture->result, ==, res);
536   switch (test->fixture->result)
537     {
538       case G_TLS_INTERACTION_HANDLED:
539         g_assert_no_error (error);
540         g_assert_cmpstr ((const gchar *)g_tls_password_get_value (test->password, NULL), ==, "the password");
541         break;
542       case G_TLS_INTERACTION_FAILED:
543         g_assert_error (error, test->fixture->error_domain, test->fixture->error_code);
544         g_assert_cmpstr (error->message, ==, test->fixture->error_message);
545         g_clear_error (&error);
546         break;
547       case G_TLS_INTERACTION_UNHANDLED:
548         g_assert_no_error (error);
549         break;
550       default:
551         g_assert_not_reached ();
552     }
553
554   /* This allows teardown to stop if running with loop */
555   if (test->loop)
556     g_main_loop_quit (test->loop);
557 }
558
559 static void
560 on_request_certificate_async_call (GObject      *source,
561                                    GAsyncResult *result,
562                                    gpointer      user_data)
563 {
564   Test *test = user_data;
565   GTlsInteractionResult res;
566   GError *error = NULL;
567
568   g_assert (G_IS_TLS_INTERACTION (source));
569   g_assert (G_TLS_INTERACTION (source) == test->interaction);
570
571   /* Check that this callback is being run in the right place */
572   g_assert (g_thread_self () == test->interaction_thread);
573
574   res = g_tls_interaction_request_certificate_finish (test->interaction, result, &error);
575
576   /* Check that the results match the fixture */
577   g_assert_cmpuint (test->fixture->result, ==, res);
578   switch (test->fixture->result)
579     {
580       case G_TLS_INTERACTION_HANDLED:
581         g_assert_no_error (error);
582         g_assert_cmpstr (g_object_get_data (G_OBJECT (test->connection), "chosen-certificate"), ==, "my-certificate");
583         break;
584       case G_TLS_INTERACTION_FAILED:
585         g_assert_error (error, test->fixture->error_domain, test->fixture->error_code);
586         g_assert_cmpstr (error->message, ==, test->fixture->error_message);
587         g_clear_error (&error);
588         break;
589       case G_TLS_INTERACTION_UNHANDLED:
590         g_assert_no_error (error);
591         break;
592       default:
593         g_assert_not_reached ();
594     }
595
596   /* Signal the end of the test */
597   g_main_loop_quit (test->loop);
598 }
599
600 static void
601 test_request_certificate_async (Test            *test,
602                                 gconstpointer    unused)
603 {
604   /* This test only works with a main loop */
605   g_assert (test->loop);
606
607   g_tls_interaction_request_certificate_async (test->interaction,
608                                                test->connection, 0, NULL,
609                                                on_request_certificate_async_call,
610                                                test);
611
612   /* teardown waits until g_main_loop_quit(). called from callback */
613 }
614
615 static void
616 test_invoke_request_certificate (Test         *test,
617                                  gconstpointer unused)
618 {
619   GTlsInteractionResult res;
620   GError *error = NULL;
621
622   res = g_tls_interaction_invoke_request_certificate (test->interaction,
623                                                       test->connection,
624                                                       0, NULL, &error);
625
626   /* Check that the results match the fixture */
627   g_assert_cmpuint (test->fixture->result, ==, res);
628   switch (test->fixture->result)
629     {
630       case G_TLS_INTERACTION_HANDLED:
631         g_assert_no_error (error);
632         g_assert_cmpstr (g_object_get_data (G_OBJECT (test->connection), "chosen-certificate"), ==, "my-certificate");
633         break;
634       case G_TLS_INTERACTION_FAILED:
635         g_assert_error (error, test->fixture->error_domain, test->fixture->error_code);
636         g_assert_cmpstr (error->message, ==, test->fixture->error_message);
637         g_clear_error (&error);
638         break;
639       case G_TLS_INTERACTION_UNHANDLED:
640         g_assert_no_error (error);
641         break;
642       default:
643         g_assert_not_reached ();
644     }
645
646   /* This allows teardown to stop if running with loop */
647   if (test->loop)
648     g_main_loop_quit (test->loop);
649 }
650
651 static void
652 test_request_certificate (Test         *test,
653                           gconstpointer unused)
654 {
655   GTlsInteractionResult res;
656   GError *error = NULL;
657
658   res = g_tls_interaction_request_certificate (test->interaction, test->connection,
659                                                0, NULL, &error);
660
661   /* Check that the results match the fixture */
662   g_assert_cmpuint (test->fixture->result, ==, res);
663   switch (test->fixture->result)
664     {
665       case G_TLS_INTERACTION_HANDLED:
666         g_assert_no_error (error);
667         g_assert_cmpstr (g_object_get_data (G_OBJECT (test->connection), "chosen-certificate"), ==, "my-certificate");
668         break;
669       case G_TLS_INTERACTION_FAILED:
670         g_assert_error (error, test->fixture->error_domain, test->fixture->error_code);
671         g_assert_cmpstr (error->message, ==, test->fixture->error_message);
672         g_clear_error (&error);
673         break;
674       case G_TLS_INTERACTION_UNHANDLED:
675         g_assert_no_error (error);
676         break;
677       default:
678         g_assert_not_reached ();
679     }
680
681   /* This allows teardown to stop if running with loop */
682   if (test->loop)
683     g_main_loop_quit (test->loop);
684 }
685
686 /* ----------------------------------------------------------------------------
687  * TEST SETUP
688  */
689
690 static void
691 setup_without_loop (Test           *test,
692                     gconstpointer   user_data)
693 {
694   const Fixture *fixture = user_data;
695   GTlsInteractionClass *klass;
696   GTlsBackend *backend;
697   GError *error = NULL;
698
699   test->fixture = fixture;
700
701   test->interaction = g_object_new (TEST_TYPE_INTERACTION, NULL);
702   g_assert (TEST_IS_INTERACTION (test->interaction));
703
704   TEST_INTERACTION (test->interaction)->test = test;
705
706   klass =  G_TLS_INTERACTION_GET_CLASS (test->interaction);
707   klass->ask_password = fixture->ask_password_func;
708   klass->ask_password_async = fixture->ask_password_async_func;
709   klass->ask_password_finish = fixture->ask_password_finish_func;
710   klass->request_certificate = fixture->request_certificate_func;
711   klass->request_certificate_async = fixture->request_certificate_async_func;
712   klass->request_certificate_finish = fixture->request_certificate_finish_func;
713
714   backend = g_object_new (G_TYPE_TEST_TLS_BACKEND, NULL);
715   test->connection = g_object_new (g_tls_backend_get_server_connection_type (backend), NULL);
716   g_assert_no_error (error);
717   g_object_unref (backend);
718
719   test->password = g_tls_password_new (0, "Description");
720   test->test_thread = g_thread_self ();
721
722   /*
723    * If no loop is running then interaction should happen in the same
724    * thread that the tests are running in.
725    */
726   test->interaction_thread = test->test_thread;
727 }
728
729 static void
730 teardown_without_loop (Test            *test,
731                        gconstpointer    unused)
732 {
733   g_object_unref (test->connection);
734   g_object_unref (test->password);
735
736   g_assert_finalize_object (test->interaction);
737 }
738
739 typedef struct {
740   GMutex loop_mutex;
741   GCond loop_started;
742   gboolean started;
743   Test *test;
744 } ThreadLoop;
745
746 static gpointer
747 thread_loop (gpointer user_data)
748 {
749   GMainContext *context = g_main_context_default ();
750   ThreadLoop *closure = user_data;
751   Test *test = closure->test;
752
753   g_mutex_lock (&closure->loop_mutex);
754
755   g_assert (test->loop_thread == g_thread_self ());
756   g_assert (test->loop == NULL);
757   test->loop = g_main_loop_new (context, TRUE);
758
759   g_main_context_acquire (context);
760   closure->started = TRUE;
761   g_cond_signal (&closure->loop_started);
762   g_mutex_unlock (&closure->loop_mutex);
763
764   while (g_main_loop_is_running (test->loop))
765     g_main_context_iteration (context, TRUE);
766
767   g_main_context_release (context);
768   return test;
769 }
770
771 static void
772 setup_with_thread_loop (Test            *test,
773                         gconstpointer    user_data)
774 {
775   ThreadLoop closure;
776
777   setup_without_loop (test, user_data);
778
779   g_mutex_init (&closure.loop_mutex);
780   g_cond_init (&closure.loop_started);
781   closure.started = FALSE;
782   closure.test = test;
783
784   g_mutex_lock (&closure.loop_mutex);
785   test->loop_thread = g_thread_new ("loop", thread_loop, &closure);
786   while (!closure.started)
787     g_cond_wait (&closure.loop_started, &closure.loop_mutex);
788   g_mutex_unlock (&closure.loop_mutex);
789
790   /*
791    * When a loop is running then interaction should always occur in the main
792    * context of that loop.
793    */
794   test->interaction_thread = test->loop_thread;
795
796   g_mutex_clear (&closure.loop_mutex);
797   g_cond_clear (&closure.loop_started);
798 }
799
800 static void
801 teardown_with_thread_loop (Test            *test,
802                            gconstpointer    unused)
803 {
804   gpointer check;
805
806   g_assert (test->loop_thread);
807   check = g_thread_join (test->loop_thread);
808   g_assert (check == test);
809   test->loop_thread = NULL;
810
811   g_main_loop_unref (test->loop);
812
813   teardown_without_loop (test, unused);
814 }
815
816 static void
817 setup_with_normal_loop (Test            *test,
818                         gconstpointer    user_data)
819 {
820   GMainContext *context;
821
822   setup_without_loop (test, user_data);
823
824   context = g_main_context_default ();
825   if (!g_main_context_acquire (context))
826     g_assert_not_reached ();
827
828   test->loop = g_main_loop_new (context, TRUE);
829   g_assert (g_main_loop_is_running (test->loop));
830 }
831
832 static void
833 teardown_with_normal_loop (Test            *test,
834                            gconstpointer    unused)
835 {
836   GMainContext *context;
837
838   context = g_main_context_default ();
839   while (g_main_loop_is_running (test->loop))
840     g_main_context_iteration (context, TRUE);
841
842   g_main_context_release (context);
843
844   /* Run test until complete */
845   g_main_loop_unref (test->loop);
846   test->loop = NULL;
847
848   teardown_without_loop (test, unused);
849 }
850
851 typedef void (*TestFunc) (Test *test, gconstpointer data);
852
853 static void
854 test_with_async_ask_password (const gchar *name,
855                               TestFunc     setup,
856                               TestFunc     func,
857                               TestFunc     teardown)
858 {
859   gchar *test_name;
860   Fixture *fixture;
861
862   /* Async implementation that succeeds */
863   fixture = g_new0 (Fixture, 1);
864   fixture->ask_password_async_func = test_interaction_ask_password_async_success;
865   fixture->ask_password_finish_func = test_interaction_ask_password_finish_success;
866   fixture->ask_password_func = NULL;
867   fixture->result = G_TLS_INTERACTION_HANDLED;
868   test_name = g_strdup_printf ("%s/async-implementation-success", name);
869   g_test_add (test_name, Test, fixture, setup, func, teardown);
870   g_free (test_name);
871   g_ptr_array_add (fixtures, fixture);
872
873   /* Async implementation that fails */
874   fixture = g_new0 (Fixture, 1);
875   fixture->ask_password_async_func = test_interaction_ask_password_async_failure;
876   fixture->ask_password_finish_func = test_interaction_ask_password_finish_failure;
877   fixture->ask_password_func = NULL;
878   fixture->result = G_TLS_INTERACTION_FAILED;
879   fixture->error_domain = G_FILE_ERROR;
880   fixture->error_code = G_FILE_ERROR_ACCES;
881   fixture->error_message = "The message";
882   test_name = g_strdup_printf ("%s/async-implementation-failure", name);
883   g_test_add (test_name, Test, fixture, setup, func, teardown);
884   g_free (test_name);
885   g_ptr_array_add (fixtures, fixture);
886 }
887
888 static void
889 test_with_unhandled_ask_password (const gchar *name,
890                                   TestFunc     setup,
891                                   TestFunc     func,
892                                   TestFunc     teardown)
893 {
894   gchar *test_name;
895   Fixture *fixture;
896
897   /* Unhandled implementation */
898   fixture = g_new0 (Fixture, 1);
899   fixture->ask_password_async_func = NULL;
900   fixture->ask_password_finish_func = NULL;
901   fixture->ask_password_func = NULL;
902   fixture->result = G_TLS_INTERACTION_UNHANDLED;
903   test_name = g_strdup_printf ("%s/unhandled-implementation", name);
904   g_test_add (test_name, Test, fixture, setup, func, teardown);
905   g_free (test_name);
906   g_ptr_array_add (fixtures, fixture);
907 }
908
909 static void
910 test_with_sync_ask_password (const gchar *name,
911                                              TestFunc     setup,
912                                              TestFunc     func,
913                                              TestFunc     teardown)
914 {
915   gchar *test_name;
916   Fixture *fixture;
917
918   /* Sync implementation that succeeds */
919   fixture = g_new0 (Fixture, 1);
920   fixture->ask_password_async_func = NULL;
921   fixture->ask_password_finish_func = NULL;
922   fixture->ask_password_func = test_interaction_ask_password_sync_success;
923   fixture->result = G_TLS_INTERACTION_HANDLED;
924   test_name = g_strdup_printf ("%s/sync-implementation-success", name);
925   g_test_add (test_name, Test, fixture, setup, func, teardown);
926   g_free (test_name);
927   g_ptr_array_add (fixtures, fixture);
928
929   /* Async implementation that fails */
930   fixture = g_new0 (Fixture, 1);
931   fixture->ask_password_async_func = NULL;
932   fixture->ask_password_finish_func = NULL;
933   fixture->ask_password_func = test_interaction_ask_password_sync_failure;
934   fixture->result = G_TLS_INTERACTION_FAILED;
935   fixture->error_domain = G_FILE_ERROR;
936   fixture->error_code = G_FILE_ERROR_ACCES;
937   fixture->error_message = "The message";
938   test_name = g_strdup_printf ("%s/sync-implementation-failure", name);
939   g_test_add (test_name, Test, fixture, setup, func, teardown);
940   g_free (test_name);
941   g_ptr_array_add (fixtures, fixture);
942 }
943
944 static void
945 test_with_all_ask_password (const gchar *name,
946                             TestFunc setup,
947                             TestFunc func,
948                             TestFunc teardown)
949 {
950   test_with_unhandled_ask_password (name, setup, func, teardown);
951   test_with_async_ask_password (name, setup, func, teardown);
952   test_with_sync_ask_password (name, setup, func, teardown);
953 }
954
955 static void
956 test_with_async_request_certificate (const gchar *name,
957                                      TestFunc     setup,
958                                      TestFunc     func,
959                                      TestFunc     teardown)
960 {
961   gchar *test_name;
962   Fixture *fixture;
963
964   /* Async implementation that succeeds */
965   fixture = g_new0 (Fixture, 1);
966   fixture->request_certificate_async_func = test_interaction_request_certificate_async_success;
967   fixture->request_certificate_finish_func = test_interaction_request_certificate_finish_success;
968   fixture->request_certificate_func = NULL;
969   fixture->result = G_TLS_INTERACTION_HANDLED;
970   test_name = g_strdup_printf ("%s/async-implementation-success", name);
971   g_test_add (test_name, Test, fixture, setup, func, teardown);
972   g_free (test_name);
973   g_ptr_array_add (fixtures, fixture);
974
975   /* Async implementation that fails */
976   fixture = g_new0 (Fixture, 1);
977   fixture->request_certificate_async_func = test_interaction_request_certificate_async_failure;
978   fixture->request_certificate_finish_func = test_interaction_request_certificate_finish_failure;
979   fixture->request_certificate_func = NULL;
980   fixture->result = G_TLS_INTERACTION_FAILED;
981   fixture->error_domain = G_FILE_ERROR;
982   fixture->error_code = G_FILE_ERROR_NOENT;
983   fixture->error_message = "Another message";
984   test_name = g_strdup_printf ("%s/async-implementation-failure", name);
985   g_test_add (test_name, Test, fixture, setup, func, teardown);
986   g_free (test_name);
987   g_ptr_array_add (fixtures, fixture);
988 }
989
990 static void
991 test_with_unhandled_request_certificate (const gchar *name,
992                                          TestFunc     setup,
993                                          TestFunc     func,
994                                          TestFunc     teardown)
995 {
996   gchar *test_name;
997   Fixture *fixture;
998
999   /* Unhandled implementation */
1000   fixture = g_new0 (Fixture, 1);
1001   fixture->request_certificate_async_func = NULL;
1002   fixture->request_certificate_finish_func = NULL;
1003   fixture->request_certificate_func = NULL;
1004   fixture->result = G_TLS_INTERACTION_UNHANDLED;
1005   test_name = g_strdup_printf ("%s/unhandled-implementation", name);
1006   g_test_add (test_name, Test, fixture, setup, func, teardown);
1007   g_free (test_name);
1008   g_ptr_array_add (fixtures, fixture);
1009 }
1010
1011 static void
1012 test_with_sync_request_certificate (const gchar *name,
1013                                     TestFunc     setup,
1014                                     TestFunc     func,
1015                                     TestFunc     teardown)
1016 {
1017   gchar *test_name;
1018   Fixture *fixture;
1019
1020   /* Sync implementation that succeeds */
1021   fixture = g_new0 (Fixture, 1);
1022   fixture->request_certificate_async_func = NULL;
1023   fixture->request_certificate_finish_func = NULL;
1024   fixture->request_certificate_func = test_interaction_request_certificate_sync_success;
1025   fixture->result = G_TLS_INTERACTION_HANDLED;
1026   test_name = g_strdup_printf ("%s/sync-implementation-success", name);
1027   g_test_add (test_name, Test, fixture, setup, func, teardown);
1028   g_free (test_name);
1029   g_ptr_array_add (fixtures, fixture);
1030
1031   /* Async implementation that fails */
1032   fixture = g_new0 (Fixture, 1);
1033   fixture->request_certificate_async_func = NULL;
1034   fixture->request_certificate_finish_func = NULL;
1035   fixture->request_certificate_func = test_interaction_request_certificate_sync_failure;
1036   fixture->result = G_TLS_INTERACTION_FAILED;
1037   fixture->error_domain = G_FILE_ERROR;
1038   fixture->error_code = G_FILE_ERROR_NOENT;
1039   fixture->error_message = "Another message";
1040   test_name = g_strdup_printf ("%s/sync-implementation-failure", name);
1041   g_test_add (test_name, Test, fixture, setup, func, teardown);
1042   g_free (test_name);
1043   g_ptr_array_add (fixtures, fixture);
1044 }
1045
1046 static void
1047 test_with_all_request_certificate (const gchar *name,
1048                                    TestFunc setup,
1049                                    TestFunc func,
1050                                    TestFunc teardown)
1051 {
1052   test_with_unhandled_request_certificate (name, setup, func, teardown);
1053   test_with_async_request_certificate (name, setup, func, teardown);
1054   test_with_sync_request_certificate (name, setup, func, teardown);
1055 }
1056 int
1057 main (int   argc,
1058       char *argv[])
1059 {
1060   gint ret;
1061
1062   g_test_init (&argc, &argv, NULL);
1063
1064   fixtures = g_ptr_array_new_with_free_func (g_free);
1065
1066   /* Tests for g_tls_interaction_invoke_ask_password */
1067   test_with_all_ask_password ("/tls-interaction/ask-password/invoke-with-loop",
1068                               setup_with_thread_loop, test_invoke_ask_password, teardown_with_thread_loop);
1069   test_with_all_ask_password ("/tls-interaction/ask-password/invoke-without-loop",
1070                               setup_without_loop, test_invoke_ask_password, teardown_without_loop);
1071   test_with_all_ask_password ("/tls-interaction/ask-password/invoke-in-loop",
1072                                               setup_with_normal_loop, test_invoke_ask_password, teardown_with_normal_loop);
1073
1074   /* Tests for g_tls_interaction_ask_password */
1075   test_with_unhandled_ask_password ("/tls-interaction/ask-password/sync",
1076                                     setup_without_loop, test_ask_password, teardown_without_loop);
1077   test_with_sync_ask_password ("/tls-interaction/ask-password/sync",
1078                                setup_without_loop, test_ask_password, teardown_without_loop);
1079
1080   /* Tests for g_tls_interaction_ask_password_async */
1081   test_with_unhandled_ask_password ("/tls-interaction/ask-password/async",
1082                                     setup_with_normal_loop, test_ask_password_async, teardown_with_normal_loop);
1083   test_with_async_ask_password ("/tls-interaction/ask-password/async",
1084                                 setup_with_normal_loop, test_ask_password_async, teardown_with_normal_loop);
1085
1086   /* Tests for g_tls_interaction_invoke_request_certificate */
1087   test_with_all_request_certificate ("/tls-interaction/request-certificate/invoke-with-loop",
1088                                      setup_with_thread_loop, test_invoke_request_certificate, teardown_with_thread_loop);
1089   test_with_all_request_certificate ("/tls-interaction/request-certificate/invoke-without-loop",
1090                                      setup_without_loop, test_invoke_request_certificate, teardown_without_loop);
1091   test_with_all_request_certificate ("/tls-interaction/request-certificate/invoke-in-loop",
1092                               setup_with_normal_loop, test_invoke_request_certificate, teardown_with_normal_loop);
1093
1094   /* Tests for g_tls_interaction_ask_password */
1095   test_with_unhandled_request_certificate ("/tls-interaction/request-certificate/sync",
1096                                            setup_without_loop, test_request_certificate, teardown_without_loop);
1097   test_with_sync_request_certificate ("/tls-interaction/request-certificate/sync",
1098                                       setup_without_loop, test_request_certificate, teardown_without_loop);
1099
1100   /* Tests for g_tls_interaction_ask_password_async */
1101   test_with_unhandled_request_certificate ("/tls-interaction/request-certificate/async",
1102                                            setup_with_normal_loop, test_request_certificate_async, teardown_with_normal_loop);
1103   test_with_async_request_certificate ("/tls-interaction/request-certificate/async",
1104                                        setup_with_normal_loop, test_request_certificate_async, teardown_with_normal_loop);
1105
1106   ret = g_test_run();
1107   g_ptr_array_free (fixtures, TRUE);
1108   return ret;
1109 }