1 /* Feature test for Conn.I.Balance
2  *
3  * Copyright © 2007-2011 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 #define BALANCE 1234
26 #define BALANCE_SCALE 2
27 #define BALANCE_CURRENCY "BDD" /* badger dollars */
28 #define MANAGE_CREDIT_URI "http://chat.badger.net/topup"
29 
30 /* -- BalancedConnection -- */
31 typedef TpTestsSimpleConnection BalancedConnection;
32 typedef TpTestsSimpleConnectionClass BalancedConnectionClass;
33 
34 #define TYPE_BALANCED_CONNECTION (balanced_connection_get_type ())
35 static GType balanced_connection_get_type (void);
36 
37 G_DEFINE_TYPE_WITH_CODE (BalancedConnection,
38     balanced_connection,
39     TP_TESTS_TYPE_SIMPLE_CONNECTION,
40 
41     G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_BALANCE, NULL))
42 
43 enum
44 {
45   PROP_0,
46   PROP_ACCOUNT_BALANCE,
47   PROP_MANAGE_CREDIT_URI
48 };
49 
50 static void
balanced_connection_get_property(GObject * self G_GNUC_UNUSED,guint prop_id,GValue * value,GParamSpec * pspec)51 balanced_connection_get_property (GObject *self G_GNUC_UNUSED,
52     guint prop_id,
53     GValue *value,
54     GParamSpec *pspec)
55 {
56   switch (prop_id)
57     {
58       case PROP_ACCOUNT_BALANCE:
59         /* known balance */
60         g_value_take_boxed (value, tp_value_array_build (3,
61               G_TYPE_INT, BALANCE,
62               G_TYPE_UINT, BALANCE_SCALE,
63               G_TYPE_STRING, BALANCE_CURRENCY,
64               G_TYPE_INVALID));
65         break;
66 
67       case PROP_MANAGE_CREDIT_URI:
68         g_value_set_static_string (value, MANAGE_CREDIT_URI);
69         break;
70 
71       default:
72         G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
73         break;
74     }
75 }
76 
77 static void
balanced_connection_init(BalancedConnection * self G_GNUC_UNUSED)78 balanced_connection_init (BalancedConnection *self G_GNUC_UNUSED)
79 {
80 }
81 
82 static GPtrArray *
get_interfaces(TpBaseConnection * base)83 get_interfaces (TpBaseConnection *base)
84 {
85   GPtrArray *interfaces;
86 
87   interfaces = TP_BASE_CONNECTION_CLASS (
88       balanced_connection_parent_class)->get_interfaces_always_present (base);
89 
90   g_ptr_array_add (interfaces, TP_IFACE_CONNECTION_INTERFACE_BALANCE);
91 
92   return interfaces;
93 }
94 
95 static void
balanced_connection_class_init(BalancedConnectionClass * cls)96 balanced_connection_class_init (BalancedConnectionClass *cls)
97 {
98   GObjectClass *object_class = (GObjectClass *) cls;
99   TpBaseConnectionClass *base_class = TP_BASE_CONNECTION_CLASS (cls);
100 
101   static TpDBusPropertiesMixinPropImpl balance_props[] = {
102         { "AccountBalance", "account-balance", NULL },
103         { "ManageCreditURI", "manage-credit-uri", NULL },
104         { NULL }
105   };
106 
107   object_class->get_property = balanced_connection_get_property;
108 
109   base_class->get_interfaces_always_present = get_interfaces;
110 
111   g_object_class_install_property (object_class, PROP_ACCOUNT_BALANCE,
112       g_param_spec_boxed ("account-balance", "", "",
113         TP_STRUCT_TYPE_CURRENCY_AMOUNT,
114         G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
115 
116   g_object_class_install_property (object_class, PROP_MANAGE_CREDIT_URI,
117       g_param_spec_string ("manage-credit-uri", "", "",
118         NULL,
119         G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
120 
121   tp_dbus_properties_mixin_implement_interface (object_class,
122       TP_IFACE_QUARK_CONNECTION_INTERFACE_BALANCE,
123       tp_dbus_properties_mixin_getter_gobject_properties, NULL,
124       balance_props);
125 }
126 
127 /* -- UnbalancedConnection -- */
128 typedef TpTestsSimpleConnection UnbalancedConnection;
129 typedef TpTestsSimpleConnectionClass UnbalancedConnectionClass;
130 
131 #define TYPE_UNBALANCED_CONNECTION (unbalanced_connection_get_type ())
132 static GType unbalanced_connection_get_type (void);
133 
G_DEFINE_TYPE(UnbalancedConnection,unbalanced_connection,TYPE_BALANCED_CONNECTION)134 G_DEFINE_TYPE (UnbalancedConnection,
135     unbalanced_connection,
136     TYPE_BALANCED_CONNECTION)
137 
138 static void
139 unbalanced_connection_get_property (GObject *self G_GNUC_UNUSED,
140     guint prop_id,
141     GValue *value,
142     GParamSpec *pspec)
143 {
144   switch (prop_id)
145     {
146       case PROP_ACCOUNT_BALANCE:
147         /* unknown balance */
148         g_value_take_boxed (value, tp_value_array_build (3,
149               G_TYPE_INT, 0,
150               G_TYPE_UINT, G_MAXUINT32,
151               G_TYPE_STRING, "",
152               G_TYPE_INVALID));
153         break;
154 
155       default:
156         G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
157         break;
158     }
159 }
160 
161 static void
unbalanced_connection_init(UnbalancedConnection * self G_GNUC_UNUSED)162 unbalanced_connection_init (UnbalancedConnection *self G_GNUC_UNUSED)
163 {
164 }
165 
166 static void
unbalanced_connection_class_init(UnbalancedConnectionClass * cls)167 unbalanced_connection_class_init (UnbalancedConnectionClass *cls)
168 {
169   GObjectClass *object_class = (GObjectClass *) cls;
170 
171   object_class->get_property = unbalanced_connection_get_property;
172 
173   g_object_class_override_property (object_class, PROP_ACCOUNT_BALANCE,
174       "account-balance");
175 }
176 
177 /* -- Tests -- */
178 typedef struct {
179     GMainLoop *mainloop;
180     TpDBusDaemon *dbus;
181     DBusConnection *client_libdbus;
182     DBusGConnection *client_dbusglib;
183     TpDBusDaemon *client_bus;
184     TpTestsSimpleConnection *service_conn;
185     TpBaseConnection *service_conn_as_base;
186     gchar *conn_name;
187     gchar *conn_path;
188     TpConnection *conn;
189 
190     gboolean cwr_ready;
191     GError *cwr_error /* initialized in setup */;
192 
193     GError *error /* initialized where needed */;
194     gint wait;
195 } Test;
196 
197 static void
setup(Test * test,gconstpointer data)198 setup (Test *test,
199     gconstpointer data)
200 {
201   GError *error = NULL;
202   GQuark features[] = { TP_CONNECTION_FEATURE_CONNECTED, 0 };
203   GType conn_type = GPOINTER_TO_SIZE (data);
204 
205   tp_debug_set_flags ("all");
206   test->dbus = tp_tests_dbus_daemon_dup_or_die ();
207 
208   test->mainloop = g_main_loop_new (NULL, FALSE);
209   test->error = NULL;
210 
211   test->client_libdbus = dbus_bus_get_private (DBUS_BUS_STARTER, NULL);
212   g_assert (test->client_libdbus != NULL);
213   dbus_connection_setup_with_g_main (test->client_libdbus, NULL);
214   dbus_connection_set_exit_on_disconnect (test->client_libdbus, FALSE);
215   test->client_dbusglib = dbus_connection_get_g_connection (
216       test->client_libdbus);
217   dbus_g_connection_ref (test->client_dbusglib);
218   test->client_bus = tp_dbus_daemon_new (test->client_dbusglib);
219   g_assert (test->client_bus != NULL);
220 
221   test->service_conn = tp_tests_object_new_static_class (
222         conn_type,
223         "account", "me@example.com",
224         "protocol", "simple-protocol",
225         NULL);
226   test->service_conn_as_base = TP_BASE_CONNECTION (test->service_conn);
227   g_assert (test->service_conn != NULL);
228   g_assert (test->service_conn_as_base != NULL);
229 
230   g_assert (tp_base_connection_register (test->service_conn_as_base, "simple",
231         &test->conn_name, &test->conn_path, &error));
232   g_assert_no_error (error);
233 
234   test->cwr_ready = FALSE;
235   test->cwr_error = NULL;
236 
237   test->conn = tp_connection_new (test->client_bus, test->conn_name,
238       test->conn_path, &error);
239   g_assert (test->conn != NULL);
240   g_assert_no_error (error);
241 
242   tp_cli_connection_call_connect (test->conn, -1, NULL, NULL, NULL, NULL);
243 
244   g_assert (!tp_proxy_is_prepared (test->conn, TP_CONNECTION_FEATURE_CORE));
245   g_assert (!tp_proxy_is_prepared (test->conn,
246         TP_CONNECTION_FEATURE_CONNECTED));
247   g_assert (!tp_proxy_is_prepared (test->conn, TP_CONNECTION_FEATURE_BALANCE));
248 
249   tp_tests_proxy_run_until_prepared (test->conn, features);
250 }
251 
252 static void
teardown(Test * test,gconstpointer data G_GNUC_UNUSED)253 teardown (Test *test,
254     gconstpointer data G_GNUC_UNUSED)
255 {
256   TpConnection *conn;
257   GError *error = NULL;
258 
259   g_clear_error (&test->error);
260   tp_clear_pointer (&test->mainloop, g_main_loop_unref);
261   tp_clear_object (&test->conn);
262 
263   /* disconnect the connection so we don't leak it */
264   conn = tp_connection_new (test->dbus, test->conn_name, test->conn_path,
265       &error);
266   g_assert (conn != NULL);
267   g_assert_no_error (error);
268 
269   tp_tests_connection_assert_disconnect_succeeds (conn);
270 
271   g_assert (!tp_connection_run_until_ready (conn, FALSE, &error, NULL));
272   g_assert_error (error, TP_ERROR, TP_ERROR_CANCELLED);
273   g_clear_error (&error);
274 
275   test->service_conn_as_base = NULL;
276   g_object_unref (test->service_conn);
277   g_free (test->conn_name);
278   g_free (test->conn_path);
279 
280   g_object_unref (test->dbus);
281   test->dbus = NULL;
282   g_object_unref (test->client_bus);
283   test->client_bus = NULL;
284 
285   dbus_g_connection_unref (test->client_dbusglib);
286   dbus_connection_close (test->client_libdbus);
287   dbus_connection_unref (test->client_libdbus);
288 }
289 
290 static void
balance_changed_cb(TpConnection * conn,gint balance,guint scale,const gchar * currency,Test * test)291 balance_changed_cb (TpConnection *conn,
292     gint balance,
293     guint scale,
294     const gchar *currency,
295     Test *test)
296 {
297   g_assert_cmpint (balance, ==, BALANCE * 2);
298   g_assert_cmpuint (scale, ==, BALANCE_SCALE);
299   g_assert_cmpstr (currency, ==, BALANCE_CURRENCY);
300 
301   test->wait--;
302   if (test->wait <= 0)
303     g_main_loop_quit (test->mainloop);
304 }
305 
306 static void
test_balance(Test * test,gconstpointer nil G_GNUC_UNUSED)307 test_balance (Test *test,
308     gconstpointer nil G_GNUC_UNUSED)
309 {
310   GQuark features[] = { TP_CONNECTION_FEATURE_BALANCE, 0 };
311   gint balance;
312   guint scale;
313   const gchar *currency, *uri;
314   gchar *currency_alloc, *uri_alloc;
315   GValueArray *v;
316 
317   g_assert (!tp_proxy_is_prepared (test->conn, TP_CONNECTION_FEATURE_BALANCE));
318 
319   tp_tests_proxy_run_until_prepared (test->conn, features);
320 
321   g_assert (tp_connection_get_balance (test->conn,
322         &balance, &scale, &currency));
323 
324   g_assert_cmpint (balance, ==, BALANCE);
325   g_assert_cmpuint (scale, ==, BALANCE_SCALE);
326   g_assert_cmpstr (currency, ==, BALANCE_CURRENCY);
327 
328   uri = tp_connection_get_balance_uri (test->conn);
329 
330   g_assert_cmpstr (uri, ==, MANAGE_CREDIT_URI);
331 
332   g_object_get (test->conn,
333       "balance", &balance,
334       "balance-scale", &scale,
335       "balance-currency", &currency_alloc,
336       "balance-uri", &uri_alloc,
337       NULL);
338 
339   g_assert_cmpint (balance, ==, BALANCE);
340   g_assert_cmpuint (scale, ==, BALANCE_SCALE);
341   g_assert_cmpstr (currency_alloc, ==, BALANCE_CURRENCY);
342   g_assert_cmpstr (uri_alloc, ==, MANAGE_CREDIT_URI);
343 
344   v = tp_value_array_build (3,
345               G_TYPE_INT, BALANCE * 2,
346               G_TYPE_UINT, BALANCE_SCALE,
347               G_TYPE_STRING, BALANCE_CURRENCY,
348               G_TYPE_INVALID);
349 
350   tp_svc_connection_interface_balance_emit_balance_changed (
351       test->service_conn_as_base, v);
352 
353   g_signal_connect (test->conn, "balance-changed",
354       G_CALLBACK (balance_changed_cb), test);
355 
356   test->wait = 1;
357   g_main_loop_run (test->mainloop);
358   g_assert_no_error (test->error);
359 
360   g_free (currency_alloc);
361   g_free (uri_alloc);
362 }
363 
364 static void
test_balance_unknown(Test * test,gconstpointer nil G_GNUC_UNUSED)365 test_balance_unknown (Test *test,
366     gconstpointer nil G_GNUC_UNUSED)
367 {
368   GQuark features[] = { TP_CONNECTION_FEATURE_BALANCE, 0 };
369   gint balance;
370   guint scale;
371   const gchar *currency;
372 
373   g_assert (!tp_proxy_is_prepared (test->conn, TP_CONNECTION_FEATURE_BALANCE));
374 
375   tp_tests_proxy_run_until_prepared (test->conn, features);
376 
377   g_assert (!tp_connection_get_balance (test->conn,
378         &balance, &scale, &currency));
379 }
380 
381 int
main(int argc,char ** argv)382 main (int argc,
383       char **argv)
384 {
385   tp_tests_abort_after (5);
386   g_test_init (&argc, &argv, NULL);
387 
388   g_test_add ("/conn/balance", Test,
389       GSIZE_TO_POINTER (TYPE_BALANCED_CONNECTION),
390       setup, test_balance, teardown);
391   g_test_add ("/conn/balance-unknown", Test,
392       GSIZE_TO_POINTER (TYPE_UNBALANCED_CONNECTION),
393       setup, test_balance_unknown, teardown);
394   g_test_add ("/conn/balance-unimplemented", Test,
395       GSIZE_TO_POINTER (TP_TESTS_TYPE_SIMPLE_CONNECTION),
396       setup, test_balance_unknown, teardown);
397 
398   return tp_tests_run_with_bus ();
399 }
400