chiark / gitweb /
a95789fe9cbd04751f041e5be7863743590e8f32
[elogind.git] / src / libsystemd-bus / test-bus-objects.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <assert.h>
23 #include <stdlib.h>
24 #include <pthread.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27
28 #include "log.h"
29 #include "util.h"
30 #include "macro.h"
31 #include "strv.h"
32
33 #include "sd-bus.h"
34 #include "bus-internal.h"
35 #include "bus-message.h"
36
37 /* Test:
38  *
39  *   sd_bus_add_object_manager()
40  *   sd_bus_emit_properties_changed()
41  *
42  *   Add in:
43  *
44  *   automatic properties
45  *   node hierarchy updates during dispatching
46  *   emit_interfaces_added/emit_interfaces_removed
47  *
48  */
49
50 struct context {
51         int fds[2];
52         bool quit;
53         char *something;
54 };
55
56 static int something_handler(sd_bus *bus, sd_bus_message *m, void *userdata) {
57         struct context *c = userdata;
58         const char *s;
59         char *n = NULL;
60         int r;
61
62         r = sd_bus_message_read(m, "s", &s);
63         assert_se(r > 0);
64
65         n = strjoin("<<<", s, ">>>", NULL);
66         assert_se(n);
67
68         free(c->something);
69         c->something = n;
70
71         log_info("AlterSomething() called, got %s, returning %s", s, n);
72
73         r = sd_bus_reply_method_return(bus, m, "s", n);
74         assert_se(r >= 0);
75
76         return 1;
77 }
78
79 static int exit_handler(sd_bus *bus, sd_bus_message *m, void *userdata) {
80         struct context *c = userdata;
81         int r;
82
83         c->quit = true;
84
85         log_info("Exit called");
86
87         r = sd_bus_reply_method_return(bus, m, "");
88         assert_se(r >= 0);
89
90         return 1;
91 }
92
93 static int get_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata) {
94         struct context *c = userdata;
95         int r;
96
97         log_info("property get for %s called", property);
98
99         r = sd_bus_message_append(reply, "s", c->something);
100         assert_se(r >= 0);
101
102         return 1;
103 }
104
105 static int set_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, sd_bus_error *error, void *userdata) {
106         struct context *c = userdata;
107         const char *s;
108         char *n;
109         int r;
110
111         log_info("property set for %s called", property);
112
113         r = sd_bus_message_read(value, "s", &s);
114         assert_se(r >= 0);
115
116         n = strdup(s);
117         assert_se(n);
118
119         free(c->something);
120         c->something = n;
121
122         return 1;
123 }
124
125 static int value_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata) {
126         _cleanup_free_ char *s = NULL;
127         const char *x;
128         int r;
129
130         assert_se(asprintf(&s, "object %p, path %s", userdata, path) >= 0);
131         r = sd_bus_message_append(reply, "s", s);
132         assert_se(r >= 0);
133
134         assert_se(x = startswith(path, "/value/"));
135
136         assert_se(PTR_TO_UINT(userdata) == 30);
137
138
139         return 1;
140 }
141
142 static const sd_bus_vtable vtable[] = {
143         SD_BUS_VTABLE_START(0),
144         SD_BUS_METHOD("AlterSomething", "s", "s", 0, something_handler),
145         SD_BUS_METHOD("Exit", "", "", 0, exit_handler),
146         SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
147         SD_BUS_VTABLE_END
148 };
149
150 static const sd_bus_vtable vtable2[] = {
151         SD_BUS_VTABLE_START(0),
152         SD_BUS_PROPERTY("Value", "s", value_handler, 10, 0),
153         SD_BUS_VTABLE_END
154 };
155
156 static int enumerator_callback(sd_bus *b, const char *path, char ***nodes, void *userdata) {
157
158         if (object_path_startswith("/value", path))
159                 assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL));
160
161         return 1;
162 }
163
164 static void *server(void *p) {
165         struct context *c = p;
166         sd_bus *bus = NULL;
167         sd_id128_t id;
168         int r;
169
170         c->quit = false;
171
172         assert_se(sd_id128_randomize(&id) >= 0);
173
174         assert_se(sd_bus_new(&bus) >= 0);
175         assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
176         assert_se(sd_bus_set_server(bus, 1, id) >= 0);
177
178         assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
179         assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
180         assert_se(sd_bus_add_fallback_vtable(bus, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
181         assert_se(sd_bus_add_node_enumerator(bus, "/value", enumerator_callback, NULL) >= 0);
182
183         assert_se(sd_bus_start(bus) >= 0);
184
185         log_error("Entering event loop on server");
186
187         while (!c->quit) {
188                 log_error("Loop!");
189
190                 r = sd_bus_process(bus, NULL);
191                 if (r < 0) {
192                         log_error("Failed to process requests: %s", strerror(-r));
193                         goto fail;
194                 }
195
196                 if (r == 0) {
197                         r = sd_bus_wait(bus, (uint64_t) -1);
198                         if (r < 0) {
199                                 log_error("Failed to wait: %s", strerror(-r));
200                                 goto fail;
201                         }
202
203                         continue;
204                 }
205         }
206
207         r = 0;
208
209 fail:
210         if (bus) {
211                 sd_bus_flush(bus);
212                 sd_bus_unref(bus);
213         }
214
215         return INT_TO_PTR(r);
216 }
217
218 static int client(struct context *c) {
219         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
220         _cleanup_bus_unref_ sd_bus *bus = NULL;
221         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
222         const char *s;
223         int r;
224
225         assert_se(sd_bus_new(&bus) >= 0);
226         assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
227         assert_se(sd_bus_start(bus) >= 0);
228
229         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo");
230         assert_se(r >= 0);
231
232         r = sd_bus_message_read(reply, "s", &s);
233         assert_se(r >= 0);
234         assert_se(streq(s, "<<<hallo>>>"));
235
236         sd_bus_message_unref(reply);
237         reply = NULL;
238
239         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, "");
240         assert_se(r < 0);
241         assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.UnknownMethod"));
242
243         sd_bus_error_free(&error);
244
245         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo");
246         assert_se(r < 0);
247         assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.InvalidArgs"));
248
249         sd_bus_error_free(&error);
250
251         r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
252         assert_se(r >= 0);
253
254         r = sd_bus_message_read(reply, "s", &s);
255         assert_se(r >= 0);
256         assert_se(streq(s, "<<<hallo>>>"));
257
258         sd_bus_message_unref(reply);
259         reply = NULL;
260
261         r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
262         assert_se(r >= 0);
263
264         r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
265         assert_se(r >= 0);
266
267         r = sd_bus_message_read(reply, "s", &s);
268         assert_se(r >= 0);
269         assert_se(streq(s, "test"));
270
271         sd_bus_message_unref(reply);
272         reply = NULL;
273
274         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
275         assert_se(r <= 0);
276
277         r = sd_bus_message_read(reply, "s", &s);
278         assert_se(r >= 0);
279         fputs(s, stdout);
280
281         sd_bus_message_unref(reply);
282         reply = NULL;
283
284         r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
285         assert_se(r >= 0);
286
287         r = sd_bus_message_read(reply, "s", &s);
288         assert_se(r >= 0);
289         log_info("read %s", s);
290
291         sd_bus_message_unref(reply);
292         reply = NULL;
293
294         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
295         assert_se(r <= 0);
296
297         r = sd_bus_message_read(reply, "s", &s);
298         assert_se(r >= 0);
299         fputs(s, stdout);
300
301         sd_bus_message_unref(reply);
302         reply = NULL;
303
304         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
305         assert_se(r <= 0);
306
307         r = sd_bus_message_read(reply, "s", &s);
308         assert_se(r >= 0);
309         fputs(s, stdout);
310
311         sd_bus_message_unref(reply);
312         reply = NULL;
313
314         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
315         assert_se(r <= 0);
316
317         r = sd_bus_message_read(reply, "s", &s);
318         assert_se(r >= 0);
319         fputs(s, stdout);
320
321         sd_bus_message_unref(reply);
322         reply = NULL;
323
324         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
325         assert_se(r <= 0);
326
327         bus_message_dump(reply);
328
329         sd_bus_message_unref(reply);
330         reply = NULL;
331
332         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2");
333         assert_se(r < 0);
334         assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.UnknownInterface"));
335         sd_bus_error_free(&error);
336
337         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
338         assert_se(r >= 0);
339
340         sd_bus_flush(bus);
341
342         return 0;
343 }
344
345 int main(int argc, char *argv[]) {
346         struct context c;
347         pthread_t s;
348         void *p;
349         int r, q;
350
351         zero(c);
352
353         assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
354
355         r = pthread_create(&s, NULL, server, &c);
356         if (r != 0)
357                 return -r;
358
359         r = client(&c);
360
361         q = pthread_join(s, &p);
362         if (q != 0)
363                 return -q;
364
365         if (r < 0)
366                 return r;
367
368         if (PTR_TO_INT(p) < 0)
369                 return PTR_TO_INT(p);
370
371         free(c.something);
372
373         return EXIT_SUCCESS;
374 }