AndroidTestRunner: print test results to stdout as they go
The testrunner was always printing the results only at the end of the test run. If tests are long, it means waiting long to have any sort of result. With this, the results are printed to stdout whenever they are written by qtest on the device. Fixes: QTBUG-129975 Change-Id: If4315eb74e73f6274a735e56be7e6989563bb514 Reviewed-by: Ville Voutilainen <ville.voutilainen@qt.io> (cherry picked from commit 7545e7c921f364cdb037f8e967f012351c2eb3ad) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
9f61acc7b2
commit
8102f8f1bb
@ -16,6 +16,7 @@
|
||||
#include <atomic>
|
||||
#include <csignal>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#if defined(Q_OS_WIN32)
|
||||
#include <process.h>
|
||||
#else
|
||||
@ -38,11 +39,13 @@ struct Options
|
||||
QString package;
|
||||
QString activity;
|
||||
QStringList testArgsList;
|
||||
QString stdoutFormat;
|
||||
QHash<QString, QString> outFiles;
|
||||
QStringList amStarttestArgs;
|
||||
QString apkPath;
|
||||
QString ndkStackPath;
|
||||
bool showLogcatOutput = false;
|
||||
std::optional<QProcess> stdoutLogger;
|
||||
};
|
||||
|
||||
static Options g_options;
|
||||
@ -260,10 +263,13 @@ static QString activityFromAndroidManifest(const QString &androidManifestPath)
|
||||
static void setOutputFile(QString file, QString format)
|
||||
{
|
||||
if (file.isEmpty())
|
||||
file = "-"_L1;
|
||||
file = u'-';
|
||||
if (format.isEmpty())
|
||||
format = "txt"_L1;
|
||||
|
||||
if (file == u'-')
|
||||
g_options.stdoutFormat = format;
|
||||
|
||||
g_options.outFiles[format] = file;
|
||||
}
|
||||
|
||||
@ -364,6 +370,11 @@ static bool obtainPid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
static QString runCommandAsUserArgs(const QString &cmd)
|
||||
{
|
||||
return "run-as %1 --user %2 %3"_L1.arg(g_options.package, g_testInfo.userId, cmd);
|
||||
}
|
||||
|
||||
static bool isRunning() {
|
||||
if (g_testInfo.pid < 1)
|
||||
return false;
|
||||
@ -382,7 +393,7 @@ static bool isRunning() {
|
||||
return psSuccess && output.trimmed() == g_options.package.toUtf8();
|
||||
}
|
||||
|
||||
static void waitForStartedAndFinished()
|
||||
static void waitForStarted()
|
||||
{
|
||||
// wait to start and set PID
|
||||
QDeadlineTimer startDeadline(10000);
|
||||
@ -391,7 +402,69 @@ static void waitForStartedAndFinished()
|
||||
break;
|
||||
QThread::msleep(100);
|
||||
} while (!startDeadline.hasExpired() && !g_testInfo.isTestRunnerInterrupted.load());
|
||||
}
|
||||
|
||||
static void waitForLoggingStarted()
|
||||
{
|
||||
const QString lsCmd = "ls files/output.%1"_L1.arg(g_options.stdoutFormat);
|
||||
const QStringList adbLsCmd = { "shell"_L1, runCommandAsUserArgs(lsCmd) };
|
||||
|
||||
QDeadlineTimer deadline(5000);
|
||||
do {
|
||||
if (execAdbCommand(adbLsCmd))
|
||||
break;
|
||||
QThread::msleep(100);
|
||||
} while (!deadline.hasExpired() && !g_testInfo.isTestRunnerInterrupted.load());
|
||||
}
|
||||
|
||||
static bool setupStdoutLogger()
|
||||
{
|
||||
// Start tail to get results to stdout as soon as they're available
|
||||
const QString tailPipeCmd = "tail -n +1 -f files/output.%1"_L1.arg(g_options.stdoutFormat);
|
||||
const QStringList adbTailCmd = { "shell"_L1, runCommandAsUserArgs(tailPipeCmd) };
|
||||
|
||||
g_options.stdoutLogger.emplace();
|
||||
g_options.stdoutLogger->setProcessChannelMode(QProcess::ForwardedOutputChannel);
|
||||
g_options.stdoutLogger->start(g_options.adbCommand, adbTailCmd);
|
||||
|
||||
if (!g_options.stdoutLogger->waitForStarted()) {
|
||||
qCritical() << "Error: failed to run adb command to fetch stdout test results.";
|
||||
g_options.stdoutLogger = std::nullopt;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool stopStdoutLogger()
|
||||
{
|
||||
if (!g_options.stdoutLogger.has_value()) {
|
||||
// In case this ever happens, it setupStdoutLogger() wasn't called, whether
|
||||
// that's on purpose or not, return true since what it does is achieved.
|
||||
qCritical() << "Trying to stop the stdout logger process while it's been uninitialised";
|
||||
return true;
|
||||
}
|
||||
|
||||
if (g_options.stdoutLogger->state() == QProcess::NotRunning) {
|
||||
// We expect the tail command to be running until we stop it, so if it's
|
||||
// not running it might have been terminated outside of the test runner.
|
||||
qCritical() << "The stdout logger process was terminated unexpectedly, "
|
||||
"It might have been terminated by an external process";
|
||||
return false;
|
||||
}
|
||||
|
||||
g_options.stdoutLogger->terminate();
|
||||
|
||||
if (!g_options.stdoutLogger->waitForFinished()) {
|
||||
qCritical() << "Error: adb test results tail command timed out.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void waitForFinished()
|
||||
{
|
||||
// Wait to finish
|
||||
QDeadlineTimer finishedDeadline(g_options.timeoutSecs * 1000);
|
||||
do {
|
||||
@ -451,11 +524,6 @@ static QStringList runningDevices()
|
||||
return devices;
|
||||
}
|
||||
|
||||
static QString runCommandAsUserArgs(const QString &cmd)
|
||||
{
|
||||
return "run-as %1 --user %2 %3"_L1.arg(g_options.package, g_testInfo.userId, cmd);
|
||||
}
|
||||
|
||||
static bool pullResults()
|
||||
{
|
||||
for (auto it = g_options.outFiles.constBegin(); it != g_options.outFiles.end(); ++it) {
|
||||
@ -485,9 +553,7 @@ static bool pullResults()
|
||||
return false;
|
||||
}
|
||||
|
||||
if (it.value() == u'-') {
|
||||
fprintf(stdout, "%s\n", output.constData());
|
||||
} else {
|
||||
if (it.value() != u'-') {
|
||||
QFile out{it.value()};
|
||||
if (!out.open(QIODevice::WriteOnly))
|
||||
return false;
|
||||
@ -745,13 +811,21 @@ int main(int argc, char *argv[])
|
||||
if (!g_testInfo.isPackageInstalled)
|
||||
return 1;
|
||||
|
||||
const QString formattedTime = getCurrentTimeString();
|
||||
|
||||
// start the tests
|
||||
const QString formattedTime = getCurrentTimeString();
|
||||
if (!execAdbCommand(g_options.amStarttestArgs, nullptr))
|
||||
return 1;
|
||||
|
||||
waitForStartedAndFinished();
|
||||
waitForStarted();
|
||||
waitForLoggingStarted();
|
||||
|
||||
if (!setupStdoutLogger())
|
||||
return 1;
|
||||
|
||||
waitForFinished();
|
||||
|
||||
if (!stopStdoutLogger())
|
||||
return 1;
|
||||
|
||||
int exitCode = testExitCode();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user