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
44 #define INSTALLED_TESTS_DIR "/usr/lib/dbus/installed-tests/dbus/data"
58 char comment[MAX_COMMENT];
59 char result[MAX_COMMENT];
60 char name[MAX_COMMENT];
65 const char* description;
71 struct test_case* test_cases;
74 char** (*prepare_args) (const struct binary* b, const char* test_name);
75 void (*parse) (const struct binary* b, const char* test_name, char* buffer, int state_change, int state_option);
80 char* get_test_id(char* dest, const struct binary* b, const char* test_name);
81 void add_test_result(const char* test_id, const char* result, const char* comment, int res);
87 void parse_binary_outputs(const struct binary* b, const char* test_name, char* buffer, int state_change, int state_option);
88 char** prepare_args_for_binary(const struct binary* b, const char* test_name);
89 char** prepare_args_for_dir_iter(const struct binary* b, const char* test_name);
90 int init_environment_vars();
92 static struct test_case desc_2[] = {
93 {"", "Testing DBus ability to iterate over directory contents."}, {NULL, NULL}
95 static struct test_case desc_3[] = {
96 {"", "Simple manual tcp check."}, {NULL, NULL}
98 static struct test_case desc_4[] = {
99 {"", "Test for being disconnected by a corrupt message."}, {NULL, NULL}
101 static struct test_case desc_5[] = {
102 {"", "Integration tests for the dbus-daemon."}, {NULL, NULL}
104 static struct test_case desc_6[] = {
105 {"", "Checks DBus daemon eavesdropping ability."}, {NULL, NULL}
107 static struct test_case desc_7[] = {
108 {"", "Tests passing various ammounts of fds(If supported on given platform)."}, {NULL, NULL}
110 static struct test_case desc_8[] = {
111 {"", "Simple sanity-check for loopback through TCP and Unix sockets."}, {NULL, NULL}
113 static struct test_case desc_9[] = {
114 {"", "Simple sanity-check for D-Bus message serialization."}, {NULL, NULL}
116 static struct test_case desc_10[] = {
117 {"", "Integration tests for monitor-mode D-Bus connections."}, {NULL, NULL}
119 static struct test_case desc_11[] = {
120 {"", "Test for _dbus_printf_string_upper_bound."}, {NULL, NULL}
122 static struct test_case desc_12[] = {
123 {"", "Test for thread-safe reference-counting."}, {NULL, NULL}
125 static struct test_case desc_13[] = {
126 {"", "Test for passing unmodified messages between connections."}, {NULL, NULL}
128 static struct test_case desc_14[] = {
129 {"", "Unit tests for systemd activation."}, {NULL, NULL}
131 static struct test_case desc_15[] = {
132 {"", "Test for shell commands."}, {NULL, NULL}
134 static struct test_case desc_16[] = {
135 {"", "Test dor D-bus syntax validation."}, {NULL, NULL}
137 static struct test_case desc_17[] = {
138 {"", "Manual test for syslog support."}, {NULL, NULL}
140 static struct test_case desc_18[] = {
141 {"", "Integration tests for the dbus-daemon's uid-based hardening."}, {NULL, NULL}
144 /* This table is used to start binaries */
145 struct binary tests[] = {
146 /*path, name, TC_table, timeout in us, prepare_args_handler, parse_function_handler, init_handler, clean_handler*/
147 {"/usr/lib/dbus-tests/test-suites/dbus-tests/manual-dir-iter",
148 "manual-dir-iter", desc_2, 1000*1000, prepare_args_for_dir_iter, parse_binary_outputs, init_environment_vars, NULL},
149 {"/usr/lib/dbus-tests/test-suites/dbus-tests/manual-tcp",
150 "manual-tcp", desc_3, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
151 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-corrupt",
152 "test-corrupt", desc_4, 10*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
153 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-dbus-daemon",
154 "test-dbus-daemon", desc_5, 15*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
155 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-dbus-daemon-eavesdrop",
156 "test-dbus-daemon-eavesdrop", desc_6, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
157 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-fdpass",
158 "test-fdpass", desc_7, 3*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
159 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-loopback",
160 "test-loopback", desc_8, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
161 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-marshal",
162 "test-marshal", desc_9, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
163 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-monitor",
164 "test-monitor", desc_10, 3*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
165 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-printf",
166 "test-printf", desc_11, 2*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
167 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-refs",
168 "test-refs", desc_12, 90*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
169 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-relay",
170 "test-relay", desc_13, 6*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
171 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-sd-activation",
172 "test-sd-activation", desc_14, 90*1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
173 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-shell",
174 "test-shell", desc_15, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
175 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-syntax",
176 "test-syntax", desc_16, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
177 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-syslog",
178 "test-syslog", desc_17, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL},
179 {"/usr/lib/dbus-tests/test-suites/dbus-tests/test-uid-permissions",
180 "test-uid-permissions", desc_18, 1000*1000, prepare_args_for_binary, parse_binary_outputs, init_environment_vars, NULL}
185 static const char result_pattern[] = "[r][%0]%1";
186 static struct state {
187 unsigned int i; // index of input buffer
188 unsigned int j; // index in results[n]
189 unsigned int n; //index in results buffer (0 or 1)
190 char results[2][MAX_COMMENT];
193 static void sm_reset(void)
195 memset(&g_state, 0, sizeof (g_state));
198 static int sm_update(char* buffer, int i)
200 int l = strlen(buffer) + 1;
201 while (i < l && g_state.i < sizeof(result_pattern) - 1) {
202 if (result_pattern[g_state.i] == '%') {
203 g_state.n = result_pattern[g_state.i+1] - '0';
207 } else if (isalnum(buffer[i])) {
208 g_state.results[g_state.n][g_state.j++] = buffer[i];
209 } else if (buffer[i] == result_pattern[g_state.i+2] || buffer[i] == '\n') {
210 g_state.results[g_state.n][g_state.j] = 0;
219 } else if (result_pattern[g_state.i] == buffer[i]) {
227 if (g_state.i >= sizeof(result_pattern) - 1) {
228 g_state.results[g_state.n][g_state.j] = 0;
238 static const char* sm_get_result(int i)
240 return g_state.results[i];
243 static char* args[3];
244 char** prepare_args_for_binary(const struct binary* b, const char* test_name)
246 args[0] = (char*)b->name;
250 args[1] = (char*)test_name;
256 char** prepare_args_for_dir_iter(const struct binary* b, const char* test_name)
258 static char* args_dir[2];
259 args_dir[0] = (char*)b->name;
260 args_dir[1] = INSTALLED_TESTS_DIR;
264 int init_environment_vars()
266 return !(putenv("DBUS_TEST_DATA="INSTALLED_TESTS_DIR));
269 void parse_binary_outputs(const struct binary* b, const char* test_name, char* buffer, int state_change, int state_option)
271 char test_id[MAX_COMMENT];
273 switch(state_change) {
277 buffer[state_option] = 0;
278 get_test_id(test_id, b, test_name);
279 fprintf(stderr, "[stdout][%s]%s\n",test_id, buffer);
282 buffer[state_option] = 0;
283 get_test_id(test_id, b, test_name);
284 fprintf(stderr, "[stderr][%s]%s\n",test_id, buffer);
287 get_test_id(test_id, b, test_name);
288 if (state_option != 0)
289 add_test_result(test_id, "FAIL", "", 0);
290 else if (state_option == 77)
291 add_test_result(test_id, "SKIP", "", 0);
293 add_test_result(test_id, "PASS", "", 1);
296 get_test_id(test_id, b, test_name);
297 add_test_result(test_id, "FAIL", "Finished by SIGNAL", 0);
300 get_test_id(test_id, b, test_name);
301 add_test_result(test_id, "FAIL", "Test TIMEOUT", 0);
306 static struct option long_options[] = {
307 {"list", no_argument, 0, 'l'},
308 {"run", required_argument, 0, 'r'},
309 {"description", required_argument, 0, 'd'},
313 static int stdin_pipe[2];
314 static int stdout_pipe[2];
315 static int stderr_pipe[2];
316 static int gravedigger_pipe[2];
317 static char buffer[MAX_BUFFER];
318 static const char* requested_tc[MAX_TC_NUM];
320 char* get_test_id(char* dest, const struct binary* b, const char* test_name)
322 int len = strlen(b->name);
323 memcpy(dest, b->name, len);
324 memcpy(dest + len, test_name, strlen(test_name)+1);
328 static void print_description(const char* name, const char* description)
330 printf("%s;%s\n",name, description);
333 static void print_list(const char* test_name)
336 char full_name[MAX_COMMENT];
337 for (i = 0;i < sizeof(tests)/sizeof(struct binary); i++) {
339 int l = strlen(tests[i].name);
340 memcpy(full_name, tests[i].name, l+1);
341 if (test_name && strncmp(test_name, full_name, l) != 0)
344 while (tests[i].test_cases[j].name) {
345 memcpy(full_name + l, tests[i].test_cases[j].name, strlen(tests[i].test_cases[j].name) + 1);
346 if (!test_name || strcmp(full_name, test_name) == 0)
347 print_description(full_name,tests[i].test_cases[j].description);
353 static void stop_binary(const struct binary* b, pid_t pid, const char* test_name, int w_res)
358 res = waitpid(pid, &status, WNOHANG);
360 res = waitpid(pid, &status, 0);
365 res = waitpid(pid, &status, WNOHANG);
366 b->parse(b, test_name, buffer, RESULT_TIMEOUT, res);
367 } else if (res < 0) {
370 res = waitpid(pid, &status, WNOHANG);
371 b->parse(b, test_name, buffer, RESULT_ERROR, res);
372 } else if (res > 0) {
373 if (WIFEXITED(status)) {
374 b->parse(b, test_name, buffer, RESULT_CODE, WEXITSTATUS(status));
375 } else if (WIFSIGNALED(status)) {
376 b->parse(b, test_name, buffer, RESULT_SIGNAL, WTERMSIG(status));
377 } else if (WIFSTOPPED(status)) {
378 b->parse(b, test_name, buffer, RESULT_SIGNAL, WSTOPSIG(status));
379 } else if (WIFCONTINUED(status)) {
381 b->parse(b, test_name, buffer, RESULT_SIGNAL, -1);
387 static void parse_output_with_timeout(const struct binary* b, pid_t pid, const char* test_name)
394 tv.tv_sec = b->timeout/(1000*1000);
395 tv.tv_usec = (b->timeout-tv.tv_sec*1000*1000);
398 if (stdout_pipe[PIPE_READ] > -1) {
399 assert(stdout_pipe[PIPE_READ] > -1);
400 assert(stdout_pipe[PIPE_READ] < 1024);
401 FD_SET(stdout_pipe[PIPE_READ], &rfds);
403 if (stderr_pipe[PIPE_READ] > -1) {
404 assert(stderr_pipe[PIPE_READ] > -1);
405 assert(stderr_pipe[PIPE_READ] < 1024);
406 FD_SET(stderr_pipe[PIPE_READ], &rfds);
408 FD_SET(gravedigger_pipe[PIPE_READ], &rfds);
410 nfds = select(FD_SETSIZE, &rfds, NULL, NULL, &tv);
412 if (errno != EINTR) {
416 } else if (nfds > 0) {
417 if (stdout_pipe[PIPE_READ] > -1 && FD_ISSET(stdout_pipe[PIPE_READ], &rfds)) {
418 res = read(stdout_pipe[PIPE_READ], buffer, MAX_BUFFER-1);
419 if (res == 0 || (res < 0 && errno != EINTR)) {
420 close (stdout_pipe[PIPE_READ]);
421 stdout_pipe[PIPE_READ] = -1;
423 } else if (res >=0) {
424 b->parse(b, test_name, buffer, NEW_STDOUT, res);
428 if (stderr_pipe[PIPE_READ] > -1 && FD_ISSET(stderr_pipe[PIPE_READ], &rfds)) {
429 res = read(stderr_pipe[PIPE_READ], buffer, MAX_BUFFER-1);
430 if (res == 0 || (res < 0 && errno != EINTR)) {
431 close (stderr_pipe[PIPE_READ]);
432 stderr_pipe[PIPE_READ] = -1;
435 b->parse(b, test_name, buffer, NEW_STDERR, res);
438 if (FD_ISSET(gravedigger_pipe[PIPE_READ], &rfds)) {
440 break; //it has ended
448 stop_binary(b, pid, test_name, w_res);
451 static int create_child(const char* path, char* const arguments[])
455 if (pipe(gravedigger_pipe) < 0) {
456 perror("allocating pipe for gravedigger failed");
460 if (pipe(stdin_pipe) < 0) {
461 perror("allocating pipe for child input redirect failed");
465 if (pipe(stdout_pipe) < 0) {
466 perror("allocating pipe for child output redirect failed");
470 if (pipe(stderr_pipe) < 0) {
471 perror("allocating pipe for child output redirect failed");
478 sprintf(ld_path, "/usr/lib/dbus-tests/lib/libdbuspolicy-tests/:");
480 if (dup2(stdin_pipe[PIPE_READ], STDIN_FILENO) == -1) {
481 perror("redirecting stdin failed");
486 if (dup2(stdout_pipe[PIPE_WRITE], STDOUT_FILENO) == -1) {
487 perror("redirecting stdout failed");
492 if (dup2(stderr_pipe[PIPE_WRITE], STDERR_FILENO) == -1) {
493 perror("redirecting stderr failed");
497 // all these are for use by parent only
498 close(stdin_pipe[PIPE_READ]);
499 close(stdin_pipe[PIPE_WRITE]);
500 close(stdout_pipe[PIPE_READ]);
501 close(stdout_pipe[PIPE_WRITE]);
502 close(stderr_pipe[PIPE_READ]);
503 close(stderr_pipe[PIPE_WRITE]);
504 close(gravedigger_pipe[PIPE_READ]);
506 char* ld_path_b = getenv("LD_LIBRARY_PATH");
507 if (ld_path_b != NULL)
508 memcpy(ld_path + strlen(ld_path), ld_path_b, strlen(ld_path_b)+1);
509 setenv("LD_LIBRARY_PATH", ld_path, 1);
510 // run child process image
511 nResult = execv(path, arguments);
513 // if we get here at all, an error occurred, but we are in the child
514 // process, so just exit
515 perror("exec of the child process failed");
517 } else if (child > 0) {
518 // parent continues here
520 // close unused file descriptors, these are for child only
521 close(stdin_pipe[PIPE_READ]);
522 close(stdout_pipe[PIPE_WRITE]);
523 close(stderr_pipe[PIPE_WRITE]);
524 close(gravedigger_pipe[PIPE_WRITE]);
526 // failed to create child
533 close(stderr_pipe[PIPE_READ]);
534 close(stderr_pipe[PIPE_WRITE]);
536 close(stdout_pipe[PIPE_READ]);
537 close(stdout_pipe[PIPE_WRITE]);
539 close(stdin_pipe[PIPE_READ]);
540 close(stdin_pipe[PIPE_WRITE]);
545 static void run_test(const struct binary* b, const char* test_name)
549 char test_id[MAX_COMMENT];
556 arg = b->prepare_args(b, test_name);
560 add_test_result(get_test_id(test_id, b, test_name), "ERROR", "Cannot init test", 0);
564 res = create_child(b->path, arg);
566 parse_output_with_timeout(b, res, test_name);
568 add_test_result(get_test_id(test_id, b, test_name), "ERROR", "Cannot start test", 0);
574 static void parse_run_test(const char* tc) {
576 for (i = 0;i < sizeof(tests)/sizeof(struct binary); i++) {
577 int len = strlen(tests[i].name);
578 if (strncmp(tc, tests[i].name, len) == 0) {
579 if (tc[len] == '*' || tc[len] == '\0')
580 run_test(&tests[i], "");
582 run_test(&tests[i], tc + len);
587 static int parse_option(int argc, char* argv[])
591 while ((ch = getopt_long(argc, argv, "lr:d:", long_options, NULL)) != -1) {
597 if (c >= MAX_TC_NUM - 1) //NULL at the end
601 requested_tc[c++] = optarg;
612 void add_test_result(const char* test_id, const char* result, const char* comment, int res)
614 printf("%s;%s;%s\n", test_id, result, comment);
618 int main(int argc, char* argv[])
621 signal(SIGPIPE, SIG_IGN);
622 if (parse_option(argc, argv))
625 if (!requested_tc[0]) {
626 for (i = 0;i < sizeof(tests)/sizeof(struct binary); i++)
627 run_test(&tests[i], "");
630 while(requested_tc[i]) {
631 parse_run_test(requested_tc[i]);