testutils.c 32.5 KB
Newer Older
K
Karel Zak 已提交
1
/*
2
 * testutils.c: basic test utils
K
Karel Zak 已提交
3
 *
4
 * Copyright (C) 2005-2015 Red Hat, Inc.
K
Karel Zak 已提交
5
 *
O
Osier Yang 已提交
6 7 8 9 10 11 12 13 14 15 16
 * 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
17
 * License along with this library.  If not, see
O
Osier Yang 已提交
18
 * <http://www.gnu.org/licenses/>.
K
Karel Zak 已提交
19 20
 */

21
#include <config.h>
22

23
#include <stdarg.h>
K
Karel Zak 已提交
24
#include <sys/time.h>
25 26
#include <sys/types.h>
#include <sys/stat.h>
27 28
#include <sys/wait.h>
#include <regex.h>
29
#include <unistd.h>
30
#include <fcntl.h>
K
Karel Zak 已提交
31
#include "testutils.h"
32
#include "internal.h"
33
#include "viralloc.h"
34
#include "virutil.h"
35
#include "virthread.h"
36
#include "virerror.h"
37
#include "virbuffer.h"
38
#include "virlog.h"
39
#include "vircommand.h"
40
#include "virrandom.h"
E
Eric Blake 已提交
41
#include "dirname.h"
42
#include "virprocess.h"
43
#include "virstring.h"
44

45 46
#define VIR_FROM_THIS VIR_FROM_NONE

47 48
VIR_LOG_INIT("tests.testutils");

49
#include "virbitmap.h"
E
Eric Blake 已提交
50
#include "virfile.h"
51

52
static unsigned int testDebug = -1;
53
static unsigned int testVerbose = -1;
54
static unsigned int testExpensive = -1;
55
static unsigned int testRegenerate = -1;
56

57

58
static size_t testCounter;
59
static virBitmapPtr testBitmap;
60

E
Eric Blake 已提交
61
char *progname;
J
Ján Tomko 已提交
62
static char *perl;
E
Eric Blake 已提交
63

64
static int virTestUseTerminalColors(void)
65
{
66
    return isatty(STDOUT_FILENO);
67 68
}

69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
static unsigned int
virTestGetFlag(const char *name)
{
    char *flagStr;
    unsigned int flag;

    if ((flagStr = getenv(name)) == NULL)
        return 0;

    if (virStrToLong_ui(flagStr, NULL, 10, &flag) < 0)
        return 0;

    return flag;
}

84

85
/*
86
 * Runs test
87 88
 *
 * returns: -1 = error, 0 = success
K
Karel Zak 已提交
89 90
 */
int
91 92
virTestRun(const char *title,
           int (*body)(const void *data), const void *data)
K
Karel Zak 已提交
93
{
94
    int ret = 0;
95

96 97 98 99 100
    /* Some test are fragile about environ settings.  If that's
     * the case, don't poison it. */
    if (getenv("VIR_TEST_MOCK_PROGNAME"))
        setenv("VIR_TEST_MOCK_TESTNAME", title, 1);

101 102 103
    if (testCounter == 0 && !virTestGetVerbose())
        fprintf(stderr, "      ");

104
    testCounter++;
105

106 107

    /* Skip tests if out of range */
108
    if (testBitmap && !virBitmapIsBitSet(testBitmap, testCounter))
109 110
        return 0;

D
Daniel P. Berrange 已提交
111 112
    if (virTestGetVerbose())
        fprintf(stderr, "%2zu) %-65s ... ", testCounter, title);
113

114 115
    virResetLastError();
    ret = body(data);
116
    if (virGetLastErrorCode()) {
117 118
        if (virTestGetVerbose() || virTestGetDebug())
            virDispatchError(NULL);
119
    }
120

D
Daniel P. Berrange 已提交
121
    if (virTestGetVerbose()) {
122
        if (ret == 0)
123
            if (virTestUseTerminalColors())
124 125 126
                fprintf(stderr, "\e[32mOK\e[0m\n");  /* green */
            else
                fprintf(stderr, "OK\n");
D
Daniel P. Berrange 已提交
127
        else if (ret == EXIT_AM_SKIP)
128
            if (virTestUseTerminalColors())
129 130 131
                fprintf(stderr, "\e[34m\e[1mSKIP\e[0m\n");  /* bold blue */
            else
                fprintf(stderr, "SKIP\n");
D
Daniel P. Berrange 已提交
132
        else
133
            if (virTestUseTerminalColors())
134 135 136
                fprintf(stderr, "\e[31m\e[1mFAILED\e[0m\n");  /* bold red */
            else
                fprintf(stderr, "FAILED\n");
D
Daniel P. Berrange 已提交
137 138 139 140 141
    } else {
        if (testCounter != 1 &&
            !((testCounter-1) % 40)) {
            fprintf(stderr, " %-3zu\n", (testCounter-1));
            fprintf(stderr, "      ");
142
        }
D
Daniel P. Berrange 已提交
143
        if (ret == 0)
144
                fprintf(stderr, ".");
D
Daniel P. Berrange 已提交
145 146 147 148
        else if (ret == EXIT_AM_SKIP)
            fprintf(stderr, "_");
        else
            fprintf(stderr, "!");
149
    }
150

151
    unsetenv("VIR_TEST_MOCK_TESTNAME");
152
    return ret;
K
Karel Zak 已提交
153
}
154

155 156 157 158 159 160 161 162 163 164 165

/**
 * virTestLoadFile:
 * @file: name of the file to load
 * @buf: buffer to load the file into
 *
 * Allocates @buf to the size of FILE. Reads FILE into buffer BUF.
 * Upon any failure, error is printed to stderr and -1 is returned. 'errno' is
 * not preserved. On success 0 is returned. Caller is responsible for freeing
 * @buf.
 */
166
int
167
virTestLoadFile(const char *file, char **buf)
168
{
169
    FILE *fp = fopen(file, "r");
170
    struct stat st;
171 172
    char *tmp;
    int len, tmplen, buflen;
173

174
    if (!fp) {
175
        fprintf(stderr, "%s: failed to open: %s\n", file, g_strerror(errno));
176
        return -1;
177
    }
178 179

    if (fstat(fileno(fp), &st) < 0) {
180
        fprintf(stderr, "%s: failed to fstat: %s\n", file, g_strerror(errno));
181
        VIR_FORCE_FCLOSE(fp);
182 183 184
        return -1;
    }

185 186 187
    tmplen = buflen = st.st_size + 1;

    if (VIR_ALLOC_N(*buf, buflen) < 0) {
188
        VIR_FORCE_FCLOSE(fp);
189 190 191
        return -1;
    }

192
    tmp = *buf;
193
    (*buf)[0] = '\0';
194
    if (st.st_size) {
195 196 197
        /* read the file line by line */
        while (fgets(tmp, tmplen, fp) != NULL) {
            len = strlen(tmp);
198 199 200
            /* stop on an empty line */
            if (len == 0)
                break;
201 202 203 204 205 206 207 208 209 210
            /* remove trailing backslash-newline pair */
            if (len >= 2 && tmp[len-2] == '\\' && tmp[len-1] == '\n') {
                len -= 2;
                tmp[len] = '\0';
            }
            /* advance the temporary buffer pointer */
            tmp += len;
            tmplen -= len;
        }
        if (ferror(fp)) {
211
            fprintf(stderr, "%s: read failed: %s\n", file, g_strerror(errno));
212
            VIR_FORCE_FCLOSE(fp);
213
            VIR_FREE(*buf);
214 215
            return -1;
        }
216 217
    }

218
    VIR_FORCE_FCLOSE(fp);
219
    return 0;
220 221
}

222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272

static char *
virTestLoadFileGetPath(const char *p,
                       va_list ap)
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *path = NULL;

    virBufferAddLit(&buf, abs_srcdir "/");

    if (p) {
        virBufferAdd(&buf, p, -1);
        virBufferStrcatVArgs(&buf, ap);
    }

    if (!(path = virBufferContentAndReset(&buf)))
        VIR_TEST_VERBOSE("failed to format file path");

    return path;
}


/**
 * virTestLoadFilePath:
 * @...: file name components terminated with a NULL
 *
 * Constructs the test file path from variable arguments and loads the file.
 * 'abs_srcdir' is automatically prepended.
 */
char *
virTestLoadFilePath(const char *p, ...)
{
    char *path = NULL;
    char *ret = NULL;
    va_list ap;

    va_start(ap, p);

    if (!(path = virTestLoadFileGetPath(p, ap)))
        goto cleanup;

    ignore_value(virTestLoadFile(path, &ret));

 cleanup:
    va_end(ap);
    VIR_FREE(path);

    return ret;
}


273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
/**
 * virTestLoadFileJSON:
 * @...: name components terminated with a NULL
 *
 * Constructs the test file path from variable arguments and loads and parses
 * the JSON file. 'abs_srcdir' is automatically prepended to the path.
 */
virJSONValuePtr
virTestLoadFileJSON(const char *p, ...)
{
    virJSONValuePtr ret = NULL;
    char *jsonstr = NULL;
    char *path = NULL;
    va_list ap;

    va_start(ap, p);

    if (!(path = virTestLoadFileGetPath(p, ap)))
        goto cleanup;

    if (virTestLoadFile(path, &jsonstr) < 0)
        goto cleanup;

    if (!(ret = virJSONValueFromString(jsonstr)))
        VIR_TEST_VERBOSE("failed to parse json from file '%s'", path);

 cleanup:
    va_end(ap);
    VIR_FREE(jsonstr);
    VIR_FREE(path);
    return ret;
}


A
Atsushi SAKAI 已提交
307
#ifndef WIN32
308
static
309 310
void virTestCaptureProgramExecChild(const char *const argv[],
                                    int pipefd)
311
{
312
    size_t i;
313 314 315 316 317 318 319
    int open_max;
    int stdinfd = -1;
    const char *const env[] = {
        "LANG=C",
        NULL
    };

320
    if ((stdinfd = open("/dev/null", O_RDONLY)) < 0)
321 322
        goto cleanup;

323
    open_max = sysconf(_SC_OPEN_MAX);
J
John Ferlan 已提交
324 325 326
    if (open_max < 0)
        goto cleanup;

327 328
    for (i = 0; i < open_max; i++) {
        if (i != stdinfd &&
329
            i != pipefd) {
330 331
            int tmpfd;
            tmpfd = i;
332 333
            VIR_FORCE_CLOSE(tmpfd);
        }
334 335 336 337 338 339
    }

    if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO)
        goto cleanup;
    if (dup2(pipefd, STDOUT_FILENO) != STDOUT_FILENO)
        goto cleanup;
340
    if (dup2(pipefd, STDERR_FILENO) != STDERR_FILENO)
341 342 343 344
        goto cleanup;

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

 cleanup:
347
    VIR_FORCE_CLOSE(stdinfd);
348 349
}

350
int
351
virTestCaptureProgramOutput(const char *const argv[], char **buf, int maxlen)
352
{
353
    int pipefd[2];
354
    int len;
355 356 357 358

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

359
    pid_t pid = fork();
360
    switch (pid) {
361
    case 0:
362
        VIR_FORCE_CLOSE(pipefd[0]);
363
        virTestCaptureProgramExecChild(argv, pipefd[1]);
364

365
        VIR_FORCE_CLOSE(pipefd[1]);
366
        _exit(EXIT_FAILURE);
367

368 369
    case -1:
        return -1;
370

371
    default:
372 373 374
        VIR_FORCE_CLOSE(pipefd[1]);
        len = virFileReadLimFD(pipefd[0], maxlen, buf);
        VIR_FORCE_CLOSE(pipefd[0]);
375
        if (virProcessWait(pid, NULL, false) < 0)
E
Eric Blake 已提交
376
            return -1;
377

378
        return len;
379
    }
380
}
381
#else /* !WIN32 */
382
int
J
Ján Tomko 已提交
383 384 385
virTestCaptureProgramOutput(const char *const argv[] G_GNUC_UNUSED,
                            char **buf G_GNUC_UNUSED,
                            int maxlen G_GNUC_UNUSED)
386
{
387 388
    return -1;
}
A
Atsushi SAKAI 已提交
389
#endif /* !WIN32 */
390

391 392 393 394 395 396 397
static int
virTestRewrapFile(const char *filename)
{
    int ret = -1;
    char *script = NULL;
    virCommandPtr cmd = NULL;

398 399
    if (!(virStringHasSuffix(filename, ".args") ||
          virStringHasSuffix(filename, ".ldargs")))
J
Ján Tomko 已提交
400 401
        return 0;

J
Ján Tomko 已提交
402 403 404 405 406
    if (!perl) {
        fprintf(stderr, "cannot rewrap %s: unable to find perl in path", filename);
        return -1;
    }

407 408 409
    if (virAsprintf(&script, "%s/test-wrap-argv.pl", abs_srcdir) < 0)
        goto cleanup;

J
Ján Tomko 已提交
410
    cmd = virCommandNewArgList(perl, script, "--in-place", filename, NULL);
411 412 413 414 415 416 417 418 419
    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;

    ret = 0;
 cleanup:
    VIR_FREE(script);
    virCommandFree(cmd);
    return ret;
}
420 421

/**
422
 * @param stream: output stream to write differences to
423
 * @param expect: expected output text
424
 * @param expectName: name designator of the expected text
425
 * @param actual: actual output text
426
 * @param actualName: name designator of the actual text
427
 * @param regenerate: enable or disable regenerate functionality
428
 *
429 430 431
 * Display expected and actual output text, trimmed to first and last
 * characters at which differences occur. Displays names of the text strings if
 * non-NULL.
432
 */
433
static int
434 435 436 437 438 439
virTestDifferenceFullInternal(FILE *stream,
                              const char *expect,
                              const char *expectName,
                              const char *actual,
                              const char *actualName,
                              bool regenerate)
440
{
441 442 443 444 445 446 447 448 449 450 451 452 453 454
    const char *expectStart;
    const char *expectEnd;
    const char *actualStart;
    const char *actualEnd;

    if (!expect)
        expect = "";
    if (!actual)
        actual = "";

    expectStart = expect;
    expectEnd = expect + (strlen(expect)-1);
    actualStart = actual;
    actualEnd = actual + (strlen(actual)-1);
455

456
    if (expectName && regenerate && (virTestGetRegenerate() > 0)) {
457 458
        if (virFileWriteStr(expectName, actual, 0666) < 0) {
            virDispatchError(NULL);
459
            return -1;
460
        }
461

462 463
        if (virTestRewrapFile(expectName) < 0) {
            virDispatchError(NULL);
464
            return -1;
465
        }
466 467
    }

468
    if (!virTestGetDebug())
469 470
        return 0;

471
    if (virTestGetDebug() < 2) {
472 473 474 475 476 477
        /* Skip to first character where they differ */
        while (*expectStart && *actualStart &&
               *actualStart == *expectStart) {
            actualStart++;
            expectStart++;
        }
478

479 480 481 482 483 484 485
        /* Work backwards to last character where they differ */
        while (actualEnd > actualStart &&
               expectEnd > expectStart &&
               *actualEnd == *expectEnd) {
            actualEnd--;
            expectEnd--;
        }
486 487 488
    }

    /* Show the trimmed differences */
489 490
    if (expectName)
        fprintf(stream, "\nIn '%s':", expectName);
E
Eric Blake 已提交
491
    fprintf(stream, "\nOffset %d\nExpect [", (int) (expectStart - expect));
492 493 494 495
    if ((expectEnd - expectStart + 1) &&
        fwrite(expectStart, (expectEnd-expectStart+1), 1, stream) != 1)
        return -1;
    fprintf(stream, "]\n");
496 497
    if (actualName)
        fprintf(stream, "In '%s':\n", actualName);
498 499 500 501 502 503 504 505 506 507 508
    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;
}
509

510 511 512 513 514 515 516 517 518 519 520 521 522
/**
 * @param stream: output stream to write differences to
 * @param expect: expected output text
 * @param expectName: name designator of the expected text
 * @param actual: actual output text
 * @param actualName: name designator of the actual text
 *
 * Display expected and actual output text, trimmed to first and last
 * characters at which differences occur. Displays names of the text strings if
 * non-NULL. If VIR_TEST_REGENERATE_OUTPUT is used, this function will
 * regenerate the expected file.
 */
int
523 524 525 526 527
virTestDifferenceFull(FILE *stream,
                      const char *expect,
                      const char *expectName,
                      const char *actual,
                      const char *actualName)
528
{
529 530
    return virTestDifferenceFullInternal(stream, expect, expectName,
                                         actual, actualName, true);
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
}

/**
 * @param stream: output stream to write differences to
 * @param expect: expected output text
 * @param expectName: name designator of the expected text
 * @param actual: actual output text
 * @param actualName: name designator of the actual text
 *
 * Display expected and actual output text, trimmed to first and last
 * characters at which differences occur. Displays names of the text strings if
 * non-NULL. If VIR_TEST_REGENERATE_OUTPUT is used, this function will not
 * regenerate the expected file.
 */
int
546 547 548 549 550
virTestDifferenceFullNoRegenerate(FILE *stream,
                                  const char *expect,
                                  const char *expectName,
                                  const char *actual,
                                  const char *actualName)
551
{
552 553
    return virTestDifferenceFullInternal(stream, expect, expectName,
                                         actual, actualName, false);
554 555
}

556
/**
557
 * @param stream: output stream to write differences to
558 559 560 561 562 563
 * @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
 */
564
int
565 566 567
virTestDifference(FILE *stream,
                  const char *expect,
                  const char *actual)
568
{
569 570 571
    return virTestDifferenceFullNoRegenerate(stream,
                                             expect, NULL,
                                             actual, NULL);
572 573 574
}


575
/**
576
 * @param stream: output stream to write differences to
577 578 579 580 581 582
 * @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
 */
583 584 585 586
int virTestDifferenceBin(FILE *stream,
                         const char *expect,
                         const char *actual,
                         size_t length)
587 588 589 590 591 592 593 594 595
{
    size_t start = 0, end = length;
    ssize_t i;

    if (!virTestGetDebug())
        return 0;

    if (virTestGetDebug() < 2) {
        /* Skip to first character where they differ */
596
        for (i = 0; i < length; i++) {
597 598 599 600 601 602 603
            if (expect[i] != actual[i]) {
                start = i;
                break;
            }
        }

        /* Work backwards to last character where they differ */
604
        for (i = (length -1); i >= 0; i--) {
605 606 607 608 609 610
            if (expect[i] != actual[i]) {
                end = i;
                break;
            }
        }
    }
E
Eric Blake 已提交
611
    /* Round to nearest boundary of 4, except that last word can be short */
612 613 614 615 616 617 618
    start -= (start % 4);
    end += 4 - (end % 4);
    if (end >= length)
        end = length - 1;

    /* Show the trimmed differences */
    fprintf(stream, "\nExpect [ Region %d-%d", (int)start, (int)end);
619
    for (i = start; i < end; i++) {
620 621 622 623 624 625
        if ((i % 4) == 0)
            fprintf(stream, "\n    ");
        fprintf(stream, "0x%02x, ", ((int)expect[i])&0xff);
    }
    fprintf(stream, "]\n");
    fprintf(stream, "Actual [ Region %d-%d", (int)start, (int)end);
626
    for (i = start; i < end; i++) {
627 628 629 630 631 632 633 634 635 636 637 638
        if ((i % 4) == 0)
            fprintf(stream, "\n    ");
        fprintf(stream, "0x%02x, ", ((int)actual[i])&0xff);
    }
    fprintf(stream, "]\n");

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

    return 0;
}

C
Cole Robinson 已提交
639
/*
640 641
 * @param actual: String input content
 * @param filename: File to compare @actual against
642
 *
643
 * If @actual is NULL, it's treated as an empty string.
C
Cole Robinson 已提交
644 645
 */
int
646
virTestCompareToFile(const char *actual,
647
                     const char *filename)
C
Cole Robinson 已提交
648 649 650 651
{
    int ret = -1;
    char *filecontent = NULL;
    char *fixedcontent = NULL;
652
    const char *cmpcontent = actual;
C
Cole Robinson 已提交
653

654 655 656
    if (!cmpcontent)
        cmpcontent = "";

657
    if (virTestLoadFile(filename, &filecontent) < 0 && !virTestGetRegenerate())
C
Cole Robinson 已提交
658 659
        goto failure;

660 661
    if (filecontent) {
        size_t filecontentLen = strlen(filecontent);
662
        size_t cmpcontentLen = strlen(cmpcontent);
663 664 665

        if (filecontentLen > 0 &&
            filecontent[filecontentLen - 1] == '\n' &&
666
            (cmpcontentLen == 0 || cmpcontent[cmpcontentLen - 1] != '\n')) {
667
            if (virAsprintf(&fixedcontent, "%s\n", cmpcontent) < 0)
668 669 670
                goto failure;
            cmpcontent = fixedcontent;
        }
C
Cole Robinson 已提交
671 672
    }

673
    if (STRNEQ_NULLABLE(cmpcontent, filecontent)) {
674 675
        virTestDifferenceFull(stderr,
                              filecontent, filename,
676
                              cmpcontent, NULL);
C
Cole Robinson 已提交
677 678 679 680 681 682 683 684 685 686
        goto failure;
    }

    ret = 0;
 failure:
    VIR_FREE(fixedcontent);
    VIR_FREE(filecontent);
    return ret;
}

687
int
688 689
virTestCompareToULL(unsigned long long expect,
                    unsigned long long actual)
690
{
691 692
    g_autofree char *expectStr = NULL;
    g_autofree char *actualStr = NULL;
693

694
    if (virAsprintf(&expectStr, "%llu", expect) < 0)
695
        return -1;
696

697
    if (virAsprintf(&actualStr, "%llu", actual) < 0)
698
        return -1;
699

700
    return virTestCompareToString(expectStr, actualStr);
701 702
}

J
Jim Fehlig 已提交
703
int
704 705
virTestCompareToString(const char *expect,
                       const char *actual)
J
Jim Fehlig 已提交
706
{
707 708
    if (STRNEQ_NULLABLE(expect, actual)) {
        virTestDifference(stderr, expect, actual);
J
Jim Fehlig 已提交
709 710 711 712 713 714
        return -1;
    }

    return 0;
}

715
static void
J
Ján Tomko 已提交
716 717
virTestErrorFuncQuiet(void *data G_GNUC_UNUSED,
                      virErrorPtr err G_GNUC_UNUSED)
718
{ }
719 720 721 722


/* register an error handler in tests when using connections */
void
723
virTestQuiesceLibvirtErrors(bool always)
724 725
{
    if (always || !virTestGetVerbose())
726
        virSetErrorFunc(NULL, virTestErrorFuncQuiet);
727
}
728

729 730 731 732 733 734
struct virtTestLogData {
    virBuffer buf;
};

static struct virtTestLogData testLog = { VIR_BUFFER_INITIALIZER };

735
static void
J
Ján Tomko 已提交
736 737 738 739 740
virtTestLogOutput(virLogSourcePtr source G_GNUC_UNUSED,
                  virLogPriority priority G_GNUC_UNUSED,
                  const char *filename G_GNUC_UNUSED,
                  int lineno G_GNUC_UNUSED,
                  const char *funcname G_GNUC_UNUSED,
741
                  const char *timestamp,
J
Ján Tomko 已提交
742 743
                  virLogMetadataPtr metadata G_GNUC_UNUSED,
                  const char *rawstr G_GNUC_UNUSED,
744 745
                  const char *str,
                  void *data)
746 747
{
    struct virtTestLogData *log = data;
748
    virBufferAsprintf(&log->buf, "%s: %s", timestamp, str);
749 750 751 752 753 754 755 756 757 758 759 760 761
}

static void
virtTestLogClose(void *data)
{
    struct virtTestLogData *log = data;

    virBufferFreeAndReset(&log->buf);
}

/* Return a malloc'd string (possibly with strlen of 0) of all data
 * logged since the last call to this function, or NULL on failure.  */
char *
762
virTestLogContentAndReset(void)
763 764 765 766
{
    char *ret;

    ret = virBufferContentAndReset(&testLog.buf);
767
    if (!ret)
768
        ret = g_strdup("");
769
    return ret;
770 771
}

772

773
unsigned int
774 775
virTestGetDebug(void)
{
776 777
    if (testDebug == -1)
        testDebug = virTestGetFlag("VIR_TEST_DEBUG");
778 779
    return testDebug;
}
780

781
unsigned int
782 783
virTestGetVerbose(void)
{
784 785 786 787 788
    if (testVerbose == -1)
        testVerbose = virTestGetFlag("VIR_TEST_VERBOSE");
    return testVerbose || virTestGetDebug();
}

789
unsigned int
790 791
virTestGetExpensive(void)
{
792 793 794 795 796
    if (testExpensive == -1)
        testExpensive = virTestGetFlag("VIR_TEST_EXPENSIVE");
    return testExpensive;
}

797 798 799 800 801 802 803 804
unsigned int
virTestGetRegenerate(void)
{
    if (testRegenerate == -1)
        testRegenerate = virTestGetFlag("VIR_TEST_REGENERATE_OUTPUT");
    return testRegenerate;
}

M
Michal Privoznik 已提交
805 806 807 808 809 810 811
static int
virTestSetEnvPath(void)
{
    int ret = -1;
    const char *path = getenv("PATH");
    char *new_path = NULL;

812 813 814 815 816
    if (path) {
        if (strstr(path, abs_builddir) != path &&
            virAsprintf(&new_path, "%s:%s", abs_builddir, path) < 0)
            goto cleanup;
    } else {
817
        new_path = g_strdup(abs_builddir);
818 819
    }

820 821
    if (new_path &&
        setenv("PATH", new_path, 1) < 0)
M
Michal Privoznik 已提交
822 823 824 825 826 827 828 829
        goto cleanup;

    ret = 0;
 cleanup:
    VIR_FREE(new_path);
    return ret;
}

830 831 832 833
int virTestMain(int argc,
                char **argv,
                int (*func)(void),
                ...)
834
{
835 836
    const char *lib;
    va_list ap;
837
    int ret;
838
    char *testRange = NULL;
839 840 841
    size_t noutputs = 0;
    virLogOutputPtr output = NULL;
    virLogOutputPtr *outputs = NULL;
842

843
    if (getenv("VIR_TEST_FILE_ACCESS"))
844
        VIR_TEST_PRELOAD(VIR_TEST_MOCK("virtest"));
845

846 847
    va_start(ap, func);
    while ((lib = va_arg(ap, const char *)))
848
        VIR_TEST_PRELOAD(lib);
849
    va_end(ap);
850 851 852 853 854 855 856

    progname = last_component(argv[0]);
    if (STRPREFIX(progname, "lt-"))
        progname += 3;

    setenv("VIR_TEST_MOCK_PROGNAME", progname, 1);

857
    virFileActivateDirOverrideForProg(argv[0]);
858

M
Michal Privoznik 已提交
859 860 861
    if (virTestSetEnvPath() < 0)
        return EXIT_AM_HARDFAIL;

862
    if (!virFileExists(abs_srcdir))
863
        return EXIT_AM_HARDFAIL;
E
Eric Blake 已提交
864 865 866

    if (argc > 1) {
        fprintf(stderr, "Usage: %s\n", argv[0]);
867 868
        fputs("effective environment variables:\n"
              "VIR_TEST_VERBOSE set to show names of individual tests\n"
869
              "VIR_TEST_DEBUG set to show information for debugging failures",
870
              stderr);
E
Eric Blake 已提交
871 872 873
        return EXIT_FAILURE;
    }
    fprintf(stderr, "TEST: %s\n", progname);
874

875
    if (virErrorInitialize() < 0)
876
        return EXIT_FAILURE;
877

878
    virLogSetFromEnv();
879
    if (!getenv("LIBVIRT_DEBUG") && !virLogGetNbOutputs()) {
880 881 882 883 884 885 886
        if (!(output = virLogOutputNew(virtTestLogOutput, virtTestLogClose,
                                       &testLog, VIR_LOG_DEBUG,
                                       VIR_LOG_TO_STDERR, NULL)) ||
            VIR_APPEND_ELEMENT(outputs, noutputs, output) < 0 ||
            virLogDefineOutputs(outputs, noutputs) < 0) {
            virLogOutputFree(output);
            virLogOutputListFree(outputs, noutputs);
887
            return EXIT_FAILURE;
888
        }
889
    }
890

891
    if ((testRange = getenv("VIR_TEST_RANGE")) != NULL) {
892
        if (!(testBitmap = virBitmapParseUnlimited(testRange))) {
893 894 895 896 897
            fprintf(stderr, "Cannot parse range %s\n", testRange);
            return EXIT_FAILURE;
        }
    }

J
Ján Tomko 已提交
898 899 900
    /* Find perl early because some tests override PATH */
    perl = virFindFileInPath("perl");

E
Eric Blake 已提交
901
    ret = (func)();
902 903

    virResetLastError();
904
    if (!virTestGetVerbose() && ret != EXIT_AM_SKIP) {
E
Eric Blake 已提交
905
        if (testCounter == 0 || testCounter % 40)
906 907
            fprintf(stderr, "%*s", 40 - (int)(testCounter % 40), "");
        fprintf(stderr, " %-3zu %s\n", testCounter, ret == 0 ? "OK" : "FAIL");
908
    }
909
    virLogReset();
J
Ján Tomko 已提交
910
    VIR_FREE(perl);
911
    return ret;
912
}
913 914


915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932
/*
 * @cmdset contains a list of command line args, eg
 *
 * "/usr/sbin/iptables --table filter --insert INPUT --in-interface virbr0 --protocol tcp --destination-port 53 --jump ACCEPT
 *  /usr/sbin/iptables --table filter --insert INPUT --in-interface virbr0 --protocol udp --destination-port 53 --jump ACCEPT
 *  /usr/sbin/iptables --table filter --insert FORWARD --in-interface virbr0 --jump REJECT
 *  /usr/sbin/iptables --table filter --insert FORWARD --out-interface virbr0 --jump REJECT
 *  /usr/sbin/iptables --table filter --insert FORWARD --in-interface virbr0 --out-interface virbr0 --jump ACCEPT"
 *
 * And we're munging it in-place to strip the path component
 * of the command line, to produce
 *
 * "iptables --table filter --insert INPUT --in-interface virbr0 --protocol tcp --destination-port 53 --jump ACCEPT
 *  iptables --table filter --insert INPUT --in-interface virbr0 --protocol udp --destination-port 53 --jump ACCEPT
 *  iptables --table filter --insert FORWARD --in-interface virbr0 --jump REJECT
 *  iptables --table filter --insert FORWARD --out-interface virbr0 --jump REJECT
 *  iptables --table filter --insert FORWARD --in-interface virbr0 --out-interface virbr0 --jump ACCEPT"
 */
933
void virTestClearCommandPath(char *cmdset)
934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965
{
    size_t offset = 0;
    char *lineStart = cmdset;
    char *lineEnd = strchr(lineStart, '\n');

    while (lineStart) {
        char *dirsep;
        char *movestart;
        size_t movelen;
        dirsep = strchr(lineStart, ' ');
        if (dirsep) {
            while (dirsep > lineStart && *dirsep != '/')
                dirsep--;
            if (*dirsep == '/')
                dirsep++;
            movestart = dirsep;
        } else {
            movestart = lineStart;
        }
        movelen = lineEnd ? lineEnd - movestart : strlen(movestart);

        if (movelen) {
            memmove(cmdset + offset, movestart, movelen + 1);
            offset += movelen + 1;
        }
        lineStart = lineEnd ? lineEnd + 1 : NULL;
        lineEnd = lineStart ? strchr(lineStart, '\n') : NULL;
    }
    cmdset[offset] = '\0';
}


966 967 968 969 970 971
virCapsPtr virTestGenericCapsInit(void)
{
    virCapsPtr caps;
    virCapsGuestPtr guest;

    if ((caps = virCapabilitiesNew(VIR_ARCH_X86_64,
972
                                   false, false)) == NULL)
973 974
        return NULL;

975
    if ((guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM, VIR_ARCH_I686,
976 977 978 979
                                         "/usr/bin/acme-virt", NULL,
                                         0, NULL)) == NULL)
        goto error;

980
    if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_TEST, NULL, NULL, 0, NULL))
981
        goto error;
982 983 984 985 986 987
    if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_QEMU,
                                       NULL, NULL, 0, NULL))
        goto error;
    if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_KVM,
                                       NULL, NULL, 0, NULL))
        goto error;
988

989
    if ((guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM, VIR_ARCH_X86_64,
990 991 992 993
                                         "/usr/bin/acme-virt", NULL,
                                         0, NULL)) == NULL)
        goto error;

994
    if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_TEST, NULL, NULL, 0, NULL))
995
        goto error;
996 997 998 999 1000 1001
    if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_QEMU,
                                       NULL, NULL, 0, NULL))
        goto error;
    if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_KVM,
                                       NULL, NULL, 0, NULL))
        goto error;
1002 1003


1004
    if (virTestGetDebug() > 1) {
1005 1006 1007 1008 1009 1010
        char *caps_str;

        caps_str = virCapabilitiesFormatXML(caps);
        if (!caps_str)
            goto error;

1011
        VIR_TEST_DEBUG("Generic driver capabilities:\n%s", caps_str);
1012 1013 1014 1015 1016 1017

        VIR_FREE(caps_str);
    }

    return caps;

1018
 error:
1019 1020 1021 1022
    virObjectUnref(caps);
    return NULL;
}

1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073

#define MAX_CELLS 4
#define MAX_CPUS_IN_CELL 2
#define MAX_MEM_IN_CELL 2097152

/*
 * Build NUMA topology with cell id starting from (0 + seq)
 * for testing
 */
int
virTestCapsBuildNUMATopology(virCapsPtr caps,
                             int seq)
{
    virCapsHostNUMACellCPUPtr cell_cpus = NULL;
    int core_id, cell_id;
    int id;

    id = 0;
    for (cell_id = 0; cell_id < MAX_CELLS; cell_id++) {
        if (VIR_ALLOC_N(cell_cpus, MAX_CPUS_IN_CELL) < 0)
            goto error;

        for (core_id = 0; core_id < MAX_CPUS_IN_CELL; core_id++) {
            cell_cpus[core_id].id = id + core_id;
            cell_cpus[core_id].socket_id = cell_id + seq;
            cell_cpus[core_id].core_id = id + core_id;
            if (!(cell_cpus[core_id].siblings =
                  virBitmapNew(MAX_CPUS_IN_CELL)))
                goto error;
            ignore_value(virBitmapSetBit(cell_cpus[core_id].siblings, id));
        }
        id++;

        if (virCapabilitiesAddHostNUMACell(caps, cell_id + seq,
                                           MAX_MEM_IN_CELL,
                                           MAX_CPUS_IN_CELL, cell_cpus,
                                           VIR_ARCH_NONE, NULL,
                                           VIR_ARCH_NONE, NULL) < 0)
           goto error;

        cell_cpus = NULL;
    }

    return 0;

 error:
    virCapabilitiesClearHostNUMACellCPUTopology(cell_cpus, MAX_CPUS_IN_CELL);
    VIR_FREE(cell_cpus);
    return -1;
}

1074 1075 1076
static virDomainDefParserConfig virTestGenericDomainDefParserConfig = {
    .features = VIR_DOMAIN_DEF_FEATURE_INDIVIDUAL_VCPUS,
};
1077 1078 1079 1080

virDomainXMLOptionPtr virTestGenericDomainXMLConfInit(void)
{
    return virDomainXMLOptionNew(&virTestGenericDomainDefParserConfig,
1081
                                 NULL, NULL, NULL, NULL);
1082
}
1083 1084


1085 1086
int
testCompareDomXML2XMLFiles(virCapsPtr caps, virDomainXMLOptionPtr xmlopt,
1087
                           const char *infile, const char *outfile, bool live,
1088
                           unsigned int parseFlags,
1089
                           testCompareDomXML2XMLResult expectResult)
1090 1091 1092
{
    char *actual = NULL;
    int ret = -1;
1093
    testCompareDomXML2XMLResult result;
1094 1095 1096
    virDomainDefPtr def = NULL;
    unsigned int parse_flags = live ? 0 : VIR_DOMAIN_DEF_PARSE_INACTIVE;
    unsigned int format_flags = VIR_DOMAIN_DEF_FORMAT_SECURE;
1097 1098 1099

    parse_flags |= parseFlags;

1100 1101 1102 1103 1104
    if (!virFileExists(infile)) {
        VIR_TEST_DEBUG("Test input file '%s' is missing", infile);
        return -1;
    }

1105 1106 1107
    if (!live)
        format_flags |= VIR_DOMAIN_DEF_FORMAT_INACTIVE;

1108
    if (!(def = virDomainDefParseFile(infile, caps, xmlopt, NULL, parse_flags))) {
1109 1110 1111
        result = TEST_COMPARE_DOM_XML2XML_RESULT_FAIL_PARSE;
        goto out;
    }
1112

1113
    if (!virDomainDefCheckABIStability(def, def, xmlopt)) {
1114
        VIR_TEST_DEBUG("ABI stability check failed on %s", infile);
1115 1116
        result = TEST_COMPARE_DOM_XML2XML_RESULT_FAIL_STABILITY;
        goto out;
1117 1118
    }

1119 1120 1121 1122
    if (!(actual = virDomainDefFormat(def, caps, format_flags))) {
        result = TEST_COMPARE_DOM_XML2XML_RESULT_FAIL_FORMAT;
        goto out;
    }
1123

1124
    if (virTestCompareToFile(actual, outfile) < 0) {
1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142
        result = TEST_COMPARE_DOM_XML2XML_RESULT_FAIL_COMPARE;
        goto out;
    }

    result = TEST_COMPARE_DOM_XML2XML_RESULT_SUCCESS;

 out:
    if (result == expectResult) {
        ret = 0;
        if (expectResult != TEST_COMPARE_DOM_XML2XML_RESULT_SUCCESS) {
            VIR_TEST_DEBUG("Got expected failure code=%d msg=%s",
                           result, virGetLastErrorMessage());
        }
    } else {
        ret = -1;
        VIR_TEST_DEBUG("Expected result code=%d but received code=%d",
                       expectResult, result);
    }
1143 1144 1145 1146 1147 1148 1149

    VIR_FREE(actual);
    virDomainDefFree(def);
    return ret;
}


1150 1151 1152 1153 1154 1155
static int virtTestCounter;
static char virtTestCounterStr[128];
static char *virtTestCounterPrefixEndOffset;


/**
1156
 * virTestCounterReset:
1157 1158 1159
 * @prefix: name of the test group
 *
 * Resets the counter and sets up the test group name to use with
1160
 * virTestCounterNext(). This function is not thread safe.
1161 1162 1163 1164 1165
 *
 * Note: The buffer for the assembled message is 128 bytes long. Longer test
 * case names (including the number index) will be silently truncated.
 */
void
1166
virTestCounterReset(const char *prefix)
1167 1168 1169 1170 1171 1172 1173 1174 1175
{
    virtTestCounter = 0;

    ignore_value(virStrcpyStatic(virtTestCounterStr, prefix));
    virtTestCounterPrefixEndOffset = strchrnul(virtTestCounterStr, '\0');
}


/**
1176
 * virTestCounterNext:
1177 1178 1179 1180 1181
 *
 * This function is designed to ease test creation and reordering by adding
 * a way to do automagic test case numbering.
 *
 * Returns string consisting of test name prefix configured via
1182
 * virTestCounterReset() and a number that increments in every call of this
1183 1184 1185 1186 1187 1188
 * function. This function is not thread safe.
 *
 * Note: The buffer for the assembled message is 128 bytes long. Longer test
 * case names (including the number index) will be silently truncated.
 */
const char
1189
*virTestCounterNext(void)
1190
{
1191
    size_t len = G_N_ELEMENTS(virtTestCounterStr);
1192 1193 1194 1195 1196 1197 1198 1199

    /* calculate length of the rest of the string */
    len -= (virtTestCounterPrefixEndOffset - virtTestCounterStr);

    snprintf(virtTestCounterPrefixEndOffset, len, "%d", ++virtTestCounter);

    return virtTestCounterStr;
}