AndroidTestRunner: don't fail waiting for the app to start/finish
Currently, under waitToFinish(), we wait for the app to start and if it doesn't start or starts and exits too quickly for the test runner to catch it, it fails. The test runner tries to get the pid of the test after it detects the app has started. However, we don't really need to fail, the test runner could simply continue the execution and assume the test was run and finished, and proceed to fetching the test results. Since, the results fetching don't anyway rely on the pid, the test runner can let that operation decide whether to fail or not (if not output is found). Also, along the way, instead of issuing a different command to get the pid (i.e. adb shell pidof), we can use the same "adb shell ps" command that is used to check if the app is running, to obtain the pid. Fixes: QTQAINFRA-5928 Fixes: QTBUG-88508 Pick-to: 6.6 6.5 Change-Id: Ice945fcb686c4ef21b5f1c143aa22922ae928333 Reviewed-by: Axel Spoerl <axel.spoerl@qt.io>
This commit is contained in:
parent
518ac20dcb
commit
4bc3f700ff
@ -10,9 +10,9 @@
|
||||
#include <QXmlStreamReader>
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <QtCore/QDeadlineTimer>
|
||||
#include <QtCore/QThread>
|
||||
|
||||
#include <shellquote_shared.h>
|
||||
|
||||
@ -115,7 +115,7 @@ struct Options
|
||||
bool helpRequested = false;
|
||||
bool verbose = false;
|
||||
bool skipAddInstallRoot = false;
|
||||
std::chrono::seconds timeout{480}; // 8 minutes
|
||||
int timeoutSecs = 480; // 8 minutes
|
||||
QString buildPath;
|
||||
QString adbCommand{QStringLiteral("adb")};
|
||||
QString makeCommand;
|
||||
@ -205,7 +205,7 @@ static bool parseOptions()
|
||||
if (i + 1 == arguments.size())
|
||||
g_options.helpRequested = true;
|
||||
else
|
||||
g_options.timeout = std::chrono::seconds{arguments.at(++i).toInt()};
|
||||
g_options.timeoutSecs = arguments.at(++i).toInt();
|
||||
} else if (argument.compare(QStringLiteral("--help"), Qt::CaseInsensitive) == 0) {
|
||||
g_options.helpRequested = true;
|
||||
} else if (argument.compare(QStringLiteral("--verbose"), Qt::CaseInsensitive) == 0) {
|
||||
@ -355,53 +355,58 @@ static bool parseTestArgs()
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool obtainPid() {
|
||||
QByteArray output;
|
||||
const auto psCmd = "%1 shell \"ps | grep ' %2'\""_L1.arg(g_options.adbCommand,
|
||||
shellQuote(g_options.package));
|
||||
if (!execCommand(psCmd, &output))
|
||||
return false;
|
||||
|
||||
const QList<QByteArray> lines = output.split(u'\n');
|
||||
if (lines.size() < 1)
|
||||
return false;
|
||||
|
||||
QList<QByteArray> columns = lines.first().simplified().replace(u'\t', u' ').split(u' ');
|
||||
if (columns.size() < 3)
|
||||
return false;
|
||||
|
||||
if (g_options.pid == -1) {
|
||||
bool ok = false;
|
||||
int pid = columns.at(1).toInt(&ok);
|
||||
if (ok)
|
||||
g_options.pid = pid;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool isRunning() {
|
||||
QByteArray output;
|
||||
if (!execCommand(QStringLiteral("%1 shell \"ps | grep ' %2'\"").arg(g_options.adbCommand,
|
||||
shellQuote(g_options.package)), &output)) {
|
||||
|
||||
const auto psCmd = "%1 shell \"ps | grep ' %2'\""_L1.arg(g_options.adbCommand,
|
||||
shellQuote(g_options.package));
|
||||
if (!execCommand(psCmd, &output))
|
||||
return false;
|
||||
}
|
||||
|
||||
return output.indexOf(QLatin1StringView(" " + g_options.package.toUtf8())) > -1;
|
||||
}
|
||||
|
||||
static bool waitToFinish()
|
||||
static void waitForFinished()
|
||||
{
|
||||
using clock = std::chrono::system_clock;
|
||||
auto start = clock::now();
|
||||
// wait to start
|
||||
while (!isRunning()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
if ((clock::now() - start) > std::chrono::seconds{10})
|
||||
return false;
|
||||
}
|
||||
|
||||
if (g_options.sdkVersion > 23) { // pidof is broken in SDK 23, non-existent before
|
||||
QByteArray output;
|
||||
const QString command(QStringLiteral("%1 shell pidof -s %2")
|
||||
.arg(g_options.adbCommand, shellQuote(g_options.package)));
|
||||
execCommand(command, &output, g_options.verbose);
|
||||
bool ok = false;
|
||||
int pid = output.toInt(&ok); // If we got more than one pid, fail.
|
||||
if (ok) {
|
||||
g_options.pid = pid;
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Unable to obtain the PID of the running unit test. Command \"%s\" "
|
||||
"returned \"%s\"\n",
|
||||
command.toUtf8().constData(), output.constData());
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
// wait to start and set PID
|
||||
QDeadlineTimer startDeadline(10000);
|
||||
do {
|
||||
if (obtainPid())
|
||||
break;
|
||||
QThread::msleep(100);
|
||||
} while (!startDeadline.hasExpired());
|
||||
|
||||
// Wait to finish
|
||||
while (isRunning()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(250));
|
||||
if (g_options.timeout >= std::chrono::seconds::zero()
|
||||
&& (clock::now() - start) > g_options.timeout)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
QDeadlineTimer finishedDeadline(g_options.timeoutSecs * 1000);
|
||||
do {
|
||||
if (!isRunning())
|
||||
break;
|
||||
QThread::msleep(250);
|
||||
} while (!finishedDeadline.hasExpired());
|
||||
}
|
||||
|
||||
static void obtainSDKVersion()
|
||||
@ -604,9 +609,10 @@ int main(int argc, char *argv[])
|
||||
const QString formattedTime = getCurrentTimeString();
|
||||
|
||||
// start the tests
|
||||
bool res = execCommand("%1 %2"_L1.arg(g_options.adbCommand, g_options.testArgs),
|
||||
nullptr, g_options.verbose)
|
||||
&& waitToFinish();
|
||||
const auto startCmd = "%1 %2"_L1.arg(g_options.adbCommand, g_options.testArgs);
|
||||
bool res = execCommand(startCmd, nullptr, g_options.verbose);
|
||||
|
||||
waitForFinished();
|
||||
|
||||
if (res)
|
||||
res &= pullFiles();
|
||||
|
Loading…
x
Reference in New Issue
Block a user