QTest: expose API needed for Qt Quick Test to print crash backtraces

As discussed in QTQAINFRA-6146, there were two potential approaches to
enabling backtraces in Qt Quick tests:

- Either via a thorough refactoring of quicktest.cpp so that each
testcase is a Slot in a programmatically-created QObject-derived class,
which will be executed via QTest::qExec() similar to the documented
QTest way. This way the pre-existing code in QTest::qRun() will setup
the fatal signal handler.
- Or as a quick fix, modify quick_test_main_with_setup() to setup a
FatalSignalHandler class and invoke prepareStackTrace() like it's
already done in QTest::qRun(). This would require exporting these
symbols in the private header.

This patch enables the implementation of the latter, as it has a
fairly light footprint, is easily revertable (should we need to),
and allows us to immediately gain insight into crashes in CI.

Task-number: QTQAINFRA-6146
Change-Id: Iedffc968acb3e570214df34884ab0afcb6b30850
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
bb10
Mitch Curtis 2024-03-04 17:24:21 +08:00
parent c0014becca
commit d72d7945d4
3 changed files with 13 additions and 7 deletions

View File

@ -432,11 +432,14 @@ static int eventDelay = -1;
#if QT_CONFIG(thread)
static int timeout = -1;
#endif
static bool noCrashHandler = false;
static int repetitions = 1;
static bool repeatForever = false;
static bool skipBlacklisted = false;
namespace Internal {
bool noCrashHandler = false;
}
static bool invokeTestMethodIfValid(QMetaMethod m, QObject *obj = QTest::currentTestObject)
{
if (!m.isValid())
@ -843,7 +846,7 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, const char *const argv[], bool
repeatForever = repetitions < 0;
}
} else if (strcmp(argv[i], "-nocrashhandler") == 0) {
QTest::noCrashHandler = true;
QTest::Internal::noCrashHandler = true;
} else if (strcmp(argv[i], "-skipblacklisted") == 0) {
QTest::skipBlacklisted = true;
} else if (strcmp(argv[i], "-throwonfail") == 0) {
@ -1889,7 +1892,7 @@ int QTest::qRun()
{
std::optional<CrashHandler::FatalSignalHandler> handler;
CrashHandler::prepareStackTrace();
if (!noCrashHandler)
if (!Internal::noCrashHandler)
handler.emplace();
bool seenBad = false;

View File

@ -377,6 +377,9 @@ namespace QTest
return msg;
}
// Exported so Qt Quick Test can also use it for generating backtraces upon crashes.
Q_TESTLIB_EXPORT extern bool noCrashHandler;
} // namespace Internal
template<typename T>

View File

@ -82,7 +82,7 @@ namespace CrashHandler {
#endif
void maybeDisableCoreDump();
void prepareStackTrace();
Q_TESTLIB_EXPORT void prepareStackTrace();
#if defined(Q_OS_WIN)
// Helper class for resolving symbol names by dynamically loading "dbghelp.dll".
@ -135,7 +135,7 @@ namespace CrashHandler {
SymFromAddrType m_symFromAddr;
};
class WindowsFaultHandler
class Q_TESTLIB_EXPORT WindowsFaultHandler
{
public:
WindowsFaultHandler();
@ -145,7 +145,7 @@ namespace CrashHandler {
};
using FatalSignalHandler = WindowsFaultHandler;
#elif defined(Q_OS_UNIX) && !defined(Q_OS_WASM)
class FatalSignalHandler
class Q_TESTLIB_EXPORT FatalSignalHandler
{
public:
# define OUR_SIGNALS(F) \
@ -241,7 +241,7 @@ namespace CrashHandler {
static bool pauseOnCrash;
};
#else // Q_OS_WASM or weird systems
class FatalSignalHandler {};
class Q_TESTLIB_EXPORT FatalSignalHandler {};
inline void blockUnixSignals() {}
#endif // Q_OS_* choice
} // namespace CrashHandler