From 34a1a6b5d6399e7bcad136fdaa9a050a0f8bb2dc Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Fri, 16 Apr 2010 15:33:41 +1000 Subject: Wait for debug clients asynchronously instead of blocking creation of the engine until a debug client has connected. This makes for easier debugging from Qt Creator when debugging C++ and QML together and when debugging an application that has multiple engines. --- .../debugger/qdeclarativedebugservice.cpp | 133 +++++++++------------ .../debugger/qdeclarativedebugservice_p.h | 7 +- src/declarative/qml/qdeclarativeengine.cpp | 2 - .../qdeclarativedebug/tst_qdeclarativedebug.cpp | 91 +++++++------- .../tst_qdeclarativedebugclient.cpp | 42 +++---- .../tst_qdeclarativedebugservice.cpp | 42 +++---- tests/auto/declarative/shared/debugutil.cpp | 81 +------------ tests/auto/declarative/shared/debugutil_p.h | 56 --------- 8 files changed, 143 insertions(+), 311 deletions(-) diff --git a/src/declarative/debugger/qdeclarativedebugservice.cpp b/src/declarative/debugger/qdeclarativedebugservice.cpp index 9d9d1d0..34e73fd 100644 --- a/src/declarative/debugger/qdeclarativedebugservice.cpp +++ b/src/declarative/debugger/qdeclarativedebugservice.cpp @@ -60,12 +60,12 @@ class QDeclarativeDebugServer : public QObject Q_DISABLE_COPY(QDeclarativeDebugServer) public: static QDeclarativeDebugServer *instance(); - void wait(); - void registerForStartNotification(QObject *object, const char *receiver); + void listen(); + bool hasDebuggingClient() const; private Q_SLOTS: void readyRead(); - void registeredObjectDestroyed(QObject *object); + void newConnection(); private: friend class QDeclarativeDebugService; @@ -78,14 +78,14 @@ class QDeclarativeDebugServerPrivate : public QObjectPrivate Q_DECLARE_PUBLIC(QDeclarativeDebugServer) public: QDeclarativeDebugServerPrivate(); - void wait(); int port; QTcpSocket *connection; QPacketProtocol *protocol; QHash plugins; QStringList enabledPlugins; - QList > notifyClients; + QTcpServer *tcpServer; + bool gotHello; }; class QDeclarativeDebugServicePrivate : public QObjectPrivate @@ -99,56 +99,41 @@ public: }; QDeclarativeDebugServerPrivate::QDeclarativeDebugServerPrivate() -: connection(0), protocol(0) +: connection(0), protocol(0), gotHello(false) { } -void QDeclarativeDebugServerPrivate::wait() +void QDeclarativeDebugServer::listen() { - Q_Q(QDeclarativeDebugServer); - QTcpServer server; - - if (!server.listen(QHostAddress::Any, port)) { - qWarning("QDeclarativeDebugServer: Unable to listen on port %d", port); - return; - } - - qWarning("QDeclarativeDebugServer: Waiting for connection on port %d...", port); - - for (int i=0; itcpServer = new QTcpServer(this); + QObject::connect(d->tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection())); + if (d->tcpServer->listen(QHostAddress::Any, d->port)) + qWarning("QDeclarativeDebugServer: Waiting for connection on port %d...", d->port); + else + qWarning("QDeclarativeDebugServer: Unable to listen on port %d", d->port); +} - connection = server.nextPendingConnection(); - connection->setParent(q); - protocol = new QPacketProtocol(connection, q); +void QDeclarativeDebugServer::newConnection() +{ + Q_D(QDeclarativeDebugServer); - // ### Wait for hello - while (!protocol->packetsAvailable()) { - connection->waitForReadyRead(); - } - QPacket hello = protocol->read(); - QString name; - hello >> name >> enabledPlugins; - if (name != QLatin1String("QDeclarativeDebugServer")) { - qWarning("QDeclarativeDebugServer: Invalid hello message"); - delete protocol; delete connection; connection = 0; protocol = 0; + if (d->connection) { + qWarning("QDeclarativeDebugServer error: another client is already connected"); return; } - QObject::connect(protocol, SIGNAL(readyRead()), q, SLOT(readyRead())); - q->readyRead(); + d->connection = d->tcpServer->nextPendingConnection(); + d->connection->setParent(this); + d->protocol = new QPacketProtocol(d->connection, this); + QObject::connect(d->protocol, SIGNAL(readyRead()), this, SLOT(readyRead())); +} - qWarning("QDeclarativeDebugServer: Connection established"); +bool QDeclarativeDebugServer::hasDebuggingClient() const +{ + Q_D(const QDeclarativeDebugServer); + return d->gotHello; } QDeclarativeDebugServer *QDeclarativeDebugServer::instance() @@ -163,36 +148,15 @@ QDeclarativeDebugServer *QDeclarativeDebugServer::instance() bool ok = false; int port = env.toInt(&ok); - if (ok && port > 1024) + if (ok && port > 1024) { server = new QDeclarativeDebugServer(port); + server->listen(); + } } return server; } -void QDeclarativeDebugServer::wait() -{ - Q_D(QDeclarativeDebugServer); - d->wait(); -} - -void QDeclarativeDebugServer::registerForStartNotification(QObject *object, const char *methodName) -{ - Q_D(QDeclarativeDebugServer); - connect(object, SIGNAL(destroyed(QObject*)), SLOT(registeredObjectDestroyed(QObject*))); - d->notifyClients.append(qMakePair(object, QByteArray(methodName))); -} - -void QDeclarativeDebugServer::registeredObjectDestroyed(QObject *object) -{ - Q_D(QDeclarativeDebugServer); - QMutableListIterator > i(d->notifyClients); - while (i.hasNext()) { - if (i.next().first == object) - i.remove(); - } -} - QDeclarativeDebugServer::QDeclarativeDebugServer(int port) : QObject(*(new QDeclarativeDebugServerPrivate)) { @@ -204,6 +168,23 @@ void QDeclarativeDebugServer::readyRead() { Q_D(QDeclarativeDebugServer); + if (!d->gotHello) { + QPacket hello = d->protocol->read(); + QString name; + hello >> name >> d->enabledPlugins; + if (name != QLatin1String("QDeclarativeDebugServer")) { + qWarning("QDeclarativeDebugServer: Invalid hello message"); + QObject::disconnect(d->protocol, SIGNAL(readyRead()), this, SLOT(readyRead())); + d->protocol->deleteLater(); + d->protocol = 0; + d->connection->deleteLater(); + d->connection = 0; + return; + } + d->gotHello = true; + qWarning("QDeclarativeDebugServer: Connection established"); + } + QString debugServer(QLatin1String("QDeclarativeDebugServer")); while (d->protocol->packetsAvailable()) { @@ -375,6 +356,12 @@ bool QDeclarativeDebugService::isDebuggingEnabled() return QDeclarativeDebugServer::instance() != 0; } +bool QDeclarativeDebugService::hasDebuggingClient() +{ + return QDeclarativeDebugServer::instance() != 0 + && QDeclarativeDebugServer::instance()->hasDebuggingClient(); +} + QString QDeclarativeDebugService::objectToString(QObject *obj) { if(!obj) @@ -390,16 +377,6 @@ QString QDeclarativeDebugService::objectToString(QObject *obj) return rv; } -void QDeclarativeDebugService::waitForClients() -{ - QDeclarativeDebugServer::instance()->wait(); -} - -void QDeclarativeDebugService::notifyOnServerStart(QObject *object, const char *receiver) -{ - QDeclarativeDebugServer::instance()->registerForStartNotification(object, receiver); -} - void QDeclarativeDebugService::sendMessage(const QByteArray &message) { Q_D(QDeclarativeDebugService); diff --git a/src/declarative/debugger/qdeclarativedebugservice_p.h b/src/declarative/debugger/qdeclarativedebugservice_p.h index 498edf3..c461ddf 100644 --- a/src/declarative/debugger/qdeclarativedebugservice_p.h +++ b/src/declarative/debugger/qdeclarativedebugservice_p.h @@ -68,19 +68,16 @@ public: static int idForObject(QObject *); static QObject *objectForId(int); - static bool isDebuggingEnabled(); static QString objectToString(QObject *obj); - static void waitForClients(); - - static void notifyOnServerStart(QObject *object, const char *receiver); + static bool isDebuggingEnabled(); + static bool hasDebuggingClient(); protected: virtual void enabledChanged(bool); virtual void messageReceived(const QByteArray &); private: - void registerForStartNotification(QObject *object, const char *methodName); friend class QDeclarativeDebugServer; }; diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index cfdc79e..4dbd199 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -390,8 +390,6 @@ void QDeclarativeEnginePrivate::init() qmlEngineDebugServer(); isDebugging = true; QDeclarativeEngineDebugServer::addEngine(q); - - qmlEngineDebugServer()->waitForClients(); } } diff --git a/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp b/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp index 133dcb8..49d430e 100644 --- a/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp +++ b/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp @@ -60,6 +60,7 @@ #include #include +#include "../../../shared/util.h" #include "../shared/debugutil_p.h" Q_DECLARE_METATYPE(QDeclarativeDebugWatch::State) @@ -69,14 +70,6 @@ class tst_QDeclarativeDebug : public QObject { Q_OBJECT -public: - tst_QDeclarativeDebug(QDeclarativeDebugTestData *data) - { - m_conn = data->conn; - m_engine = data->engine; - m_rootItem = data->items[0]; - } - private: QDeclarativeDebugObjectReference findRootObject(); QDeclarativeDebugPropertyReference findProperty(const QList &props, const QString &name) const; @@ -93,8 +86,11 @@ private: QDeclarativeEngine *m_engine; QDeclarativeItem *m_rootItem; + QObjectList m_components; + private slots: void initTestCase(); + void cleanupTestCase(); void watch_property(); void watch_object(); @@ -278,9 +274,50 @@ void tst_QDeclarativeDebug::compareProperties(const QDeclarativeDebugPropertyRef void tst_QDeclarativeDebug::initTestCase() { + qRegisterMetaType(); + + qputenv("QML_DEBUG_SERVER_PORT", "3768"); + m_engine = new QDeclarativeEngine(this); + + QList qml; + qml << "import Qt 4.7\n" + "Item {" + "width: 10; height: 20; scale: blueRect.scale;" + "Rectangle { id: blueRect; width: 500; height: 600; color: \"blue\"; }" + "Text { color: blueRect.color; }" + "MouseArea {" + "onEntered: { console.log('hello') }" + "}" + "}"; + // add second component to test multiple root contexts + qml << "import Qt 4.7\n" + "Item {}"; + + for (int i=0; i(component.create()); + } + m_rootItem = qobject_cast(m_components.first()); + + + // add an extra context to test for multiple contexts + QDeclarativeContext *context = new QDeclarativeContext(m_engine->rootContext(), this); + context->setObjectName("tst_QDeclarativeDebug_childContext"); + + m_conn = new QDeclarativeDebugConnection(this); + m_conn->connectToHost("127.0.0.1", 3768); + bool ok = m_conn->waitForConnected(); + Q_ASSERT(ok); + QTRY_VERIFY(QDeclarativeDebugService::hasDebuggingClient()); + m_dbg = new QDeclarativeEngineDebug(m_conn, this); +} - qRegisterMetaType(); +void tst_QDeclarativeDebug::cleanupTestCase() +{ + qDeleteAll(m_components); } void tst_QDeclarativeDebug::watch_property() @@ -804,40 +841,6 @@ void tst_QDeclarativeDebug::tst_QDeclarativeDebugPropertyReference() compareProperties(r, ref); } - -class tst_QDeclarativeDebug_Factory : public QDeclarativeTestFactory -{ -public: - QObject *createTest(QDeclarativeDebugTestData *data) - { - tst_QDeclarativeDebug *test = new tst_QDeclarativeDebug(data); - QDeclarativeContext *c = new QDeclarativeContext(data->engine->rootContext(), test); - c->setObjectName("tst_QDeclarativeDebug_childContext"); - return test; - } -}; - -int main(int argc, char *argv[]) -{ - QApplication app(argc, argv); - - QList qml; - qml << "import Qt 4.7\n" - "Item {" - "width: 10; height: 20; scale: blueRect.scale;" - "Rectangle { id: blueRect; width: 500; height: 600; color: \"blue\"; }" - "Text { color: blueRect.color; }" - "MouseArea {" - "onEntered: { console.log('hello') }" - "}" - "}"; - // add second component to test multiple root contexts - qml << "import Qt 4.7\n" - "Item {}"; - tst_QDeclarativeDebug_Factory factory; - return QDeclarativeDebugTest::runTests(&factory, qml); -} - -//QTEST_MAIN(tst_QDeclarativeDebug) +QTEST_MAIN(tst_QDeclarativeDebug) #include "tst_qdeclarativedebug.moc" diff --git a/tests/auto/declarative/qdeclarativedebugclient/tst_qdeclarativedebugclient.cpp b/tests/auto/declarative/qdeclarativedebugclient/tst_qdeclarativedebugclient.cpp index d3679a7..fb17f90 100644 --- a/tests/auto/declarative/qdeclarativedebugclient/tst_qdeclarativedebugclient.cpp +++ b/tests/auto/declarative/qdeclarativedebugclient/tst_qdeclarativedebugclient.cpp @@ -52,21 +52,19 @@ #include #include +#include "../../../shared/util.h" #include "../shared/debugutil_p.h" class tst_QDeclarativeDebugClient : public QObject { Q_OBJECT -public: - tst_QDeclarativeDebugClient(QDeclarativeDebugTestData *data) - { - m_conn = data->conn; - } - +private: QDeclarativeDebugConnection *m_conn; private slots: + void initTestCase(); + void name(); void isEnabled(); void setEnabled(); @@ -74,6 +72,19 @@ private slots: void sendMessage(); }; +void tst_QDeclarativeDebugClient::initTestCase() +{ + qputenv("QML_DEBUG_SERVER_PORT", "3768"); + new QDeclarativeEngine(this); + + m_conn = new QDeclarativeDebugConnection(this); + m_conn->connectToHost("127.0.0.1", 3768); + bool ok = m_conn->waitForConnected(); + Q_ASSERT(ok); + + QTRY_VERIFY(QDeclarativeDebugService::hasDebuggingClient()); +} + void tst_QDeclarativeDebugClient::name() { QString name = "tst_QDeclarativeDebugClient::name()"; @@ -136,22 +147,7 @@ void tst_QDeclarativeDebugClient::sendMessage() QCOMPARE(resp, msg); } - -class tst_QDeclarativeDebugClient_Factory : public QDeclarativeTestFactory -{ -public: - QObject *createTest(QDeclarativeDebugTestData *data) { return new tst_QDeclarativeDebugClient(data); } -}; - - -// This does not use QTEST_MAIN because the test has to be created and run -// in a separate thread. -int main(int argc, char *argv[]) -{ - QApplication app(argc, argv); - - tst_QDeclarativeDebugClient_Factory factory; - return QDeclarativeDebugTest::runTests(&factory); -} +QTEST_MAIN(tst_QDeclarativeDebugClient) #include "tst_qdeclarativedebugclient.moc" + diff --git a/tests/auto/declarative/qdeclarativedebugservice/tst_qdeclarativedebugservice.cpp b/tests/auto/declarative/qdeclarativedebugservice/tst_qdeclarativedebugservice.cpp index c8fc001..80d7f76 100644 --- a/tests/auto/declarative/qdeclarativedebugservice/tst_qdeclarativedebugservice.cpp +++ b/tests/auto/declarative/qdeclarativedebugservice/tst_qdeclarativedebugservice.cpp @@ -52,21 +52,19 @@ #include #include +#include "../../../shared/util.h" #include "../shared/debugutil_p.h" + class tst_QDeclarativeDebugService : public QObject { Q_OBJECT - -public: - tst_QDeclarativeDebugService(QDeclarativeDebugTestData *data) - { - m_conn = data->conn; - } - +private: QDeclarativeDebugConnection *m_conn; private slots: + void initTestCase(); + void name(); void isEnabled(); void enabledChanged(); @@ -76,6 +74,19 @@ private slots: void objectToString(); }; +void tst_QDeclarativeDebugService::initTestCase() +{ + qputenv("QML_DEBUG_SERVER_PORT", "3768"); + new QDeclarativeEngine(this); + + m_conn = new QDeclarativeDebugConnection(this); + m_conn->connectToHost("127.0.0.1", 3768); + bool ok = m_conn->waitForConnected(); + Q_ASSERT(ok); + + QTRY_VERIFY(QDeclarativeDebugService::hasDebuggingClient()); +} + void tst_QDeclarativeDebugService::name() { QString name = "tst_QDeclarativeDebugService::name()"; @@ -170,21 +181,6 @@ void tst_QDeclarativeDebugService::objectToString() delete obj; } - -class tst_QDeclarativeDebugService_Factory : public QDeclarativeTestFactory -{ -public: - QObject *createTest(QDeclarativeDebugTestData *data) { return new tst_QDeclarativeDebugService(data); } -}; - -// This does not use QTEST_MAIN because the test has to be created and run -// in a separate thread. -int main(int argc, char *argv[]) -{ - QApplication app(argc, argv); - - tst_QDeclarativeDebugService_Factory factory; - return QDeclarativeDebugTest::runTests(&factory); -} +QTEST_MAIN(tst_QDeclarativeDebugService) #include "tst_qdeclarativedebugservice.moc" diff --git a/tests/auto/declarative/shared/debugutil.cpp b/tests/auto/declarative/shared/debugutil.cpp index 66f04e5..c0c3eca 100644 --- a/tests/auto/declarative/shared/debugutil.cpp +++ b/tests/auto/declarative/shared/debugutil.cpp @@ -47,11 +47,11 @@ #include "debugutil_p.h" -#include bool QDeclarativeDebugTest::waitForSignal(QObject *receiver, const char *member, int timeout) { QEventLoop loop; QTimer timer; + timer.setSingleShot(true); QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); QObject::connect(receiver, member, &loop, SLOT(quit())); timer.start(timeout); @@ -59,25 +59,6 @@ bool QDeclarativeDebugTest::waitForSignal(QObject *receiver, const char *member, return timer.isActive(); } - -QDeclarativeDebugTestData::QDeclarativeDebugTestData(QEventLoop *el) - : exitCode(-1), loop(el) -{ -} - -QDeclarativeDebugTestData::~QDeclarativeDebugTestData() -{ - qDeleteAll(items); -} - -void QDeclarativeDebugTestData::testsFinished(int code) -{ - exitCode = code; - loop->quit(); -} - - - QDeclarativeDebugTestService::QDeclarativeDebugTestService(const QString &s, QObject *parent) : QDeclarativeDebugService(s, parent), enabled(false) { @@ -117,63 +98,3 @@ void QDeclarativeDebugTestClient::messageReceived(const QByteArray &ba) emit serverMessage(ba); } - -tst_QDeclarativeDebug_Thread::tst_QDeclarativeDebug_Thread(QDeclarativeDebugTestData *data, QDeclarativeTestFactory *factory) - : m_data(data), m_factory(factory) -{ -} - -void tst_QDeclarativeDebug_Thread::run() -{ - bool ok = false; - - QDeclarativeDebugConnection conn; - conn.connectToHost("127.0.0.1", 3768); - ok = conn.waitForConnected(); - Q_ASSERT(ok); - - QEventLoop loop; - connect(m_data, SIGNAL(engineCreated()), &loop, SLOT(quit())); - loop.exec(); - - m_data->conn = &conn; - - Q_ASSERT(m_factory); - QObject *test = m_factory->createTest(m_data); - Q_ASSERT(test); - int code = QTest::qExec(test, QCoreApplication::arguments()); - delete test; - emit testsFinished(code); -} - -int QDeclarativeDebugTest::runTests(QDeclarativeTestFactory *factory, const QList &qml) -{ - qputenv("QML_DEBUG_SERVER_PORT", "3768"); - - QEventLoop loop; - QDeclarativeDebugTestData data(&loop); - - tst_QDeclarativeDebug_Thread thread(&data, factory); - QObject::connect(&thread, SIGNAL(testsFinished(int)), &data, SLOT(testsFinished(int))); - - QDeclarativeDebugService::notifyOnServerStart(&thread, "start"); - - QDeclarativeEngine engine; // blocks until client connects - - foreach (const QByteArray &code, qml) { - QDeclarativeComponent c(&engine); - c.setData(code, QUrl::fromLocalFile("")); - Q_ASSERT(c.isReady()); // fails if bad syntax - data.items << qobject_cast(c.create()); - } - - // start the test - data.engine = &engine; - emit data.engineCreated(); - - loop.exec(); - thread.wait(); - - return data.exitCode; -} - diff --git a/tests/auto/declarative/shared/debugutil_p.h b/tests/auto/declarative/shared/debugutil_p.h index c152b5a..e6bb7ad 100644 --- a/tests/auto/declarative/shared/debugutil_p.h +++ b/tests/auto/declarative/shared/debugutil_p.h @@ -51,50 +51,10 @@ #include #include -class QDeclarativeTestFactory; - class QDeclarativeDebugTest { public: static bool waitForSignal(QObject *receiver, const char *member, int timeout = 5000); - - static int runTests(QDeclarativeTestFactory *factory, const QList &qml = QList()); -}; - -class QDeclarativeDebugTestData : public QObject -{ - Q_OBJECT -public: - QDeclarativeDebugTestData(QEventLoop *el); - - ~QDeclarativeDebugTestData(); - - QDeclarativeDebugConnection *conn; - QDeclarativeEngine *engine; - - int exitCode; - QEventLoop *loop; - - QList items; - -signals: - void engineCreated(); - -public slots: - void testsFinished(int code); - -private: - friend class QDeclarativeDebugTest; -}; - - -class QDeclarativeTestFactory -{ -public: - QDeclarativeTestFactory() {} - virtual ~QDeclarativeTestFactory() {} - - virtual QObject *createTest(QDeclarativeDebugTestData *data) = 0; }; class QDeclarativeDebugTestService : public QDeclarativeDebugService @@ -131,20 +91,4 @@ private: QByteArray lastMsg; }; -class tst_QDeclarativeDebug_Thread : public QThread -{ - Q_OBJECT -public: - tst_QDeclarativeDebug_Thread(QDeclarativeDebugTestData *data, QDeclarativeTestFactory *factory); - - void run(); - -signals: - void testsFinished(int); - -private: - QDeclarativeDebugTestData *m_data; - QDeclarativeTestFactory *m_factory; -}; - -- cgit v0.12