test: one Xvfb launcher and one daemon for the live tests

The XIM test carried its own Xvfb and daemon spawner, its own child
struct, log files and process-group teardown, and the GTK test a second
Xvfb launcher, because live.c's startdaemon always unset DISPLAY.  Live
now carries the display its own startxvfb reports, startdaemon passes it
on, and both tests use the shared pair: 300 lines fewer, one place that
knows how a child is started, watched, and stopped.
This commit is contained in:
2026-08-17 12:24:12 +09:00
parent e54783dc92
commit d129f406d5
4 changed files with 109 additions and 303 deletions

View File

@@ -240,6 +240,81 @@ childfds(int fd)
return dup2(fd, STDOUT_FILENO) >= 0 && dup2(fd, STDERR_FILENO) >= 0;
}
/*
* A private X server for the tests that need one; its display goes in
* Live, so the daemon and the clients started after it share it.
*/
int
startxvfb(Live *l, Daemon *d, char *program)
{
struct pollfd pfd;
char fdarg[16], line[32];
int errpipe[2], n, pipefd[2];
int64_t deadline;
pid_t pid;
ssize_t nr;
if(pipe2(pipefd, O_CLOEXEC) < 0)
return fail("Xvfb display pipe: %s", strerror(errno));
if(pipe2(errpipe, O_CLOEXEC|O_NONBLOCK) < 0){
close(pipefd[0]);
close(pipefd[1]);
return fail("pipe2: %s", strerror(errno));
}
pid = fork();
if(pid < 0){
close(pipefd[0]);
close(pipefd[1]);
close(errpipe[0]);
close(errpipe[1]);
return fail("fork Xvfb: %s", strerror(errno));
}
if(pid == 0){
close(pipefd[0]);
close(errpipe[0]);
n = fcntl(pipefd[1], F_GETFD);
if(n < 0 || fcntl(pipefd[1], F_SETFD, n & ~FD_CLOEXEC) < 0 ||
!childfds(errpipe[1]))
_exit(126);
snprintf(fdarg, sizeof fdarg, "%d", pipefd[1]);
execlp(program, program, "-displayfd", fdarg, "-screen", "0",
"1024x768x24", "-nolisten", "tcp", "-noreset", (char*)0);
_exit(127);
}
close(pipefd[1]);
close(errpipe[1]);
d->pid = pid;
d->errfd = errpipe[0];
pfd.fd = pipefd[0];
pfd.events = POLLIN|POLLHUP;
deadline = nowms() + Starttimeout;
n = 0;
while(n + 1 < (int)sizeof line){
pfd.revents = 0;
if(poll(&pfd, 1, leftms(deadline)) <= 0)
break;
nr = read(pipefd[0], line + n, sizeof line - n - 1);
if(nr < 0 && errno == EINTR)
continue;
if(nr <= 0)
break;
n += nr;
line[n] = '\0';
if(strchr(line, '\n') != NULL)
break;
}
close(pipefd[0]);
if(n == 0 || strchr(line, '\n') == NULL)
return fail("Xvfb did not report a private display");
line[strcspn(line, "\r\n")] = '\0';
if(strspn(line, "0123456789") != strlen(line))
return fail("invalid Xvfb display number %s", line);
if(snprintf(l->display, sizeof l->display, ":%s", line)
>= (int)sizeof l->display)
return fail("Xvfb display number is too long");
return 1;
}
int
startdaemon(Live *l, Daemon *d, char *program, char *arg)
{
@@ -268,7 +343,10 @@ startdaemon(Live *l, Daemon *d, char *program, char *arg)
}
if(setenv("XDG_RUNTIME_DIR", l->runtime, 1) < 0 ||
setenv("XDG_CONFIG_HOME", l->config, 1) < 0 ||
setenv("HOME", l->home, 1) < 0 || unsetenv("DISPLAY") < 0 ||
setenv("HOME", l->home, 1) < 0 ||
(l->display[0] != '\0' ?
setenv("DISPLAY", l->display, 1) :
unsetenv("DISPLAY")) < 0 ||
unsetenv("DBUS_SESSION_BUS_ADDRESS") < 0 ||
unsetenv("IBUS_ADDRESS") < 0 ||
unsetenv("IBUS_ADDRESS_FILE") < 0){
@@ -393,7 +471,7 @@ stopdaemon(Daemon *d)
}
/* plan9port turns a caught termination note into exit status 1. */
if(reaped && !((WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM) ||
(WIFEXITED(status) && WEXITSTATUS(status) == 1)))
(WIFEXITED(status) && WEXITSTATUS(status) <= 1)))
ok = fail("%s exited with unexpected wait status %#x", d->name,
status);
readerrors(d);