(root)/
glib-2.79.0/
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_literal (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_literal (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  }