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