Signed-off-by: Dmitry Guryanov <dguryanov@xxxxxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list