commandtest: Test virCommandSetSendBuffer() with virCommandDoAsyncIO()

Introduce a test case which ensures that a daemonized process can
work with virCommandSetSendBuffer() when async IO is enabled.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com>
This commit is contained in:
Michal Privoznik 2022-03-22 12:06:22 +01:00
parent 5c1b5f208a
commit e97b6f4bc5
2 changed files with 117 additions and 0 deletions

View File

@ -0,0 +1,20 @@
ARG:--close-stdin
ARG:--check-daemonize
ARG:--readfd
ARG:3
ENV:DISPLAY=:0.0
ENV:HOME=/home/test
ENV:HOSTNAME=test
ENV:LANG=C
ENV:LOGNAME=test
ENV:PATH=/usr/bin:/bin
ENV:TMPDIR=/tmp
ENV:USER=test
FD:0
FD:1
FD:2
FD:3
FD:6
DAEMON:yes
CWD:/
UMASK:0022

View File

@ -25,6 +25,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#ifndef WIN32 #ifndef WIN32
# include <sys/wait.h> # include <sys/wait.h>
# include <poll.h>
#endif #endif
#include <fcntl.h> #include <fcntl.h>
@ -1155,6 +1156,101 @@ test28(const void *unused G_GNUC_UNUSED)
} }
static int
test29(const void *unused G_GNUC_UNUSED)
{
g_autoptr(virCommand) cmd = virCommandNew(abs_builddir "/commandhelper");
g_autofree char *pidfile = virPidFileBuildPath(abs_builddir, "commandhelper");
pid_t pid;
int buffd;
VIR_AUTOCLOSE outfd = -1;
size_t buflen = 1024 * 10;
g_autofree unsigned char *buffer = NULL;
g_autofree char *outactual = NULL;
g_autofree char *outexpect = NULL;
size_t i;
size_t outactuallen = 0;
int ret = -1;
if (!pidfile)
return -1;
buffer = g_new0(unsigned char, buflen + 1);
for (i = 0; i < buflen; i++) {
buffer[i] = 'a' + i % ('z' - 'a' + 1);
}
buffer[buflen] = '\0';
outexpect = g_strdup_printf("BEGIN STDOUT\n%sEND STDOUT\n", buffer);
buffd = virCommandSetSendBuffer(cmd, &buffer, buflen);
virCommandAddArg(cmd, "--close-stdin");
virCommandAddArg(cmd, "--check-daemonize");
virCommandAddArg(cmd, "--readfd");
virCommandAddArgFormat(cmd, "%d", buffd);
virCommandSetOutputFD(cmd, &outfd);
virCommandSetPidFile(cmd, pidfile);
virCommandDaemonize(cmd);
virCommandDoAsyncIO(cmd);
if (virCommandRun(cmd, NULL) < 0) {
fprintf(stderr, "Cannot run child %s\n", virGetLastErrorMessage());
goto cleanup;
}
if (virPidFileReadPath(pidfile, &pid) < 0) {
fprintf(stderr, "cannot read pidfile: %s\n", pidfile);
goto cleanup;
}
while (1) {
char buf[1024] = { 0 };
struct pollfd pfd = {.fd = outfd, .events = POLLIN, .revents = 0};
int rc = 0;
rc = poll(&pfd, 1, 1000);
if (rc < 0) {
if (errno == EINTR)
continue;
fprintf(stderr, "poll() returned errno = %d\n", errno);
goto cleanup;
}
if (pfd.revents & POLLIN) {
rc = read(outfd, buf, sizeof(buf));
if (rc < 0) {
fprintf(stderr, "cannot read from output pipe: errno=%d\n", errno);
goto cleanup;
}
outactual = g_renew(char, outactual, outactuallen + rc + 1);
memcpy(outactual + outactuallen, buf, rc);
outactuallen += rc;
outactual[outactuallen] = '\0';
} else if (pfd.revents & POLLERR ||
pfd.revents & POLLHUP) {
break;
}
}
if (STRNEQ_NULLABLE(outactual, outexpect)) {
virTestDifference(stderr, outexpect, outactual);
goto cleanup;
}
ret = checkoutput("test29");
cleanup:
if (pidfile)
unlink(pidfile);
return ret;
}
static int static int
mymain(void) mymain(void)
{ {
@ -1252,6 +1348,7 @@ mymain(void)
DO_TEST(test26); DO_TEST(test26);
DO_TEST(test27); DO_TEST(test27);
DO_TEST(test28); DO_TEST(test28);
DO_TEST(test29);
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
} }