/* * Copyright © 2012 Collabora, Ltd. * * 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 #include #include #include #include #include #include #include "test-runner.h" #include "wayland-util.h" #include "wayland-private.h" #include "test-compositor.h" extern int fd_leak_check_enabled; TEST(empty) { } TEST(exit_success) { exit(EXIT_SUCCESS); } FAIL_TEST(exit_failure) { exit(EXIT_FAILURE); } FAIL_TEST(fail_abort) { test_disable_coredumps(); abort(); } FAIL_TEST(fail_wl_abort) { test_disable_coredumps(); wl_abort("Abort the program\n"); } FAIL_TEST(fail_kill) { kill(getpid(), SIGTERM); } FAIL_TEST(fail_segv) { char * volatile *null = 0; test_disable_coredumps(); *null = "Goodbye, world"; } FAIL_TEST(sanity_assert) { test_disable_coredumps(); /* must fail */ assert(0); } FAIL_TEST(sanity_fd_leak) { int fd[2]; assert(fd_leak_check_enabled); /* leak 2 file descriptors */ if (pipe(fd) < 0) exit(EXIT_SUCCESS); /* failed to fail */ test_disable_coredumps(); } FAIL_TEST(sanity_fd_leak_exec) { int fd[2]; int nr_fds = count_open_fds(); /* leak 2 file descriptors */ if (pipe(fd) < 0) exit(EXIT_SUCCESS); /* failed to fail */ test_disable_coredumps(); exec_fd_leak_check(nr_fds); } TEST(sanity_fd_exec) { int fd[2]; int nr_fds = count_open_fds(); /* create 2 file descriptors, that should pass over exec */ assert(pipe(fd) >= 0); exec_fd_leak_check(nr_fds + 2); } static void sanity_fd_no_leak(void) { int fd[2]; assert(fd_leak_check_enabled); /* leak 2 file descriptors */ if (pipe(fd) < 0) exit(EXIT_SUCCESS); /* failed to fail */ close(fd[0]); close(fd[1]); } static void sanity_client_no_leak(void) { struct wl_display *display = wl_display_connect(NULL); assert(display); wl_display_disconnect(display); } TEST(tc_client_no_fd_leaks) { struct display *d = display_create(); /* Client which does not consume the WAYLAND_DISPLAY socket. */ client_create_noarg(d, sanity_fd_no_leak); display_run(d); /* Client which does consume the WAYLAND_DISPLAY socket. */ client_create_noarg(d, sanity_client_no_leak); display_run(d); display_destroy(d); } FAIL_TEST(tc_client_fd_leaks) { struct display *d = display_create(); client_create_noarg(d, sanity_fd_leak); display_run(d); test_disable_coredumps(); display_destroy(d); } FAIL_TEST(tc_client_fd_leaks_exec) { struct display *d = display_create(); client_create_noarg(d, sanity_fd_leak_exec); display_run(d); test_disable_coredumps(); display_destroy(d); } static char * map_file(int fd, size_t *len) { char *data; *len = lseek(fd, 0, SEEK_END); data = mmap(0, *len, PROT_READ, MAP_PRIVATE, fd, 0); assert(data != MAP_FAILED && "Failed to mmap file"); return data; } static void sanity_client_log(void) { char *log; size_t log_len; char *wayland_socket = strdup(getenv("WAYLAND_SOCKET")); char *xdg_runtime_dir = strdup(getenv("XDG_RUNTIME_DIR")); unsetenv("WAYLAND_SOCKET"); unsetenv("XDG_RUNTIME_DIR"); /* Try to connect to the default wayland display, which should fail since * we have neither WAYLAND_SOCKET nor XDG_RUNTIME_DIR. */ assert(!wl_display_connect(NULL)); /* Check that the client log contains some mention of XDG_RUNTIME_DIR. */ log = map_file(client_log_fd, &log_len); assert(strstr(log, "XDG_RUNTIME_DIR")); munmap(log, log_len); /* Reset the environment variables we unset for the test. The test harness * leak checker cares about the value of WAYLAND_SOCKET during teardown for * correct fd accounting. */ setenv("XDG_RUNTIME_DIR", xdg_runtime_dir, 0); setenv("WAYLAND_SOCKET", wayland_socket, 0); free(xdg_runtime_dir); free(wayland_socket); } TEST(tc_client_log) { struct display *d = display_create(); struct client_info *ci; char *log; size_t log_len; ci = client_create_noarg(d, sanity_client_log); display_run(d); /* Check that the client log contains some mention of XDG_RUNTIME_DIR. */ log = map_file(ci->log_fd, &log_len); assert(strstr(log, "XDG_RUNTIME_DIR")); munmap(log, log_len); display_destroy(d); } FAIL_TEST(timeout_tst) { test_set_timeout(1); test_disable_coredumps(); /* test should reach timeout */ test_sleep(2); } TEST(timeout2_tst) { /* the test should end before reaching timeout, * thus it should pass */ test_set_timeout(1); /* 200 000 microsec = 0.2 sec */ test_usleep(200000); } FAIL_TEST(timeout_reset_tst) { test_set_timeout(5); test_set_timeout(10); test_set_timeout(1); test_disable_coredumps(); /* test should fail on timeout */ test_sleep(2); } TEST(timeout_turnoff) { test_set_timeout(1); test_set_timeout(0); test_usleep(2); } /* test timeouts with test-compositor */ FAIL_TEST(tc_timeout_tst) { struct display *d = display_create(); client_create_noarg(d, timeout_tst); display_run(d); test_disable_coredumps(); display_destroy(d); } FAIL_TEST(tc_timeout2_tst) { struct display *d = display_create(); client_create_noarg(d, timeout_reset_tst); display_run(d); test_disable_coredumps(); display_destroy(d); } TEST(tc_timeout3_tst) { struct display *d = display_create(); client_create_noarg(d, timeout2_tst); display_run(d); client_create_noarg(d, timeout_turnoff); display_run(d); display_destroy(d); }