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

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



---
 tests/jsontest.c |  208 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 203 insertions(+), 5 deletions(-)

Changes in v3:
	* Fix conflict in jsontest.c

diff --git a/tests/jsontest.c b/tests/jsontest.c
index a37a980..a2ce184 100644
--- a/tests/jsontest.c
+++ b/tests/jsontest.c
@@ -4,15 +4,24 @@
 #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;
     const char *expect;
     bool pass;
+    size_t chunk;
 };
 
 
@@ -123,21 +132,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, expect, pass)                  \
+#define DO_TEST_FULL(name, cmd, doc, expect, pass, chunk)           \
     do {                                                            \
-        struct testInfo info = { doc, expect, pass };               \
+        struct testInfo info = { doc, expect, 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, NULL, true)
+    DO_TEST_FULL(name, FromString, doc, NULL, true, 0)
 
     DO_TEST_PARSE("Simple", "{\"return\": {}, \"id\": \"libvirt-1\"}");
     DO_TEST_PARSE("NotSoSimple", "{\"QMP\": {\"version\": {\"qemu\":"
@@ -178,9 +351,34 @@ mymain(void)
     DO_TEST_FULL("add and remove", AddRemove,
                  "{\"name\": \"sample\", \"value\": true}",
                  "{\"value\":true,\"newname\":\"foo\"}",
-                 true);
+                 true, 0);
     DO_TEST_FULL("add and remove", AddRemove,
-                 "[ 1 ]", NULL, false);
+                 "[ 1 ]", NULL, false, 0);
+
+
+#define DO_TEST_PARSE_STREAM(name, doc, chunk)          \
+    DO_TEST_FULL(name, FromStream, doc, NULL, 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]