From d3d10cf23d61f4a011f1a7e9abdee1a92717e80f Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 17 Apr 2015 11:11:58 +0200 Subject: [PATCH] Improve error handling in qtestlib Dump a stack trace on Linux if the process crashes. This will give us much better log output in the new CI system. In addition, create a watch dog thread, that kills the test if the test function times out (ie. hangs) Implementations of the stack trace dumping for Mac and Windows are still pending. Change-Id: I65426c5afe290a0a2019b881436a0c278f1cafaf Reviewed-by: Simon Hausmann --- src/testlib/qtestcase.cpp | 91 ++++++++++++++++++- .../auto/testlib/selftests/tst_selftests.cpp | 4 +- 2 files changed, 91 insertions(+), 4 deletions(-) diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index e2f98c2f041..4d4a3cd7b2d 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -50,6 +50,9 @@ #include #include #include +#include +#include +#include #include #include @@ -70,6 +73,11 @@ #include #include +#if defined(Q_OS_LINUX) +#include +#include +#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 <= dataCount ? static_cast(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) { diff --git a/tests/auto/testlib/selftests/tst_selftests.cpp b/tests/auto/testlib/selftests/tst_selftests.cpp index 488b65c6576..a5840d16d22 100644 --- a/tests/auto/testlib/selftests/tst_selftests.cpp +++ b/tests/auto/testlib/selftests/tst_selftests.cpp @@ -566,7 +566,9 @@ void tst_Selftests::doRunSubTest(QString const& subdir, QStringList const& logge #endif QProcess proc; - static const QProcessEnvironment environment = processEnvironment(); + QProcessEnvironment environment = processEnvironment(); + if (crashes) + environment.insert("QTEST_DISABLE_STACK_DUMP", "1"); proc.setProcessEnvironment(environment); const QString path = subdir + QLatin1Char('/') + subdir; proc.start(path, arguments);