mirror of
https://github.com/libvirt/libvirt.git
synced 2025-02-25 18:55:26 -06:00
Generic test suite helpers for OOM testing
This commit is contained in:
@@ -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>
|
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
|
* src/memory.c, src/memory.h, configure.ac: Add generics hooks
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ LDADDS = \
|
|||||||
$(COVERAGE_LDFLAGS)
|
$(COVERAGE_LDFLAGS)
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
|
oomtrace.pl \
|
||||||
test-lib.sh \
|
test-lib.sh \
|
||||||
xmlrpcserver.py \
|
xmlrpcserver.py \
|
||||||
test_conf.sh \
|
test_conf.sh \
|
||||||
|
|||||||
41
tests/oomtrace.pl
Normal file
41
tests/oomtrace.pl
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,6 +24,12 @@
|
|||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include "testutils.h"
|
#include "testutils.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#if TEST_OOM_TRACE
|
||||||
|
#include <execinfo.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_PATHS_H
|
#ifdef HAVE_PATHS_H
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
@@ -38,6 +44,10 @@
|
|||||||
((((int) ((T)->tv_sec - (U)->tv_sec)) * 1000000.0 + \
|
((((int) ((T)->tv_sec - (U)->tv_sec)) * 1000000.0 + \
|
||||||
((int) ((T)->tv_usec - (U)->tv_usec))) / 1000.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
|
double
|
||||||
virtTestCountAverage(double *items, int nitems)
|
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;
|
int i, ret = 0;
|
||||||
double *ts = NULL;
|
double *ts = NULL;
|
||||||
static int counter = 0;
|
|
||||||
|
|
||||||
counter++;
|
testCounter++;
|
||||||
|
|
||||||
fprintf(stderr, "%2d) %-65s ... ", counter, title);
|
if (testOOM < 2) {
|
||||||
fflush(stderr);
|
fprintf(stderr, "%2d) %-65s ... ", testCounter, title);
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
|
||||||
if (nloops > 1 && (ts = calloc(nloops,
|
if (nloops > 1 && (ts = calloc(nloops,
|
||||||
sizeof(double)))==NULL)
|
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);
|
ts[i] = DIFF_MSEC(&after, &before);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ret == 0 && ts)
|
if (testOOM < 2) {
|
||||||
fprintf(stderr, "OK [%.5f ms]\n",
|
if (ret == 0 && ts)
|
||||||
virtTestCountAverage(ts, nloops));
|
fprintf(stderr, "OK [%.5f ms]\n",
|
||||||
else if (ret == 0)
|
virtTestCountAverage(ts, nloops));
|
||||||
fprintf(stderr, "OK\n");
|
else if (ret == 0)
|
||||||
else
|
fprintf(stderr, "OK\n");
|
||||||
fprintf(stderr, "FAILED\n");
|
else
|
||||||
|
fprintf(stderr, "FAILED\n");
|
||||||
|
}
|
||||||
|
|
||||||
free(ts);
|
free(ts);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -232,13 +245,14 @@ int virtTestDifference(FILE *stream,
|
|||||||
const char *expectEnd = expect + (strlen(expect)-1);
|
const char *expectEnd = expect + (strlen(expect)-1);
|
||||||
const char *actualStart = actual;
|
const char *actualStart = actual;
|
||||||
const char *actualEnd = actual + (strlen(actual)-1);
|
const char *actualEnd = actual + (strlen(actual)-1);
|
||||||
const char *debug;
|
|
||||||
|
|
||||||
if ((debug = getenv("DEBUG_TESTS")) == NULL)
|
if (testOOM < 2)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (STREQ(debug, "") ||
|
if (!testDebug)
|
||||||
STREQ(debug, "1")) {
|
return 0;
|
||||||
|
|
||||||
|
if (testDebug < 2) {
|
||||||
/* Skip to first character where they differ */
|
/* Skip to first character where they differ */
|
||||||
while (*expectStart && *actualStart &&
|
while (*expectStart && *actualStart &&
|
||||||
*actualStart == *expectStart) {
|
*actualStart == *expectStart) {
|
||||||
@@ -272,3 +286,114 @@ int virtTestDifference(FILE *stream,
|
|||||||
|
|
||||||
return 0;
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -37,6 +37,15 @@ extern "C" {
|
|||||||
const char *expect,
|
const char *expect,
|
||||||
const char *actual);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user