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(a)redhat.com>
---
tests/commanddata/test29.log | 20 ++++++++
tests/commandtest.c | 97 ++++++++++++++++++++++++++++++++++++
2 files changed, 117 insertions(+)
create mode 100644 tests/commanddata/test29.log
diff --git a/tests/commanddata/test29.log b/tests/commanddata/test29.log
new file mode 100644
index 0000000000..962f8526f1
--- /dev/null
+++ b/tests/commanddata/test29.log
@@ -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
diff --git a/tests/commandtest.c b/tests/commandtest.c
index 8c5a9245a1..6d45ff196f 100644
--- a/tests/commandtest.c
+++ b/tests/commandtest.c
@@ -25,6 +25,7 @@
#include <sys/stat.h>
#ifndef WIN32
# include <sys/wait.h>
+# include <poll.h>
#endif
#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
mymain(void)
{
@@ -1252,6 +1348,7 @@ mymain(void)
DO_TEST(test26);
DO_TEST(test27);
DO_TEST(test28);
+ DO_TEST(test29);
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
--
2.37.4