[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH v2 2/2] json: add test for virJSONValueFromStream function



Signed-off-by: Dmitry Guryanov <dguryanov parallels com>
---
 tests/jsontest.c |  205 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 201 insertions(+), 4 deletions(-)

diff --git a/tests/jsontest.c b/tests/jsontest.c
index 98a6069..107d772 100644
--- a/tests/jsontest.c
+++ b/tests/jsontest.c
@@ -4,14 +4,23 @@
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include <unistd.h>
+#include <poll.h>
+#include <signal.h>
+#include <sched.h>
 
 #include "internal.h"
 #include "virjson.h"
 #include "testutils.h"
+#include "vircommand.h"
+#include "virprocess.h"
+#include "virtime.h"
+#include "virfile.h"
 
 struct testInfo {
     const char *doc;
     bool pass;
+    size_t chunk;
 };
 
 
@@ -53,21 +62,185 @@ cleanup:
     return ret;
 }
 
+ATTRIBUTE_NORETURN static int
+testJSONReadProcess(int fd, int finishFd)
+{
+    int n = 0;
+    int exitcode = EXIT_FAILURE;
+    virJSONValuePtr v;
+    virJSONStreamParserState state;
+    int x;
+
+    if (safewrite(finishFd, " ", 1) != 1) {
+        if (virTestGetVerbose())
+            perror("write");
+        _exit(exitcode);
+    }
+    /* There must be exactly two objects, each must have "valid"
+     * field with integer value */
+
+    memset(&state, 0, sizeof(state));
+    while (1) {
+        v = virJSONValueFromStream(fd, &state);
+
+        if (v == (void *)-1) {
+            if (virTestGetVerbose())
+                fprintf(stderr, "virJSONValueFromStream returned error\n");
+            goto cleanup;
+        }
+
+        if (v == 0)
+            break;
+
+        n++;
+
+        if (virJSONValueObjectGetNumberInt(v, "valid", &x) < 0) {
+            if (virTestGetVerbose())
+                fprintf(stderr, "Parsed value in object %d doesn't have "
+                    "'valid' integer field\n", n);
+            goto cleanup;
+        }
+    }
+
+    if (n != 2) {
+        if (virTestGetVerbose())
+            fprintf(stderr, "Invalid number of objects: %d, must be 2\n", n);
+    } else {
+        exitcode = EXIT_SUCCESS;
+    }
+
+cleanup:
+    if (safewrite(finishFd, " ", 1) != 1) {
+        if (virTestGetVerbose())
+            perror("write");
+        _exit(exitcode);
+    }
+
+    VIR_FORCE_CLOSE(fd);
+    VIR_FORCE_CLOSE(finishFd);
+    _exit(exitcode);
+}
+
+/*
+ * This test creates a separate process, which reads JSON data
+ * from a pipe with help of virJSONValueFromStream function. It expects
+ * 2 objects, each must have 'valid' integer key. Parent process writes
+ * data to the pipe and handles child exit code.
+ */
+static int
+testJSONFromStream(const void *data)
+{
+    struct testInfo *info = (struct testInfo *)data;
+    int ret = -1;
+    int pret;
+    int pipefd[2];
+    int wpipefd[2];
+    ssize_t w;
+    pid_t pid;
+    struct pollfd pollfd;
+    int status;
+    size_t docLen, i;
+    char c;
+
+    if (pipe(pipefd) < 0) {
+        if (virTestGetVerbose())
+            perror("pipe");
+        return -1;
+    }
+
+    if (pipe(wpipefd) < 0) {
+        if (virTestGetVerbose())
+            perror("pipe");
+        goto cleanup;
+    }
+
+    if (virFork(&pid) < 0) {
+        if (virTestGetVerbose())
+            perror("fork");
+        goto cleanup2;
+    }
+
+    if (pid == 0) {
+        VIR_FORCE_CLOSE(pipefd[1]);
+        VIR_FORCE_CLOSE(wpipefd[0]);
+        testJSONReadProcess(pipefd[0], wpipefd[1]);
+        /* couldn't be reached */
+    }
+
+    /* write test data */
+    docLen = strlen(info->doc);
+
+    if (read(wpipefd[0], &c, 1) < 0) {
+        if (virTestGetVerbose())
+            perror("read");
+        goto cleanup2;
+    }
+
+    for (i = 0; i < docLen; i += info->chunk) {
+        size_t len = i + info->chunk <= docLen ? info->chunk : docLen % info->chunk;
+
+        w = safewrite(pipefd[1], info->doc + i * info->chunk, len);
+        if (w < 0) {
+            if (virTestGetVerbose())
+                perror("write");
+            goto cleanup2;
+        }
+
+        if (w < len) {
+            if (virTestGetVerbose())
+                fprintf(stderr, "Couldn't write entire json string to the pipe\n");
+            goto cleanup2;
+        }
+
+        sched_yield();
+    }
+
+    VIR_FORCE_CLOSE(pipefd[1]);
+
+    /* wait for read process */
+    pollfd.fd = wpipefd[0];
+    pollfd.events = POLLIN;
+
+    pret = poll(&pollfd, 1, 1000);
+    if (pret < 0) {
+        if (virTestGetVerbose())
+            perror("poll");
+        goto cleanup2;
+    }
+
+    if (pret == 0) {
+        if (virTestGetVerbose())
+            fprintf(stderr, "timeout reached\n");
+        virProcessKill(pid, SIGTERM);
+    }
+
+    if (virProcessWait(pid, &status) == 0 && !WIFSIGNALED(status)
+        && WEXITSTATUS(status) == 0)
+            ret = 0;
+
+cleanup2:
+    VIR_FORCE_CLOSE(wpipefd[0]);
+    VIR_FORCE_CLOSE(wpipefd[1]);
+cleanup:
+    VIR_FORCE_CLOSE(pipefd[0]);
+    VIR_FORCE_CLOSE(pipefd[1]);
+    return ret;
+}
 
 static int
 mymain(void)
 {
     int ret = 0;
 
-#define DO_TEST_FULL(name, cmd, doc, pass)                          \
+#define DO_TEST_FULL(name, cmd, doc, pass, chunk)                   \
     do {                                                            \
-        struct testInfo info = { doc, pass };                       \
+        struct testInfo info = { doc, pass, chunk };                \
         if (virtTestRun(name, 1, testJSON ## cmd, &info) < 0)       \
             ret = -1;                                               \
     } while (0)
 
 #define DO_TEST_PARSE(name, doc)                \
-    DO_TEST_FULL(name, FromString, doc, true)
+    DO_TEST_FULL(name, FromString, doc, true, 0)
 
     DO_TEST_PARSE("Simple", "{\"return\": {}, \"id\": \"libvirt-1\"}");
     DO_TEST_PARSE("NotSoSimple", "{\"QMP\": {\"version\": {\"qemu\":"
@@ -105,6 +278,30 @@ mymain(void)
                   "\"query-uuid\"}, {\"name\": \"query-migrate\"}, {\"name\": "
                   "\"query-balloon\"}], \"id\": \"libvirt-2\"}");
 
+#define DO_TEST_PARSE_STREAM(name, doc, chunk)          \
+    DO_TEST_FULL(name, FromStream, doc, true, chunk)
+
+    DO_TEST_PARSE_STREAM("StreamSimple", "{\"valid\": 10}{\"valid\": 10}", 1);
+
+    char *largeText;
+    size_t largeTextSize = 8192;
+    size_t pos = 0;
+
+    if (VIR_ALLOC_N(largeText, largeTextSize) < 0)
+        return EXIT_FAILURE;
+
+    memset(largeText, 0, largeTextSize);
+    pos += snprintf(largeText + pos, 64, "{");
+    while (pos < largeTextSize / 2 - 100)
+        pos += snprintf(largeText + pos, 64, "\"x%ld\": %ld, ", pos, pos);
+    pos += snprintf(largeText + pos, 64, "\"valid\": 1}");
+    pos += snprintf(largeText + pos, strlen(largeText) + 1, "%s", largeText);
+
+    DO_TEST_PARSE_STREAM("StreamLargeChunks", largeText, largeTextSize);
+    DO_TEST_PARSE_STREAM("StreamSmallChunks", largeText, 1);
+
+    VIR_FREE(largeText);
+
     return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
-- 
1.7.1


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]