1 /* Tests of TpSimpleHandler
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 #include <telepathy-glib/simple-handler.h>
13 #include <telepathy-glib/client.h>
14 #include <telepathy-glib/debug.h>
15 #include <telepathy-glib/defs.h>
16 #include <telepathy-glib/proxy-subclass.h>
17 
18 #include "tests/lib/util.h"
19 #include "tests/lib/simple-account.h"
20 #include "tests/lib/simple-conn.h"
21 #include "tests/lib/textchan-null.h"
22 
23 typedef struct {
24     GMainLoop *mainloop;
25     TpDBusDaemon *dbus;
26 
27     /* Service side objects */
28     TpBaseClient *simple_handler;
29     TpBaseConnection *base_connection;
30     TpTestsSimpleAccount *account_service;
31     TpTestsTextChannelNull *text_chan_service;
32 
33     /* Client side objects */
34     TpClient *client;
35     TpConnection *connection;
36     TpAccount *account;
37     TpChannel *text_chan;
38 
39     GError *error /* initialized where needed */;
40 } Test;
41 
42 #define ACCOUNT_PATH TP_ACCOUNT_OBJECT_PATH_BASE "what/ev/er"
43 
44 static void
setup(Test * test,gconstpointer data)45 setup (Test *test,
46        gconstpointer data)
47 {
48   gchar *chan_path;
49   TpHandle handle;
50   TpHandleRepoIface *contact_repo;
51 
52   test->mainloop = g_main_loop_new (NULL, FALSE);
53   test->dbus = tp_tests_dbus_daemon_dup_or_die ();
54 
55   test->error = NULL;
56 
57   /* Claim AccountManager bus-name (needed as we're going to export an Account
58    * object). */
59   tp_dbus_daemon_request_name (test->dbus,
60           TP_ACCOUNT_MANAGER_BUS_NAME, FALSE, &test->error);
61   g_assert_no_error (test->error);
62 
63   /* Create service-side Account object */
64   test->account_service = tp_tests_object_new_static_class (
65       TP_TESTS_TYPE_SIMPLE_ACCOUNT, NULL);
66   tp_dbus_daemon_register_object (test->dbus, ACCOUNT_PATH,
67       test->account_service);
68 
69    /* Create client-side Account object */
70   test->account = tp_account_new (test->dbus, ACCOUNT_PATH, NULL);
71   g_assert (test->account != NULL);
72 
73   /* Create (service and client sides) connection objects */
74   tp_tests_create_and_connect_conn (TP_TESTS_TYPE_SIMPLE_CONNECTION,
75       "me@test.com", &test->base_connection, &test->connection);
76 
77   /* Create service-side text channel object */
78   chan_path = g_strdup_printf ("%s/Channel",
79       tp_proxy_get_object_path (test->connection));
80 
81   contact_repo = tp_base_connection_get_handles (test->base_connection,
82       TP_HANDLE_TYPE_CONTACT);
83   g_assert (contact_repo != NULL);
84 
85   handle = tp_handle_ensure (contact_repo, "bob", NULL, &test->error);
86   g_assert_no_error (test->error);
87 
88   test->text_chan_service = TP_TESTS_TEXT_CHANNEL_NULL (
89       tp_tests_object_new_static_class (
90         TP_TESTS_TYPE_TEXT_CHANNEL_NULL,
91         "connection", test->base_connection,
92         "object-path", chan_path,
93         "handle", handle,
94         NULL));
95 
96   /* Create client-side text channel object */
97   test->text_chan = tp_channel_new (test->connection, chan_path, NULL,
98       TP_HANDLE_TYPE_CONTACT, handle, &test->error);
99   g_assert_no_error (test->error);
100 
101   tp_handle_unref (contact_repo, handle);
102 
103   g_free (chan_path);
104 }
105 
106 static void
teardown_channel_invalidated_cb(TpChannel * self,guint domain,gint code,gchar * message,Test * test)107 teardown_channel_invalidated_cb (TpChannel *self,
108   guint domain,
109   gint code,
110   gchar *message,
111   Test *test)
112 {
113   g_main_loop_quit (test->mainloop);
114 }
115 
116 static void
teardown_run_close_channel(Test * test,TpChannel * channel)117 teardown_run_close_channel (Test *test, TpChannel *channel)
118 {
119   if (channel != NULL && tp_proxy_get_invalidated (channel) == NULL)
120     {
121       g_signal_connect (channel, "invalidated",
122           G_CALLBACK (teardown_channel_invalidated_cb), test);
123       tp_cli_channel_call_close (channel, -1, NULL, NULL, NULL, NULL);
124       g_main_loop_run (test->mainloop);
125     }
126 }
127 
128 static void
teardown(Test * test,gconstpointer data)129 teardown (Test *test,
130           gconstpointer data)
131 {
132   teardown_run_close_channel (test, test->text_chan);
133 
134   g_clear_error (&test->error);
135 
136   g_object_unref (test->simple_handler);
137   g_object_unref (test->client);
138 
139   tp_dbus_daemon_unregister_object (test->dbus, test->account_service);
140   g_object_unref (test->account_service);
141 
142   tp_dbus_daemon_release_name (test->dbus, TP_ACCOUNT_MANAGER_BUS_NAME,
143       &test->error);
144   g_assert_no_error (test->error);
145 
146   g_object_unref (test->dbus);
147   test->dbus = NULL;
148   g_main_loop_unref (test->mainloop);
149   test->mainloop = NULL;
150 
151   g_object_unref (test->account);
152 
153   g_object_unref (test->text_chan_service);
154   g_object_unref (test->text_chan);
155 
156   tp_tests_connection_assert_disconnect_succeeds (test->connection);
157   g_object_unref (test->connection);
158   g_object_unref (test->base_connection);
159 }
160 
161 static void
create_simple_handler(Test * test,gboolean bypass_approval,gboolean requests,TpSimpleHandlerHandleChannelsImpl impl)162 create_simple_handler (Test *test,
163     gboolean bypass_approval,
164     gboolean requests,
165     TpSimpleHandlerHandleChannelsImpl impl)
166 {
167   /* Create service-side Client object */
168   test->simple_handler = tp_tests_object_new_static_class (
169       TP_TYPE_SIMPLE_HANDLER,
170       "dbus-daemon", test->dbus,
171       "bypass-approval", bypass_approval,
172       "requests", requests,
173       "name", "MySimpleHandler",
174       "uniquify-name", FALSE,
175       "callback", impl,
176       "user-data", test,
177       "destroy", NULL,
178       NULL);
179   g_assert (test->simple_handler != NULL);
180 
181  /* Create client-side Client object */
182   test->client = tp_tests_object_new_static_class (TP_TYPE_CLIENT,
183           "dbus-daemon", test->dbus,
184           "bus-name", tp_base_client_get_bus_name (test->simple_handler),
185           "object-path", tp_base_client_get_object_path (test->simple_handler),
186           NULL);
187 
188   g_assert (test->client != NULL);
189 }
190 
191 static void
get_client_prop_cb(TpProxy * proxy,GHashTable * properties,const GError * error,gpointer user_data,GObject * weak_object)192 get_client_prop_cb (TpProxy *proxy,
193     GHashTable *properties,
194     const GError *error,
195     gpointer user_data,
196     GObject *weak_object)
197 {
198   Test *test = user_data;
199   const gchar * const *interfaces;
200 
201   if (error != NULL)
202     {
203       test->error = g_error_copy (error);
204       goto out;
205     }
206 
207   g_assert_cmpint (g_hash_table_size (properties), == , 1);
208 
209   interfaces = tp_asv_get_strv (properties, "Interfaces");
210   g_assert_cmpint (g_strv_length ((GStrv) interfaces), ==, 2);
211   g_assert (tp_strv_contains (interfaces, TP_IFACE_CLIENT_HANDLER));
212   g_assert (tp_strv_contains (interfaces, TP_IFACE_CLIENT_INTERFACE_REQUESTS));
213 
214 out:
215   g_main_loop_quit (test->mainloop);
216 }
217 
218 static void
check_filters(GPtrArray * filters)219 check_filters (GPtrArray *filters)
220 {
221   GHashTable *filter;
222 
223   g_assert (filters != NULL);
224   g_assert_cmpuint (filters->len, ==, 2);
225 
226   filter = g_ptr_array_index (filters, 0);
227   g_assert_cmpuint (g_hash_table_size (filter), ==, 1);
228   g_assert_cmpstr (tp_asv_get_string (filter, TP_PROP_CHANNEL_CHANNEL_TYPE), ==,
229       TP_IFACE_CHANNEL_TYPE_TEXT);
230 
231   filter = g_ptr_array_index (filters, 1);
232   g_assert_cmpuint (g_hash_table_size (filter), ==, 2);
233   g_assert_cmpstr (tp_asv_get_string (filter, TP_PROP_CHANNEL_CHANNEL_TYPE), ==,
234       TP_IFACE_CHANNEL_TYPE_STREAM_TUBE);
235   g_assert_cmpuint (tp_asv_get_uint32 (filter,
236         TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL), ==, TP_HANDLE_TYPE_CONTACT);
237 }
238 
239 static void
get_handler_prop_cb(TpProxy * proxy,GHashTable * properties,const GError * error,gpointer user_data,GObject * weak_object)240 get_handler_prop_cb (TpProxy *proxy,
241     GHashTable *properties,
242     const GError *error,
243     gpointer user_data,
244     GObject *weak_object)
245 {
246   Test *test = user_data;
247   GPtrArray *filters;
248   gboolean bypass;
249   gboolean valid;
250   const gchar * const * capabilities;
251   GPtrArray *handled;
252 
253   if (error != NULL)
254     {
255       test->error = g_error_copy (error);
256       goto out;
257     }
258 
259   g_assert_cmpint (g_hash_table_size (properties), == , 4);
260 
261   filters = tp_asv_get_boxed (properties, "HandlerChannelFilter",
262       TP_ARRAY_TYPE_CHANNEL_CLASS_LIST);
263   check_filters (filters);
264 
265   bypass = tp_asv_get_boolean (properties, "BypassApproval", &valid);
266   g_assert (valid);
267   g_assert (!bypass);
268 
269   capabilities = tp_asv_get_strv (properties, "Capabilities");
270   g_assert_cmpint (g_strv_length ((GStrv) capabilities), ==, 0);
271 
272   handled = tp_asv_get_boxed (properties, "HandledChannels",
273       TP_ARRAY_TYPE_OBJECT_PATH_LIST);
274   g_assert (handled != NULL);
275   g_assert_cmpint (handled->len, ==, 0);
276 
277 out:
278   g_main_loop_quit (test->mainloop);
279 }
280 
281 static void
handle_channels_success(TpSimpleHandler * handler,TpAccount * account,TpConnection * connection,GList * channels,GList * requests_satisified,gint64 user_action_time,TpHandleChannelsContext * context,gpointer user_data)282 handle_channels_success (
283     TpSimpleHandler *handler,
284     TpAccount *account,
285     TpConnection *connection,
286     GList *channels,
287     GList *requests_satisified,
288     gint64 user_action_time,
289     TpHandleChannelsContext *context,
290     gpointer user_data)
291 {
292   tp_handle_channels_context_accept (context);
293 }
294 
295 static void
test_properties(Test * test,gconstpointer data G_GNUC_UNUSED)296 test_properties (Test *test,
297     gconstpointer data G_GNUC_UNUSED)
298 {
299   create_simple_handler (test, FALSE, TRUE, handle_channels_success);
300 
301   tp_base_client_add_handler_filter_vardict (test->simple_handler,
302       g_variant_new_parsed ("{ %s: <%s> }",
303         TP_PROP_CHANNEL_CHANNEL_TYPE, TP_IFACE_CHANNEL_TYPE_TEXT));
304 
305   tp_base_client_add_handler_filter_vardict (test->simple_handler,
306       g_variant_new_parsed ("{ %s: <%s>, %s: <%u> }",
307         TP_PROP_CHANNEL_CHANNEL_TYPE, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE,
308         TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, (guint32) TP_HANDLE_TYPE_CONTACT));
309 
310   tp_base_client_register (test->simple_handler, &test->error);
311   g_assert_no_error (test->error);
312 
313   /* Check Client properties */
314   tp_cli_dbus_properties_call_get_all (test->client, -1,
315       TP_IFACE_CLIENT, get_client_prop_cb, test, NULL, NULL);
316 
317   g_main_loop_run (test->mainloop);
318   g_assert_no_error (test->error);
319 
320   /* Check Handler properties */
321   tp_cli_dbus_properties_call_get_all (test->client, -1,
322       TP_IFACE_CLIENT_HANDLER, get_handler_prop_cb, test, NULL, NULL);
323 
324   g_main_loop_run (test->mainloop);
325   g_assert_no_error (test->error);
326 }
327 
328 static void
no_return_cb(TpClient * proxy,const GError * error,gpointer user_data,GObject * weak_object)329 no_return_cb (TpClient *proxy,
330     const GError *error,
331     gpointer user_data,
332     GObject *weak_object)
333 {
334   Test *test = user_data;
335 
336   g_clear_error (&test->error);
337 
338   if (error != NULL)
339     {
340       test->error = g_error_copy (error);
341       goto out;
342     }
343 
344 out:
345   g_main_loop_quit (test->mainloop);
346 }
347 
348 static void
add_channel_to_ptr_array(GPtrArray * arr,TpChannel * channel)349 add_channel_to_ptr_array (GPtrArray *arr,
350     TpChannel *channel)
351 {
352   GValueArray *tmp;
353 
354   g_assert (arr != NULL);
355   g_assert (channel != NULL);
356 
357   tmp = tp_value_array_build (2,
358       DBUS_TYPE_G_OBJECT_PATH, tp_proxy_get_object_path (channel),
359       TP_HASH_TYPE_STRING_VARIANT_MAP, tp_channel_borrow_immutable_properties (
360         channel),
361       G_TYPE_INVALID);
362 
363   g_ptr_array_add (arr, tmp);
364 }
365 
366 static void
free_channel_details(gpointer data,gpointer user_data)367 free_channel_details (gpointer data,
368     gpointer user_data)
369 {
370   g_boxed_free (TP_STRUCT_TYPE_CHANNEL_DETAILS, data);
371 }
372 
373 static void
call_handle_channels(Test * test)374 call_handle_channels (Test *test)
375 {
376   GPtrArray *channels, *requests_satisified;
377   GHashTable *info;
378   int i;
379 
380   channels = g_ptr_array_sized_new (1);
381   add_channel_to_ptr_array (channels, test->text_chan);
382 
383   requests_satisified = g_ptr_array_sized_new (0);
384   info = g_hash_table_new (NULL, NULL);
385 
386   tp_proxy_add_interface_by_id (TP_PROXY (test->client),
387       TP_IFACE_QUARK_CLIENT_HANDLER);
388 
389   for (i = 0 ; i < 10 ; i ++)
390     {
391       tp_cli_client_handler_call_handle_channels (test->client, -1,
392           tp_proxy_get_object_path (test->account),
393           tp_proxy_get_object_path (test->connection),
394           channels, requests_satisified, 0, info,
395           no_return_cb, test, NULL, NULL);
396 
397       g_main_loop_run (test->mainloop);
398     }
399 
400   g_ptr_array_foreach (channels, free_channel_details, NULL);
401   g_ptr_array_unref (channels);
402   g_ptr_array_unref (requests_satisified);
403   g_hash_table_unref (info);
404 }
405 
406 /* HandleChannels returns immediately */
407 static void
test_success(Test * test,gconstpointer data G_GNUC_UNUSED)408 test_success (Test *test,
409     gconstpointer data G_GNUC_UNUSED)
410 {
411   create_simple_handler (test, FALSE, FALSE, handle_channels_success);
412 
413   tp_base_client_add_handler_filter_vardict (test->simple_handler,
414       g_variant_new_parsed ("@a{sv} {}"));
415 
416   tp_base_client_register (test->simple_handler, &test->error);
417   g_assert_no_error (test->error);
418 
419   call_handle_channels (test);
420   g_assert_no_error (test->error);
421 }
422 
423 /* HandleChannels returns in an async way */
424 static gboolean
accept_idle_cb(gpointer data)425 accept_idle_cb (gpointer data)
426 {
427   TpHandleChannelsContext *context = data;
428 
429   tp_handle_channels_context_accept (context);
430   g_object_unref (context);
431   return FALSE;
432 }
433 
434 static void
handle_channels_async(TpSimpleHandler * handler,TpAccount * account,TpConnection * connection,GList * channels,GList * requests_satisified,gint64 user_action_time,TpHandleChannelsContext * context,gpointer user_data)435 handle_channels_async (
436     TpSimpleHandler *handler,
437     TpAccount *account,
438     TpConnection *connection,
439     GList *channels,
440     GList *requests_satisified,
441     gint64 user_action_time,
442     TpHandleChannelsContext *context,
443     gpointer user_data)
444 {
445   g_idle_add (accept_idle_cb, g_object_ref (context));
446 
447   tp_handle_channels_context_delay (context);
448 }
449 
450 static void
test_delayed(Test * test,gconstpointer data G_GNUC_UNUSED)451 test_delayed (Test *test,
452     gconstpointer data G_GNUC_UNUSED)
453 {
454   create_simple_handler (test, FALSE, FALSE, handle_channels_async);
455 
456   tp_base_client_add_handler_filter_vardict (test->simple_handler,
457       g_variant_new_parsed ("@a{sv} {}"));
458 
459   tp_base_client_register (test->simple_handler, &test->error);
460   g_assert_no_error (test->error);
461 
462   call_handle_channels (test);
463   g_assert_no_error (test->error);
464 }
465 
466 /* HandleChannels fails */
467 static void
handle_channels_fail(TpSimpleHandler * handler,TpAccount * account,TpConnection * connection,GList * channels,GList * requests_satisified,gint64 user_action_time,TpHandleChannelsContext * context,gpointer user_data)468 handle_channels_fail (
469     TpSimpleHandler *handler,
470     TpAccount *account,
471     TpConnection *connection,
472     GList *channels,
473     GList *requests_satisified,
474     gint64 user_action_time,
475     TpHandleChannelsContext *context,
476     gpointer user_data)
477 {
478   GError error = { TP_ERROR, TP_ERROR_NOT_AVAILABLE,
479       "No HandleChannels for you!" };
480 
481   tp_handle_channels_context_fail (context, &error);
482 }
483 
484 static void
test_fail(Test * test,gconstpointer data G_GNUC_UNUSED)485 test_fail (Test *test,
486     gconstpointer data G_GNUC_UNUSED)
487 {
488   create_simple_handler (test, FALSE, FALSE, handle_channels_fail);
489 
490   tp_base_client_add_handler_filter_vardict (test->simple_handler,
491       g_variant_new_parsed ("@a{sv} {}"));
492 
493   tp_base_client_register (test->simple_handler, &test->error);
494   g_assert_no_error (test->error);
495 
496   call_handle_channels (test);
497   g_assert_error (test->error, TP_ERROR, TP_ERROR_NOT_AVAILABLE);
498 }
499 
500 int
main(int argc,char ** argv)501 main (int argc,
502       char **argv)
503 {
504   tp_tests_init (&argc, &argv);
505   g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
506 
507   g_test_add ("/simple-handler/properties", Test, NULL, setup, test_properties,
508       teardown);
509   g_test_add ("/simple-handler/success", Test, NULL, setup, test_success,
510       teardown);
511   g_test_add ("/simple-handler/delayed", Test, NULL, setup, test_delayed,
512       teardown);
513   g_test_add ("/simple-handler/fail", Test, NULL, setup, test_fail,
514       teardown);
515 
516   return tp_tests_run_with_bus ();
517 }
518