diff options
author | Rohan McGovern <rohan.mcgovern@nokia.com> | 2009-07-14 07:02:35 (GMT) |
---|---|---|
committer | Rohan McGovern <rohan.mcgovern@nokia.com> | 2009-07-15 22:47:56 (GMT) |
commit | 1b5f6836ffeda29925bb7f3a65b68c53341fdc91 (patch) | |
tree | a7e90241b3a06f2918d312fb950c8fcca6493bf3 | |
parent | 4a2471196122a095481f1e0cc6b7b9b2d3027592 (diff) | |
download | Qt-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.
-rw-r--r-- | src/testlib/qtestcase.cpp | 86 | ||||
-rw-r--r-- | tests/auto/selftests/expected_crashes_3.txt | 8 | ||||
-rw-r--r-- | tests/auto/selftests/selftests.qrc | 1 | ||||
-rw-r--r-- | tests/auto/selftests/tst_selftests.cpp | 4 |
4 files changed, 93 insertions, 6 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 (...) { diff --git a/tests/auto/selftests/expected_crashes_3.txt b/tests/auto/selftests/expected_crashes_3.txt new file mode 100644 index 0000000..55cd0b4 --- /dev/null +++ b/tests/auto/selftests/expected_crashes_3.txt @@ -0,0 +1,8 @@ +********* Start testing of tst_Crashes ********* +Config: Using QTest library 4.6.0, Qt 4.6.0 +PASS : tst_Crashes::initTestCase() +QFATAL : tst_Crashes::crash() Received signal 11 +FAIL! : tst_Crashes::crash() Received a fatal error. + Loc: [Unknown file(0)] +Totals: 1 passed, 1 failed, 0 skipped +********* Finished testing of tst_Crashes ********* diff --git a/tests/auto/selftests/selftests.qrc b/tests/auto/selftests/selftests.qrc index 9dc9dd0..3d78bf5 100644 --- a/tests/auto/selftests/selftests.qrc +++ b/tests/auto/selftests/selftests.qrc @@ -14,6 +14,7 @@ <file>expected_fetchbogus.txt</file> <file>expected_crashes_1.txt</file> <file>expected_crashes_2.txt</file> + <file>expected_crashes_3.txt</file> <file>expected_multiexec.txt</file> <file>expected_failinit.txt</file> <file>expected_failinitdata.txt</file> diff --git a/tests/auto/selftests/tst_selftests.cpp b/tests/auto/selftests/tst_selftests.cpp index ba17ccb..8eb7fe1 100644 --- a/tests/auto/selftests/tst_selftests.cpp +++ b/tests/auto/selftests/tst_selftests.cpp @@ -297,7 +297,9 @@ void tst_Selftests::runSubTest() void tst_Selftests::initTestCase() { - m_checkXMLBlacklist.append("crashes"); // This test crashes +#ifndef Q_OS_UNIX + m_checkXMLBlacklist.append("crashes"); // This test crashes (XML valid on Unix only) +#endif m_checkXMLBlacklist.append("waitwithoutgui"); // This test is not a QTestLib test. /* Output from several tests is broken with the XML output method, |