1 /* Feature test for ConnectionError signal emission
2  *
3  * Copyright (C) 2009 Collabora Ltd. <http://www.collabora.co.uk/>
4  * Copyright (C) 2009 Nokia Corporation
5  *
6  * Copying and distribution of this file, with or without modification,
7  * are permitted in any medium without royalty provided the copyright
8  * notice and this notice are preserved.
9  */
10 
11 #include "config.h"
12 
13 #include <telepathy-glib/connection.h>
14 #include <telepathy-glib/dbus.h>
15 #include <telepathy-glib/debug.h>
16 #include <telepathy-glib/interfaces.h>
17 #include <telepathy-glib/proxy-subclass.h>
18 #include <telepathy-glib/util.h>
19 
20 #include "tests/lib/myassert.h"
21 #include "tests/lib/simple-conn.h"
22 #include "tests/lib/util.h"
23 
24 static int connection_errors;
25 
26 static void
on_connection_error(TpConnection * conn,const gchar * error,GHashTable * details,gpointer user_data,GObject * weak_object)27 on_connection_error (TpConnection *conn,
28                      const gchar *error,
29                      GHashTable *details,
30                      gpointer user_data,
31                      GObject *weak_object)
32 {
33   connection_errors++;
34   g_assert_cmpstr (error, ==, "com.example.DomainSpecificError");
35   g_assert_cmpuint (g_hash_table_size (details), ==, 0);
36 }
37 
38 static void
on_status_changed(TpConnection * conn,guint status,guint reason,gpointer user_data,GObject * weak_object)39 on_status_changed (TpConnection *conn,
40                    guint status,
41                    guint reason,
42                    gpointer user_data,
43                    GObject *weak_object)
44 {
45   g_assert_cmpuint (status, ==, TP_CONNECTION_STATUS_DISCONNECTED);
46   g_assert_cmpuint (reason, ==, TP_CONNECTION_STATUS_REASON_NETWORK_ERROR);
47   g_main_loop_quit (user_data);
48 }
49 
50 typedef enum
51 {
52   DOMAIN_SPECIFIC_ERROR = 0,
53 } ExampleError;
54 
55 /* example_com_error_get_type relies on this */
56 G_STATIC_ASSERT (sizeof (GType) <= sizeof (gsize));
57 
58 static GType
example_com_error_get_type(void)59 example_com_error_get_type (void)
60 {
61   static gsize type = 0;
62 
63   if (g_once_init_enter (&type))
64     {
65       static const GEnumValue values[] = {
66             { DOMAIN_SPECIFIC_ERROR, "DOMAIN_SPECIFIC_ERROR",
67               "DomainSpecificError" },
68             { 0 }
69       };
70       GType gtype;
71 
72       gtype = g_enum_register_static ("ExampleError", values);
73       g_once_init_leave (&type, gtype);
74     }
75 
76   return (GType) type;
77 }
78 
79 static GQuark
example_com_error_quark(void)80 example_com_error_quark (void)
81 {
82   static gsize quark = 0;
83 
84   if (g_once_init_enter (&quark))
85     {
86       GQuark domain = g_quark_from_static_string ("com.example");
87 
88       g_assert (sizeof (GQuark) <= sizeof (gsize));
89 
90       dbus_g_error_domain_register (domain, "com.example",
91           example_com_error_get_type ());
92       g_once_init_leave (&quark, domain);
93     }
94 
95   return (GQuark) quark;
96 }
97 
98 typedef struct {
99   TpDBusDaemon *dbus;
100   GMainLoop *mainloop;
101   TpTestsSimpleConnection *service_conn;
102   TpBaseConnection *service_conn_as_base;
103   gchar *conn_name;
104   gchar *conn_path;
105   TpConnection *conn;
106 } Test;
107 
108 static void
global_setup(void)109 global_setup (void)
110 {
111   static gboolean done = FALSE;
112 
113   if (done)
114     return;
115 
116   done = TRUE;
117 
118   tp_debug_set_flags ("all");
119 
120   tp_proxy_subclass_add_error_mapping (TP_TYPE_CONNECTION,
121       "com.example", example_com_error_quark (), example_com_error_get_type ());
122 }
123 
124 static void
setup(Test * test,gconstpointer nil G_GNUC_UNUSED)125 setup (Test *test,
126     gconstpointer nil G_GNUC_UNUSED)
127 {
128   GError *error = NULL;
129 
130   global_setup ();
131 
132   test->mainloop = g_main_loop_new (NULL, FALSE);
133   test->dbus = tp_tests_dbus_daemon_dup_or_die ();
134 
135   test->service_conn = TP_TESTS_SIMPLE_CONNECTION (
136       tp_tests_object_new_static_class (
137         TP_TESTS_TYPE_SIMPLE_CONNECTION,
138         "account", "me@example.com",
139         "protocol", "simple",
140         NULL));
141   test->service_conn_as_base = TP_BASE_CONNECTION (test->service_conn);
142   MYASSERT (test->service_conn != NULL, "");
143   MYASSERT (test->service_conn_as_base != NULL, "");
144 
145   MYASSERT (tp_base_connection_register (test->service_conn_as_base, "simple",
146         &test->conn_name, &test->conn_path, &error), "");
147   g_assert_no_error (error);
148 
149   test->conn = tp_connection_new (test->dbus, test->conn_name, test->conn_path,
150       &error);
151   MYASSERT (test->conn != NULL, "");
152   g_assert_no_error (error);
153   MYASSERT (tp_connection_run_until_ready (test->conn, TRUE, &error, NULL),
154       "");
155   g_assert_no_error (error);
156 }
157 
158 static void
teardown(Test * test,gconstpointer nil G_GNUC_UNUSED)159 teardown (Test *test,
160     gconstpointer nil G_GNUC_UNUSED)
161 {
162   GAsyncResult *result = NULL;
163 
164   tp_connection_disconnect_async (test->conn, tp_tests_result_ready_cb,
165       &result);
166   tp_tests_run_until_result (&result);
167   /* Ignore success/failure: it might already have gone */
168   g_object_unref (result);
169 
170   test->service_conn_as_base = NULL;
171   g_object_unref (test->service_conn);
172   g_free (test->conn_name);
173   g_free (test->conn_path);
174   g_object_unref (test->dbus);
175   g_main_loop_unref (test->mainloop);
176 }
177 
178 static void
test_registered_error(Test * test,gconstpointer nil G_GNUC_UNUSED)179 test_registered_error (Test *test,
180     gconstpointer nil G_GNUC_UNUSED)
181 {
182   GError *error = NULL;
183   const GHashTable *asv;
184 
185   asv = GUINT_TO_POINTER (0xDEADBEEF);
186   g_assert_cmpstr (tp_connection_get_detailed_error (test->conn, NULL), ==,
187       NULL);
188   g_assert_cmpstr (tp_connection_get_detailed_error (test->conn, &asv), ==,
189       NULL);
190   g_assert_cmpuint (GPOINTER_TO_UINT (asv), ==, 0xDEADBEEF);
191 
192   connection_errors = 0;
193   tp_cli_connection_connect_to_connection_error (test->conn,
194       on_connection_error, NULL, NULL, NULL, NULL);
195   tp_cli_connection_connect_to_status_changed (test->conn, on_status_changed,
196       test->mainloop, NULL, NULL, NULL);
197 
198   tp_base_connection_disconnect_with_dbus_error (test->service_conn_as_base,
199       "com.example.DomainSpecificError", NULL,
200       TP_CONNECTION_STATUS_REASON_NETWORK_ERROR);
201 
202   g_main_loop_run (test->mainloop);
203 
204   g_assert_cmpuint (connection_errors, ==, 1);
205 
206   MYASSERT (!tp_connection_run_until_ready (test->conn, FALSE, &error, NULL),
207       "");
208 
209   g_assert_error (error, example_com_error_quark (), DOMAIN_SPECIFIC_ERROR);
210 
211   g_assert_cmpstr (tp_connection_get_detailed_error (test->conn, NULL), ==,
212       "com.example.DomainSpecificError");
213   g_assert_cmpstr (tp_connection_get_detailed_error (test->conn, &asv), ==,
214       "com.example.DomainSpecificError");
215   g_assert (asv != NULL);
216 
217   g_assert_cmpstr (g_quark_to_string (error->domain), ==,
218       g_quark_to_string (example_com_error_quark ()));
219   g_assert_cmpuint (error->code, ==, DOMAIN_SPECIFIC_ERROR);
220   g_error_free (error);
221   error = NULL;
222 }
223 
224 static void
on_unregistered_connection_error(TpConnection * conn,const gchar * error,GHashTable * details,gpointer user_data,GObject * weak_object)225 on_unregistered_connection_error (TpConnection *conn,
226     const gchar *error,
227     GHashTable *details,
228     gpointer user_data,
229     GObject *weak_object)
230 {
231   connection_errors++;
232   g_assert_cmpstr (error, ==, "net.example.WTF");
233   g_assert_cmpuint (g_hash_table_size (details), ==, 0);
234 }
235 
236 static void
test_unregistered_error(Test * test,gconstpointer nil G_GNUC_UNUSED)237 test_unregistered_error (Test *test,
238     gconstpointer nil G_GNUC_UNUSED)
239 {
240   GError *error = NULL;
241   const GHashTable *asv;
242 
243   connection_errors = 0;
244   tp_cli_connection_connect_to_connection_error (test->conn,
245       on_unregistered_connection_error, NULL, NULL, NULL, NULL);
246   tp_cli_connection_connect_to_status_changed (test->conn, on_status_changed,
247       test->mainloop, NULL, NULL, NULL);
248 
249   tp_base_connection_disconnect_with_dbus_error (test->service_conn_as_base,
250       "net.example.WTF", NULL,
251       TP_CONNECTION_STATUS_REASON_NETWORK_ERROR);
252 
253   g_main_loop_run (test->mainloop);
254 
255   g_assert_cmpuint (connection_errors, ==, 1);
256 
257   MYASSERT (!tp_connection_run_until_ready (test->conn, FALSE, &error, NULL),
258       "");
259 
260   /* Because we didn't understand net.example.WTF as a GError, TpConnection
261    * falls back to turning the Connection_Status_Reason into a GError. */
262   g_assert_error (error, TP_ERROR, TP_ERROR_NETWORK_ERROR);
263 
264   g_assert_cmpstr (tp_connection_get_detailed_error (test->conn, NULL), ==,
265       "net.example.WTF");
266   g_assert_cmpstr (tp_connection_get_detailed_error (test->conn, &asv), ==,
267       "net.example.WTF");
268   g_assert (asv != NULL);
269 
270   g_error_free (error);
271   error = NULL;
272 }
273 
274 static void
on_detailed_connection_error(TpConnection * conn,const gchar * error,GHashTable * details,gpointer user_data,GObject * weak_object)275 on_detailed_connection_error (TpConnection *conn,
276     const gchar *error,
277     GHashTable *details,
278     gpointer user_data,
279     GObject *weak_object)
280 {
281   connection_errors++;
282   g_assert_cmpstr (error, ==, "com.example.DomainSpecificError");
283   g_assert_cmpuint (g_hash_table_size (details), ==, 2);
284 }
285 
286 static void
test_detailed_error(Test * test,gconstpointer mode)287 test_detailed_error (Test *test,
288     gconstpointer mode)
289 {
290   GError *error = NULL;
291   const GHashTable *asv;
292   gchar *str;
293   GVariant *variant;
294   gboolean ok;
295   gint32 bees;
296 
297   asv = GUINT_TO_POINTER (0xDEADBEEF);
298   g_assert_cmpstr (tp_connection_get_detailed_error (test->conn, NULL), ==,
299       NULL);
300   g_assert_cmpstr (tp_connection_get_detailed_error (test->conn, &asv), ==,
301       NULL);
302   g_assert_cmpuint (GPOINTER_TO_UINT (asv), ==, 0xDEADBEEF);
303 
304   connection_errors = 0;
305   tp_cli_connection_connect_to_connection_error (test->conn,
306       on_detailed_connection_error, NULL, NULL, NULL, NULL);
307   tp_cli_connection_connect_to_status_changed (test->conn, on_status_changed,
308       test->mainloop, NULL, NULL, NULL);
309 
310   if (!tp_strdiff (mode, "variant"))
311     {
312       GVariant *details = g_variant_parse (G_VARIANT_TYPE_VARDICT,
313           "{ 'debug-message': <'not enough bees'>, "
314           " 'bees-required': <2342> }", NULL, NULL, &error);
315 
316       g_assert_no_error (error);
317 
318       tp_base_connection_disconnect_with_dbus_error_vardict (
319           test->service_conn_as_base,
320           "com.example.DomainSpecificError",
321           details,
322           TP_CONNECTION_STATUS_REASON_NETWORK_ERROR);
323       g_variant_unref (details);
324     }
325   else
326     {
327       GHashTable *details = tp_asv_new (
328           "debug-message", G_TYPE_STRING, "not enough bees",
329           "bees-required", G_TYPE_INT, 2342,
330           NULL);
331 
332       tp_base_connection_disconnect_with_dbus_error (
333           test->service_conn_as_base,
334           "com.example.DomainSpecificError",
335           details,
336           TP_CONNECTION_STATUS_REASON_NETWORK_ERROR);
337       g_hash_table_unref (details);
338     }
339 
340   g_main_loop_run (test->mainloop);
341 
342   g_assert_cmpuint (connection_errors, ==, 1);
343 
344   MYASSERT (!tp_connection_run_until_ready (test->conn, FALSE, &error, NULL),
345       "");
346 
347   g_assert_error (error, example_com_error_quark (), DOMAIN_SPECIFIC_ERROR);
348 
349   g_assert_cmpstr (tp_connection_get_detailed_error (test->conn, NULL), ==,
350       "com.example.DomainSpecificError");
351   g_assert_cmpstr (tp_connection_get_detailed_error (test->conn, &asv), ==,
352       "com.example.DomainSpecificError");
353   g_assert (asv != NULL);
354   g_assert_cmpstr (tp_asv_get_string (asv, "debug-message"), ==,
355       "not enough bees");
356   g_assert_cmpint (tp_asv_get_int32 (asv, "bees-required", NULL), ==, 2342);
357 
358   str = tp_connection_dup_detailed_error_vardict (test->conn, NULL);
359   g_assert_cmpstr (str, ==, "com.example.DomainSpecificError");
360   g_free (str);
361   str = tp_connection_dup_detailed_error_vardict (test->conn, &variant);
362   g_assert_cmpstr (str, ==, "com.example.DomainSpecificError");
363   g_free (str);
364   g_assert (variant != NULL);
365   ok = g_variant_lookup (variant, "debug-message", "s", &str);
366   g_assert (ok);
367   g_assert_cmpstr (str, ==, "not enough bees");
368   g_free (str);
369   ok = g_variant_lookup (variant, "bees-required", "i", &bees);
370   g_assert (ok);
371   g_assert_cmpint (bees, ==, 2342);
372 
373   g_assert_cmpstr (g_quark_to_string (error->domain), ==,
374       g_quark_to_string (example_com_error_quark ()));
375   g_assert_cmpuint (error->code, ==, DOMAIN_SPECIFIC_ERROR);
376   g_error_free (error);
377   error = NULL;
378 }
379 
380 int
main(int argc,char ** argv)381 main (int argc,
382       char **argv)
383 {
384   tp_tests_abort_after (10);
385   g_test_init (&argc, &argv, NULL);
386 
387   g_test_add ("/connection/registered-error", Test, NULL, setup,
388       test_registered_error, teardown);
389   g_test_add ("/connection/unregistered-error", Test, NULL, setup,
390       test_unregistered_error, teardown);
391   g_test_add ("/connection/detailed-error", Test, NULL, setup,
392       test_detailed_error, teardown);
393   g_test_add ("/connection/detailed-error-vardict", Test, "variant", setup,
394       test_detailed_error, teardown);
395 
396   return tp_tests_run_with_bus ();
397 }
398