1/* GLib testing framework examples and tests
2 *
3 * Copyright (C) 2012 Red Hat Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 *
18 * Author: Stef Walter <stefw@gnome.org>
19 */
20
21#include "config.h"
22
23#include <gio/gio.h>
24
25#include <sys/socket.h>
26
27#include <errno.h>
28#include <string.h>
29#include <unistd.h>
30
31typedef struct {
32 GDBusInterfaceSkeleton parent;
33 gint number;
34} MockInterface;
35
36typedef struct {
37 GDBusInterfaceSkeletonClass parent_class;
38} MockInterfaceClass;
39
40static GType mock_interface_get_type (void);
41G_DEFINE_TYPE (MockInterface, mock_interface, G_TYPE_DBUS_INTERFACE_SKELETON)
42
43static void
44mock_interface_init (MockInterface *self)
45{
46
47}
48
49static GDBusInterfaceInfo *
50mock_interface_get_info (GDBusInterfaceSkeleton *skeleton)
51{
52 static GDBusPropertyInfo path_info = {
53 -1,
54 "Path",
55 "o",
56 G_DBUS_PROPERTY_INFO_FLAGS_READABLE,
57 NULL,
58 };
59
60 static GDBusPropertyInfo number_info = {
61 -1,
62 "Number",
63 "i",
64 G_DBUS_PROPERTY_INFO_FLAGS_READABLE,
65 NULL,
66 };
67
68 static GDBusPropertyInfo *property_info[] = {
69 &path_info,
70 &number_info,
71 NULL
72 };
73
74 static GDBusInterfaceInfo interface_info = {
75 -1,
76 (gchar *) "org.mock.Interface",
77 NULL,
78 NULL,
79 (GDBusPropertyInfo **) &property_info,
80 NULL
81 };
82
83 return &interface_info;
84}
85
86static GVariant *
87mock_interface_get_property (GDBusConnection *connection,
88 const gchar *sender,
89 const gchar *object_path,
90 const gchar *interface_name,
91 const gchar *property_name,
92 GError **error,
93 gpointer user_data)
94{
95 MockInterface *self = user_data;
96 if (g_str_equal (v1: property_name, v2: "Path"))
97 return g_variant_new_object_path (object_path);
98 else if (g_str_equal (v1: property_name, v2: "Number"))
99 return g_variant_new_int32 (value: self->number);
100 else
101 return NULL;
102}
103
104static GDBusInterfaceVTable *
105mock_interface_get_vtable (GDBusInterfaceSkeleton *interface)
106{
107 static GDBusInterfaceVTable vtable = {
108 NULL,
109 mock_interface_get_property,
110 NULL,
111 };
112
113 return &vtable;
114}
115
116static GVariant *
117mock_interface_get_properties (GDBusInterfaceSkeleton *interface)
118{
119 GVariantBuilder builder;
120 GDBusInterfaceInfo *info;
121 GDBusInterfaceVTable *vtable;
122 guint n;
123
124 /* Groan, this is completely generic code and should be in gdbus */
125
126 info = g_dbus_interface_skeleton_get_info (interface_: interface);
127 vtable = g_dbus_interface_skeleton_get_vtable (interface_: interface);
128
129 g_variant_builder_init (builder: &builder, G_VARIANT_TYPE ("a{sv}"));
130 for (n = 0; info->properties[n] != NULL; n++)
131 {
132 if (info->properties[n]->flags & G_DBUS_PROPERTY_INFO_FLAGS_READABLE)
133 {
134 GVariant *value;
135 g_return_val_if_fail (vtable->get_property != NULL, NULL);
136 value = (vtable->get_property) (g_dbus_interface_skeleton_get_connection (interface_: interface), NULL,
137 g_dbus_interface_skeleton_get_object_path (interface_: interface),
138 info->name, info->properties[n]->name,
139 NULL, interface);
140 if (value != NULL)
141 {
142 g_variant_take_ref (value);
143 g_variant_builder_add (builder: &builder, format_string: "{sv}", info->properties[n]->name, value);
144 g_variant_unref (value);
145 }
146 }
147 }
148
149 return g_variant_builder_end (builder: &builder);
150}
151
152static void
153mock_interface_flush (GDBusInterfaceSkeleton *skeleton)
154{
155
156}
157
158static void
159mock_interface_class_init (MockInterfaceClass *klass)
160{
161 GDBusInterfaceSkeletonClass *skeleton_class = G_DBUS_INTERFACE_SKELETON_CLASS (klass);
162 skeleton_class->get_info = mock_interface_get_info;
163 skeleton_class->get_properties = mock_interface_get_properties;
164 skeleton_class->flush = mock_interface_flush;
165 skeleton_class->get_vtable = mock_interface_get_vtable;
166}
167typedef struct {
168 GDBusConnection *server;
169 GDBusConnection *client;
170 GMainLoop *loop;
171 GAsyncResult *result;
172} Test;
173
174static void
175on_server_connection (GObject *source,
176 GAsyncResult *result,
177 gpointer user_data)
178{
179 Test *test = user_data;
180 GError *error = NULL;
181
182 g_assert (test->server == NULL);
183 test->server = g_dbus_connection_new_finish (res: result, error: &error);
184 g_assert_no_error (error);
185 g_assert (test->server != NULL);
186
187 if (test->server && test->client)
188 g_main_loop_quit (loop: test->loop);
189}
190
191static void
192on_client_connection (GObject *source,
193 GAsyncResult *result,
194 gpointer user_data)
195{
196 Test *test = user_data;
197 GError *error = NULL;
198
199 g_assert (test->client == NULL);
200 test->client = g_dbus_connection_new_finish (res: result, error: &error);
201 g_assert_no_error (error);
202 g_assert (test->client != NULL);
203
204 if (test->server && test->client)
205 g_main_loop_quit (loop: test->loop);
206}
207
208static void
209setup (Test *test,
210 gconstpointer unused)
211{
212 GError *error = NULL;
213 GSocket *socket;
214 GSocketConnection *stream;
215 gchar *guid;
216 int pair[2];
217
218 test->loop = g_main_loop_new (NULL, FALSE);
219
220 if (socketpair (AF_UNIX, SOCK_STREAM, protocol: 0, fds: pair) < 0)
221 {
222 int errsv = errno;
223 g_set_error (err: &error, G_IO_ERROR, code: g_io_error_from_errno (err_no: errsv),
224 format: "%s", g_strerror (errnum: errsv));
225 g_assert_no_error (error);
226 }
227
228 /* Build up the server stuff */
229 socket = g_socket_new_from_fd (fd: pair[1], error: &error);
230 g_assert_no_error (error);
231
232 stream = g_socket_connection_factory_create_connection (socket);
233 g_assert (stream != NULL);
234 g_object_unref (object: socket);
235
236 guid = g_dbus_generate_guid ();
237 g_dbus_connection_new (G_IO_STREAM (stream), guid,
238 flags: G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER |
239 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS,
240 NULL, NULL, callback: on_server_connection, user_data: test);
241 g_object_unref (object: stream);
242 g_free (mem: guid);
243
244 /* Build up the client stuff */
245 socket = g_socket_new_from_fd (fd: pair[0], error: &error);
246 g_assert_no_error (error);
247
248 stream = g_socket_connection_factory_create_connection (socket);
249 g_assert (stream != NULL);
250 g_object_unref (object: socket);
251
252 g_dbus_connection_new (G_IO_STREAM (stream), NULL,
253 flags: G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
254 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS,
255 NULL, NULL, callback: on_client_connection, user_data: test);
256
257 g_main_loop_run (loop: test->loop);
258
259 g_assert (test->server);
260 g_assert (test->client);
261
262 g_object_unref (object: stream);
263}
264
265static void
266teardown (Test *test,
267 gconstpointer unused)
268{
269 g_clear_object (&test->client);
270 g_clear_object (&test->server);
271 g_main_loop_unref (loop: test->loop);
272}
273
274static void
275on_result (GObject *source,
276 GAsyncResult *result,
277 gpointer user_data)
278{
279 Test *test = user_data;
280 g_assert (test->result == NULL);
281 test->result = g_object_ref (result);
282 g_main_loop_quit (loop: test->loop);
283
284}
285
286static void
287test_object_manager (Test *test,
288 gconstpointer test_data)
289{
290 GDBusObjectManager *client;
291 GDBusObjectManagerServer *server;
292 MockInterface *mock;
293 GDBusObjectSkeleton *skeleton;
294 const gchar *dbus_name;
295 GError *error = NULL;
296 GDBusInterface *proxy;
297 GVariant *prop;
298 const gchar *object_path = test_data;
299 gchar *number1_path = NULL, *number2_path = NULL;
300
301 if (g_strcmp0 (str1: object_path, str2: "/") == 0)
302 {
303 number1_path = g_strdup (str: "/number_1");
304 number2_path = g_strdup (str: "/number_2");
305 }
306 else
307 {
308 number1_path = g_strdup_printf (format: "%s/number_1", object_path);
309 number2_path = g_strdup_printf (format: "%s/number_2", object_path);
310 }
311
312 server = g_dbus_object_manager_server_new (object_path);
313
314 mock = g_object_new (object_type: mock_interface_get_type (), NULL);
315 mock->number = 1;
316 skeleton = g_dbus_object_skeleton_new (object_path: number1_path);
317 g_dbus_object_skeleton_add_interface (object: skeleton, G_DBUS_INTERFACE_SKELETON (mock));
318 g_dbus_object_manager_server_export (manager: server, object: skeleton);
319
320 mock = g_object_new (object_type: mock_interface_get_type (), NULL);
321 mock->number = 2;
322 skeleton = g_dbus_object_skeleton_new (object_path: number2_path);
323 g_dbus_object_skeleton_add_interface (object: skeleton, G_DBUS_INTERFACE_SKELETON (mock));
324 g_dbus_object_manager_server_export (manager: server, object: skeleton);
325
326 g_dbus_object_manager_server_set_connection (manager: server, connection: test->server);
327
328 dbus_name = NULL;
329
330 g_dbus_object_manager_client_new (connection: test->client, flags: G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START,
331 name: dbus_name, object_path, NULL, NULL, NULL, NULL, callback: on_result, user_data: test);
332
333 g_main_loop_run (loop: test->loop);
334 client = g_dbus_object_manager_client_new_finish (res: test->result, error: &error);
335 g_assert_no_error (error);
336 g_clear_object (&test->result);
337
338 proxy = g_dbus_object_manager_get_interface (manager: client, object_path: number1_path, interface_name: "org.mock.Interface");
339 g_assert (proxy != NULL);
340 prop = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), property_name: "Path");
341 g_assert (prop != NULL);
342 g_assert_cmpstr ((gchar *)g_variant_get_type (prop), ==, (gchar *)G_VARIANT_TYPE_OBJECT_PATH);
343 g_assert_cmpstr (g_variant_get_string (prop, NULL), ==, number1_path);
344 g_variant_unref (value: prop);
345 prop = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), property_name: "Number");
346 g_assert (prop != NULL);
347 g_assert_cmpstr ((gchar *)g_variant_get_type (prop), ==, (gchar *)G_VARIANT_TYPE_INT32);
348 g_assert_cmpint (g_variant_get_int32 (prop), ==, 1);
349 g_variant_unref (value: prop);
350 g_object_unref (object: proxy);
351
352 proxy = g_dbus_object_manager_get_interface (manager: client, object_path: number2_path, interface_name: "org.mock.Interface");
353 g_assert (proxy != NULL);
354 prop = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), property_name: "Path");
355 g_assert (prop != NULL);
356 g_assert_cmpstr ((gchar *)g_variant_get_type (prop), ==, (gchar *)G_VARIANT_TYPE_OBJECT_PATH);
357 g_assert_cmpstr (g_variant_get_string (prop, NULL), ==, number2_path);
358 g_variant_unref (value: prop);
359 prop = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), property_name: "Number");
360 g_assert (prop != NULL);
361 g_assert_cmpstr ((gchar *)g_variant_get_type (prop), ==, (gchar *)G_VARIANT_TYPE_INT32);
362 g_assert_cmpint (g_variant_get_int32 (prop), ==, 2);
363 g_variant_unref (value: prop);
364 g_object_unref (object: proxy);
365
366 g_object_unref (object: server);
367 g_object_unref (object: client);
368
369 g_free (mem: number2_path);
370 g_free (mem: number1_path);
371}
372
373int
374main (int argc,
375 char *argv[])
376{
377 g_test_init (argc: &argc, argv: &argv, NULL);
378
379 g_test_add ("/gdbus/peer-object-manager/normal", Test, "/objects",
380 setup, test_object_manager, teardown);
381 g_test_add ("/gdbus/peer-object-manager/root", Test, "/",
382 setup, test_object_manager, teardown);
383
384 return g_test_run();
385}
386

source code of gtk/subprojects/glib/gio/tests/gdbus-peer-object-manager.c