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