1 /* Tests of TpBaseClient
2  *
3  * Copyright © 2010 Collabora Ltd. <http://www.collabora.co.uk/>
4  *
5  * Copying and distribution of this file, with or without modification,
6  * are permitted in any medium without royalty provided the copyright
7  * notice and this notice are preserved.
8  */
9 
10 #include "config.h"
11 
12 /* We include -internal headers of context to be able to easily access to
13  * their semi-private attributes (connection, account, channels, etc). */
14 #include <telepathy-glib/account-manager.h>
15 #include <telepathy-glib/add-dispatch-operation-context-internal.h>
16 #include <telepathy-glib/base-client.h>
17 #include <telepathy-glib/client.h>
18 #include <telepathy-glib/debug.h>
19 #include <telepathy-glib/defs.h>
20 #include <telepathy-glib/handle-channels-context-internal.h>
21 #include <telepathy-glib/observe-channels-context-internal.h>
22 #include <telepathy-glib/proxy-subclass.h>
23 
24 #include "tests/lib/util.h"
25 #include "tests/lib/simple-account.h"
26 #include "tests/lib/simple-channel-dispatch-operation.h"
27 #include "tests/lib/simple-channel-dispatcher.h"
28 #include "tests/lib/simple-channel-request.h"
29 #include "tests/lib/simple-client.h"
30 #include "tests/lib/simple-conn.h"
31 #include "tests/lib/textchan-null.h"
32 
33 typedef struct {
34     GMainLoop *mainloop;
35     TpDBusDaemon *dbus;
36 
37     /* Service side objects */
38     TpBaseClient *base_client;
39     TpTestsSimpleClient *simple_client;
40     TpBaseConnection *base_connection;
41     TpTestsSimpleAccount *account_service;
42     TpTestsTextChannelNull *text_chan_service;
43     TpTestsTextChannelNull *text_chan_service_2;
44     TpTestsSimpleChannelDispatchOperation *cdo_service;
45     TpTestsSimpleChannelDispatcher *cd_service;
46 
47     /* Client side objects */
48     TpAccountManager *account_mgr;
49     TpClient *client;
50     TpConnection *connection;
51     TpAccount *account;
52     TpChannel *text_chan;
53     TpChannel *text_chan_2;
54 
55     GError *error /* initialized where needed */;
56     GStrv interfaces;
57     gint wait;
58 
59     GPtrArray *delegated;
60     GHashTable *not_delegated;
61 } Test;
62 
63 #define ACCOUNT_PATH TP_ACCOUNT_OBJECT_PATH_BASE "what/ev/er"
64 #define CDO_PATH "/whatever"
65 
66 static void
setup(Test * test,gconstpointer data)67 setup (Test *test,
68        gconstpointer data)
69 {
70   gchar *chan_path;
71   TpHandle handle;
72   TpHandleRepoIface *contact_repo;
73 
74   test->mainloop = g_main_loop_new (NULL, FALSE);
75   test->dbus = tp_tests_dbus_daemon_dup_or_die ();
76 
77   test->error = NULL;
78   test->interfaces = NULL;
79 
80   /* The case of a non-shared TpAccountManager is tested in
81    * simple-approver.c */
82   test->account_mgr = tp_account_manager_dup ();
83   g_assert (test->account_mgr != NULL);
84 
85   /* Claim AccountManager bus-name (needed as we're going to export an Account
86    * object). */
87   tp_dbus_daemon_request_name (test->dbus,
88           TP_ACCOUNT_MANAGER_BUS_NAME, FALSE, &test->error);
89   g_assert_no_error (test->error);
90 
91   /* Create service-side Client object */
92   test->simple_client = tp_tests_simple_client_new (test->dbus, "Test", FALSE);
93   g_assert (test->simple_client != NULL);
94   test->base_client = TP_BASE_CLIENT (test->simple_client);
95 
96   /* Create service-side Account object */
97   test->account_service = tp_tests_object_new_static_class (
98       TP_TESTS_TYPE_SIMPLE_ACCOUNT, NULL);
99   tp_dbus_daemon_register_object (test->dbus, ACCOUNT_PATH,
100       test->account_service);
101 
102   /* Create client-side Client object */
103   test->client = tp_tests_object_new_static_class (TP_TYPE_CLIENT,
104           "dbus-daemon", test->dbus,
105           "bus-name", tp_base_client_get_bus_name (test->base_client),
106           "object-path", tp_base_client_get_object_path (test->base_client),
107           NULL);
108 
109   g_assert (test->client != NULL);
110 
111   /* Create client-side Account object */
112   test->account = tp_account_manager_ensure_account (test->account_mgr,
113       ACCOUNT_PATH);
114   g_assert (test->account != NULL);
115   g_object_ref (test->account);
116 
117   /* Create (service and client sides) connection objects */
118   tp_tests_create_and_connect_conn (TP_TESTS_TYPE_SIMPLE_CONNECTION,
119       "me@test.com", &test->base_connection, &test->connection);
120 
121   /* Create service-side text channel object */
122   chan_path = g_strdup_printf ("%s/Channel",
123       tp_proxy_get_object_path (test->connection));
124 
125   contact_repo = tp_base_connection_get_handles (test->base_connection,
126       TP_HANDLE_TYPE_CONTACT);
127   g_assert (contact_repo != NULL);
128 
129   handle = tp_handle_ensure (contact_repo, "bob", NULL, &test->error);
130   g_assert_no_error (test->error);
131 
132   test->text_chan_service = TP_TESTS_TEXT_CHANNEL_NULL (
133       tp_tests_object_new_static_class (
134         TP_TESTS_TYPE_TEXT_CHANNEL_NULL,
135         "connection", test->base_connection,
136         "object-path", chan_path,
137         "handle", handle,
138         NULL));
139 
140   /* Create client-side text channel object */
141   test->text_chan = tp_channel_new (test->connection, chan_path, NULL,
142       TP_HANDLE_TYPE_CONTACT, handle, &test->error);
143   g_assert_no_error (test->error);
144 
145   tp_handle_unref (contact_repo, handle);
146   g_free (chan_path);
147 
148   /* Create a second channel */
149   chan_path = g_strdup_printf ("%s/Channel2",
150       tp_proxy_get_object_path (test->connection));
151 
152   handle = tp_handle_ensure (contact_repo, "alice", NULL, &test->error);
153   g_assert_no_error (test->error);
154 
155   test->text_chan_service_2 = TP_TESTS_TEXT_CHANNEL_NULL (
156       tp_tests_object_new_static_class (
157         TP_TESTS_TYPE_TEXT_CHANNEL_NULL,
158         "connection", test->base_connection,
159         "object-path", chan_path,
160         "handle", handle,
161         NULL));
162 
163   /* Create client-side text channel object */
164   test->text_chan_2 = tp_channel_new (test->connection, chan_path, NULL,
165       TP_HANDLE_TYPE_CONTACT, handle, &test->error);
166   g_assert_no_error (test->error);
167 
168   tp_handle_unref (contact_repo, handle);
169   g_free (chan_path);
170 
171   /* Create Service side ChannelDispatchOperation object */
172   test->cdo_service = tp_tests_object_new_static_class (
173       TP_TESTS_TYPE_SIMPLE_CHANNEL_DISPATCH_OPERATION,
174       NULL);
175   tp_dbus_daemon_register_object (test->dbus, CDO_PATH, test->cdo_service);
176 
177   tp_tests_simple_channel_dispatch_operation_set_conn_path (test->cdo_service,
178       tp_proxy_get_object_path (test->connection));
179 
180   tp_tests_simple_channel_dispatch_operation_set_account_path (
181       test->cdo_service, tp_proxy_get_object_path (test->account));
182 
183   tp_tests_simple_channel_dispatch_operation_add_channel (test->cdo_service,
184       test->text_chan);
185   tp_tests_simple_channel_dispatch_operation_add_channel (test->cdo_service,
186       test->text_chan_2);
187 
188   g_assert (tp_dbus_daemon_request_name (test->dbus,
189       TP_CHANNEL_DISPATCHER_BUS_NAME, FALSE, NULL));
190 
191   /* Create and register CD */
192   test->cd_service = tp_tests_object_new_static_class (
193       TP_TESTS_TYPE_SIMPLE_CHANNEL_DISPATCHER,
194       "connection", test->base_connection,
195       NULL);
196 
197   tp_dbus_daemon_register_object (test->dbus, TP_CHANNEL_DISPATCHER_OBJECT_PATH,
198       test->cd_service);
199 }
200 
201 static void
teardown_channel_invalidated_cb(TpChannel * self,guint domain,gint code,gchar * message,Test * test)202 teardown_channel_invalidated_cb (TpChannel *self,
203   guint domain,
204   gint code,
205   gchar *message,
206   Test *test)
207 {
208   g_main_loop_quit (test->mainloop);
209 }
210 
211 static void
teardown_run_close_channel(Test * test,TpChannel * channel)212 teardown_run_close_channel (Test *test, TpChannel *channel)
213 {
214   if (channel != NULL && tp_proxy_get_invalidated (channel) == NULL)
215     {
216       g_signal_connect (channel, "invalidated",
217           G_CALLBACK (teardown_channel_invalidated_cb), test);
218       tp_cli_channel_call_close (channel, -1, NULL, NULL, NULL, NULL);
219       g_main_loop_run (test->mainloop);
220     }
221 }
222 
223 static void
teardown(Test * test,gconstpointer data)224 teardown (Test *test,
225           gconstpointer data)
226 {
227   teardown_run_close_channel (test, test->text_chan);
228   teardown_run_close_channel (test, test->text_chan_2);
229 
230   g_clear_error (&test->error);
231 
232   g_strfreev (test->interfaces);
233 
234   g_object_unref (test->account_mgr);
235 
236   tp_dbus_daemon_release_name (test->dbus, TP_CHANNEL_DISPATCHER_BUS_NAME,
237       NULL);
238 
239   g_object_unref (test->base_client);
240   g_object_unref (test->client);
241 
242   tp_dbus_daemon_unregister_object (test->dbus, test->account_service);
243   g_object_unref (test->account_service);
244 
245   tp_dbus_daemon_release_name (test->dbus, TP_ACCOUNT_MANAGER_BUS_NAME,
246       &test->error);
247   g_assert_no_error (test->error);
248 
249   g_object_unref (test->dbus);
250   test->dbus = NULL;
251   g_main_loop_unref (test->mainloop);
252   test->mainloop = NULL;
253 
254   g_object_unref (test->account);
255 
256   if (test->text_chan_service != NULL)
257     g_object_unref (test->text_chan_service);
258   g_object_unref (test->text_chan);
259 
260   if (test->text_chan_service_2 != NULL)
261     g_object_unref (test->text_chan_service_2);
262   g_object_unref (test->text_chan_2);
263 
264   tp_clear_object (&test->cdo_service);
265 
266   tp_tests_connection_assert_disconnect_succeeds (test->connection);
267   g_object_unref (test->connection);
268   g_object_unref (test->base_connection);
269 
270   tp_clear_object (&test->cd_service);
271 
272   tp_clear_pointer (&test->delegated, g_ptr_array_unref);
273   tp_clear_pointer (&test->not_delegated, g_hash_table_unref);
274 }
275 
276 /* Test Basis */
277 
278 static void
test_basics(Test * test,gconstpointer data G_GNUC_UNUSED)279 test_basics (Test *test,
280     gconstpointer data G_GNUC_UNUSED)
281 {
282   TpAccountManager *account_manager;
283   TpDBusDaemon *dbus;
284   gchar *name;
285   gboolean unique;
286 
287   g_object_get (test->base_client,
288       "account-manager", &account_manager,
289       "dbus-daemon", &dbus,
290       "name", &name,
291       "uniquify-name", &unique,
292       NULL);
293 
294   g_assert (test->account_mgr == account_manager);
295   g_assert (test->dbus == dbus);
296   g_assert_cmpstr ("Test", ==, name);
297   g_assert (!unique);
298 
299   g_assert (test->account_mgr == tp_base_client_get_account_manager (
300         test->base_client));
301   g_assert (test->dbus == tp_base_client_get_dbus_daemon (test->base_client));
302   g_assert_cmpstr ("Test", ==, tp_base_client_get_name (test->base_client));
303   g_assert (!tp_base_client_get_uniquify_name (test->base_client));
304 
305   g_object_unref (account_manager);
306   g_object_unref (dbus);
307   g_free (name);
308 }
309 
310 /* Test register */
311 
312 static void
get_client_prop_cb(TpProxy * proxy,GHashTable * properties,const GError * error,gpointer user_data,GObject * weak_object)313 get_client_prop_cb (TpProxy *proxy,
314     GHashTable *properties,
315     const GError *error,
316     gpointer user_data,
317     GObject *weak_object)
318 {
319   Test *test = user_data;
320 
321   if (error != NULL)
322     {
323       test->error = g_error_copy (error);
324       goto out;
325     }
326 
327   g_assert_cmpint (g_hash_table_size (properties), == , 1);
328 
329   g_strfreev (test->interfaces);
330   test->interfaces = g_strdupv ((GStrv) tp_asv_get_strv (
331         properties, "Interfaces"));
332 
333 out:
334   g_main_loop_quit (test->mainloop);
335 }
336 
337 static void
test_register(Test * test,gconstpointer data G_GNUC_UNUSED)338 test_register (Test *test,
339     gconstpointer data G_GNUC_UNUSED)
340 {
341   tp_base_client_be_a_handler (test->base_client);
342 
343   /* no-op as the client is not registered yet */
344   tp_base_client_unregister (test->base_client);
345 
346   /* Client is not registered yet */
347   tp_cli_dbus_properties_call_get_all (test->client, -1,
348       TP_IFACE_CLIENT, get_client_prop_cb, test, NULL, NULL);
349   g_main_loop_run (test->mainloop);
350 
351   g_assert_error (test->error, DBUS_GERROR, DBUS_GERROR_SERVICE_UNKNOWN);
352   g_error_free (test->error);
353   test->error = NULL;
354 
355   /* register the client */
356   tp_base_client_register (test->base_client, &test->error);
357   g_assert_no_error (test->error);
358 
359   tp_cli_dbus_properties_call_get_all (test->client, -1,
360       TP_IFACE_CLIENT, get_client_prop_cb, test, NULL, NULL);
361   g_main_loop_run (test->mainloop);
362 
363   g_assert_no_error (test->error);
364 
365   /* unregister the client */
366   tp_base_client_unregister (test->base_client);
367   tp_tests_proxy_run_until_dbus_queue_processed (test->client);
368 
369   tp_cli_dbus_properties_call_get_all (test->client, -1,
370       TP_IFACE_CLIENT, get_client_prop_cb, test, NULL, NULL);
371   g_main_loop_run (test->mainloop);
372 
373   g_assert_error (test->error, DBUS_GERROR, DBUS_GERROR_SERVICE_UNKNOWN);
374   g_error_free (test->error);
375   test->error = NULL;
376 
377   /* re-register the client */
378   tp_base_client_register (test->base_client, &test->error);
379   g_assert_no_error (test->error);
380 
381   tp_cli_dbus_properties_call_get_all (test->client, -1,
382       TP_IFACE_CLIENT, get_client_prop_cb, test, NULL, NULL);
383   g_main_loop_run (test->mainloop);
384 
385   g_assert_no_error (test->error);
386 }
387 
388 /* Test Observer */
389 static void
check_filters(GPtrArray * filters)390 check_filters (GPtrArray *filters)
391 {
392   GHashTable *filter;
393 
394   g_assert (filters != NULL);
395   g_assert_cmpuint (filters->len, ==, 2);
396 
397   filter = g_ptr_array_index (filters, 0);
398   g_assert_cmpuint (g_hash_table_size (filter), ==, 1);
399   g_assert_cmpstr (tp_asv_get_string (filter, TP_PROP_CHANNEL_CHANNEL_TYPE), ==,
400       TP_IFACE_CHANNEL_TYPE_TEXT);
401 
402   filter = g_ptr_array_index (filters, 1);
403   g_assert_cmpuint (g_hash_table_size (filter), ==, 2);
404   g_assert_cmpstr (tp_asv_get_string (filter, TP_PROP_CHANNEL_CHANNEL_TYPE), ==,
405       TP_IFACE_CHANNEL_TYPE_STREAM_TUBE);
406   g_assert_cmpuint (tp_asv_get_uint32 (filter,
407         TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL), ==, TP_HANDLE_TYPE_CONTACT);
408 }
409 
410 static void
get_observer_prop_cb(TpProxy * proxy,GHashTable * properties,const GError * error,gpointer user_data,GObject * weak_object)411 get_observer_prop_cb (TpProxy *proxy,
412     GHashTable *properties,
413     const GError *error,
414     gpointer user_data,
415     GObject *weak_object)
416 {
417   Test *test = user_data;
418   GPtrArray *filters;
419   gboolean recover, delay;
420   gboolean valid;
421 
422   if (error != NULL)
423     {
424       test->error = g_error_copy (error);
425       goto out;
426     }
427 
428   g_assert_cmpint (g_hash_table_size (properties), == , 3);
429 
430   filters = tp_asv_get_boxed (properties, "ObserverChannelFilter",
431       TP_ARRAY_TYPE_CHANNEL_CLASS_LIST);
432   check_filters (filters);
433 
434   recover = tp_asv_get_boolean (properties, "Recover", &valid);
435   g_assert (valid);
436   g_assert (recover);
437 
438   delay = tp_asv_get_boolean (properties, "DelayApprovers", &valid);
439   g_assert (valid);
440   g_assert (delay);
441 
442 out:
443   g_main_loop_quit (test->mainloop);
444 }
445 
446 static void
no_return_cb(TpClient * proxy,const GError * error,gpointer user_data,GObject * weak_object)447 no_return_cb (TpClient *proxy,
448     const GError *error,
449     gpointer user_data,
450     GObject *weak_object)
451 {
452   Test *test = user_data;
453 
454   g_clear_error (&test->error);
455 
456   if (error != NULL)
457     {
458       test->error = g_error_copy (error);
459       goto out;
460     }
461 
462 out:
463   test->wait--;
464   if (test->wait == 0)
465     g_main_loop_quit (test->mainloop);
466 }
467 
468 static void
add_channel_to_ptr_array(GPtrArray * arr,TpChannel * channel)469 add_channel_to_ptr_array (GPtrArray *arr,
470     TpChannel *channel)
471 {
472   GValueArray *tmp;
473 
474   g_assert (arr != NULL);
475   g_assert (channel != NULL);
476 
477   tmp = tp_value_array_build (2,
478       DBUS_TYPE_G_OBJECT_PATH, tp_proxy_get_object_path (channel),
479       TP_HASH_TYPE_STRING_VARIANT_MAP, tp_channel_borrow_immutable_properties (
480         channel),
481       G_TYPE_INVALID);
482 
483   g_ptr_array_add (arr, tmp);
484 }
485 
486 static void
free_channel_details(gpointer data,gpointer user_data)487 free_channel_details (gpointer data,
488     gpointer user_data)
489 {
490   g_boxed_free (TP_STRUCT_TYPE_CHANNEL_DETAILS, data);
491 }
492 
493 static void
test_observer(Test * test,gconstpointer data G_GNUC_UNUSED)494 test_observer (Test *test,
495     gconstpointer data G_GNUC_UNUSED)
496 {
497   GHashTable *filter;
498   GPtrArray *channels, *requests_satisified;
499   GHashTable *info;
500   TpChannel *chan;
501 
502   filter = tp_asv_new (
503       TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_TEXT,
504       NULL);
505 
506   tp_base_client_add_observer_filter (test->base_client, filter);
507   g_hash_table_unref (filter);
508 
509   tp_base_client_take_observer_filter (test->base_client, tp_asv_new (
510         TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
511           TP_IFACE_CHANNEL_TYPE_STREAM_TUBE,
512         TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT,
513           TP_HANDLE_TYPE_CONTACT,
514         NULL));
515 
516   tp_base_client_set_observer_recover (test->base_client, TRUE);
517   tp_base_client_set_observer_delay_approvers (test->base_client, TRUE);
518 
519   tp_base_client_register (test->base_client, &test->error);
520   g_assert_no_error (test->error);
521 
522   /* Check Client properties */
523   tp_cli_dbus_properties_call_get_all (test->client, -1,
524       TP_IFACE_CLIENT, get_client_prop_cb, test, NULL, NULL);
525   g_main_loop_run (test->mainloop);
526 
527   g_assert_no_error (test->error);
528   g_assert_cmpint (g_strv_length (test->interfaces), ==, 1);
529   g_assert (tp_strv_contains ((const gchar * const *) test->interfaces,
530         TP_IFACE_CLIENT_OBSERVER));
531 
532   /* Check Observer properties */
533   tp_cli_dbus_properties_call_get_all (test->client, -1,
534       TP_IFACE_CLIENT_OBSERVER, get_observer_prop_cb, test, NULL, NULL);
535   g_main_loop_run (test->mainloop);
536 
537   g_assert_no_error (test->error);
538 
539   /* Call ObserveChannels */
540   channels = g_ptr_array_sized_new (1);
541   add_channel_to_ptr_array (channels, test->text_chan);
542 
543   requests_satisified = g_ptr_array_sized_new (0);
544   info = tp_asv_new (
545       "recovering", G_TYPE_BOOLEAN, TRUE,
546       NULL);
547 
548   tp_proxy_add_interface_by_id (TP_PROXY (test->client),
549       TP_IFACE_QUARK_CLIENT_OBSERVER);
550 
551   tp_cli_client_observer_call_observe_channels (test->client, -1,
552       tp_proxy_get_object_path (test->account),
553       tp_proxy_get_object_path (test->connection),
554       channels, "/", requests_satisified, info,
555       no_return_cb, test, NULL, NULL);
556 
557   test->wait++;
558   g_main_loop_run (test->mainloop);
559   g_assert_no_error (test->error);
560 
561   g_assert (test->simple_client->observe_ctx != NULL);
562   g_assert (tp_observe_channels_context_is_recovering (
563         test->simple_client->observe_ctx));
564 
565   g_assert (test->simple_client->observe_ctx->account == test->account);
566 
567   /* Now call it with an invalid argument */
568   tp_asv_set_boolean (info, "FAIL", TRUE);
569 
570   tp_cli_client_observer_call_observe_channels (test->client, -1,
571       tp_proxy_get_object_path (test->account),
572       tp_proxy_get_object_path (test->connection),
573       channels, "/", requests_satisified, info,
574       no_return_cb, test, NULL, NULL);
575 
576   test->wait++;
577   g_main_loop_run (test->mainloop);
578   g_assert_error (test->error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT);
579   g_clear_error (&test->error);
580 
581   /* The channel being observed is invalidated while preparing */
582   g_hash_table_remove (info, "FAIL");
583 
584   tp_cli_client_observer_call_observe_channels (test->client, -1,
585       tp_proxy_get_object_path (test->account),
586       tp_proxy_get_object_path (test->connection),
587       channels, "/", requests_satisified, info,
588       no_return_cb, test, NULL, NULL);
589 
590   tp_tests_text_channel_null_close (test->text_chan_service);
591 
592   test->wait++;
593   g_main_loop_run (test->mainloop);
594   g_assert_no_error (test->error);
595 
596   chan = g_ptr_array_index (test->simple_client->observe_ctx->channels, 0);
597   g_assert (TP_IS_CHANNEL (chan));
598   g_assert (tp_proxy_get_invalidated (chan) != NULL);
599 
600   g_ptr_array_foreach (channels, free_channel_details, NULL);
601   g_ptr_array_unref (channels);
602   g_ptr_array_unref (requests_satisified);
603   g_hash_table_unref (info);
604 }
605 
606 /* Test Approver */
607 static void
get_approver_prop_cb(TpProxy * proxy,GHashTable * properties,const GError * error,gpointer user_data,GObject * weak_object)608 get_approver_prop_cb (TpProxy *proxy,
609     GHashTable *properties,
610     const GError *error,
611     gpointer user_data,
612     GObject *weak_object)
613 {
614   Test *test = user_data;
615   GPtrArray *filters;
616 
617   if (error != NULL)
618     {
619       test->error = g_error_copy (error);
620       goto out;
621     }
622 
623   g_assert_cmpint (g_hash_table_size (properties), == , 1);
624 
625   filters = tp_asv_get_boxed (properties, "ApproverChannelFilter",
626       TP_ARRAY_TYPE_CHANNEL_CLASS_LIST);
627   check_filters (filters);
628 
629 out:
630   g_main_loop_quit (test->mainloop);
631 }
632 
633 static void
test_approver(Test * test,gconstpointer data G_GNUC_UNUSED)634 test_approver (Test *test,
635     gconstpointer data G_GNUC_UNUSED)
636 {
637   GHashTable *filter;
638   GPtrArray *channels, *chans;
639   GHashTable *properties;
640   static const char *interfaces[] = { NULL };
641   static const gchar *possible_handlers[] = {
642     TP_CLIENT_BUS_NAME_BASE ".Badger", NULL, };
643   guint i;
644 
645   filter = tp_asv_new (
646       TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_TEXT,
647       NULL);
648 
649   tp_base_client_add_approver_filter (test->base_client, filter);
650   g_hash_table_unref (filter);
651 
652   tp_base_client_take_approver_filter (test->base_client, tp_asv_new (
653         TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
654           TP_IFACE_CHANNEL_TYPE_STREAM_TUBE,
655         TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT,
656           TP_HANDLE_TYPE_CONTACT,
657         NULL));
658 
659   tp_base_client_register (test->base_client, &test->error);
660   g_assert_no_error (test->error);
661 
662   /* Check Client properties */
663   tp_cli_dbus_properties_call_get_all (test->client, -1,
664       TP_IFACE_CLIENT, get_client_prop_cb, test, NULL, NULL);
665   g_main_loop_run (test->mainloop);
666 
667   g_assert_no_error (test->error);
668   g_assert_cmpint (g_strv_length (test->interfaces), ==, 1);
669   g_assert (tp_strv_contains ((const gchar * const *) test->interfaces,
670         TP_IFACE_CLIENT_APPROVER));
671 
672   /* Check Approver properties */
673   tp_cli_dbus_properties_call_get_all (test->client, -1,
674       TP_IFACE_CLIENT_APPROVER, get_approver_prop_cb, test, NULL, NULL);
675   g_main_loop_run (test->mainloop);
676   g_assert_no_error (test->error);
677 
678   /* Call AddDispatchOperation */
679   channels = g_ptr_array_sized_new (2);
680   add_channel_to_ptr_array (channels, test->text_chan);
681   add_channel_to_ptr_array (channels, test->text_chan_2);
682 
683   properties = tp_asv_new (
684       TP_PROP_CHANNEL_DISPATCH_OPERATION_INTERFACES,
685         G_TYPE_STRV, interfaces,
686       TP_PROP_CHANNEL_DISPATCH_OPERATION_CONNECTION,
687         DBUS_TYPE_G_OBJECT_PATH, tp_proxy_get_object_path (test->connection),
688       TP_PROP_CHANNEL_DISPATCH_OPERATION_ACCOUNT,
689         DBUS_TYPE_G_OBJECT_PATH, tp_proxy_get_object_path (test->account),
690       TP_PROP_CHANNEL_DISPATCH_OPERATION_POSSIBLE_HANDLERS,
691         G_TYPE_STRV, possible_handlers,
692       NULL);
693 
694   tp_proxy_add_interface_by_id (TP_PROXY (test->client),
695       TP_IFACE_QUARK_CLIENT_APPROVER);
696 
697   tp_cli_client_approver_call_add_dispatch_operation (test->client, -1,
698       channels, CDO_PATH, properties,
699       no_return_cb, test, NULL, NULL);
700 
701   test->wait++;
702   g_main_loop_run (test->mainloop);
703   g_assert_no_error (test->error);
704 
705   g_assert (test->simple_client->add_dispatch_ctx != NULL);
706   chans = tp_channel_dispatch_operation_borrow_channels (
707       test->simple_client->add_dispatch_ctx->dispatch_operation);
708   g_assert_cmpuint (chans->len, ==, 2);
709 
710   /* Check that we reuse existing proxies rather than creating new ones */
711   g_assert (test->simple_client->add_dispatch_ctx->account == test->account);
712   g_assert (tp_channel_dispatch_operation_borrow_account (
713         test->simple_client->add_dispatch_ctx->dispatch_operation) ==
714       test->account);
715 
716   g_assert (tp_channel_dispatch_operation_borrow_connection (
717         test->simple_client->add_dispatch_ctx->dispatch_operation) ==
718       test->simple_client->add_dispatch_ctx->connection);
719 
720   g_assert (chans->len == test->simple_client->add_dispatch_ctx->channels->len);
721   for (i = 0; i < chans->len; i++)
722     {
723       g_assert (g_ptr_array_index (chans, i) ==
724           g_ptr_array_index (test->simple_client->add_dispatch_ctx->channels,
725             i));
726     }
727 
728   /* Another call to AddDispatchOperation, the second channel will be
729    * invalidated during the call */
730   tp_cli_client_approver_call_add_dispatch_operation (test->client, -1,
731       channels, CDO_PATH, properties,
732       no_return_cb, test, NULL, NULL);
733 
734   tp_tests_text_channel_null_close (test->text_chan_service_2);
735 
736   test->wait++;
737   g_object_unref (test->text_chan_service_2);
738   test->text_chan_service_2 = NULL;
739 
740   tp_tests_simple_channel_dispatch_operation_lost_channel (test->cdo_service,
741       test->text_chan_2);
742 
743   g_main_loop_run (test->mainloop);
744   g_assert_no_error (test->error);
745 
746   g_assert (test->simple_client->add_dispatch_ctx != NULL);
747   /* The CDO only contain valid channels */
748   chans = tp_channel_dispatch_operation_borrow_channels (
749       test->simple_client->add_dispatch_ctx->dispatch_operation);
750   g_assert_cmpuint (chans->len, ==, 1);
751   /* But the context contains both */
752   g_assert_cmpuint (test->simple_client->add_dispatch_ctx->channels->len,
753       ==, 2);
754 
755   /* Another call to AddDispatchOperation, the last channel will be
756    * invalidated during the call */
757   tp_cli_client_approver_call_add_dispatch_operation (test->client, -1,
758       channels, CDO_PATH, properties,
759       no_return_cb, test, NULL, NULL);
760 
761   tp_tests_text_channel_null_close (test->text_chan_service);
762   g_object_unref (test->text_chan_service);
763   test->text_chan_service = NULL;
764 
765   tp_tests_simple_channel_dispatch_operation_lost_channel (test->cdo_service,
766       test->text_chan);
767 
768   test->wait++;
769   g_main_loop_run (test->mainloop);
770   g_assert_no_error (test->error);
771 
772   g_ptr_array_foreach (channels, free_channel_details, NULL);
773   g_ptr_array_unref (channels);
774   g_hash_table_unref (properties);
775 }
776 
777 /* Test Handler */
778 static void
get_handler_prop_cb(TpProxy * proxy,GHashTable * properties,const GError * error,gpointer user_data,GObject * weak_object)779 get_handler_prop_cb (TpProxy *proxy,
780     GHashTable *properties,
781     const GError *error,
782     gpointer user_data,
783     GObject *weak_object)
784 {
785   Test *test = user_data;
786   GPtrArray *filters;
787   gboolean bypass;
788   gboolean valid;
789   const gchar * const * capabilities;
790   GPtrArray *handled;
791 
792   if (error != NULL)
793     {
794       test->error = g_error_copy (error);
795       goto out;
796     }
797 
798   g_assert_cmpint (g_hash_table_size (properties), == , 4);
799 
800   filters = tp_asv_get_boxed (properties, "HandlerChannelFilter",
801       TP_ARRAY_TYPE_CHANNEL_CLASS_LIST);
802   check_filters (filters);
803 
804   bypass = tp_asv_get_boolean (properties, "BypassApproval", &valid);
805   g_assert (valid);
806   g_assert (bypass);
807 
808   capabilities = tp_asv_get_strv (properties, "Capabilities");
809   g_assert_cmpint (g_strv_length ((GStrv) capabilities), ==, 5);
810   g_assert (tp_strv_contains (capabilities, "badger"));
811   g_assert (tp_strv_contains (capabilities, "mushroom"));
812   g_assert (tp_strv_contains (capabilities, "snake"));
813   g_assert (tp_strv_contains (capabilities, "goat"));
814   g_assert (tp_strv_contains (capabilities, "pony"));
815 
816   handled = tp_asv_get_boxed (properties, "HandledChannels",
817       TP_ARRAY_TYPE_OBJECT_PATH_LIST);
818   g_assert (handled != NULL);
819   g_assert_cmpint (handled->len, ==, 0);
820 
821 out:
822   g_main_loop_quit (test->mainloop);
823 }
824 
825 static void
channel_invalidated_cb(TpChannel * channel,guint domain,gint code,gchar * message,Test * test)826 channel_invalidated_cb (TpChannel *channel,
827     guint domain,
828     gint code,
829     gchar *message,
830     Test *test)
831 {
832   g_main_loop_quit (test->mainloop);
833 }
834 
835 static void
test_handler(Test * test,gconstpointer data G_GNUC_UNUSED)836 test_handler (Test *test,
837     gconstpointer data G_GNUC_UNUSED)
838 {
839   GHashTable *filter;
840   const gchar *caps[] = { "mushroom", "snake", NULL };
841   GPtrArray *channels;
842   GPtrArray *requests_satisified;
843   GHashTable *info;
844   GList *chans;
845   TpTestsSimpleClient *client_2;
846 
847   filter = tp_asv_new (
848       TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_TEXT,
849       NULL);
850 
851   tp_base_client_add_handler_filter (test->base_client, filter);
852   g_hash_table_unref (filter);
853 
854   tp_base_client_take_handler_filter (test->base_client, tp_asv_new (
855         TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
856           TP_IFACE_CHANNEL_TYPE_STREAM_TUBE,
857         TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT,
858           TP_HANDLE_TYPE_CONTACT,
859         NULL));
860 
861   tp_base_client_set_handler_bypass_approval (test->base_client, TRUE);
862 
863   tp_base_client_add_handler_capability (test->base_client, "badger");
864   tp_base_client_add_handler_capabilities (test->base_client, caps);
865   tp_base_client_add_handler_capabilities_varargs (test->base_client,
866       "goat", "pony", NULL);
867 
868   tp_base_client_register (test->base_client, &test->error);
869   g_assert_no_error (test->error);
870 
871   /* Check Client properties */
872   tp_cli_dbus_properties_call_get_all (test->client, -1,
873       TP_IFACE_CLIENT, get_client_prop_cb, test, NULL, NULL);
874   g_main_loop_run (test->mainloop);
875 
876   g_assert_no_error (test->error);
877   g_assert_cmpint (g_strv_length (test->interfaces), ==, 1);
878   g_assert (tp_strv_contains ((const gchar * const *) test->interfaces,
879         TP_IFACE_CLIENT_HANDLER));
880 
881   /* Check Handler properties */
882   tp_cli_dbus_properties_call_get_all (test->client, -1,
883       TP_IFACE_CLIENT_HANDLER, get_handler_prop_cb, test, NULL, NULL);
884   g_main_loop_run (test->mainloop);
885   g_assert_no_error (test->error);
886 
887   g_assert (!tp_base_client_is_handling_channel (test->base_client,
888         test->text_chan));
889   g_assert (!tp_base_client_is_handling_channel (test->base_client,
890         test->text_chan_2));
891 
892   /* Call HandleChannels */
893   channels = g_ptr_array_sized_new (2);
894   add_channel_to_ptr_array (channels, test->text_chan);
895   add_channel_to_ptr_array (channels, test->text_chan_2);
896 
897   requests_satisified = g_ptr_array_sized_new (0);
898   info = g_hash_table_new (NULL, NULL);
899 
900   tp_proxy_add_interface_by_id (TP_PROXY (test->client),
901       TP_IFACE_QUARK_CLIENT_HANDLER);
902 
903   tp_cli_client_handler_call_handle_channels (test->client, -1,
904       tp_proxy_get_object_path (test->account),
905       tp_proxy_get_object_path (test->connection),
906       channels, requests_satisified, 0, info,
907       no_return_cb, test, NULL, NULL);
908 
909   test->wait++;
910   g_main_loop_run (test->mainloop);
911   g_assert_no_error (test->error);
912 
913   g_assert (test->simple_client->handle_channels_ctx != NULL);
914   g_assert (test->simple_client->handle_channels_ctx->account == test->account);
915 
916   chans = tp_base_client_get_handled_channels (test->base_client);
917   g_assert_cmpuint (g_list_length (chans), ==, 2);
918   g_list_free (chans);
919 
920   g_assert (tp_base_client_is_handling_channel (test->base_client,
921         test->text_chan));
922   g_assert (tp_base_client_is_handling_channel (test->base_client,
923         test->text_chan_2));
924 
925   /* One of the channel is closed */
926   g_signal_connect (test->text_chan, "invalidated",
927       G_CALLBACK (channel_invalidated_cb), test);
928   tp_tests_text_channel_null_close (test->text_chan_service);
929   g_main_loop_run (test->mainloop);
930 
931   chans = tp_base_client_get_handled_channels (test->base_client);
932   g_assert_cmpuint (g_list_length (chans), ==, 1);
933   g_list_free (chans);
934 
935   g_assert (!tp_base_client_is_handling_channel (test->base_client,
936         test->text_chan));
937   g_assert (tp_base_client_is_handling_channel (test->base_client,
938         test->text_chan_2));
939 
940   /* Create another client sharing the same unique name */
941   client_2 = tp_tests_simple_client_new (test->dbus, "Test", TRUE);
942   tp_base_client_be_a_handler (TP_BASE_CLIENT (client_2));
943   tp_base_client_register (TP_BASE_CLIENT (client_2), &test->error);
944   g_assert_no_error (test->error);
945 
946   chans = tp_base_client_get_handled_channels (TP_BASE_CLIENT (client_2));
947   g_assert_cmpuint (g_list_length (chans), ==, 1);
948   g_list_free (chans);
949 
950   g_assert (!tp_base_client_is_handling_channel (TP_BASE_CLIENT (client_2),
951         test->text_chan));
952   g_assert (tp_base_client_is_handling_channel (TP_BASE_CLIENT (client_2),
953         test->text_chan_2));
954 
955   g_object_unref (client_2);
956 
957   g_ptr_array_foreach (channels, free_channel_details, NULL);
958   g_ptr_array_unref (channels);
959   g_ptr_array_unref (requests_satisified);
960   g_hash_table_unref (info);
961 }
962 
963 /* Test Requests interface on Handler */
964 static void
get_requests_prop_cb(TpProxy * proxy,GHashTable * properties,const GError * error,gpointer user_data,GObject * weak_object)965 get_requests_prop_cb (TpProxy *proxy,
966     GHashTable *properties,
967     const GError *error,
968     gpointer user_data,
969     GObject *weak_object)
970 {
971   Test *test = user_data;
972 
973   if (error != NULL)
974     {
975       test->error = g_error_copy (error);
976       goto out;
977     }
978 
979   g_assert_cmpint (g_hash_table_size (properties), == , 0);
980 
981 out:
982   g_main_loop_quit (test->mainloop);
983 }
984 
985 static void
request_added_cb(TpBaseClient * client,TpAccount * account,TpChannelRequest * request,Test * test)986 request_added_cb (TpBaseClient *client,
987     TpAccount *account,
988     TpChannelRequest *request,
989     Test *test)
990 {
991   GList *requests;
992 
993   g_assert (TP_IS_CHANNEL_REQUEST (request));
994   g_assert (TP_IS_ACCOUNT (account));
995   g_assert (tp_proxy_is_prepared (account, TP_ACCOUNT_FEATURE_CORE));
996 
997   requests = tp_base_client_get_pending_requests (test->base_client);
998   g_assert_cmpuint (g_list_length ((GList *) requests), ==, 1);
999   g_assert (requests->data == request);
1000   g_list_free (requests);
1001 
1002   test->wait--;
1003   if (test->wait == 0)
1004     g_main_loop_quit (test->mainloop);
1005 }
1006 
1007 static void
request_removed_cb(TpBaseClient * client,TpChannelRequest * request,const gchar * error,const gchar * reason,Test * test)1008 request_removed_cb (TpBaseClient *client,
1009     TpChannelRequest *request,
1010     const gchar *error,
1011     const gchar *reason,
1012     Test *test)
1013 {
1014   g_assert (TP_IS_CHANNEL_REQUEST (request));
1015 
1016   test->wait--;
1017   if (test->wait == 0)
1018     g_main_loop_quit (test->mainloop);
1019 }
1020 
1021 static void
test_handler_requests(Test * test,gconstpointer data G_GNUC_UNUSED)1022 test_handler_requests (Test *test,
1023     gconstpointer data G_GNUC_UNUSED)
1024 {
1025   GHashTable *properties;
1026   GPtrArray *channels;
1027   GPtrArray *requests_satisified;
1028   GHashTable *info;
1029   TpChannelRequest *request;
1030   GList *requests;
1031 
1032   tp_base_client_take_handler_filter (test->base_client, tp_asv_new (
1033         TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
1034           TP_IFACE_CHANNEL_TYPE_STREAM_TUBE,
1035         TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT,
1036           TP_HANDLE_TYPE_CONTACT,
1037         NULL));
1038 
1039   tp_base_client_set_handler_request_notification (test->base_client);
1040 
1041   tp_base_client_register (test->base_client, &test->error);
1042   g_assert_no_error (test->error);
1043 
1044   /* Check Client properties */
1045   tp_cli_dbus_properties_call_get_all (test->client, -1,
1046       TP_IFACE_CLIENT, get_client_prop_cb, test, NULL, NULL);
1047   g_main_loop_run (test->mainloop);
1048 
1049   g_assert_no_error (test->error);
1050   g_assert_cmpint (g_strv_length (test->interfaces), ==, 2);
1051   g_assert (tp_strv_contains ((const gchar * const *) test->interfaces,
1052         TP_IFACE_CLIENT_HANDLER));
1053   g_assert (tp_strv_contains ((const gchar * const *) test->interfaces,
1054         TP_IFACE_CLIENT_INTERFACE_REQUESTS));
1055 
1056   /* Check Requests properties */
1057   tp_cli_dbus_properties_call_get_all (test->client, -1,
1058       TP_IFACE_CLIENT_INTERFACE_REQUESTS, get_requests_prop_cb,
1059       test, NULL, NULL);
1060   g_main_loop_run (test->mainloop);
1061   g_assert_no_error (test->error);
1062 
1063   g_assert (tp_base_client_get_pending_requests (test->base_client) == NULL);
1064 
1065   /* Call AddRequest */
1066   properties = tp_asv_new (
1067       TP_PROP_CHANNEL_REQUEST_ACCOUNT, DBUS_TYPE_G_OBJECT_PATH, ACCOUNT_PATH,
1068       NULL);
1069 
1070   tp_proxy_add_interface_by_id (TP_PROXY (test->client),
1071       TP_IFACE_QUARK_CLIENT_INTERFACE_REQUESTS);
1072 
1073   g_signal_connect (test->base_client, "request-added",
1074       G_CALLBACK (request_added_cb), test);
1075 
1076   tp_cli_client_interface_requests_call_add_request (test->client, -1,
1077       "/Request", properties,
1078       no_return_cb, test, NULL, NULL);
1079 
1080   test->wait = 2;
1081   g_main_loop_run (test->mainloop);
1082   g_assert_no_error (test->error);
1083 
1084   requests = tp_base_client_get_pending_requests (test->base_client);
1085   g_assert (requests != NULL);
1086   g_list_free (requests);
1087 
1088   /* Call HandleChannels */
1089   channels = g_ptr_array_sized_new (2);
1090   add_channel_to_ptr_array (channels, test->text_chan);
1091 
1092   requests_satisified = g_ptr_array_sized_new (1);
1093   g_ptr_array_add (requests_satisified, "/Request");
1094 
1095   info = g_hash_table_new (NULL, NULL);
1096 
1097   tp_proxy_add_interface_by_id (TP_PROXY (test->client),
1098       TP_IFACE_QUARK_CLIENT_HANDLER);
1099 
1100   tp_cli_client_handler_call_handle_channels (test->client, -1,
1101       tp_proxy_get_object_path (test->account),
1102       tp_proxy_get_object_path (test->connection),
1103       channels, requests_satisified, 0, info,
1104       no_return_cb, test, NULL, NULL);
1105 
1106   test->wait++;
1107   g_main_loop_run (test->mainloop);
1108   g_assert_no_error (test->error);
1109 
1110   g_assert (test->simple_client->handle_channels_ctx != NULL);
1111   g_assert_cmpint (
1112       test->simple_client->handle_channels_ctx->requests_satisfied->len, ==, 1);
1113   request = g_ptr_array_index (
1114       test->simple_client->handle_channels_ctx->requests_satisfied, 0);
1115   requests = tp_base_client_get_pending_requests (test->base_client);
1116   g_assert (requests->data == request);
1117   g_list_free (requests);
1118 
1119   /* Call RemoveRequest */
1120   g_signal_connect (test->base_client, "request-removed",
1121       G_CALLBACK (request_removed_cb), test);
1122 
1123   tp_cli_client_interface_requests_call_remove_request (test->client, -1,
1124       "/Request", "Badger", "snake",
1125       no_return_cb, test, NULL, NULL);
1126 
1127   test->wait = 2;
1128   g_main_loop_run (test->mainloop);
1129   g_assert_no_error (test->error);
1130 
1131   g_assert (tp_base_client_get_pending_requests (test->base_client) == NULL);
1132 
1133   g_hash_table_unref (properties);
1134   g_ptr_array_foreach (channels, free_channel_details, NULL);
1135   g_ptr_array_unref (channels);
1136   g_ptr_array_unref (requests_satisified);
1137   g_hash_table_unref (info);
1138 }
1139 
1140 static void
claim_with_cb(GObject * source,GAsyncResult * result,gpointer user_data)1141 claim_with_cb (GObject *source,
1142     GAsyncResult *result,
1143     gpointer user_data)
1144 {
1145   Test *test = user_data;
1146 
1147   tp_channel_dispatch_operation_claim_with_finish (
1148       TP_CHANNEL_DISPATCH_OPERATION (source), result, &test->error);
1149 
1150   test->wait--;
1151   if (test->wait == 0)
1152     g_main_loop_quit (test->mainloop);
1153 }
1154 
1155 static void
cdo_finished_cb(TpTestsSimpleChannelDispatchOperation * cdo,Test * test)1156 cdo_finished_cb (TpTestsSimpleChannelDispatchOperation *cdo,
1157     Test *test)
1158 {
1159   tp_clear_object (&test->cdo_service);
1160 }
1161 
1162 static void
test_channel_dispatch_operation_claim_with_async(Test * test,gconstpointer data G_GNUC_UNUSED)1163 test_channel_dispatch_operation_claim_with_async (Test *test,
1164     gconstpointer data G_GNUC_UNUSED)
1165 {
1166   GPtrArray *channels;
1167   GHashTable *properties;
1168   static const char *interfaces[] = { NULL };
1169   static const gchar *possible_handlers[] = {
1170     TP_CLIENT_BUS_NAME_BASE ".Badger", NULL, };
1171   TpChannelDispatchOperation *cdo;
1172   GList *handled;
1173 
1174   /* Register an Approver and Handler */
1175   tp_base_client_take_approver_filter (test->base_client, tp_asv_new (
1176         TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
1177           TP_IFACE_CHANNEL_TYPE_TEXT,
1178         NULL));
1179 
1180   tp_base_client_take_handler_filter (test->base_client, tp_asv_new (
1181         TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
1182           TP_IFACE_CHANNEL_TYPE_TEXT,
1183         NULL));
1184 
1185   tp_base_client_register (test->base_client, &test->error);
1186   g_assert_no_error (test->error);
1187 
1188   /* Call AddDispatchOperation */
1189   channels = g_ptr_array_sized_new (2);
1190   add_channel_to_ptr_array (channels, test->text_chan);
1191   add_channel_to_ptr_array (channels, test->text_chan_2);
1192 
1193   properties = tp_asv_new (
1194       TP_PROP_CHANNEL_DISPATCH_OPERATION_INTERFACES,
1195         G_TYPE_STRV, interfaces,
1196       TP_PROP_CHANNEL_DISPATCH_OPERATION_CONNECTION,
1197         DBUS_TYPE_G_OBJECT_PATH, tp_proxy_get_object_path (test->connection),
1198       TP_PROP_CHANNEL_DISPATCH_OPERATION_ACCOUNT,
1199         DBUS_TYPE_G_OBJECT_PATH, tp_proxy_get_object_path (test->account),
1200       TP_PROP_CHANNEL_DISPATCH_OPERATION_POSSIBLE_HANDLERS,
1201         G_TYPE_STRV, possible_handlers,
1202       NULL);
1203 
1204   tp_proxy_add_interface_by_id (TP_PROXY (test->client),
1205       TP_IFACE_QUARK_CLIENT_APPROVER);
1206 
1207   tp_cli_client_approver_call_add_dispatch_operation (test->client, -1,
1208       channels, CDO_PATH, properties,
1209       no_return_cb, test, NULL, NULL);
1210 
1211   test->wait++;
1212   g_main_loop_run (test->mainloop);
1213   g_assert_no_error (test->error);
1214 
1215   cdo = test->simple_client->add_dispatch_ctx->dispatch_operation;
1216   g_assert (TP_IS_CHANNEL_DISPATCH_OPERATION (cdo));
1217 
1218   handled = tp_base_client_get_handled_channels (test->base_client);
1219   g_assert (handled == NULL);
1220 
1221   /* Connect to CDO's Finished signal so we can remove it from the bus when
1222    * it's claimed as MC would do. */
1223   g_signal_connect (test->cdo_service, "finished",
1224       G_CALLBACK (cdo_finished_cb), test);
1225 
1226   /* Claim the CDO, as the client is also a Handler, it is now handling the
1227    * channels */
1228   tp_channel_dispatch_operation_claim_with_async (cdo, test->base_client,
1229       claim_with_cb, test);
1230 
1231   test->wait++;
1232   g_main_loop_run (test->mainloop);
1233   g_assert_no_error (test->error);
1234 
1235   handled = tp_base_client_get_handled_channels (test->base_client);
1236   g_assert_cmpuint (g_list_length (handled), ==, 2);
1237   g_list_free (handled);
1238 
1239   g_assert (tp_base_client_is_handling_channel (test->base_client,
1240         test->text_chan));
1241   g_assert (tp_base_client_is_handling_channel (test->base_client,
1242         test->text_chan_2));
1243 
1244   g_ptr_array_foreach (channels, free_channel_details, NULL);
1245   g_ptr_array_unref (channels);
1246   g_hash_table_unref (properties);
1247 }
1248 
1249 static void
delegate_channels_cb(GObject * source,GAsyncResult * result,gpointer user_data)1250 delegate_channels_cb (GObject *source,
1251     GAsyncResult *result,
1252     gpointer user_data)
1253 {
1254   Test *test = user_data;
1255 
1256   tp_base_client_delegate_channels_finish (
1257       TP_BASE_CLIENT (source), result, &test->delegated, &test->not_delegated,
1258       &test->error);
1259 
1260   test->wait--;
1261   if (test->wait == 0)
1262     g_main_loop_quit (test->mainloop);
1263 }
1264 
1265 static void
test_delegate_channels(Test * test,gconstpointer data G_GNUC_UNUSED)1266 test_delegate_channels (Test *test,
1267     gconstpointer data G_GNUC_UNUSED)
1268 {
1269   GPtrArray *channels;
1270   GPtrArray *requests_satisified;
1271   GHashTable *info;
1272   GList *chans;
1273   GError *error = NULL;
1274 
1275   tp_base_client_be_a_handler (test->base_client);
1276 
1277   tp_base_client_register (test->base_client, &test->error);
1278   g_assert_no_error (test->error);
1279 
1280   /* Call HandleChannels */
1281   channels = g_ptr_array_sized_new (2);
1282   add_channel_to_ptr_array (channels, test->text_chan);
1283   add_channel_to_ptr_array (channels, test->text_chan_2);
1284 
1285   requests_satisified = g_ptr_array_sized_new (0);
1286   info = g_hash_table_new (NULL, NULL);
1287 
1288   tp_proxy_add_interface_by_id (TP_PROXY (test->client),
1289       TP_IFACE_QUARK_CLIENT_HANDLER);
1290 
1291   tp_cli_client_handler_call_handle_channels (test->client, -1,
1292       tp_proxy_get_object_path (test->account),
1293       tp_proxy_get_object_path (test->connection),
1294       channels, requests_satisified, 0, info,
1295       no_return_cb, test, NULL, NULL);
1296 
1297   test->wait++;
1298   g_main_loop_run (test->mainloop);
1299   g_assert_no_error (test->error);
1300 
1301   /* The client is handling the 2 channels */
1302   chans = tp_base_client_get_handled_channels (test->base_client);
1303   g_assert_cmpuint (g_list_length (chans), ==, 2);
1304   g_list_free (chans);
1305 
1306   g_assert (tp_base_client_is_handling_channel (test->base_client,
1307         test->text_chan));
1308   g_assert (tp_base_client_is_handling_channel (test->base_client,
1309         test->text_chan_2));
1310 
1311   /* Try to delegate the first one */
1312   chans = g_list_append (NULL, test->text_chan);
1313 
1314   tp_base_client_delegate_channels_async (test->base_client,
1315       chans, TP_USER_ACTION_TIME_CURRENT_TIME, NULL,
1316       delegate_channels_cb, test);
1317 
1318   g_list_free (chans);
1319 
1320   test->wait++;
1321   g_main_loop_run (test->mainloop);
1322   g_assert_no_error (test->error);
1323 
1324   g_assert_cmpuint (test->delegated->len, ==, 1);
1325   g_assert (g_ptr_array_index (test->delegated, 0) == test->text_chan);
1326   g_assert_cmpuint (g_hash_table_size (test->not_delegated), ==, 0);
1327 
1328   /* Client is not handling the channel any more */
1329   chans = tp_base_client_get_handled_channels (test->base_client);
1330   g_assert_cmpuint (g_list_length (chans), ==, 1);
1331   g_list_free (chans);
1332 
1333   g_assert (!tp_base_client_is_handling_channel (test->base_client,
1334         test->text_chan));
1335   g_assert (tp_base_client_is_handling_channel (test->base_client,
1336         test->text_chan_2));
1337 
1338   /* Try delegating the second channel, but MC refuses */
1339   test->cd_service->refuse_delegate = TRUE;
1340 
1341   chans = g_list_append (NULL, test->text_chan_2);
1342 
1343   tp_base_client_delegate_channels_async (test->base_client,
1344       chans, TP_USER_ACTION_TIME_CURRENT_TIME, NULL,
1345       delegate_channels_cb, test);
1346 
1347   g_list_free (chans);
1348 
1349   test->wait++;
1350   g_main_loop_run (test->mainloop);
1351   g_assert_no_error (test->error);
1352 
1353   g_assert_cmpuint (test->delegated->len, ==, 0);
1354   g_assert_cmpuint (g_hash_table_size (test->not_delegated), ==, 1);
1355   error = g_hash_table_lookup (test->not_delegated, test->text_chan_2);
1356   g_assert_error (error, TP_ERROR, TP_ERROR_BUSY);
1357 
1358   /* Client is still handling the channel */
1359   chans = tp_base_client_get_handled_channels (test->base_client);
1360   g_assert_cmpuint (g_list_length (chans), ==, 1);
1361   g_list_free (chans);
1362 
1363   g_assert (!tp_base_client_is_handling_channel (test->base_client,
1364         test->text_chan));
1365   g_assert (tp_base_client_is_handling_channel (test->base_client,
1366         test->text_chan_2));
1367 
1368   g_ptr_array_foreach (channels, free_channel_details, NULL);
1369   g_ptr_array_unref (channels);
1370   g_ptr_array_unref (requests_satisified);
1371   g_hash_table_unref (info);
1372 }
1373 
1374 static void
present_channel_cb(GObject * source,GAsyncResult * result,gpointer user_data)1375 present_channel_cb (GObject *source,
1376     GAsyncResult *result,
1377     gpointer user_data)
1378 {
1379   Test *test = user_data;
1380 
1381   tp_channel_dispatcher_present_channel_finish (
1382       TP_CHANNEL_DISPATCHER (source), result, &test->error);
1383 
1384   test->wait--;
1385   if (test->wait == 0)
1386     g_main_loop_quit (test->mainloop);
1387 }
1388 
1389 static void
test_present_channel(Test * test,gconstpointer data G_GNUC_UNUSED)1390 test_present_channel (Test *test,
1391     gconstpointer data G_GNUC_UNUSED)
1392 {
1393   TpChannelDispatcher *cd;
1394 
1395   cd = tp_channel_dispatcher_new (test->dbus);
1396 
1397   tp_channel_dispatcher_present_channel_async (cd, test->text_chan,
1398       TP_USER_ACTION_TIME_CURRENT_TIME, present_channel_cb, test);
1399 
1400   test->wait++;
1401   g_main_loop_run (test->mainloop);
1402   g_assert_no_error (test->error);
1403 
1404   g_object_unref (cd);
1405 }
1406 
1407 #define PREFERRED_HANDLER_NAME TP_CLIENT_BUS_NAME_BASE ".Badger"
1408 
1409 static gboolean
channel_in_array(GPtrArray * array,TpChannel * channel)1410 channel_in_array (GPtrArray *array,
1411     TpChannel *channel)
1412 {
1413   guint i;
1414 
1415   for (i = 0; i < array->len; i++)
1416     {
1417       TpChannel *c = g_ptr_array_index (array, i);
1418 
1419       if (!tp_strdiff (tp_proxy_get_object_path (channel),
1420             tp_proxy_get_object_path (c)))
1421         return TRUE;
1422     }
1423 
1424   return FALSE;
1425 }
1426 
1427 static void
delegated_channels_cb(TpBaseClient * client,GPtrArray * channels,gpointer user_data)1428 delegated_channels_cb (TpBaseClient *client,
1429     GPtrArray *channels,
1430     gpointer user_data)
1431 {
1432   Test *test = user_data;
1433 
1434   g_assert_cmpuint (channels->len, ==, 2);
1435 
1436   g_assert (channel_in_array (channels, test->text_chan));
1437   g_assert (channel_in_array (channels, test->text_chan_2));
1438 
1439   test->wait--;
1440   if (test->wait == 0)
1441     g_main_loop_quit (test->mainloop);
1442 }
1443 
1444 static void
delegate_to_preferred_handler(Test * test,gboolean supported)1445 delegate_to_preferred_handler (Test *test,
1446     gboolean supported)
1447 {
1448   GPtrArray *channels;
1449   GPtrArray *requests_satisified;
1450   GPtrArray *requests;
1451   GHashTable *request_props;
1452   GHashTable *info;
1453   TpTestsSimpleChannelRequest *cr;
1454   GHashTable *hints;
1455 
1456   tp_base_client_be_a_handler (test->base_client);
1457 
1458   if (supported)
1459     {
1460       tp_base_client_set_delegated_channels_callback (test->base_client,
1461           delegated_channels_cb, test, NULL);
1462     }
1463 
1464   tp_base_client_register (test->base_client, &test->error);
1465   g_assert_no_error (test->error);
1466 
1467   /* Call HandleChannels */
1468   channels = g_ptr_array_sized_new (2);
1469   add_channel_to_ptr_array (channels, test->text_chan);
1470   add_channel_to_ptr_array (channels, test->text_chan_2);
1471 
1472   requests_satisified = g_ptr_array_sized_new (0);
1473   info = g_hash_table_new (NULL, NULL);
1474 
1475   tp_proxy_add_interface_by_id (TP_PROXY (test->client),
1476       TP_IFACE_QUARK_CLIENT_HANDLER);
1477 
1478   tp_cli_client_handler_call_handle_channels (test->client, -1,
1479       tp_proxy_get_object_path (test->account),
1480       tp_proxy_get_object_path (test->connection),
1481       channels, requests_satisified, 0, info,
1482       no_return_cb, test, NULL, NULL);
1483 
1484   test->wait++;
1485   g_main_loop_run (test->mainloop);
1486   g_assert_no_error (test->error);
1487 
1488   /* The client is handling the 2 channels */
1489   g_assert (tp_base_client_is_handling_channel (test->base_client,
1490         test->text_chan));
1491   g_assert (tp_base_client_is_handling_channel (test->base_client,
1492         test->text_chan_2));
1493 
1494   /* Another client asks to dispatch the channel to it */
1495   requests = g_ptr_array_new ();
1496 
1497   hints = tp_asv_new (
1498       "org.freedesktop.Telepathy.ChannelRequest.DelegateToPreferredHandler",
1499         G_TYPE_BOOLEAN, TRUE,
1500       NULL);
1501 
1502   cr = tp_tests_simple_channel_request_new ("/CR",
1503       TP_TESTS_SIMPLE_CONNECTION (test->base_connection), ACCOUNT_PATH,
1504       TP_USER_ACTION_TIME_CURRENT_TIME, PREFERRED_HANDLER_NAME,
1505       requests, hints);
1506 
1507   g_ptr_array_add (requests_satisified, "/CR");
1508 
1509   request_props = g_hash_table_new_full (g_str_hash, g_str_equal,
1510       NULL, (GDestroyNotify) g_hash_table_unref);
1511 
1512   g_hash_table_insert (request_props, "/CR",
1513       tp_tests_simple_channel_request_dup_immutable_props (cr));
1514 
1515   tp_asv_set_boxed (info,
1516       "request-properties", TP_HASH_TYPE_OBJECT_IMMUTABLE_PROPERTIES_MAP,
1517       request_props);
1518 
1519   tp_cli_client_handler_call_handle_channels (test->client, -1,
1520       tp_proxy_get_object_path (test->account),
1521       tp_proxy_get_object_path (test->connection),
1522       channels, requests_satisified, 0, info,
1523       no_return_cb, test, NULL, NULL);
1524 
1525   test->wait = 1;
1526 
1527   /* If we support the DelegateToPreferredHandler hint, we wait for
1528    * delegated_channels_cb to be called */
1529   if (supported)
1530     test->wait++;
1531 
1532   g_main_loop_run (test->mainloop);
1533   g_assert_no_error (test->error);
1534 
1535   if (supported)
1536     {
1537       /* We are not handling the channels any more */
1538       g_assert (!tp_base_client_is_handling_channel (test->base_client,
1539             test->text_chan));
1540       g_assert (!tp_base_client_is_handling_channel (test->base_client,
1541             test->text_chan_2));
1542     }
1543   else
1544     {
1545       /* We are still handling the channels */
1546       g_assert (tp_base_client_is_handling_channel (test->base_client,
1547             test->text_chan));
1548       g_assert (tp_base_client_is_handling_channel (test->base_client,
1549             test->text_chan_2));
1550     }
1551 
1552   tp_base_client_unregister (test->base_client);
1553 
1554   g_object_unref (cr);
1555   g_ptr_array_foreach (channels, free_channel_details, NULL);
1556   g_ptr_array_unref (channels);
1557   g_ptr_array_unref (requests_satisified);
1558   g_ptr_array_unref (requests);
1559   g_hash_table_unref (info);
1560   g_hash_table_unref (hints);
1561   g_hash_table_unref (request_props);
1562 }
1563 
1564 static void
test_delegate_to_preferred_handler_not_supported(Test * test,gconstpointer data G_GNUC_UNUSED)1565 test_delegate_to_preferred_handler_not_supported (Test *test,
1566     gconstpointer data G_GNUC_UNUSED)
1567 {
1568   delegate_to_preferred_handler (test, FALSE);
1569 }
1570 
1571 static void
test_delegate_to_preferred_handler_supported(Test * test,gconstpointer data G_GNUC_UNUSED)1572 test_delegate_to_preferred_handler_supported (Test *test,
1573     gconstpointer data G_GNUC_UNUSED)
1574 {
1575   delegate_to_preferred_handler (test, TRUE);
1576 }
1577 
1578 int
main(int argc,char ** argv)1579 main (int argc,
1580       char **argv)
1581 {
1582   tp_tests_init (&argc, &argv);
1583 
1584   g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
1585 
1586   g_test_add ("/base-client/basics", Test, NULL, setup, test_basics, teardown);
1587   g_test_add ("/base-client/register", Test, NULL, setup, test_register,
1588       teardown);
1589   g_test_add ("/base-client/observer", Test, NULL, setup, test_observer,
1590       teardown);
1591   g_test_add ("/base-client/approver", Test, NULL, setup, test_approver,
1592       teardown);
1593   g_test_add ("/base-client/handler", Test, NULL, setup, test_handler,
1594       teardown);
1595   g_test_add ("/base-client/handler-requests", Test, NULL, setup,
1596       test_handler_requests, teardown);
1597   g_test_add ("/cdo/claim_with", Test, NULL, setup,
1598       test_channel_dispatch_operation_claim_with_async, teardown);
1599   g_test_add ("/base-client/delegate-channels", Test, NULL, setup,
1600       test_delegate_channels, teardown);
1601   g_test_add ("/cd/present-channel", Test, NULL, setup,
1602       test_present_channel, teardown);
1603   g_test_add ("/cd/delegate-to-preferred-handler/not-supported", Test, NULL,
1604       setup, test_delegate_to_preferred_handler_not_supported, teardown);
1605   g_test_add ("/cd/delegate-to-preferred-handler/supported", Test, NULL,
1606       setup, test_delegate_to_preferred_handler_supported, teardown);
1607 
1608   return tp_tests_run_with_bus ();
1609 }
1610