1 /* This file contains test-runner
3 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
4 * Author: Kazimierz Krosman <k.krosman@samsung.com>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
27 #include <sys/types.h>
29 #include <sys/select.h>
33 #include <sys/select.h>
35 #include <sys/types.h>
40 #define MAX_TC_NUM 1024
41 #define MAX_BUFFER (64*1024)
42 #define MAX_COMMENT 1024
56 char comment[MAX_COMMENT];
57 char result[MAX_COMMENT];
58 char name[MAX_COMMENT];
63 const char* description;
69 struct test_case* test_cases;
72 char** (*prepare_args) (const struct binary* b, const char* test_name);
73 void (*parse) (const struct binary* b, const char* test_name, char* buffer, int state_change, int state_option);
78 char* get_test_id(char* dest, const struct binary* b, const char* test_name);
79 void add_test_result(const char* test_id, const char* result, const char* comment, int res);
85 void parse_binary_outputs(const struct binary* b, const char* test_name, char* buffer, int state_change, int state_option);
86 char** prepare_args_for_binary(const struct binary* b, const char* test_name);
87 char** prepare_args_for_dir_iter(const struct binary* b, const char* test_name);
88 int init_environment_vars();
90 static struct test_case desc_1[] = {
91 {"", "Simple sanity-check for authentication and authorization."}, {NULL, NULL}
93 static struct test_case desc_2[] = {
94 {"", "Testing DBus ability to iterate over directory contents."}, {NULL, NULL}
96 static struct test_case desc_3[] = {
97 {"", "Simple manual tcp check."}, {NULL, NULL}
99 static struct test_case desc_4[] = {
100 {"", "Test for being disconnected by a corrupt message."}, {NULL, NULL}
102 static struct test_case desc_5[] = {
103 {"", "Integration tests for the dbus-daemon."}, {NULL, NULL}
105 static struct test_case desc_6[] = {
106 {"", "Checks DBus daemon eavesdropping ability."}, {NULL, NULL}
108 static struct test_case desc_7[] = {
109 {"", "Tests passing various ammounts of fds(If supported on given platform)."}, {NULL, NULL}
111 static struct test_case desc_8[] = {
112 {"", "Simple sanity-check for loopback through TCP and Unix sockets."}, {NULL, NULL}
114 static struct test_case desc_9[] = {
115 {"", "Simple sanity-check for D-Bus message serialization."}, {NULL, NULL}
117 static struct test_case desc_10[] = {
118 {"", "Integration tests for monitor-mode D-Bus connections."}, {NULL, NULL}
120 static struct test_case desc_11[] = {
121 {"", "Test for _dbus_printf_string_upper_bound."}, {NULL, NULL}
123 static struct test_case desc_12[] = {
124 {"", "Test for thread-safe reference-counting."}, {NULL, NULL}
126 static struct test_case desc_13[] = {
127 {"", "Test for passing unmodified messages between connections."}, {NULL, NULL}
129 static struct test_case desc_14[] = {
130 {"", "Unit tests for systemd activation."}, {NULL, NULL}
132 static struct test_case desc_15[] = {
133 {"", "Test for shell commands."}, {NULL, NULL}
135 static struct test_case desc_16[] = {
136 {"", "Test dor D-bus syntax validation."}, {NULL, NULL}
138 static struct test_case desc_17[] = {
139 {"", "Manual test for syslog support."}, {NULL, NULL}
141 static struct test_case desc_18[] = {
142 {"", "Integration tests for the dbus-daemon's uid-based hardening."}, {NULL, NULL}
145 /* This table is used to start binaries */
146 struct binary tests[] = {
147 /*path, name, TC_table, timeout in us, prepare_args_handler, parse_function_handler, init_handler, clean_handler*/
148 {"/usr/lib/dbus-tests/test-suites/dbus-tests/manual-authz",
149 "manual-authz", desc_1, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
150 {"/usr/lib/dbus-tests/test-suites/dbus-tests/manual-dir-iter",
151 "manual-dir-iter", desc_2, 1000*1000, prepare_args_for_dir_iter, parse_binary_outputs, init_environment_vars, NULL},
152 {"/usr/lib/dbus-tests/test-suites/dbus-tests/manual-tcp",
153 "manual-tcp", desc_3, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
154 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-corrupt",
155 "test-corrupt", desc_4, 10*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
156 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-dbus-daemon",
157 "test-dbus-daemon", desc_5, 15*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
158 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-dbus-daemon-eavesdrop",
159 "test-dbus-daemon-eavesdrop", desc_6, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
160 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-fdpass",
161 "test-fdpass", desc_7, 3*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
162 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-loopback",
163 "test-loopback", desc_8, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
164 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-marshal",
165 "test-marshal", desc_9, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
166 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-monitor",
167 "test-monitor", desc_10, 3*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
168 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-printf",
169 "test-printf", desc_11, 2*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
170 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-refs",
171 "test-refs", desc_12, 90*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
172 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-relay",
173 "test-relay", desc_13, 6*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
174 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-sd-activation",
175 "test-sd-activation", desc_14, 90*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
176 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-shell",
177 "test-shell", desc_15, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
178 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-syntax",
179 "test-syntax", desc_16, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
180 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-syslog",
181 "test-syslog", desc_17, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
182 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-uid-permissions",
183 "test-uid-permissions", desc_18, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL}
188 static const char result_pattern[] = "[r][%0]%1";
189 static struct state {
190 unsigned int i; // index of input buffer
191 unsigned int j; // index in results[n]
192 unsigned int n; //index in results buffer (0 or 1)
193 char results[2][MAX_COMMENT];
196 static void sm_reset(void)
198 memset(&g_state, 0, sizeof (g_state));
201 static int sm_update(char* buffer, int i)
203 int l = strlen(buffer) + 1;
204 while (i < l && g_state.i < sizeof(result_pattern) - 1) {
205 if (result_pattern[g_state.i] == '%') {
206 g_state.n = result_pattern[g_state.i+1] - '0';
210 } else if (isalnum(buffer[i])) {
211 g_state.results[g_state.n][g_state.j++] = buffer[i];
212 } else if (buffer[i] == result_pattern[g_state.i+2] || buffer[i] == '\n') {
213 g_state.results[g_state.n][g_state.j] = 0;
222 } else if (result_pattern[g_state.i] == buffer[i]) {
230 if (g_state.i >= sizeof(result_pattern) - 1) {
231 g_state.results[g_state.n][g_state.j] = 0;
241 static const char* sm_get_result(int i)
243 return g_state.results[i];
246 static char* args[3];
247 char** prepare_args_for_binary(const struct binary* b, const char* test_name)
249 args[0] = (char*)b->name;
253 args[1] = (char*)test_name;
259 char** prepare_args_for_dir_iter(const struct binary* b, const char* test_name)
261 static char* args_dir[2];
262 args_dir[0] = (char*)b->name;
263 args_dir[1] = "/usr/lib/dbus-tests/test-suites/dbus-tests/data";
267 int init_environment_vars()
269 return !(putenv("DBUS_TEST_DATA=/usr/lib/dbus-tests/test-suites/dbus-tests/data"));
272 void parse_binary_outputs(const struct binary* b, const char* test_name, char* buffer, int state_change, int state_option)
274 char test_id[MAX_COMMENT];
276 switch(state_change) {
280 buffer[state_option] = 0;
281 get_test_id(test_id, b, test_name);
282 fprintf(stderr, "[stdout][%s]%s\n",test_id, buffer);
285 buffer[state_option] = 0;
286 get_test_id(test_id, b, test_name);
287 fprintf(stderr, "[stderr][%s]%s\n",test_id, buffer);
290 get_test_id(test_id, b, test_name);
291 if (state_option != 0)
292 add_test_result(test_id, "FAIL", "", 0);
293 else if (state_option == 77)
294 add_test_result(test_id, "SKIP", "", 0);
296 add_test_result(test_id, "PASS", "", 1);
299 get_test_id(test_id, b, test_name);
300 add_test_result(test_id, "FAIL", "Finished by SIGNAL", 0);
303 get_test_id(test_id, b, test_name);
304 add_test_result(test_id, "FAIL", "Test TIMEOUT", 0);
309 static struct option long_options[] = {
310 {"list", no_argument, 0, 'l'},
311 {"run", required_argument, 0, 'r'},
312 {"description", required_argument, 0, 'd'},
316 static int stdin_pipe[2];
317 static int stdout_pipe[2];
318 static int stderr_pipe[2];
319 static int gravedigger_pipe[2];
320 static struct test_result test_results[MAX_TC_NUM];
321 static int test_results_i;
322 static char buffer[MAX_BUFFER];
323 static const char* requested_tc[MAX_TC_NUM];
325 char* get_test_id(char* dest, const struct binary* b, const char* test_name)
327 int len = strlen(b->name);
328 memcpy(dest, b->name, len);
329 memcpy(dest + len, test_name, strlen(test_name)+1);
333 static void print_description(const char* name, const char* description)
335 printf("%s;%s\n",name, description);
338 static void print_list(const char* test_name)
341 char full_name[MAX_COMMENT];
342 for (i = 0;i < sizeof(tests)/sizeof(struct binary); i++) {
344 int l = strlen(tests[i].name);
345 memcpy(full_name, tests[i].name, l+1);
346 if (test_name && strncmp(test_name, full_name, l) != 0)
349 while (tests[i].test_cases[j].name) {
350 memcpy(full_name + l, tests[i].test_cases[j].name, strlen(tests[i].test_cases[j].name) + 1);
351 if (!test_name || strcmp(full_name, test_name) == 0)
352 print_description(full_name,tests[i].test_cases[j].description);
358 static void stop_binary(const struct binary* b, pid_t pid, const char* test_name, int w_res)
363 res = waitpid(pid, &status, WNOHANG);
365 res = waitpid(pid, &status, 0);
370 res = waitpid(pid, &status, WNOHANG);
371 b->parse(b, test_name, buffer, RESULT_TIMEOUT, res);
372 } else if (res < 0) {
375 res = waitpid(pid, &status, WNOHANG);
376 b->parse(b, test_name, buffer, RESULT_ERROR, res);
377 } else if (res > 0) {
378 if (WIFEXITED(status)) {
379 b->parse(b, test_name, buffer, RESULT_CODE, WEXITSTATUS(status));
380 } else if (WIFSIGNALED(status)) {
381 b->parse(b, test_name, buffer, RESULT_SIGNAL, WTERMSIG(status));
382 } else if (WIFSTOPPED(status)) {
383 b->parse(b, test_name, buffer, RESULT_SIGNAL, WSTOPSIG(status));
384 } else if (WIFCONTINUED(status)) {
386 b->parse(b, test_name, buffer, RESULT_SIGNAL, -1);
392 static void parse_output_with_timeout(const struct binary* b, pid_t pid, const char* test_name)
399 tv.tv_sec = b->timeout/(1000*1000);
400 tv.tv_usec = (b->timeout-tv.tv_sec*1000*1000);
403 if (stdout_pipe[PIPE_READ] > -1) {
404 assert(stdout_pipe[PIPE_READ] > -1);
405 assert(stdout_pipe[PIPE_READ] < 1024);
406 FD_SET(stdout_pipe[PIPE_READ], &rfds);
408 if (stderr_pipe[PIPE_READ] > -1) {
409 assert(stderr_pipe[PIPE_READ] > -1);
410 assert(stderr_pipe[PIPE_READ] < 1024);
411 FD_SET(stderr_pipe[PIPE_READ], &rfds);
413 FD_SET(gravedigger_pipe[PIPE_READ], &rfds);
415 nfds = select(FD_SETSIZE, &rfds, NULL, NULL, &tv);
417 if (errno != EINTR) {
421 } else if (nfds > 0) {
422 if (stdout_pipe[PIPE_READ] > -1 && FD_ISSET(stdout_pipe[PIPE_READ], &rfds)) {
423 res = read(stdout_pipe[PIPE_READ], buffer, MAX_BUFFER-1);
424 if (res == 0 || (res < 0 && errno != EINTR)) {
425 close (stdout_pipe[PIPE_READ]);
426 stdout_pipe[PIPE_READ] = -1;
428 } else if (res >=0) {
429 b->parse(b, test_name, buffer, NEW_STDOUT, res);
433 if (stderr_pipe[PIPE_READ] > -1 && FD_ISSET(stderr_pipe[PIPE_READ], &rfds)) {
434 res = read(stderr_pipe[PIPE_READ], buffer, MAX_BUFFER-1);
435 if (res == 0 || (res < 0 && errno != EINTR)) {
436 close (stderr_pipe[PIPE_READ]);
437 stderr_pipe[PIPE_READ] = -1;
440 b->parse(b, test_name, buffer, NEW_STDERR, res);
443 if (FD_ISSET(gravedigger_pipe[PIPE_READ], &rfds)) {
445 break; //it has ended
453 stop_binary(b, pid, test_name, w_res);
456 static int create_child(const char* path, char* const arguments[])
460 if (pipe(gravedigger_pipe) < 0) {
461 perror("allocating pipe for gravedigger failed");
465 if (pipe(stdin_pipe) < 0) {
466 perror("allocating pipe for child input redirect failed");
470 if (pipe(stdout_pipe) < 0) {
471 perror("allocating pipe for child output redirect failed");
475 if (pipe(stderr_pipe) < 0) {
476 perror("allocating pipe for child output redirect failed");
483 sprintf(ld_path, "/usr/lib/dbus-tests/lib/libdbuspolicy-tests/:");
485 if (dup2(stdin_pipe[PIPE_READ], STDIN_FILENO) == -1) {
486 perror("redirecting stdin failed");
491 if (dup2(stdout_pipe[PIPE_WRITE], STDOUT_FILENO) == -1) {
492 perror("redirecting stdout failed");
497 if (dup2(stderr_pipe[PIPE_WRITE], STDERR_FILENO) == -1) {
498 perror("redirecting stderr failed");
502 // all these are for use by parent only
503 close(stdin_pipe[PIPE_READ]);
504 close(stdin_pipe[PIPE_WRITE]);
505 close(stdout_pipe[PIPE_READ]);
506 close(stdout_pipe[PIPE_WRITE]);
507 close(stderr_pipe[PIPE_READ]);
508 close(stderr_pipe[PIPE_WRITE]);
509 close(gravedigger_pipe[PIPE_READ]);
511 char* ld_path_b = getenv("LD_LIBRARY_PATH");
512 if (ld_path_b != NULL)
513 memcpy(ld_path + strlen(ld_path), ld_path_b, strlen(ld_path_b)+1);
514 setenv("LD_LIBRARY_PATH", ld_path, 1);
515 // run child process image
516 nResult = execv(path, arguments);
518 // if we get here at all, an error occurred, but we are in the child
519 // process, so just exit
520 perror("exec of the child process failed");
522 } else if (child > 0) {
523 // parent continues here
525 // close unused file descriptors, these are for child only
526 close(stdin_pipe[PIPE_READ]);
527 close(stdout_pipe[PIPE_WRITE]);
528 close(stderr_pipe[PIPE_WRITE]);
529 close(gravedigger_pipe[PIPE_WRITE]);
531 // failed to create child
538 close(stderr_pipe[PIPE_READ]);
539 close(stderr_pipe[PIPE_WRITE]);
541 close(stdout_pipe[PIPE_READ]);
542 close(stdout_pipe[PIPE_WRITE]);
544 close(stdin_pipe[PIPE_READ]);
545 close(stdin_pipe[PIPE_WRITE]);
550 static void run_test(const struct binary* b, const char* test_name)
554 char test_id[MAX_COMMENT];
561 arg = b->prepare_args(b, test_name);
565 add_test_result(get_test_id(test_id, b, test_name), "ERROR", "Cannot init test", 0);
569 res = create_child(b->path, arg);
571 parse_output_with_timeout(b, res, test_name);
573 add_test_result(get_test_id(test_id, b, test_name), "ERROR", "Cannot start test", 0);
579 static void parse_run_test(const char* tc) {
581 for (i = 0;i < sizeof(tests)/sizeof(struct binary); i++) {
582 int len = strlen(tests[i].name);
583 if (strncmp(tc, tests[i].name, len) == 0) {
584 if (tc[len] == '*' || tc[len] == '\0')
585 run_test(&tests[i], "");
587 run_test(&tests[i], tc + len);
592 static int parse_option(int argc, char* argv[])
596 while ((ch = getopt_long(argc, argv, "lr:d:", long_options, NULL)) != -1) {
602 if (c >= MAX_TC_NUM - 1) //NULL at the end
606 requested_tc[c++] = optarg;
617 void add_test_result(const char* test_id, const char* result, const char* comment, int res)
619 test_results[test_results_i].is_positive = res;
620 strcpy(test_results[test_results_i].result, result);
621 strcpy(test_results[test_results_i].comment, comment);
622 strcpy(test_results[test_results_i++].name, test_id);
625 static void print_results()
628 for (i = 0; i < test_results_i; i++)
630 printf("%s;%s;%s\n", test_results[i].name, test_results[i].result, test_results[i].comment);
634 int main(int argc, char* argv[])
637 signal(SIGPIPE, SIG_IGN);
638 if (parse_option(argc, argv))
641 if (!requested_tc[0]) {
642 for (i = 0;i < sizeof(tests)/sizeof(struct binary); i++)
643 run_test(&tests[i], "");
646 while(requested_tc[i]) {
647 parse_run_test(requested_tc[i]);