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