| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- /*
- * Copyright © 2013 Red Hat, Inc.
- * Copyright © 2013 Marcin Slusarz <marcin.slusarz@gmail.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
- #include "config.h"
- #include <dirent.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <fnmatch.h>
- #include <getopt.h>
- #include <libudev.h>
- #include <poll.h>
- #include <signal.h>
- #include <stdarg.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/ptrace.h>
- #include <sys/resource.h>
- #include <sys/stat.h>
- #include <sys/sysinfo.h>
- #include <sys/timerfd.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <time.h>
- #include <unistd.h>
- #include "linux/input.h"
- #ifdef HAVE_LIBSYSTEMD
- #include <systemd/sd-bus.h>
- #endif
- #ifdef __FreeBSD__
- #include <termios.h>
- #endif
- #include <valgrind/valgrind.h>
- #include "util-backtrace.h"
- #include "util-files.h"
- #include "util-libinput.h"
- #include "builddir.h"
- #include "libinput-util.h"
- #include "litest-int.h"
- #include "litest-runner.h"
- #include "litest.h"
- #include "quirks.h"
- static struct list all_test_suites = LIST_INIT(all_test_suites); /* struct suite */
- static int jobs;
- extern bool use_colors;
- extern bool in_debugger;
- extern bool verbose;
- extern bool run_deviceless;
- extern struct suite *current_suite;
- static bool
- is_debugger_attached(void)
- {
- int status;
- bool rc;
- int pid = fork();
- if (pid == -1)
- return 0;
- if (pid == 0) {
- int ppid = getppid();
- if (ptrace(PTRACE_ATTACH, ppid, NULL, 0) == 0) {
- waitpid(ppid, NULL, 0);
- ptrace(PTRACE_CONT, ppid, NULL, 0);
- ptrace(PTRACE_DETACH, ppid, NULL, 0);
- rc = false;
- } else {
- rc = true;
- }
- _exit(rc);
- } else {
- waitpid(pid, &status, 0);
- rc = WEXITSTATUS(status);
- }
- return !!rc;
- }
- static void
- litest_list_tests(struct list *tests)
- {
- struct suite *s;
- const char *last_test_name = "<invalid>";
- const char *last_dev_name = "<invalid>";
- printf("groups:\n");
- list_for_each(s, tests, node) {
- struct test *t;
- printf(" - group: \"%s\"\n", s->name);
- printf(" tests:\n");
- list_for_each(t, &s->tests, node) {
- bool same_test = streq(last_test_name, t->name);
- bool same_dev = streq(last_dev_name, t->devname);
- if (!same_test) {
- printf(" - name: \"%s\"\n", t->name);
- printf(" devices:\n");
- }
- if (!same_test || !same_dev) {
- last_test_name = t->name;
- last_dev_name = t->devname;
- printf(" - name: \"%s\"\n", t->devname);
- }
- }
- }
- }
- extern const struct test_device __start_test_device_section, __stop_test_device_section;
- static void
- litest_init_test_devices(void)
- {
- const struct test_device *t;
- const struct test_device *start = &__start_test_device_section;
- const struct test_device *stop = &__stop_test_device_section;
- for (t = start; t < stop; t++)
- litest_add_test_device(
- &t->device->node); /* NOLINT(clang-analyzer-security.ArrayBound)
- */
- }
- extern const struct test_collection __start_test_collection_section,
- __stop_test_collection_section;
- static void
- setup_tests(void)
- {
- /* Iterate through linker-provided section boundaries.
- * These symbols mark the start and end of the test_collection_section. */
- const struct test_collection *start = &__start_test_collection_section;
- const struct test_collection *stop = &__stop_test_collection_section;
- const struct test_collection *c;
- for (c = start; c < stop;
- c++) { /* NOLINT(clang-analyzer-security.ArrayBound) */
- struct suite *s;
- s = zalloc(sizeof(*s));
- s->name = safe_strdup(
- c->name); /* NOLINT(clang-analyzer-security.ArrayBound) */
- list_init(&s->tests);
- list_append(&all_test_suites, &s->node);
- current_suite = s;
- c->setup();
- current_suite = NULL;
- }
- }
- static int
- check_device_access(void)
- {
- if (getuid() != 0) {
- fprintf(stderr,
- "%s must be run as root.\n",
- program_invocation_short_name);
- return 77;
- }
- if (access("/dev/uinput", F_OK) == -1 &&
- access("/dev/input/uinput", F_OK) == -1) {
- fprintf(stderr, "uinput device is missing, skipping tests.\n");
- return 77;
- }
- return 0;
- }
- static void
- litest_free_test_list(struct list *tests)
- {
- struct suite *s;
- list_for_each_safe(s, tests, node) {
- struct test *t;
- list_for_each_safe(t, &s->tests, node) {
- litest_test_parameters_unref(t->params);
- free(t->name);
- free(t->devname);
- list_remove(&t->node);
- free(t);
- }
- list_remove(&s->node);
- free(s->name);
- free(s);
- }
- }
- int
- main(int argc, char **argv)
- {
- enum litest_mode mode;
- int rc;
- const char *meson_testthreads;
- use_colors = getenv("FORCE_COLOR") || isatty(STDERR_FILENO);
- if (getenv("NO_COLOR"))
- use_colors = false;
- in_debugger = is_debugger_attached();
- if (in_debugger) {
- jobs = 0;
- } else if ((meson_testthreads = getenv("MESON_TESTTHREADS")) == NULL ||
- !safe_atoi(meson_testthreads, &jobs)) {
- jobs = get_nprocs();
- if (!RUNNING_ON_VALGRIND)
- jobs *= 2;
- }
- if (getenv("LITEST_VERBOSE"))
- verbose = true;
- mode = litest_parse_argv(argc, argv, &jobs);
- if (mode == LITEST_MODE_ERROR)
- return EXIT_FAILURE;
- litest_init_test_devices();
- setup_tests();
- if (list_empty(&all_test_suites)) {
- fprintf(stderr, "Error: filters are too strict, no tests to run.\n");
- return EXIT_FAILURE;
- }
- if (mode == LITEST_MODE_LIST) {
- litest_list_tests(&all_test_suites);
- return EXIT_SUCCESS;
- }
- if (!run_deviceless && (rc = check_device_access()) != 0)
- return rc;
- enum litest_runner_result result = litest_run(&all_test_suites, jobs);
- litest_free_test_list(&all_test_suites);
- switch (result) {
- case LITEST_PASS:
- return EXIT_SUCCESS;
- case LITEST_SKIP:
- return 77;
- default:
- return result;
- }
- }
|