litest-main.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /*
  2. * Copyright © 2013 Red Hat, Inc.
  3. * Copyright © 2013 Marcin Slusarz <marcin.slusarz@gmail.com>
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a
  6. * copy of this software and associated documentation files (the "Software"),
  7. * to deal in the Software without restriction, including without limitation
  8. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  9. * and/or sell copies of the Software, and to permit persons to whom the
  10. * Software is furnished to do so, subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice (including the next
  13. * paragraph) shall be included in all copies or substantial portions of the
  14. * Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  22. * DEALINGS IN THE SOFTWARE.
  23. */
  24. #include "config.h"
  25. #include <dirent.h>
  26. #include <errno.h>
  27. #include <fcntl.h>
  28. #include <fnmatch.h>
  29. #include <getopt.h>
  30. #include <libudev.h>
  31. #include <poll.h>
  32. #include <signal.h>
  33. #include <stdarg.h>
  34. #include <stdint.h>
  35. #include <stdio.h>
  36. #include <stdlib.h>
  37. #include <sys/ptrace.h>
  38. #include <sys/resource.h>
  39. #include <sys/stat.h>
  40. #include <sys/sysinfo.h>
  41. #include <sys/timerfd.h>
  42. #include <sys/types.h>
  43. #include <sys/wait.h>
  44. #include <time.h>
  45. #include <unistd.h>
  46. #include "linux/input.h"
  47. #ifdef HAVE_LIBSYSTEMD
  48. #include <systemd/sd-bus.h>
  49. #endif
  50. #ifdef __FreeBSD__
  51. #include <termios.h>
  52. #endif
  53. #include <valgrind/valgrind.h>
  54. #include "util-backtrace.h"
  55. #include "util-files.h"
  56. #include "util-libinput.h"
  57. #include "builddir.h"
  58. #include "libinput-util.h"
  59. #include "litest-int.h"
  60. #include "litest-runner.h"
  61. #include "litest.h"
  62. #include "quirks.h"
  63. static struct list all_test_suites = LIST_INIT(all_test_suites); /* struct suite */
  64. static int jobs;
  65. extern bool use_colors;
  66. extern bool in_debugger;
  67. extern bool verbose;
  68. extern bool run_deviceless;
  69. extern struct suite *current_suite;
  70. static bool
  71. is_debugger_attached(void)
  72. {
  73. int status;
  74. bool rc;
  75. int pid = fork();
  76. if (pid == -1)
  77. return 0;
  78. if (pid == 0) {
  79. int ppid = getppid();
  80. if (ptrace(PTRACE_ATTACH, ppid, NULL, 0) == 0) {
  81. waitpid(ppid, NULL, 0);
  82. ptrace(PTRACE_CONT, ppid, NULL, 0);
  83. ptrace(PTRACE_DETACH, ppid, NULL, 0);
  84. rc = false;
  85. } else {
  86. rc = true;
  87. }
  88. _exit(rc);
  89. } else {
  90. waitpid(pid, &status, 0);
  91. rc = WEXITSTATUS(status);
  92. }
  93. return !!rc;
  94. }
  95. static void
  96. litest_list_tests(struct list *tests)
  97. {
  98. struct suite *s;
  99. const char *last_test_name = "<invalid>";
  100. const char *last_dev_name = "<invalid>";
  101. printf("groups:\n");
  102. list_for_each(s, tests, node) {
  103. struct test *t;
  104. printf(" - group: \"%s\"\n", s->name);
  105. printf(" tests:\n");
  106. list_for_each(t, &s->tests, node) {
  107. bool same_test = streq(last_test_name, t->name);
  108. bool same_dev = streq(last_dev_name, t->devname);
  109. if (!same_test) {
  110. printf(" - name: \"%s\"\n", t->name);
  111. printf(" devices:\n");
  112. }
  113. if (!same_test || !same_dev) {
  114. last_test_name = t->name;
  115. last_dev_name = t->devname;
  116. printf(" - name: \"%s\"\n", t->devname);
  117. }
  118. }
  119. }
  120. }
  121. extern const struct test_device __start_test_device_section, __stop_test_device_section;
  122. static void
  123. litest_init_test_devices(void)
  124. {
  125. const struct test_device *t;
  126. const struct test_device *start = &__start_test_device_section;
  127. const struct test_device *stop = &__stop_test_device_section;
  128. for (t = start; t < stop; t++)
  129. litest_add_test_device(
  130. &t->device->node); /* NOLINT(clang-analyzer-security.ArrayBound)
  131. */
  132. }
  133. extern const struct test_collection __start_test_collection_section,
  134. __stop_test_collection_section;
  135. static void
  136. setup_tests(void)
  137. {
  138. /* Iterate through linker-provided section boundaries.
  139. * These symbols mark the start and end of the test_collection_section. */
  140. const struct test_collection *start = &__start_test_collection_section;
  141. const struct test_collection *stop = &__stop_test_collection_section;
  142. const struct test_collection *c;
  143. for (c = start; c < stop;
  144. c++) { /* NOLINT(clang-analyzer-security.ArrayBound) */
  145. struct suite *s;
  146. s = zalloc(sizeof(*s));
  147. s->name = safe_strdup(
  148. c->name); /* NOLINT(clang-analyzer-security.ArrayBound) */
  149. list_init(&s->tests);
  150. list_append(&all_test_suites, &s->node);
  151. current_suite = s;
  152. c->setup();
  153. current_suite = NULL;
  154. }
  155. }
  156. static int
  157. check_device_access(void)
  158. {
  159. if (getuid() != 0) {
  160. fprintf(stderr,
  161. "%s must be run as root.\n",
  162. program_invocation_short_name);
  163. return 77;
  164. }
  165. if (access("/dev/uinput", F_OK) == -1 &&
  166. access("/dev/input/uinput", F_OK) == -1) {
  167. fprintf(stderr, "uinput device is missing, skipping tests.\n");
  168. return 77;
  169. }
  170. return 0;
  171. }
  172. static void
  173. litest_free_test_list(struct list *tests)
  174. {
  175. struct suite *s;
  176. list_for_each_safe(s, tests, node) {
  177. struct test *t;
  178. list_for_each_safe(t, &s->tests, node) {
  179. litest_test_parameters_unref(t->params);
  180. free(t->name);
  181. free(t->devname);
  182. list_remove(&t->node);
  183. free(t);
  184. }
  185. list_remove(&s->node);
  186. free(s->name);
  187. free(s);
  188. }
  189. }
  190. int
  191. main(int argc, char **argv)
  192. {
  193. enum litest_mode mode;
  194. int rc;
  195. const char *meson_testthreads;
  196. use_colors = getenv("FORCE_COLOR") || isatty(STDERR_FILENO);
  197. if (getenv("NO_COLOR"))
  198. use_colors = false;
  199. in_debugger = is_debugger_attached();
  200. if (in_debugger) {
  201. jobs = 0;
  202. } else if ((meson_testthreads = getenv("MESON_TESTTHREADS")) == NULL ||
  203. !safe_atoi(meson_testthreads, &jobs)) {
  204. jobs = get_nprocs();
  205. if (!RUNNING_ON_VALGRIND)
  206. jobs *= 2;
  207. }
  208. if (getenv("LITEST_VERBOSE"))
  209. verbose = true;
  210. mode = litest_parse_argv(argc, argv, &jobs);
  211. if (mode == LITEST_MODE_ERROR)
  212. return EXIT_FAILURE;
  213. litest_init_test_devices();
  214. setup_tests();
  215. if (list_empty(&all_test_suites)) {
  216. fprintf(stderr, "Error: filters are too strict, no tests to run.\n");
  217. return EXIT_FAILURE;
  218. }
  219. if (mode == LITEST_MODE_LIST) {
  220. litest_list_tests(&all_test_suites);
  221. return EXIT_SUCCESS;
  222. }
  223. if (!run_deviceless && (rc = check_device_access()) != 0)
  224. return rc;
  225. enum litest_runner_result result = litest_run(&all_test_suites, jobs);
  226. litest_free_test_list(&all_test_suites);
  227. switch (result) {
  228. case LITEST_PASS:
  229. return EXIT_SUCCESS;
  230. case LITEST_SKIP:
  231. return 77;
  232. default:
  233. return result;
  234. }
  235. }