3 Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
4 Author: Kazimierz Krosman <k.krosman@samsung.com>
6 Permission is hereby granted, free of charge, to any person obtaining
7 a copy of this software and associated documentation files (the
8 "Software"), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sublicense, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
14 The above copyright notice and this permission notice shall be
15 included in all copies or substantial portions of the Software.
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35 #include <sys/types.h>
37 #include <sys/select.h>
41 #include <sys/select.h>
43 #include <sys/types.h>
48 #define MAX_TC_NUM 1024
49 #define MAX_BUFFER (64*1024)
50 #define MAX_COMMENT 1024
52 #define INSTALLED_TESTS_DIR "/usr/lib/dbus/installed-tests/dbus/data"
66 char comment[MAX_COMMENT];
67 char result[MAX_COMMENT];
68 char name[MAX_COMMENT];
73 const char* description;
79 struct test_case* test_cases;
82 char** (*prepare_args) (const struct binary* b, const char* test_name);
83 void (*parse) (const struct binary* b, const char* test_name, char* buffer, int state_change, int state_option);
88 char* get_test_id(char* dest, const struct binary* b, const char* test_name);
89 void add_test_result(const char* test_id, const char* result, const char* comment, int res);
95 void parse_binary_outputs(const struct binary* b, const char* test_name, char* buffer, int state_change, int state_option);
96 char** prepare_args_for_binary(const struct binary* b, const char* test_name);
97 char** prepare_args_for_dir_iter(const struct binary* b, const char* test_name);
98 int init_environment_vars();
100 static struct test_case desc_2[] = {
101 {"", "Testing DBus ability to iterate over directory contents."}, {NULL, NULL}
103 static struct test_case desc_3[] = {
104 {"", "Simple manual tcp check."}, {NULL, NULL}
106 static struct test_case desc_4[] = {
107 {"", "Test for being disconnected by a corrupt message."}, {NULL, NULL}
109 static struct test_case desc_5[] = {
110 {"", "Integration tests for the dbus-daemon."}, {NULL, NULL}
112 static struct test_case desc_6[] = {
113 {"", "Checks DBus daemon eavesdropping ability."}, {NULL, NULL}
115 static struct test_case desc_7[] = {
116 {"", "Tests passing various ammounts of fds(If supported on given platform)."}, {NULL, NULL}
118 static struct test_case desc_8[] = {
119 {"", "Simple sanity-check for loopback through TCP and Unix sockets."}, {NULL, NULL}
121 static struct test_case desc_9[] = {
122 {"", "Simple sanity-check for D-Bus message serialization."}, {NULL, NULL}
124 static struct test_case desc_10[] = {
125 {"", "Integration tests for monitor-mode D-Bus connections."}, {NULL, NULL}
127 static struct test_case desc_11[] = {
128 {"", "Test for _dbus_printf_string_upper_bound."}, {NULL, NULL}
130 static struct test_case desc_12[] = {
131 {"", "Test for thread-safe reference-counting."}, {NULL, NULL}
133 static struct test_case desc_13[] = {
134 {"", "Test for passing unmodified messages between connections."}, {NULL, NULL}
136 static struct test_case desc_14[] = {
137 {"", "Unit tests for systemd activation."}, {NULL, NULL}
139 static struct test_case desc_15[] = {
140 {"", "Test for shell commands."}, {NULL, NULL}
142 static struct test_case desc_16[] = {
143 {"", "Test dor D-bus syntax validation."}, {NULL, NULL}
145 static struct test_case desc_17[] = {
146 {"", "Manual test for syslog support."}, {NULL, NULL}
148 static struct test_case desc_18[] = {
149 {"", "Integration tests for the dbus-daemon's uid-based hardening."}, {NULL, NULL}
152 /* This table is used to start binaries */
153 struct binary tests[] = {
154 /*path, name, TC_table, timeout in us, prepare_args_handler, parse_function_handler, init_handler, clean_handler*/
155 {"/usr/lib/dbus-tests/test-suites/dbus-tests/manual-dir-iter",
156 "manual-dir-iter", desc_2, 1000*1000, prepare_args_for_dir_iter, parse_binary_outputs, init_environment_vars, NULL},
157 {"/usr/lib/dbus-tests/test-suites/dbus-tests/manual-tcp",
158 "manual-tcp", desc_3, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
159 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-corrupt",
160 "test-corrupt", desc_4, 10*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
161 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-dbus-daemon",
162 "test-dbus-daemon", desc_5, 15*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
163 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-dbus-daemon-eavesdrop",
164 "test-dbus-daemon-eavesdrop", desc_6, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
165 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-fdpass",
166 "test-fdpass", desc_7, 3*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
167 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-loopback",
168 "test-loopback", desc_8, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
169 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-marshal",
170 "test-marshal", desc_9, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
171 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-monitor",
172 "test-monitor", desc_10, 3*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
173 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-printf",
174 "test-printf", desc_11, 2*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
175 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-refs",
176 "test-refs", desc_12, 90*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
177 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-relay",
178 "test-relay", desc_13, 6*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
179 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-sd-activation",
180 "test-sd-activation", desc_14, 90*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
181 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-shell",
182 "test-shell", desc_15, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
183 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-syntax",
184 "test-syntax", desc_16, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
185 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-syslog",
186 "test-syslog", desc_17, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
187 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-uid-permissions",
188 "test-uid-permissions", desc_18, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL}
193 static const char result_pattern[] = "[r][%0]%1";
194 static struct state {
195 unsigned int i; // index of input buffer
196 unsigned int j; // index in results[n]
197 unsigned int n; //index in results buffer (0 or 1)
198 char results[2][MAX_COMMENT];
201 static void sm_reset(void)
203 memset(&g_state, 0, sizeof (g_state));
206 static int sm_update(char* buffer, int i)
208 int l = strlen(buffer) + 1;
209 while (i < l && g_state.i < sizeof(result_pattern) - 1) {
210 if (result_pattern[g_state.i] == '%') {
211 g_state.n = result_pattern[g_state.i+1] - '0';
215 } else if (isalnum(buffer[i])) {
216 g_state.results[g_state.n][g_state.j++] = buffer[i];
217 } else if (buffer[i] == result_pattern[g_state.i+2] || buffer[i] == '\n') {
218 g_state.results[g_state.n][g_state.j] = 0;
227 } else if (result_pattern[g_state.i] == buffer[i]) {
235 if (g_state.i >= sizeof(result_pattern) - 1) {
236 g_state.results[g_state.n][g_state.j] = 0;
246 static const char* sm_get_result(int i)
248 return g_state.results[i];
251 static char* args[3];
252 char** prepare_args_for_binary(const struct binary* b, const char* test_name)
254 args[0] = (char*)b->name;
258 args[1] = (char*)test_name;
264 char** prepare_args_for_dir_iter(const struct binary* b, const char* test_name)
266 static char* args_dir[2];
267 args_dir[0] = (char*)b->name;
268 args_dir[1] = INSTALLED_TESTS_DIR;
272 int init_environment_vars()
274 return !(putenv("DBUS_TEST_DATA="INSTALLED_TESTS_DIR));
277 void parse_binary_outputs(const struct binary* b, const char* test_name, char* buffer, int state_change, int state_option)
279 char test_id[MAX_COMMENT];
281 switch(state_change) {
285 buffer[state_option] = 0;
286 get_test_id(test_id, b, test_name);
287 fprintf(stderr, "[stdout][%s]%s\n",test_id, buffer);
290 buffer[state_option] = 0;
291 get_test_id(test_id, b, test_name);
292 fprintf(stderr, "[stderr][%s]%s\n",test_id, buffer);
295 get_test_id(test_id, b, test_name);
296 if (state_option != 0)
297 add_test_result(test_id, "FAIL", "", 0);
298 else if (state_option == 77)
299 add_test_result(test_id, "SKIP", "", 0);
301 add_test_result(test_id, "PASS", "", 1);
304 get_test_id(test_id, b, test_name);
305 add_test_result(test_id, "FAIL", "Finished by SIGNAL", 0);
308 get_test_id(test_id, b, test_name);
309 add_test_result(test_id, "FAIL", "Test TIMEOUT", 0);
314 static struct option long_options[] = {
315 {"list", no_argument, 0, 'l'},
316 {"run", required_argument, 0, 'r'},
317 {"description", required_argument, 0, 'd'},
321 static int stdin_pipe[2];
322 static int stdout_pipe[2];
323 static int stderr_pipe[2];
324 static int gravedigger_pipe[2];
325 static char buffer[MAX_BUFFER];
326 static const char* requested_tc[MAX_TC_NUM];
328 char* get_test_id(char* dest, const struct binary* b, const char* test_name)
330 int len = strlen(b->name);
331 memcpy(dest, b->name, len);
332 memcpy(dest + len, test_name, strlen(test_name)+1);
336 static void print_description(const char* name, const char* description)
338 printf("%s;%s\n",name, description);
341 static void print_list(const char* test_name)
344 char full_name[MAX_COMMENT];
345 for (i = 0;i < sizeof(tests)/sizeof(struct binary); i++) {
347 int l = strlen(tests[i].name);
348 memcpy(full_name, tests[i].name, l+1);
349 if (test_name && strncmp(test_name, full_name, l) != 0)
352 while (tests[i].test_cases[j].name) {
353 memcpy(full_name + l, tests[i].test_cases[j].name, strlen(tests[i].test_cases[j].name) + 1);
354 if (!test_name || strcmp(full_name, test_name) == 0)
355 print_description(full_name,tests[i].test_cases[j].description);
361 static void stop_binary(const struct binary* b, pid_t pid, const char* test_name, int w_res)
366 res = waitpid(pid, &status, WNOHANG);
368 res = waitpid(pid, &status, 0);
373 res = waitpid(pid, &status, WNOHANG);
374 b->parse(b, test_name, buffer, RESULT_TIMEOUT, res);
375 } else if (res < 0) {
378 res = waitpid(pid, &status, WNOHANG);
379 b->parse(b, test_name, buffer, RESULT_ERROR, res);
380 } else if (res > 0) {
381 if (WIFEXITED(status)) {
382 b->parse(b, test_name, buffer, RESULT_CODE, WEXITSTATUS(status));
383 } else if (WIFSIGNALED(status)) {
384 b->parse(b, test_name, buffer, RESULT_SIGNAL, WTERMSIG(status));
385 } else if (WIFSTOPPED(status)) {
386 b->parse(b, test_name, buffer, RESULT_SIGNAL, WSTOPSIG(status));
387 } else if (WIFCONTINUED(status)) {
389 b->parse(b, test_name, buffer, RESULT_SIGNAL, -1);
395 static void parse_output_with_timeout(const struct binary* b, pid_t pid, const char* test_name)
402 tv.tv_sec = b->timeout/(1000*1000);
403 tv.tv_usec = (b->timeout-tv.tv_sec*1000*1000);
406 if (stdout_pipe[PIPE_READ] > -1) {
407 assert(stdout_pipe[PIPE_READ] > -1);
408 assert(stdout_pipe[PIPE_READ] < 1024);
409 FD_SET(stdout_pipe[PIPE_READ], &rfds);
411 if (stderr_pipe[PIPE_READ] > -1) {
412 assert(stderr_pipe[PIPE_READ] > -1);
413 assert(stderr_pipe[PIPE_READ] < 1024);
414 FD_SET(stderr_pipe[PIPE_READ], &rfds);
416 FD_SET(gravedigger_pipe[PIPE_READ], &rfds);
418 nfds = select(FD_SETSIZE, &rfds, NULL, NULL, &tv);
420 if (errno != EINTR) {
424 } else if (nfds > 0) {
425 if (stdout_pipe[PIPE_READ] > -1 && FD_ISSET(stdout_pipe[PIPE_READ], &rfds)) {
426 res = read(stdout_pipe[PIPE_READ], buffer, MAX_BUFFER-1);
427 if (res == 0 || (res < 0 && errno != EINTR)) {
428 close (stdout_pipe[PIPE_READ]);
429 stdout_pipe[PIPE_READ] = -1;
431 } else if (res >=0) {
432 b->parse(b, test_name, buffer, NEW_STDOUT, res);
436 if (stderr_pipe[PIPE_READ] > -1 && FD_ISSET(stderr_pipe[PIPE_READ], &rfds)) {
437 res = read(stderr_pipe[PIPE_READ], buffer, MAX_BUFFER-1);
438 if (res == 0 || (res < 0 && errno != EINTR)) {
439 close (stderr_pipe[PIPE_READ]);
440 stderr_pipe[PIPE_READ] = -1;
443 b->parse(b, test_name, buffer, NEW_STDERR, res);
446 if (FD_ISSET(gravedigger_pipe[PIPE_READ], &rfds)) {
448 break; //it has ended
456 stop_binary(b, pid, test_name, w_res);
459 static int create_child(const char* path, char* const arguments[])
463 if (pipe(gravedigger_pipe) < 0) {
464 perror("allocating pipe for gravedigger failed");
468 if (pipe(stdin_pipe) < 0) {
469 perror("allocating pipe for child input redirect failed");
473 if (pipe(stdout_pipe) < 0) {
474 perror("allocating pipe for child output redirect failed");
478 if (pipe(stderr_pipe) < 0) {
479 perror("allocating pipe for child output redirect failed");
486 sprintf(ld_path, "/usr/lib/dbus-tests/lib/libdbuspolicy-tests/:");
488 if (dup2(stdin_pipe[PIPE_READ], STDIN_FILENO) == -1) {
489 perror("redirecting stdin failed");
494 if (dup2(stdout_pipe[PIPE_WRITE], STDOUT_FILENO) == -1) {
495 perror("redirecting stdout failed");
500 if (dup2(stderr_pipe[PIPE_WRITE], STDERR_FILENO) == -1) {
501 perror("redirecting stderr failed");
505 // all these are for use by parent only
506 close(stdin_pipe[PIPE_READ]);
507 close(stdin_pipe[PIPE_WRITE]);
508 close(stdout_pipe[PIPE_READ]);
509 close(stdout_pipe[PIPE_WRITE]);
510 close(stderr_pipe[PIPE_READ]);
511 close(stderr_pipe[PIPE_WRITE]);
512 close(gravedigger_pipe[PIPE_READ]);
514 char* ld_path_b = getenv("LD_LIBRARY_PATH");
515 if (ld_path_b != NULL)
516 memcpy(ld_path + strlen(ld_path), ld_path_b, strlen(ld_path_b)+1);
517 setenv("LD_LIBRARY_PATH", ld_path, 1);
518 // run child process image
519 nResult = execv(path, arguments);
521 // if we get here at all, an error occurred, but we are in the child
522 // process, so just exit
523 perror("exec of the child process failed");
525 } else if (child > 0) {
526 // parent continues here
528 // close unused file descriptors, these are for child only
529 close(stdin_pipe[PIPE_READ]);
530 close(stdout_pipe[PIPE_WRITE]);
531 close(stderr_pipe[PIPE_WRITE]);
532 close(gravedigger_pipe[PIPE_WRITE]);
534 // failed to create child
541 close(stderr_pipe[PIPE_READ]);
542 close(stderr_pipe[PIPE_WRITE]);
544 close(stdout_pipe[PIPE_READ]);
545 close(stdout_pipe[PIPE_WRITE]);
547 close(stdin_pipe[PIPE_READ]);
548 close(stdin_pipe[PIPE_WRITE]);
553 static void run_test(const struct binary* b, const char* test_name)
557 char test_id[MAX_COMMENT];
564 arg = b->prepare_args(b, test_name);
568 add_test_result(get_test_id(test_id, b, test_name), "ERROR", "Cannot init test", 0);
572 res = create_child(b->path, arg);
574 parse_output_with_timeout(b, res, test_name);
576 add_test_result(get_test_id(test_id, b, test_name), "ERROR", "Cannot start test", 0);
582 static void parse_run_test(const char* tc) {
584 for (i = 0;i < sizeof(tests)/sizeof(struct binary); i++) {
585 int len = strlen(tests[i].name);
586 if (strncmp(tc, tests[i].name, len) == 0) {
587 if (tc[len] == '*' || tc[len] == '\0')
588 run_test(&tests[i], "");
590 run_test(&tests[i], tc + len);
595 static int parse_option(int argc, char* argv[])
599 while ((ch = getopt_long(argc, argv, "lr:d:", long_options, NULL)) != -1) {
605 if (c >= MAX_TC_NUM - 1) //NULL at the end
609 requested_tc[c++] = optarg;
620 void add_test_result(const char* test_id, const char* result, const char* comment, int res)
622 printf("%s;%s;%s\n", test_id, result, comment);
626 int main(int argc, char* argv[])
629 signal(SIGPIPE, SIG_IGN);
630 if (parse_option(argc, argv))
633 if (!requested_tc[0]) {
634 for (i = 0;i < sizeof(tests)/sizeof(struct binary); i++)
635 run_test(&tests[i], "");
638 while(requested_tc[i]) {
639 parse_run_test(requested_tc[i]);