]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
tests: Extend command test to transfer large data to process on multiple fds
authorStefan Berger <stefanb@linux.vnet.ibm.com>
Thu, 25 Jul 2019 18:22:10 +0000 (14:22 -0400)
committerDaniel P. Berrangé <berrange@redhat.com>
Fri, 26 Jul 2019 09:30:57 +0000 (10:30 +0100)
Add a test case to commandtest.c to test the transfer of data to a
process who received the read-end of pipes' file descriptors. Transfer
large (128 kb) byte streams.

Extend the commandhelper.c with support for --readfd <fd> command line
parameter and convert the data receive loop to use poll and receive data
on multiple file descriptors (up to 3) and read data into distinct buffers
that we grow while adding more (string) data.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
tests/commandhelper.c
tests/commandtest.c

index 32ebeeaef26e704a60369c3803eac49d3bde7b73..1312f3ee527c82c78e22d7e76e5d9a8c07e010d7 100644 (file)
@@ -23,6 +23,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/stat.h>
+#include <poll.h>
 
 #include "internal.h"
 #define NO_LIBVIRT
@@ -62,13 +63,27 @@ int main(int argc, char **argv) {
     char *cwd;
     FILE *log = fopen(abs_builddir "/commandhelper.log", "w");
     int ret = EXIT_FAILURE;
+    int readfds[3] = { STDIN_FILENO, };
+    int numreadfds = 1;
+    struct pollfd fds[3];
+    int numpollfds = 0;
+    char *buffers[3] = {NULL, NULL, NULL};
+    size_t buflen[3] = {0, 0, 0};
+    char c;
 
     if (!log)
         return ret;
 
-    for (i = 1; i < argc; i++)
+    for (i = 1; i < argc; i++) {
         fprintf(log, "ARG:%s\n", argv[i]);
 
+        if (STREQ(argv[i - 1], "--readfd") &&
+            sscanf(argv[i], "%u%c", &readfds[numreadfds++], &c) != 1) {
+            printf("Could not parse fd %s\n", argv[i]);
+            goto cleanup;
+        }
+    }
+
     origenv = environ;
     n = 0;
     while (*origenv != NULL) {
@@ -134,15 +149,56 @@ int main(int argc, char **argv) {
     fprintf(stderr, "BEGIN STDERR\n");
     fflush(stderr);
 
+    for (i = 0; i < numreadfds; i++) {
+        fds[numpollfds].fd = readfds[i];
+        fds[numpollfds].events = POLLIN;
+        fds[numpollfds].revents = 0;
+        numpollfds++;
+    }
+
     for (;;) {
-        got = read(STDIN_FILENO, buf, sizeof(buf));
-        if (got < 0)
+        unsigned ctr = 0;
+
+        if (poll(fds, numpollfds, -1) < 0) {
+            printf("poll failed: %s\n", strerror(errno));
             goto cleanup;
-        if (got == 0)
+        }
+
+        for (i = 0; i < numpollfds; i++) {
+            if (fds[i].revents & (POLLIN | POLLHUP | POLLERR)) {
+                fds[i].revents = 0;
+
+                got = read(fds[i].fd, buf, sizeof(buf));
+                if (got < 0)
+                    goto cleanup;
+                if (got == 0) {
+                    /* do not want to hear from this fd anymore */
+                    fds[i].events = 0;
+                } else {
+                    buffers[i] = realloc(buffers[i], buflen[i] + got);
+                    if (!buf[i]) {
+                        fprintf(stdout, "Out of memory!\n");
+                        goto cleanup;
+                    }
+                    memcpy(buffers[i] + buflen[i], buf, got);
+                    buflen[i] += got;
+                }
+            }
+        }
+        for (i = 0; i < numpollfds; i++) {
+            if (fds[i].events) {
+                ctr++;
+                break;
+            }
+        }
+        if (ctr == 0)
             break;
-        if (write(STDOUT_FILENO, buf, got) != got)
+    }
+
+    for (i = 0; i < numpollfds; i++) {
+        if (write(STDOUT_FILENO, buffers[i], buflen[i]) != buflen[i])
             goto cleanup;
-        if (write(STDERR_FILENO, buf, got) != got)
+        if (write(STDERR_FILENO, buffers[i], buflen[i]) != buflen[i])
             goto cleanup;
     }
 
@@ -154,6 +210,8 @@ int main(int argc, char **argv) {
     ret = EXIT_SUCCESS;
 
  cleanup:
+    for (i = 0; i < ARRAY_CARDINALITY(buffers); i++)
+        free(buffers[i]);
     fclose(log);
     free(newenv);
     return ret;
index ce0832fb0c67991588dd2799c02db73f4f16471d..991c0572b072ec26e601145e9103b2c45f3f6bec 100644 (file)
@@ -1139,6 +1139,118 @@ static int test26(const void *unused ATTRIBUTE_UNUSED)
     return ret;
 }
 
+static int test27(const void *unused ATTRIBUTE_UNUSED)
+{
+    virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
+    int pipe1[2];
+    int pipe2[2];
+    int ret = -1;
+    size_t buflen = 1024 * 128;
+    char *buffer0 = NULL;
+    char *buffer1 = NULL;
+    char *buffer2 = NULL;
+    char *outactual = NULL;
+    char *erractual = NULL;
+    char *outexpect = NULL;
+# define TEST27_OUTEXPECT_TEMP "BEGIN STDOUT\n" \
+        "%s%s%s" \
+        "END STDOUT\n"
+    char *errexpect = NULL;
+# define TEST27_ERREXPECT_TEMP "BEGIN STDERR\n" \
+        "%s%s%s" \
+        "END STDERR\n"
+
+    if (VIR_ALLOC_N(buffer0, buflen) < 0 ||
+        VIR_ALLOC_N(buffer1, buflen) < 0 ||
+        VIR_ALLOC_N(buffer2, buflen) < 0)
+        goto cleanup;
+
+    memset(buffer0, 'H', buflen - 2);
+    buffer0[buflen - 2] = '\n';
+    buffer0[buflen - 1] = 0;
+
+    memset(buffer1, '1', buflen - 2);
+    buffer1[buflen - 2] = '\n';
+    buffer1[buflen - 1] = 0;
+
+    memset(buffer2, '2', buflen - 2);
+    buffer2[buflen - 2] = '\n';
+    buffer2[buflen - 1] = 0;
+
+    if (virAsprintf(&outexpect, TEST27_OUTEXPECT_TEMP,
+                    buffer0, buffer1, buffer2) < 0 ||
+        virAsprintf(&errexpect, TEST27_ERREXPECT_TEMP,
+                    buffer0, buffer1, buffer2) < 0) {
+        printf("Could not virAsprintf expected output\n");
+        goto cleanup;
+    }
+
+    if (pipe(pipe1) < 0 || pipe(pipe2) < 0) {
+        printf("Could not create pipe: %s\n", strerror(errno));
+        goto cleanup;
+    }
+
+    if (virCommandSetSendBuffer(cmd, pipe1[1],
+            (unsigned char *)buffer1, buflen - 1)  < 0 ||
+        virCommandSetSendBuffer(cmd, pipe2[1],
+            (unsigned char *)buffer2, buflen - 1) < 0) {
+        printf("Could not set send buffers\n");
+        goto cleanup;
+    }
+    pipe1[1] = 0;
+    pipe2[1] = 0;
+    buffer1 = NULL;
+    buffer2 = NULL;
+
+    virCommandAddArg(cmd, "--readfd");
+    virCommandAddArgFormat(cmd, "%d", pipe1[0]);
+    virCommandPassFD(cmd, pipe1[0], 0);
+
+    virCommandAddArg(cmd, "--readfd");
+    virCommandAddArgFormat(cmd, "%d", pipe2[0]);
+    virCommandPassFD(cmd, pipe2[0], 0);
+
+    virCommandSetInputBuffer(cmd, buffer0);
+    virCommandSetOutputBuffer(cmd, &outactual);
+    virCommandSetErrorBuffer(cmd, &erractual);
+
+    if (virCommandRun(cmd, NULL) < 0) {
+        printf("Cannot run child %s\n", virGetLastErrorMessage());
+        goto cleanup;
+    }
+
+    virCommandFree(cmd);
+
+    if (!outactual || !erractual)
+        goto cleanup;
+
+    if (STRNEQ(outactual, outexpect)) {
+        virTestDifference(stderr, outexpect, outactual);
+        goto cleanup;
+    }
+    if (STRNEQ(erractual, errexpect)) {
+        virTestDifference(stderr, errexpect, erractual);
+        goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+    VIR_FORCE_CLOSE(pipe1[0]);
+    VIR_FORCE_CLOSE(pipe2[0]);
+    VIR_FORCE_CLOSE(pipe1[1]);
+    VIR_FORCE_CLOSE(pipe2[1]);
+    VIR_FREE(buffer0);
+    VIR_FREE(buffer1);
+    VIR_FREE(buffer2);
+    VIR_FREE(outactual);
+    VIR_FREE(erractual);
+    VIR_FREE(outexpect);
+    VIR_FREE(errexpect);
+
+    return ret;
+}
+
 static void virCommandThreadWorker(void *opaque)
 {
     virCommandTestDataPtr test = opaque;
@@ -1292,6 +1404,7 @@ mymain(void)
     DO_TEST(test23);
     DO_TEST(test25);
     DO_TEST(test26);
+    DO_TEST(test27);
 
     virMutexLock(&test->lock);
     if (test->running) {