tests: Capture the test client log
authorAlexandros Frantzis <alexandros.frantzis@collabora.com>
Thu, 1 Dec 2022 18:02:43 +0000 (20:02 +0200)
committerSimon Ser <contact@emersion.fr>
Tue, 28 Feb 2023 11:22:04 +0000 (11:22 +0000)
Capture the test client log to a temporary fd, so that is accessible by both
the test server process and the test client process.

Signed-off-by: Alexandros Frantzis <alexandros.frantzis@collabora.com>
tests/sanity-test.c
tests/test-compositor.c
tests/test-compositor.h

index 1a33c12..e614cfb 100644 (file)
@@ -25,7 +25,9 @@
 
 #include <stdlib.h>
 #include <assert.h>
+#include <string.h>
 #include <sys/types.h>
+#include <sys/mman.h>
 #include <signal.h>
 #include <unistd.h>
 
@@ -181,6 +183,65 @@ FAIL_TEST(tc_client_fd_leaks_exec)
        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);
index 103ddc8..587bc2b 100644 (file)
@@ -40,6 +40,8 @@
 #include "test-runner.h"
 #include "test-compositor.h"
 
+int client_log_fd = -1;
+
 /* --- Protocol --- */
 struct test_compositor;
 
@@ -156,8 +158,20 @@ client_destroyed(struct wl_listener *listener, void *data)
 }
 
 static void
+client_log_handler(const char *fmt, va_list arg)
+{
+       va_list arg_copy;
+
+       va_copy(arg_copy, arg);
+       vdprintf(client_log_fd, fmt, arg_copy);
+       va_end(arg_copy);
+
+       vfprintf(stderr, fmt, arg);
+}
+
+static void
 run_client(void (*client_main)(void *data), void *data,
-          int wayland_sock, int client_pipe)
+          int wayland_sock, int client_pipe, int log_fd)
 {
        char s[8];
        int cur_fds;
@@ -173,6 +187,10 @@ run_client(void (*client_main)(void *data), void *data,
        snprintf(s, sizeof s, "%d", wayland_sock);
        setenv("WAYLAND_SOCKET", s, 0);
 
+       /* Capture the log to the specified file descriptor. */
+       client_log_fd = log_fd;
+       wl_log_set_handler_client(client_log_handler);
+
        cur_fds = count_open_fds();
 
        client_main(data);
@@ -188,6 +206,18 @@ run_client(void (*client_main)(void *data), void *data,
        check_fd_leaks(cur_fds);
 }
 
+static int
+create_log_fd(void)
+{
+       char logname[] = "/tmp/wayland-tests-log-XXXXXX";
+       int log_fd = mkstemp(logname);
+
+       if (log_fd >= 0)
+               unlink(logname);
+
+       return log_fd;
+}
+
 static struct client_info *
 display_create_client(struct display *d,
                      void (*client_main)(void *data),
@@ -199,11 +229,15 @@ display_create_client(struct display *d,
        pid_t pid;
        int can_continue = 0;
        struct client_info *cl;
+       int log_fd;
 
        assert(pipe(pipe_cli) == 0 && "Failed creating pipe");
        assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sock_wayl) == 0
               && "Failed creating socket pair");
 
+       log_fd = create_log_fd();
+       assert(log_fd >= 0 && "Failed to create log fd");
+
        pid = fork();
        assert(pid != -1 && "Fork failed");
 
@@ -211,10 +245,11 @@ display_create_client(struct display *d,
                close(sock_wayl[1]);
                close(pipe_cli[1]);
 
-               run_client(client_main, data, sock_wayl[0], pipe_cli[0]);
+               run_client(client_main, data, sock_wayl[0], pipe_cli[0], log_fd);
 
                close(sock_wayl[0]);
                close(pipe_cli[0]);
+               close(log_fd);
 
                exit(0);
        }
@@ -231,6 +266,7 @@ display_create_client(struct display *d,
        cl->name = name;
        cl->pid = pid;
        cl->pipe = pipe_cli[1];
+       cl->log_fd = log_fd;
        cl->destroy_listener.notify = &client_destroyed;
 
        cl->wl_client = wl_client_create(d->wl_display, sock_wayl[1]);
@@ -407,6 +443,7 @@ display_destroy(struct display *d)
                }
 
                close(cl->pipe);
+               close(cl->log_fd);
                free(cl);
        }
 
index 7b350fe..b681b09 100644 (file)
@@ -43,6 +43,7 @@ struct client_info {
 
        struct wl_list link;
        void *data; /* for arbitrary use */
+       int log_fd;
 };
 
 struct display {
@@ -106,6 +107,9 @@ void display_post_resume_events(struct display *d);
  * it then reruns the display. */
 void display_resume(struct display *d);
 
+/* The file descriptor containing the client log. This is only valid in the
+ * test client processes. */
+extern int client_log_fd;
 
 struct client_info *client_create_with_name(struct display *d,
                                            void (*client_main)(void *data),