Run prebuilt android test APKs
androidtestrunner now checks is the apk is build and if it is, it will skip the build phase. Now we can build the apks in parallel (which takes most of the time) and run them sequentially. This way running tests on Android is much faster. Change-Id: I82f34723ac08f7728cc0daab3366e03821335eed Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
This commit is contained in:
parent
d73497cf77
commit
079dafc42f
@ -54,6 +54,7 @@ debug_and_release:debug_and_release_target {
|
||||
# Allow for a custom test runner script
|
||||
|
||||
android: isEmpty($(TESTRUNNER)) {
|
||||
APK_PATH = $$shell_path($$OUT_PWD/android-build/$${TARGET}.apk)
|
||||
qtPrepareTool(ANDROIDTESTRUNNER, androidtestrunner)
|
||||
qtPrepareTool(ANDROIDDEPLOYQT, androiddeployqt)
|
||||
isEmpty(ANDROID_DEPLOYMENT_SETTINGS_FILE): ANDROID_DEPLOYMENT_SETTINGS_FILE = $$OUT_PWD/android-$$TARGET-deployment-settings.json
|
||||
@ -62,6 +63,7 @@ android: isEmpty($(TESTRUNNER)) {
|
||||
$${type}.commands += --path \"$$OUT_PWD/android-build\"
|
||||
$${type}.commands += --adb \"$$shell_path($${ANDROID_SDK_ROOT}$${QMAKE_DIR_SEP}platform-tools$${QMAKE_DIR_SEP}adb$${extension})\"
|
||||
$${type}.commands += --make \"$(MAKE) -f $(MAKEFILE)\"
|
||||
$${type}.commands += --apk $$APK_PATH
|
||||
} else: $${type}.commands += $(TESTRUNNER)
|
||||
|
||||
unix {
|
||||
|
@ -150,11 +150,18 @@ QSharedMemoryPrivate::makePlatformSafeKey(const QString &key,
|
||||
|
||||
\sa setKey()
|
||||
*/
|
||||
|
||||
#ifndef QT_NO_QOBJECT
|
||||
QSharedMemory::QSharedMemory(QObject *parent)
|
||||
: QObject(*new QSharedMemoryPrivate, parent)
|
||||
{
|
||||
}
|
||||
|
||||
#else
|
||||
QSharedMemory::QSharedMemory()
|
||||
: d_ptr(new QSharedMemoryPrivate)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
/*!
|
||||
Constructs a shared memory object with the given \a parent and with
|
||||
its key set to \a key. Because its key is set, its create() and
|
||||
@ -162,11 +169,19 @@ QSharedMemory::QSharedMemory(QObject *parent)
|
||||
|
||||
\sa setKey(), create(), attach()
|
||||
*/
|
||||
#ifndef QT_NO_QOBJECT
|
||||
QSharedMemory::QSharedMemory(const QString &key, QObject *parent)
|
||||
: QObject(*new QSharedMemoryPrivate, parent)
|
||||
{
|
||||
setKey(key);
|
||||
}
|
||||
#else
|
||||
QSharedMemory::QSharedMemory(const QString &key)
|
||||
: d_ptr(new QSharedMemoryPrivate)
|
||||
{
|
||||
setKey(key);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
The destructor clears the key, which forces the shared memory object
|
||||
@ -604,4 +619,6 @@ QString QSharedMemory::errorString() const
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#ifndef QT_NO_QOBJECT
|
||||
#include "moc_qsharedmemory.cpp"
|
||||
#endif
|
||||
|
@ -40,8 +40,14 @@
|
||||
#ifndef QSHAREDMEMORY_H
|
||||
#define QSHAREDMEMORY_H
|
||||
|
||||
#include <QtCore/qobject.h>
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#ifndef QT_NO_QOBJECT
|
||||
# include <QtCore/qobject.h>
|
||||
#else
|
||||
# include <QtCore/qobjectdefs.h>
|
||||
# include <QtCore/qscopedpointer.h>
|
||||
# include <QtCore/qstring.h>
|
||||
#endif
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
||||
@ -49,9 +55,14 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
class QSharedMemoryPrivate;
|
||||
|
||||
class Q_CORE_EXPORT QSharedMemory : public QObject
|
||||
class Q_CORE_EXPORT QSharedMemory
|
||||
#ifndef QT_NO_QOBJECT
|
||||
: public QObject
|
||||
#endif
|
||||
{
|
||||
#ifndef QT_NO_QOBJECT
|
||||
Q_OBJECT
|
||||
#endif
|
||||
Q_DECLARE_PRIVATE(QSharedMemory)
|
||||
|
||||
public:
|
||||
@ -74,8 +85,17 @@ public:
|
||||
UnknownError
|
||||
};
|
||||
|
||||
#ifndef QT_NO_QOBJECT
|
||||
QSharedMemory(QObject *parent = nullptr);
|
||||
QSharedMemory(const QString &key, QObject *parent = nullptr);
|
||||
#else
|
||||
QSharedMemory();
|
||||
QSharedMemory(const QString &key);
|
||||
static QString tr(const char * str)
|
||||
{
|
||||
return QString::fromLatin1(str);
|
||||
}
|
||||
#endif
|
||||
~QSharedMemory();
|
||||
|
||||
void setKey(const QString &key);
|
||||
@ -104,6 +124,9 @@ public:
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(QSharedMemory)
|
||||
#ifdef QT_NO_QOBJECT
|
||||
QScopedPointer<QSharedMemoryPrivate> d_ptr;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // QT_NO_SHAREDMEMORY
|
||||
|
@ -67,7 +67,10 @@ namespace QSharedMemoryPrivate
|
||||
#else
|
||||
|
||||
#include "qsystemsemaphore.h"
|
||||
#include "private/qobject_p.h"
|
||||
|
||||
#ifndef QT_NO_QOBJECT
|
||||
# include "private/qobject_p.h"
|
||||
#endif
|
||||
|
||||
#if !defined(Q_OS_WIN) && !defined(Q_OS_ANDROID) && !defined(Q_OS_INTEGRITY) && !defined(Q_OS_RTEMS)
|
||||
# include <sys/sem.h>
|
||||
@ -107,9 +110,14 @@ private:
|
||||
};
|
||||
#endif // QT_NO_SYSTEMSEMAPHORE
|
||||
|
||||
class Q_AUTOTEST_EXPORT QSharedMemoryPrivate : public QObjectPrivate
|
||||
class Q_AUTOTEST_EXPORT QSharedMemoryPrivate
|
||||
#ifndef QT_NO_QOBJECT
|
||||
: public QObjectPrivate
|
||||
#endif
|
||||
{
|
||||
#ifndef QT_NO_QOBJECT
|
||||
Q_DECLARE_PUBLIC(QSharedMemory)
|
||||
#endif
|
||||
|
||||
public:
|
||||
QSharedMemoryPrivate();
|
||||
|
@ -64,8 +64,11 @@
|
||||
#ifndef QT_NO_SHAREDMEMORY
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QSharedMemoryPrivate::QSharedMemoryPrivate()
|
||||
: QObjectPrivate(), memory(0), size(0), error(QSharedMemory::NoError),
|
||||
QSharedMemoryPrivate::QSharedMemoryPrivate() :
|
||||
#ifndef QT_NO_QOBJECT
|
||||
QObjectPrivate(),
|
||||
#endif
|
||||
memory(0), size(0), error(QSharedMemory::NoError),
|
||||
#ifndef QT_NO_SYSTEMSEMAPHORE
|
||||
systemSemaphore(QString()), lockedByMe(false),
|
||||
#endif
|
||||
|
@ -47,7 +47,10 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
#ifndef QT_NO_SHAREDMEMORY
|
||||
|
||||
QSharedMemoryPrivate::QSharedMemoryPrivate() : QObjectPrivate(),
|
||||
QSharedMemoryPrivate::QSharedMemoryPrivate() :
|
||||
#ifndef QT_NO_QOBJECT
|
||||
QObjectPrivate(),
|
||||
#endif
|
||||
memory(0), size(0), error(QSharedMemory::NoError),
|
||||
systemSemaphore(QString()), lockedByMe(false), hand(0)
|
||||
{
|
||||
|
@ -209,6 +209,7 @@ struct Options
|
||||
bool sectionsOnly;
|
||||
bool protectedAuthenticationPath;
|
||||
bool jarSigner;
|
||||
QString apkPath;
|
||||
|
||||
// Gdbserver
|
||||
TriState gdbServer;
|
||||
@ -396,6 +397,11 @@ Options parseOptions()
|
||||
options.helpRequested = true;
|
||||
else
|
||||
options.jdkPath = arguments.at(++i);
|
||||
} else if (argument.compare(QLatin1String("--apk"), Qt::CaseInsensitive) == 0) {
|
||||
if (i + 1 == arguments.size())
|
||||
options.helpRequested = true;
|
||||
else
|
||||
options.apkPath = arguments.at(++i);
|
||||
} else if (argument.compare(QLatin1String("--sign"), Qt::CaseInsensitive) == 0) {
|
||||
if (i + 2 >= arguments.size()) {
|
||||
options.helpRequested = true;
|
||||
@ -544,6 +550,7 @@ void printHelp()
|
||||
" dependencies into the build directory and update the XML templates.\n"
|
||||
" The project will not be built or installed.\n"
|
||||
" --no-strip: Do not strip debug symbols from libraries.\n"
|
||||
" --apk <path/where/to/copy/the/apk>: Path where to copy the built apk.\n"
|
||||
" --help: Displays this information.\n\n",
|
||||
qPrintable(QCoreApplication::arguments().at(0))
|
||||
);
|
||||
@ -2389,6 +2396,14 @@ bool installApk(const Options &options)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool copyPackage(const Options &options)
|
||||
{
|
||||
fflush(stdout);
|
||||
auto from = apkPath(options, options.keyStore.isEmpty() ? UnsignedAPK : SignedAPK);
|
||||
QFile::remove(options.apkPath);
|
||||
return QFile::copy(from, options.apkPath);
|
||||
}
|
||||
|
||||
bool copyStdCpp(Options *options)
|
||||
{
|
||||
if (options->verbose)
|
||||
@ -2759,7 +2774,8 @@ enum ErrorCode
|
||||
CannotSignPackage = 15,
|
||||
CannotInstallApk = 16,
|
||||
CannotGenerateAssetsFileList = 18,
|
||||
CannotCopyAndroidExtraResources = 19
|
||||
CannotCopyAndroidExtraResources = 19,
|
||||
CannotCopyApk = 20
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@ -2902,6 +2918,9 @@ int main(int argc, char *argv[])
|
||||
if (!options.keyStore.isEmpty() && !signPackage(options))
|
||||
return CannotSignPackage;
|
||||
|
||||
if (!options.apkPath.isEmpty() && !copyPackage(options))
|
||||
return CannotCopyApk;
|
||||
|
||||
if (Q_UNLIKELY(options.timing))
|
||||
fprintf(stdout, "[TIMING] %d ms: Signed package\n", options.timer.elapsed());
|
||||
}
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <QDir>
|
||||
#include <QHash>
|
||||
#include <QRegExp>
|
||||
#include <QSystemSemaphore>
|
||||
#include <QXmlStreamReader>
|
||||
|
||||
#include <algorithm>
|
||||
@ -60,6 +61,7 @@ struct Options
|
||||
QStringList testArgsList;
|
||||
QHash<QString, QString> outFiles;
|
||||
QString testArgs;
|
||||
QString apkPath;
|
||||
QHash<QString, std::function<bool(const QByteArray &)>> checkFiles = {
|
||||
{QStringLiteral("txt"), [](const QByteArray &data) -> bool {
|
||||
return data.indexOf("\nFAIL! : ") < 0;
|
||||
@ -227,6 +229,11 @@ static bool parseOptions()
|
||||
g_options.helpRequested = true;
|
||||
else
|
||||
g_options.makeCommand = arguments.at(++i);
|
||||
} else if (argument.compare(QStringLiteral("--apk"), Qt::CaseInsensitive) == 0) {
|
||||
if (i + 1 == arguments.size())
|
||||
g_options.helpRequested = true;
|
||||
else
|
||||
g_options.apkPath = arguments.at(++i);
|
||||
} else if (argument.compare(QStringLiteral("--activity"), Qt::CaseInsensitive) == 0) {
|
||||
if (i + 1 == arguments.size())
|
||||
g_options.helpRequested = true;
|
||||
@ -280,6 +287,8 @@ static void printHelp()
|
||||
" Default is 5 minutes.\n"
|
||||
" --make <make cmd>: make command, needed to install the qt library.\n"
|
||||
" If make is missing make sure the --path is set.\n"
|
||||
" --apk <apk path>: If the apk is specified and if exists, we'll skip\n"
|
||||
" the package building.\n"
|
||||
" -- arguments that will be passed to the test application.\n"
|
||||
" --verbose: Prints out information during processing.\n"
|
||||
" --help: Displays this information.\n\n",
|
||||
@ -420,6 +429,19 @@ static bool pullFiles()
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct RunnerLocker
|
||||
{
|
||||
RunnerLocker()
|
||||
{
|
||||
runner.acquire();
|
||||
}
|
||||
~RunnerLocker()
|
||||
{
|
||||
runner.release();
|
||||
}
|
||||
QSystemSemaphore runner{QStringLiteral("androidtestrunner"), 1, QSystemSemaphore::Open};
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication a(argc, argv);
|
||||
@ -428,19 +450,29 @@ int main(int argc, char *argv[])
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!g_options.makeCommand.isEmpty()) {
|
||||
// we need to run make INSTALL_ROOT=path install to install the application file(s) first
|
||||
if (!execCommand(QStringLiteral("%1 INSTALL_ROOT=%2 install")
|
||||
.arg(g_options.makeCommand, g_options.buildPath), nullptr, g_options.verbose)) {
|
||||
RunnerLocker lock; // do not install or run packages while another test is running
|
||||
if (!g_options.apkPath.isEmpty() && QFile::exists(g_options.apkPath)) {
|
||||
if (!execCommand(QStringLiteral("%1 install -r %2")
|
||||
.arg(g_options.adbCommand, g_options.apkPath), nullptr, g_options.verbose)) {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (!g_options.makeCommand.isEmpty()) {
|
||||
// we need to run make INSTALL_ROOT=path install to install the application file(s) first
|
||||
if (!execCommand(QStringLiteral("%1 INSTALL_ROOT=%2 install")
|
||||
.arg(g_options.makeCommand, g_options.buildPath), nullptr, g_options.verbose)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Run androiddeployqt
|
||||
static auto verbose = g_options.verbose ? QStringLiteral("--verbose") : QStringLiteral();
|
||||
if (!execCommand(QStringLiteral("%1 %3 --reinstall --output %2 --apk %4").arg(g_options.androidDeployQtCommand,
|
||||
g_options.buildPath,
|
||||
verbose,
|
||||
g_options.apkPath), nullptr, true)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
// Run androiddeployqt
|
||||
static auto verbose = g_options.verbose ? QStringLiteral("--verbose") : QStringLiteral();
|
||||
if (!execCommand(QStringLiteral("%1 %3 --reinstall --output %2").arg(g_options.androidDeployQtCommand,
|
||||
g_options.buildPath,
|
||||
verbose), nullptr, g_options.verbose)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
QString manifest = g_options.buildPath + QStringLiteral("/AndroidManifest.xml");
|
||||
|
@ -60,6 +60,8 @@ SOURCES += \
|
||||
../../corelib/kernel/qmetatype.cpp \
|
||||
../../corelib/kernel/qvariant.cpp \
|
||||
../../corelib/kernel/qsystemerror.cpp \
|
||||
../../corelib/kernel/qsharedmemory.cpp \
|
||||
../../corelib/kernel/qsystemsemaphore.cpp \
|
||||
../../corelib/plugin/quuid.cpp \
|
||||
../../corelib/serialization/qdatastream.cpp \
|
||||
../../corelib/serialization/qjson.cpp \
|
||||
@ -103,6 +105,12 @@ SOURCES += \
|
||||
../../xml/sax/qxml.cpp
|
||||
|
||||
unix:SOURCES += ../../corelib/kernel/qcore_unix.cpp \
|
||||
../../corelib/kernel/qsharedmemory_posix.cpp \
|
||||
../../corelib/kernel/qsharedmemory_systemv.cpp \
|
||||
../../corelib/kernel/qsharedmemory_unix.cpp \
|
||||
../../corelib/kernel/qsystemsemaphore_posix.cpp \
|
||||
../../corelib/kernel/qsystemsemaphore_systemv.cpp \
|
||||
../../corelib/kernel/qsystemsemaphore_unix.cpp \
|
||||
../../corelib/io/qfilesystemengine_unix.cpp \
|
||||
../../corelib/io/qfilesystemiterator_unix.cpp \
|
||||
../../corelib/io/qfsfileengine_unix.cpp
|
||||
@ -112,12 +120,18 @@ win32:SOURCES += ../../corelib/global/qoperatingsystemversion_win.cpp \
|
||||
../../corelib/io/qfilesystemiterator_win.cpp \
|
||||
../../corelib/io/qfsfileengine_win.cpp \
|
||||
../../corelib/kernel/qcoreapplication_win.cpp \
|
||||
../../corelib/kernel/qsharedmemory_win.cpp \
|
||||
../../corelib/kernel/qsystemsemaphore_win.cpp \
|
||||
../../corelib/plugin/qsystemlibrary.cpp \
|
||||
|
||||
mac {
|
||||
SOURCES += \
|
||||
../../corelib/kernel/qcoreapplication_mac.cpp \
|
||||
../../corelib/kernel/qcore_mac.cpp
|
||||
../../corelib/kernel/qcore_mac.cpp \
|
||||
../../corelib/io/qfilesystemengine_unix.cpp \
|
||||
../../corelib/io/qfilesystemiterator_unix.cpp \
|
||||
../../corelib/io/qfsfileengine_unix.cpp
|
||||
|
||||
OBJECTIVE_SOURCES += \
|
||||
../../corelib/global/qoperatingsystemversion_darwin.mm \
|
||||
../../corelib/kernel/qcore_mac_objc.mm \
|
||||
|
Loading…
Reference in New Issue
Block a user