2 * This file contains standalone test-runner.
3 * This file is NOT part of GLib project.
5 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
6 * Author: Kazimierz Krosman <k.krosman@samsung.com>
10 * Permission is hereby granted, free of charge, to any person
11 * obtaining a copy of this software and associated documentation
12 * files (the "Software"), to deal in the Software without
13 * restriction, including without limitation the rights to use, copy,
14 * modify, merge, publish, distribute, sublicense, and/or sell copies
15 * of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37 #include <sys/types.h>
39 #include <sys/select.h>
43 #include <sys/select.h>
45 #include <sys/types.h>
50 #define MAX_TC_NUM 1024
51 #define MAX_BUFFER (64*1024)
52 #define MAX_COMMENT 1024
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);
96 void parse_test_state(const struct binary* b, const char* test_name, char* buffer, int state_change, int state_option);
97 void parse_one_test_one_binary(const struct binary* b, const char* test_name, char* buffer, int state_change, int state_option);
98 char** prepare_args_for_binary(const struct binary* b, const char* test_name);
100 static struct test_case test_case_desc_01[] = {
101 {"", "Checks if the library supports format of addresses described in the D-Bus specification (key/value pairs for each transport are valid)"},
105 static struct test_case test_case_desc_02[] = {
106 {"", "Test case for GNOME #662395"},
110 static struct test_case test_case_desc_03[] = {
111 {"", "Test dbus authentication methods"},
115 static struct test_case test_case_desc_04[] = {
116 {"", "Test 'lock' and 'copy' operations on GDBusMessage object"},
120 static struct test_case test_case_desc_05[] = {
121 {"", "Test 'non-socket' connections (connection via pipes and GIOStreams objects)"},
125 static struct test_case test_case_desc_06[] = {
126 {"", "Test overflowing socket buffer in producer/consumer scenario (UNIX sockets as a transport mechanism)"},
130 static struct test_case test_case_desc_07[] = {
131 {"", "Test that peer-to-peer connections work"},
135 static struct test_case test_case_desc_08[] = {
136 {"", "Test that peer-to-peer connections work (using GDBusObjectManagerServer and GDBusObjectManager objects)"},
140 /* This table is used to start binaries */
141 struct binary tests[] = {
142 /*path, name, TC_table, timeout in us, prepare_args_handler, parse_function_handler, init_handler, clean_handler*/
143 {TESTS_DIR "/gdbus-addresses", "gdbus-addresses", test_case_desc_01, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
144 {TESTS_DIR "/gdbus-connection-flush", "gdbus-connection-flush", test_case_desc_02, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
145 {TESTS_DIR "/gdbus-server-auth", "gdbus-server-auth", test_case_desc_03, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
146 {TESTS_DIR "/gdbus-message", "gdbus-message", test_case_desc_04, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
147 {TESTS_DIR "/gdbus-non-socket", "gdbus-non-socket", test_case_desc_05, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
148 {TESTS_DIR "/gdbus-overflow", "gdbus-overflow", test_case_desc_06, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
149 {TESTS_DIR "/gdbus-peer", "gdbus-peer", test_case_desc_07, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
150 {TESTS_DIR "/gdbus-peer-object-manager", "gdbus-peer-object-manager", test_case_desc_08, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
153 static char* args[3];
154 char** prepare_args_for_binary(const struct binary* b, const char* test_name)
156 args[0] = (char*)b->name;
161 void parse_one_test_one_binary(const struct binary* b, const char* test_name, char* buffer, int state_change, int state_option)
163 char test_id[MAX_COMMENT];
165 switch(state_change) {
169 buffer[state_option] = 0;
170 get_test_id(test_id, b, test_name);
171 fprintf(stderr, "[stdout][%s]%s\n",test_id, buffer);
174 buffer[state_option] = 0;
175 get_test_id(test_id, b, test_name);
176 fprintf(stderr, "[stderr][%s]%s\n",test_id, buffer);
179 get_test_id(test_id, b, test_name);
180 if (state_option == 0)
181 add_test_result(test_id, "PASS", "", 1);
182 else if (state_option == 77)
183 add_test_result(test_id, "SKIP", "", 0);
185 add_test_result(test_id, "FAIL", "", 0);
188 get_test_id(test_id, b, test_name);
189 add_test_result(test_id, "FAIL", "Finished by SIGNAL", 0);
192 get_test_id(test_id, b, test_name);
193 add_test_result(test_id, "FAIL", "Test TIMEOUT", 0);
198 static struct option long_options[] = {
199 {"list", no_argument, 0, 'l'},
200 {"run", required_argument, 0, 'r'},
201 {"description", required_argument, 0, 'd'},
205 static int stdin_pipe[2];
206 static int stdout_pipe[2];
207 static int stderr_pipe[2];
208 static int gravedigger_pipe[2];
209 static char buffer[MAX_BUFFER];
210 static const char* requested_tc[MAX_TC_NUM];
212 char* get_test_id(char* dest, const struct binary* b, const char* test_name)
214 int len = strlen(b->name);
215 memcpy(dest, b->name, len);
216 memcpy(dest + len, test_name, strlen(test_name)+1);
220 static void print_description(const char* name, const char* description)
222 printf("%s;%s\n",name, description);
225 static void print_list(const char* test_name)
228 char full_name[MAX_COMMENT];
229 for (i = 0;i < sizeof(tests)/sizeof(struct binary); i++) {
231 int l = strlen(tests[i].name);
232 memcpy(full_name, tests[i].name, l+1);
233 if (test_name && strncmp(test_name, full_name, l) != 0)
236 while (tests[i].test_cases[j].name) {
237 memcpy(full_name + l, tests[i].test_cases[j].name, strlen(tests[i].test_cases[j].name) + 1);
238 if (!test_name || strncmp(full_name, test_name, sizeof(full_name)) == 0)
239 print_description(full_name,tests[i].test_cases[j].description);
246 static void stop_binary(const struct binary* b, pid_t pid, const char* test_name, int w_res)
251 res = waitpid(pid, &status, WNOHANG);
253 res = waitpid(pid, &status, 0);
258 res = waitpid(pid, &status, WNOHANG);
259 b->parse(b, test_name, buffer, RESULT_TIMEOUT, res);
260 } else if (res < 0) {
263 res = waitpid(pid, &status, WNOHANG);
264 b->parse(b, test_name, buffer, RESULT_ERROR, res);
265 } else if (res > 0) {
266 if (WIFEXITED(status)) {
267 b->parse(b, test_name, buffer, RESULT_CODE, WEXITSTATUS(status));
268 } else if (WIFSIGNALED(status)) {
269 b->parse(b, test_name, buffer, RESULT_SIGNAL, WTERMSIG(status));
270 } else if (WIFSTOPPED(status)) {
271 b->parse(b, test_name, buffer, RESULT_SIGNAL, WSTOPSIG(status));
272 } else if (WIFCONTINUED(status)) {
274 b->parse(b, test_name, buffer, RESULT_SIGNAL, -1);
279 static void parse_output_with_timeout(const struct binary* b, pid_t pid, const char* test_name)
286 tv.tv_sec = b->timeout/(1000*1000);
287 tv.tv_usec = (b->timeout-tv.tv_sec*1000*1000);
290 if (stdout_pipe[PIPE_READ] > -1) {
291 assert(stdout_pipe[PIPE_READ] > -1);
292 assert(stdout_pipe[PIPE_READ] < 1024);
293 FD_SET(stdout_pipe[PIPE_READ], &rfds);
295 if (stderr_pipe[PIPE_READ] > -1) {
296 assert(stderr_pipe[PIPE_READ] > -1);
297 assert(stderr_pipe[PIPE_READ] < 1024);
298 FD_SET(stderr_pipe[PIPE_READ], &rfds);
300 FD_SET(gravedigger_pipe[PIPE_READ], &rfds);
302 nfds = select(FD_SETSIZE, &rfds, NULL, NULL, &tv);
304 if (errno != EINTR) {
308 } else if (nfds > 0) {
309 if (stdout_pipe[PIPE_READ] > -1 && FD_ISSET(stdout_pipe[PIPE_READ], &rfds)) {
310 res = read(stdout_pipe[PIPE_READ], buffer, MAX_BUFFER-1);
311 if (res == 0 || (res < 0 && errno != EINTR)) {
312 close (stdout_pipe[PIPE_READ]);
313 stdout_pipe[PIPE_READ] = -1;
315 } else if (res >=0) {
316 b->parse(b, test_name, buffer, NEW_STDOUT, res);
320 if (stderr_pipe[PIPE_READ] > -1 && FD_ISSET(stderr_pipe[PIPE_READ], &rfds)) {
321 res = read(stderr_pipe[PIPE_READ], buffer, MAX_BUFFER-1);
322 if (res == 0 || (res < 0 && errno != EINTR)) {
323 close (stderr_pipe[PIPE_READ]);
324 stderr_pipe[PIPE_READ] = -1;
327 b->parse(b, test_name, buffer, NEW_STDERR, res);
330 if (FD_ISSET(gravedigger_pipe[PIPE_READ], &rfds)) {
332 break; //it has ended
340 stop_binary(b, pid, test_name, w_res);
343 static int create_child(const char* path, char* const arguments[])
347 if (pipe(gravedigger_pipe) < 0) {
348 perror("allocating pipe for gravedigger failed");
352 if (pipe(stdin_pipe) < 0) {
353 perror("allocating pipe for child input redirect failed");
357 if (pipe(stdout_pipe) < 0) {
358 perror("allocating pipe for child output redirect failed");
362 if (pipe(stderr_pipe) < 0) {
363 perror("allocating pipe for child output redirect failed");
370 sprintf(ld_path, TESTS_DIR ":");
372 if (dup2(stdin_pipe[PIPE_READ], STDIN_FILENO) == -1) {
373 perror("redirecting stdin failed");
377 if (dup2(stdout_pipe[PIPE_WRITE], STDOUT_FILENO) == -1) {
378 perror("redirecting stdout failed");
382 if (dup2(stderr_pipe[PIPE_WRITE], STDERR_FILENO) == -1) {
383 perror("redirecting stderr failed");
387 close(stdin_pipe[PIPE_READ]);
388 close(stdin_pipe[PIPE_WRITE]);
389 close(stdout_pipe[PIPE_READ]);
390 close(stdout_pipe[PIPE_WRITE]);
391 close(stderr_pipe[PIPE_READ]);
392 close(stderr_pipe[PIPE_WRITE]);
393 close(gravedigger_pipe[PIPE_READ]);
395 char* ld_path_b = getenv("LD_LIBRARY_PATH");
396 if (ld_path_b != NULL)
397 memcpy(ld_path + strlen(ld_path), ld_path_b, strlen(ld_path_b)+1);
398 setenv("LD_LIBRARY_PATH", ld_path, 1);
399 setenv("G_TEST_SRCDIR", TESTS_DIR, 1);
401 // run child process image
402 nResult = execv(path, arguments);
404 // if we get here at all, an error occurred, but we are in the child
405 // process, so just exit
406 perror("exec of the child process failed");
408 } else if (child > 0) {
409 // close unused file descriptors, these are for child only
410 close(stdin_pipe[PIPE_READ]);
411 close(stdout_pipe[PIPE_WRITE]);
412 close(stderr_pipe[PIPE_WRITE]);
413 close(gravedigger_pipe[PIPE_WRITE]);
415 // failed to create child
422 close(stderr_pipe[PIPE_READ]);
423 close(stderr_pipe[PIPE_WRITE]);
425 close(stdout_pipe[PIPE_READ]);
426 close(stdout_pipe[PIPE_WRITE]);
428 close(stdin_pipe[PIPE_READ]);
429 close(stdin_pipe[PIPE_WRITE]);
434 static void run_test(const struct binary* b, const char* test_name)
438 char test_id[MAX_COMMENT];
445 arg = b->prepare_args(b, test_name);
449 add_test_result(get_test_id(test_id, b, test_name), "ERROR", "Cannot init test", 0);
453 res = create_child(b->path, arg);
455 parse_output_with_timeout(b, res, test_name);
457 add_test_result(get_test_id(test_id, b, test_name), "ERROR", "Cannot start test", 0);
463 static void parse_run_test(const char* tc) {
465 for (i = 0;i < sizeof(tests)/sizeof(struct binary); i++) {
466 int len = strlen(tests[i].name);
467 if (strncmp(tc, tests[i].name, len) == 0) {
468 if (tc[len] == '*' || tc[len] == '\0')
469 run_test(&tests[i], "");
471 run_test(&tests[i], tc + len);
476 static int parse_option(int argc, char* argv[])
480 while ((ch = getopt_long(argc, argv, "lr:d:", long_options, NULL)) != -1) {
486 if (c >= MAX_TC_NUM - 1) //NULL at the end
490 requested_tc[c++] = optarg;
501 void add_test_result(const char* test_id, const char* result, const char* comment, int res)
503 printf("%s;%s;%s\n", test_id, result, comment);
507 static void prepare_results(void)
511 int main(int argc, char* argv[])
514 signal(SIGPIPE, SIG_IGN);
515 if (parse_option(argc, argv))
520 if (!requested_tc[0]) {
521 for (i = 0;i < sizeof(tests)/sizeof(struct binary); i++)
522 run_test(&tests[i], "");
525 while(requested_tc[i]) {
526 parse_run_test(requested_tc[i]);