backup: Wire up qemu full pull backup commands over QMP
[libvirt/ericb.git] / tests / testutils.c
blob245b1832f6f3c1f6bf5b757aa0fdbc27897f00af
1 /*
2 * testutils.c: basic test utils
4 * Copyright (C) 2005-2015 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/>.
21 #include <config.h>
23 #include <stdarg.h>
24 #include <sys/time.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <sys/wait.h>
28 #include <regex.h>
29 #include <unistd.h>
30 #include <fcntl.h>
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"
41 #include "dirname.h"
42 #include "virprocess.h"
43 #include "virstring.h"
45 #ifdef TEST_OOM
46 # ifdef TEST_OOM_TRACE
47 # include <dlfcn.h>
48 # include <execinfo.h>
49 # endif
50 #endif
52 #define VIR_FROM_THIS VIR_FROM_NONE
54 VIR_LOG_INIT("tests.testutils");
56 #include "virbitmap.h"
57 #include "virfile.h"
59 static unsigned int testDebug = -1;
60 static unsigned int testVerbose = -1;
61 static unsigned int testExpensive = -1;
62 static unsigned int testRegenerate = -1;
64 #ifdef TEST_OOM
65 static unsigned int testOOM;
66 static unsigned int testOOMStart = -1;
67 static unsigned int testOOMEnd = -1;
68 static unsigned int testOOMTrace;
69 # ifdef TEST_OOM_TRACE
70 void *testAllocStack[30];
71 int ntestAllocStack;
72 # endif
73 #endif
74 static bool testOOMActive;
76 static size_t testCounter;
77 static virBitmapPtr testBitmap;
79 char *progname;
80 static char *perl;
82 bool virTestOOMActive(void)
84 return testOOMActive;
87 static int virTestUseTerminalColors(void)
89 return isatty(STDOUT_FILENO);
92 static unsigned int
93 virTestGetFlag(const char *name)
95 char *flagStr;
96 unsigned int flag;
98 if ((flagStr = getenv(name)) == NULL)
99 return 0;
101 if (virStrToLong_ui(flagStr, NULL, 10, &flag) < 0)
102 return 0;
104 return flag;
107 #ifdef TEST_OOM_TRACE
108 static void virTestAllocHook(int nalloc ATTRIBUTE_UNUSED,
109 void *opaque ATTRIBUTE_UNUSED)
111 ntestAllocStack = backtrace(testAllocStack, ARRAY_CARDINALITY(testAllocStack));
113 #endif
115 #ifdef TEST_OOM_TRACE
116 static void
117 virTestShowTrace(void)
119 size_t j;
120 for (j = 2; j < ntestAllocStack; j++) {
121 Dl_info info;
122 char *cmd;
124 dladdr(testAllocStack[j], &info);
125 if (info.dli_fname &&
126 strstr(info.dli_fname, ".so")) {
127 if (virAsprintf(&cmd, ADDR2LINE " -f -e %s %p",
128 info.dli_fname,
129 ((void*)((unsigned long long)testAllocStack[j]
130 - (unsigned long long)info.dli_fbase))) < 0)
131 continue;
132 } else {
133 if (virAsprintf(&cmd, ADDR2LINE " -f -e %s %p",
134 (char*)(info.dli_fname ? info.dli_fname : "<unknown>"),
135 testAllocStack[j]) < 0)
136 continue;
138 ignore_value(system(cmd));
139 VIR_FREE(cmd);
142 #endif
145 * Runs test
147 * returns: -1 = error, 0 = success
150 virTestRun(const char *title,
151 int (*body)(const void *data), const void *data)
153 int ret = 0;
155 /* Some test are fragile about environ settings. If that's
156 * the case, don't poison it. */
157 if (getenv("VIR_TEST_MOCK_PROGNAME"))
158 setenv("VIR_TEST_MOCK_TESTNAME", title, 1);
160 if (testCounter == 0 && !virTestGetVerbose())
161 fprintf(stderr, " ");
163 testCounter++;
166 /* Skip tests if out of range */
167 if (testBitmap && !virBitmapIsBitSet(testBitmap, testCounter))
168 return 0;
170 if (virTestGetVerbose())
171 fprintf(stderr, "%2zu) %-65s ... ", testCounter, title);
173 virResetLastError();
174 ret = body(data);
175 if (virGetLastErrorCode()) {
176 if (virTestGetVerbose() || virTestGetDebug())
177 virDispatchError(NULL);
180 if (virTestGetVerbose()) {
181 if (ret == 0)
182 if (virTestUseTerminalColors())
183 fprintf(stderr, "\e[32mOK\e[0m\n"); /* green */
184 else
185 fprintf(stderr, "OK\n");
186 else if (ret == EXIT_AM_SKIP)
187 if (virTestUseTerminalColors())
188 fprintf(stderr, "\e[34m\e[1mSKIP\e[0m\n"); /* bold blue */
189 else
190 fprintf(stderr, "SKIP\n");
191 else
192 if (virTestUseTerminalColors())
193 fprintf(stderr, "\e[31m\e[1mFAILED\e[0m\n"); /* bold red */
194 else
195 fprintf(stderr, "FAILED\n");
196 } else {
197 if (testCounter != 1 &&
198 !((testCounter-1) % 40)) {
199 fprintf(stderr, " %-3zu\n", (testCounter-1));
200 fprintf(stderr, " ");
202 if (ret == 0)
203 fprintf(stderr, ".");
204 else if (ret == EXIT_AM_SKIP)
205 fprintf(stderr, "_");
206 else
207 fprintf(stderr, "!");
210 #ifdef TEST_OOM
211 if (testOOM && ret != EXIT_AM_SKIP) {
212 int nalloc;
213 int oomret;
214 int start, end;
215 size_t i;
216 virResetLastError();
217 virAllocTestInit();
218 # ifdef TEST_OOM_TRACE
219 virAllocTestHook(virTestAllocHook, NULL);
220 # endif
221 oomret = body(data);
222 nalloc = virAllocTestCount();
223 fprintf(stderr, " Test OOM for nalloc=%d ", nalloc);
224 if (testOOMStart == -1 ||
225 testOOMEnd == -1) {
226 start = 0;
227 end = nalloc;
228 } else {
229 start = testOOMStart;
230 end = testOOMEnd + 1;
232 testOOMActive = true;
233 for (i = start; i < end; i++) {
234 bool missingFail = false;
235 # ifdef TEST_OOM_TRACE
236 memset(testAllocStack, 0, sizeof(testAllocStack));
237 ntestAllocStack = 0;
238 # endif
239 virAllocTestOOM(i + 1, 1);
240 oomret = body(data);
242 /* fprintf() disabled because XML parsing APIs don't allow
243 * distinguish between element / attribute not present
244 * in the XML (which is non-fatal), vs OOM / malformed
245 * which should be fatal. Thus error reporting for
246 * optionally present XML is mostly broken.
248 if (oomret == 0) {
249 missingFail = true;
250 # if 0
251 fprintf(stderr, " alloc %zu failed but no err status\n", i + 1);
252 # endif
253 } else {
254 if (virGetLastErrorCode() == VIR_ERR_OK) {
255 # if 0
256 fprintf(stderr, " alloc %zu failed but no error report\n", i + 1);
257 # endif
258 missingFail = true;
261 if ((missingFail && testOOMTrace) || (testOOMTrace > 1)) {
262 fprintf(stderr, "%s", "!");
263 # ifdef TEST_OOM_TRACE
264 virTestShowTrace();
265 # endif
266 ret = -1;
267 } else {
268 fprintf(stderr, "%s", ".");
271 testOOMActive = false;
272 if (ret == 0)
273 fprintf(stderr, " OK\n");
274 else
275 fprintf(stderr, " FAILED\n");
276 virAllocTestInit();
278 #endif /* TEST_OOM */
280 unsetenv("VIR_TEST_MOCK_TESTNAME");
281 return ret;
286 * virTestLoadFile:
287 * @file: name of the file to load
288 * @buf: buffer to load the file into
290 * Allocates @buf to the size of FILE. Reads FILE into buffer BUF.
291 * Upon any failure, error is printed to stderr and -1 is returned. 'errno' is
292 * not preserved. On success 0 is returned. Caller is responsible for freeing
293 * @buf.
296 virTestLoadFile(const char *file, char **buf)
298 FILE *fp = fopen(file, "r");
299 struct stat st;
300 char *tmp;
301 int len, tmplen, buflen;
303 if (!fp) {
304 fprintf(stderr, "%s: failed to open: %s\n", file, strerror(errno));
305 return -1;
308 if (fstat(fileno(fp), &st) < 0) {
309 fprintf(stderr, "%s: failed to fstat: %s\n", file, strerror(errno));
310 VIR_FORCE_FCLOSE(fp);
311 return -1;
314 tmplen = buflen = st.st_size + 1;
316 if (VIR_ALLOC_N(*buf, buflen) < 0) {
317 VIR_FORCE_FCLOSE(fp);
318 return -1;
321 tmp = *buf;
322 (*buf)[0] = '\0';
323 if (st.st_size) {
324 /* read the file line by line */
325 while (fgets(tmp, tmplen, fp) != NULL) {
326 len = strlen(tmp);
327 /* stop on an empty line */
328 if (len == 0)
329 break;
330 /* remove trailing backslash-newline pair */
331 if (len >= 2 && tmp[len-2] == '\\' && tmp[len-1] == '\n') {
332 len -= 2;
333 tmp[len] = '\0';
335 /* advance the temporary buffer pointer */
336 tmp += len;
337 tmplen -= len;
339 if (ferror(fp)) {
340 fprintf(stderr, "%s: read failed: %s\n", file, strerror(errno));
341 VIR_FORCE_FCLOSE(fp);
342 VIR_FREE(*buf);
343 return -1;
347 VIR_FORCE_FCLOSE(fp);
348 return 0;
352 static char *
353 virTestLoadFileGetPath(const char *p,
354 va_list ap)
356 virBuffer buf = VIR_BUFFER_INITIALIZER;
357 char *path = NULL;
359 virBufferAddLit(&buf, abs_srcdir "/");
361 if (p) {
362 virBufferAdd(&buf, p, -1);
363 virBufferStrcatVArgs(&buf, ap);
366 if (!(path = virBufferContentAndReset(&buf)))
367 VIR_TEST_VERBOSE("failed to format file path");
369 return path;
374 * virTestLoadFilePath:
375 * @...: file name components terminated with a NULL
377 * Constructs the test file path from variable arguments and loads the file.
378 * 'abs_srcdir' is automatically prepended.
380 char *
381 virTestLoadFilePath(const char *p, ...)
383 char *path = NULL;
384 char *ret = NULL;
385 va_list ap;
387 va_start(ap, p);
389 if (!(path = virTestLoadFileGetPath(p, ap)))
390 goto cleanup;
392 ignore_value(virTestLoadFile(path, &ret));
394 cleanup:
395 va_end(ap);
396 VIR_FREE(path);
398 return ret;
403 * virTestLoadFileJSON:
404 * @...: name components terminated with a NULL
406 * Constructs the test file path from variable arguments and loads and parses
407 * the JSON file. 'abs_srcdir' is automatically prepended to the path.
409 virJSONValuePtr
410 virTestLoadFileJSON(const char *p, ...)
412 virJSONValuePtr ret = NULL;
413 char *jsonstr = NULL;
414 char *path = NULL;
415 va_list ap;
417 va_start(ap, p);
419 if (!(path = virTestLoadFileGetPath(p, ap)))
420 goto cleanup;
422 if (virTestLoadFile(path, &jsonstr) < 0)
423 goto cleanup;
425 if (!(ret = virJSONValueFromString(jsonstr)))
426 VIR_TEST_VERBOSE("failed to parse json from file '%s'", path);
428 cleanup:
429 va_end(ap);
430 VIR_FREE(jsonstr);
431 VIR_FREE(path);
432 return ret;
436 #ifndef WIN32
437 static
438 void virTestCaptureProgramExecChild(const char *const argv[],
439 int pipefd)
441 size_t i;
442 int open_max;
443 int stdinfd = -1;
444 const char *const env[] = {
445 "LANG=C",
446 NULL
449 if ((stdinfd = open("/dev/null", O_RDONLY)) < 0)
450 goto cleanup;
452 open_max = sysconf(_SC_OPEN_MAX);
453 if (open_max < 0)
454 goto cleanup;
456 for (i = 0; i < open_max; i++) {
457 if (i != stdinfd &&
458 i != pipefd) {
459 int tmpfd;
460 tmpfd = i;
461 VIR_FORCE_CLOSE(tmpfd);
465 if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO)
466 goto cleanup;
467 if (dup2(pipefd, STDOUT_FILENO) != STDOUT_FILENO)
468 goto cleanup;
469 if (dup2(pipefd, STDERR_FILENO) != STDERR_FILENO)
470 goto cleanup;
472 /* SUS is crazy here, hence the cast */
473 execve(argv[0], (char *const*)argv, (char *const*)env);
475 cleanup:
476 VIR_FORCE_CLOSE(stdinfd);
480 virTestCaptureProgramOutput(const char *const argv[], char **buf, int maxlen)
482 int pipefd[2];
483 int len;
485 if (pipe(pipefd) < 0)
486 return -1;
488 pid_t pid = fork();
489 switch (pid) {
490 case 0:
491 VIR_FORCE_CLOSE(pipefd[0]);
492 virTestCaptureProgramExecChild(argv, pipefd[1]);
494 VIR_FORCE_CLOSE(pipefd[1]);
495 _exit(EXIT_FAILURE);
497 case -1:
498 return -1;
500 default:
501 VIR_FORCE_CLOSE(pipefd[1]);
502 len = virFileReadLimFD(pipefd[0], maxlen, buf);
503 VIR_FORCE_CLOSE(pipefd[0]);
504 if (virProcessWait(pid, NULL, false) < 0)
505 return -1;
507 return len;
510 #else /* !WIN32 */
512 virTestCaptureProgramOutput(const char *const argv[] ATTRIBUTE_UNUSED,
513 char **buf ATTRIBUTE_UNUSED,
514 int maxlen ATTRIBUTE_UNUSED)
516 return -1;
518 #endif /* !WIN32 */
520 static int
521 virTestRewrapFile(const char *filename)
523 int ret = -1;
524 char *script = NULL;
525 virCommandPtr cmd = NULL;
527 if (!(virStringHasSuffix(filename, ".args") ||
528 virStringHasSuffix(filename, ".ldargs")))
529 return 0;
531 if (!perl) {
532 fprintf(stderr, "cannot rewrap %s: unable to find perl in path", filename);
533 return -1;
536 if (virAsprintf(&script, "%s/test-wrap-argv.pl", abs_srcdir) < 0)
537 goto cleanup;
539 cmd = virCommandNewArgList(perl, script, "--in-place", filename, NULL);
540 if (virCommandRun(cmd, NULL) < 0)
541 goto cleanup;
543 ret = 0;
544 cleanup:
545 VIR_FREE(script);
546 virCommandFree(cmd);
547 return ret;
551 * @param stream: output stream to write differences to
552 * @param expect: expected output text
553 * @param expectName: name designator of the expected text
554 * @param actual: actual output text
555 * @param actualName: name designator of the actual text
556 * @param regenerate: enable or disable regenerate functionality
558 * Display expected and actual output text, trimmed to first and last
559 * characters at which differences occur. Displays names of the text strings if
560 * non-NULL.
562 static int
563 virTestDifferenceFullInternal(FILE *stream,
564 const char *expect,
565 const char *expectName,
566 const char *actual,
567 const char *actualName,
568 bool regenerate)
570 const char *expectStart;
571 const char *expectEnd;
572 const char *actualStart;
573 const char *actualEnd;
575 if (!expect)
576 expect = "";
577 if (!actual)
578 actual = "";
580 expectStart = expect;
581 expectEnd = expect + (strlen(expect)-1);
582 actualStart = actual;
583 actualEnd = actual + (strlen(actual)-1);
585 if (expectName && regenerate && (virTestGetRegenerate() > 0)) {
586 if (virFileWriteStr(expectName, actual, 0666) < 0) {
587 virDispatchError(NULL);
588 return -1;
591 if (virTestRewrapFile(expectName) < 0) {
592 virDispatchError(NULL);
593 return -1;
597 if (!virTestGetDebug())
598 return 0;
600 if (virTestGetDebug() < 2) {
601 /* Skip to first character where they differ */
602 while (*expectStart && *actualStart &&
603 *actualStart == *expectStart) {
604 actualStart++;
605 expectStart++;
608 /* Work backwards to last character where they differ */
609 while (actualEnd > actualStart &&
610 expectEnd > expectStart &&
611 *actualEnd == *expectEnd) {
612 actualEnd--;
613 expectEnd--;
617 /* Show the trimmed differences */
618 if (expectName)
619 fprintf(stream, "\nIn '%s':", expectName);
620 fprintf(stream, "\nOffset %d\nExpect [", (int) (expectStart - expect));
621 if ((expectEnd - expectStart + 1) &&
622 fwrite(expectStart, (expectEnd-expectStart+1), 1, stream) != 1)
623 return -1;
624 fprintf(stream, "]\n");
625 if (actualName)
626 fprintf(stream, "In '%s':\n", actualName);
627 fprintf(stream, "Actual [");
628 if ((actualEnd - actualStart + 1) &&
629 fwrite(actualStart, (actualEnd-actualStart+1), 1, stream) != 1)
630 return -1;
631 fprintf(stream, "]\n");
633 /* Pad to line up with test name ... in virTestRun */
634 fprintf(stream, " ... ");
636 return 0;
640 * @param stream: output stream to write differences to
641 * @param expect: expected output text
642 * @param expectName: name designator of the expected text
643 * @param actual: actual output text
644 * @param actualName: name designator of the actual text
646 * Display expected and actual output text, trimmed to first and last
647 * characters at which differences occur. Displays names of the text strings if
648 * non-NULL. If VIR_TEST_REGENERATE_OUTPUT is used, this function will
649 * regenerate the expected file.
652 virTestDifferenceFull(FILE *stream,
653 const char *expect,
654 const char *expectName,
655 const char *actual,
656 const char *actualName)
658 return virTestDifferenceFullInternal(stream, expect, expectName,
659 actual, actualName, true);
663 * @param stream: output stream to write differences to
664 * @param expect: expected output text
665 * @param expectName: name designator of the expected text
666 * @param actual: actual output text
667 * @param actualName: name designator of the actual text
669 * Display expected and actual output text, trimmed to first and last
670 * characters at which differences occur. Displays names of the text strings if
671 * non-NULL. If VIR_TEST_REGENERATE_OUTPUT is used, this function will not
672 * regenerate the expected file.
675 virTestDifferenceFullNoRegenerate(FILE *stream,
676 const char *expect,
677 const char *expectName,
678 const char *actual,
679 const char *actualName)
681 return virTestDifferenceFullInternal(stream, expect, expectName,
682 actual, actualName, false);
686 * @param stream: output stream to write differences to
687 * @param expect: expected output text
688 * @param actual: actual output text
690 * Display expected and actual output text, trimmed to
691 * first and last characters at which differences occur
694 virTestDifference(FILE *stream,
695 const char *expect,
696 const char *actual)
698 return virTestDifferenceFullNoRegenerate(stream,
699 expect, NULL,
700 actual, NULL);
705 * @param stream: output stream to write differences to
706 * @param expect: expected output text
707 * @param actual: actual output text
709 * Display expected and actual output text, trimmed to
710 * first and last characters at which differences occur
712 int virTestDifferenceBin(FILE *stream,
713 const char *expect,
714 const char *actual,
715 size_t length)
717 size_t start = 0, end = length;
718 ssize_t i;
720 if (!virTestGetDebug())
721 return 0;
723 if (virTestGetDebug() < 2) {
724 /* Skip to first character where they differ */
725 for (i = 0; i < length; i++) {
726 if (expect[i] != actual[i]) {
727 start = i;
728 break;
732 /* Work backwards to last character where they differ */
733 for (i = (length -1); i >= 0; i--) {
734 if (expect[i] != actual[i]) {
735 end = i;
736 break;
740 /* Round to nearest boundary of 4, except that last word can be short */
741 start -= (start % 4);
742 end += 4 - (end % 4);
743 if (end >= length)
744 end = length - 1;
746 /* Show the trimmed differences */
747 fprintf(stream, "\nExpect [ Region %d-%d", (int)start, (int)end);
748 for (i = start; i < end; i++) {
749 if ((i % 4) == 0)
750 fprintf(stream, "\n ");
751 fprintf(stream, "0x%02x, ", ((int)expect[i])&0xff);
753 fprintf(stream, "]\n");
754 fprintf(stream, "Actual [ Region %d-%d", (int)start, (int)end);
755 for (i = start; i < end; i++) {
756 if ((i % 4) == 0)
757 fprintf(stream, "\n ");
758 fprintf(stream, "0x%02x, ", ((int)actual[i])&0xff);
760 fprintf(stream, "]\n");
762 /* Pad to line up with test name ... in virTestRun */
763 fprintf(stream, " ... ");
765 return 0;
769 * @param actual: String input content
770 * @param filename: File to compare @actual against
772 * If @actual is NULL, it's treated as an empty string.
775 virTestCompareToFile(const char *actual,
776 const char *filename)
778 int ret = -1;
779 char *filecontent = NULL;
780 char *fixedcontent = NULL;
781 const char *cmpcontent = actual;
783 if (!cmpcontent)
784 cmpcontent = "";
786 if (virTestLoadFile(filename, &filecontent) < 0 && !virTestGetRegenerate())
787 goto failure;
789 if (filecontent) {
790 size_t filecontentLen = strlen(filecontent);
791 size_t cmpcontentLen = strlen(cmpcontent);
793 if (filecontentLen > 0 &&
794 filecontent[filecontentLen - 1] == '\n' &&
795 (cmpcontentLen == 0 || cmpcontent[cmpcontentLen - 1] != '\n')) {
796 if (virAsprintf(&fixedcontent, "%s\n", cmpcontent) < 0)
797 goto failure;
798 cmpcontent = fixedcontent;
802 if (STRNEQ_NULLABLE(cmpcontent, filecontent)) {
803 virTestDifferenceFull(stderr,
804 filecontent, filename,
805 cmpcontent, NULL);
806 goto failure;
809 ret = 0;
810 failure:
811 VIR_FREE(fixedcontent);
812 VIR_FREE(filecontent);
813 return ret;
817 virTestCompareToULL(unsigned long long expect,
818 unsigned long long actual)
820 VIR_AUTOFREE(char *) expectStr = NULL;
821 VIR_AUTOFREE(char *) actualStr = NULL;
823 if (virAsprintf(&expectStr, "%llu", expect) < 0)
824 return -1;
826 if (virAsprintf(&actualStr, "%llu", actual) < 0)
827 return -1;
829 return virTestCompareToString(expectStr, actualStr);
833 virTestCompareToString(const char *expect,
834 const char *actual)
836 if (STRNEQ_NULLABLE(expect, actual)) {
837 virTestDifference(stderr, expect, actual);
838 return -1;
841 return 0;
844 static void
845 virTestErrorFuncQuiet(void *data ATTRIBUTE_UNUSED,
846 virErrorPtr err ATTRIBUTE_UNUSED)
850 /* register an error handler in tests when using connections */
851 void
852 virTestQuiesceLibvirtErrors(bool always)
854 if (always || !virTestGetVerbose())
855 virSetErrorFunc(NULL, virTestErrorFuncQuiet);
858 struct virtTestLogData {
859 virBuffer buf;
862 static struct virtTestLogData testLog = { VIR_BUFFER_INITIALIZER };
864 static void
865 virtTestLogOutput(virLogSourcePtr source ATTRIBUTE_UNUSED,
866 virLogPriority priority ATTRIBUTE_UNUSED,
867 const char *filename ATTRIBUTE_UNUSED,
868 int lineno ATTRIBUTE_UNUSED,
869 const char *funcname ATTRIBUTE_UNUSED,
870 const char *timestamp,
871 virLogMetadataPtr metadata ATTRIBUTE_UNUSED,
872 unsigned int flags,
873 const char *rawstr ATTRIBUTE_UNUSED,
874 const char *str,
875 void *data)
877 struct virtTestLogData *log = data;
878 virCheckFlags(VIR_LOG_STACK_TRACE,);
879 if (!testOOMActive)
880 virBufferAsprintf(&log->buf, "%s: %s", timestamp, str);
883 static void
884 virtTestLogClose(void *data)
886 struct virtTestLogData *log = data;
888 virBufferFreeAndReset(&log->buf);
891 /* Return a malloc'd string (possibly with strlen of 0) of all data
892 * logged since the last call to this function, or NULL on failure. */
893 char *
894 virTestLogContentAndReset(void)
896 char *ret;
898 if (virBufferError(&testLog.buf))
899 return NULL;
900 ret = virBufferContentAndReset(&testLog.buf);
901 if (!ret)
902 ignore_value(VIR_STRDUP(ret, ""));
903 return ret;
907 unsigned int
908 virTestGetDebug(void)
910 if (testDebug == -1)
911 testDebug = virTestGetFlag("VIR_TEST_DEBUG");
912 return testDebug;
915 unsigned int
916 virTestGetVerbose(void)
918 if (testVerbose == -1)
919 testVerbose = virTestGetFlag("VIR_TEST_VERBOSE");
920 return testVerbose || virTestGetDebug();
923 unsigned int
924 virTestGetExpensive(void)
926 if (testExpensive == -1)
927 testExpensive = virTestGetFlag("VIR_TEST_EXPENSIVE");
928 return testExpensive;
931 unsigned int
932 virTestGetRegenerate(void)
934 if (testRegenerate == -1)
935 testRegenerate = virTestGetFlag("VIR_TEST_REGENERATE_OUTPUT");
936 return testRegenerate;
939 static int
940 virTestSetEnvPath(void)
942 int ret = -1;
943 const char *path = getenv("PATH");
944 char *new_path = NULL;
946 if (path) {
947 if (strstr(path, abs_builddir) != path &&
948 virAsprintf(&new_path, "%s:%s", abs_builddir, path) < 0)
949 goto cleanup;
950 } else {
951 if (VIR_STRDUP(new_path, abs_builddir) < 0)
952 goto cleanup;
955 if (new_path &&
956 setenv("PATH", new_path, 1) < 0)
957 goto cleanup;
959 ret = 0;
960 cleanup:
961 VIR_FREE(new_path);
962 return ret;
965 #define TEST_MOCK (abs_builddir "/.libs/virtestmock.so")
967 int virTestMain(int argc,
968 char **argv,
969 int (*func)(void),
970 ...)
972 const char *lib;
973 va_list ap;
974 int ret;
975 char *testRange = NULL;
976 #ifdef TEST_OOM
977 char *oomstr;
978 #endif
979 size_t noutputs = 0;
980 virLogOutputPtr output = NULL;
981 virLogOutputPtr *outputs = NULL;
983 if (getenv("VIR_TEST_FILE_ACCESS"))
984 VIR_TEST_PRELOAD(TEST_MOCK);
986 va_start(ap, func);
987 while ((lib = va_arg(ap, const char *)))
988 VIR_TEST_PRELOAD(lib);
989 va_end(ap);
991 progname = last_component(argv[0]);
992 if (STRPREFIX(progname, "lt-"))
993 progname += 3;
995 setenv("VIR_TEST_MOCK_PROGNAME", progname, 1);
997 virFileActivateDirOverride(argv[0]);
999 if (virTestSetEnvPath() < 0)
1000 return EXIT_AM_HARDFAIL;
1002 if (!virFileExists(abs_srcdir))
1003 return EXIT_AM_HARDFAIL;
1005 if (argc > 1) {
1006 fprintf(stderr, "Usage: %s\n", argv[0]);
1007 fputs("effective environment variables:\n"
1008 "VIR_TEST_VERBOSE set to show names of individual tests\n"
1009 "VIR_TEST_DEBUG set to show information for debugging failures\n",
1010 stderr);
1011 return EXIT_FAILURE;
1013 fprintf(stderr, "TEST: %s\n", progname);
1015 if (virThreadInitialize() < 0 ||
1016 virErrorInitialize() < 0)
1017 return EXIT_FAILURE;
1019 virLogSetFromEnv();
1020 if (!getenv("LIBVIRT_DEBUG") && !virLogGetNbOutputs()) {
1021 if (!(output = virLogOutputNew(virtTestLogOutput, virtTestLogClose,
1022 &testLog, VIR_LOG_DEBUG,
1023 VIR_LOG_TO_STDERR, NULL)) ||
1024 VIR_APPEND_ELEMENT(outputs, noutputs, output) < 0 ||
1025 virLogDefineOutputs(outputs, noutputs) < 0) {
1026 virLogOutputFree(output);
1027 virLogOutputListFree(outputs, noutputs);
1028 return EXIT_FAILURE;
1032 if ((testRange = getenv("VIR_TEST_RANGE")) != NULL) {
1033 if (!(testBitmap = virBitmapParseUnlimited(testRange))) {
1034 fprintf(stderr, "Cannot parse range %s\n", testRange);
1035 return EXIT_FAILURE;
1039 #ifdef TEST_OOM
1040 if ((oomstr = getenv("VIR_TEST_OOM")) != NULL) {
1041 char *next;
1042 if (testDebug == -1)
1043 testDebug = 1;
1044 testOOM = 1;
1045 if (oomstr[0] != '\0' &&
1046 oomstr[1] == ':') {
1047 if (virStrToLong_ui(oomstr + 2, &next, 10, &testOOMStart) < 0) {
1048 fprintf(stderr, "Cannot parse range %s\n", oomstr);
1049 return EXIT_FAILURE;
1051 if (*next == '\0') {
1052 testOOMEnd = testOOMStart;
1053 } else {
1054 if (*next != '-') {
1055 fprintf(stderr, "Cannot parse range %s\n", oomstr);
1056 return EXIT_FAILURE;
1058 if (virStrToLong_ui(next+1, NULL, 10, &testOOMEnd) < 0) {
1059 fprintf(stderr, "Cannot parse range %s\n", oomstr);
1060 return EXIT_FAILURE;
1063 } else {
1064 testOOMStart = -1;
1065 testOOMEnd = -1;
1069 # ifdef TEST_OOM_TRACE
1070 if ((oomstr = getenv("VIR_TEST_OOM_TRACE")) != NULL) {
1071 if (virStrToLong_ui(oomstr, NULL, 10, &testOOMTrace) < 0) {
1072 fprintf(stderr, "Cannot parse oom trace %s\n", oomstr);
1073 return EXIT_FAILURE;
1076 # else
1077 if (getenv("VIR_TEST_OOM_TRACE")) {
1078 fprintf(stderr, "%s", "OOM test tracing not enabled in this build\n");
1079 return EXIT_FAILURE;
1081 # endif
1082 #else /* TEST_OOM */
1083 if (getenv("VIR_TEST_OOM")) {
1084 fprintf(stderr, "%s", "OOM testing not enabled in this build\n");
1085 return EXIT_FAILURE;
1087 if (getenv("VIR_TEST_OOM_TRACE")) {
1088 fprintf(stderr, "%s", "OOM test tracing not enabled in this build\n");
1089 return EXIT_FAILURE;
1091 #endif /* TEST_OOM */
1093 /* Find perl early because some tests override PATH */
1094 perl = virFindFileInPath("perl");
1096 ret = (func)();
1098 virResetLastError();
1099 if (!virTestGetVerbose() && ret != EXIT_AM_SKIP) {
1100 if (testCounter == 0 || testCounter % 40)
1101 fprintf(stderr, "%*s", 40 - (int)(testCounter % 40), "");
1102 fprintf(stderr, " %-3zu %s\n", testCounter, ret == 0 ? "OK" : "FAIL");
1104 virLogReset();
1105 VIR_FREE(perl);
1106 return ret;
1111 * @cmdset contains a list of command line args, eg
1113 * "/usr/sbin/iptables --table filter --insert INPUT --in-interface virbr0 --protocol tcp --destination-port 53 --jump ACCEPT
1114 * /usr/sbin/iptables --table filter --insert INPUT --in-interface virbr0 --protocol udp --destination-port 53 --jump ACCEPT
1115 * /usr/sbin/iptables --table filter --insert FORWARD --in-interface virbr0 --jump REJECT
1116 * /usr/sbin/iptables --table filter --insert FORWARD --out-interface virbr0 --jump REJECT
1117 * /usr/sbin/iptables --table filter --insert FORWARD --in-interface virbr0 --out-interface virbr0 --jump ACCEPT"
1119 * And we're munging it in-place to strip the path component
1120 * of the command line, to produce
1122 * "iptables --table filter --insert INPUT --in-interface virbr0 --protocol tcp --destination-port 53 --jump ACCEPT
1123 * iptables --table filter --insert INPUT --in-interface virbr0 --protocol udp --destination-port 53 --jump ACCEPT
1124 * iptables --table filter --insert FORWARD --in-interface virbr0 --jump REJECT
1125 * iptables --table filter --insert FORWARD --out-interface virbr0 --jump REJECT
1126 * iptables --table filter --insert FORWARD --in-interface virbr0 --out-interface virbr0 --jump ACCEPT"
1128 void virTestClearCommandPath(char *cmdset)
1130 size_t offset = 0;
1131 char *lineStart = cmdset;
1132 char *lineEnd = strchr(lineStart, '\n');
1134 while (lineStart) {
1135 char *dirsep;
1136 char *movestart;
1137 size_t movelen;
1138 dirsep = strchr(lineStart, ' ');
1139 if (dirsep) {
1140 while (dirsep > lineStart && *dirsep != '/')
1141 dirsep--;
1142 if (*dirsep == '/')
1143 dirsep++;
1144 movestart = dirsep;
1145 } else {
1146 movestart = lineStart;
1148 movelen = lineEnd ? lineEnd - movestart : strlen(movestart);
1150 if (movelen) {
1151 memmove(cmdset + offset, movestart, movelen + 1);
1152 offset += movelen + 1;
1154 lineStart = lineEnd ? lineEnd + 1 : NULL;
1155 lineEnd = lineStart ? strchr(lineStart, '\n') : NULL;
1157 cmdset[offset] = '\0';
1161 virCapsPtr virTestGenericCapsInit(void)
1163 virCapsPtr caps;
1164 virCapsGuestPtr guest;
1166 if ((caps = virCapabilitiesNew(VIR_ARCH_X86_64,
1167 false, false)) == NULL)
1168 return NULL;
1170 if ((guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM, VIR_ARCH_I686,
1171 "/usr/bin/acme-virt", NULL,
1172 0, NULL)) == NULL)
1173 goto error;
1175 if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_TEST, NULL, NULL, 0, NULL))
1176 goto error;
1177 if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_QEMU,
1178 NULL, NULL, 0, NULL))
1179 goto error;
1180 if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_KVM,
1181 NULL, NULL, 0, NULL))
1182 goto error;
1184 if ((guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM, VIR_ARCH_X86_64,
1185 "/usr/bin/acme-virt", NULL,
1186 0, NULL)) == NULL)
1187 goto error;
1189 if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_TEST, NULL, NULL, 0, NULL))
1190 goto error;
1191 if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_QEMU,
1192 NULL, NULL, 0, NULL))
1193 goto error;
1194 if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_KVM,
1195 NULL, NULL, 0, NULL))
1196 goto error;
1199 if (virTestGetDebug() > 1) {
1200 char *caps_str;
1202 caps_str = virCapabilitiesFormatXML(caps);
1203 if (!caps_str)
1204 goto error;
1206 VIR_TEST_DEBUG("Generic driver capabilities:\n%s", caps_str);
1208 VIR_FREE(caps_str);
1211 return caps;
1213 error:
1214 virObjectUnref(caps);
1215 return NULL;
1219 #define MAX_CELLS 4
1220 #define MAX_CPUS_IN_CELL 2
1221 #define MAX_MEM_IN_CELL 2097152
1224 * Build NUMA topology with cell id starting from (0 + seq)
1225 * for testing
1228 virTestCapsBuildNUMATopology(virCapsPtr caps,
1229 int seq)
1231 virCapsHostNUMACellCPUPtr cell_cpus = NULL;
1232 int core_id, cell_id;
1233 int id;
1235 id = 0;
1236 for (cell_id = 0; cell_id < MAX_CELLS; cell_id++) {
1237 if (VIR_ALLOC_N(cell_cpus, MAX_CPUS_IN_CELL) < 0)
1238 goto error;
1240 for (core_id = 0; core_id < MAX_CPUS_IN_CELL; core_id++) {
1241 cell_cpus[core_id].id = id + core_id;
1242 cell_cpus[core_id].socket_id = cell_id + seq;
1243 cell_cpus[core_id].core_id = id + core_id;
1244 if (!(cell_cpus[core_id].siblings =
1245 virBitmapNew(MAX_CPUS_IN_CELL)))
1246 goto error;
1247 ignore_value(virBitmapSetBit(cell_cpus[core_id].siblings, id));
1249 id++;
1251 if (virCapabilitiesAddHostNUMACell(caps, cell_id + seq,
1252 MAX_MEM_IN_CELL,
1253 MAX_CPUS_IN_CELL, cell_cpus,
1254 VIR_ARCH_NONE, NULL,
1255 VIR_ARCH_NONE, NULL) < 0)
1256 goto error;
1258 cell_cpus = NULL;
1261 return 0;
1263 error:
1264 virCapabilitiesClearHostNUMACellCPUTopology(cell_cpus, MAX_CPUS_IN_CELL);
1265 VIR_FREE(cell_cpus);
1266 return -1;
1269 static virDomainDefParserConfig virTestGenericDomainDefParserConfig = {
1270 .features = VIR_DOMAIN_DEF_FEATURE_INDIVIDUAL_VCPUS,
1273 virDomainXMLOptionPtr virTestGenericDomainXMLConfInit(void)
1275 return virDomainXMLOptionNew(&virTestGenericDomainDefParserConfig,
1276 NULL, NULL, NULL, NULL);
1281 testCompareDomXML2XMLFiles(virCapsPtr caps, virDomainXMLOptionPtr xmlopt,
1282 const char *infile, const char *outfile, bool live,
1283 unsigned int parseFlags,
1284 testCompareDomXML2XMLResult expectResult)
1286 char *actual = NULL;
1287 int ret = -1;
1288 testCompareDomXML2XMLResult result;
1289 virDomainDefPtr def = NULL;
1290 unsigned int parse_flags = live ? 0 : VIR_DOMAIN_DEF_PARSE_INACTIVE;
1291 unsigned int format_flags = VIR_DOMAIN_DEF_FORMAT_SECURE;
1293 parse_flags |= parseFlags;
1295 if (!virFileExists(infile)) {
1296 VIR_TEST_DEBUG("Test input file '%s' is missing", infile);
1297 return -1;
1300 if (!live)
1301 format_flags |= VIR_DOMAIN_DEF_FORMAT_INACTIVE;
1303 if (!(def = virDomainDefParseFile(infile, caps, xmlopt, NULL, parse_flags))) {
1304 result = TEST_COMPARE_DOM_XML2XML_RESULT_FAIL_PARSE;
1305 goto out;
1308 if (!virDomainDefCheckABIStability(def, def, xmlopt)) {
1309 VIR_TEST_DEBUG("ABI stability check failed on %s", infile);
1310 result = TEST_COMPARE_DOM_XML2XML_RESULT_FAIL_STABILITY;
1311 goto out;
1314 if (!(actual = virDomainDefFormat(def, caps, format_flags))) {
1315 result = TEST_COMPARE_DOM_XML2XML_RESULT_FAIL_FORMAT;
1316 goto out;
1319 if (virTestCompareToFile(actual, outfile) < 0) {
1320 result = TEST_COMPARE_DOM_XML2XML_RESULT_FAIL_COMPARE;
1321 goto out;
1324 result = TEST_COMPARE_DOM_XML2XML_RESULT_SUCCESS;
1326 out:
1327 if (result == expectResult) {
1328 ret = 0;
1329 if (expectResult != TEST_COMPARE_DOM_XML2XML_RESULT_SUCCESS) {
1330 VIR_TEST_DEBUG("Got expected failure code=%d msg=%s",
1331 result, virGetLastErrorMessage());
1333 } else {
1334 ret = -1;
1335 VIR_TEST_DEBUG("Expected result code=%d but received code=%d",
1336 expectResult, result);
1339 VIR_FREE(actual);
1340 virDomainDefFree(def);
1341 return ret;
1345 static int virtTestCounter;
1346 static char virtTestCounterStr[128];
1347 static char *virtTestCounterPrefixEndOffset;
1351 * virTestCounterReset:
1352 * @prefix: name of the test group
1354 * Resets the counter and sets up the test group name to use with
1355 * virTestCounterNext(). This function is not thread safe.
1357 * Note: The buffer for the assembled message is 128 bytes long. Longer test
1358 * case names (including the number index) will be silently truncated.
1360 void
1361 virTestCounterReset(const char *prefix)
1363 virtTestCounter = 0;
1365 ignore_value(virStrcpyStatic(virtTestCounterStr, prefix));
1366 virtTestCounterPrefixEndOffset = strchrnul(virtTestCounterStr, '\0');
1371 * virTestCounterNext:
1373 * This function is designed to ease test creation and reordering by adding
1374 * a way to do automagic test case numbering.
1376 * Returns string consisting of test name prefix configured via
1377 * virTestCounterReset() and a number that increments in every call of this
1378 * function. This function is not thread safe.
1380 * Note: The buffer for the assembled message is 128 bytes long. Longer test
1381 * case names (including the number index) will be silently truncated.
1383 const char
1384 *virTestCounterNext(void)
1386 size_t len = ARRAY_CARDINALITY(virtTestCounterStr);
1388 /* calculate length of the rest of the string */
1389 len -= (virtTestCounterPrefixEndOffset - virtTestCounterStr);
1391 snprintf(virtTestCounterPrefixEndOffset, len, "%d", ++virtTestCounter);
1393 return virtTestCounterStr;