Commit c9501866 authored by Clinton Stimpson's avatar Clinton Stimpson

ENH: Improve error handling when testing with python.

parent 7f800488
...@@ -177,6 +177,8 @@ void pqEventDispatcher::stopPlayback() ...@@ -177,6 +177,8 @@ void pqEventDispatcher::stopPlayback()
this, this,
SIGNAL(readyPlayNextEvent())); SIGNAL(readyPlayNextEvent()));
#endif #endif
this->Implementation->Source->stop();
this->Implementation->Source = 0; this->Implementation->Source = 0;
this->Implementation->Player = 0; this->Implementation->Player = 0;
......
...@@ -60,6 +60,9 @@ public: ...@@ -60,6 +60,9 @@ public:
Returns true for valid file, false for invalid file */ Returns true for valid file, false for invalid file */
virtual void setContent(const QString& filename) = 0; virtual void setContent(const QString& filename) = 0;
/** tell the source to stop feeding in events */
virtual void stop() {}
}; };
#endif // !_pqEventSource_h #endif // !_pqEventSource_h
......
...@@ -45,7 +45,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ...@@ -45,7 +45,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QFile> #include <QFile>
#include <QtDebug> #include <QtDebug>
#include <QMutex> #include <QMutex>
#include <QWaitCondition>
#include <QCoreApplication> #include <QCoreApplication>
#include <QEvent> #include <QEvent>
#include <QStringList> #include <QStringList>
...@@ -62,7 +61,6 @@ static pqPythonEventSource* Instance = NULL; ...@@ -62,7 +61,6 @@ static pqPythonEventSource* Instance = NULL;
static QString PropertyObject; static QString PropertyObject;
static QString PropertyResult; static QString PropertyResult;
static QString PropertyValue; static QString PropertyValue;
static QWaitCondition WaitResults;
static QStringList ObjectList; static QStringList ObjectList;
...@@ -84,7 +82,11 @@ QtTesting_playCommand(PyObject* /*self*/, PyObject* args) ...@@ -84,7 +82,11 @@ QtTesting_playCommand(PyObject* /*self*/, PyObject* args)
if(Instance) if(Instance)
{ {
Instance->postNextEvent(object, command, arguments); if(!Instance->postNextEvent(object, command, arguments))
{
PyErr_SetString(PyExc_AssertionError, "error processing event");
return NULL;
}
} }
else else
{ {
...@@ -117,7 +119,11 @@ QtTesting_getProperty(PyObject* /*self*/, PyObject* args) ...@@ -117,7 +119,11 @@ QtTesting_getProperty(PyObject* /*self*/, PyObject* args)
QMutex mut; QMutex mut;
mut.lock(); mut.lock();
QMetaObject::invokeMethod(Instance, "threadGetProperty", Qt::QueuedConnection); QMetaObject::invokeMethod(Instance, "threadGetProperty", Qt::QueuedConnection);
WaitResults.wait(&mut); if(!Instance->waitForGUI(mut))
{
PyErr_SetString(PyExc_ValueError, "error getting property");
return NULL;
}
} }
else if(QThread::currentThread() == QApplication::instance()->thread()) else if(QThread::currentThread() == QApplication::instance()->thread())
{ {
...@@ -164,7 +170,11 @@ QtTesting_setProperty(PyObject* /*self*/, PyObject* args) ...@@ -164,7 +170,11 @@ QtTesting_setProperty(PyObject* /*self*/, PyObject* args)
QMutex mut; QMutex mut;
mut.lock(); mut.lock();
QMetaObject::invokeMethod(Instance, "threadSetProperty", Qt::QueuedConnection); QMetaObject::invokeMethod(Instance, "threadSetProperty", Qt::QueuedConnection);
WaitResults.wait(&mut); if(!Instance->waitForGUI(mut))
{
PyErr_SetString(PyExc_ValueError, "error setting property");
return NULL;
}
} }
else if(QThread::currentThread() == QApplication::instance()->thread()) else if(QThread::currentThread() == QApplication::instance()->thread())
{ {
...@@ -242,7 +252,11 @@ QtTesting_getChildren(PyObject* /*self*/, PyObject* args) ...@@ -242,7 +252,11 @@ QtTesting_getChildren(PyObject* /*self*/, PyObject* args)
QMutex mut; QMutex mut;
mut.lock(); mut.lock();
QMetaObject::invokeMethod(Instance, "threadGetChildren", Qt::QueuedConnection); QMetaObject::invokeMethod(Instance, "threadGetChildren", Qt::QueuedConnection);
WaitResults.wait(&mut); if(!Instance->waitForGUI(mut))
{
PyErr_SetString(PyExc_ValueError, "error getting children");
return NULL;
}
} }
else if(QThread::currentThread() == QApplication::instance()->thread()) else if(QThread::currentThread() == QApplication::instance()->thread())
{ {
...@@ -374,7 +388,7 @@ QString pqPythonEventSource::getProperty(QString& object, const QString& prop) ...@@ -374,7 +388,7 @@ QString pqPythonEventSource::getProperty(QString& object, const QString& prop)
void pqPythonEventSource::threadGetProperty() void pqPythonEventSource::threadGetProperty()
{ {
PropertyResult = this->getProperty(PropertyObject, PropertyResult); PropertyResult = this->getProperty(PropertyObject, PropertyResult);
WaitResults.wakeAll(); this->guiAcknowledge();
} }
...@@ -402,7 +416,7 @@ void pqPythonEventSource::setProperty(QString& object, QString& prop, ...@@ -402,7 +416,7 @@ void pqPythonEventSource::setProperty(QString& object, QString& prop,
void pqPythonEventSource::threadSetProperty() void pqPythonEventSource::threadSetProperty()
{ {
this->setProperty(PropertyObject, PropertyResult, PropertyValue); this->setProperty(PropertyObject, PropertyResult, PropertyValue);
WaitResults.wakeAll(); this->guiAcknowledge();
} }
...@@ -432,7 +446,7 @@ QStringList pqPythonEventSource::getChildren(QString& object) ...@@ -432,7 +446,7 @@ QStringList pqPythonEventSource::getChildren(QString& object)
void pqPythonEventSource::threadGetChildren() void pqPythonEventSource::threadGetChildren()
{ {
ObjectList = this->getChildren(PropertyObject); ObjectList = this->getChildren(PropertyObject);
WaitResults.wakeAll(); this->guiAcknowledge();
} }
void pqPythonEventSource::run() void pqPythonEventSource::run()
......
...@@ -41,32 +41,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ...@@ -41,32 +41,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QEvent> #include <QEvent>
#include <QApplication> #include <QApplication>
namespace
{
class pqPlayCommandEvent : public QEvent
{
public:
pqPlayCommandEvent(const QString& o, const QString& c, const QString& a)
: QEvent(QEvent::User),
Object(o),
Command(c),
Arguments(a)
{
}
QString Object;
QString Command;
QString Arguments;
};
}
class pqThreadedEventSource::pqInternal : public QThread class pqThreadedEventSource::pqInternal : public QThread
{ {
friend class pqThreadedEventSource; friend class pqThreadedEventSource;
public: public:
pqInternal(pqThreadedEventSource& source) pqInternal(pqThreadedEventSource& source)
: Source(source), : Source(source),
ShouldStop(0),
GotEvent(false) GotEvent(false)
{ {
} }
...@@ -81,6 +62,7 @@ public: ...@@ -81,6 +62,7 @@ public:
QWaitCondition WaitCondition; QWaitCondition WaitCondition;
QEventLoop Loop; QEventLoop Loop;
QAtomic ShouldStop;
bool GotEvent; bool GotEvent;
QString CurrentObject; QString CurrentObject;
QString CurrentCommand; QString CurrentCommand;
...@@ -117,8 +99,8 @@ int pqThreadedEventSource::getNextEvent( ...@@ -117,8 +99,8 @@ int pqThreadedEventSource::getNextEvent(
command = this->Internal->CurrentCommand; command = this->Internal->CurrentCommand;
arguments = this->Internal->CurrentArgument; arguments = this->Internal->CurrentArgument;
this->Internal->GotEvent = false; this->Internal->GotEvent = false;
this->Internal->WaitCondition.wakeAll(); this->guiAcknowledge();
if(object == QString::null) if(object == QString::null)
{ {
if(arguments == "failure") if(arguments == "failure")
...@@ -144,7 +126,7 @@ void pqThreadedEventSource::relayEvent(QString object, QString command, QString ...@@ -144,7 +126,7 @@ void pqThreadedEventSource::relayEvent(QString object, QString command, QString
} }
void pqThreadedEventSource::postNextEvent(const QString& object, bool pqThreadedEventSource::postNextEvent(const QString& object,
const QString& command, const QString& command,
const QString& argument) const QString& argument)
{ {
...@@ -155,8 +137,7 @@ void pqThreadedEventSource::postNextEvent(const QString& object, ...@@ -155,8 +137,7 @@ void pqThreadedEventSource::postNextEvent(const QString& object,
Q_ARG(QString, command), Q_ARG(QString, command),
Q_ARG(QString, argument)); Q_ARG(QString, argument));
// wait for the GUI thread to take the event and wake us up return this->waitForGUI(mut);
this->Internal->WaitCondition.wait(&mut);
} }
void pqThreadedEventSource::start() void pqThreadedEventSource::start()
...@@ -164,6 +145,27 @@ void pqThreadedEventSource::start() ...@@ -164,6 +145,27 @@ void pqThreadedEventSource::start()
this->Internal->start(); this->Internal->start();
} }
void pqThreadedEventSource::stop()
{
this->Internal->ShouldStop = 1;
this->guiAcknowledge();
}
bool pqThreadedEventSource::waitForGUI(QMutex& m)
{
if(this->Internal->ShouldStop)
{
return false;
}
this->Internal->WaitCondition.wait(&m);
return !this->Internal->ShouldStop;
}
void pqThreadedEventSource::guiAcknowledge()
{
this->Internal->WaitCondition.wakeAll();
}
void pqThreadedEventSource::done(int success) void pqThreadedEventSource::done(int success)
{ {
if(success == 0) if(success == 0)
......
...@@ -37,6 +37,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ...@@ -37,6 +37,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "pqEventSource.h" #include "pqEventSource.h"
class QString; class QString;
class QMutex;
/// Abstract interface for objects that can supply high-level testing events /// Abstract interface for objects that can supply high-level testing events
/// on a separte thread. This class is derived from, and run() is /// on a separte thread. This class is derived from, and run() is
...@@ -59,10 +60,26 @@ public: ...@@ -59,10 +60,26 @@ public:
QString& arguments); QString& arguments);
/** The testing thread may post an event for the GUI to process. /** The testing thread may post an event for the GUI to process.
This function blocks until there are no previously queued events to play. */ This function blocks until there are no previously queued
void postNextEvent(const QString& object, events to play.
If the event plays successfully, true is returned. */
bool postNextEvent(const QString& object,
const QString& command, const QString& command,
const QString& argument); const QString& argument);
/** tell this source to stop */
void stop();
/** Wait for the GUI thread to acknowledge an event.
A previously locked mutex must be passed in.
For use by the testing thread.
If return value is false, an error occurred and
the testing thread should terminate. */
bool waitForGUI(QMutex& m);
/** Give the testing thread an acknowledgement.
For use by the GUI thread */
void guiAcknowledge();
private slots: private slots:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment