[libvirt] [PATCH v7 14/19] tests: Extend command test to transfer large data to process on multiple fds

John Ferlan jferlan at redhat.com
Fri Jul 26 10:46:05 UTC 2019



On 7/25/19 2:22 PM, Stefan Berger wrote:
> 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 at linux.ibm.com>
> Reviewed-by: Daniel P. Berrangé <berrange at redhat.com>
> ---
>  tests/commandhelper.c |  70 +++++++++++++++++++++++---
>  tests/commandtest.c   | 113 ++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 177 insertions(+), 6 deletions(-)
> 

[...]

> diff --git a/tests/commandtest.c b/tests/commandtest.c
> index ce0832fb0c..991c0572b0 100644
> --- a/tests/commandtest.c
> +++ b/tests/commandtest.c
> @@ -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);

This should be in the cleanup section; otherwise, Coverity considers
@cmd as leaked for any other path above where @cmd is allocated and we
go to cleanup.

John

> +
> +    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) {
> 




More information about the libvir-list mailing list