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