summaryrefslogtreecommitdiffstats
path: root/src/testlib
diff options
context:
space:
mode:
authorRohan McGovern <rohan.mcgovern@nokia.com>2009-07-14 07:02:35 (GMT)
committerRohan McGovern <rohan.mcgovern@nokia.com>2009-07-15 22:47:56 (GMT)
commit1b5f6836ffeda29925bb7f3a65b68c53341fdc91 (patch)
treea7e90241b3a06f2918d312fb950c8fcca6493bf3 /src/testlib
parent4a2471196122a095481f1e0cc6b7b9b2d3027592 (diff)
downloadQt-1b5f6836ffeda29925bb7f3a65b68c53341fdc91.zip
Qt-1b5f6836ffeda29925bb7f3a65b68c53341fdc91.tar.gz
Qt-1b5f6836ffeda29925bb7f3a65b68c53341fdc91.tar.bz2
Use Unix signal handlers to properly close the test log when a test is
terminated by a signal. The new XML testloggers in Qt 4.6 only output a testlog after the test completes. Therefore, if a test crashes, no testlog will be output at all. This is a functional regression from Qt 4.5 and earlier where the testlog would be output up to the point where the crash occurred. This is a Unix-specific fix for this problem. This change is also useful for hanging tests; if the test is killed with SIGTERM it will output the test log up to the current test before it exits.
Diffstat (limited to 'src/testlib')
-rw-r--r--src/testlib/qtestcase.cpp86
1 files changed, 81 insertions, 5 deletions
diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp
index 435ecf4..9ac9562 100644
--- a/src/testlib/qtestcase.cpp
+++ b/src/testlib/qtestcase.cpp
@@ -72,6 +72,8 @@
#include <windows.h> // for Sleep
#endif
#ifdef Q_OS_UNIX
+#include <errno.h>
+#include <signal.h>
#include <time.h>
#endif
@@ -1330,6 +1332,80 @@ static void qInvokeTestMethods(QObject *testObject)
QTestLog::stopLogging();
}
+#ifdef Q_OS_UNIX
+class FatalSignalHandler
+{
+public:
+ FatalSignalHandler();
+ ~FatalSignalHandler();
+
+private:
+ static void signal(int);
+ sigset_t handledSignals;
+};
+
+void FatalSignalHandler::signal(int signum)
+{
+ qFatal("Received signal %d", signum);
+}
+
+FatalSignalHandler::FatalSignalHandler()
+{
+ sigemptyset(&handledSignals);
+
+ const int fatalSignals[] = {
+ SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGFPE, SIGSEGV, SIGPIPE, SIGTERM, 0 };
+
+ struct sigaction act;
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = FatalSignalHandler::signal;
+
+ // Remove the handler after it is invoked.
+ act.sa_flags = SA_RESETHAND;
+
+ // Block all fatal signals in our signal handler so we don't try to close
+ // the testlog twice.
+ sigemptyset(&act.sa_mask);
+ for (int i = 0; fatalSignals[i]; ++i)
+ sigaddset(&act.sa_mask, fatalSignals[i]);
+
+ struct sigaction oldact;
+
+ for (int i = 0; fatalSignals[i]; ++i) {
+ sigaction(fatalSignals[i], &act, &oldact);
+ // Don't overwrite any non-default handlers
+ if (oldact.sa_flags & SA_SIGINFO || oldact.sa_handler != SIG_DFL) {
+ sigaction(fatalSignals[i], &oldact, 0);
+ } else {
+ sigaddset(&handledSignals, fatalSignals[i]);
+ }
+ }
+}
+
+
+FatalSignalHandler::~FatalSignalHandler()
+{
+ // Unregister any of our remaining signal handlers
+ struct sigaction act;
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = SIG_DFL;
+
+ struct sigaction oldact;
+
+ for (int i = 0; i < 32; ++i) {
+ if (!sigismember(&handledSignals, i))
+ continue;
+ sigaction(i, &act, &oldact);
+
+ // If someone overwrote it in the mean time, put it back
+ if (oldact.sa_handler != FatalSignalHandler::signal)
+ sigaction(i, &oldact, 0);
+ }
+}
+
+#endif
+
+
} // namespace
/*!
@@ -1424,14 +1500,14 @@ int QTest::qExec(QObject *testObject, int argc, char **argv)
QBenchmarkValgrindUtils::cleanup();
- } else {
+ } else
+#endif
+ {
+#ifdef Q_OS_UNIX
+ FatalSignalHandler handler;
#endif
-
qInvokeTestMethods(testObject);
-
-#ifdef QTESTLIB_USE_VALGRIND
}
-#endif
#ifndef QT_NO_EXCEPTIONS
} catch (...) {