diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/testlib/qtestcase.cpp | 91 |
1 files changed, 88 insertions, 3 deletions
diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index e2f98c2f04..4d4a3cd7b2 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -50,6 +50,9 @@ #include <QtCore/private/qtools_p.h> #include <QtCore/qdiriterator.h> #include <QtCore/qtemporarydir.h> +#include <QtCore/qthread.h> +#include <QtCore/qwaitcondition.h> +#include <QtCore/qmutex.h> #include <QtTest/private/qtestlog_p.h> #include <QtTest/private/qtesttable_p.h> @@ -70,6 +73,11 @@ #include <stdio.h> #include <stdlib.h> +#if defined(Q_OS_LINUX) +#include <sys/types.h> +#include <unistd.h> +#endif + #ifdef Q_OS_WIN #ifndef Q_OS_WINCE # if !defined(Q_CC_MINGW) || (defined(Q_CC_MINGW) && defined(__MINGW64_VERSION_MAJOR)) @@ -93,6 +101,28 @@ QT_BEGIN_NAMESPACE using QtMiscUtils::toHexUpper; using QtMiscUtils::fromHex; + +static void stackTrace() +{ + bool ok = false; + const int disableStackDump = qEnvironmentVariableIntValue("QTEST_DISABLE_STACK_DUMP", &ok); + if (ok && disableStackDump == 1) + return; +#ifdef Q_OS_LINUX + fprintf(stderr, "\n========= Received signal, dumping stack ==============\n"); + char cmd[512]; + qsnprintf(cmd, 512, "gdb --pid %d 2>/dev/null <<EOF\n" + "set prompt\n" + "thread apply all where\n" + "detach\n" + "quit\n" + "EOF\n", + (int)getpid()); + system(cmd); + fprintf(stderr, "========= End of stack trace ==============\n"); +#endif +} + /*! \namespace QTest \inmodule QtTest @@ -2010,6 +2040,55 @@ static void qInvokeTestMethodDataEntry(char *slot) } } +class WatchDog : public QThread +{ +public: + WatchDog() + { + timeout.store(-1); + start(); + } + ~WatchDog() { + { + QMutexLocker locker(&mutex); + timeout.store(0); + waitCondition.wakeAll(); + } + wait(); + } + + void beginTest() { + QMutexLocker locker(&mutex); + timeout.store(5*60*1000); + waitCondition.wakeAll(); + } + + void testFinished() { + QMutexLocker locker(&mutex); + timeout.store(-1); + waitCondition.wakeAll(); + } + + void run() { + QMutexLocker locker(&mutex); + while (1) { + int t = timeout.load(); + if (!t) + break; + if (!waitCondition.wait(&mutex, t)) { + stackTrace(); + qFatal("Test function timed out"); + } + } + } + +private: + QBasicAtomicInt timeout; + QMutex mutex; + QWaitCondition waitCondition; +}; + + /*! \internal @@ -2019,7 +2098,7 @@ static void qInvokeTestMethodDataEntry(char *slot) If the function was successfully called, true is returned, otherwise false. */ -static bool qInvokeTestMethod(const char *slotName, const char *data=0) +static bool qInvokeTestMethod(const char *slotName, const char *data, WatchDog *watchDog) { QTEST_ASSERT(slotName); @@ -2078,7 +2157,9 @@ static bool qInvokeTestMethod(const char *slotName, const char *data=0) QTestDataSetter s(curDataIndex >= dataCount ? static_cast<QTestData *>(0) : table.testData(curDataIndex)); + watchDog->beginTest(); qInvokeTestMethodDataEntry(slot); + watchDog->testFinished(); if (data) break; @@ -2359,6 +2440,8 @@ static void qInvokeTestMethods(QObject *testObject) QTestTable::globalTestTable(); invokeMethod(testObject, "initTestCase_data()"); + WatchDog watchDog; + if (!QTestResult::skipCurrentTest() && !QTest::currentTestFailed()) { invokeMethod(testObject, "initTestCase()"); @@ -2373,7 +2456,7 @@ static void qInvokeTestMethods(QObject *testObject) if (QTest::testFuncs) { for (int i = 0; i != QTest::testFuncCount; i++) { if (!qInvokeTestMethod(metaObject->method(QTest::testFuncs[i].function()).methodSignature().constData(), - QTest::testFuncs[i].data())) { + QTest::testFuncs[i].data(), &watchDog)) { break; } } @@ -2386,7 +2469,7 @@ static void qInvokeTestMethods(QObject *testObject) for (int i = 0; i != methodCount; i++) { if (!isValidSlot(testMethods[i])) continue; - if (!qInvokeTestMethod(testMethods[i].methodSignature().constData())) + if (!qInvokeTestMethod(testMethods[i].methodSignature().constData(), 0, &watchDog)) break; } delete[] testMethods; @@ -2422,6 +2505,8 @@ private: void FatalSignalHandler::signal(int signum) { + if (signum != SIGINT) + stackTrace(); qFatal("Received signal %d", signum); #if defined(Q_OS_INTEGRITY) { |