Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright (c) 2014 Red Hat, Inc.
      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 
     26 #include <assert.h>
     27 #include <errno.h>
     28 #include <stdio.h>
     29 #include <string.h>
     30 #include <stdlib.h>
     31 #include <stdint.h>
     32 #include <unistd.h>
     33 #include <sys/time.h>
     34 #include <sys/socket.h>
     35 #include <sys/wait.h>
     36 #include <signal.h>
     37 
     38 #define WL_HIDE_DEPRECATED
     39 
     40 #include "test-runner.h"
     41 #include "test-compositor.h"
     42 
     43 /* --- Protocol --- */
     44 struct test_compositor;
     45 
     46 static const struct wl_message tc_requests[] = {
     47 	/* this request serves as a barrier for synchronizing*/
     48 	{ "stop_display", "u", NULL }
     49 };
     50 
     51 static const struct wl_message tc_events[] = {
     52 	{ "display_resumed", "", NULL }
     53 };
     54 
     55 const struct wl_interface test_compositor_interface = {
     56 	"test", 1,
     57 	1, tc_requests,
     58 	1, tc_events
     59 };
     60 
     61 struct test_compositor_interface {
     62 	void (*stop_display)(struct wl_client *client,
     63 			     struct wl_resource *resource,
     64 			     uint32_t num);
     65 };
     66 
     67 struct test_compositor_listener {
     68 	void (*display_resumed)(void *data, struct test_compositor *tc);
     69 
     70 };
     71 
     72 enum {
     73 	STOP_DISPLAY = 0
     74 };
     75 
     76 enum {
     77 	DISPLAY_RESUMED = 0
     78 };
     79 
     80 /* Since tests can run parallelly, we need unique socket names
     81  * for each test, otherwise the test can fail on wl_display_add_socket. */
     82 static const char *
     83 get_socket_name(void)
     84 {
     85 	struct timeval tv;
     86 	static char retval[64];
     87 
     88 	gettimeofday(&tv, NULL);
     89 	snprintf(retval, sizeof retval, "wayland-test-%d-%ld%ld",
     90 		 getpid(), tv.tv_sec, tv.tv_usec);
     91 
     92 	return retval;
     93 }
     94 
     95 static void
     96 handle_client_destroy(void *data)
     97 {
     98 	struct client_info *ci = data;
     99 	struct display *d;
    100 	siginfo_t status;
    101 
    102 	d = ci->display;
    103 
    104 	assert(waitid(P_PID, ci->pid, &status, WEXITED) != -1);
    105 
    106 	switch (status.si_code) {
    107 	case CLD_KILLED:
    108 	case CLD_DUMPED:
    109 		fprintf(stderr, "Client '%s' was killed by signal %d\n",
    110 			ci->name, status.si_status);
    111 		ci->exit_code = status.si_status;
    112 		break;
    113 	case CLD_EXITED:
    114 		if (status.si_status != EXIT_SUCCESS)
    115 			fprintf(stderr, "Client '%s' exited with code %d\n",
    116 				ci->name, status.si_status);
    117 
    118 		ci->exit_code = status.si_status;
    119 		break;
    120 	}
    121 
    122 	++d->clients_terminated_no;
    123 	if (d->clients_no == d->clients_terminated_no) {
    124 		wl_display_terminate(d->wl_display);
    125 	}
    126 
    127 	/* the clients are not removed from the list, because
    128 	 * at the end of the test we check the exit codes of all
    129 	 * clients. In the case that the test would go through
    130 	 * the clients list manually, zero out the wl_client as a sign
    131 	 * that the client is not running anymore */
    132 }
    133 
    134 /**
    135  * Check client's state and terminate display when all clients exited
    136  */
    137 static void
    138 client_destroyed(struct wl_listener *listener, void *data)
    139 {
    140 	struct client_info *ci;
    141 	struct display *d;
    142 	struct wl_event_loop *loop;
    143 
    144 	/* Wait for client in an idle handler to avoid blocking the actual
    145 	 * client destruction (fd close etc. */
    146 	ci = wl_container_of(listener, ci, destroy_listener);
    147 	d = ci->display;
    148 	loop = wl_display_get_event_loop(d->wl_display);
    149 	wl_event_loop_add_idle(loop, handle_client_destroy, ci);
    150 
    151 	ci->wl_client = NULL;
    152 }
    153 
    154 static void
    155 run_client(void (*client_main)(void *data), void *data,
    156 	   int wayland_sock, int client_pipe)
    157 {
    158 	char s[8];
    159 	int cur_alloc, cur_fds;
    160 	int can_continue = 0;
    161 
    162 	/* Wait until display signals that client can continue */
    163 	assert(read(client_pipe, &can_continue, sizeof(int)) == sizeof(int));
    164 
    165 	if (can_continue == 0)
    166 		abort(); /* error in parent */
    167 
    168 	/* for wl_display_connect() */
    169 	snprintf(s, sizeof s, "%d", wayland_sock);
    170 	setenv("WAYLAND_SOCKET", s, 0);
    171 
    172 	cur_alloc = get_current_alloc_num();
    173 	cur_fds = count_open_fds();
    174 
    175 	client_main(data);
    176 
    177 	/* Clients using wl_display_connect() will end up closing the socket
    178 	 * passed in through the WAYLAND_SOCKET environment variable. When
    179 	 * doing this, it clears the environment variable, so if it's been
    180 	 * unset, then we assume the client consumed the file descriptor and
    181 	 * do not count it towards leak checking. */
    182 	if (!getenv("WAYLAND_SOCKET"))
    183 		cur_fds--;
    184 
    185 	check_leaks(cur_alloc, cur_fds);
    186 }
    187 
    188 static struct client_info *
    189 display_create_client(struct display *d,
    190 		      void (*client_main)(void *data),
    191 		      void *data,
    192 		      const char *name)
    193 {
    194 	int pipe_cli[2];
    195 	int sock_wayl[2];
    196 	pid_t pid;
    197 	int can_continue = 0;
    198 	struct client_info *cl;
    199 
    200 	assert(pipe(pipe_cli) == 0 && "Failed creating pipe");
    201 	assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sock_wayl) == 0
    202 	       && "Failed creating socket pair");
    203 
    204 	pid = fork();
    205 	assert(pid != -1 && "Fork failed");
    206 
    207 	if (pid == 0) {
    208 		close(sock_wayl[1]);
    209 		close(pipe_cli[1]);
    210 
    211 		run_client(client_main, data, sock_wayl[0], pipe_cli[0]);
    212 
    213 		close(sock_wayl[0]);
    214 		close(pipe_cli[0]);
    215 
    216 		exit(0);
    217 	}
    218 
    219 	close(sock_wayl[0]);
    220 	close(pipe_cli[0]);
    221 
    222 	cl = calloc(1, sizeof(struct client_info));
    223 	assert(cl && "Out of memory");
    224 
    225 	wl_list_insert(&d->clients, &cl->link);
    226 
    227 	cl->display = d;
    228 	cl->name = name;
    229 	cl->pid = pid;
    230 	cl->pipe = pipe_cli[1];
    231 	cl->destroy_listener.notify = &client_destroyed;
    232 
    233 	cl->wl_client = wl_client_create(d->wl_display, sock_wayl[1]);
    234 	if (!cl->wl_client) {
    235 		int ret;
    236 
    237 		/* abort the client */
    238 		ret = write(cl->pipe, &can_continue, sizeof(int));
    239 		assert(ret == sizeof(int) && "aborting the client failed");
    240 		assert(0 && "Couldn't create wayland client");
    241 	}
    242 
    243 	wl_client_add_destroy_listener(cl->wl_client,
    244 				       &cl->destroy_listener);
    245 
    246 	++d->clients_no;
    247 
    248 	return cl;
    249 }
    250 
    251 struct client_info *
    252 client_create_with_name(struct display *d,
    253 			void (*client_main)(void *data), void *data,
    254 			const char *name)
    255 {
    256 	int can_continue = 1;
    257 	struct client_info *cl = display_create_client(d,
    258 						       client_main, data,
    259 						       name);
    260 
    261 	/* let the show begin! */
    262 	assert(write(cl->pipe, &can_continue, sizeof(int)) == sizeof(int));
    263 
    264 	return cl;
    265 }
    266 
    267 /* wfr = waiting for resume */
    268 struct wfr {
    269 	struct wl_resource *resource;
    270 	struct wl_list link;
    271 };
    272 
    273 static void
    274 handle_stop_display(struct wl_client *client,
    275 		    struct wl_resource *resource, uint32_t num)
    276 {
    277 	struct display *d = wl_resource_get_user_data(resource);
    278 	struct wfr *wfr;
    279 
    280 	assert(d->wfr_num < num
    281 	       && "test error: Too many clients sent stop_display request");
    282 
    283 	++d->wfr_num;
    284 
    285 	wfr = malloc(sizeof *wfr);
    286 	if (!wfr) {
    287 		wl_client_post_no_memory(client);
    288 		assert(0 && "Out of memory");
    289 	}
    290 
    291 	wfr->resource = resource;
    292 	wl_list_insert(&d->waiting_for_resume, &wfr->link);
    293 
    294 	if (d->wfr_num == num)
    295 		wl_display_terminate(d->wl_display);
    296 }
    297 
    298 static const struct test_compositor_interface tc_implementation = {
    299 	handle_stop_display
    300 };
    301 
    302 static void
    303 tc_bind(struct wl_client *client, void *data,
    304 	uint32_t ver, uint32_t id)
    305 {
    306 	struct wl_resource *res;
    307 
    308 	res = wl_resource_create(client, &test_compositor_interface, ver, id);
    309 	if (!res) {
    310 		wl_client_post_no_memory(client);
    311 		assert(0 && "Out of memory");
    312 	}
    313 
    314 	wl_resource_set_implementation(res, &tc_implementation, data, NULL);
    315 }
    316 
    317 struct display *
    318 display_create(void)
    319 {
    320 	struct display *d = NULL;
    321 	struct wl_global *g;
    322 	const char *socket_name;
    323 	int stat = 0;
    324 
    325 	d = calloc(1, sizeof *d);
    326 	assert(d && "Out of memory");
    327 
    328 	d->wl_display = wl_display_create();
    329 	assert(d->wl_display && "Creating display failed");
    330 
    331 	/* hope the path won't be longer than 108 ... */
    332 	socket_name = get_socket_name();
    333 	stat = wl_display_add_socket(d->wl_display, socket_name);
    334 	assert(stat == 0 && "Failed adding socket");
    335 
    336 	wl_list_init(&d->clients);
    337 	d->clients_no = d->clients_terminated_no = 0;
    338 
    339 	wl_list_init(&d->waiting_for_resume);
    340 	d->wfr_num = 0;
    341 
    342 	g = wl_global_create(d->wl_display, &test_compositor_interface,
    343 			     1, d, tc_bind);
    344 	assert(g && "Creating test global failed");
    345 
    346 	return d;
    347 }
    348 
    349 void
    350 display_run(struct display *d)
    351 {
    352 	assert(d->wfr_num == 0
    353 	       && "test error: Have waiting clients. Use display_resume.");
    354 	wl_display_run(d->wl_display);
    355 }
    356 
    357 void
    358 display_resume(struct display *d)
    359 {
    360 	struct wfr *wfr, *next;
    361 
    362 	assert(d->wfr_num > 0 && "test error: No clients waiting.");
    363 
    364 	wl_list_for_each_safe(wfr, next, &d->waiting_for_resume, link) {
    365 		wl_resource_post_event(wfr->resource, DISPLAY_RESUMED);
    366 		wl_list_remove(&wfr->link);
    367 		free(wfr);
    368 	}
    369 
    370 	assert(wl_list_empty(&d->waiting_for_resume));
    371 	d->wfr_num = 0;
    372 
    373 	wl_display_run(d->wl_display);
    374 }
    375 
    376 void
    377 display_destroy(struct display *d)
    378 {
    379 	struct client_info *cl, *next;
    380 	int failed = 0;
    381 
    382 	assert(d->wfr_num == 0
    383 	       && "test error: Didn't you forget to call display_resume?");
    384 
    385 	wl_list_for_each_safe(cl, next, &d->clients, link) {
    386 		assert(cl->wl_client == NULL);
    387 
    388 		if (cl->exit_code != 0) {
    389 			++failed;
    390 			fprintf(stderr, "Client '%s' failed\n", cl->name);
    391 		}
    392 
    393 		close(cl->pipe);
    394 		free(cl);
    395 	}
    396 
    397 	wl_display_destroy(d->wl_display);
    398 	free(d);
    399 
    400 	if (failed) {
    401 		fprintf(stderr, "%d child(ren) failed\n", failed);
    402 		abort();
    403 	}
    404 }
    405 
    406 /*
    407  * --- Client helper functions ---
    408  */
    409 static void
    410 handle_display_resumed(void *data, struct test_compositor *tc)
    411 {
    412 	struct client *c = data;
    413 
    414 	c->display_stopped = 0;
    415 }
    416 
    417 static const struct test_compositor_listener tc_listener = {
    418 	handle_display_resumed
    419 };
    420 
    421 static void
    422 registry_handle_globals(void *data, struct wl_registry *registry,
    423 			uint32_t id, const char *intf, uint32_t ver)
    424 {
    425 	struct client *c = data;
    426 
    427 	if (strcmp(intf, "test") != 0)
    428 		return;
    429 
    430 	c->tc = wl_registry_bind(registry, id, &test_compositor_interface, ver);
    431 	assert(c->tc && "Failed binding to registry");
    432 
    433 	wl_proxy_add_listener((struct wl_proxy *) c->tc,
    434 			      (void *) &tc_listener, c);
    435 }
    436 
    437 static const struct wl_registry_listener registry_listener =
    438 {
    439 	registry_handle_globals,
    440 	NULL
    441 };
    442 
    443 struct client *client_connect()
    444 {
    445 	struct wl_registry *reg;
    446 	struct client *c = calloc(1, sizeof *c);
    447 	assert(c && "Out of memory");
    448 
    449 	c->wl_display = wl_display_connect(NULL);
    450 	assert(c->wl_display && "Failed connecting to display");
    451 
    452 	/* create test_compositor proxy. Do it with temporary
    453 	 * registry so that client can define it's own listener later */
    454 	reg = wl_display_get_registry(c->wl_display);
    455 	assert(reg);
    456 	wl_registry_add_listener(reg, &registry_listener, c);
    457 	wl_display_roundtrip(c->wl_display);
    458 	assert(c->tc);
    459 
    460 	wl_registry_destroy(reg);
    461 
    462 	return c;
    463 }
    464 
    465 static void
    466 check_error(struct wl_display *display)
    467 {
    468 	uint32_t ec, id;
    469 	const struct wl_interface *intf;
    470 	int err;
    471 
    472 	err = wl_display_get_error(display);
    473 	/* write out message about protocol error */
    474 	if (err == EPROTO) {
    475 		ec = wl_display_get_protocol_error(display, &intf, &id);
    476 		fprintf(stderr, "Client: Got protocol error %u on interface %s"
    477 				" (object %u)\n", ec, intf->name, id);
    478 	}
    479 
    480 	if (err) {
    481 		fprintf(stderr, "Client error: %s\n", strerror(err));
    482 		abort();
    483 	}
    484 }
    485 
    486 void
    487 client_disconnect(struct client *c)
    488 {
    489 	/* check for errors */
    490 	check_error(c->wl_display);
    491 
    492 	wl_proxy_destroy((struct wl_proxy *) c->tc);
    493 	wl_display_disconnect(c->wl_display);
    494 	free(c);
    495 }
    496 
    497 /* num is number of clients that requests to stop display.
    498  * Display is stopped after it receives num STOP_DISPLAY requests */
    499 int
    500 stop_display(struct client *c, int num)
    501 {
    502 	int n = 0;
    503 
    504 	c->display_stopped = 1;
    505 	wl_proxy_marshal((struct wl_proxy *) c->tc, STOP_DISPLAY, num);
    506 
    507 	while (c->display_stopped && n >= 0) {
    508 		n = wl_display_dispatch(c->wl_display);
    509 	}
    510 
    511 	return n;
    512 }
    513