blob: d4ad369d62745950d64c6ecd4e607369f76c686f [file] [log] [blame]
Pekka Paalanenbabb3b32019-11-01 14:02:15 +02001/*
2 * Copyright 2019 Collabora, Ltd.
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 "config.h"
27
28#include <string.h>
29#include <assert.h>
Leandro Ribeiroe8a8c132020-05-06 11:21:03 -030030#include <libudev.h>
31#include <unistd.h>
32#include <sys/file.h>
Igor Matheus Andrade Torrentead41a882020-08-15 21:19:13 -030033#include <sys/types.h>
34#include <sys/stat.h>
35#include <stdarg.h>
36#include <stdlib.h>
Leandro Ribeiroe8a8c132020-05-06 11:21:03 -030037#include <errno.h>
Denys Dmytriyenkob10c0e82020-09-08 19:37:42 -040038#include <fcntl.h>
Pekka Paalanenbabb3b32019-11-01 14:02:15 +020039
40#include "shared/helpers.h"
41#include "weston-test-fixture-compositor.h"
42#include "weston.h"
Pekka Paalanen82dd6ce2019-11-01 15:39:30 +020043#include "test-config.h"
Pekka Paalanenbabb3b32019-11-01 14:02:15 +020044
Pekka Paalanen19d31dd2021-03-01 11:24:59 +020045static_assert(WET_MAIN_RET_MISSING_CAPS == RESULT_SKIP,
46 "wet_main() return value for skip is wrong");
47
Pekka Paalanenbabb3b32019-11-01 14:02:15 +020048struct prog_args {
49 int argc;
50 char **argv;
51 char **saved;
52 int alloc;
53};
54
55static void
56prog_args_init(struct prog_args *p)
57{
58 memset(p, 0, sizeof(*p));
59}
60
61static void
62prog_args_take(struct prog_args *p, char *arg)
63{
64 assert(arg);
65
66 if (p->argc == p->alloc) {
67 p->alloc += 10;
68 p->argv = realloc(p->argv, sizeof(char *) * p->alloc);
69 assert(p->argv);
70 }
71
72 p->argv[p->argc++] = arg;
73}
74
75/*
76 * The program to be executed will trample on argv, hence we need a copy to
77 * be able to free all our args.
78 */
79static void
80prog_args_save(struct prog_args *p)
81{
82 assert(p->saved == NULL);
83
84 p->saved = calloc(p->argc, sizeof(char *));
85 assert(p->saved);
86
87 memcpy(p->saved, p->argv, sizeof(char *) * p->argc);
88}
89
90static void
91prog_args_fini(struct prog_args *p)
92{
93 int i;
94
Leandro Ribeiro5911d2a2021-10-21 10:44:55 -030095 if (p->saved) {
96 for (i = 0; i < p->argc; i++)
97 free(p->saved[i]);
98 free(p->saved);
99 }
Pekka Paalanenbabb3b32019-11-01 14:02:15 +0200100
Pekka Paalanenbabb3b32019-11-01 14:02:15 +0200101 free(p->argv);
102 prog_args_init(p);
103}
104
Leandro Ribeiroe8a8c132020-05-06 11:21:03 -0300105static char *
106get_lock_path(void)
107{
108 const char *env_path, *suffix;
109 char *lock_path;
110
111 suffix = "weston-test-suite-drm-lock";
112 env_path = getenv("XDG_RUNTIME_DIR");
113 if (!env_path) {
114 fprintf(stderr, "Failed to compute lock file path. " \
115 "XDG_RUNTIME_DIR is not set.\n");
116 return NULL;
117 }
118
119 if (asprintf(&lock_path, "%s/%s", env_path, suffix) == -1)
120 return NULL;
121
122 return lock_path;
123}
124
125/*
126 * DRM-backend tests need to be run sequentially, since there can only be
127 * one user at a time with master status in a DRM KMS device. Since the
128 * test suite runs the tests in parallel, there's a mechanism to assure
129 * only one DRM-backend test is running at a time: tests of this type keep
130 * waiting until they acquire a lock (which is hold until they end).
131 *
132 * Returns -1 in failure and fd in success.
133 */
134static int
135wait_for_lock(void)
136{
137 char *lock_path;
138 int fd;
139
140 lock_path = get_lock_path();
141 if (!lock_path)
142 goto err_path;
143
144 fd = open(lock_path, O_RDWR | O_CLOEXEC | O_CREAT, 00700);
145 if (fd == -1) {
146 fprintf(stderr, "Could not open lock file %s: %s\n", lock_path, strerror(errno));
147 goto err_open;
148 }
149 fprintf(stderr, "Waiting for lock on %s...\n", lock_path);
150
151 /* The call is blocking, so we don't need a 'while'. Also, as we
152 * have a timeout for each test, this won't get stuck waiting. */
153 if (flock(fd, LOCK_EX) == -1) {
154 fprintf(stderr, "Could not lock %s: %s\n", lock_path, strerror(errno));
155 goto err_lock;
156 }
157 fprintf(stderr, "Lock %s acquired.\n", lock_path);
158 free(lock_path);
159
160 return fd;
161
162err_lock:
163 close(fd);
164err_open:
165 free(lock_path);
166err_path:
167 return -1;
168}
169
Pekka Paalanenbabb3b32019-11-01 14:02:15 +0200170/** Initialize part of compositor setup
171 *
172 * \param setup The variable to initialize.
173 * \param testset_name Value for testset_name member.
174 *
175 * \ingroup testharness_private
176 */
177void
178compositor_setup_defaults_(struct compositor_setup *setup,
179 const char *testset_name)
180{
181 *setup = (struct compositor_setup) {
Leandro Ribeiro32a5acd2020-10-19 16:06:22 -0300182 .test_quirks = (struct weston_testsuite_quirks){ },
Pekka Paalanenbabb3b32019-11-01 14:02:15 +0200183 .backend = WESTON_BACKEND_HEADLESS,
184 .renderer = RENDERER_NOOP,
185 .shell = SHELL_DESKTOP,
186 .xwayland = false,
187 .width = 320,
188 .height = 240,
Pekka Paalanen0ce5a192020-01-22 11:53:12 +0200189 .scale = 1,
190 .transform = WL_OUTPUT_TRANSFORM_NORMAL,
Pekka Paalanenbabb3b32019-11-01 14:02:15 +0200191 .config_file = NULL,
192 .extra_module = NULL,
193 .logging_scopes = NULL,
194 .testset_name = testset_name,
195 };
196}
197
198static const char *
199backend_to_str(enum weston_compositor_backend b)
200{
201 static const char * const names[] = {
202 [WESTON_BACKEND_DRM] = "drm-backend.so",
203 [WESTON_BACKEND_FBDEV] = "fbdev-backend.so",
204 [WESTON_BACKEND_HEADLESS] = "headless-backend.so",
205 [WESTON_BACKEND_RDP] = "rdp-backend.so",
206 [WESTON_BACKEND_WAYLAND] = "wayland-backend.so",
207 [WESTON_BACKEND_X11] = "X11-backend.so",
208 };
209 assert(b >= 0 && b < ARRAY_LENGTH(names));
210 return names[b];
211}
212
213static const char *
214renderer_to_arg(enum weston_compositor_backend b, enum renderer_type r)
215{
216 static const char * const headless_names[] = {
217 [RENDERER_NOOP] = NULL,
218 [RENDERER_PIXMAN] = "--use-pixman",
219 [RENDERER_GL] = "--use-gl",
220 };
Leandro Ribeiro7b37b4d2020-05-05 18:14:25 -0300221 static const char * const drm_names[] = {
222 [RENDERER_PIXMAN] = "--use-pixman",
223 [RENDERER_GL] = NULL,
224 };
Pekka Paalanenbabb3b32019-11-01 14:02:15 +0200225
226 switch (b) {
227 case WESTON_BACKEND_HEADLESS:
Leandro Ribeiro7b37b4d2020-05-05 18:14:25 -0300228 assert(r >= RENDERER_NOOP && r <= RENDERER_GL);
Pekka Paalanenbabb3b32019-11-01 14:02:15 +0200229 return headless_names[r];
Leandro Ribeiro7b37b4d2020-05-05 18:14:25 -0300230 case WESTON_BACKEND_DRM:
231 assert(r >= RENDERER_PIXMAN && r <= RENDERER_GL);
232 return drm_names[r];
Pekka Paalanenbabb3b32019-11-01 14:02:15 +0200233 default:
234 assert(0 && "renderer_to_str() does not know the backend");
235 }
236
237 return NULL;
238}
239
240static const char *
241shell_to_str(enum shell_type t)
242{
243 static const char * const names[] = {
244 [SHELL_TEST_DESKTOP] = "weston-test-desktop-shell.so",
245 [SHELL_DESKTOP] = "desktop-shell.so",
246 [SHELL_FULLSCREEN] = "fullscreen-shell.so",
247 [SHELL_IVI] = "ivi-shell.so",
248 };
249 assert(t >= 0 && t < ARRAY_LENGTH(names));
250 return names[t];
251}
252
Pekka Paalanen0ce5a192020-01-22 11:53:12 +0200253static const char *
254transform_to_str(enum wl_output_transform t)
255{
256 static const char * const names[] = {
257 [WL_OUTPUT_TRANSFORM_NORMAL] = "normal",
258 [WL_OUTPUT_TRANSFORM_90] = "rotate-90",
259 [WL_OUTPUT_TRANSFORM_180] = "rotate-180",
260 [WL_OUTPUT_TRANSFORM_270] = "rotate-270",
261 [WL_OUTPUT_TRANSFORM_FLIPPED] = "flipped",
262 [WL_OUTPUT_TRANSFORM_FLIPPED_90] = "flipped-rotate-90",
263 [WL_OUTPUT_TRANSFORM_FLIPPED_180] = "flipped-rotate-180",
264 [WL_OUTPUT_TRANSFORM_FLIPPED_270] = "flipped-rotate-270",
265 };
266
267 assert(t < ARRAY_LENGTH(names) && names[t]);
268 return names[t];
269}
270
Pekka Paalanenbabb3b32019-11-01 14:02:15 +0200271/** Execute compositor
272 *
273 * Manufactures the compositor command line and calls wet_main().
274 *
275 * Returns RESULT_SKIP if the given setup contains features that were disabled
276 * in the build, e.g. GL-renderer or DRM-backend.
277 *
278 * \ingroup testharness_private
279 */
280int
281execute_compositor(const struct compositor_setup *setup,
282 struct wet_testsuite_data *data)
283{
Leandro Ribeiro32a5acd2020-10-19 16:06:22 -0300284 struct weston_testsuite_data test_data;
Pekka Paalanenbabb3b32019-11-01 14:02:15 +0200285 struct prog_args args;
286 char *tmp;
Leandro Ribeiroe8a8c132020-05-06 11:21:03 -0300287 const char *ctmp, *drm_device;
288 int ret, lock_fd = -1;
Pekka Paalanenbabb3b32019-11-01 14:02:15 +0200289
Pekka Paalanen82dd6ce2019-11-01 15:39:30 +0200290 if (setenv("WESTON_MODULE_MAP", WESTON_MODULE_MAP, 0) < 0 ||
291 setenv("WESTON_DATA_DIR", WESTON_DATA_DIR, 0) < 0) {
292 fprintf(stderr, "Error: environment setup failed.\n");
293 return RESULT_HARD_ERROR;
294 }
295
Pekka Paalanenbabb3b32019-11-01 14:02:15 +0200296#ifndef BUILD_DRM_COMPOSITOR
297 if (setup->backend == WESTON_BACKEND_DRM) {
298 fprintf(stderr, "DRM-backend required but not built, skipping.\n");
299 return RESULT_SKIP;
300 }
301#endif
302
303#ifndef BUILD_FBDEV_COMPOSITOR
304 if (setup->backend == WESTON_BACKEND_FBDEV) {
305 fprintf(stderr, "fbdev-backend required but not built, skipping.\n");
306 return RESULT_SKIP;
307 }
308#endif
309
310#ifndef BUILD_RDP_COMPOSITOR
311 if (setup->backend == WESTON_BACKEND_RDP) {
312 fprintf(stderr, "RDP-backend required but not built, skipping.\n");
313 return RESULT_SKIP;
314 }
315#endif
316
317#ifndef BUILD_WAYLAND_COMPOSITOR
318 if (setup->backend == WESTON_BACKEND_WAYLAND) {
319 fprintf(stderr, "wayland-backend required but not built, skipping.\n");
320 return RESULT_SKIP;
321 }
322#endif
323
324#ifndef BUILD_X11_COMPOSITOR
325 if (setup->backend == WESTON_BACKEND_X11) {
326 fprintf(stderr, "X11-backend required but not built, skipping.\n");
327 return RESULT_SKIP;
328 }
329#endif
330
331#ifndef ENABLE_EGL
332 if (setup->renderer == RENDERER_GL) {
333 fprintf(stderr, "GL-renderer required but not built, skipping.\n");
334 return RESULT_SKIP;
335 }
336#endif
337
Pekka Paalanen16186972020-02-04 16:59:59 +0200338#if !TEST_GL_RENDERER
339 if (setup->renderer == RENDERER_GL) {
340 fprintf(stderr, "GL-renderer disabled for tests, skipping.\n");
341 return RESULT_SKIP;
342 }
343#endif
344
Pekka Paalanenbabb3b32019-11-01 14:02:15 +0200345 prog_args_init(&args);
346
347 /* argv[0] */
348 asprintf(&tmp, "weston-%s", setup->testset_name);
349 prog_args_take(&args, tmp);
350
351 asprintf(&tmp, "--backend=%s", backend_to_str(setup->backend));
352 prog_args_take(&args, tmp);
353
Leandro Ribeiroe8a8c132020-05-06 11:21:03 -0300354 if (setup->backend == WESTON_BACKEND_DRM) {
355
356 drm_device = getenv("WESTON_TEST_SUITE_DRM_DEVICE");
357 if (!drm_device) {
358 fprintf(stderr, "Skipping DRM-backend tests because " \
359 "WESTON_TEST_SUITE_DRM_DEVICE is not set. " \
360 "See test suite documentation to learn how " \
361 "to run them.\n");
Leandro Ribeiro5911d2a2021-10-21 10:44:55 -0300362 ret = RESULT_SKIP;
363 goto out;
Leandro Ribeiroe8a8c132020-05-06 11:21:03 -0300364 }
365 asprintf(&tmp, "--drm-device=%s", drm_device);
366 prog_args_take(&args, tmp);
367
368 prog_args_take(&args, strdup("--seat=weston-test-seat"));
369
370 prog_args_take(&args, strdup("--continue-without-input"));
371
372 lock_fd = wait_for_lock();
Leandro Ribeiro5911d2a2021-10-21 10:44:55 -0300373 if (lock_fd == -1) {
374 ret = RESULT_FAIL;
375 goto out;
376 }
Leandro Ribeiroe8a8c132020-05-06 11:21:03 -0300377 }
378
Leandro Ribeiro9e907602020-10-17 15:03:09 -0300379 /* Test suite needs the debug protocol to be able to take screenshots */
380 prog_args_take(&args, strdup("--debug"));
381
Pekka Paalanenbabb3b32019-11-01 14:02:15 +0200382 asprintf(&tmp, "--socket=%s", setup->testset_name);
383 prog_args_take(&args, tmp);
384
385 asprintf(&tmp, "--modules=%s%s%s", TESTSUITE_PLUGIN_PATH,
386 setup->extra_module ? "," : "",
387 setup->extra_module ? setup->extra_module : "");
388 prog_args_take(&args, tmp);
389
Leandro Ribeiroe8033e32020-05-05 16:09:03 -0300390 if (setup->backend != WESTON_BACKEND_DRM &&
391 setup->backend != WESTON_BACKEND_FBDEV) {
392 asprintf(&tmp, "--width=%d", setup->width);
393 prog_args_take(&args, tmp);
Pekka Paalanenbabb3b32019-11-01 14:02:15 +0200394
Leandro Ribeiroe8033e32020-05-05 16:09:03 -0300395 asprintf(&tmp, "--height=%d", setup->height);
396 prog_args_take(&args, tmp);
397 }
Pekka Paalanenbabb3b32019-11-01 14:02:15 +0200398
Pekka Paalanen0ce5a192020-01-22 11:53:12 +0200399 if (setup->scale != 1) {
400 asprintf(&tmp, "--scale=%d", setup->scale);
401 prog_args_take(&args, tmp);
402 }
403
404 if (setup->transform != WL_OUTPUT_TRANSFORM_NORMAL) {
405 asprintf(&tmp, "--transform=%s",
406 transform_to_str(setup->transform));
407 prog_args_take(&args, tmp);
408 }
409
Pekka Paalanenbabb3b32019-11-01 14:02:15 +0200410 if (setup->config_file) {
411 asprintf(&tmp, "--config=%s", setup->config_file);
412 prog_args_take(&args, tmp);
Igor Matheus Andrade Torrentead41a882020-08-15 21:19:13 -0300413 free(setup->config_file);
Pekka Paalanenbabb3b32019-11-01 14:02:15 +0200414 } else {
415 prog_args_take(&args, strdup("--no-config"));
416 }
417
418 ctmp = renderer_to_arg(setup->backend, setup->renderer);
419 if (ctmp)
420 prog_args_take(&args, strdup(ctmp));
421
422 asprintf(&tmp, "--shell=%s", shell_to_str(setup->shell));
423 prog_args_take(&args, tmp);
424
425 if (setup->logging_scopes) {
426 asprintf(&tmp, "--logger-scopes=%s", setup->logging_scopes);
427 prog_args_take(&args, tmp);
428 }
429
430 if (setup->xwayland)
431 prog_args_take(&args, strdup("--xwayland"));
432
Leandro Ribeiro32a5acd2020-10-19 16:06:22 -0300433 test_data.test_quirks = setup->test_quirks;
434 test_data.test_private_data = data;
Pekka Paalanenbabb3b32019-11-01 14:02:15 +0200435 prog_args_save(&args);
Leandro Ribeiro32a5acd2020-10-19 16:06:22 -0300436 ret = wet_main(args.argc, args.argv, &test_data);
Pekka Paalanenbabb3b32019-11-01 14:02:15 +0200437
Leandro Ribeiro5911d2a2021-10-21 10:44:55 -0300438out:
Pekka Paalanenbabb3b32019-11-01 14:02:15 +0200439 prog_args_fini(&args);
440
Leandro Ribeiroe8a8c132020-05-06 11:21:03 -0300441 /* We acquired a lock (if this is a DRM-backend test) and now we can
442 * close its fd and release it, as it has already been run. */
443 if (lock_fd != -1)
444 close(lock_fd);
445
Pekka Paalanenbabb3b32019-11-01 14:02:15 +0200446 return ret;
447}
Igor Matheus Andrade Torrentead41a882020-08-15 21:19:13 -0300448
449static void
450write_cfg(va_list entry_list, FILE *weston_ini)
451{
452 char *entry = va_arg(entry_list, char *);
453 int ret;
454 assert(entry);
455
456 while (entry) {
457 ret = fprintf(weston_ini, "%s\n", entry);
458 assert(ret >= 0);
459 free(entry);
460 entry = va_arg(entry_list, char *);
461 }
462}
463
464static FILE *
465open_ini_file(struct compositor_setup *setup)
466{
467 char *wd, *tmp_path = NULL;
468 FILE *weston_ini = NULL;
469
470 assert(!setup->config_file);
471
472 wd = realpath(".", NULL);
473 assert(wd);
474
475 if (asprintf(&tmp_path, "%s/%s.ini", wd, setup->testset_name) == -1) {
Maxime Roussin-Bélanger4e8ea1f2020-12-17 17:07:49 -0500476 fprintf(stderr, "Fail formatting Weston.ini file name.\n");
Igor Matheus Andrade Torrentead41a882020-08-15 21:19:13 -0300477 goto out;
478 }
479
480 weston_ini = fopen(tmp_path, "w");
481 assert(weston_ini);
482 setup->config_file = tmp_path;
483
484out:
485 free(wd);
486 return weston_ini;
487}
488
489void
490weston_ini_setup_(struct compositor_setup *setup, ...)
491{
492 FILE *weston_ini = NULL;
493 int ret;
494 va_list entry_list;
495
496 weston_ini = open_ini_file(setup);
497 assert(weston_ini);
498
499 va_start(entry_list, setup);
500 write_cfg(entry_list, weston_ini);
501 va_end(entry_list);
502
503 ret = fclose(weston_ini);
504 assert(ret != EOF);
505}
506
507char *
508cfgln(const char *fmt, ...)
509{
510 char *str;
511 int ret;
512 va_list ap;
513
514 va_start(ap, fmt);
515 ret = vasprintf(&str, fmt, ap);
516 assert(ret >= 0);
517 va_end(ap);
518
519 return str;
520}
521