summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndreas Buhr <andreas.buhr@qt.io>2021-09-27 08:50:23 +0200
committerAndreas Buhr <andreas.buhr@qt.io>2021-11-09 22:39:24 +0100
commit0098dd8120be482397b28d034e0c338d7bb81418 (patch)
treec28107f0da861f3df7c1bcc69b826defb2a3a7a5 /src
parent81c92aec66dc71cbea932f12606c9f6c546a8ac1 (diff)
Capture full logcat output in Android unit tests
Previously, when running unit tests on Android, the log presented to the user was the log as known to the Qt logging system. This does not include log messages generated by Java code using e.g. Log.d("message"). Neither does it include log messages by system libs. This patch changes androidtestrunner to capture the full logcat output for the unit test. This improves the developer experience when working with unit tests. Fixes: QTBUG-93438 Change-Id: I580f728349041eb8a84a32d187754b7b5448f512 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/tools/androidtestrunner/main.cpp70
1 files changed, 69 insertions, 1 deletions
diff --git a/src/tools/androidtestrunner/main.cpp b/src/tools/androidtestrunner/main.cpp
index aa3c390563..b6d68882a9 100644
--- a/src/tools/androidtestrunner/main.cpp
+++ b/src/tools/androidtestrunner/main.cpp
@@ -74,6 +74,9 @@ struct Options
QHash<QString, QString> outFiles;
QString testArgs;
QString apkPath;
+ int sdkVersion = -1;
+ int pid = -1;
+ bool showLogcatOutput = false;
QHash<QString, std::function<bool(const QByteArray &)>> checkFiles = {
{QStringLiteral("txt"), [](const QByteArray &data) -> bool {
return data.indexOf("\nFAIL! : ") < 0;
@@ -126,6 +129,10 @@ static bool execCommand(const QString &command, QByteArray *output = nullptr, bo
if (verbose)
fprintf(stdout, "%s", buffer);
}
+
+ fflush(stdout);
+ fflush(stderr);
+
return pclose(process) == 0;
}
@@ -233,6 +240,8 @@ static bool parseOptions()
g_options.activity = arguments.at(++i);
} else if (argument.compare(QStringLiteral("--skip-install-root"), Qt::CaseInsensitive) == 0) {
g_options.skipAddInstallRoot = true;
+ } else if (argument.compare(QStringLiteral("--show-logcat"), Qt::CaseInsensitive) == 0) {
+ g_options.showLogcatOutput = true;
} else if (argument.compare(QStringLiteral("--timeout"), Qt::CaseInsensitive) == 0) {
if (i + 1 == arguments.size())
g_options.helpRequested = true;
@@ -289,6 +298,8 @@ static void printHelp()
"\n"
" --skip-install-root: Do not append INSTALL_ROOT=... to the make command.\n"
"\n"
+ " --show-logcat: Print Logcat output to stdout.\n"
+ "\n"
" -- Arguments that will be passed to the test application.\n"
"\n"
" --verbose: Prints out information during processing.\n"
@@ -403,6 +414,24 @@ static bool waitToFinish()
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 finish
while (isRunning()) {
std::this_thread::sleep_for(std::chrono::milliseconds(250));
@@ -412,6 +441,26 @@ static bool waitToFinish()
return true;
}
+static void obtainSDKVersion()
+{
+ // SDK version is necessary, as in SDK 23 pidof is broken, so we cannot obtain the pid.
+ // Also, Logcat cannot filter by pid in SDK 23, so we don't offer the --show-logcat option.
+ QByteArray output;
+ const QString command(
+ QStringLiteral("%1 shell getprop ro.build.version.sdk").arg(g_options.adbCommand));
+ execCommand(command, &output, g_options.verbose);
+ bool ok = false;
+ int sdkVersion = output.toInt(&ok);
+ if (ok) {
+ g_options.sdkVersion = sdkVersion;
+ } else {
+ fprintf(stderr,
+ "Unable to obtain the SDK version of the target. Command \"%s\" "
+ "returned \"%s\"\n",
+ command.toUtf8().constData(), output.constData());
+ fflush(stderr);
+ }
+}
static bool pullFiles()
{
@@ -496,6 +545,8 @@ int main(int argc, char *argv[])
return 1;
}
+ obtainSDKVersion();
+
RunnerLocker lock; // do not install or run packages while another test is running
if (!execCommand(QStringLiteral("%1 install -r -g %2")
.arg(g_options.adbCommand, g_options.apkPath), nullptr, g_options.verbose)) {
@@ -513,7 +564,24 @@ int main(int argc, char *argv[])
// start the tests
bool res = execCommand(QStringLiteral("%1 %2").arg(g_options.adbCommand, g_options.testArgs),
- nullptr, g_options.verbose) && waitToFinish();
+ 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();
res &= execCommand(QStringLiteral("%1 uninstall %2").arg(g_options.adbCommand, g_options.package),