264 lines
8.4 KiB
C++
264 lines
8.4 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
** Contact: https://www.qt.io/licensing/
|
|
**
|
|
** This file is part of the test suite of the Qt Toolkit.
|
|
**
|
|
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
|
** Commercial License Usage
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
** accordance with the commercial license agreement provided with the
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
|
**
|
|
** GNU General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
** General Public License version 3 as published by the Free Software
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
** included in the packaging of this file. Please review the following
|
|
** information to ensure the GNU General Public License requirements will
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
**
|
|
** $QT_END_LICENSE$
|
|
**
|
|
****************************************************************************/
|
|
|
|
#include "debugutil_p.h"
|
|
#include "qqmldebugprocess_p.h"
|
|
|
|
#include <private/qqmldebugconnection_p.h>
|
|
|
|
#include <QtCore/qtimer.h>
|
|
#include <QtTest/qtest.h>
|
|
#include <QtTest/qsignalspy.h>
|
|
|
|
QQmlDebugTest::QQmlDebugTest(const char *qmlTestDataDir)
|
|
: QQmlDataTest(qmlTestDataDir)
|
|
{
|
|
}
|
|
|
|
bool QQmlDebugTest::waitForSignal(QObject *sender, const char *member, int timeout)
|
|
{
|
|
QSignalSpy spy(sender, member);
|
|
|
|
// Do not use spy.wait(). We want to avoid nested event loops.
|
|
if (QTest::qWaitFor([&]() { return spy.count() > 0; }, timeout))
|
|
return true;
|
|
|
|
qWarning("waitForSignal %s timed out after %d ms", member, timeout);
|
|
return false;
|
|
}
|
|
|
|
QList<QQmlDebugClient *> QQmlDebugTest::createOtherClients(QQmlDebugConnection *connection)
|
|
{
|
|
QList<QQmlDebugClient *> ret;
|
|
|
|
static const auto debuggerServices
|
|
= QStringList({"V8Debugger", "QmlDebugger", "DebugMessages"});
|
|
static const auto inspectorServices
|
|
= QStringList({"QmlInspector"});
|
|
static const auto profilerServices
|
|
= QStringList({"CanvasFrameRate", "EngineControl", "DebugMessages"});
|
|
|
|
for (const QString &service : debuggerServices) {
|
|
if (!connection->client(service))
|
|
ret << new QQmlDebugClient(service, connection);
|
|
}
|
|
for (const QString &service : inspectorServices) {
|
|
if (!connection->client(service))
|
|
ret << new QQmlDebugClient(service, connection);
|
|
}
|
|
for (const QString &service : profilerServices) {
|
|
if (!connection->client(service))
|
|
ret << new QQmlDebugClient(service, connection);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
QString QQmlDebugTest::clientStateString(const QQmlDebugClient *client)
|
|
{
|
|
if (!client)
|
|
return QLatin1String("null");
|
|
|
|
switch (client->state()) {
|
|
case QQmlDebugClient::NotConnected: return QLatin1String("Not connected");
|
|
case QQmlDebugClient::Unavailable: return QLatin1String("Unavailable");
|
|
case QQmlDebugClient::Enabled: return QLatin1String("Enabled");
|
|
default: return QLatin1String("Invalid");
|
|
}
|
|
|
|
}
|
|
|
|
QString QQmlDebugTest::connectionStateString(const QQmlDebugConnection *connection)
|
|
{
|
|
if (!connection)
|
|
return QLatin1String("null");
|
|
|
|
return connection->isConnected() ? QLatin1String("connected") : QLatin1String("not connected");
|
|
}
|
|
|
|
QQmlDebugTestClient::QQmlDebugTestClient(const QString &s, QQmlDebugConnection *c)
|
|
: QQmlDebugClient(s, c)
|
|
{
|
|
connect(this, &QQmlDebugClient::stateChanged, this, [this](QQmlDebugClient::State newState) {
|
|
QCOMPARE(newState, state());
|
|
});
|
|
}
|
|
|
|
QByteArray QQmlDebugTestClient::waitForResponse()
|
|
{
|
|
lastMsg.clear();
|
|
QQmlDebugTest::waitForSignal(this, SIGNAL(serverMessage(QByteArray)));
|
|
if (lastMsg.isEmpty()) {
|
|
qWarning() << "no response from server!";
|
|
return QByteArray();
|
|
}
|
|
return lastMsg;
|
|
}
|
|
|
|
void QQmlDebugTestClient::messageReceived(const QByteArray &ba)
|
|
{
|
|
lastMsg = ba;
|
|
emit serverMessage(ba);
|
|
}
|
|
|
|
QQmlDebugTest::ConnectResult QQmlDebugTest::connectTo(
|
|
const QString &executable, const QString &services, const QString &extraArgs,
|
|
bool block)
|
|
{
|
|
QStringList arguments;
|
|
arguments << QString::fromLatin1("-qmljsdebugger=port:13773,13783%3%4")
|
|
.arg(block ? QStringLiteral(",block") : QString())
|
|
.arg(services.isEmpty() ? services : (QStringLiteral(",services:") + services))
|
|
<< extraArgs;
|
|
|
|
m_process = createProcess(executable);
|
|
if (!m_process)
|
|
return ProcessFailed;
|
|
|
|
m_process->start(QStringList() << arguments);
|
|
if (!m_process->waitForSessionStart())
|
|
return SessionFailed;
|
|
|
|
m_connection = createConnection();
|
|
if (!m_connection)
|
|
return ConnectionFailed;
|
|
|
|
m_clients = createClients();
|
|
if (m_clients.contains(nullptr))
|
|
return ClientsFailed;
|
|
|
|
ClientStateHandler stateHandler(m_clients, createOtherClients(m_connection), services.isEmpty()
|
|
? QQmlDebugClient::Enabled : QQmlDebugClient::Unavailable);
|
|
|
|
QSignalSpy okSpy(&stateHandler, &ClientStateHandler::allOk);
|
|
QSignalSpy disconnectSpy(m_connection, &QQmlDebugConnection::disconnected);
|
|
m_connection->connectToHost(QLatin1String("127.0.0.1"), m_process->debugPort());
|
|
if (!QTest::qWaitFor([&](){ return okSpy.count() > 0 || disconnectSpy.count() > 0; }, 5000))
|
|
return ConnectionTimeout;
|
|
|
|
if (!stateHandler.allEnabled())
|
|
return EnableFailed;
|
|
|
|
if (!stateHandler.othersAsExpected())
|
|
return RestrictFailed;
|
|
|
|
return ConnectSuccess;
|
|
}
|
|
|
|
QList<QQmlDebugClient *> QQmlDebugTest::createClients()
|
|
{
|
|
return QList<QQmlDebugClient *>();
|
|
}
|
|
|
|
QQmlDebugProcess *QQmlDebugTest::createProcess(const QString &executable)
|
|
{
|
|
return new QQmlDebugProcess(executable, this);
|
|
}
|
|
|
|
QQmlDebugConnection *QQmlDebugTest::createConnection()
|
|
{
|
|
return new QQmlDebugConnection(this);
|
|
}
|
|
|
|
void QQmlDebugTest::cleanup()
|
|
{
|
|
if (QTest::currentTestFailed()) {
|
|
const QString null = QStringLiteral("null");
|
|
|
|
qDebug() << "Process State:" << (m_process ? m_process->stateString() : null);
|
|
qDebug() << "Application Output:" << (m_process ? m_process->output() : null);
|
|
qDebug() << "Connection State:" << QQmlDebugTest::connectionStateString(m_connection);
|
|
for (QQmlDebugClient *client : m_clients) {
|
|
if (client)
|
|
qDebug() << client->name() << "State:" << QQmlDebugTest::clientStateString(client);
|
|
else
|
|
qDebug() << "Failed Client:" << null;
|
|
}
|
|
}
|
|
|
|
qDeleteAll(m_clients);
|
|
m_clients.clear();
|
|
|
|
delete m_connection;
|
|
m_connection = nullptr;
|
|
|
|
if (m_process) {
|
|
m_process->stop();
|
|
delete m_process;
|
|
m_process = nullptr;
|
|
}
|
|
}
|
|
|
|
ClientStateHandler::ClientStateHandler(const QList<QQmlDebugClient *> &clients,
|
|
const QList<QQmlDebugClient *> &others,
|
|
QQmlDebugClient::State expectedOthers) :
|
|
m_clients(clients), m_others(others), m_expectedOthers(expectedOthers)
|
|
{
|
|
for (QQmlDebugClient *client : m_clients) {
|
|
QObject::connect(client, &QQmlDebugClient::stateChanged,
|
|
this, &ClientStateHandler::checkStates);
|
|
}
|
|
for (QQmlDebugClient *client : m_others) {
|
|
QObject::connect(client, &QQmlDebugClient::stateChanged,
|
|
this, &ClientStateHandler::checkStates);
|
|
}
|
|
}
|
|
|
|
ClientStateHandler::~ClientStateHandler()
|
|
{
|
|
qDeleteAll(m_others);
|
|
}
|
|
|
|
void ClientStateHandler::checkStates()
|
|
{
|
|
for (QQmlDebugClient *client : m_clients) {
|
|
if (client->state() != QQmlDebugClient::Enabled)
|
|
return;
|
|
}
|
|
|
|
m_allEnabled = true;
|
|
|
|
for (QQmlDebugClient *other : m_others) {
|
|
if (other->state() != m_expectedOthers)
|
|
return;
|
|
}
|
|
|
|
m_othersAsExpected = true;
|
|
emit allOk();
|
|
}
|
|
|
|
QString debugJsServerPath(const QString &selfPath)
|
|
{
|
|
static const char *debugserver = "qqmldebugjsserver";
|
|
QString appPath = QCoreApplication::applicationDirPath();
|
|
const int position = appPath.lastIndexOf(selfPath);
|
|
return (position == -1 ? appPath : appPath.replace(position, selfPath.length(), debugserver))
|
|
+ "/" + debugserver;
|
|
}
|
|
|
|
#include <moc_debugutil_p.cpp>
|