AndroidTestRunner: print logcat and crash stacktrace when a test fails

For better debugging for test failures, print both logcat and crash
stacktrace (since the start of the current test only), to have an
immediate idea of the reason of the failure or crash if any.

The crash report and the logcat for Android before level 23, is fetched
from the device's time of the app start since those two cases don't
have an option for filtering by pid.

Task-number: QTQAINFRA-5928
Fixes: QTBUG-114898
Pick-to: 6.5
Change-Id: I7760985032f342da4165cdb7573d4cfe5369ae03
Reviewed-by: Dimitrios Apostolou <jimis@qt.io>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Axel Spoerl <axel.spoerl@qt.io>
(cherry picked from commit 518ac20dcb3cebf0956a399f40cbf51e9f3c188e)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Assam Boudjelthia 2023-11-20 15:28:02 +02:00 committed by Qt Cherry-pick Bot
parent f0b9a812f0
commit f3c1bad7e5

View File

@ -488,6 +488,65 @@ struct RunnerLocker
1, QSystemSemaphore::Open };
};
void printLogcat(const QString &formattedTime)
{
QString logcatCmd = "%1 logcat "_L1.arg(g_options.adbCommand);
if (g_options.sdkVersion <= 23 || g_options.pid == -1)
logcatCmd += "-t '%1'"_L1.arg(formattedTime);
else
logcatCmd += "-d --pid=%1"_L1.arg(QString::number(g_options.pid));
QByteArray logcat;
if (!execCommand(logcatCmd, &logcat)) {
qCritical() << "Error: failed to fetch logcat of the test";
return;
}
if (logcat.isEmpty()) {
qWarning() << "The retrieved logcat is empty";
return;
}
qDebug() << "****** Begin logcat output ******";
qDebug().noquote() << logcat;
qDebug() << "****** End logcat output ******";
}
void printLogcatCrashBuffer(const QString &formattedTime)
{
QString crashCmd = "%1 logcat -b crash -t '%2'"_L1.arg(g_options.adbCommand, formattedTime);
QByteArray crashLogcat;
if (!execCommand(crashCmd, &crashLogcat)) {
qCritical() << "Error: failed to fetch logcat crash buffer";
return;
}
if (crashLogcat.isEmpty()) {
qDebug() << "The retrieved logcat crash buffer is empty";
return;
}
qDebug() << "****** Begin logcat crash buffer output ******";
qDebug().noquote() << crashLogcat;
qDebug() << "****** End logcat crash buffer output ******";
}
static QString getCurrentTimeString()
{
const QString timeFormat = (g_options.sdkVersion <= 23) ?
"%m-%d\\ %H:%M:%S.000"_L1 : "%Y-%m-%d\\ %H:%M:%S.%3N"_L1;
QString dateCmd = "%1 shell date +'%2'"_L1.arg(g_options.adbCommand, timeFormat);
QByteArray output;
if (!execCommand(dateCmd, &output)) {
qWarning() << "Date/time adb command failed";
return {};
}
return QString::fromUtf8(output.simplified());
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
@ -542,28 +601,25 @@ int main(int argc, char *argv[])
if (!parseTestArgs())
return 1;
const QString formattedTime = getCurrentTimeString();
// start the tests
bool res = execCommand(QStringLiteral("%1 %2").arg(g_options.adbCommand, g_options.testArgs),
bool res = execCommand("%1 %2"_L1.arg(g_options.adbCommand, g_options.testArgs),
nullptr, g_options.verbose)
&& waitToFinish();
// get logcat output
if (res && g_options.showLogcatOutput) {
if (g_options.sdkVersion <= 23) {
fprintf(stderr, "Cannot show logcat output on Android 23 and below.\n");
fflush(stderr);
} else if (g_options.pid > 0) {
fprintf(stdout, "Logcat output:\n");
res &= execCommand(QStringLiteral("%1 logcat -d --pid=%2")
.arg(g_options.adbCommand)
.arg(g_options.pid),
nullptr, true);
fprintf(stdout, "End Logcat output.\n");
}
}
if (res)
res &= pullFiles();
// If we have a failure, attempt to print both logcat and the crash buffer which
// includes the crash stacktrace that is not included in the default logcat.
if (!res) {
printLogcat(formattedTime);
printLogcatCrashBuffer(formattedTime);
} else if (g_options.showLogcatOutput) {
printLogcat(formattedTime);
}
res &= execCommand(QStringLiteral("%1 uninstall %2").arg(g_options.adbCommand, g_options.package),
nullptr, g_options.verbose);
fflush(stdout);