2 * testutils.c: basic test utils
4 * Copyright (C) 2005-2014 Red Hat, Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see
18 * <http://www.gnu.org/licenses/>.
20 * Karel Zak <kzak@redhat.com>
28 #include <sys/types.h>
36 #include "testutils.h"
40 #include "virthread.h"
42 #include "virbuffer.h"
44 #include "vircommand.h"
45 #include "virrandom.h"
47 #include "virprocess.h"
48 #include "virstring.h"
51 # ifdef TEST_OOM_TRACE
53 # include <execinfo.h>
61 #define VIR_FROM_THIS VIR_FROM_NONE
63 VIR_LOG_INIT("tests.testutils");
65 #define GETTIMEOFDAY(T) gettimeofday(T, NULL)
66 #define DIFF_MSEC(T, U) \
67 ((((int) ((T)->tv_sec - (U)->tv_sec)) * 1000000.0 + \
68 ((int) ((T)->tv_usec - (U)->tv_usec))) / 1000.0)
72 static unsigned int testDebug = -1;
73 static unsigned int testVerbose = -1;
74 static unsigned int testExpensive = -1;
77 static unsigned int testOOM = 0;
78 static unsigned int testOOMStart = -1;
79 static unsigned int testOOMEnd = -1;
80 static unsigned int testOOMTrace = 0;
81 # ifdef TEST_OOM_TRACE
82 void *testAllocStack[30];
86 static bool testOOMActive = false;
88 static size_t testCounter = 0;
89 static size_t testStart = 0;
90 static size_t testEnd = 0;
94 bool virtTestOOMActive(void)
100 static void virTestAllocHook(int nalloc ATTRIBUTE_UNUSED,
101 void *opaque ATTRIBUTE_UNUSED)
103 ntestAllocStack = backtrace(testAllocStack, ARRAY_CARDINALITY(testAllocStack));
107 void virtTestResult(const char *name, int ret, const char *msg, ...)
110 va_start(vargs, msg);
112 if (testCounter == 0 && !virTestGetVerbose())
113 fprintf(stderr, " ");
116 if (virTestGetVerbose()) {
117 fprintf(stderr, "%3zu) %-60s ", testCounter, name);
119 fprintf(stderr, "OK\n");
121 fprintf(stderr, "FAILED\n");
124 if (virVasprintfQuiet(&str, msg, vargs) == 0) {
125 fprintf(stderr, "%s", str);
131 if (testCounter != 1 &&
132 !((testCounter-1) % 40)) {
133 fprintf(stderr, " %-3zu\n", (testCounter-1));
134 fprintf(stderr, " ");
137 fprintf(stderr, ".");
139 fprintf(stderr, "!");
145 #ifdef TEST_OOM_TRACE
147 virTestShowTrace(void)
150 for (j = 2; j < ntestAllocStack; j++) {
154 dladdr(testAllocStack[j], &info);
155 if (info.dli_fname &&
156 strstr(info.dli_fname, ".so")) {
157 if (virAsprintf(&cmd, ADDR2LINE " -f -e %s %p",
159 ((void*)((unsigned long long)testAllocStack[j]
160 - (unsigned long long)info.dli_fbase))) < 0)
163 if (virAsprintf(&cmd, ADDR2LINE " -f -e %s %p",
164 (char*)(info.dli_fname ? info.dli_fname : "<unknown>"),
165 testAllocStack[j]) < 0)
168 ignore_value(system(cmd));
177 * returns: -1 = error, 0 = success
180 virtTestRun(const char *title,
181 int (*body)(const void *data), const void *data)
185 if (testCounter == 0 && !virTestGetVerbose())
186 fprintf(stderr, " ");
191 /* Skip tests if out of range */
192 if ((testStart != 0) &&
193 (testCounter < testStart ||
194 testCounter > testEnd))
197 if (virTestGetVerbose())
198 fprintf(stderr, "%2zu) %-65s ... ", testCounter, title);
202 virErrorPtr err = virGetLastError();
204 if (virTestGetVerbose() || virTestGetDebug())
205 virDispatchError(NULL);
208 if (virTestGetVerbose()) {
210 fprintf(stderr, "OK\n");
211 else if (ret == EXIT_AM_SKIP)
212 fprintf(stderr, "SKIP\n");
214 fprintf(stderr, "FAILED\n");
216 if (testCounter != 1 &&
217 !((testCounter-1) % 40)) {
218 fprintf(stderr, " %-3zu\n", (testCounter-1));
219 fprintf(stderr, " ");
222 fprintf(stderr, ".");
223 else if (ret == EXIT_AM_SKIP)
224 fprintf(stderr, "_");
226 fprintf(stderr, "!");
230 if (testOOM && ret != EXIT_AM_SKIP) {
237 # ifdef TEST_OOM_TRACE
238 virAllocTestHook(virTestAllocHook, NULL);
241 nalloc = virAllocTestCount();
242 fprintf(stderr, " Test OOM for nalloc=%d ", nalloc);
243 if (testOOMStart == -1 ||
248 start = testOOMStart;
249 end = testOOMEnd + 1;
251 testOOMActive = true;
252 for (i = start; i < end; i++) {
253 bool missingFail = false;
254 # ifdef TEST_OOM_TRACE
255 memset(testAllocStack, 0, ARRAY_CARDINALITY(testAllocStack));
258 virAllocTestOOM(i + 1, 1);
261 /* fprintf() disabled because XML parsing APIs don't allow
262 * distinguish between element / attribute not present
263 * in the XML (which is non-fatal), vs OOM / malformed
264 * which should be fatal. Thus error reporting for
265 * optionally present XML is mostly broken.
270 fprintf(stderr, " alloc %zu failed but no err status\n", i + 1);
273 virErrorPtr lerr = virGetLastError();
276 fprintf(stderr, " alloc %zu failed but no error report\n", i + 1);
281 if ((missingFail && testOOMTrace) || (testOOMTrace > 1)) {
282 fprintf(stderr, "%s", "!");
283 # ifdef TEST_OOM_TRACE
288 fprintf(stderr, "%s", ".");
291 testOOMActive = false;
293 fprintf(stderr, " OK\n");
295 fprintf(stderr, " FAILED\n");
298 #endif /* TEST_OOM */
303 /* Allocate BUF to the size of FILE. Read FILE into buffer BUF.
304 Upon any failure, diagnose it and return -1, but don't bother trying
305 to preserve errno. Otherwise, return the number of bytes copied into BUF. */
307 virtTestLoadFile(const char *file, char **buf)
309 FILE *fp = fopen(file, "r");
312 int len, tmplen, buflen;
315 fprintf(stderr, "%s: failed to open: %s\n", file, strerror(errno));
319 if (fstat(fileno(fp), &st) < 0) {
320 fprintf(stderr, "%s: failed to fstat: %s\n", file, strerror(errno));
321 VIR_FORCE_FCLOSE(fp);
325 tmplen = buflen = st.st_size + 1;
327 if (VIR_ALLOC_N(*buf, buflen) < 0) {
328 VIR_FORCE_FCLOSE(fp);
335 /* read the file line by line */
336 while (fgets(tmp, tmplen, fp) != NULL) {
338 /* stop on an empty line */
341 /* remove trailing backslash-newline pair */
342 if (len >= 2 && tmp[len-2] == '\\' && tmp[len-1] == '\n') {
346 /* advance the temporary buffer pointer */
351 fprintf(stderr, "%s: read failed: %s\n", file, strerror(errno));
352 VIR_FORCE_FCLOSE(fp);
358 VIR_FORCE_FCLOSE(fp);
364 void virtTestCaptureProgramExecChild(const char *const argv[],
370 const char *const env[] = {
372 # if WITH_DRIVER_MODULES
373 "LIBVIRT_DRIVER_DIR=" TEST_DRIVER_DIR,
378 if ((stdinfd = open("/dev/null", O_RDONLY)) < 0)
381 open_max = sysconf(_SC_OPEN_MAX);
385 for (i = 0; i < open_max; i++) {
390 VIR_FORCE_CLOSE(tmpfd);
394 if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO)
396 if (dup2(pipefd, STDOUT_FILENO) != STDOUT_FILENO)
398 if (dup2(pipefd, STDERR_FILENO) != STDERR_FILENO)
401 /* SUS is crazy here, hence the cast */
402 execve(argv[0], (char *const*)argv, (char *const*)env);
405 VIR_FORCE_CLOSE(stdinfd);
409 virtTestCaptureProgramOutput(const char *const argv[], char **buf, int maxlen)
414 if (pipe(pipefd) < 0)
420 VIR_FORCE_CLOSE(pipefd[0]);
421 virtTestCaptureProgramExecChild(argv, pipefd[1]);
423 VIR_FORCE_CLOSE(pipefd[1]);
430 VIR_FORCE_CLOSE(pipefd[1]);
431 len = virFileReadLimFD(pipefd[0], maxlen, buf);
432 VIR_FORCE_CLOSE(pipefd[0]);
433 if (virProcessWait(pid, NULL, false) < 0)
441 virtTestCaptureProgramOutput(const char *const argv[] ATTRIBUTE_UNUSED,
442 char **buf ATTRIBUTE_UNUSED,
443 int maxlen ATTRIBUTE_UNUSED)
451 * @param stream: output stream write to differences to
452 * @param expect: expected output text
453 * @param actual: actual output text
455 * Display expected and actual output text, trimmed to
456 * first and last characters at which differences occur
458 int virtTestDifference(FILE *stream,
462 const char *expectStart;
463 const char *expectEnd;
464 const char *actualStart;
465 const char *actualEnd;
472 expectStart = expect;
473 expectEnd = expect + (strlen(expect)-1);
474 actualStart = actual;
475 actualEnd = actual + (strlen(actual)-1);
477 if (!virTestGetDebug())
480 if (virTestGetDebug() < 2) {
481 /* Skip to first character where they differ */
482 while (*expectStart && *actualStart &&
483 *actualStart == *expectStart) {
488 /* Work backwards to last character where they differ */
489 while (actualEnd > actualStart &&
490 expectEnd > expectStart &&
491 *actualEnd == *expectEnd) {
497 /* Show the trimmed differences */
498 fprintf(stream, "\nOffset %d\nExpect [", (int) (expectStart - expect));
499 if ((expectEnd - expectStart + 1) &&
500 fwrite(expectStart, (expectEnd-expectStart+1), 1, stream) != 1)
502 fprintf(stream, "]\n");
503 fprintf(stream, "Actual [");
504 if ((actualEnd - actualStart + 1) &&
505 fwrite(actualStart, (actualEnd-actualStart+1), 1, stream) != 1)
507 fprintf(stream, "]\n");
509 /* Pad to line up with test name ... in virTestRun */
510 fprintf(stream, " ... ");
516 * @param stream: output stream write to differences to
517 * @param expect: expected output text
518 * @param actual: actual output text
520 * Display expected and actual output text, trimmed to
521 * first and last characters at which differences occur
523 int virtTestDifferenceBin(FILE *stream,
528 size_t start = 0, end = length;
531 if (!virTestGetDebug())
534 if (virTestGetDebug() < 2) {
535 /* Skip to first character where they differ */
536 for (i = 0; i < length; i++) {
537 if (expect[i] != actual[i]) {
543 /* Work backwards to last character where they differ */
544 for (i = (length -1); i >= 0; i--) {
545 if (expect[i] != actual[i]) {
551 /* Round to nearest boundary of 4, except that last word can be short */
552 start -= (start % 4);
553 end += 4 - (end % 4);
557 /* Show the trimmed differences */
558 fprintf(stream, "\nExpect [ Region %d-%d", (int)start, (int)end);
559 for (i = start; i < end; i++) {
561 fprintf(stream, "\n ");
562 fprintf(stream, "0x%02x, ", ((int)expect[i])&0xff);
564 fprintf(stream, "]\n");
565 fprintf(stream, "Actual [ Region %d-%d", (int)start, (int)end);
566 for (i = start; i < end; i++) {
568 fprintf(stream, "\n ");
569 fprintf(stream, "0x%02x, ", ((int)actual[i])&0xff);
571 fprintf(stream, "]\n");
573 /* Pad to line up with test name ... in virTestRun */
574 fprintf(stream, " ... ");
580 virtTestErrorFuncQuiet(void *data ATTRIBUTE_UNUSED,
581 virErrorPtr err ATTRIBUTE_UNUSED)
585 /* register an error handler in tests when using connections */
587 virtTestQuiesceLibvirtErrors(bool always)
589 if (always || !virTestGetVerbose())
590 virSetErrorFunc(NULL, virtTestErrorFuncQuiet);
593 struct virtTestLogData {
597 static struct virtTestLogData testLog = { VIR_BUFFER_INITIALIZER };
600 virtTestLogOutput(virLogSourcePtr source ATTRIBUTE_UNUSED,
601 virLogPriority priority ATTRIBUTE_UNUSED,
602 const char *filename ATTRIBUTE_UNUSED,
603 int lineno ATTRIBUTE_UNUSED,
604 const char *funcname ATTRIBUTE_UNUSED,
605 const char *timestamp,
606 virLogMetadataPtr metadata ATTRIBUTE_UNUSED,
608 const char *rawstr ATTRIBUTE_UNUSED,
612 struct virtTestLogData *log = data;
613 virCheckFlags(VIR_LOG_STACK_TRACE,);
615 virBufferAsprintf(&log->buf, "%s: %s", timestamp, str);
619 virtTestLogClose(void *data)
621 struct virtTestLogData *log = data;
623 virBufferFreeAndReset(&log->buf);
626 /* Return a malloc'd string (possibly with strlen of 0) of all data
627 * logged since the last call to this function, or NULL on failure. */
629 virtTestLogContentAndReset(void)
633 if (virBufferError(&testLog.buf))
635 ret = virBufferContentAndReset(&testLog.buf);
637 ignore_value(VIR_STRDUP(ret, ""));
643 virTestGetFlag(const char *name)
648 if ((flagStr = getenv(name)) == NULL)
651 if (virStrToLong_ui(flagStr, NULL, 10, &flag) < 0)
658 virTestGetDebug(void)
661 testDebug = virTestGetFlag("VIR_TEST_DEBUG");
666 virTestGetVerbose(void)
668 if (testVerbose == -1)
669 testVerbose = virTestGetFlag("VIR_TEST_VERBOSE");
670 return testVerbose || virTestGetDebug();
674 virTestGetExpensive(void)
676 if (testExpensive == -1)
677 testExpensive = virTestGetFlag("VIR_TEST_EXPENSIVE");
678 return testExpensive;
681 int virtTestMain(int argc,
686 char *testRange = NULL;
691 virFileActivateDirOverride(argv[0]);
693 if (!virFileExists(abs_srcdir))
694 return EXIT_AM_HARDFAIL;
696 progname = last_component(argv[0]);
697 if (STRPREFIX(progname, "lt-"))
700 fprintf(stderr, "Usage: %s\n", argv[0]);
701 fputs("effective environment variables:\n"
702 "VIR_TEST_VERBOSE set to show names of individual tests\n"
703 "VIR_TEST_DEBUG set to show information for debugging failures\n",
707 fprintf(stderr, "TEST: %s\n", progname);
709 if (virThreadInitialize() < 0 ||
710 virErrorInitialize() < 0)
714 if (!getenv("LIBVIRT_DEBUG") && !virLogGetNbOutputs()) {
715 if (virLogDefineOutput(virtTestLogOutput, virtTestLogClose, &testLog,
716 VIR_LOG_DEBUG, VIR_LOG_TO_STDERR, NULL, 0) < 0)
720 if ((testRange = getenv("VIR_TEST_RANGE")) != NULL) {
723 if (virStrToLong_ui(testRange, &end, 10, &iv) < 0) {
724 fprintf(stderr, "Cannot parse range %s\n", testRange);
727 testStart = testEnd = iv;
730 fprintf(stderr, "Cannot parse range %s\n", testRange);
734 if (virStrToLong_ui(end, NULL, 10, &iv) < 0) {
735 fprintf(stderr, "Cannot parse range %s\n", testRange);
740 if (testEnd < testStart) {
741 fprintf(stderr, "Test range end %zu must be >= %zu\n", testEnd, testStart);
748 if ((oomstr = getenv("VIR_TEST_OOM")) != NULL) {
753 if (oomstr[0] != '\0' &&
755 if (virStrToLong_ui(oomstr + 2, &next, 10, &testOOMStart) < 0) {
756 fprintf(stderr, "Cannot parse range %s\n", oomstr);
760 testOOMEnd = testOOMStart;
763 fprintf(stderr, "Cannot parse range %s\n", oomstr);
766 if (virStrToLong_ui(next+1, NULL, 10, &testOOMEnd) < 0) {
767 fprintf(stderr, "Cannot parse range %s\n", oomstr);
777 # ifdef TEST_OOM_TRACE
778 if ((oomstr = getenv("VIR_TEST_OOM_TRACE")) != NULL) {
779 if (virStrToLong_ui(oomstr, NULL, 10, &testOOMTrace) < 0) {
780 fprintf(stderr, "Cannot parse oom trace %s\n", oomstr);
785 if (getenv("VIR_TEST_OOM_TRACE")) {
786 fprintf(stderr, "%s", "OOM test tracing not enabled in this build\n");
791 if (getenv("VIR_TEST_OOM")) {
792 fprintf(stderr, "%s", "OOM testing not enabled in this build\n");
795 if (getenv("VIR_TEST_OOM_TRACE")) {
796 fprintf(stderr, "%s", "OOM test tracing not enabled in this build\n");
799 #endif /* TEST_OOM */
804 if (!virTestGetVerbose() && ret != EXIT_AM_SKIP) {
805 if (testCounter == 0 || testCounter % 40)
806 fprintf(stderr, "%*s", 40 - (int)(testCounter % 40), "");
807 fprintf(stderr, " %-3zu %s\n", testCounter, ret == 0 ? "OK" : "FAIL");
813 int virtTestClearLineRegex(const char *pattern,
817 char *lineStart = str;
818 char *lineEnd = strchr(str, '\n');
820 if (regcomp(®, pattern, REG_EXTENDED | REG_NOSUB) != 0)
829 ret = regexec(®, lineStart, 0, NULL, 0);
830 //fprintf(stderr, "Match %d '%s' '%s'\n", ret, lineStart, pattern);
833 memmove(lineStart, lineEnd + 1, strlen(lineEnd+1) + 1);
834 /* Don't update lineStart - just iterate again on this
836 lineEnd = strchr(lineStart, '\n');
844 lineStart = lineEnd + 1;
845 lineEnd = strchr(lineStart, '\n');
859 * @cmdset contains a list of command line args, eg
861 * "/usr/sbin/iptables --table filter --insert INPUT --in-interface virbr0 --protocol tcp --destination-port 53 --jump ACCEPT
862 * /usr/sbin/iptables --table filter --insert INPUT --in-interface virbr0 --protocol udp --destination-port 53 --jump ACCEPT
863 * /usr/sbin/iptables --table filter --insert FORWARD --in-interface virbr0 --jump REJECT
864 * /usr/sbin/iptables --table filter --insert FORWARD --out-interface virbr0 --jump REJECT
865 * /usr/sbin/iptables --table filter --insert FORWARD --in-interface virbr0 --out-interface virbr0 --jump ACCEPT"
867 * And we're munging it in-place to strip the path component
868 * of the command line, to produce
870 * "iptables --table filter --insert INPUT --in-interface virbr0 --protocol tcp --destination-port 53 --jump ACCEPT
871 * iptables --table filter --insert INPUT --in-interface virbr0 --protocol udp --destination-port 53 --jump ACCEPT
872 * iptables --table filter --insert FORWARD --in-interface virbr0 --jump REJECT
873 * iptables --table filter --insert FORWARD --out-interface virbr0 --jump REJECT
874 * iptables --table filter --insert FORWARD --in-interface virbr0 --out-interface virbr0 --jump ACCEPT"
876 void virtTestClearCommandPath(char *cmdset)
879 char *lineStart = cmdset;
880 char *lineEnd = strchr(lineStart, '\n');
886 dirsep = strchr(lineStart, ' ');
888 while (dirsep > lineStart && *dirsep != '/')
894 movestart = lineStart;
896 movelen = lineEnd ? lineEnd - movestart : strlen(movestart);
899 memmove(cmdset + offset, movestart, movelen + 1);
900 offset += movelen + 1;
902 lineStart = lineEnd ? lineEnd + 1 : NULL;
903 lineEnd = lineStart ? strchr(lineStart, '\n') : NULL;
905 cmdset[offset] = '\0';
909 virCapsPtr virTestGenericCapsInit(void)
912 virCapsGuestPtr guest;
914 if ((caps = virCapabilitiesNew(VIR_ARCH_X86_64,
918 if ((guest = virCapabilitiesAddGuest(caps, "hvm", VIR_ARCH_I686,
919 "/usr/bin/acme-virt", NULL,
923 if (!virCapabilitiesAddGuestDomain(guest, "test", NULL, NULL, 0, NULL))
927 if ((guest = virCapabilitiesAddGuest(caps, "hvm", VIR_ARCH_X86_64,
928 "/usr/bin/acme-virt", NULL,
932 if (!virCapabilitiesAddGuestDomain(guest, "test", NULL, NULL, 0, NULL))
936 if (virTestGetDebug()) {
939 caps_str = virCapabilitiesFormatXML(caps);
943 fprintf(stderr, "Generic driver capabilities:\n%s", caps_str);
951 virObjectUnref(caps);
955 static virDomainDefParserConfig virTestGenericDomainDefParserConfig;
956 static virDomainXMLPrivateDataCallbacks virTestGenericPrivateDataCallbacks;
958 virDomainXMLOptionPtr virTestGenericDomainXMLConfInit(void)
960 return virDomainXMLOptionNew(&virTestGenericDomainDefParserConfig,
961 &virTestGenericPrivateDataCallbacks,