fdstreamtest.c 9.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
/*
 * Copyright (C) 2013 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library;  If not, see
 * <http://www.gnu.org/licenses/>.
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>

#include <stdlib.h>
#include <fcntl.h>

#include "testutils.h"

28
#include "virfdstream.h"
29 30 31 32 33 34 35 36 37 38
#include "datatypes.h"
#include "virerror.h"
#include "viralloc.h"
#include "virlog.h"
#include "virstring.h"
#include "virfile.h"
#include "virutil.h"

#define VIR_FROM_THIS VIR_FROM_NONE

39 40
VIR_LOG_INIT("tests.fdstreamtest");

41 42 43 44 45
#define PATTERN_LEN 256

static int testFDStreamReadCommon(const char *scratchdir, bool blocking)
{
    int fd = -1;
46
    char *file = NULL;
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
    int ret = -1;
    char *pattern = NULL;
    char *buf = NULL;
    virStreamPtr st = NULL;
    size_t i;
    virConnectPtr conn = NULL;
    int flags = 0;

    if (!blocking)
        flags |= VIR_STREAM_NONBLOCK;

    if (!(conn = virConnectOpen("test:///default")))
        goto cleanup;

    if (VIR_ALLOC_N(pattern, PATTERN_LEN) < 0 ||
        VIR_ALLOC_N(buf, PATTERN_LEN) < 0)
        goto cleanup;

65
    for (i = 0; i < PATTERN_LEN; i++)
66 67
        pattern[i] = i;

68
    if (virAsprintf(&file, "%s/input.data", scratchdir) < 0)
69 70
        goto cleanup;

71
    if ((fd = open(file, O_CREAT|O_WRONLY|O_EXCL, 0600)) < 0)
72 73
        goto cleanup;

74
    for (i = 0; i < 10; i++) {
75 76 77 78 79 80 81 82 83 84 85 86 87
        if (safewrite(fd, pattern, PATTERN_LEN) != PATTERN_LEN)
            goto cleanup;
    }

    if (VIR_CLOSE(fd) < 0)
        goto cleanup;

    if (!(st = virStreamNew(conn, flags)))
        goto cleanup;

    /* Start reading 1/2 way through first pattern
     * and end 1/2 way through last pattern
     */
88
    if (virFDStreamOpenFile(st, file,
89 90 91 92
                            PATTERN_LEN / 2, PATTERN_LEN * 9,
                            O_RDONLY) < 0)
        goto cleanup;

93
    for (i = 0; i < 10; i++) {
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
        size_t offset = 0;
        size_t want;
        if (i == 0)
            want = PATTERN_LEN / 2;
        else
            want = PATTERN_LEN;

        while (want > 0) {
            int got;
        reread:
            got = st->driver->streamRecv(st, buf + offset, want);
            if (got < 0) {
                if (got == -2 && !blocking) {
                    usleep(20 * 1000);
                    goto reread;
                }
110 111
                virFilePrintf(stderr, "Failed to read stream: %s\n",
                              virGetLastErrorMessage());
112 113 114 115 116 117
                goto cleanup;
            }
            if (got == 0) {
                /* Expect EOF 1/2 through last pattern */
                if (i == 9 && want == (PATTERN_LEN / 2))
                    break;
118 119
                virFilePrintf(stderr, "Unexpected EOF block %zu want %zu\n",
                              i, want);
120 121 122 123 124 125 126
                goto cleanup;
            }
            offset += got;
            want -= got;
        }
        if (i == 0) {
            if (memcmp(buf, pattern + (PATTERN_LEN / 2), PATTERN_LEN / 2) != 0) {
127
                virFilePrintf(stderr, "Mismatched pattern data iteration %zu\n", i);
128 129 130 131
                goto cleanup;
            }
        } else if (i == 9) {
            if (memcmp(buf, pattern, PATTERN_LEN / 2) != 0) {
132
                virFilePrintf(stderr, "Mismatched pattern data iteration %zu\n", i);
133 134 135 136
                goto cleanup;
            }
        } else {
            if (memcmp(buf, pattern, PATTERN_LEN) != 0) {
137
                virFilePrintf(stderr, "Mismatched pattern data iteration %zu\n", i);
138 139 140 141 142 143
                goto cleanup;
            }
        }
    }

    if (st->driver->streamFinish(st) != 0) {
144 145
        virFilePrintf(stderr, "Failed to finish stream: %s\n",
                      virGetLastErrorMessage());
146 147 148 149
        goto cleanup;
    }

    ret = 0;
150
 cleanup:
151 152 153
    if (st)
        virStreamFree(st);
    VIR_FORCE_CLOSE(fd);
154 155
    if (file != NULL)
        unlink(file);
156 157
    if (conn)
        virConnectClose(conn);
158
    VIR_FREE(file);
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
    VIR_FREE(pattern);
    VIR_FREE(buf);
    return ret;
}


static int testFDStreamReadBlock(const void *data)
{
    return testFDStreamReadCommon(data, true);
}
static int testFDStreamReadNonblock(const void *data)
{
    return testFDStreamReadCommon(data, false);
}


static int testFDStreamWriteCommon(const char *scratchdir, bool blocking)
{
    int fd = -1;
178
    char *file = NULL;
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
    int ret = -1;
    char *pattern = NULL;
    char *buf = NULL;
    virStreamPtr st = NULL;
    size_t i;
    virConnectPtr conn = NULL;
    int flags = 0;

    if (!blocking)
        flags |= VIR_STREAM_NONBLOCK;

    if (!(conn = virConnectOpen("test:///default")))
        goto cleanup;

    if (VIR_ALLOC_N(pattern, PATTERN_LEN) < 0 ||
        VIR_ALLOC_N(buf, PATTERN_LEN) < 0)
        goto cleanup;

197
    for (i = 0; i < PATTERN_LEN; i++)
198 199
        pattern[i] = i;

200
    if (virAsprintf(&file, "%s/input.data", scratchdir) < 0)
201 202 203 204 205 206 207 208
        goto cleanup;

    if (!(st = virStreamNew(conn, flags)))
        goto cleanup;

    /* Start writing 1/2 way through first pattern
     * and end 1/2 way through last pattern
     */
209
    if (virFDStreamCreateFile(st, file,
210 211 212 213
                              PATTERN_LEN / 2, PATTERN_LEN * 9,
                              O_WRONLY, 0600) < 0)
        goto cleanup;

214
    for (i = 0; i < 10; i++) {
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
        size_t offset = 0;
        size_t want;
        if (i == 0)
            want = PATTERN_LEN / 2;
        else
            want = PATTERN_LEN;

        while (want > 0) {
            int got;
        rewrite:
            got = st->driver->streamSend(st, pattern + offset, want);
            if (got < 0) {
                if (got == -2 && !blocking) {
                    usleep(20 * 1000);
                    goto rewrite;
                }
                if (i == 9 &&
                    want == (PATTERN_LEN / 2))
                    break;
234 235
                virFilePrintf(stderr, "Failed to write stream: %s\n",
                              virGetLastErrorMessage());
236 237 238 239 240 241 242 243
                goto cleanup;
            }
            offset += got;
            want -= got;
        }
    }

    if (st->driver->streamFinish(st) != 0) {
244 245
        virFilePrintf(stderr, "Failed to finish stream: %s\n",
                      virGetLastErrorMessage());
246 247 248
        goto cleanup;
   }

249
    if ((fd = open(file, O_RDONLY)) < 0)
250 251
        goto cleanup;

252
    for (i = 0; i < 10; i++) {
253 254 255 256 257 258 259
        size_t want;
        if (i == 9)
            want = PATTERN_LEN / 2;
        else
            want = PATTERN_LEN;

        if (saferead(fd, buf, want) != want) {
260
            virFilePrintf(stderr, "Short read from data\n");
261 262 263 264 265
            goto cleanup;
        }

        if (i == 0) {
            size_t j;
266
            for (j = 0; j < (PATTERN_LEN / 2); j++) {
267
                if (buf[j] != 0) {
268
                    virFilePrintf(stderr, "Mismatched pattern data iteration %zu\n", i);
269 270 271 272
                    goto cleanup;
                }
            }
            if (memcmp(buf + (PATTERN_LEN / 2), pattern, PATTERN_LEN / 2) != 0) {
273
                virFilePrintf(stderr, "Mismatched pattern data iteration %zu\n", i);
274 275 276 277
                goto cleanup;
            }
        } else if (i == 9) {
            if (memcmp(buf, pattern, PATTERN_LEN / 2) != 0) {
278
                virFilePrintf(stderr, "Mismatched pattern data iteration %zu\n", i);
279 280 281 282
                goto cleanup;
            }
        } else {
            if (memcmp(buf, pattern, PATTERN_LEN) != 0) {
283
                virFilePrintf(stderr, "Mismatched pattern data iteration %zu\n", i);
284 285 286 287 288 289 290 291 292
                goto cleanup;
            }
        }
    }

    if (VIR_CLOSE(fd) < 0)
        goto cleanup;

    ret = 0;
293
 cleanup:
294 295 296
    if (st)
        virStreamFree(st);
    VIR_FORCE_CLOSE(fd);
297 298
    if (file != NULL)
        unlink(file);
299 300
    if (conn)
        virConnectClose(conn);
301
    VIR_FREE(file);
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
    VIR_FREE(pattern);
    VIR_FREE(buf);
    return ret;
}


static int testFDStreamWriteBlock(const void *data)
{
    return testFDStreamWriteCommon(data, true);
}
static int testFDStreamWriteNonblock(const void *data)
{
    return testFDStreamWriteCommon(data, false);
}

M
Michal Privoznik 已提交
317
#define SCRATCHDIRTEMPLATE abs_builddir "/fdstreamdir-XXXXXX"
318 319 320 321 322 323 324 325

static int
mymain(void)
{
    char scratchdir[] = SCRATCHDIRTEMPLATE;
    int ret = 0;

    if (!mkdtemp(scratchdir)) {
M
Michal Privoznik 已提交
326
        virFilePrintf(stderr, "Cannot create fdstreamdir");
327 328 329
        abort();
    }

330
    if (virTestRun("Stream read blocking ", testFDStreamReadBlock, scratchdir) < 0)
331
        ret = -1;
332
    if (virTestRun("Stream read non-blocking ", testFDStreamReadNonblock, scratchdir) < 0)
333
        ret = -1;
334
    if (virTestRun("Stream write blocking ", testFDStreamWriteBlock, scratchdir) < 0)
335
        ret = -1;
336
    if (virTestRun("Stream write non-blocking ", testFDStreamWriteNonblock, scratchdir) < 0)
337 338 339 340 341 342 343 344
        ret = -1;

    if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL)
        virFileDeleteTree(scratchdir);

    return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}

345
VIR_TEST_MAIN(mymain)