1 /* Feature test for https://bugs.freedesktop.org/show_bug.cgi?id=15300
2  *
3  * Copyright (C) 2007-2008 Collabora Ltd. <http://www.collabora.co.uk/>
4  * Copyright (C) 2007-2008 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 
19 #include "tests/lib/myassert.h"
20 #include "tests/lib/simple-conn.h"
21 #include "tests/lib/util.h"
22 
23 typedef struct {
24     TpDBusDaemon *dbus;
25     TpTestsSimpleConnection *service_conn;
26     TpBaseConnection *service_conn_as_base;
27     gchar *conn_name;
28     gchar *conn_path;
29     TpConnection *conn;
30 
31     gboolean cwr_ready;
32     GError *cwr_error /* initialized in setup */;
33 
34     GAsyncResult *prepare_result;
35 } Test;
36 
37 static GError invalidated_for_test = { 0, TP_ERROR_PERMISSION_DENIED,
38       "No connection for you!" };
39 
40 static void
connection_prepared_cb(GObject * object,GAsyncResult * res,gpointer user_data)41 connection_prepared_cb (GObject *object,
42     GAsyncResult *res,
43     gpointer user_data)
44 {
45   Test *test = user_data;
46 
47   g_message ("%p prepared", object);
48   g_assert (test->prepare_result == NULL);
49   test->prepare_result = g_object_ref (res);
50 }
51 
52 static void
setup(Test * test,gconstpointer data)53 setup (Test *test,
54     gconstpointer data)
55 {
56   GError *error = NULL;
57 
58   invalidated_for_test.domain = TP_ERROR;
59 
60   tp_debug_set_flags ("all");
61   test->dbus = tp_tests_dbus_daemon_dup_or_die ();
62 
63   test->service_conn = TP_TESTS_SIMPLE_CONNECTION (
64     tp_tests_object_new_static_class (
65         TP_TESTS_TYPE_SIMPLE_CONNECTION,
66         "account", "me@example.com",
67         "protocol", "simple-protocol",
68         NULL));
69   test->service_conn_as_base = TP_BASE_CONNECTION (test->service_conn);
70   g_assert (test->service_conn != NULL);
71   g_assert (test->service_conn_as_base != NULL);
72 
73   g_assert (tp_base_connection_register (test->service_conn_as_base, "simple",
74         &test->conn_name, &test->conn_path, &error));
75   g_assert_no_error (error);
76 
77   test->cwr_ready = FALSE;
78   test->cwr_error = NULL;
79 }
80 
81 static void
teardown(Test * test,gconstpointer data)82 teardown (Test *test,
83     gconstpointer data)
84 {
85   TpConnection *conn;
86   GError *error = NULL;
87 
88   if (test->conn != NULL)
89     {
90       g_object_unref (test->conn);
91       test->conn = NULL;
92     }
93 
94   /* disconnect the connection so we don't leak it */
95   conn = tp_connection_new (test->dbus, test->conn_name, test->conn_path,
96       &error);
97   g_assert (conn != NULL);
98   g_assert_no_error (error);
99 
100   tp_tests_connection_assert_disconnect_succeeds (conn);
101 
102   g_assert (!tp_connection_run_until_ready (conn, FALSE, &error, NULL));
103   g_assert_error (error, TP_ERROR, TP_ERROR_CANCELLED);
104   g_clear_error (&error);
105 
106   test->service_conn_as_base = NULL;
107   g_object_unref (test->service_conn);
108   g_free (test->conn_name);
109   g_free (test->conn_path);
110 
111   g_object_unref (test->dbus);
112   test->dbus = NULL;
113 }
114 
115 static void
test_run_until_invalid(Test * test,gconstpointer nil G_GNUC_UNUSED)116 test_run_until_invalid (Test *test,
117     gconstpointer nil G_GNUC_UNUSED)
118 {
119   GError *error = NULL;
120 
121   test->conn = tp_connection_new (test->dbus, test->conn_name, test->conn_path,
122       &error);
123   g_assert (test->conn != NULL);
124   g_assert_no_error (error);
125   tp_proxy_invalidate ((TpProxy *) test->conn, &invalidated_for_test);
126 
127   MYASSERT (!tp_connection_run_until_ready (test->conn, TRUE, &error, NULL),
128       "");
129   g_assert (error != NULL);
130   g_assert_error (error, invalidated_for_test.domain,
131       invalidated_for_test.code);
132   g_assert_cmpstr (error->message, ==, invalidated_for_test.message);
133   g_error_free (error);
134 }
135 
136 static void
test_run_until_ready(Test * test,gconstpointer nil G_GNUC_UNUSED)137 test_run_until_ready (Test *test,
138     gconstpointer nil G_GNUC_UNUSED)
139 {
140   GError *error = NULL;
141 
142   test->conn = tp_connection_new (test->dbus, test->conn_name, test->conn_path,
143       &error);
144   g_assert (test->conn != NULL);
145   g_assert_no_error (error);
146 
147   MYASSERT (tp_connection_run_until_ready (test->conn, TRUE, &error, NULL),
148       "");
149   g_assert_no_error (error);
150 }
151 
152 static void
conn_ready(TpConnection * connection,const GError * error,gpointer user_data)153 conn_ready (TpConnection *connection,
154             const GError *error,
155             gpointer user_data)
156 {
157   Test *test = user_data;
158 
159   test->cwr_ready = TRUE;
160 
161   if (error == NULL)
162     {
163       gboolean parsed;
164       gchar *proto = NULL;
165       gchar *cm_name = NULL;
166 
167       g_message ("connection %p ready", connection);
168       parsed = tp_connection_parse_object_path (connection, &proto, &cm_name);
169       g_assert (parsed);
170       g_assert_cmpstr (proto, ==, "simple-protocol");
171       g_assert_cmpstr (cm_name, ==, "simple");
172       g_free (proto);
173       g_free (cm_name);
174     }
175   else
176     {
177       g_message ("connection %p invalidated: %s #%u \"%s\"", connection,
178           g_quark_to_string (error->domain), error->code, error->message);
179 
180       test->cwr_error = g_error_copy (error);
181     }
182 }
183 
184 static void
test_prepare(Test * test,gconstpointer nil G_GNUC_UNUSED)185 test_prepare (Test *test,
186     gconstpointer nil G_GNUC_UNUSED)
187 {
188   GError *error = NULL;
189   GQuark features[] = { TP_CONNECTION_FEATURE_CONNECTED,
190       TP_CONNECTION_FEATURE_CAPABILITIES, 0 };
191   TpConnectionStatusReason reason;
192   TpCapabilities *caps;
193   GPtrArray *classes;
194   gchar *cm_name, *protocol_name;
195 
196   test->conn = tp_connection_new (test->dbus, test->conn_name, test->conn_path,
197       &error);
198   g_assert (test->conn != NULL);
199   g_assert_no_error (error);
200 
201   g_assert (!tp_proxy_is_prepared (test->conn, TP_CONNECTION_FEATURE_CORE));
202   g_assert (!tp_proxy_is_prepared (test->conn,
203         TP_CONNECTION_FEATURE_CONNECTED));
204 
205   tp_proxy_prepare_async (test->conn, NULL, connection_prepared_cb, test);
206   /* this is not synchronous */
207   g_assert (test->prepare_result == NULL);
208   g_assert (!tp_proxy_is_prepared (test->conn, TP_CONNECTION_FEATURE_CORE));
209 
210   while (test->prepare_result == NULL)
211     g_main_context_iteration (NULL, TRUE);
212 
213   g_assert (tp_proxy_prepare_finish (test->conn, test->prepare_result,
214         &error));
215   g_assert_no_error (error);
216   g_object_unref (test->prepare_result);
217   test->prepare_result = NULL;
218 
219   g_assert (tp_proxy_is_prepared (test->conn, TP_CONNECTION_FEATURE_CORE));
220   g_assert (!tp_proxy_is_prepared (test->conn,
221         TP_CONNECTION_FEATURE_CONNECTED));
222   g_assert_cmpuint (tp_connection_get_self_handle (test->conn), ==, 0);
223   g_assert_cmpint (tp_connection_get_status (test->conn, NULL), ==,
224       TP_CONNECTION_STATUS_DISCONNECTED);
225 
226   g_assert_cmpstr (tp_connection_get_cm_name (test->conn), ==,
227           "simple");
228   g_assert_cmpstr (tp_connection_get_protocol_name (test->conn), ==,
229           "simple-protocol");
230 
231   g_object_get (test->conn,
232       "cm-name", &cm_name,
233       "protocol-name", &protocol_name,
234       NULL);
235   g_assert_cmpstr (cm_name, ==, "simple");
236   g_assert_cmpstr (protocol_name, ==, "simple-protocol");
237   g_free (cm_name);
238   g_free (protocol_name);
239 
240   tp_cli_connection_call_connect (test->conn, -1, NULL, NULL, NULL, NULL);
241 
242   tp_proxy_prepare_async (test->conn, features, connection_prepared_cb, test);
243 
244   while (test->prepare_result == NULL)
245     g_main_context_iteration (NULL, TRUE);
246 
247   g_assert (tp_proxy_prepare_finish (test->conn, test->prepare_result,
248         &error));
249   g_assert_no_error (error);
250   g_object_unref (test->prepare_result);
251   test->prepare_result = NULL;
252 
253   g_assert (tp_proxy_is_prepared (test->conn, TP_CONNECTION_FEATURE_CORE));
254   g_assert (tp_proxy_is_prepared (test->conn,
255         TP_CONNECTION_FEATURE_CONNECTED));
256   g_assert (tp_proxy_is_prepared (test->conn,
257         TP_CONNECTION_FEATURE_CAPABILITIES));
258   g_assert_cmpuint (tp_connection_get_self_handle (test->conn), !=, 0);
259   g_assert_cmpint (tp_connection_get_status (test->conn, &reason), ==,
260       TP_CONNECTION_STATUS_CONNECTED);
261   g_assert_cmpint (reason, ==, TP_CONNECTION_STATUS_REASON_REQUESTED);
262 
263   caps = tp_connection_get_capabilities (test->conn);
264   g_assert (caps != NULL);
265   classes = tp_capabilities_get_channel_classes (caps);
266   g_assert (classes != NULL);
267   g_assert_cmpint (classes->len, ==, 0);
268 }
269 
270 static void
test_fail_to_prepare(Test * test,gconstpointer nil G_GNUC_UNUSED)271 test_fail_to_prepare (Test *test,
272     gconstpointer nil G_GNUC_UNUSED)
273 {
274   GError *error = NULL;
275   GQuark features[] = { TP_CONNECTION_FEATURE_CONNECTED, 0 };
276   const GHashTable *asv;
277 
278   test->conn = tp_connection_new (test->dbus, test->conn_name, test->conn_path,
279       &error);
280   g_assert (test->conn != NULL);
281   g_assert_no_error (error);
282 
283   g_assert (!tp_proxy_is_prepared (test->conn, TP_CONNECTION_FEATURE_CORE));
284   g_assert (!tp_proxy_is_prepared (test->conn,
285         TP_CONNECTION_FEATURE_CONNECTED));
286 
287   tp_proxy_prepare_async (test->conn, NULL, connection_prepared_cb, test);
288   tp_cli_connection_call_connect (test->conn, -1, NULL, NULL, NULL, NULL);
289   tp_proxy_invalidate ((TpProxy *) test->conn, &invalidated_for_test);
290   /* this is not synchronous */
291   g_assert (test->prepare_result == NULL);
292   g_assert (!tp_proxy_is_prepared (test->conn, TP_CONNECTION_FEATURE_CORE));
293 
294   while (test->prepare_result == NULL)
295     g_main_context_iteration (NULL, TRUE);
296 
297   g_assert (!tp_proxy_prepare_finish (test->conn, test->prepare_result,
298         &error));
299   g_assert_error (error, TP_ERROR, TP_ERROR_PERMISSION_DENIED);
300   g_clear_error (&error);
301   g_object_unref (test->prepare_result);
302   test->prepare_result = NULL;
303 
304   g_assert (!tp_proxy_is_prepared (test->conn, TP_CONNECTION_FEATURE_CORE));
305   g_assert (!tp_proxy_is_prepared (test->conn,
306         TP_CONNECTION_FEATURE_CONNECTED));
307 
308   /* it's not synchronous even if we were already invalidated */
309   tp_proxy_prepare_async (test->conn, features, connection_prepared_cb, test);
310   g_assert (test->prepare_result == NULL);
311 
312   while (test->prepare_result == NULL)
313     g_main_context_iteration (NULL, TRUE);
314 
315   g_assert (!tp_proxy_prepare_finish (test->conn, test->prepare_result,
316         &error));
317   g_assert_error (error, TP_ERROR, TP_ERROR_PERMISSION_DENIED);
318   g_clear_error (&error);
319   g_object_unref (test->prepare_result);
320   test->prepare_result = NULL;
321 
322   g_assert (!tp_proxy_is_prepared (test->conn, TP_CONNECTION_FEATURE_CORE));
323   g_assert (!tp_proxy_is_prepared (test->conn,
324         TP_CONNECTION_FEATURE_CONNECTED));
325 
326   g_assert_cmpstr (tp_connection_get_detailed_error (test->conn, NULL), ==,
327       TP_ERROR_STR_PERMISSION_DENIED);
328   g_assert_cmpstr (tp_connection_get_detailed_error (test->conn, &asv), ==,
329       TP_ERROR_STR_PERMISSION_DENIED);
330   g_assert (asv != NULL);
331 }
332 
333 static void
test_call_when_ready(Test * test,gconstpointer nil G_GNUC_UNUSED)334 test_call_when_ready (Test *test,
335     gconstpointer nil G_GNUC_UNUSED)
336 {
337   GError *error = NULL;
338 
339   test->conn = tp_connection_new (test->dbus, test->conn_name, test->conn_path,
340       &error);
341   g_assert (test->conn != NULL);
342   g_assert_no_error (error);
343 
344   tp_cli_connection_call_connect (test->conn, -1, NULL, NULL, NULL, NULL);
345 
346   tp_connection_call_when_ready (test->conn, conn_ready, test);
347 
348   while (!test->cwr_ready)
349     g_main_context_iteration (NULL, TRUE);
350 
351   g_assert_no_error (test->cwr_error);
352 
353   /* Connection already ready here, so we are called back synchronously */
354 
355   test->cwr_ready = FALSE;
356   test->cwr_error = NULL;
357   tp_connection_call_when_ready (test->conn, conn_ready, test);
358   g_assert_cmpint (test->cwr_ready, ==, TRUE);
359   g_assert_no_error (test->cwr_error);
360 }
361 
362 static void
test_call_when_invalid(Test * test,gconstpointer nil G_GNUC_UNUSED)363 test_call_when_invalid (Test *test,
364     gconstpointer nil G_GNUC_UNUSED)
365 {
366   GError *error = NULL;
367 
368   test->conn = tp_connection_new (test->dbus, test->conn_name, test->conn_path,
369       &error);
370   g_assert (test->conn != NULL);
371   g_assert_no_error (error);
372 
373   /* Connection becomes invalid, so we are called back synchronously */
374 
375   tp_connection_call_when_ready (test->conn, conn_ready, test);
376   tp_proxy_invalidate ((TpProxy *) test->conn, &invalidated_for_test);
377   g_assert_cmpint (test->cwr_ready, ==, TRUE);
378   g_assert_error (test->cwr_error, invalidated_for_test.domain,
379       invalidated_for_test.code);
380   g_assert_cmpstr (test->cwr_error->message, ==, invalidated_for_test.message);
381   g_clear_error (&test->cwr_error);
382 
383   /* Connection already invalid, so we are called back synchronously */
384 
385   test->cwr_ready = FALSE;
386   test->cwr_error = NULL;
387   tp_connection_call_when_ready (test->conn, conn_ready, test);
388   g_assert (test->cwr_ready);
389   g_assert_error (test->cwr_error, invalidated_for_test.domain,
390       invalidated_for_test.code);
391   g_assert_cmpstr (test->cwr_error->message, ==, invalidated_for_test.message);
392   g_error_free (test->cwr_error);
393   test->cwr_error = NULL;
394 }
395 
396 static void
test_object_path(Test * test,gconstpointer nil G_GNUC_UNUSED)397 test_object_path (Test *test,
398     gconstpointer nil G_GNUC_UNUSED)
399 {
400   const gchar *invalid_path = TP_CONN_OBJECT_PATH_BASE "invalid";
401   const gchar *invalid_name = TP_CONN_BUS_NAME_BASE "invalid";
402   TpConnection *connection;
403   GError *error = NULL;
404 
405   test->conn = tp_connection_new (test->dbus, test->conn_name, test->conn_path,
406       &error);
407   g_assert (test->conn != NULL);
408   g_assert_no_error (error);
409 
410   tp_tests_proxy_run_until_prepared (test->conn, NULL);
411   g_assert_cmpstr (tp_connection_get_cm_name (test->conn), ==,
412       "simple");
413   g_assert_cmpstr (tp_connection_get_protocol_name (test->conn), ==,
414       "simple-protocol");
415 
416   /* Register the same connection with an invalid object path */
417   tp_dbus_daemon_register_object (test->dbus, invalid_path, test->service_conn);
418   tp_dbus_daemon_request_name (test->dbus, invalid_name, FALSE, &error);
419   g_assert_no_error (error);
420 
421   /* Create a TpConnection for that path, it return invalidated connection */
422   connection = tp_connection_new (test->dbus, NULL, invalid_path, &error);
423   g_assert (connection == NULL);
424   g_assert_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_INVALID_OBJECT_PATH);
425   g_clear_error (&error);
426 }
427 
428 int
main(int argc,char ** argv)429 main (int argc,
430       char **argv)
431 {
432   tp_tests_init (&argc, &argv);
433 
434   g_test_add ("/conn/prepare", Test, NULL, setup, test_prepare, teardown);
435   g_test_add ("/conn/fail_to_prepare", Test, NULL, setup, test_fail_to_prepare,
436       teardown);
437   g_test_add ("/conn/run_until_invalid", Test, NULL, setup,
438       test_run_until_invalid, teardown);
439   g_test_add ("/conn/run_until_ready", Test, NULL, setup,
440       test_run_until_ready, teardown);
441   g_test_add ("/conn/call_when_ready", Test, NULL, setup,
442       test_call_when_ready, teardown);
443   g_test_add ("/conn/call_when_invalid", Test, NULL, setup,
444       test_call_when_invalid, teardown);
445   g_test_add ("/conn/object_path", Test, NULL, setup,
446       test_object_path, teardown);
447 
448   return tp_tests_run_with_bus ();
449 }
450