chiark / gitweb /
f3571cb3c42635f1dff21c58a45d67a22b3f8513
[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_emit_properties_changed()
40  *
41  *   Add in:
42  *
43  *   automatic properties
44  *   node hierarchy updates during dispatching
45  *   emit_interfaces_added/emit_interfaces_removed
46  *
47  */
48
49 struct context {
50         int fds[2];
51         bool quit;
52         char *something;
53 };
54
55 static int something_handler(sd_bus *bus, sd_bus_message *m, void *userdata) {
56         struct context *c = userdata;
57         const char *s;
58         char *n = NULL;
59         int r;
60
61         r = sd_bus_message_read(m, "s", &s);
62         assert_se(r > 0);
63
64         n = strjoin("<<<", s, ">>>", NULL);
65         assert_se(n);
66
67         free(c->something);
68         c->something = n;
69
70         log_info("AlterSomething() called, got %s, returning %s", s, n);
71
72         r = sd_bus_reply_method_return(bus, m, "s", n);
73         assert_se(r >= 0);
74
75         return 1;
76 }
77
78 static int exit_handler(sd_bus *bus, sd_bus_message *m, void *userdata) {
79         struct context *c = userdata;
80         int r;
81
82         c->quit = true;
83
84         log_info("Exit called");
85
86         r = sd_bus_reply_method_return(bus, m, "");
87         assert_se(r >= 0);
88
89         return 1;
90 }
91
92 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) {
93         struct context *c = userdata;
94         int r;
95
96         log_info("property get for %s called", property);
97
98         r = sd_bus_message_append(reply, "s", c->something);
99         assert_se(r >= 0);
100
101         return 1;
102 }
103
104 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) {
105         struct context *c = userdata;
106         const char *s;
107         char *n;
108         int r;
109
110         log_info("property set for %s called", property);
111
112         r = sd_bus_message_read(value, "s", &s);
113         assert_se(r >= 0);
114
115         n = strdup(s);
116         assert_se(n);
117
118         free(c->something);
119         c->something = n;
120
121         return 1;
122 }
123
124 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) {
125         _cleanup_free_ char *s = NULL;
126         const char *x;
127         int r;
128
129         assert_se(asprintf(&s, "object %p, path %s", userdata, path) >= 0);
130         r = sd_bus_message_append(reply, "s", s);
131         assert_se(r >= 0);
132
133         assert_se(x = startswith(path, "/value/"));
134
135         assert_se(PTR_TO_UINT(userdata) == 30);
136
137
138         return 1;
139 }
140
141 static const sd_bus_vtable vtable[] = {
142         SD_BUS_VTABLE_START(0),
143         SD_BUS_METHOD("AlterSomething", "s", "s", 0, something_handler),
144         SD_BUS_METHOD("Exit", "", "", 0, exit_handler),
145         SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
146         SD_BUS_VTABLE_END
147 };
148
149 static const sd_bus_vtable vtable2[] = {
150         SD_BUS_VTABLE_START(0),
151         SD_BUS_PROPERTY("Value", "s", value_handler, 10, 0),
152         SD_BUS_VTABLE_END
153 };
154
155 static int enumerator_callback(sd_bus *b, const char *path, char ***nodes, void *userdata) {
156
157         if (object_path_startswith("/value", path))
158                 assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL));
159
160         return 1;
161 }
162
163 static void *server(void *p) {
164         struct context *c = p;
165         sd_bus *bus = NULL;
166         sd_id128_t id;
167         int r;
168
169         c->quit = false;
170
171         assert_se(sd_id128_randomize(&id) >= 0);
172
173         assert_se(sd_bus_new(&bus) >= 0);
174         assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
175         assert_se(sd_bus_set_server(bus, 1, id) >= 0);
176
177         assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
178         assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
179         assert_se(sd_bus_add_fallback_vtable(bus, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
180         assert_se(sd_bus_add_node_enumerator(bus, "/value", enumerator_callback, NULL) >= 0);
181         assert_se(sd_bus_add_object_manager(bus, "/value") >= 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.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
338         assert_se(r < 0);
339         assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.UnknownMethod"));
340         sd_bus_error_free(&error);
341
342         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
343         assert_se(r >= 0);
344
345         bus_message_dump(reply);
346
347         sd_bus_message_unref(reply);
348         reply = NULL;
349
350         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
351         assert_se(r >= 0);
352
353         sd_bus_flush(bus);
354
355         return 0;
356 }
357
358 int main(int argc, char *argv[]) {
359         struct context c;
360         pthread_t s;
361         void *p;
362         int r, q;
363
364         zero(c);
365
366         assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
367
368         r = pthread_create(&s, NULL, server, &c);
369         if (r != 0)
370                 return -r;
371
372         r = client(&c);
373
374         q = pthread_join(s, &p);
375         if (q != 0)
376                 return -q;
377
378         if (r < 0)
379                 return r;
380
381         if (PTR_TO_INT(p) < 0)
382                 return PTR_TO_INT(p);
383
384         free(c.something);
385
386         return EXIT_SUCCESS;
387 }