(root)/
glib-2.79.0/
gio/
tests/
gdbus-proxy.c
       1  /* GLib testing framework examples and tests
       2   *
       3   * Copyright (C) 2008-2010 Red Hat, Inc.
       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: David Zeuthen <davidz@redhat.com>
      21   */
      22  
      23  #include <gio/gio.h>
      24  #include <unistd.h>
      25  #include <string.h>
      26  
      27  #include "gdbus-tests.h"
      28  
      29  /* all tests rely on a shared mainloop */
      30  static GMainLoop *loop = NULL;
      31  
      32  /* ---------------------------------------------------------------------------------------------------- */
      33  /* Test that the method aspects of GDBusProxy works */
      34  /* ---------------------------------------------------------------------------------------------------- */
      35  
      36  static void
      37  test_methods (GDBusProxy *proxy)
      38  {
      39    GVariant *result;
      40    GError *error;
      41    const gchar *str;
      42    gchar *dbus_error_name;
      43  
      44    /* check that we can invoke a method */
      45    error = NULL;
      46    result = g_dbus_proxy_call_sync (proxy,
      47                                     "HelloWorld",
      48                                     g_variant_new ("(s)", "Hey"),
      49                                     G_DBUS_CALL_FLAGS_NONE,
      50                                     -1,
      51                                     NULL,
      52                                     &error);
      53    g_assert_no_error (error);
      54    g_assert_nonnull (result);
      55    g_assert_cmpstr (g_variant_get_type_string (result), ==, "(s)");
      56    g_variant_get (result, "(&s)", &str);
      57    g_assert_cmpstr (str, ==, "You greeted me with 'Hey'. Thanks!");
      58    g_variant_unref (result);
      59  
      60    /* Check that we can completely recover the returned error */
      61    result = g_dbus_proxy_call_sync (proxy,
      62                                     "HelloWorld",
      63                                     g_variant_new ("(s)", "Yo"),
      64                                     G_DBUS_CALL_FLAGS_NONE,
      65                                     -1,
      66                                     NULL,
      67                                     &error);
      68    g_assert_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR);
      69    g_assert_true (g_dbus_error_is_remote_error (error));
      70    g_assert_true (g_dbus_error_is_remote_error (error));
      71    g_assert_null (result);
      72    dbus_error_name = g_dbus_error_get_remote_error (error);
      73    g_assert_cmpstr (dbus_error_name, ==, "com.example.TestException");
      74    g_free (dbus_error_name);
      75    g_assert_true (g_dbus_error_strip_remote_error (error));
      76    g_assert_cmpstr (error->message, ==, "Yo is not a proper greeting");
      77    g_clear_error (&error);
      78  
      79    /* Check that we get a timeout if the method handling is taking longer than
      80     * timeout. We use such a long sleep because on slow machines, if the
      81     * sleep isn't much longer than the timeout and we're doing a parallel
      82     * build, there's no guarantee we'll be scheduled in the window between
      83     * the timeout being hit and the sleep finishing. */
      84    error = NULL;
      85    result = g_dbus_proxy_call_sync (proxy,
      86                                     "Sleep",
      87                                     g_variant_new ("(i)", 10000 /* msec */),
      88                                     G_DBUS_CALL_FLAGS_NONE,
      89                                     100 /* msec */,
      90                                     NULL,
      91                                     &error);
      92    g_assert_error (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT);
      93    g_assert_false (g_dbus_error_is_remote_error (error));
      94    g_assert_null (result);
      95    g_clear_error (&error);
      96  
      97    /* Check that proxy-default timeouts work. */
      98    g_assert_cmpint (g_dbus_proxy_get_default_timeout (proxy), ==, -1);
      99  
     100    /* the default timeout is 25000 msec so this should work */
     101    result = g_dbus_proxy_call_sync (proxy,
     102                                     "Sleep",
     103                                     g_variant_new ("(i)", 500 /* msec */),
     104                                     G_DBUS_CALL_FLAGS_NONE,
     105                                     -1, /* use proxy default (e.g. -1 -> e.g. 25000 msec) */
     106                                     NULL,
     107                                     &error);
     108    g_assert_no_error (error);
     109    g_assert_nonnull (result);
     110    g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
     111    g_variant_unref (result);
     112  
     113    /* Now set the proxy-default timeout to 250 msec and try the 10000 msec
     114     * call - this should FAIL. Again, we use such a long sleep because on slow
     115     * machines there's no guarantee we'll be scheduled when we want to be. */
     116    g_dbus_proxy_set_default_timeout (proxy, 250);
     117    g_assert_cmpint (g_dbus_proxy_get_default_timeout (proxy), ==, 250);
     118    result = g_dbus_proxy_call_sync (proxy,
     119                                     "Sleep",
     120                                     g_variant_new ("(i)", 10000 /* msec */),
     121                                     G_DBUS_CALL_FLAGS_NONE,
     122                                     -1, /* use proxy default (e.g. 250 msec) */
     123                                     NULL,
     124                                     &error);
     125    g_assert_error (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT);
     126    g_assert_false (g_dbus_error_is_remote_error (error));
     127    g_assert_null (result);
     128    g_clear_error (&error);
     129  
     130    /* clean up after ourselves */
     131    g_dbus_proxy_set_default_timeout (proxy, -1);
     132  }
     133  
     134  static gboolean
     135  strv_equal (gchar **strv, ...)
     136  {
     137    gsize count;
     138    va_list list;
     139    const gchar *str;
     140    gboolean res;
     141  
     142    res = TRUE;
     143    count = 0;
     144    va_start (list, strv);
     145    while (1)
     146      {
     147        str = va_arg (list, const gchar *);
     148        if (str == NULL)
     149          break;
     150        if (g_strcmp0 (str, strv[count]) != 0)
     151          {
     152            res = FALSE;
     153            break;
     154          }
     155        count++;
     156      }
     157    va_end (list);
     158  
     159    if (res)
     160      res = g_strv_length (strv) == count;
     161  
     162    return res;
     163  }
     164  
     165  /* ---------------------------------------------------------------------------------------------------- */
     166  /* Test that the property aspects of GDBusProxy works */
     167  /* ---------------------------------------------------------------------------------------------------- */
     168  
     169  static void
     170  test_properties (GDBusProxy *proxy)
     171  {
     172    GError *error;
     173    GVariant *variant;
     174    GVariant *variant2;
     175    GVariant *result;
     176    gchar **names;
     177    gchar *name_owner;
     178    GDBusProxy *proxy2;
     179  
     180    error = NULL;
     181  
     182    if (g_dbus_proxy_get_flags (proxy) & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES)
     183      {
     184         g_assert_null (g_dbus_proxy_get_cached_property_names (proxy));
     185         return;
     186      }
     187  
     188    /*
     189     * Check that we can list all cached properties.
     190     */
     191    names = g_dbus_proxy_get_cached_property_names (proxy);
     192  
     193    g_assert_true (strv_equal (names,
     194                               "PropertyThatWillBeInvalidated",
     195                               "ab",
     196                               "ad",
     197                               "ai",
     198                               "an",
     199                               "ao",
     200                               "aq",
     201                               "as",
     202                               "at",
     203                               "au",
     204                               "ax",
     205                               "ay",
     206                               "b",
     207                               "d",
     208                               "foo",
     209                               "i",
     210                               "n",
     211                               "o",
     212                               "q",
     213                               "s",
     214                               "t",
     215                               "u",
     216                               "x",
     217                               "y",
     218                               NULL));
     219  
     220    g_strfreev (names);
     221  
     222    /*
     223     * Check that we can read cached properties.
     224     *
     225     * No need to test all properties - GVariant has already been tested
     226     */
     227    variant = g_dbus_proxy_get_cached_property (proxy, "y");
     228    g_assert_nonnull (variant);
     229    g_assert_cmpint (g_variant_get_byte (variant), ==, 1);
     230    g_variant_unref (variant);
     231    variant = g_dbus_proxy_get_cached_property (proxy, "o");
     232    g_assert_nonnull (variant);
     233    g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "/some/path");
     234    g_variant_unref (variant);
     235  
     236    /*
     237     * Now ask the service to change a property and check that #GDBusProxy::g-property-changed
     238     * is received. Also check that the cache is updated.
     239     */
     240    variant2 = g_variant_new_byte (42);
     241    result = g_dbus_proxy_call_sync (proxy,
     242                                     "FrobSetProperty",
     243                                     g_variant_new ("(sv)",
     244                                                    "y",
     245                                                    variant2),
     246                                     G_DBUS_CALL_FLAGS_NONE,
     247                                     -1,
     248                                     NULL,
     249                                     &error);
     250    g_assert_no_error (error);
     251    g_assert_nonnull (result);
     252    g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
     253    g_variant_unref (result);
     254    _g_assert_signal_received (proxy, "g-properties-changed");
     255    variant = g_dbus_proxy_get_cached_property (proxy, "y");
     256    g_assert_nonnull (variant);
     257    g_assert_cmpint (g_variant_get_byte (variant), ==, 42);
     258    g_variant_unref (variant);
     259  
     260    g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_byte (142));
     261    variant = g_dbus_proxy_get_cached_property (proxy, "y");
     262    g_assert_nonnull (variant);
     263    g_assert_cmpint (g_variant_get_byte (variant), ==, 142);
     264    g_variant_unref (variant);
     265  
     266    g_dbus_proxy_set_cached_property (proxy, "y", NULL);
     267    variant = g_dbus_proxy_get_cached_property (proxy, "y");
     268    g_assert_null (variant);
     269  
     270    /* Check that the invalidation feature of the PropertiesChanged()
     271     * signal works... First, check that we have a cached value of the
     272     * property (from the initial GetAll() call)
     273     */
     274    variant = g_dbus_proxy_get_cached_property (proxy, "PropertyThatWillBeInvalidated");
     275    g_assert_nonnull (variant);
     276    g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "InitialValue");
     277    g_variant_unref (variant);
     278    /* now ask to invalidate the property - this causes a
     279     *
     280     *   PropertiesChanaged("com.example.Frob",
     281     *                      {},
     282     *                      ["PropertyThatWillBeInvalidated")
     283     *
     284     * signal to be emitted. This is received before the method reply
     285     * for FrobInvalidateProperty *but* since the proxy was created in
     286     * the same thread as we're doing this synchronous call, we'll get
     287     * the method reply before...
     288     */
     289    result = g_dbus_proxy_call_sync (proxy,
     290                                     "FrobInvalidateProperty",
     291                                     g_variant_new ("(s)", "OMGInvalidated"),
     292                                     G_DBUS_CALL_FLAGS_NONE,
     293                                     -1,
     294                                     NULL,
     295                                     &error);
     296    g_assert_no_error (error);
     297    g_assert_nonnull (result);
     298    g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
     299    g_variant_unref (result);
     300    /* ... hence we wait for the g-properties-changed signal to be delivered */
     301    _g_assert_signal_received (proxy, "g-properties-changed");
     302    /* ... and now we finally, check that the cached value has been invalidated */
     303    variant = g_dbus_proxy_get_cached_property (proxy, "PropertyThatWillBeInvalidated");
     304    g_assert_null (variant);
     305  
     306    /* Now test that G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES works - we need a new proxy for that */
     307    error = NULL;
     308    proxy2 = g_dbus_proxy_new_sync (g_dbus_proxy_get_connection (proxy),
     309                                    G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES,
     310                                    NULL,                      /* GDBusInterfaceInfo */
     311                                    "com.example.TestService", /* name */
     312                                    "/com/example/TestObject", /* object path */
     313                                    "com.example.Frob",        /* interface */
     314                                    NULL, /* GCancellable */
     315                                    &error);
     316    g_assert_no_error (error);
     317  
     318    name_owner = g_dbus_proxy_get_name_owner (proxy2);
     319    g_assert_nonnull (name_owner);
     320    g_free (name_owner);
     321  
     322    variant = g_dbus_proxy_get_cached_property (proxy2, "PropertyThatWillBeInvalidated");
     323    g_assert_nonnull (variant);
     324    g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "OMGInvalidated"); /* from previous test */
     325    g_variant_unref (variant);
     326  
     327    result = g_dbus_proxy_call_sync (proxy2,
     328                                     "FrobInvalidateProperty",
     329                                     g_variant_new ("(s)", "OMGInvalidated2"),
     330                                     G_DBUS_CALL_FLAGS_NONE,
     331                                     -1,
     332                                     NULL,
     333                                     &error);
     334    g_assert_no_error (error);
     335    g_assert_nonnull (result);
     336    g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
     337    g_variant_unref (result);
     338  
     339    /* this time we should get the ::g-properties-changed _with_ the value */
     340    _g_assert_signal_received (proxy2, "g-properties-changed");
     341  
     342    variant = g_dbus_proxy_get_cached_property (proxy2, "PropertyThatWillBeInvalidated");
     343    g_assert_nonnull (variant);
     344    g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "OMGInvalidated2");
     345    g_variant_unref (variant);
     346  
     347    g_object_unref (proxy2);
     348  }
     349  
     350  /* ---------------------------------------------------------------------------------------------------- */
     351  /* Test that the signal aspects of GDBusProxy works */
     352  /* ---------------------------------------------------------------------------------------------------- */
     353  
     354  static void
     355  test_proxy_signals_on_signal (GDBusProxy  *proxy,
     356                                const gchar *sender_name,
     357                                const gchar *signal_name,
     358                                GVariant    *parameters,
     359                                gpointer     user_data)
     360  {
     361    GString *s = user_data;
     362  
     363    g_assert_cmpstr (signal_name, ==, "TestSignal");
     364    g_assert_cmpstr (g_variant_get_type_string (parameters), ==, "(sov)");
     365  
     366    g_variant_print_string (parameters, s, TRUE);
     367  }
     368  
     369  typedef struct
     370  {
     371    GMainLoop *internal_loop;
     372    GString *s;
     373  } TestSignalData;
     374  
     375  static void
     376  test_proxy_signals_on_emit_signal_cb (GDBusProxy   *proxy,
     377                                        GAsyncResult *res,
     378                                        gpointer      user_data)
     379  {
     380    TestSignalData *data = user_data;
     381    GError *error;
     382    GVariant *result;
     383  
     384    error = NULL;
     385    result = g_dbus_proxy_call_finish (proxy,
     386                                       res,
     387                                       &error);
     388    g_assert_no_error (error);
     389    g_assert_nonnull (result);
     390    g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
     391    g_variant_unref (result);
     392  
     393    /* check that the signal was received before we got the method result */
     394    g_assert_cmpuint (strlen (data->s->str), >, 0);
     395  
     396    /* break out of the loop */
     397    g_main_loop_quit (data->internal_loop);
     398  }
     399  
     400  static void
     401  test_signals (GDBusProxy *proxy)
     402  {
     403    GError *error;
     404    GString *s;
     405    gulong signal_handler_id;
     406    TestSignalData data;
     407    GVariant *result;
     408  
     409    error = NULL;
     410  
     411    /*
     412     * Ask the service to emit a signal and check that we receive it.
     413     *
     414     * Note that blocking calls don't block in the mainloop so wait for the signal (which
     415     * is dispatched before the method reply)
     416     */
     417    s = g_string_new (NULL);
     418    signal_handler_id = g_signal_connect (proxy,
     419                                          "g-signal",
     420                                          G_CALLBACK (test_proxy_signals_on_signal),
     421                                          s);
     422  
     423    result = g_dbus_proxy_call_sync (proxy,
     424                                     "EmitSignal",
     425                                     g_variant_new ("(so)",
     426                                                    "Accept the next proposition you hear",
     427                                                    "/some/path"),
     428                                     G_DBUS_CALL_FLAGS_NONE,
     429                                     -1,
     430                                     NULL,
     431                                     &error);
     432    g_assert_no_error (error);
     433    g_assert_nonnull (result);
     434    g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
     435    g_variant_unref (result);
     436    /* check that we haven't received the signal just yet */
     437    g_assert_cmpuint (strlen (s->str), ==, 0);
     438    /* and now wait for the signal */
     439    _g_assert_signal_received (proxy, "g-signal");
     440    g_assert_cmpstr (s->str,
     441                     ==,
     442                     "('Accept the next proposition you hear .. in bed!', objectpath '/some/path/in/bed', <'a variant'>)");
     443    g_signal_handler_disconnect (proxy, signal_handler_id);
     444    g_string_free (s, TRUE);
     445  
     446    /*
     447     * Now do this async to check the signal is received before the method returns.
     448     */
     449    s = g_string_new (NULL);
     450    data.internal_loop = g_main_loop_new (NULL, FALSE);
     451    data.s = s;
     452    signal_handler_id = g_signal_connect (proxy,
     453                                          "g-signal",
     454                                          G_CALLBACK (test_proxy_signals_on_signal),
     455                                          s);
     456    g_dbus_proxy_call (proxy,
     457                       "EmitSignal",
     458                       g_variant_new ("(so)",
     459                                      "You will make a great programmer",
     460                                      "/some/other/path"),
     461                       G_DBUS_CALL_FLAGS_NONE,
     462                       -1,
     463                       NULL,
     464                       (GAsyncReadyCallback) test_proxy_signals_on_emit_signal_cb,
     465                       &data);
     466    g_main_loop_run (data.internal_loop);
     467    g_main_loop_unref (data.internal_loop);
     468    g_assert_cmpstr (s->str,
     469                     ==,
     470                     "('You will make a great programmer .. in bed!', objectpath '/some/other/path/in/bed', <'a variant'>)");
     471    g_signal_handler_disconnect (proxy, signal_handler_id);
     472    g_string_free (s, TRUE);
     473  }
     474  
     475  /* ---------------------------------------------------------------------------------------------------- */
     476  
     477  static void
     478  test_bogus_method_return (GDBusProxy *proxy)
     479  {
     480    GError *error = NULL;
     481    GVariant *result;
     482  
     483    result = g_dbus_proxy_call_sync (proxy,
     484                                     "PairReturn",
     485                                     NULL,
     486                                     G_DBUS_CALL_FLAGS_NONE,
     487                                     -1,
     488                                     NULL,
     489                                     &error);
     490    g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
     491    g_error_free (error);
     492    g_assert_null (result);
     493  }
     494  
     495  #if 0 /* Disabled: see https://bugzilla.gnome.org/show_bug.cgi?id=658999 */
     496  static void
     497  test_bogus_signal (GDBusProxy *proxy)
     498  {
     499    GError *error = NULL;
     500    GVariant *result;
     501    GDBusInterfaceInfo *old_iface_info;
     502  
     503    result = g_dbus_proxy_call_sync (proxy,
     504                                     "EmitSignal2",
     505                                     NULL,
     506                                     G_DBUS_CALL_FLAGS_NONE,
     507                                     -1,
     508                                     NULL,
     509                                     &error);
     510    g_assert_no_error (error);
     511    g_assert_nonnull (result);
     512    g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
     513    g_variant_unref (result);
     514  
     515    if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
     516      {
     517        /* and now wait for the signal that will never arrive */
     518        _g_assert_signal_received (proxy, "g-signal");
     519      }
     520    g_test_trap_assert_stderr ("*Dropping signal TestSignal2 of type (i) since the type from the expected interface is (u)*");
     521    g_test_trap_assert_failed();
     522  
     523    /* Our main branch will also do g_warning() when running the mainloop so
     524     * temporarily remove the expected interface
     525     */
     526    old_iface_info = g_dbus_proxy_get_interface_info (proxy);
     527    g_dbus_proxy_set_interface_info (proxy, NULL);
     528    _g_assert_signal_received (proxy, "g-signal");
     529    g_dbus_proxy_set_interface_info (proxy, old_iface_info);
     530  }
     531  
     532  static void
     533  test_bogus_property (GDBusProxy *proxy)
     534  {
     535    GError *error = NULL;
     536    GVariant *result;
     537    GDBusInterfaceInfo *old_iface_info;
     538  
     539    /* Make the service emit a PropertiesChanged signal for property 'i' of type 'i' - since
     540     * our introspection data has this as type 'u' we should get a warning on stderr.
     541     */
     542    result = g_dbus_proxy_call_sync (proxy,
     543                                     "FrobSetProperty",
     544                                     g_variant_new ("(sv)",
     545                                                    "i", g_variant_new_int32 (42)),
     546                                     G_DBUS_CALL_FLAGS_NONE,
     547                                     -1,
     548                                     NULL,
     549                                     &error);
     550    g_assert_no_error (error);
     551    g_assert_nonnull (result);
     552    g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
     553    g_variant_unref (result);
     554  
     555    if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
     556      {
     557        /* and now wait for the signal that will never arrive */
     558        _g_assert_signal_received (proxy, "g-properties-changed");
     559      }
     560    g_test_trap_assert_stderr ("*Received property i with type i does not match expected type u in the expected interface*");
     561    g_test_trap_assert_failed();
     562  
     563    /* Our main branch will also do g_warning() when running the mainloop so
     564     * temporarily remove the expected interface
     565     */
     566    old_iface_info = g_dbus_proxy_get_interface_info (proxy);
     567    g_dbus_proxy_set_interface_info (proxy, NULL);
     568    _g_assert_signal_received (proxy, "g-properties-changed");
     569    g_dbus_proxy_set_interface_info (proxy, old_iface_info);
     570  }
     571  #endif /* Disabled: see https://bugzilla.gnome.org/show_bug.cgi?id=658999 */
     572  
     573  /* ---------------------------------------------------------------------------------------------------- */
     574  
     575  static const gchar *frob_dbus_interface_xml =
     576    "<node>"
     577    "  <interface name='com.example.Frob'>"
     578    /* PairReturn() is deliberately different from gdbus-testserver's definition */
     579    "    <method name='PairReturn'>"
     580    "      <arg type='u' name='somenumber' direction='in'/>"
     581    "      <arg type='s' name='somestring' direction='out'/>"
     582    "    </method>"
     583    "    <method name='HelloWorld'>"
     584    "      <arg type='s' name='somestring' direction='in'/>"
     585    "      <arg type='s' name='somestring' direction='out'/>"
     586    "    </method>"
     587    "    <method name='Sleep'>"
     588    "      <arg type='i' name='timeout' direction='in'/>"
     589    "    </method>"
     590    /* We deliberately only mention a single property here */
     591    "    <property name='y' type='y' access='readwrite'/>"
     592    /* The 'i' property is deliberately different from gdbus-testserver's definition */
     593    "    <property name='i' type='u' access='readwrite'/>"
     594    /* ::TestSignal2 is deliberately different from gdbus-testserver's definition */
     595    "    <signal name='TestSignal2'>"
     596    "      <arg type='u' name='somenumber'/>"
     597    "    </signal>"
     598    "  </interface>"
     599    "</node>";
     600  static GDBusInterfaceInfo *frob_dbus_interface_info;
     601  
     602  static void
     603  test_expected_interface (GDBusProxy *proxy)
     604  {
     605    GVariant *value;
     606    GError *error;
     607  
     608    /* This is obviously wrong but expected interface is not set so we don't fail... */
     609    g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_string ("error_me_out!"));
     610    g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_byte (42));
     611    g_dbus_proxy_set_cached_property (proxy, "does-not-exist", g_variant_new_string ("something"));
     612    g_dbus_proxy_set_cached_property (proxy, "does-not-exist", NULL);
     613  
     614    /* Now repeat the method tests, with an expected interface set */
     615    g_dbus_proxy_set_interface_info (proxy, frob_dbus_interface_info);
     616    test_methods (proxy);
     617    test_signals (proxy);
     618  
     619    /* And also where we deliberately set the expected interface definition incorrectly */
     620    test_bogus_method_return (proxy);
     621    /* Disabled: see https://bugzilla.gnome.org/show_bug.cgi?id=658999
     622    test_bogus_signal (proxy);
     623    test_bogus_property (proxy);
     624    */
     625  
     626    if (g_test_undefined ())
     627      {
     628        /* Also check that we complain if setting a cached property of the wrong type */
     629        g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
     630                               "*Trying to set property y of type s but according to the expected interface the type is y*");
     631        value = g_variant_ref_sink (g_variant_new_string ("error_me_out!"));
     632        g_dbus_proxy_set_cached_property (proxy, "y", value);
     633        g_variant_unref (value);
     634        g_test_assert_expected_messages ();
     635      }
     636  
     637    /* this should work, however (since the type is correct) */
     638    g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_byte (42));
     639  
     640    if (g_test_undefined ())
     641      {
     642        /* Try to get the value of a property where the type we expect is different from
     643         * what we have in our cache (e.g. what the service returned)
     644         */
     645        g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
     646                               "*Trying to get property i with type i but according to the expected interface the type is u*");
     647        value = g_dbus_proxy_get_cached_property (proxy, "i");
     648        g_test_assert_expected_messages ();
     649      }
     650  
     651    /* Even if a property does not exist in expected_interface, looking it
     652     * up, or setting it, should never fail. Because it could be that the
     653     * property has been added to the service but the GDBusInterfaceInfo*
     654     * passed to g_dbus_proxy_set_interface_info() just haven't been updated.
     655     *
     656     * See https://bugzilla.gnome.org/show_bug.cgi?id=660886
     657     */
     658    value = g_dbus_proxy_get_cached_property (proxy, "d");
     659    g_assert_nonnull (value);
     660    g_assert_true (g_variant_is_of_type (value, G_VARIANT_TYPE_DOUBLE));
     661    g_assert_cmpfloat (g_variant_get_double (value), ==, 7.5);
     662    g_variant_unref (value);
     663    /* update it via the cached property... */
     664    g_dbus_proxy_set_cached_property (proxy, "d", g_variant_new_double (75.0));
     665    /* ... and finally check that it has changed */
     666    value = g_dbus_proxy_get_cached_property (proxy, "d");
     667    g_assert_nonnull (value);
     668    g_assert_true (g_variant_is_of_type (value, G_VARIANT_TYPE_DOUBLE));
     669    g_assert_cmpfloat (g_variant_get_double (value), ==, 75.0);
     670    g_variant_unref (value);
     671    /* now update it via the D-Bus interface... */
     672    error = NULL;
     673    value = g_dbus_proxy_call_sync (proxy, "FrobSetProperty",
     674                                    g_variant_new ("(sv)", "d", g_variant_new_double (85.0)),
     675                                    G_DBUS_CALL_FLAGS_NONE,
     676                                    -1, NULL, &error);
     677    g_assert_no_error (error);
     678    g_assert_nonnull (value);
     679    g_assert_cmpstr (g_variant_get_type_string (value), ==, "()");
     680    g_variant_unref (value);
     681    /* ...ensure we receive the ::PropertiesChanged signal... */
     682    _g_assert_signal_received (proxy, "g-properties-changed");
     683    /* ... and finally check that it has changed */
     684    value = g_dbus_proxy_get_cached_property (proxy, "d");
     685    g_assert_nonnull (value);
     686    g_assert_true (g_variant_is_of_type (value, G_VARIANT_TYPE_DOUBLE));
     687    g_assert_cmpfloat (g_variant_get_double (value), ==, 85.0);
     688    g_variant_unref (value);
     689  }
     690  
     691  static void
     692  test_basic (GDBusProxy *proxy)
     693  {
     694    GDBusConnection *connection;
     695    GDBusConnection *conn;
     696    GDBusProxyFlags flags;
     697    GDBusInterfaceInfo *info;
     698    gchar *name;
     699    gchar *path;
     700    gchar *interface;
     701    gint timeout;
     702  
     703    connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
     704  
     705    g_assert_true (g_dbus_proxy_get_connection (proxy) == connection);
     706    g_assert_null (g_dbus_proxy_get_interface_info (proxy));
     707    g_assert_cmpstr (g_dbus_proxy_get_name (proxy), ==, "com.example.TestService");
     708    g_assert_cmpstr (g_dbus_proxy_get_object_path (proxy), ==, "/com/example/TestObject");
     709    g_assert_cmpstr (g_dbus_proxy_get_interface_name (proxy), ==, "com.example.Frob");
     710    g_assert_cmpint (g_dbus_proxy_get_default_timeout (proxy), ==, -1);
     711  
     712    g_object_get (proxy,
     713                  "g-connection", &conn,
     714                  "g-interface-info", &info,
     715                  "g-flags", &flags,
     716                  "g-name", &name,
     717                  "g-object-path", &path,
     718                  "g-interface-name", &interface,
     719                  "g-default-timeout", &timeout,
     720                  NULL);
     721  
     722    g_assert_true (conn == connection);
     723    g_assert_null (info);
     724    g_assert_cmpint (flags, ==, g_dbus_proxy_get_flags (proxy));
     725    g_assert_cmpstr (name, ==, "com.example.TestService");
     726    g_assert_cmpstr (path, ==, "/com/example/TestObject");
     727    g_assert_cmpstr (interface, ==, "com.example.Frob");
     728    g_assert_cmpint (timeout, ==, -1);
     729  
     730    g_object_unref (conn);
     731    g_free (name);
     732    g_free (path);
     733    g_free (interface);
     734  
     735    g_object_unref (connection);
     736  }
     737  
     738  static void
     739  name_disappeared_cb (GDBusConnection *connection,
     740                       const gchar     *name,
     741                       gpointer         user_data)
     742  {
     743    gboolean *name_disappeared = user_data;
     744    *name_disappeared = TRUE;
     745    g_main_context_wakeup (NULL);
     746  }
     747  
     748  static void
     749  kill_test_service (GDBusConnection *connection)
     750  {
     751  #ifdef G_OS_UNIX
     752    guint pid;
     753    GVariant *ret;
     754    GError *error = NULL;
     755    const gchar *name = "com.example.TestService";
     756    guint watch_id;
     757    gboolean name_disappeared = FALSE;
     758  
     759    ret = g_dbus_connection_call_sync (connection,
     760                                       "org.freedesktop.DBus",
     761                                       "/org/freedesktop/DBus",
     762                                       "org.freedesktop.DBus",
     763                                       "GetConnectionUnixProcessID",
     764                                       g_variant_new ("(s)", name),
     765                                       NULL,
     766                                       G_DBUS_CALL_FLAGS_NONE,
     767                                       -1,
     768                                       NULL,
     769                                       &error);
     770    g_variant_get (ret, "(u)", &pid);
     771    g_variant_unref (ret);
     772  
     773    /* Watch the name and wait until it’s disappeared. */
     774    watch_id = g_bus_watch_name_on_connection (connection, name,
     775                                               G_BUS_NAME_WATCHER_FLAGS_NONE,
     776                                               NULL, name_disappeared_cb,
     777                                               &name_disappeared, NULL);
     778    kill (pid, SIGTERM);
     779  
     780    while (!name_disappeared)
     781      g_main_context_iteration (NULL, TRUE);
     782  
     783    g_bus_unwatch_name (watch_id);
     784  #else
     785    g_warning ("Can't kill com.example.TestService");
     786  #endif
     787  }
     788  
     789  static void
     790  test_proxy_with_flags (GDBusProxyFlags flags)
     791  {
     792    GDBusProxy *proxy;
     793    GDBusConnection *connection;
     794    GError *error;
     795    gchar *owner;
     796  
     797    error = NULL;
     798    connection = g_bus_get_sync (G_BUS_TYPE_SESSION,
     799                                 NULL,
     800                                 &error);
     801    g_assert_no_error (error);
     802    error = NULL;
     803    proxy = g_dbus_proxy_new_sync (connection,
     804                                   flags,
     805                                   NULL,                      /* GDBusInterfaceInfo */
     806                                   "com.example.TestService", /* name */
     807                                   "/com/example/TestObject", /* object path */
     808                                   "com.example.Frob",        /* interface */
     809                                   NULL, /* GCancellable */
     810                                   &error);
     811    g_assert_no_error (error);
     812  
     813    /* this is safe; we explicitly kill the service later on */
     814    g_assert_true (g_spawn_command_line_async (g_test_get_filename (G_TEST_BUILT, "gdbus-testserver", NULL), NULL));
     815  
     816    _g_assert_property_notify (proxy, "g-name-owner");
     817  
     818    test_basic (proxy);
     819    test_methods (proxy);
     820    test_properties (proxy);
     821    test_signals (proxy);
     822    test_expected_interface (proxy);
     823  
     824    kill_test_service (connection);
     825  
     826    owner = g_dbus_proxy_get_name_owner (proxy);
     827    g_assert_null (owner);
     828    g_free (owner);
     829  
     830    g_object_unref (proxy);
     831    g_object_unref (connection);
     832  }
     833  
     834  static void
     835  test_proxy (void)
     836  {
     837    test_proxy_with_flags (G_DBUS_PROXY_FLAGS_NONE);
     838  }
     839  
     840  /* ---------------------------------------------------------------------------------------------------- */
     841  
     842  static void
     843  proxy_ready (GObject      *source,
     844               GAsyncResult *result,
     845               gpointer      user_data)
     846  {
     847    GDBusProxy *proxy;
     848    GError *error;
     849    gchar *owner;
     850  
     851    error = NULL;
     852    proxy = g_dbus_proxy_new_for_bus_finish (result, &error);
     853    g_assert_no_error (error);
     854  
     855    owner = g_dbus_proxy_get_name_owner (proxy);
     856    g_assert_null (owner);
     857    g_free (owner);
     858  
     859    /* this is safe; we explicitly kill the service later on */
     860    g_assert_true (g_spawn_command_line_async (g_test_get_filename (G_TEST_BUILT, "gdbus-testserver", NULL), NULL));
     861  
     862    _g_assert_property_notify (proxy, "g-name-owner");
     863  
     864    test_basic (proxy);
     865    test_methods (proxy);
     866    test_properties (proxy);
     867    test_signals (proxy);
     868    test_expected_interface (proxy);
     869  
     870    kill_test_service (g_dbus_proxy_get_connection (proxy));
     871    g_object_unref (proxy);
     872    g_main_loop_quit (loop);
     873  }
     874  
     875  static gboolean
     876  fail_test (gpointer user_data)
     877  {
     878    g_assert_not_reached ();
     879  }
     880  
     881  static void
     882  test_async (void)
     883  {
     884    guint id;
     885  
     886    g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
     887                              G_DBUS_PROXY_FLAGS_NONE,
     888                              NULL,                      /* GDBusInterfaceInfo */
     889                              "com.example.TestService", /* name */
     890                              "/com/example/TestObject", /* object path */
     891                              "com.example.Frob",        /* interface */
     892                              NULL, /* GCancellable */
     893                              proxy_ready,
     894                              NULL);
     895  
     896    id = g_timeout_add (10000, fail_test, NULL);
     897    g_main_loop_run (loop);
     898  
     899    g_source_remove (id);
     900  }
     901  
     902  static void
     903  test_no_properties (void)
     904  {
     905    GDBusProxy *proxy;
     906    GError *error;
     907  
     908    error = NULL;
     909    proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
     910                                           G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
     911                                           NULL,                      /* GDBusInterfaceInfo */
     912                                           "com.example.TestService", /* name */
     913                                           "/com/example/TestObject", /* object path */
     914                                           "com.example.Frob",        /* interface */
     915                                           NULL, /* GCancellable */
     916                                           &error);
     917    g_assert_no_error (error);
     918  
     919    test_properties (proxy);
     920  
     921    g_object_unref (proxy);
     922  }
     923  
     924  static void
     925  check_error (GObject      *source,
     926               GAsyncResult *result,
     927               gpointer      user_data)
     928  {
     929    GError *error = NULL;
     930    GVariant *reply;
     931  
     932    reply = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error);
     933    g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
     934    g_assert_null (reply);
     935    g_error_free (error);
     936  
     937    g_main_loop_quit (loop);
     938  }
     939  
     940  static void
     941  test_wellknown_noauto (void)
     942  {
     943    GError *error = NULL;
     944    GDBusProxy *proxy;
     945    guint id;
     946  
     947    proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
     948                                           G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
     949                                           NULL, "some.name.that.does.not.exist",
     950                                           "/", "some.interface", NULL, &error);
     951    g_assert_no_error (error);
     952    g_assert_nonnull (proxy);
     953  
     954    g_dbus_proxy_call (proxy, "method", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, check_error, NULL);
     955    id = g_timeout_add (10000, fail_test, NULL);
     956    g_main_loop_run (loop);
     957    g_object_unref (proxy);
     958    g_source_remove (id);
     959  }
     960  
     961  typedef enum {
     962    ADD_MATCH,
     963    REMOVE_MATCH,
     964  } AddOrRemove;
     965  
     966  static void
     967  add_or_remove_match_rule (GDBusConnection *connection,
     968                            AddOrRemove      add_or_remove,
     969                            GVariant        *match_rule)
     970  {
     971    GDBusMessage *message = NULL;
     972    GError *error = NULL;
     973  
     974    message = g_dbus_message_new_method_call ("org.freedesktop.DBus", /* name */
     975                                              "/org/freedesktop/DBus", /* path */
     976                                              "org.freedesktop.DBus", /* interface */
     977                                              (add_or_remove == ADD_MATCH) ? "AddMatch" : "RemoveMatch");
     978    g_dbus_message_set_body (message, match_rule);
     979    g_dbus_connection_send_message (connection,
     980                                    message,
     981                                    G_DBUS_SEND_MESSAGE_FLAGS_NONE,
     982                                    NULL,
     983                                    &error);
     984    g_assert_no_error (error);
     985    g_clear_object (&message);
     986  }
     987  
     988  static void
     989  test_proxy_no_match_rule (void)
     990  {
     991    GDBusConnection *connection = NULL;
     992    GVariant *match_rule = NULL;
     993  
     994    g_test_summary ("Test that G_DBUS_PROXY_FLAGS_NO_MATCH_RULE works");
     995    g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/1109");
     996  
     997    connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
     998  
     999    /* Add a custom match rule which matches everything. */
    1000    match_rule = g_variant_ref_sink (g_variant_new ("(s)", "type='signal'"));
    1001    add_or_remove_match_rule (connection, ADD_MATCH, match_rule);
    1002  
    1003    /* Run the tests. */
    1004    test_proxy_with_flags (G_DBUS_PROXY_FLAGS_NO_MATCH_RULE);
    1005  
    1006    /* Remove the match rule again. */
    1007    add_or_remove_match_rule (connection, REMOVE_MATCH, match_rule);
    1008  
    1009    g_clear_pointer (&match_rule, g_variant_unref);
    1010    g_clear_object (&connection);
    1011  }
    1012  
    1013  int
    1014  main (int   argc,
    1015        char *argv[])
    1016  {
    1017    gint ret;
    1018    GDBusNodeInfo *introspection_data = NULL;
    1019  
    1020    g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
    1021  
    1022    introspection_data = g_dbus_node_info_new_for_xml (frob_dbus_interface_xml, NULL);
    1023    g_assert_nonnull (introspection_data);
    1024    frob_dbus_interface_info = introspection_data->interfaces[0];
    1025  
    1026    /* all the tests rely on a shared main loop */
    1027    loop = g_main_loop_new (NULL, FALSE);
    1028  
    1029    g_test_add_func ("/gdbus/proxy", test_proxy);
    1030    g_test_add_func ("/gdbus/proxy/no-properties", test_no_properties);
    1031    g_test_add_func ("/gdbus/proxy/wellknown-noauto", test_wellknown_noauto);
    1032    g_test_add_func ("/gdbus/proxy/async", test_async);
    1033    g_test_add_func ("/gdbus/proxy/no-match-rule", test_proxy_no_match_rule);
    1034  
    1035    ret = session_bus_run();
    1036  
    1037    g_dbus_node_info_unref (introspection_data);
    1038    g_main_loop_unref (loop);
    1039  
    1040    return ret;
    1041  }