test: share one daemon and D-Bus harness across live tests
Six live tests carried private copies of the same daemon harness: the
private XDG_RUNTIME_DIR, the fork/exec with captured stderr, the
readiness waits, the SIGTERM and SIGKILL paths, the IBus address file
reader, the socket connect, and the IPC probe. Three of them also
carried the same libdbus helpers.
Extract one implementation into tests/live.c and, so that the binaries
that do not link dbus-1 keep not linking it, the D-Bus half into
tests/livebus.c. Both are compiled into each binary the way ../ipc.c
already is. gtk_live_test keeps its own fake-server harness and only
takes fail, nowms and leftms; xim_live_test keeps its own Xvfb and
process-group daemon spawn, which must inherit DISPLAY, and takes the
temporary directory, timing and cleanup halves.
The copies had drifted; the harness keeps the stricter behaviour.
- nowms reports a broken clock (-1) instead of pretending it read
zero, and leftms turns that into an expired deadline, so a loop
ends in a timeout failure rather than spinning. livesetup checks
the clock once up front, as daemon_restart_test did.
- Timeouts compare with <= 0, not == 0.
- readuntil keeps the three-way result (complete, peer closed, error)
from ipc_live_test and daemon_restart_test rather than folding
peer closure into ECONNRESET.
- The daemon's stdout and stderr are both captured, and a failing
setenv is reported, for every daemon; daemon_failure_test captured
stderr only and said nothing about setenv.
- The child keeps daemon_restart_test's careful redirect that also
works when the pipe lands on fd 1 or 2.
- parseaddress requires a positive declared PID.
- killdaemon reports ECHILD after SIGKILL as a failure; one copy
accepted it. It now reaps with a blocking waitpid, which SIGKILL
guarantees will return, instead of daemon_restart_test's polled
wait with its own timeout diagnostic.
- stopdaemon tolerates ESRCH on SIGTERM, a benign race two copies
reported as an error.
- liveclean removes the socket and address files and then rmdirs
each directory, reporting leftovers, rather than deleting the
temporary root recursively.
- ibus_live_test now waits for the IPC socket and the address file
by polling, dropping its inotify variant; it asserted only the
address file before.
This commit is contained in:
@@ -1,53 +1,25 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/wait.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "ipc.h"
|
||||
#include "live.h"
|
||||
|
||||
enum
|
||||
{
|
||||
Maxclients = 64,
|
||||
Calltimeout = 4000,
|
||||
Starttimeout = 8000,
|
||||
Stoptimeout = 3000,
|
||||
Cappreedit = 1,
|
||||
};
|
||||
|
||||
typedef struct Daemon Daemon;
|
||||
typedef struct Response Response;
|
||||
|
||||
struct Daemon
|
||||
{
|
||||
pid_t pid;
|
||||
int errfd;
|
||||
char root[256];
|
||||
char runtime[320];
|
||||
char config[320];
|
||||
char ibus[384];
|
||||
char bus[448];
|
||||
char home[320];
|
||||
char socket[384];
|
||||
char err[4096];
|
||||
size_t nerr;
|
||||
};
|
||||
|
||||
struct Response
|
||||
{
|
||||
int eaten;
|
||||
@@ -55,495 +27,6 @@ struct Response
|
||||
char preedit[Ipcfieldmax+1];
|
||||
};
|
||||
|
||||
static int
|
||||
fail(char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf(stderr, "ipc_live_test: ");
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fputc('\n', stderr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int64_t
|
||||
nowms(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
if(clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
|
||||
return 0;
|
||||
return (int64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
|
||||
}
|
||||
|
||||
static int
|
||||
leftms(int64_t deadline)
|
||||
{
|
||||
int64_t n;
|
||||
|
||||
n = deadline - nowms();
|
||||
if(n <= 0)
|
||||
return 0;
|
||||
if(n > 0x7fffffff)
|
||||
return 0x7fffffff;
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
makedir(char *path)
|
||||
{
|
||||
if(mkdir(path, 0700) == 0)
|
||||
return 1;
|
||||
return fail("mkdir %s: %s", path, strerror(errno));
|
||||
}
|
||||
|
||||
static void
|
||||
readerrors(Daemon *d)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
if(d->errfd < 0)
|
||||
return;
|
||||
while(d->nerr + 1 < sizeof d->err){
|
||||
n = read(d->errfd, d->err + d->nerr,
|
||||
sizeof d->err - d->nerr - 1);
|
||||
if(n > 0){
|
||||
d->nerr += n;
|
||||
continue;
|
||||
}
|
||||
if(n < 0 && errno == EINTR)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
d->err[d->nerr] = '\0';
|
||||
}
|
||||
|
||||
static void
|
||||
showerrors(Daemon *d)
|
||||
{
|
||||
readerrors(d);
|
||||
if(d->nerr != 0)
|
||||
fprintf(stderr, "ipc_live_test: daemon stderr:\n%s", d->err);
|
||||
}
|
||||
|
||||
static int
|
||||
waitsocket(Daemon *d, int notifyfd)
|
||||
{
|
||||
struct pollfd pfd[2];
|
||||
struct stat st;
|
||||
char buf[4096];
|
||||
int n, status, timeout;
|
||||
int64_t deadline;
|
||||
|
||||
deadline = nowms() + Starttimeout;
|
||||
for(;;){
|
||||
if(lstat(d->socket, &st) == 0 && S_ISSOCK(st.st_mode) &&
|
||||
(st.st_mode & 0777) == 0600)
|
||||
return 1;
|
||||
do
|
||||
n = waitpid(d->pid, &status, WNOHANG);
|
||||
while(n < 0 && errno == EINTR);
|
||||
if(n == d->pid){
|
||||
d->pid = -1;
|
||||
readerrors(d);
|
||||
return fail("daemon exited before creating IPC socket");
|
||||
}
|
||||
if(n < 0){
|
||||
if(errno == ECHILD)
|
||||
d->pid = -1;
|
||||
return fail("wait for daemon startup: %s", strerror(errno));
|
||||
}
|
||||
timeout = leftms(deadline);
|
||||
if(timeout == 0)
|
||||
return fail("timed out waiting for protected IPC socket %s",
|
||||
d->socket);
|
||||
pfd[0].fd = notifyfd;
|
||||
pfd[0].events = POLLIN;
|
||||
pfd[0].revents = 0;
|
||||
pfd[1].fd = d->errfd;
|
||||
pfd[1].events = POLLIN;
|
||||
pfd[1].revents = 0;
|
||||
n = poll(pfd, 2, timeout);
|
||||
if(n < 0 && errno == EINTR)
|
||||
continue;
|
||||
if(n < 0)
|
||||
return fail("poll for IPC socket: %s", strerror(errno));
|
||||
if(n == 0)
|
||||
continue;
|
||||
if(pfd[1].revents != 0)
|
||||
readerrors(d);
|
||||
if(pfd[0].revents & POLLIN)
|
||||
while(read(notifyfd, buf, sizeof buf) < 0 && errno == EINTR)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
startdaemon(Daemon *d, char *program, char *mapdir)
|
||||
{
|
||||
int fd, notifyfd, watch, errpipe[2];
|
||||
long maxfd;
|
||||
pid_t pid;
|
||||
|
||||
memset(d, 0, sizeof *d);
|
||||
d->pid = -1;
|
||||
d->errfd = -1;
|
||||
snprintf(d->root, sizeof d->root, "/tmp/strans-ipc.XXXXXX");
|
||||
if(mkdtemp(d->root) == NULL){
|
||||
d->root[0] = '\0';
|
||||
return fail("mkdtemp: %s", strerror(errno));
|
||||
}
|
||||
if(snprintf(d->runtime, sizeof d->runtime, "%s/runtime", d->root)
|
||||
>= (int)sizeof d->runtime ||
|
||||
snprintf(d->config, sizeof d->config, "%s/config", d->root)
|
||||
>= (int)sizeof d->config ||
|
||||
snprintf(d->ibus, sizeof d->ibus, "%s/ibus", d->config)
|
||||
>= (int)sizeof d->ibus ||
|
||||
snprintf(d->bus, sizeof d->bus, "%s/bus", d->ibus)
|
||||
>= (int)sizeof d->bus ||
|
||||
snprintf(d->home, sizeof d->home, "%s/home", d->root)
|
||||
>= (int)sizeof d->home ||
|
||||
snprintf(d->socket, sizeof d->socket, "%s/strans.sock", d->runtime)
|
||||
>= (int)sizeof d->socket)
|
||||
return fail("temporary path is too long");
|
||||
if(!makedir(d->runtime) || !makedir(d->config) || !makedir(d->ibus) ||
|
||||
!makedir(d->bus) || !makedir(d->home))
|
||||
return 0;
|
||||
notifyfd = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
|
||||
if(notifyfd < 0)
|
||||
return fail("inotify_init1: %s", strerror(errno));
|
||||
watch = inotify_add_watch(notifyfd, d->runtime,
|
||||
IN_CREATE|IN_MOVED_TO|IN_ATTRIB);
|
||||
if(watch < 0){
|
||||
close(notifyfd);
|
||||
return fail("inotify_add_watch: %s", strerror(errno));
|
||||
}
|
||||
if(pipe2(errpipe, O_CLOEXEC|O_NONBLOCK) < 0){
|
||||
close(notifyfd);
|
||||
return fail("pipe2: %s", strerror(errno));
|
||||
}
|
||||
pid = fork();
|
||||
if(pid < 0){
|
||||
close(errpipe[0]);
|
||||
close(errpipe[1]);
|
||||
close(notifyfd);
|
||||
return fail("fork: %s", strerror(errno));
|
||||
}
|
||||
if(pid == 0){
|
||||
close(errpipe[0]);
|
||||
close(notifyfd);
|
||||
if(dup2(errpipe[1], STDOUT_FILENO) < 0 ||
|
||||
dup2(errpipe[1], STDERR_FILENO) < 0)
|
||||
_exit(126);
|
||||
close(errpipe[1]);
|
||||
if(close_range(3, UINT_MAX, 0) < 0){
|
||||
maxfd = sysconf(_SC_OPEN_MAX);
|
||||
if(maxfd < 0)
|
||||
maxfd = 1024;
|
||||
for(fd = 3; fd < maxfd; fd++)
|
||||
close(fd);
|
||||
}
|
||||
if(setenv("XDG_RUNTIME_DIR", d->runtime, 1) < 0 ||
|
||||
setenv("XDG_CONFIG_HOME", d->config, 1) < 0 ||
|
||||
setenv("HOME", d->home, 1) < 0 || unsetenv("DISPLAY") < 0 ||
|
||||
unsetenv("DBUS_SESSION_BUS_ADDRESS") < 0 ||
|
||||
unsetenv("IBUS_ADDRESS") < 0 ||
|
||||
unsetenv("IBUS_ADDRESS_FILE") < 0){
|
||||
dprintf(STDERR_FILENO, "set daemon environment: %s\n",
|
||||
strerror(errno));
|
||||
_exit(126);
|
||||
}
|
||||
execl(program, program, mapdir, (char*)0);
|
||||
dprintf(STDERR_FILENO, "exec %s: %s\n", program, strerror(errno));
|
||||
_exit(127);
|
||||
}
|
||||
close(errpipe[1]);
|
||||
d->pid = pid;
|
||||
d->errfd = errpipe[0];
|
||||
if(!waitsocket(d, notifyfd)){
|
||||
inotify_rm_watch(notifyfd, watch);
|
||||
close(notifyfd);
|
||||
return 0;
|
||||
}
|
||||
inotify_rm_watch(notifyfd, watch);
|
||||
close(notifyfd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
clearbus(Daemon *d)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *de;
|
||||
char path[576];
|
||||
int ok;
|
||||
|
||||
dir = opendir(d->bus);
|
||||
if(dir == NULL)
|
||||
return errno == ENOENT || fail("open cleanup directory %s: %s",
|
||||
d->bus, strerror(errno));
|
||||
ok = 1;
|
||||
errno = 0;
|
||||
while((de = readdir(dir)) != NULL){
|
||||
if(strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
|
||||
continue;
|
||||
if(snprintf(path, sizeof path, "%s/%s", d->bus, de->d_name)
|
||||
>= (int)sizeof path){
|
||||
fail("cleanup path is too long: %s", de->d_name);
|
||||
ok = 0;
|
||||
continue;
|
||||
}
|
||||
if(unlink(path) < 0 && errno != ENOENT){
|
||||
fail("remove IBus address file %s: %s", de->d_name,
|
||||
strerror(errno));
|
||||
ok = 0;
|
||||
}
|
||||
errno = 0;
|
||||
}
|
||||
if(errno != 0){
|
||||
fail("read cleanup directory %s: %s", d->bus, strerror(errno));
|
||||
ok = 0;
|
||||
}
|
||||
closedir(dir);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int
|
||||
rmdirknown(char *path)
|
||||
{
|
||||
if(path[0] == '\0' || rmdir(path) == 0 || errno == ENOENT)
|
||||
return 1;
|
||||
return fail("rmdir %s: %s", path, strerror(errno));
|
||||
}
|
||||
|
||||
static int
|
||||
killdaemon(Daemon *d, int *status)
|
||||
{
|
||||
int n, ok;
|
||||
|
||||
ok = 1;
|
||||
if(kill(d->pid, SIGKILL) < 0 && errno != ESRCH){
|
||||
fail("kill -9 %ld: %s", (long)d->pid, strerror(errno));
|
||||
ok = 0;
|
||||
}
|
||||
do
|
||||
n = waitpid(d->pid, status, 0);
|
||||
while(n < 0 && errno == EINTR);
|
||||
if(n != d->pid){
|
||||
fail("reap %ld after SIGKILL: %s", (long)d->pid,
|
||||
n < 0 ? strerror(errno) : "wrong child");
|
||||
if(n < 0 && errno == ECHILD)
|
||||
d->pid = -1;
|
||||
ok = 0;
|
||||
}else
|
||||
d->pid = -1;
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int
|
||||
stopdaemon(Daemon *d)
|
||||
{
|
||||
struct pollfd pfd;
|
||||
int ok, status, n, reaped;
|
||||
int64_t deadline;
|
||||
|
||||
ok = 1;
|
||||
if(d->pid > 0){
|
||||
do
|
||||
n = waitpid(d->pid, &status, WNOHANG);
|
||||
while(n < 0 && errno == EINTR);
|
||||
if(n == d->pid){
|
||||
fail("daemon exited before test termination with wait status %#x",
|
||||
status);
|
||||
d->pid = -1;
|
||||
ok = 0;
|
||||
}else if(n < 0){
|
||||
fail("check daemon %ld before termination: %s",
|
||||
(long)d->pid, strerror(errno));
|
||||
if(errno == ECHILD)
|
||||
d->pid = -1;
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
if(d->pid > 0){
|
||||
if(kill(d->pid, SIGTERM) < 0){
|
||||
fail("kill %ld: %s", (long)d->pid, strerror(errno));
|
||||
ok = 0;
|
||||
}
|
||||
reaped = 0;
|
||||
deadline = nowms() + Stoptimeout;
|
||||
for(;;){
|
||||
n = waitpid(d->pid, &status, WNOHANG);
|
||||
if(n == d->pid){
|
||||
reaped = 1;
|
||||
d->pid = -1;
|
||||
break;
|
||||
}
|
||||
if(n < 0 && errno == EINTR)
|
||||
continue;
|
||||
if(n < 0){
|
||||
fail("waitpid %ld: %s", (long)d->pid, strerror(errno));
|
||||
ok = 0;
|
||||
if(errno == ECHILD)
|
||||
d->pid = -1;
|
||||
break;
|
||||
}
|
||||
n = leftms(deadline);
|
||||
if(n == 0){
|
||||
fail("daemon %ld did not stop after SIGTERM", (long)d->pid);
|
||||
ok = 0;
|
||||
if(!killdaemon(d, &status))
|
||||
ok = 0;
|
||||
break;
|
||||
}
|
||||
pfd.fd = d->errfd;
|
||||
pfd.events = POLLIN|POLLHUP;
|
||||
pfd.revents = 0;
|
||||
if(poll(&pfd, 1, n) < 0 && errno != EINTR){
|
||||
fail("poll daemon %ld: %s", (long)d->pid, strerror(errno));
|
||||
ok = 0;
|
||||
if(!killdaemon(d, &status))
|
||||
ok = 0;
|
||||
break;
|
||||
}
|
||||
readerrors(d);
|
||||
}
|
||||
/* plan9port turns a caught termination note into exit status 1. */
|
||||
if(reaped &&
|
||||
!((WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM) ||
|
||||
(WIFEXITED(status) && WEXITSTATUS(status) == 1))){
|
||||
fail("daemon exited with unexpected wait status %#x", status);
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
readerrors(d);
|
||||
if(d->errfd >= 0){
|
||||
close(d->errfd);
|
||||
d->errfd = -1;
|
||||
}
|
||||
if(d->socket[0] != '\0' && unlink(d->socket) < 0 && errno != ENOENT){
|
||||
fail("remove IPC socket %s: %s", d->socket, strerror(errno));
|
||||
ok = 0;
|
||||
}
|
||||
if(!clearbus(d)) ok = 0;
|
||||
if(!rmdirknown(d->bus)) ok = 0;
|
||||
if(!rmdirknown(d->ibus)) ok = 0;
|
||||
if(!rmdirknown(d->config)) ok = 0;
|
||||
if(!rmdirknown(d->runtime)) ok = 0;
|
||||
if(!rmdirknown(d->home)) ok = 0;
|
||||
if(!rmdirknown(d->root)) ok = 0;
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int
|
||||
connectuntil(char *path, int64_t deadline)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
struct pollfd pfd;
|
||||
socklen_t nerr;
|
||||
int err, fd, flags, n;
|
||||
|
||||
memset(&addr, 0, sizeof addr);
|
||||
addr.sun_family = AF_UNIX;
|
||||
if(snprintf(addr.sun_path, sizeof addr.sun_path, "%s", path)
|
||||
>= (int)sizeof addr.sun_path){
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
|
||||
if(fd < 0)
|
||||
return -1;
|
||||
if(connect(fd, (struct sockaddr*)&addr, sizeof addr) < 0 &&
|
||||
errno != EINPROGRESS){
|
||||
err = errno;
|
||||
close(fd);
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
pfd.fd = fd;
|
||||
pfd.events = POLLOUT;
|
||||
pfd.revents = 0;
|
||||
for(;;){
|
||||
n = leftms(deadline);
|
||||
if(n == 0){
|
||||
close(fd);
|
||||
errno = ETIMEDOUT;
|
||||
return -1;
|
||||
}
|
||||
n = poll(&pfd, 1, n);
|
||||
if(n < 0 && errno == EINTR)
|
||||
continue;
|
||||
if(n <= 0){
|
||||
err = n == 0 ? ETIMEDOUT : errno;
|
||||
close(fd);
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
err = 0;
|
||||
nerr = sizeof err;
|
||||
if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &nerr) < 0 || err != 0){
|
||||
if(err == 0)
|
||||
err = errno;
|
||||
close(fd);
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
flags = fcntl(fd, F_GETFL);
|
||||
if(flags < 0 || fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) < 0){
|
||||
err = errno;
|
||||
close(fd);
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* 1 is complete, 0 is peer closure, and -1 is a timeout or I/O error. */
|
||||
static int
|
||||
readuntil(int fd, void *buf, size_t n, int64_t deadline)
|
||||
{
|
||||
struct pollfd pfd;
|
||||
unsigned char *p;
|
||||
ssize_t r;
|
||||
int timeout;
|
||||
|
||||
p = buf;
|
||||
while(n > 0){
|
||||
timeout = leftms(deadline);
|
||||
if(timeout == 0){
|
||||
errno = ETIMEDOUT;
|
||||
return -1;
|
||||
}
|
||||
pfd.fd = fd;
|
||||
pfd.events = POLLIN;
|
||||
pfd.revents = 0;
|
||||
r = poll(&pfd, 1, timeout);
|
||||
if(r < 0){
|
||||
if(errno == EINTR)
|
||||
continue;
|
||||
return -1;
|
||||
}
|
||||
if(r == 0){
|
||||
errno = ETIMEDOUT;
|
||||
return -1;
|
||||
}
|
||||
r = recv(fd, p, n, 0);
|
||||
if(r < 0 && errno == EINTR)
|
||||
continue;
|
||||
if(r < 0)
|
||||
return -1;
|
||||
if(r == 0)
|
||||
return 0;
|
||||
p += r;
|
||||
n -= r;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static size_t
|
||||
getlen(unsigned char p[Ipclensz])
|
||||
{
|
||||
@@ -674,7 +157,7 @@ tryclient(char *path, int64_t deadline, int *client)
|
||||
Response res;
|
||||
int fd, rv;
|
||||
|
||||
fd = connectuntil(path, deadline);
|
||||
fd = connectsocket(path, deadline);
|
||||
if(fd < 0)
|
||||
return errno == ETIMEDOUT ? -1 : 0;
|
||||
if(!sendkey(fd, 1, 0, Kmodfirst)){
|
||||
@@ -721,7 +204,7 @@ overflowrejected(char *path)
|
||||
int64_t deadline;
|
||||
|
||||
deadline = nowms() + Calltimeout;
|
||||
fd = connectuntil(path, deadline);
|
||||
fd = connectsocket(path, deadline);
|
||||
if(fd < 0)
|
||||
return fail("overflow connect: %s", strerror(errno));
|
||||
if(!sendkey(fd, 1, 0, Kmodfirst)){
|
||||
@@ -762,11 +245,11 @@ overflowrejected(char *path)
|
||||
}
|
||||
|
||||
static int
|
||||
runsmoke(Daemon *d)
|
||||
runsmoke(char *path)
|
||||
{
|
||||
int client, ok;
|
||||
|
||||
client = connectuntil(d->socket, nowms() + Calltimeout);
|
||||
client = connectsocket(path, nowms() + Calltimeout);
|
||||
if(client < 0)
|
||||
return fail("connect client: %s", strerror(errno));
|
||||
ok = sendcap(client, Cappreedit) &&
|
||||
@@ -780,7 +263,7 @@ runsmoke(Daemon *d)
|
||||
}
|
||||
|
||||
static int
|
||||
runcapacity(Daemon *d)
|
||||
runcapacity(char *path)
|
||||
{
|
||||
int client[Maxclients];
|
||||
int i, ok;
|
||||
@@ -788,7 +271,7 @@ runcapacity(Daemon *d)
|
||||
for(i = 0; i < Maxclients; i++)
|
||||
client[i] = -1;
|
||||
ok = 0;
|
||||
client[0] = connectuntil(d->socket, nowms() + Calltimeout);
|
||||
client[0] = connectsocket(path, nowms() + Calltimeout);
|
||||
if(client[0] < 0){
|
||||
fail("connect first client: %s", strerror(errno));
|
||||
goto out;
|
||||
@@ -797,7 +280,7 @@ runcapacity(Daemon *d)
|
||||
"select Japanese"))
|
||||
goto out;
|
||||
for(i = 1; i < Maxclients; i++){
|
||||
client[i] = connectuntil(d->socket, nowms() + Calltimeout);
|
||||
client[i] = connectsocket(path, nowms() + Calltimeout);
|
||||
if(client[i] < 0){
|
||||
fail("connect capacity client %d: %s", i, strerror(errno));
|
||||
goto out;
|
||||
@@ -806,15 +289,15 @@ runcapacity(Daemon *d)
|
||||
"capacity modifier"))
|
||||
goto out;
|
||||
}
|
||||
if(!overflowrejected(d->socket))
|
||||
if(!overflowrejected(path))
|
||||
goto out;
|
||||
close(client[Maxclients-1]);
|
||||
client[Maxclients-1] = -1;
|
||||
if(!waitslot(d->socket, &client[Maxclients-1], "inactive slot recovery"))
|
||||
if(!waitslot(path, &client[Maxclients-1], "inactive slot recovery"))
|
||||
goto out;
|
||||
close(client[0]);
|
||||
client[0] = -1;
|
||||
if(!waitslot(d->socket, &client[0], "active slot recovery") ||
|
||||
if(!waitslot(path, &client[0], "active slot recovery") ||
|
||||
!requestkey(client[0], 1, 0, 'a', 1, "", "あ",
|
||||
"post-disconnect composition"))
|
||||
goto out;
|
||||
@@ -830,24 +313,30 @@ int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
Daemon daemon;
|
||||
char *program, *mapdir;
|
||||
Live live;
|
||||
int capacity, ok;
|
||||
|
||||
testname = "ipc_live_test";
|
||||
capacity = argc == 4 && strcmp(argv[1], "--capacity") == 0;
|
||||
if((!capacity && argc != 3) || (capacity && argc != 4)){
|
||||
fprintf(stderr,
|
||||
"usage: ipc_live_test [--capacity] strans mapdir\n");
|
||||
return 2;
|
||||
}
|
||||
program = argv[1+capacity];
|
||||
mapdir = argv[2+capacity];
|
||||
ok = startdaemon(&daemon, program, mapdir);
|
||||
daemoninit(&daemon, "daemon");
|
||||
ok = livesetup(&live, "ipc") &&
|
||||
startdaemon(&live, &daemon, argv[1+capacity], argv[2+capacity]) &&
|
||||
waitready(&live, &daemon, NULL, 0);
|
||||
if(ok)
|
||||
ok = capacity ? runcapacity(&daemon) : runsmoke(&daemon);
|
||||
ok = capacity ? runcapacity(live.socket) : runsmoke(live.socket);
|
||||
if(!ok)
|
||||
showerrors(&daemon);
|
||||
if(!stopdaemon(&daemon))
|
||||
ok = 0;
|
||||
if(!closeerrors(&daemon))
|
||||
ok = 0;
|
||||
if(!liveclean(&live))
|
||||
ok = 0;
|
||||
if(!ok)
|
||||
return 1;
|
||||
printf("ipc %s: ok\n", capacity ? "connection capacity" : "live smoke");
|
||||
|
||||
Reference in New Issue
Block a user