Line data Source code
1 : /*
2 : SSSD
3 :
4 : sbus_codegen tests.
5 :
6 : Authors:
7 : Stef Walter <stefw@redhat.com>
8 :
9 : Copyright (C) Red Hat, Inc 2014
10 :
11 : This program is free software; you can redistribute it and/or modify
12 : it under the terms of the GNU General Public License as published by
13 : the Free Software Foundation; either version 3 of the License, or
14 : (at your option) any later version.
15 :
16 : This program is distributed in the hope that it will be useful,
17 : but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : GNU General Public License for more details.
20 :
21 : You should have received a copy of the GNU General Public License
22 : along with this program. If not, see <http://www.gnu.org/licenses/>.
23 : */
24 :
25 : #include <stdlib.h>
26 : #include <check.h>
27 : #include <talloc.h>
28 : #include <tevent.h>
29 : #include <popt.h>
30 :
31 : #include "common.h"
32 :
33 : #include "sbus/sssd_dbus.h"
34 : #include "sbus/sssd_dbus_meta.h"
35 : #include "util/util_errors.h"
36 :
37 : /*
38 : * Although one would normally rely on the codegen to generate these
39 : * structures, we want to test this functionality *before* we test
40 : * the codegen in sbus_codegen_tests ... so these are hand rolled.
41 : */
42 :
43 : #define PILOT_IFACE "test.Pilot"
44 : #define PILOT_BLINK "Blink"
45 : #define PILOT_EAT "Eat"
46 :
47 : #define PILOT_IFACE_INTROSPECT \
48 : "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n" \
49 : " \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n" \
50 : "<node name=\"/test/leela\">\n" \
51 : " <interface name=\"org.freedesktop.DBus.Introspectable\">\n" \
52 : " <method name=\"Introspect\">\n" \
53 : " <arg type=\"s\" name=\"data\" direction=\"out\" />\n" \
54 : " </method>\n" \
55 : " </interface>\n" \
56 : " <interface name=\"org.freedesktop.DBus.Properties\">\n" \
57 : " <method name=\"Get\">\n" \
58 : " <arg type=\"s\" name=\"interface_name\" direction=\"in\" />\n" \
59 : " <arg type=\"s\" name=\"property_name\" direction=\"in\" />\n" \
60 : " <arg type=\"v\" name=\"value\" direction=\"out\" />\n" \
61 : " </method>\n" \
62 : " <method name=\"Set\">\n" \
63 : " <arg type=\"s\" name=\"interface_name\" direction=\"in\" />\n" \
64 : " <arg type=\"s\" name=\"property_name\" direction=\"in\" />\n" \
65 : " <arg type=\"v\" name=\"value\" direction=\"in\" />\n" \
66 : " </method>\n" \
67 : " <method name=\"GetAll\">\n" \
68 : " <arg type=\"s\" name=\"interface_name\" direction=\"in\" />\n" \
69 : " <arg type=\"a{sv}\" name=\"props\" direction=\"out\" />\n" \
70 : " </method>\n" \
71 : " </interface>\n" \
72 : " <interface name=\"test.Pilot\">\n" \
73 : " <method name=\"Blink\" />\n" \
74 : " <method name=\"Eat\" />\n" \
75 : " </interface>\n" \
76 : "</node>\n"
77 :
78 : /* our vtable */
79 : struct pilot_vtable {
80 : struct sbus_vtable vtable;
81 : sbus_msg_handler_fn Blink;
82 : sbus_msg_handler_fn Eat;
83 : };
84 :
85 : const struct sbus_method_meta pilot_methods[] = {
86 : {
87 : PILOT_BLINK, /* method name */
88 : NULL, /* in args: manually parsed */
89 : NULL, /* out args: manually parsed */
90 : offsetof(struct pilot_vtable, Blink),
91 : NULL
92 : },
93 : {
94 : PILOT_EAT, /* method name */
95 : NULL, /* in args: manually parsed */
96 : NULL, /* out args: manually parsed */
97 : offsetof(struct pilot_vtable, Eat),
98 : NULL
99 : },
100 : { NULL, }
101 : };
102 :
103 : const struct sbus_interface_meta pilot_meta = {
104 : PILOT_IFACE, /* name */
105 : pilot_methods,
106 : NULL, /* no signals */
107 : NULL, /* no properties */
108 : NULL, /* no GetAll invoker */
109 : };
110 :
111 0 : static int blink_handler(struct sbus_request *req, void *data)
112 : {
113 0 : DBusError error = DBUS_ERROR_INIT;
114 0 : dbus_int32_t duration = 0;
115 : dbus_bool_t crashed;
116 :
117 0 : ck_assert(req->intf->vtable->meta == &pilot_meta);
118 0 : ck_assert(data != NULL);
119 0 : ck_assert(data == req->intf->handler_data);
120 :
121 0 : ck_assert_str_eq(req->intf->path, req->path);
122 :
123 0 : if (strcmp(req->path, "/test/fry") == 0) {
124 0 : ck_assert_str_eq(data, "Don't crash");
125 0 : } else if (strcmp(req->path, "/test/leela") == 0) {
126 0 : ck_assert_str_eq(data, "Crash into the billboard");
127 : } else {
128 0 : ck_abort();
129 : }
130 :
131 0 : if (!dbus_message_get_args (req->message, &error,
132 : DBUS_TYPE_INT32, &duration,
133 : DBUS_TYPE_INVALID)) {
134 0 : sbus_request_fail_and_finish(req, &error);
135 0 : dbus_error_free(&error);
136 0 : return EOK;
137 : }
138 :
139 : /* Pilot crashes when eyes closed too long */
140 0 : crashed = (duration > 5);
141 :
142 0 : return sbus_request_return_and_finish(req,
143 : DBUS_TYPE_BOOLEAN, &crashed,
144 : DBUS_TYPE_INVALID);
145 : }
146 :
147 0 : static int eat_handler(struct sbus_request *req, void *data)
148 : {
149 : dbus_int32_t integer;
150 : dbus_bool_t boolean;
151 : const char **array;
152 : int count;
153 :
154 0 : if (!sbus_request_parse_or_finish (req,
155 : DBUS_TYPE_INT32, &integer,
156 : DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &array, &count,
157 : DBUS_TYPE_BOOLEAN, &boolean,
158 : DBUS_TYPE_INVALID)) {
159 0 : return EOK; /* handled */
160 : }
161 :
162 0 : ck_assert_int_eq(integer, 5);
163 0 : ck_assert(boolean == TRUE);
164 0 : ck_assert_int_eq(count, 3);
165 0 : ck_assert_str_eq(array[0], "one");
166 0 : ck_assert_str_eq(array[1], "two");
167 0 : ck_assert_str_eq(array[2], "three");
168 :
169 0 : return sbus_request_return_and_finish(req, DBUS_TYPE_INVALID);
170 : }
171 :
172 : struct pilot_vtable pilot_impl = {
173 : { &pilot_meta, 0 },
174 : .Blink = blink_handler,
175 : .Eat = eat_handler,
176 : };
177 :
178 0 : static int pilot_test_server_init(struct sbus_connection *server, void *unused)
179 : {
180 : int ret;
181 :
182 0 : ret = sbus_conn_register_iface(server, &pilot_impl.vtable, "/test/leela",
183 : "Crash into the billboard");
184 0 : ck_assert_int_eq(ret, EOK);
185 :
186 :
187 0 : ret = sbus_conn_register_iface(server, &pilot_impl.vtable, "/test/fry",
188 : "Don't crash");
189 0 : ck_assert_int_eq(ret, EOK);
190 :
191 0 : return EOK;
192 : }
193 :
194 1 : START_TEST(test_raw_handler)
195 : {
196 : TALLOC_CTX *ctx;
197 : DBusConnection *client;
198 1 : DBusError error = DBUS_ERROR_INIT;
199 : DBusMessage *reply;
200 : dbus_bool_t crashed;
201 : dbus_int32_t duration;
202 :
203 1 : ctx = talloc_new(NULL);
204 1 : client = test_dbus_setup_mock(ctx, NULL, pilot_test_server_init, NULL);
205 :
206 : /* Leela crashes with a duration higher than 5 */
207 1 : duration = 10;
208 1 : reply = test_dbus_call_sync(client,
209 : "/test/leela",
210 : PILOT_IFACE,
211 : PILOT_BLINK,
212 : &error,
213 : DBUS_TYPE_INT32, &duration,
214 : DBUS_TYPE_INVALID);
215 1 : ck_assert(reply != NULL);
216 1 : ck_assert(!dbus_error_is_set(&error));
217 1 : ck_assert(dbus_message_get_args(reply, NULL,
218 : DBUS_TYPE_BOOLEAN, &crashed,
219 : DBUS_TYPE_INVALID));
220 1 : dbus_message_unref (reply);
221 1 : ck_assert(crashed == true);
222 :
223 : /* Fry daesn't crash with a duration lower than 5 */
224 1 : duration = 1;
225 1 : reply = test_dbus_call_sync(client,
226 : "/test/fry",
227 : PILOT_IFACE,
228 : PILOT_BLINK,
229 : &error,
230 : DBUS_TYPE_INT32, &duration,
231 : DBUS_TYPE_INVALID);
232 1 : ck_assert(reply != NULL);
233 1 : ck_assert(!dbus_error_is_set(&error));
234 1 : ck_assert(dbus_message_get_args(reply, NULL,
235 : DBUS_TYPE_BOOLEAN, &crashed,
236 : DBUS_TYPE_INVALID));
237 1 : dbus_message_unref (reply);
238 1 : ck_assert(crashed == FALSE);
239 :
240 1 : talloc_free(ctx);
241 : }
242 1 : END_TEST
243 :
244 1 : START_TEST(test_request_parse_ok)
245 : {
246 1 : const char *args[] = { "one", "two", "three" };
247 : const char **array;
248 : TALLOC_CTX *ctx;
249 : DBusConnection *client;
250 1 : DBusError error = DBUS_ERROR_INIT;
251 : DBusMessage *reply;
252 : dbus_bool_t boolean;
253 : dbus_int32_t integer;
254 : int count;
255 :
256 1 : ctx = talloc_new(NULL);
257 1 : client = test_dbus_setup_mock(ctx, NULL, pilot_test_server_init, NULL);
258 :
259 1 : boolean = TRUE;
260 1 : integer = 5;
261 1 : count = 3;
262 1 : array = args;
263 1 : reply = test_dbus_call_sync(client,
264 : "/test/leela",
265 : PILOT_IFACE,
266 : PILOT_EAT,
267 : &error,
268 : DBUS_TYPE_INT32, &integer,
269 : DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &array, count,
270 : DBUS_TYPE_BOOLEAN, &boolean,
271 : DBUS_TYPE_INVALID);
272 1 : ck_assert(reply != NULL);
273 1 : ck_assert(!dbus_error_is_set(&error));
274 1 : ck_assert(dbus_message_get_args(reply, NULL,
275 : DBUS_TYPE_INVALID));
276 1 : dbus_message_unref (reply);
277 :
278 1 : talloc_free(ctx);
279 : }
280 1 : END_TEST
281 :
282 1 : START_TEST(test_request_parse_bad_args)
283 : {
284 : TALLOC_CTX *ctx;
285 : DBusConnection *client;
286 1 : DBusError error = DBUS_ERROR_INIT;
287 : DBusMessage *reply;
288 :
289 1 : ctx = talloc_new(NULL);
290 1 : client = test_dbus_setup_mock(ctx, NULL, pilot_test_server_init, NULL);
291 :
292 1 : reply = test_dbus_call_sync(client,
293 : "/test/leela",
294 : PILOT_IFACE,
295 : PILOT_EAT,
296 : &error,
297 : DBUS_TYPE_INVALID); /* bad agruments */
298 1 : ck_assert(reply == NULL);
299 1 : ck_assert(dbus_error_is_set(&error));
300 1 : ck_assert(dbus_error_has_name(&error, DBUS_ERROR_INVALID_ARGS));
301 1 : dbus_error_free(&error);
302 :
303 1 : talloc_free(ctx);
304 : }
305 1 : END_TEST
306 :
307 1 : START_TEST(test_introspection)
308 : {
309 : TALLOC_CTX *ctx;
310 : DBusConnection *client;
311 1 : DBusError error = DBUS_ERROR_INIT;
312 : DBusMessage *reply;
313 : char *xml;
314 :
315 1 : ctx = talloc_new(NULL);
316 1 : client = test_dbus_setup_mock(ctx, NULL, pilot_test_server_init, NULL);
317 :
318 1 : reply = test_dbus_call_sync(client,
319 : "/test/leela",
320 : DBUS_INTROSPECT_INTERFACE,
321 : DBUS_INTROSPECT_METHOD,
322 : &error,
323 : DBUS_TYPE_INVALID); /* bad agruments */
324 :
325 1 : ck_assert(reply != NULL);
326 1 : ck_assert(!dbus_error_is_set(&error));
327 1 : ck_assert(dbus_message_get_args(reply, NULL,
328 : DBUS_TYPE_STRING, &xml,
329 : DBUS_TYPE_INVALID));
330 1 : ck_assert_str_eq(PILOT_IFACE_INTROSPECT, xml);
331 :
332 1 : dbus_message_unref(reply);
333 :
334 1 : talloc_free(ctx);
335 : }
336 1 : END_TEST
337 :
338 1 : START_TEST(test_sbus_new_error)
339 : {
340 : TALLOC_CTX *ctx;
341 : DBusError *error;
342 :
343 1 : ctx = talloc_new(NULL);
344 :
345 1 : error = sbus_error_new(ctx, DBUS_ERROR_IO_ERROR, "Input-output error");
346 1 : ck_assert(error != NULL);
347 1 : ck_assert(dbus_error_is_set(error));
348 1 : ck_assert(dbus_error_has_name(error, DBUS_ERROR_IO_ERROR));
349 1 : talloc_free(error);
350 :
351 1 : error = sbus_error_new(ctx, DBUS_ERROR_IO_ERROR,
352 : "The answer should have been %d", 42);
353 1 : ck_assert(error != NULL);
354 1 : ck_assert(dbus_error_is_set(error));
355 1 : ck_assert(dbus_error_has_name(error, DBUS_ERROR_IO_ERROR));
356 1 : talloc_free(error);
357 :
358 : /* NULL message must also work */
359 1 : error = sbus_error_new(ctx, DBUS_ERROR_IO_ERROR, NULL);
360 1 : ck_assert(error != NULL);
361 1 : ck_assert(dbus_error_is_set(error));
362 1 : ck_assert(dbus_error_has_name(error, DBUS_ERROR_IO_ERROR));
363 1 : talloc_free(error);
364 :
365 1 : talloc_free(ctx);
366 : }
367 1 : END_TEST
368 :
369 1 : TCase *create_sbus_tests(void)
370 : {
371 1 : TCase *tc = tcase_create("tests");
372 :
373 1 : tcase_add_test(tc, test_raw_handler);
374 1 : tcase_add_test(tc, test_request_parse_ok);
375 1 : tcase_add_test(tc, test_request_parse_bad_args);
376 1 : tcase_add_test(tc, test_introspection);
377 1 : tcase_add_test(tc, test_sbus_new_error);
378 :
379 1 : return tc;
380 : }
381 :
382 1 : Suite *create_suite(void)
383 : {
384 1 : Suite *s = suite_create("sbus");
385 1 : suite_add_tcase(s, create_sbus_tests());
386 1 : return s;
387 : }
388 :
389 1 : int main(int argc, const char *argv[])
390 : {
391 : int opt;
392 : poptContext pc;
393 : int failure_count;
394 : Suite *suite;
395 : SRunner *sr;
396 :
397 1 : struct poptOption long_options[] = {
398 : POPT_AUTOHELP
399 : POPT_TABLEEND
400 : };
401 :
402 1 : pc = poptGetContext(argv[0], argc, argv, long_options, 0);
403 1 : while ((opt = poptGetNextOpt(pc)) != -1) {
404 : switch (opt) {
405 : default:
406 0 : fprintf(stderr, "\nInvalid option %s: %s\n\n",
407 : poptBadOption(pc, 0), poptStrerror(opt));
408 0 : poptPrintUsage(pc, stderr, 0);
409 0 : return 1;
410 : }
411 : }
412 1 : poptFreeContext(pc);
413 :
414 1 : suite = create_suite();
415 1 : sr = srunner_create(suite);
416 : /* If CK_VERBOSITY is set, use that, otherwise it defaults to CK_NORMAL */
417 1 : srunner_run_all(sr, CK_ENV);
418 1 : failure_count = srunner_ntests_failed(sr);
419 1 : srunner_free(sr);
420 1 : return (failure_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
421 : }
|