testutils.c 12.6 KB
Newer Older
K
Karel Zak 已提交
1
/*
2
 * testutils.c: basic test utils
K
Karel Zak 已提交
3
 *
4
 * Copyright (C) 2005-2009 Red Hat, Inc.
K
Karel Zak 已提交
5 6 7 8 9 10
 *
 * See COPYING.LIB for the License of this software
 *
 * Karel Zak <kzak@redhat.com>
 */

11
#include <config.h>
12

K
Karel Zak 已提交
13 14 15
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
16 17
#include <sys/types.h>
#include <sys/stat.h>
A
Atsushi SAKAI 已提交
18
#ifndef WIN32
19
#include <sys/wait.h>
A
Atsushi SAKAI 已提交
20
#endif
21
#ifdef HAVE_REGEX_H
22
#include <regex.h>
23
#endif
24
#include <unistd.h>
25
#include <string.h>
26 27
#include <fcntl.h>
#include <limits.h>
K
Karel Zak 已提交
28
#include "testutils.h"
29
#include "internal.h"
30 31
#include "memory.h"
#include "util.h"
32 33
#include "threads.h"
#include "virterror_internal.h"
34 35 36 37

#if TEST_OOM_TRACE
#include <execinfo.h>
#endif
K
Karel Zak 已提交
38

39 40 41 42
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif

K
Karel Zak 已提交
43
#define GETTIMEOFDAY(T) gettimeofday(T, NULL)
44 45 46
#define DIFF_MSEC(T, U)                                 \
    ((((int) ((T)->tv_sec - (U)->tv_sec)) * 1000000.0 +	\
      ((int) ((T)->tv_usec - (U)->tv_usec))) / 1000.0)
K
Karel Zak 已提交
47

48
static unsigned int testDebug = -1;
49

50 51 52
static unsigned int testOOM = 0;
static unsigned int testCounter = 0;

K
Karel Zak 已提交
53 54 55
double
virtTestCountAverage(double *items, int nitems)
{
56 57
    long double sum = 0;
    int i;
K
Karel Zak 已提交
58

59 60
    for (i=1; i < nitems; i++)
        sum += items[i];
K
Karel Zak 已提交
61

62
    return (double) (sum / nitems);
K
Karel Zak 已提交
63 64
}

65
/*
K
Karel Zak 已提交
66
 * Runs test and count average time (if the nloops is grater than 1)
67 68
 *
 * returns: -1 = error, 0 = success
K
Karel Zak 已提交
69 70
 */
int
71
virtTestRun(const char *title, int nloops, int (*body)(const void *data), const void *data)
K
Karel Zak 已提交
72
{
73 74
    int i, ret = 0;
    double *ts = NULL;
75

76
    testCounter++;
77

78 79 80 81
    if (testOOM < 2) {
        fprintf(stderr, "%2d) %-65s ... ", testCounter, title);
        fflush(stderr);
    }
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98

    if (nloops > 1 && (ts = calloc(nloops,
                                   sizeof(double)))==NULL)
        return -1;

    for (i=0; i < nloops; i++) {
        struct timeval before, after;

        if (ts)
            GETTIMEOFDAY(&before);
        if ((ret = body(data)) != 0)
            break;
        if (ts)	{
            GETTIMEOFDAY(&after);
            ts[i] = DIFF_MSEC(&after, &before);
        }
    }
99 100 101 102 103 104 105 106 107
    if (testOOM < 2) {
        if (ret == 0 && ts)
            fprintf(stderr, "OK     [%.5f ms]\n",
                    virtTestCountAverage(ts, nloops));
        else if (ret == 0)
            fprintf(stderr, "OK\n");
        else
            fprintf(stderr, "FAILED\n");
    }
108

109
    free(ts);
110
    return ret;
K
Karel Zak 已提交
111
}
112

113 114 115 116 117
/* Read FILE into buffer BUF of length BUFLEN.
   Upon any failure, or if FILE appears to contain more than BUFLEN bytes,
   diagnose it and return -1, but don't bother trying to preserve errno.
   Otherwise, return the number of bytes read (and copied into BUF).  */
int virtTestLoadFile(const char *file,
118 119
                     char **buf,
                     int buflen) {
120
    FILE *fp = fopen(file, "r");
121
    struct stat st;
122

123 124
    if (!fp) {
        fprintf (stderr, "%s: failed to open: %s\n", file, strerror(errno));
125
        return -1;
126
    }
127 128

    if (fstat(fileno(fp), &st) < 0) {
129
        fprintf (stderr, "%s: failed to fstat: %s\n", file, strerror(errno));
130 131 132 133 134
        fclose(fp);
        return -1;
    }

    if (st.st_size > (buflen-1)) {
135
        fprintf (stderr, "%s: larger than buffer (> %d)\n", file, buflen-1);
136 137 138 139
        fclose(fp);
        return -1;
    }

140 141
    if (st.st_size) {
        if (fread(*buf, st.st_size, 1, fp) != 1) {
142
            fprintf (stderr, "%s: read failed: %s\n", file, strerror(errno));
143 144 145
            fclose(fp);
            return -1;
        }
146 147 148 149 150 151 152
    }
    (*buf)[st.st_size] = '\0';

    fclose(fp);
    return st.st_size;
}

A
Atsushi SAKAI 已提交
153
#ifndef WIN32
154 155
static
void virtTestCaptureProgramExecChild(const char *const argv[],
156 157 158 159 160 161
                                     int pipefd) {
    int i;
    int open_max;
    int stdinfd = -1;
    const char *const env[] = {
        "LANG=C",
162 163 164
#if WITH_DRIVER_MODULES
        "LIBVIRT_DRIVER_DIR=" TEST_DRIVER_DIR,
#endif
165 166 167
        NULL
    };

168
    if ((stdinfd = open("/dev/null", O_RDONLY)) < 0)
169 170 171 172 173 174 175 176 177 178 179 180 181
        goto cleanup;

    open_max = sysconf (_SC_OPEN_MAX);
    for (i = 0; i < open_max; i++) {
        if (i != stdinfd &&
            i != pipefd)
            close(i);
    }

    if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO)
        goto cleanup;
    if (dup2(pipefd, STDOUT_FILENO) != STDOUT_FILENO)
        goto cleanup;
182
    if (dup2(pipefd, STDERR_FILENO) != STDERR_FILENO)
183 184 185 186
        goto cleanup;

    /* SUS is crazy here, hence the cast */
    execve(argv[0], (char *const*)argv, (char *const*)env);
187 188

 cleanup:
189 190
    if (stdinfd != -1)
        close(stdinfd);
191 192 193
}

int virtTestCaptureProgramOutput(const char *const argv[],
194 195 196 197 198 199 200 201 202
                                 char **buf,
                                 int buflen) {
    int pipefd[2];

    if (pipe(pipefd) < 0)
        return -1;

    int pid = fork();
    switch (pid) {
203 204
    case 0:
        close(pipefd[0]);
205 206 207 208 209
        virtTestCaptureProgramExecChild(argv, pipefd[1]);

        close(pipefd[1]);
        _exit(1);

210 211
    case -1:
        return -1;
212

213
    default:
214 215 216 217
        {
            int got = 0;
            int ret = -1;
            int want = buflen-1;
218

219
            close(pipefd[1]);
220

221 222 223 224 225 226 227
            while (want) {
                if ((ret = read(pipefd[0], (*buf)+got, want)) <= 0)
                    break;
                got += ret;
                want -= ret;
            }
            close(pipefd[0]);
228

229 230
            if (!ret)
                (*buf)[got] = '\0';
231

232
            waitpid(pid, NULL, 0);
233

234 235 236
            return ret;
        }
    }
237
}
A
Atsushi SAKAI 已提交
238
#endif /* !WIN32 */
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257


/**
 * @param stream: output stream write to differences to
 * @param expect: expected output text
 * @param actual: actual output text
 *
 * Display expected and actual output text, trimmed to
 * first and last characters at which differences occur
 */
int virtTestDifference(FILE *stream,
                       const char *expect,
                       const char *actual)
{
    const char *expectStart = expect;
    const char *expectEnd = expect + (strlen(expect)-1);
    const char *actualStart = actual;
    const char *actualEnd = actual + (strlen(actual)-1);

258
    if (!virtTestGetDebug())
259 260
        return 0;

261
    if (virtTestGetDebug() < 2) {
262 263 264 265 266 267
        /* Skip to first character where they differ */
        while (*expectStart && *actualStart &&
               *actualStart == *expectStart) {
            actualStart++;
            expectStart++;
        }
268

269 270 271 272 273 274 275
        /* Work backwards to last character where they differ */
        while (actualEnd > actualStart &&
               expectEnd > expectStart &&
               *actualEnd == *expectEnd) {
            actualEnd--;
            expectEnd--;
        }
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
    }

    /* Show the trimmed differences */
    fprintf(stream, "\nExpect [");
    if ((expectEnd - expectStart + 1) &&
        fwrite(expectStart, (expectEnd-expectStart+1), 1, stream) != 1)
        return -1;
    fprintf(stream, "]\n");
    fprintf(stream, "Actual [");
    if ((actualEnd - actualStart + 1) &&
        fwrite(actualStart, (actualEnd-actualStart+1), 1, stream) != 1)
        return -1;
    fprintf(stream, "]\n");

    /* Pad to line up with test name ... in virTestRun */
    fprintf(stream, "                                                                      ... ");

    return 0;
}
295

296
#if TEST_OOM
297 298 299 300
static void
virtTestErrorFuncQuiet(void *data ATTRIBUTE_UNUSED,
                       virErrorPtr err ATTRIBUTE_UNUSED)
{ }
301
#endif
302

303
#if TEST_OOM_TRACE
304
static void
305
virtTestErrorHook(int n, void *data ATTRIBUTE_UNUSED)
306 307 308 309 310 311 312 313 314
{
    void *trace[30];
    int ntrace = ARRAY_CARDINALITY(trace);
    int i;
    char **symbols = NULL;

    ntrace = backtrace(trace, ntrace);
    symbols = backtrace_symbols(trace, ntrace);
    if (symbols) {
315
        fprintf(stderr, "Failing allocation %d at:\n", n);
316 317 318 319 320 321 322
        for (i = 0 ; i < ntrace ; i++) {
            if (symbols[i])
                fprintf(stderr, "  TRACE:  %s\n", symbols[i]);
        }
        free(symbols);
    }
}
323
#endif
324

325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
unsigned int
virtTestGetDebug() {
    char *debugStr;
    unsigned int debug;

    if (testDebug != -1)
        return testDebug;

    testDebug = 0;

    if ((debugStr = getenv("VIR_TEST_DEBUG")) == NULL)
        return 0;

    if (virStrToLong_ui(debugStr, NULL, 10, &debug) < 0)
        return 0;

    testDebug = debug;
    return testDebug;
}
344 345 346 347 348 349

int virtTestMain(int argc,
                 char **argv,
                 int (*func)(int, char **))
{
    int ret;
350
#if TEST_OOM
351 352
    int approxAlloc = 0;
    int n;
353
    char *oomStr = NULL;
354
    int oomCount;
355 356 357
    int mp = 0;
    pid_t *workers;
    int worker = 0;
358 359
#endif

360
    if (virThreadInitialize() < 0 ||
361 362
        virErrorInitialize() < 0 ||
        virRandomInitialize(time(NULL) ^ getpid()))
363 364
        return 1;

365

366
#if TEST_OOM
367 368 369 370 371 372 373 374 375 376
    if ((oomStr = getenv("VIR_TEST_OOM")) != NULL) {
        if (virStrToLong_i(oomStr, NULL, 10, &oomCount) < 0)
            oomCount = 0;

        if (oomCount < 0)
            oomCount = 0;
        if (oomCount)
            testOOM = 1;
    }

377 378 379
    if (getenv("VIR_TEST_MP") != NULL) {
        mp = sysconf(_SC_NPROCESSORS_ONLN);
        fprintf(stderr, "Using %d worker processes\n", mp);
380 381 382 383
        if (VIR_ALLOC_N(workers, mp) < 0) {
            ret = EXIT_FAILURE;
            goto cleanup;
        }
384 385
    }

D
Daniel P. Berrange 已提交
386
    /* Run once to prime any static allocations & ensure it passes */
387 388
    ret = (func)(argc, argv);
    if (ret != EXIT_SUCCESS)
389
        goto cleanup;
390

391
#if TEST_OOM_TRACE
392
    if (virtTestGetDebug())
393
        virAllocTestHook(virtTestErrorHook, NULL);
394
#endif
395 396 397 398 399 400

    if (testOOM) {
        /* Makes next test runs quiet... */
        testOOM++;
        virSetErrorFunc(NULL, virtTestErrorFuncQuiet);

D
Daniel P. Berrange 已提交
401 402 403 404 405 406 407
        virAllocTestInit();

        /* Run again to count allocs, and ensure it passes :-) */
        ret = (func)(argc, argv);
        if (ret != EXIT_SUCCESS)
            goto cleanup;

408 409
        approxAlloc = virAllocTestCount();
        testCounter++;
410
        if (virtTestGetDebug())
411 412 413 414
            fprintf(stderr, "%d) OOM...\n", testCounter);
        else
            fprintf(stderr, "%d) OOM of %d allocs ", testCounter, approxAlloc);

415 416 417 418 419 420 421 422 423 424 425
        if (mp) {
            int i;
            for (i = 0 ; i < mp ; i++) {
                workers[i] = fork();
                if (workers[i] == 0) {
                    worker = i + 1;
                    break;
                }
            }
        }

426 427
        /* Run once for each alloc, failing a different one
           and validating that the test case failed */
428
        for (n = 0; n < approxAlloc && (!mp || worker) ; n++) {
429 430
            if (mp &&
                (n % mp) != (worker - 1))
431
                continue;
432
            if (!virtTestGetDebug()) {
433 434 435 436
                if (mp)
                    fprintf(stderr, "%d", worker);
                else
                    fprintf(stderr, ".");
437 438 439 440 441 442 443 444 445 446
                fflush(stderr);
            }
            virAllocTestOOM(n+1, oomCount);

            if (((func)(argc, argv)) != EXIT_FAILURE) {
                ret = EXIT_FAILURE;
                break;
            }
        }

447 448 449 450 451 452 453 454 455 456 457 458 459 460
        if (mp) {
            if (worker) {
                _exit(ret);
            } else {
                int i, status;
                for (i = 0 ; i < mp ; i++) {
                    waitpid(workers[i], &status, 0);
                    if (WEXITSTATUS(status) != EXIT_SUCCESS)
                        ret = EXIT_FAILURE;
                }
                VIR_FREE(workers);
            }
        }

461
        if (virtTestGetDebug())
462 463 464 465 466 467 468
            fprintf(stderr, " ... OOM of %d allocs", approxAlloc);

        if (ret == EXIT_SUCCESS)
            fprintf(stderr, " OK\n");
        else
            fprintf(stderr, " FAILED\n");
    }
469
cleanup:
470
#else
471
    ret = (func)(argc, argv);
472
#endif
473 474 475

    virResetLastError();
    return ret;
476
}
477 478


479
#ifdef HAVE_REGEX_H
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
int virtTestClearLineRegex(const char *pattern,
                           char *str)
{
    regex_t reg;
    char *lineStart = str;
    char *lineEnd = strchr(str, '\n');

    if (regcomp(&reg, pattern, REG_EXTENDED | REG_NOSUB) != 0)
        return -1;

    while (lineStart) {
        int ret;
        if (lineEnd)
            *lineEnd = '\0';


        ret = regexec(&reg, lineStart, 0, NULL, 0);
        //fprintf(stderr, "Match %d '%s' '%s'\n", ret, lineStart, pattern);
        if (ret == 0) {
            if (lineEnd) {
                memmove(lineStart, lineEnd + 1, strlen(lineEnd+1) + 1);
                /* Don't update lineStart - just iterate again on this
                   location */
                lineEnd = strchr(lineStart, '\n');
            } else {
                *lineStart = '\0';
                lineStart = NULL;
            }
        } else {
            if (lineEnd) {
                *lineEnd = '\n';
                lineStart = lineEnd + 1;
                lineEnd = strchr(lineStart, '\n');
            } else {
                lineStart = NULL;
            }
        }
    }

    regfree(&reg);

    return 0;
}
523 524 525 526 527 528 529
#else
int virtTestClearLineRegex(const char *pattern ATTRIBUTE_UNUSED,
                           char *str ATTRIBUTE_UNUSED)
{
    return 0;
}
#endif