]> xenbits.xensource.com Git - libvirt.git/commitdiff
Generic test suite helpers for OOM testing
authorDaniel P. Berrange <berrange@redhat.com>
Thu, 29 May 2008 15:21:45 +0000 (15:21 +0000)
committerDaniel P. Berrange <berrange@redhat.com>
Thu, 29 May 2008 15:21:45 +0000 (15:21 +0000)
ChangeLog
tests/Makefile.am
tests/oomtrace.pl [new file with mode: 0644]
tests/testutils.c
tests/testutils.h

index 080e32fb892ed434cb9d52d50ba849111b2b9a56..ed7cc0acc9f93e215bc9fcaa5b4b880196da791d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Thu May 29 11:12:00 EST 2008 Daniel P. Berrange <berrange@redhat.com>
+
+       * tests/testutils.c, tests/testutils.h: Add generic main()
+       impl for test programs to leverage OOM testing
+       * tests/Makefile.am, tests/oomtrace.pl: post-processor for
+       generating file/line number backtraces from OOM reports.
+
 Thu May 29 11:12:00 EST 2008 Daniel P. Berrange <berrange@redhat.com>
 
        * src/memory.c, src/memory.h, configure.ac: Add generics hooks
index 214094f0a951a762b6cbac47f708a697dc7452b3..303388ce49a68440026b3a688869dcca0ff1b53f 100644 (file)
@@ -33,6 +33,7 @@ LDADDS = \
         $(COVERAGE_LDFLAGS)
 
 EXTRA_DIST =           \
+        oomtrace.pl     \
        test-lib.sh     \
        xmlrpcserver.py \
        test_conf.sh    \
diff --git a/tests/oomtrace.pl b/tests/oomtrace.pl
new file mode 100644 (file)
index 0000000..c615ed9
--- /dev/null
@@ -0,0 +1,41 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+(my $ME = $0) =~ s|.*/||;
+# use File::Coda; # http://meyering.net/code/Coda/
+END {
+  defined fileno STDOUT or return;
+  close STDOUT and return;
+  warn "$ME: failed to close standard output: $!\n";
+  $? ||= 1;
+}
+
+
+my @data = <>;
+
+
+my %trace;
+my %lines;
+
+foreach (@data) {
+    if (/^\s*TRACE:\s+(\S+?)(?:\(.*\))?\s+\[0x(.*)\]\s*$/ ) {
+       $trace{$2} = $1;
+    }
+}
+
+foreach my $key (keys %trace) {
+    my $val = $trace{$key};
+    my $info = $val =~ /\?\?/ ? $val : `addr2line -e $val $key`;
+    $lines{$key} = $info;
+}
+
+
+foreach (@data) {
+    if (/^\s*TRACE:\s+(\S+?)(?:\(.*\))?\s+\[0x(.*)\]\s*$/ ) {
+       print $lines{$2};
+    } else {
+       print;
+    }
+}
index ea2c59f0e42945f87aa25d0730a335e8abb0c630..da24093ee06c2cdac4e2b22db7fb7f781c3b5203 100644 (file)
 #include <limits.h>
 #include "testutils.h"
 #include "internal.h"
+#include "memory.h"
+#include "util.h"
+
+#if TEST_OOM_TRACE
+#include <execinfo.h>
+#endif
 
 #ifdef HAVE_PATHS_H
 #include <paths.h>
     ((((int) ((T)->tv_sec - (U)->tv_sec)) * 1000000.0 +        \
       ((int) ((T)->tv_usec - (U)->tv_usec))) / 1000.0)
 
+static unsigned int testOOM = 0;
+static unsigned int testDebug = 0;
+static unsigned int testCounter = 0;
+
 double
 virtTestCountAverage(double *items, int nitems)
 {
@@ -60,12 +70,13 @@ virtTestRun(const char *title, int nloops, int (*body)(const void *data), const
 {
     int i, ret = 0;
     double *ts = NULL;
-    static int counter = 0;
 
-    counter++;
+    testCounter++;
 
-    fprintf(stderr, "%2d) %-65s ... ", counter, title);
-    fflush(stderr);
+    if (testOOM < 2) {
+        fprintf(stderr, "%2d) %-65s ... ", testCounter, title);
+        fflush(stderr);
+    }
 
     if (nloops > 1 && (ts = calloc(nloops,
                                    sizeof(double)))==NULL)
@@ -83,13 +94,15 @@ virtTestRun(const char *title, int nloops, int (*body)(const void *data), const
             ts[i] = DIFF_MSEC(&after, &before);
         }
     }
-    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");
+    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");
+    }
 
     free(ts);
     return ret;
@@ -232,13 +245,14 @@ int virtTestDifference(FILE *stream,
     const char *expectEnd = expect + (strlen(expect)-1);
     const char *actualStart = actual;
     const char *actualEnd = actual + (strlen(actual)-1);
-    const char *debug;
 
-    if ((debug = getenv("DEBUG_TESTS")) == NULL)
+    if (testOOM < 2)
         return 0;
 
-    if (STREQ(debug, "") ||
-        STREQ(debug, "1")) {
+    if (!testDebug)
+        return 0;
+
+    if (testDebug < 2) {
         /* Skip to first character where they differ */
         while (*expectStart && *actualStart &&
                *actualStart == *expectStart) {
@@ -272,3 +286,114 @@ int virtTestDifference(FILE *stream,
 
     return 0;
 }
+
+static void
+virtTestErrorFuncQuiet(void *data ATTRIBUTE_UNUSED,
+                       virErrorPtr err ATTRIBUTE_UNUSED)
+{ }
+
+static void
+virtTestErrorHook(void *data ATTRIBUTE_UNUSED)
+{
+#if TEST_OOM_TRACE
+    void *trace[30];
+    int ntrace = ARRAY_CARDINALITY(trace);
+    int i;
+    char **symbols = NULL;
+
+    ntrace = backtrace(trace, ntrace);
+    symbols = backtrace_symbols(trace, ntrace);
+    if (symbols) {
+        fprintf(stderr, "Failing an allocation at:\n");
+        for (i = 0 ; i < ntrace ; i++) {
+            if (symbols[i])
+                fprintf(stderr, "  TRACE:  %s\n", symbols[i]);
+        }
+        free(symbols);
+    }
+#endif
+}
+
+
+int virtTestMain(int argc,
+                 char **argv,
+                 int (*func)(int, char **))
+{
+#if TEST_OOM
+    int ret;
+    int approxAlloc = 0;
+    int n;
+    char *oomStr = NULL, *debugStr;
+    int oomCount;
+
+    if ((debugStr = getenv("VIR_TEST_DEBUG")) != NULL) {
+        if (virStrToLong_i(debugStr, NULL, 10, &testDebug) < 0)
+            testDebug = 0;
+
+        if (testDebug < 0)
+            testDebug = 0;
+    }
+
+    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;
+    }
+
+    if (testOOM)
+        virAllocTestInit();
+
+    /* Run once to count allocs, and ensure it passes :-) */
+    ret = (func)(argc, argv);
+    if (ret != EXIT_SUCCESS)
+        return EXIT_FAILURE;
+
+    if (testDebug)
+        virAllocTestHook(virtTestErrorHook, NULL);
+
+
+    if (testOOM) {
+        /* Makes next test runs quiet... */
+        testOOM++;
+        virSetErrorFunc(NULL, virtTestErrorFuncQuiet);
+
+        approxAlloc = virAllocTestCount();
+        testCounter++;
+        if (testDebug)
+            fprintf(stderr, "%d) OOM...\n", testCounter);
+        else
+            fprintf(stderr, "%d) OOM of %d allocs ", testCounter, approxAlloc);
+
+        /* Run once for each alloc, failing a different one
+           and validating that the test case failed */
+        for (n = 0; n < approxAlloc ; n++) {
+            if (!testDebug) {
+                fprintf(stderr, ".");
+                fflush(stderr);
+            }
+            virAllocTestOOM(n+1, oomCount);
+
+            if (((func)(argc, argv)) != EXIT_FAILURE) {
+                ret = EXIT_FAILURE;
+                break;
+            }
+        }
+
+        if (testDebug)
+            fprintf(stderr, " ... OOM of %d allocs", approxAlloc);
+
+        if (ret == EXIT_SUCCESS)
+            fprintf(stderr, " OK\n");
+        else
+            fprintf(stderr, " FAILED\n");
+    }
+    return ret;
+
+#else
+    return (func)(argc, argv);
+#endif
+}
index b1cd22e13b93bd1d4ff2584db4d60055d3b22879..5050926a906746c7682d4a714100c0c0d5866719 100644 (file)
@@ -37,6 +37,15 @@ extern "C" {
                            const char *expect,
                            const char *actual);
 
+    int virtTestMain(int argc,
+                     char **argv,
+                     int (*func)(int, char **));
+
+#define VIRT_TEST_MAIN(func)                    \
+    int main(int argc, char **argv)  {          \
+        return virtTestMain(argc,argv, func);   \
+    }
+
 #ifdef __cplusplus
 }
 #endif