diff options
author | Shane Kearns <shane.kearns@accenture.com> | 2009-12-22 16:14:59 (GMT) |
---|---|---|
committer | Jason McDonald <jason.mcdonald@nokia.com> | 2010-01-11 12:57:38 (GMT) |
commit | fb79b80fbd50289018ea9eced55dc865179679cb (patch) | |
tree | e6e0d2bc6a6936ef1be56df8b502c718ce41cb04 /tools | |
parent | 579b9f70d10ba66e7fce83c4b693377768f7352a (diff) | |
download | Qt-fb79b80fbd50289018ea9eced55dc865179679cb.zip Qt-fb79b80fbd50289018ea9eced55dc865179679cb.tar.gz Qt-fb79b80fbd50289018ea9eced55dc865179679cb.tar.bz2 |
Deal with test cases that crash or hang
Added an optional timeout to runonphone - the application will be killed
after this time. Used when autotesting unattended, as some tests can hang.
Handled the just in time debug halting the application when it is about
to crash, by terminating the application. In future, we could capture a
call stack or something here.
Also added quiet/verbose options to control the amount of output from
runonphone.
Reviewed-by: Janne Koskinen
(cherry picked from commit 0e94349de0b602f1b6af747b66ef03b22133cc3a)
Diffstat (limited to 'tools')
-rw-r--r-- | tools/runonphone/main.cpp | 82 | ||||
-rw-r--r-- | tools/runonphone/trk/launcher.cpp | 20 | ||||
-rw-r--r-- | tools/runonphone/trk/launcher.h | 2 | ||||
-rw-r--r-- | tools/runonphone/trksignalhandler.cpp | 98 | ||||
-rw-r--r-- | tools/runonphone/trksignalhandler.h | 12 |
5 files changed, 182 insertions, 32 deletions
diff --git a/tools/runonphone/main.cpp b/tools/runonphone/main.cpp index 98f7f2d..543c554 100644 --- a/tools/runonphone/main.cpp +++ b/tools/runonphone/main.cpp @@ -40,9 +40,10 @@ ****************************************************************************/ #include <QCoreApplication> -#include <QDebug> +#include <QTextStream> #include <QStringList> #include <QScopedPointer> +#include <QTimer> #include "trkutils.h" #include "trkdevice.h" #include "launcher.h" @@ -50,12 +51,15 @@ #include "trksignalhandler.h" #include "serenum.h" -void printUsage() +void printUsage(QTextStream& outstream) { - qDebug() << "runtest [options] <program> [program arguments]" << endl + outstream << "runtest [options] <program> [program arguments]" << endl << "-s, --sis <file> specify sis file to install" << endl << "-p, --portname <COMx> specify COM port to use by device name" << endl << "-f, --portfriendlyname <substring> specify COM port to use by friendly name" << endl + << "-t, --timeout <milliseconds> terminate test if timeout occurs" << endl + << "-v, --verbose show debugging output" << endl + << "-q, --quiet hide progress messages" << endl << endl << "USB COM ports can usually be autodetected" << endl; } @@ -70,26 +74,51 @@ int main(int argc, char *argv[]) QString exeFile; QString cmdLine; QStringList args = QCoreApplication::arguments(); + QTextStream outstream(stdout); + QTextStream errstream(stderr); + int loglevel=1; + int timeout=0; for (int i=1;i<args.size();i++) { QString arg = args.at(i); if (arg.startsWith("-")) { if (args.size() < i+2) { - qWarning("Command line missing argument parameters"); + errstream << "Command line missing argument parameters" << endl; return 1; } - i++; - QString param = args.at(i); + QString param = args.at(i+1); if(arg.compare("--portname", Qt::CaseSensitive) == 0 - || arg.compare("-p", Qt::CaseSensitive) == 0) + || arg.compare("-p", Qt::CaseSensitive) == 0) { serialPortName = param; + i++; + } else if(arg.compare("--portfriendlyname", Qt::CaseSensitive) == 0 - || arg.compare("-f", Qt::CaseSensitive) == 0) + || arg.compare("-f", Qt::CaseSensitive) == 0) { serialPortFriendlyName = param; + i++; + } else if(arg.compare("--sis", Qt::CaseSensitive) == 0 - || arg.compare("-s", Qt::CaseSensitive) == 0) + || arg.compare("-s", Qt::CaseSensitive) == 0) { sisFile = param; + i++; + } + else if(arg.compare("--timeout", Qt::CaseSensitive) == 0 + || arg.compare("-t", Qt::CaseSensitive) == 0) { + bool ok; + timeout = param.toInt(&ok); + if (!ok) { + errstream << "Timeout must be specified in milliseconds" << endl; + return 1; + } + i++; + } + else if(arg.compare("--verbose", Qt::CaseSensitive) == 0 + || arg.compare("-v", Qt::CaseSensitive) == 0) + loglevel=2; + else if(arg.compare("--quiet", Qt::CaseSensitive) == 0 + || arg.compare("-q", Qt::CaseSensitive) == 0) + loglevel=0; else - qWarning() << "unknown command line option " << arg; + errstream << "unknown command line option " << arg << endl; } else { exeFile = arg; i++; @@ -101,23 +130,27 @@ int main(int argc, char *argv[]) } if(exeFile.isEmpty()) { - printUsage(); + printUsage(outstream); return 1; } if(serialPortName.isEmpty()) { - qDebug() << "Detecting serial ports" << endl; + if(loglevel > 0) + outstream << "Detecting serial ports" << endl; QList <SerialPortId> ports = enumerateSerialPorts(); foreach(SerialPortId id, ports) { - qDebug() << "Port Name: " << id.portName << ", " + if(loglevel > 0) + outstream << "Port Name: " << id.portName << ", " << "Friendly Name:" << id.friendlyName << endl; if(serialPortName.isEmpty()) { - if(id.friendlyName.isEmpty() && + if(!id.friendlyName.isEmpty() && + serialPortFriendlyName.isEmpty() && (id.friendlyName.contains("symbian", Qt::CaseInsensitive) || id.friendlyName.contains("s60", Qt::CaseInsensitive) || id.friendlyName.contains("nokia", Qt::CaseInsensitive))) serialPortName = id.portName; else if (!id.friendlyName.isEmpty() && + !serialPortFriendlyName.isEmpty() && id.friendlyName.contains(serialPortFriendlyName)) serialPortName = id.portName; } @@ -133,20 +166,25 @@ int main(int argc, char *argv[]) if(sisFile.isEmpty()) { launcher.reset(new trk::Launcher(trk::Launcher::ActionCopyRun)); launcher->setCopyFileName(exeFile, QString("c:\\sys\\bin\\") + exeFile); - qDebug() << "System TRK required to copy EXE, use --sis if using Application TRK" << endl; + errstream << "System TRK required to copy EXE, use --sis if using Application TRK" << endl; } else { launcher.reset(new trk::Launcher(trk::Launcher::ActionCopyInstallRun)); launcher->addStartupActions(trk::Launcher::ActionInstall); launcher->setCopyFileName(sisFile, "c:\\data\\testtemp.sis"); launcher->setInstallFileName("c:\\data\\testtemp.sis"); } - qDebug() << "Connecting to target via " << serialPortName << endl; + if(loglevel > 0) + outstream << "Connecting to target via " << serialPortName << endl; launcher->setTrkServerName(QString("\\\\.\\") + serialPortName); launcher->setFileName(QString("c:\\sys\\bin\\") + exeFile); launcher->setCommandLineArgs(cmdLine); + if(loglevel > 1) + launcher->setVerbose(1); + TrkSignalHandler handler; + handler.setLogLevel(loglevel); QObject::connect(launcher.data(), SIGNAL(copyingStarted()), &handler, SLOT(copyingStarted())); QObject::connect(launcher.data(), SIGNAL(canNotConnect(const QString &)), &handler, SLOT(canNotConnect(const QString &))); @@ -162,11 +200,21 @@ int main(int argc, char *argv[]) QObject::connect(launcher.data(), SIGNAL(applicationOutputReceived(const QString &)), &handler, SLOT(applicationOutputReceived(const QString &))); QObject::connect(launcher.data(), SIGNAL(copyProgress(int)), &handler, SLOT(copyProgress(int))); QObject::connect(launcher.data(), SIGNAL(stateChanged(int)), &handler, SLOT(stateChanged(int))); + QObject::connect(launcher.data(), SIGNAL(stopped(uint,uint,uint,QString)), &handler, SLOT(stopped(uint,uint,uint,QString))); + QObject::connect(&handler, SIGNAL(resume(uint,uint)), launcher.data(), SLOT(resume(uint,uint))); + QObject::connect(&handler, SIGNAL(terminate()), launcher.data(), SLOT(terminate())); QObject::connect(launcher.data(), SIGNAL(finished()), &handler, SLOT(finished())); + QTimer timer; + timer.setSingleShot(true); + QObject::connect(&timer, SIGNAL(timeout()), &handler, SLOT(timeout())); + if (timeout > 0) { + timer.start(timeout); + } + QString errorMessage; if(!launcher->startServer(&errorMessage)) { - qWarning() << errorMessage; + errstream << errorMessage << endl; return 1; } diff --git a/tools/runonphone/trk/launcher.cpp b/tools/runonphone/trk/launcher.cpp index 95f4364..2715115 100644 --- a/tools/runonphone/trk/launcher.cpp +++ b/tools/runonphone/trk/launcher.cpp @@ -317,6 +317,18 @@ void Launcher::handleResult(const TrkResult &result) case TrkNotifyStopped: { // Notified Stopped logMessage(prefix + "NOTE: STOPPED " + str); // 90 01 78 6a 40 40 00 00 07 23 00 00 07 24 00 00 + QString reason; + if (result.data.size() >= 14) { + uint pc = extractInt(result.data.mid(0,4).constData()); + uint pid = extractInt(result.data.mid(4,4).constData()); + uint tid = extractInt(result.data.mid(8,4).constData()); + ushort len = extractShort(result.data.mid(12,2).constData()); + if(len > 0) + reason = result.data.mid(14, len); + emit(stopped(pc, pid, tid, reason)); + } else { + emit(stopped(0, 0, 0, reason)); + } //const char *data = result.data.data(); // uint addr = extractInt(data); //code address: 4 bytes; code base address for the library // uint pid = extractInt(data + 4); // ProcessID: 4 bytes; @@ -692,4 +704,12 @@ void Launcher::startInferiorIfNeeded() } d->m_device->sendTrkMessage(TrkCreateItem, TrkCallback(this, &Launcher::handleCreateProcess), ba); // Create Item } + +void Launcher::resume(uint pid, uint tid) +{ + QByteArray ba; + appendInt(&ba, pid, BigEndian); + appendInt(&ba, tid, BigEndian); + d->m_device->sendTrkMessage(TrkContinue, TrkCallback(), ba, "CONTINUE"); +} } // namespace trk diff --git a/tools/runonphone/trk/launcher.h b/tools/runonphone/trk/launcher.h index 98c64e9..e34dc80 100644 --- a/tools/runonphone/trk/launcher.h +++ b/tools/runonphone/trk/launcher.h @@ -125,9 +125,11 @@ signals: void applicationOutputReceived(const QString &output); void copyProgress(int percent); void stateChanged(int); + void stopped(uint pc, uint pid, uint tid, const QString& reason); public slots: void terminate(); + void resume(uint pid, uint tid); private slots: void handleResult(const trk::TrkResult &data); diff --git a/tools/runonphone/trksignalhandler.cpp b/tools/runonphone/trksignalhandler.cpp index 429c552..72b5446 100644 --- a/tools/runonphone/trksignalhandler.cpp +++ b/tools/runonphone/trksignalhandler.cpp @@ -41,81 +41,149 @@ #include <QDebug> #include <QCoreApplication> +#include <QObject> #include "trksignalhandler.h" +class TrkSignalHandlerPrivate +{ + friend class TrkSignalHandler; +public: + TrkSignalHandlerPrivate(); + ~TrkSignalHandlerPrivate(); +private: + QTextStream out; + QTextStream err; + int loglevel; +}; + void TrkSignalHandler::copyingStarted() { - qDebug() << "Copying...\n"; + if(d->loglevel > 0) + d->out << "Copying..." << endl; } void TrkSignalHandler::canNotConnect(const QString &errorMessage) { - qWarning() << "Cannot Connect - " << errorMessage; + d->err << "Cannot Connect - " << errorMessage << endl; } void TrkSignalHandler::canNotCreateFile(const QString &filename, const QString &errorMessage) { - qWarning() << "Cannot create file (" << filename << ") - " << errorMessage << "\n"; + d->err << "Cannot create file (" << filename << ") - " << errorMessage << endl; } void TrkSignalHandler::canNotWriteFile(const QString &filename, const QString &errorMessage) { - qWarning() << "Cannot write file (" << filename << ") - " << errorMessage << "\n"; + d->err << "Cannot write file (" << filename << ") - " << errorMessage << endl; } void TrkSignalHandler::canNotCloseFile(const QString &filename, const QString &errorMessage) { - qWarning() << "Cannot close file (" << filename << ") - " << errorMessage << "\n"; + d->err << "Cannot close file (" << filename << ") - " << errorMessage << endl; } void TrkSignalHandler::installingStarted() { - qDebug() << "Installing...\n"; + if(d->loglevel > 0) + d->out << "Installing..." << endl; } void TrkSignalHandler::canNotInstall(const QString &packageFilename, const QString &errorMessage) { - qWarning() << "Cannot install file (" << packageFilename << ") - " << errorMessage << "\n"; + d->err << "Cannot install file (" << packageFilename << ") - " << errorMessage << endl; } void TrkSignalHandler::installingFinished() { - qDebug() << "Installing finished\n"; + if(d->loglevel > 0) + d->out << "Installing finished" << endl; } void TrkSignalHandler::startingApplication() { - qDebug() << "Starting app...\n"; + if(d->loglevel > 0) + d->out << "Starting app..." << endl; } void TrkSignalHandler::applicationRunning(uint pid) { - qDebug() << "Running...\n"; + if(d->loglevel > 0) + d->out << "Running..." << endl; } void TrkSignalHandler::canNotRun(const QString &errorMessage) { - qWarning() << "Cannot run - " << errorMessage << "\n"; + d->err << "Cannot run - " << errorMessage << endl; } void TrkSignalHandler::finished() { - qDebug() << "Done.\n"; + if(d->loglevel > 0) + d->out << "Done." << endl; QCoreApplication::quit(); } void TrkSignalHandler::applicationOutputReceived(const QString &output) { - qDebug() << "> " << output; + d->out << output; } void TrkSignalHandler::copyProgress(int percent) { - qDebug() << percent << "%"; + if(d->loglevel > 0) { + d->out << percent << "% "; + d->out.flush(); + if(percent==100) + d->out << endl; + } } void TrkSignalHandler::stateChanged(int state) { - qDebug() << "State" << state; + if(d->loglevel > 1) + d->out << "State" << state << endl; +} + +void TrkSignalHandler::setLogLevel(int level) +{ + d->loglevel = level; +} + +void TrkSignalHandler::stopped(uint pc, uint pid, uint tid, const QString& reason) +{ + d->err << "STOPPED: pc=" << hex << pc << " pid=" << pid + << " tid=" << tid << dec << " - " << reason << endl; + // if it was a breakpoint, then we could continue with "emit resume(pid, tid);" + // since we have set no breakpoints, it will be a just in time debug of a panic / exception + emit terminate(); +} + +void TrkSignalHandler::timeout() +{ + d->err << "FAILED: stopping test due to timeout" << endl; + emit terminate(); } +TrkSignalHandlerPrivate::TrkSignalHandlerPrivate() : + out(stdout), + err(stderr), + loglevel(0) +{ + +} + +TrkSignalHandlerPrivate::~TrkSignalHandlerPrivate() +{ + out.flush(); + err.flush(); +} + +TrkSignalHandler::TrkSignalHandler() +{ + d = new TrkSignalHandlerPrivate(); +} + +TrkSignalHandler::~TrkSignalHandler() +{ + delete d; +} diff --git a/tools/runonphone/trksignalhandler.h b/tools/runonphone/trksignalhandler.h index 21df4d9..c2573da 100644 --- a/tools/runonphone/trksignalhandler.h +++ b/tools/runonphone/trksignalhandler.h @@ -44,6 +44,7 @@ #include <QObject> #include <QString> +class TrkSignalHandlerPrivate; class TrkSignalHandler : public QObject { Q_OBJECT @@ -63,6 +64,17 @@ public slots: void applicationOutputReceived(const QString &output); void copyProgress(int percent); void stateChanged(int); + void stopped(uint pc, uint pid, uint tid, const QString& reason); + void timeout(); +signals: + void resume(uint pid, uint tid); + void terminate(); +public: + TrkSignalHandler(); + ~TrkSignalHandler(); + void setLogLevel(int); +private: + TrkSignalHandlerPrivate *d; }; #endif // TRKSIGNALHANDLER_H |