test-runner.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. /*
  2. * Copyright © 2012 Intel Corporation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining
  5. * a copy of this software and associated documentation files (the
  6. * "Software"), to deal in the Software without restriction, including
  7. * without limitation the rights to use, copy, modify, merge, publish,
  8. * distribute, sublicense, and/or sell copies of the Software, and to
  9. * permit persons to whom the Software is furnished to do so, subject to
  10. * the following conditions:
  11. *
  12. * The above copyright notice and this permission notice (including the
  13. * next paragraph) shall be included in all copies or substantial
  14. * portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  17. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  18. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  19. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  20. * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  21. * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  22. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  23. * SOFTWARE.
  24. */
  25. #include "../config.h"
  26. #define _GNU_SOURCE
  27. #include <unistd.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <sys/types.h>
  31. #include <sys/wait.h>
  32. #include <sys/stat.h>
  33. #include <string.h>
  34. #include <assert.h>
  35. #include <dlfcn.h>
  36. #include <errno.h>
  37. #include <limits.h>
  38. #include <signal.h>
  39. #include <sys/ptrace.h>
  40. #ifdef HAVE_SYS_PROCCTL_H
  41. #include <sys/procctl.h>
  42. #elif defined(HAVE_SYS_PRCTL_H)
  43. #include <sys/prctl.h>
  44. #ifndef PR_SET_PTRACER
  45. # define PR_SET_PTRACER 0x59616d61
  46. #endif
  47. #endif
  48. #include "test-runner.h"
  49. /* when set to 1, check if tests are not leaking opened files.
  50. * It is turned on by default. It can be turned off by
  51. * WAYLAND_TEST_NO_LEAK_CHECK environment variable. */
  52. int fd_leak_check_enabled;
  53. /* when this var is set to 0, every call to test_set_timeout() is
  54. * suppressed - handy when debugging the test. Can be set by
  55. * WAYLAND_TEST_NO_TIMEOUTS environment variable. */
  56. static int timeouts_enabled = 1;
  57. /* set to one if the output goes to the terminal */
  58. static int is_atty = 0;
  59. extern const struct test __start_test_section, __stop_test_section;
  60. static const struct test *
  61. find_test(const char *name)
  62. {
  63. const struct test *t;
  64. for (t = &__start_test_section; t < &__stop_test_section; t++)
  65. if (strcmp(t->name, name) == 0)
  66. return t;
  67. return NULL;
  68. }
  69. static void
  70. usage(const char *name, int status)
  71. {
  72. const struct test *t;
  73. fprintf(stderr, "Usage: %s [TEST]\n\n"
  74. "With no arguments, run all test. Specify test case to run\n"
  75. "only that test without forking. Available tests:\n\n",
  76. name);
  77. for (t = &__start_test_section; t < &__stop_test_section; t++)
  78. fprintf(stderr, " %s\n", t->name);
  79. fprintf(stderr, "\n");
  80. exit(status);
  81. }
  82. void
  83. test_set_timeout(unsigned int to)
  84. {
  85. int re;
  86. if (!timeouts_enabled) {
  87. fprintf(stderr, "Timeouts suppressed.\n");
  88. return;
  89. }
  90. re = alarm(to);
  91. fprintf(stderr, "Timeout was %sset", re ? "re-" : "");
  92. if (to != 0)
  93. fprintf(stderr, " to %d second%s from now.\n",
  94. to, to > 1 ? "s" : "");
  95. else
  96. fprintf(stderr, " off.\n");
  97. }
  98. static void
  99. sigalrm_handler(int signum)
  100. {
  101. fprintf(stderr, "Test timed out.\n");
  102. abort();
  103. }
  104. void
  105. check_fd_leaks(int supposed_fds)
  106. {
  107. int num_fds;
  108. if (fd_leak_check_enabled) {
  109. num_fds = count_open_fds();
  110. if (supposed_fds != num_fds) {
  111. fprintf(stderr, "fd leak detected in test. "
  112. "Opened %d files, unclosed %d\n", num_fds,
  113. num_fds - supposed_fds);
  114. abort();
  115. }
  116. } else {
  117. fprintf(stderr, "FD leak checks disabled\n");
  118. }
  119. }
  120. static void
  121. run_test(const struct test *t)
  122. {
  123. int cur_fds;
  124. struct sigaction sa;
  125. if (timeouts_enabled) {
  126. sa.sa_handler = sigalrm_handler;
  127. sa.sa_flags = 0;
  128. sigemptyset(&sa.sa_mask);
  129. assert(sigaction(SIGALRM, &sa, NULL) == 0);
  130. }
  131. //cur_alloc = get_current_alloc_num();
  132. cur_fds = count_open_fds();
  133. t->run();
  134. /* turn off timeout (if any) after test completion */
  135. if (timeouts_enabled)
  136. alarm(0);
  137. check_fd_leaks(cur_fds);
  138. exit(EXIT_SUCCESS);
  139. }
  140. #ifndef PATH_MAX
  141. #define PATH_MAX 256
  142. #endif
  143. static void
  144. set_xdg_runtime_dir(void)
  145. {
  146. char xdg_runtime_dir[PATH_MAX];
  147. const char *xrd_env;
  148. xrd_env = getenv("XDG_RUNTIME_DIR");
  149. /* if XDG_RUNTIME_DIR is not set in environ, fallback to /tmp */
  150. assert((snprintf(xdg_runtime_dir, PATH_MAX, "%s/wayland-tests-XXXXXX",
  151. (xrd_env && xrd_env[0] == '/') ? xrd_env : "/tmp") < PATH_MAX)
  152. && "test error: XDG_RUNTIME_DIR too long");
  153. assert(mkdtemp(xdg_runtime_dir) && "test error: mkdtemp failed");
  154. if (mkdir(xdg_runtime_dir, 0700) == -1)
  155. if (errno != EEXIST) {
  156. perror("Creating XDG_RUNTIME_DIR");
  157. abort();
  158. }
  159. if (setenv("XDG_RUNTIME_DIR", xdg_runtime_dir, 1) == -1) {
  160. perror("Setting XDG_RUNTIME_DIR");
  161. abort();
  162. }
  163. }
  164. static void
  165. rmdir_xdg_runtime_dir(void)
  166. {
  167. const char *xrd_env = getenv("XDG_RUNTIME_DIR");
  168. assert(xrd_env && xrd_env[0] == '/' && "No XDG_RUNTIME_DIR set");
  169. /* rmdir may fail if some test didn't do clean up */
  170. if (rmdir(xrd_env) == -1)
  171. perror("Cleaning XDG_RUNTIME_DIR");
  172. }
  173. #define RED "\033[31m"
  174. #define GREEN "\033[32m"
  175. static void
  176. stderr_set_color(const char *color)
  177. {
  178. /* use colors only when the output is connected to
  179. * the terminal */
  180. if (is_atty)
  181. fprintf(stderr, "%s", color);
  182. }
  183. static void
  184. stderr_reset_color(void)
  185. {
  186. if (is_atty)
  187. fprintf(stderr, "\033[0m");
  188. }
  189. /* this function is taken from libinput/test/litest.c
  190. * (rev 028513a0a723e97941c39)
  191. *
  192. * Returns: 1 if a debugger is confirmed present; 0 if no debugger is
  193. * present or if it can't be determined.
  194. */
  195. #if defined(HAVE_SYS_PROCCTL_H) && defined(PROC_TRACE_STATUS)
  196. static int
  197. is_debugger_attached(void)
  198. {
  199. int rc;
  200. int status;
  201. rc = procctl(P_PID, getpid(), PROC_TRACE_STATUS, &status);
  202. if (rc == -1) {
  203. perror("procctl");
  204. return 0;
  205. }
  206. /* -1=tracing disabled, 0=no debugger attached, >0=pid of debugger. */
  207. return status > 0;
  208. }
  209. #elif defined(HAVE_SYS_PRCTL_H)
  210. static int
  211. is_debugger_attached(void)
  212. {
  213. int status;
  214. int rc;
  215. pid_t pid;
  216. int pipefd[2];
  217. if (pipe(pipefd) == -1) {
  218. perror("pipe");
  219. return 0;
  220. }
  221. pid = fork();
  222. if (pid == -1) {
  223. perror("fork");
  224. close(pipefd[0]);
  225. close(pipefd[1]);
  226. return 0;
  227. } else if (pid == 0) {
  228. char buf;
  229. pid_t ppid = getppid();
  230. /* Wait until parent is ready */
  231. close(pipefd[1]); /* Close unused write end */
  232. read(pipefd[0], &buf, 1);
  233. close(pipefd[0]);
  234. if (buf == '-')
  235. _exit(1);
  236. if (ptrace(PTRACE_ATTACH, ppid, NULL, NULL) != 0)
  237. _exit(1);
  238. if (!waitpid(-1, NULL, 0))
  239. _exit(1);
  240. ptrace(PTRACE_CONT, NULL, NULL);
  241. ptrace(PTRACE_DETACH, ppid, NULL, NULL);
  242. _exit(0);
  243. } else {
  244. close(pipefd[0]);
  245. /* Enable child to ptrace the parent process */
  246. rc = prctl(PR_SET_PTRACER, pid);
  247. if (rc != 0 && errno != EINVAL) {
  248. /* An error prevents us from telling if a debugger is attached.
  249. * Instead of propagating the error, assume no debugger present.
  250. * But note the error to the log as a clue for troubleshooting.
  251. * Then flag the error state to the client by sending '-'.
  252. */
  253. perror("prctl");
  254. write(pipefd[1], "-", 1);
  255. } else {
  256. /* Signal to client that parent is ready by passing '+' */
  257. write(pipefd[1], "+", 1);
  258. }
  259. close(pipefd[1]);
  260. waitpid(pid, &status, 0);
  261. rc = WEXITSTATUS(status);
  262. }
  263. return rc;
  264. }
  265. #else
  266. static int
  267. is_debugger_attached(void)
  268. {
  269. /* 0=debugger can't be determined */
  270. return 0;
  271. }
  272. #endif
  273. int main(int argc, char *argv[])
  274. {
  275. const struct test *t;
  276. pid_t pid;
  277. int total, pass;
  278. int info;
  279. if (isatty(fileno(stderr)))
  280. is_atty = 1;
  281. if (is_debugger_attached()) {
  282. fd_leak_check_enabled = 0;
  283. timeouts_enabled = 0;
  284. } else {
  285. fd_leak_check_enabled = !getenv("WAYLAND_TEST_NO_LEAK_CHECK");
  286. timeouts_enabled = !getenv("WAYLAND_TEST_NO_TIMEOUTS");
  287. }
  288. if (argc == 2 && strcmp(argv[1], "--help") == 0)
  289. usage(argv[0], EXIT_SUCCESS);
  290. if (argc == 2) {
  291. t = find_test(argv[1]);
  292. if (t == NULL) {
  293. fprintf(stderr, "unknown test: \"%s\"\n", argv[1]);
  294. usage(argv[0], EXIT_FAILURE);
  295. }
  296. set_xdg_runtime_dir();
  297. /* run_test calls exit() */
  298. assert(atexit(rmdir_xdg_runtime_dir) == 0);
  299. run_test(t);
  300. }
  301. /* set our own XDG_RUNTIME_DIR */
  302. set_xdg_runtime_dir();
  303. pass = 0;
  304. for (t = &__start_test_section; t < &__stop_test_section; t++) {
  305. int success = 0;
  306. pid = fork();
  307. assert(pid >= 0);
  308. if (pid == 0)
  309. run_test(t); /* never returns */
  310. if (waitpid(pid, &info, 0) == -1) {
  311. stderr_set_color(RED);
  312. fprintf(stderr, "waitpid failed: %s\n",
  313. strerror(errno));
  314. stderr_reset_color();
  315. abort();
  316. }
  317. if (WIFEXITED(info)) {
  318. if (WEXITSTATUS(info) == EXIT_SUCCESS)
  319. success = !t->must_fail;
  320. else
  321. success = t->must_fail;
  322. stderr_set_color(success ? GREEN : RED);
  323. fprintf(stderr, "test \"%s\":\texit status %d",
  324. t->name, WEXITSTATUS(info));
  325. } else if (WIFSIGNALED(info)) {
  326. if (t->must_fail)
  327. success = 1;
  328. stderr_set_color(success ? GREEN : RED);
  329. fprintf(stderr, "test \"%s\":\tsignal %d",
  330. t->name, WTERMSIG(info));
  331. }
  332. if (success) {
  333. pass++;
  334. fprintf(stderr, ", pass.\n");
  335. } else
  336. fprintf(stderr, ", fail.\n");
  337. stderr_reset_color();
  338. /* print separator line */
  339. fprintf(stderr, "----------------------------------------\n");
  340. }
  341. total = &__stop_test_section - &__start_test_section;
  342. fprintf(stderr, "%d tests, %d pass, %d fail\n",
  343. total, pass, total - pass);
  344. /* cleaning */
  345. rmdir_xdg_runtime_dir();
  346. return pass == total ? EXIT_SUCCESS : EXIT_FAILURE;
  347. }