1 /* Feature test for https://bugs.freedesktop.org/show_bug.cgi?id=27835
2  *
3  * Copyright © 2007-2010 Collabora Ltd. <http://www.collabora.co.uk/>
4  * Copyright © 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 <dbus/dbus-glib.h>
20 #include <dbus/dbus-glib-lowlevel.h>
21 
22 #include "tests/lib/simple-conn.h"
23 #include "tests/lib/util.h"
24 
25 /* an almost-no-op subclass... */
26 typedef TpTestsSimpleConnection InterestedConnection;
27 typedef TpTestsSimpleConnectionClass InterestedConnectionClass;
28 
29 static GType interested_connection_get_type (void);
30 
G_DEFINE_TYPE_WITH_CODE(InterestedConnection,interested_connection,TP_TESTS_TYPE_SIMPLE_CONNECTION,G_STMT_START{ } G_STMT_END)31 G_DEFINE_TYPE_WITH_CODE (InterestedConnection,
32     interested_connection,
33     TP_TESTS_TYPE_SIMPLE_CONNECTION,
34     G_STMT_START { } G_STMT_END)
35 
36 /* Lord Pearson of Rannoch: My Lords, I beg leave to ask the Question
37  * standing in my name on the Order Paper. In doing so, I declare an
38  * interest as patron of the British Register of Chinese Herbal Medicine.
39  * -- Hansard, 2010-02-01 */
40 #define SUPPORTED_TOKEN "com.example.rannoch/ChineseHerbalMedicine"
41 
42 /* Lord Hoyle: My Lords, in thanking my noble friend for his Answer, I declare
43  * an interest as the chairman and now president of Warrington Wolves Rugby
44  * League Club. -- Hansard, 2010-01-11
45  */
46 #define UNSUPPORTED_TOKEN "org.example.Warrington/Wolves"
47 
48 static void
49 interested_connection_init (InterestedConnection *self G_GNUC_UNUSED)
50 {
51 }
52 
53 static void
interested_connection_constructed(GObject * object)54 interested_connection_constructed (GObject *object)
55 {
56   TpBaseConnection *base = (TpBaseConnection *) object;
57   void (*chain_up) (GObject *) =
58     ((GObjectClass *) interested_connection_parent_class)->constructed;
59 
60   if (chain_up != NULL)
61     chain_up (object);
62 
63   tp_base_connection_add_possible_client_interest (base,
64       TP_IFACE_QUARK_CONNECTION_INTERFACE_LOCATION);
65   tp_base_connection_add_possible_client_interest (base,
66       g_quark_from_static_string (SUPPORTED_TOKEN));
67 }
68 
69 static void
interested_connection_class_init(InterestedConnectionClass * cls)70 interested_connection_class_init (InterestedConnectionClass *cls)
71 {
72   GObjectClass *object_class = (GObjectClass *) cls;
73 
74   object_class->constructed = interested_connection_constructed;
75 }
76 
77 typedef struct {
78     TpDBusDaemon *dbus;
79     DBusConnection *client_libdbus;
80     DBusGConnection *client_dbusglib;
81     TpDBusDaemon *client_bus;
82     TpTestsSimpleConnection *service_conn;
83     TpBaseConnection *service_conn_as_base;
84     gchar *conn_name;
85     gchar *conn_path;
86     TpConnection *conn;
87 
88     gboolean cwr_ready;
89     GError *cwr_error /* initialized in setup */;
90 
91     GAsyncResult *prepare_result;
92 
93     GPtrArray *log;
94 } Test;
95 
96 static void
connection_prepared_cb(GObject * object,GAsyncResult * res,gpointer user_data)97 connection_prepared_cb (GObject *object,
98     GAsyncResult *res,
99     gpointer user_data)
100 {
101   Test *test = user_data;
102 
103   g_message ("%p prepared", object);
104   g_assert (test->prepare_result == NULL);
105   test->prepare_result = g_object_ref (res);
106 }
107 
108 static void
interested_cb(TpBaseConnection * unused G_GNUC_UNUSED,const gchar * iface,Test * test)109 interested_cb (TpBaseConnection *unused G_GNUC_UNUSED,
110     const gchar *iface,
111     Test *test)
112 {
113   g_ptr_array_add (test->log, g_strdup_printf ("interested in %s", iface));
114 }
115 
116 static void
location_interested_cb(TpBaseConnection * unused G_GNUC_UNUSED,const gchar * iface,Test * test)117 location_interested_cb (TpBaseConnection *unused G_GNUC_UNUSED,
118     const gchar *iface,
119     Test *test)
120 {
121   g_assert_cmpstr (iface, ==, TP_IFACE_CONNECTION_INTERFACE_LOCATION);
122 
123   g_ptr_array_add (test->log, g_strdup ("Location interested"));
124 }
125 
126 static void
uninterested_cb(TpBaseConnection * unused G_GNUC_UNUSED,const gchar * iface,Test * test)127 uninterested_cb (TpBaseConnection *unused G_GNUC_UNUSED,
128     const gchar *iface,
129     Test *test)
130 {
131   g_ptr_array_add (test->log, g_strdup_printf ("uninterested in %s", iface));
132 }
133 
134 static void
location_uninterested_cb(TpBaseConnection * unused G_GNUC_UNUSED,const gchar * iface,Test * test)135 location_uninterested_cb (TpBaseConnection *unused G_GNUC_UNUSED,
136     const gchar *iface,
137     Test *test)
138 {
139   g_assert_cmpstr (iface, ==, TP_IFACE_CONNECTION_INTERFACE_LOCATION);
140 
141   g_ptr_array_add (test->log, g_strdup ("Location uninterested"));
142 }
143 
144 static void
setup(Test * test,gconstpointer data)145 setup (Test *test,
146     gconstpointer data)
147 {
148   GError *error = NULL;
149   GQuark features[] = { TP_CONNECTION_FEATURE_CONNECTED, 0 };
150 
151   tp_debug_set_flags ("all");
152   test->dbus = tp_tests_dbus_daemon_dup_or_die ();
153 
154   test->client_libdbus = dbus_bus_get_private (DBUS_BUS_STARTER, NULL);
155   g_assert (test->client_libdbus != NULL);
156   dbus_connection_setup_with_g_main (test->client_libdbus, NULL);
157   dbus_connection_set_exit_on_disconnect (test->client_libdbus, FALSE);
158   test->client_dbusglib = dbus_connection_get_g_connection (
159       test->client_libdbus);
160   dbus_g_connection_ref (test->client_dbusglib);
161   test->client_bus = tp_dbus_daemon_new (test->client_dbusglib);
162   g_assert (test->client_bus != NULL);
163 
164   test->service_conn = tp_tests_object_new_static_class (
165         interested_connection_get_type (),
166         "account", "me@example.com",
167         "protocol", "simple-protocol",
168         NULL);
169   test->service_conn_as_base = TP_BASE_CONNECTION (test->service_conn);
170   g_assert (test->service_conn != NULL);
171   g_assert (test->service_conn_as_base != NULL);
172 
173   g_assert (tp_base_connection_register (test->service_conn_as_base, "simple",
174         &test->conn_name, &test->conn_path, &error));
175   g_assert_no_error (error);
176 
177   test->cwr_ready = FALSE;
178   test->cwr_error = NULL;
179 
180   test->conn = tp_connection_new (test->client_bus, test->conn_name,
181       test->conn_path, &error);
182   g_assert (test->conn != NULL);
183   g_assert_no_error (error);
184 
185   tp_cli_connection_call_connect (test->conn, -1, NULL, NULL, NULL, NULL);
186 
187   g_assert (!tp_proxy_is_prepared (test->conn, TP_CONNECTION_FEATURE_CORE));
188   g_assert (!tp_proxy_is_prepared (test->conn,
189         TP_CONNECTION_FEATURE_CONNECTED));
190 
191   tp_proxy_prepare_async (test->conn, features, connection_prepared_cb, test);
192   g_assert (test->prepare_result == NULL);
193 
194   while (test->prepare_result == NULL)
195     g_main_context_iteration (NULL, TRUE);
196 
197   g_assert (tp_proxy_prepare_finish (test->conn, test->prepare_result,
198         &error));
199   g_assert_no_error (error);
200   g_object_unref (test->prepare_result);
201   test->prepare_result = NULL;
202 
203   test->log = g_ptr_array_new_with_free_func (g_free);
204 
205   g_signal_connect (test->service_conn,
206       "clients-interested", G_CALLBACK (interested_cb), test);
207   g_signal_connect (test->service_conn,
208       "clients-interested::" TP_IFACE_CONNECTION_INTERFACE_LOCATION,
209       G_CALLBACK (location_interested_cb), test);
210 
211   g_signal_connect (test->service_conn,
212       "clients-uninterested", G_CALLBACK (uninterested_cb), test);
213   g_signal_connect (test->service_conn,
214       "clients-uninterested::" TP_IFACE_CONNECTION_INTERFACE_LOCATION,
215       G_CALLBACK (location_uninterested_cb), test);
216 }
217 
218 static void
teardown(Test * test,gconstpointer data)219 teardown (Test *test,
220     gconstpointer data)
221 {
222   TpConnection *conn;
223   GError *error = NULL;
224 
225   if (test->conn != NULL)
226     {
227       g_object_unref (test->conn);
228       test->conn = NULL;
229     }
230 
231   /* disconnect the connection so we don't leak it */
232   conn = tp_connection_new (test->dbus, test->conn_name, test->conn_path,
233       &error);
234   g_assert (conn != NULL);
235   g_assert_no_error (error);
236 
237   tp_tests_connection_assert_disconnect_succeeds (conn);
238 
239   g_assert (!tp_connection_run_until_ready (conn, FALSE, &error, NULL));
240   g_assert_error (error, TP_ERROR, TP_ERROR_CANCELLED);
241   g_clear_error (&error);
242 
243   test->service_conn_as_base = NULL;
244   g_object_unref (test->service_conn);
245   g_free (test->conn_name);
246   g_free (test->conn_path);
247 
248   g_object_unref (test->dbus);
249   test->dbus = NULL;
250   g_object_unref (test->client_bus);
251   test->client_bus = NULL;
252 
253   dbus_g_connection_unref (test->client_dbusglib);
254   dbus_connection_close (test->client_libdbus);
255   dbus_connection_unref (test->client_libdbus);
256 
257   g_ptr_array_unref (test->log);
258 }
259 
260 static void
test_interested_client(Test * test,gconstpointer nil G_GNUC_UNUSED)261 test_interested_client (Test *test,
262     gconstpointer nil G_GNUC_UNUSED)
263 {
264   guint i;
265 
266   tp_connection_add_client_interest_by_id (test->conn,
267       TP_IFACE_QUARK_CONNECTION_INTERFACE_LOCATION);
268   tp_connection_add_client_interest_by_id (test->conn,
269       TP_IFACE_QUARK_CONNECTION_INTERFACE_AVATARS);
270 
271   /* run until (after) the AddClientInterest calls have gone out */
272   tp_tests_proxy_run_until_dbus_queue_processed (test->client_bus);
273 
274   /* we auto-release the Location client interest by disposing the client
275    * connection */
276   g_object_run_dispose ((GObject *) test->conn);
277   g_object_unref (test->conn);
278   test->conn = NULL;
279 
280   /* run until (after) the RemoveClientInterest call has gone out */
281   tp_tests_proxy_run_until_dbus_queue_processed (test->client_bus);
282 
283   /* then, run until (after) the CM should have processed both ACI and RCI */
284   tp_tests_proxy_run_until_dbus_queue_processed (test->dbus);
285 
286   i = 0;
287   g_assert_cmpuint (test->log->len, >, i);
288   g_assert_cmpstr (g_ptr_array_index (test->log, i), ==,
289       "interested in " TP_IFACE_CONNECTION_INTERFACE_LOCATION);
290 
291   i++;
292   g_assert_cmpuint (test->log->len, >, i);
293   g_assert_cmpstr (g_ptr_array_index (test->log, i), ==,
294       "Location interested");
295 
296   i++;
297   g_assert_cmpuint (test->log->len, >, i);
298   g_assert_cmpstr (g_ptr_array_index (test->log, i), ==,
299       "uninterested in " TP_IFACE_CONNECTION_INTERFACE_LOCATION);
300 
301   i++;
302   g_assert_cmpuint (test->log->len, >, i);
303   g_assert_cmpstr (g_ptr_array_index (test->log, i), ==,
304       "Location uninterested");
305 
306   i++;
307   g_assert_cmpuint (test->log->len, ==, i);
308 }
309 
310 static void
test_interest(Test * test,gconstpointer nil G_GNUC_UNUSED)311 test_interest (Test *test,
312     gconstpointer nil G_GNUC_UNUSED)
313 {
314   static const gchar * telepathy[] = {
315       TP_IFACE_CONNECTION_INTERFACE_LOCATION,
316       TP_IFACE_CONNECTION_INTERFACE_AVATARS,
317       NULL
318   };
319   static const gchar * hansard[] = {
320       SUPPORTED_TOKEN,
321       UNSUPPORTED_TOKEN,
322       NULL
323   };
324   GError *error = NULL;
325   guint i;
326 
327   tp_cli_connection_run_add_client_interest (test->conn, -1, telepathy, &error,
328       NULL);
329   g_assert_no_error (error);
330 
331   tp_cli_connection_run_add_client_interest (test->conn, -1, hansard, &error,
332       NULL);
333   g_assert_no_error (error);
334 
335   tp_cli_connection_run_add_client_interest (test->conn, -1, telepathy, &error,
336       NULL);
337   g_assert_no_error (error);
338 
339   tp_cli_connection_run_remove_client_interest (test->conn, -1, telepathy,
340       &error, NULL);
341   g_assert_no_error (error);
342 
343   tp_cli_connection_run_remove_client_interest (test->conn, -1, hansard,
344       &error, NULL);
345   g_assert_no_error (error);
346 
347   /* we auto-release the Location client interest by dropping the client
348    * connection */
349   dbus_connection_flush (test->client_libdbus);
350   dbus_connection_close (test->client_libdbus);
351 
352   while (test->log->len < 6)
353     g_main_context_iteration (NULL, TRUE);
354 
355   i = 0;
356   g_assert_cmpuint (test->log->len, >, i);
357   g_assert_cmpstr (g_ptr_array_index (test->log, i), ==,
358       "interested in " TP_IFACE_CONNECTION_INTERFACE_LOCATION);
359 
360   i++;
361   g_assert_cmpuint (test->log->len, >, i);
362   g_assert_cmpstr (g_ptr_array_index (test->log, i), ==,
363       "Location interested");
364 
365   i++;
366   g_assert_cmpuint (test->log->len, >, i);
367   g_assert_cmpstr (g_ptr_array_index (test->log, i), ==,
368       "interested in " SUPPORTED_TOKEN);
369 
370   i++;
371   g_assert_cmpuint (test->log->len, >, i);
372   g_assert_cmpstr (g_ptr_array_index (test->log, i), ==,
373       "uninterested in " SUPPORTED_TOKEN);
374 
375   i++;
376   g_assert_cmpuint (test->log->len, >, i);
377   g_assert_cmpstr (g_ptr_array_index (test->log, i), ==,
378       "uninterested in " TP_IFACE_CONNECTION_INTERFACE_LOCATION);
379 
380   i++;
381   g_assert_cmpuint (test->log->len, >, i);
382   g_assert_cmpstr (g_ptr_array_index (test->log, i), ==,
383       "Location uninterested");
384 
385   i++;
386   g_assert_cmpuint (test->log->len, ==, i);
387 }
388 
389 int
main(int argc,char ** argv)390 main (int argc,
391       char **argv)
392 {
393   tp_tests_init (&argc, &argv);
394 
395   g_test_add ("/conn/interest", Test, NULL, setup, test_interest, teardown);
396   g_test_add ("/conn/interested-client", Test, NULL, setup,
397       test_interested_client, teardown);
398 
399   return tp_tests_run_with_bus ();
400 }
401