blob: 0f72c05915aad37b785356f4c753ffede285e978 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2017 Ford Motor Company
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtRemoteObjects module 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 "../../shared/testutils.h"
#include <QtTest/QtTest>
#include <QMetaType>
#include <QProcess>
#include <QFileInfo>
#include <QTcpServer>
#include <QTcpSocket>
#include <QRemoteObjectReplica>
#include <QRemoteObjectNode>
#include <QRemoteObjectSettingsStore>
#include "engine.h"
#include "speedometer.h"
#include "rep_engine_replica.h"
#include "rep_speedometer_merged.h"
#include "rep_enum_merged.h"
#include "rep_pod_merged.h"
#include "rep_localdatacenter_source.h"
#include "rep_tcpdatacenter_source.h"
#include "rep_localdatacenter_replica.h"
#include "rep_tcpdatacenter_replica.h"
#define SET_NODE_NAME(obj) (obj).setName(QLatin1String(#obj))
//DUMMY impl for variant comparison
bool operator<(const QVector<int> &lhs, const QVector<int> &rhs)
{
return lhs.size() < rhs.size();
}
class TestLargeData: public QObject
{
Q_OBJECT
Q_SIGNALS:
void send(const QByteArray &data);
};
class TestDynamicBase : public QObject
{
Q_OBJECT
public:
TestDynamicBase(QObject *parent=nullptr) : QObject(parent) {}
signals:
void otherValueChanged();
};
class TestDynamic : public TestDynamicBase
{
Q_OBJECT
Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)
Q_PROPERTY(int otherValue READ otherValue WRITE setOtherValue NOTIFY otherValueChanged)
public:
TestDynamic(QObject *parent=nullptr) :
TestDynamicBase(parent),
m_value(0),
m_otherValue(0) {}
int value() const { return m_value; }
void setValue(int value)
{
if (m_value == value)
return;
m_value = value;
emit valueChanged();
}
int otherValue() const { return m_otherValue; }
void setOtherValue(int otherValue)
{
if (m_otherValue == otherValue)
return;
m_otherValue = otherValue;
emit otherValueChanged();
}
signals:
void valueChanged();
private:
int m_value;
int m_otherValue;
};
class TestPersistedStore : public QRemoteObjectAbstractPersistedStore
{
Q_OBJECT
public:
TestPersistedStore() : type(EngineReplica::HYBRID) {}
void saveProperties(const QString &, const QByteArray &, const QVariantList &values) override
{
type = values.at(0).value<EngineReplica::EngineType>();
}
QVariantList restoreProperties(const QString &, const QByteArray &) override
{
return QVariantList() << QVariant::fromValue(type);
}
private:
EngineReplica::EngineType type;
};
class tst_Integration: public QObject
{
Q_OBJECT
void setupTcp()
{
if (!tcpServer) {
tcpServer = new QTcpServer;
tcpServer->listen(QHostAddress::Any, 65511);
socketClient = new QTcpSocket;
socketClient->connectToHost(QHostAddress::LocalHost, tcpServer->serverPort());
QVERIFY(socketClient->waitForConnected(5000));
QVERIFY(tcpServer->waitForNewConnection(5000));
QVERIFY(tcpServer->hasPendingConnections());
socketServer = tcpServer->nextPendingConnection();
}
}
void setupHost(bool useRegistry=false)
{
QFETCH_GLOBAL(QUrl, hostUrl);
QFETCH_GLOBAL(QUrl, registryUrl);
host = new QRemoteObjectHost;
SET_NODE_NAME(*host);
if (!hostUrl.isEmpty()) {
host->setHostUrl(hostUrl);
if (useRegistry)
host->setRegistryUrl(registryUrl);
} else {
setupTcp();
host->addHostSideConnection(socketServer);
}
}
void setupClient(bool useRegistry=false)
{
QFETCH_GLOBAL(QUrl, hostUrl);
QFETCH_GLOBAL(QUrl, registryUrl);
client = new QRemoteObjectNode;
Q_SET_OBJECT_NAME(*client);
if (!hostUrl.isEmpty())
{
if (useRegistry)
client->setRegistryUrl(registryUrl);
else {
client->connectToNode(hostUrl);
}
} else {
setupTcp();
client->addClientSideConnection(socketClient);
}
}
void setupRegistry()
{
QFETCH_GLOBAL(QUrl, registryUrl);
registry = new QRemoteObjectRegistryHost(registryUrl);
SET_NODE_NAME(*registry);
}
signals:
void forwardResult(int);
private:
QRemoteObjectHost *host;
QRemoteObjectNode *client;
QRemoteObjectRegistryHost *registry;
QTcpServer *tcpServer;
QPointer<QTcpSocket> socketClient, socketServer;
private slots:
void initTestCase_data()
{
QTest::addColumn<QUrl>("hostUrl");
QTest::addColumn<QUrl>("registryUrl");
QTest::newRow("tcp") << QUrl(QLatin1String("tcp://127.0.0.1:65511")) << QUrl(QLatin1String("tcp://127.0.0.1:65512"));
#ifdef __QNXNTO__
QTest::newRow("qnx") << QUrl(QLatin1String("qnx:replica")) << QUrl(QLatin1String("qnx:registry"));
#endif
QTest::newRow("local") << QUrl(QLatin1String("local:replicaLocalIntegration")) << QUrl(QLatin1String("local:registryLocalIntegration"));
QTest::newRow("external") << QUrl() << QUrl();
}
void initTestCase()
{
QLoggingCategory::setFilterRules("qt.remoteobjects.warning=false");
// use different paths in QRemoteObjectSettingsStore
QCoreApplication::setOrganizationName(QLatin1String("QtProject"));
QStandardPaths::setTestModeEnabled(true);
}
void init()
{
registry = nullptr;
host = nullptr;
client = nullptr;
tcpServer = nullptr;
socketClient = nullptr;
socketServer = nullptr;
}
void cleanup()
{
delete registry;
delete host;
delete client;
delete tcpServer;
if (socketClient) {
socketClient->deleteLater();
}
if (socketServer) {
socketServer->deleteLater();
}
// wait for delivery of RemoveObject events to the source
QTest::qWait(200);
}
void basicTest()
{
setupHost();
Engine e;
e.setRpm(1234);
host->enableRemoting(&e);
setupClient();
const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
engine_r->waitForSource();
QCOMPARE(engine_r->rpm(), e.rpm());
}
void persistRestoreTest()
{
QRemoteObjectNode _client;
Q_SET_OBJECT_NAME(_client);
TestPersistedStore store;
_client.setPersistedStore(&store);
const QScopedPointer<EngineReplica> engine_r(_client.acquire<EngineReplica>());
QCOMPARE(engine_r->engineType(), EngineReplica::HYBRID);
}
void persistTest()
{
QRemoteObjectSettingsStore store;
setupHost();
Engine e;
e.setEngineType(EngineSimpleSource::ELECTRIC);
host->enableRemoting(&e);
setupClient();
client->setPersistedStore(&store);
QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
engine_r->waitForSource();
QCOMPARE(engine_r->engineType(), EngineReplica::ELECTRIC);
// Delete to persist
engine_r.reset();
host->disableRemoting(&e);
engine_r.reset(client->acquire<EngineReplica>());
QCOMPARE(engine_r->waitForSource(1000), false);
QCOMPARE(engine_r->engineType(), EngineReplica::ELECTRIC);
}
// ensure we don't crash when ObjectList iterates over in process replicas
void inProcessObjectList()
{
setupRegistry();
setupHost(true);
setupClient(true);
Engine e;
host->enableRemoting(&e);
e.setStarted(false);
const QScopedPointer<EngineReplica> engine_r(host->acquire<EngineReplica>());
const QScopedPointer<EngineReplica> engine_r2(client->acquire<EngineReplica>());
engine_r->waitForSource(1000);
engine_r2->waitForSource(1000);
QCOMPARE(engine_r->started(), false);
QCOMPARE(engine_r2->started(), false);
engine_r->pushStarted(true);
QTRY_COMPARE(engine_r->started(), true);
QTRY_COMPARE(engine_r2->started(), true);
}
void enumTest()
{
setupHost();
setupClient();
TestClassSimpleSource tc;
tc.setTestEnum(TestEnum::FALSE);
tc.setClassEnum(TestClassSimpleSource::One);
tc.setClassEnumRW(TestClassSimpleSource::One);
host->enableRemoting(&tc);
const QScopedPointer<TestClassReplica> tc_rep(client->acquire<TestClassReplica>());
tc_rep->waitForSource();
QCOMPARE(tc.testEnum(), tc_rep->testEnum());
QCOMPARE((qint32)tc.classEnum(), (qint32)TestClassSimpleSource::One);
// set property on the replica (test property change packet)
{
QSignalSpy spy(tc_rep.data(), SIGNAL(classEnumChanged(TestClassReplica::ClassEnum)));
QVERIFY(spy.isValid());
tc_rep->pushClassEnum(TestClassReplica::Two);
QVERIFY(spy.count() || spy.wait());
QCOMPARE((qint32)tc.classEnum(), (qint32)tc_rep->classEnum());
}
// set property on the source (test property change packet)
{
QSignalSpy spy(tc_rep.data(), SIGNAL(classEnumChanged(TestClassReplica::ClassEnum)));
tc.setClassEnum(TestClassSimpleSource::One);
QVERIFY(spy.wait());
QCOMPARE((qint32)tc.classEnum(), (qint32)tc_rep->classEnum());
}
QScopedPointer<QRemoteObjectDynamicReplica> tc_repDynamic(client->acquireDynamic(QStringLiteral("TestClass")));
tc_repDynamic->waitForSource(1000);
QVERIFY(tc_repDynamic->isInitialized());
const QMetaObject *metaObject = tc_repDynamic->metaObject();
int propertyIndex = metaObject->indexOfProperty("classEnumRW");
QVERIFY(propertyIndex >= 0);
QMetaProperty property = metaObject->property(propertyIndex);
QVERIFY(property.isValid());
QCOMPARE(property.typeName(), "ClassEnum");
// read enum on the dynamic replica
{
QCOMPARE(property.read(tc_repDynamic.data()).value<TestClassReplica::ClassEnum>(), TestClassReplica::One);
}
// write enum on the dynamic replica
{
QSignalSpy spy(tc_rep.data(), SIGNAL(classEnumRWChanged(TestClassReplica::ClassEnum)));
property.write(tc_repDynamic.data(), TestClassReplica::Two);
QVERIFY(spy.wait());
QCOMPARE(tc_rep->classEnumRW(), TestClassReplica::Two);
}
propertyIndex = metaObject->indexOfProperty("classEnum");
QVERIFY(propertyIndex >= 0);
property = metaObject->property(propertyIndex);
QVERIFY(property.isValid());
QCOMPARE(property.typeName(), "ClassEnum");
// read enum on the dynamic replica
{
QCOMPARE(property.read(tc_repDynamic.data()).value<TestClassReplica::ClassEnum>(), TestClassReplica::One);
}
// ensure write enum fails on ReadPush
{
QSignalSpy spy(tc_rep.data(), SIGNAL(classEnumChanged(TestClassReplica::ClassEnum)));
bool res = property.write(tc_repDynamic.data(), TestClassReplica::Two);
QVERIFY(!res);
int methodIndex = metaObject->indexOfMethod("pushClassEnum(TestClassReplica::ClassEnum)");
QVERIFY(methodIndex >= 0);
QMetaMethod method = metaObject->method(methodIndex);
QVERIFY(method.isValid());
QVERIFY(method.invoke(tc_repDynamic.data(), Q_ARG(TestClassReplica::ClassEnum, TestClassReplica::Two)));
QVERIFY(spy.wait());
QCOMPARE(tc_rep->classEnum(), TestClassReplica::Two);
}
}
void namedObjectTest()
{
setupHost();
setupClient();
Engine e;
e.setRpm(3333);
Engine *e2 = new Engine();
QScopedPointer<Engine> engineSave;
engineSave.reset(e2);
e2->setRpm(4444);
host->enableRemoting(&e);
host->enableRemoting(e2, QStringLiteral("MyTestEngine"));
const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
const QScopedPointer<EngineReplica> namedEngine_r(client->acquire<EngineReplica>(QStringLiteral("MyTestEngine")));
engine_r->waitForSource();
QCOMPARE(engine_r->cylinders(), e.cylinders());
QCOMPARE(engine_r->rpm(), 3333);
namedEngine_r->waitForSource();
QCOMPARE(namedEngine_r->cylinders(), e2->cylinders());
QCOMPARE(namedEngine_r->rpm(), 4444);
engineSave.reset();
//Deleting the object before disable remoting will cause disable remoting to
//return false;
QVERIFY(!host->disableRemoting(e2));
}
void multipleInstancesTest()
{
setupHost();
Engine e;
host->enableRemoting(&e);
setupClient();
auto instances = client->instances<EngineReplica>();
QCOMPARE(instances, QStringList());
Engine e2;
host->enableRemoting(&e2, QStringLiteral("Engine2"));
const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
const QScopedPointer<EngineReplica> engine2_r(client->acquire<EngineReplica>(QStringLiteral("Engine2")));
const QScopedPointer<EngineReplica> engine3_r(client->acquire<EngineReplica>(QStringLiteral("Engine_doesnotexist")));
QVERIFY(engine_r->waitForSource());
QVERIFY(engine2_r->waitForSource());
QVERIFY(!engine3_r->waitForSource(500));
instances = client->instances<EngineReplica>();
QCOMPARE(instances, QStringList({"Engine", "Engine2"}));
QSignalSpy spy(engine_r.data(), SIGNAL(stateChanged(State,State)));
host->disableRemoting(&e);
spy.wait();
QCOMPARE(spy.count(), 1);
instances = client->instances<EngineReplica>();
QCOMPARE(instances, QStringList({"Engine2"}));
}
void registryAddedTest()
{
QFETCH_GLOBAL(QUrl, registryUrl);
if (registryUrl.isEmpty())
QSKIP("Skipping registry tests for external QIODevice types.");
setupRegistry();
setupHost(true);
setupClient(true);
QScopedPointer<EngineReplica> regBase, regNamed;
QScopedPointer<QRemoteObjectDynamicReplica> regDynamic, regDynamicNamed;
int regAdded = 0;
connect(client->registry(), &QRemoteObjectRegistry::remoteObjectAdded, [&](QRemoteObjectSourceLocation entry)
{
if (entry.first == QLatin1String("Engine")) {
++regAdded;
//Add regular replica first, then dynamic one
regBase.reset(client->acquire<EngineReplica>());
regDynamic.reset(client->acquireDynamic(QStringLiteral("Engine")));
}
if (entry.first == QLatin1String("MyTestEngine")) {
regAdded += 2;
//Now add dynamic replica first, then regular one
regDynamicNamed.reset(client->acquireDynamic(QStringLiteral("MyTestEngine")));
regNamed.reset(client->acquire<EngineReplica>(QStringLiteral("MyTestEngine")));
}
});
QSignalSpy addedSpy(client->registry(), SIGNAL(remoteObjectAdded(QRemoteObjectSourceLocation)));
Engine e;
e.setRpm(1111);
host->enableRemoting(&e);
Engine e2;
e2.setRpm(2222);
host->enableRemoting(&e2, QStringLiteral("MyTestEngine"));
while (regAdded < 3) {
addedSpy.wait(100);
}
regBase->waitForSource(100);
regNamed->waitForSource(100);
regDynamic->waitForSource(100);
regDynamicNamed->waitForSource(100);
QVERIFY(regBase->isInitialized());
QCOMPARE(regBase->rpm(),e.rpm());
QVERIFY(regNamed->isInitialized());
QCOMPARE(regNamed->rpm(),e2.rpm());
QVERIFY(regDynamic->isInitialized());
const QMetaObject *metaObject = regDynamic->metaObject();
const int propertyIndex = metaObject->indexOfProperty("rpm");
QVERIFY(propertyIndex >= 0);
const QMetaProperty property = metaObject->property(propertyIndex);
QVERIFY(property.isValid());
QCOMPARE(property.read(regDynamic.data()).toInt(),e.rpm());
QVERIFY(regDynamicNamed->isInitialized());
QCOMPARE(property.read(regDynamicNamed.data()).toInt(),e2.rpm());
QVERIFY(host->disableRemoting(&e));
QVERIFY(host->disableRemoting(&e2));
}
void registryTest()
{
QFETCH_GLOBAL(QUrl, registryUrl);
if (registryUrl.isEmpty())
QSKIP("Skipping registry tests for external QIODevice types.");
setupRegistry();
TcpDataCenterSimpleSource source1;
source1.setData1(5);
source1.setData2(5.0);
source1.setData3(QStringLiteral("tcp"));
source1.setData4(QVector<int>() << 1 << 2 << 3 << 4 << 5);
registry->enableRemoting(&source1);
setupHost(true);
LocalDataCenterSimpleSource source2;
source2.setData1(5);
source2.setData2(5.0);
source2.setData3(QStringLiteral("local"));
source2.setData4(QVector<int>() << 1 << 2 << 3 << 4 << 5);
host->enableRemoting(&source2);
QVERIFY(host->waitForRegistry(1000));
setupClient(true);
const QScopedPointer<TcpDataCenterReplica> tcpCentre(client->acquire<TcpDataCenterReplica>());
const QScopedPointer<LocalDataCenterReplica> localCentre(client->acquire<LocalDataCenterReplica>());
QTRY_VERIFY(localCentre->waitForSource(100));
QTRY_VERIFY(tcpCentre->waitForSource(100));
QCOMPARE(client->registry()->sourceLocations(), host->registry()->sourceLocations());
QCOMPARE(client->registry()->sourceLocations(), registry->registry()->sourceLocations());
QTRY_VERIFY(localCentre->isInitialized());
QTRY_VERIFY(tcpCentre->isInitialized());
QCOMPARE(tcpCentre->data1(), 5 );
QCOMPARE(tcpCentre->data2(), 5.0);
QCOMPARE(tcpCentre->data3(), QStringLiteral("tcp"));
QCOMPARE(tcpCentre->data4(), QVector<int>() << 1 << 2 << 3 << 4 << 5);
QCOMPARE(localCentre->data1(), 5);
QCOMPARE(localCentre->data2(), 5.0);
QCOMPARE(localCentre->data3(), QStringLiteral("local"));
QCOMPARE(localCentre->data4(), QVector<int>() << 1 << 2 << 3 << 4 << 5);
}
void invalidUrlsTest()
{
QFETCH_GLOBAL(QUrl, hostUrl);
QFETCH_GLOBAL(QUrl, registryUrl);
const QUrl invalidUrl;
{
QRemoteObjectHost _host(invalidUrl, registryUrl);
SET_NODE_NAME(_host);
const bool res = _host.waitForRegistry(3000);
QVERIFY(!res);
}
{
QRemoteObjectHost _host(hostUrl, invalidUrl);
SET_NODE_NAME(_host);
const bool res = _host.waitForRegistry(3000);
QVERIFY(!res);
}
{
QRemoteObjectHost _host(invalidUrl, invalidUrl);
SET_NODE_NAME(_host);
const bool res = _host.waitForRegistry(3000);
QVERIFY(!res);
}
}
void noRegistryTest()
{
QFETCH_GLOBAL(QUrl, registryUrl);
if (registryUrl.isEmpty())
QSKIP("Skipping registry tests for external QIODevice types."); setupHost(true);
const bool res = host->waitForRegistry(3000);
QVERIFY(!res);
QCOMPARE(host->registry()->isInitialized(), false);
const QScopedPointer<Engine> localEngine(new Engine);
host->enableRemoting(localEngine.data());
QCOMPARE(host->registry()->sourceLocations().keys().isEmpty(), true);
}
void delayedRegistryTest()
{
QFETCH_GLOBAL(QUrl, hostUrl);
QFETCH_GLOBAL(QUrl, registryUrl);
if (registryUrl.isEmpty())
QSKIP("Skipping registry tests for external QIODevice types.");
setupClient(true);
// create a replica before the registry host started
// to check whether it gets valid later on
const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
Q_SET_OBJECT_NAME(engine_r.data());
QTRY_VERIFY(!engine_r->waitForSource(100));
setupHost(true);
const bool res = host->waitForRegistry(3000);
QVERIFY(!res);
QCOMPARE(host->registry()->isInitialized(), false);
const QScopedPointer<Engine> localEngine(new Engine);
host->enableRemoting(localEngine.data());
QCOMPARE(host->registry()->sourceLocations().keys().isEmpty(), true);
QSignalSpy spy(host->registry(), SIGNAL(initialized()));
QSignalSpy addedSpy(host->registry(), SIGNAL(remoteObjectAdded(QRemoteObjectSourceLocation)));
setupRegistry();
bool added = addedSpy.wait();
QVERIFY(spy.count() > 0);
QCOMPARE(added, true);
QCOMPARE(host->registry()->sourceLocations().keys().isEmpty(), false);
QCOMPARE(host->registry()->sourceLocations().keys().at(0), QStringLiteral("Engine"));
QCOMPARE(host->registry()->sourceLocations().value(QStringLiteral("Engine")).hostUrl, hostUrl);
// the replicate should be valid now
QTRY_VERIFY(engine_r->isInitialized());
QTRY_VERIFY(engine_r->isReplicaValid());
//This should produce a warning...
registry->enableRemoting(localEngine.data());
QVERIFY(host->registry()->sourceLocations().value(QStringLiteral("Engine")).hostUrl != registryUrl);
}
void defaultValueTest()
{
setupHost();
Engine e;
host->enableRemoting(&e);
setupClient();
const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
engine_r->waitForSource();
QCOMPARE(engine_r->cylinders(), 4);
}
void notifyTest()
{
setupHost();
Engine e;
host->enableRemoting(&e);
setupClient();
const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
QSignalSpy spy(engine_r.data(), SIGNAL(rpmChanged(int)));
e.setRpm(2345);
spy.wait();
QCOMPARE(spy.count(), 1);
const QList<QVariant> &arguments = spy.first();
bool ok;
int res = arguments.at(0).toInt(&ok);
QVERIFY(ok);
QCOMPARE(res, e.rpm());
QCOMPARE(engine_r->rpm(), e.rpm());
}
void dynamicNotifyTest()
{
setupHost();
Engine e;
host->enableRemoting(&e);
setupClient();
QSignalSpy spy(this, SIGNAL(forwardResult(int)));
QScopedPointer<QRemoteObjectDynamicReplica> engine_dr(client->acquireDynamic(QStringLiteral("Engine")));
connect(engine_dr.data(), &QRemoteObjectDynamicReplica::initialized, [&]()
{
const QMetaObject *metaObject = engine_dr->metaObject();
const int propIndex = metaObject->indexOfProperty("rpm");
QVERIFY(propIndex >= 0);
const QMetaProperty mp = metaObject->property(propIndex);
QVERIFY(connect(engine_dr.data(), QByteArray(QByteArrayLiteral("2")+mp.notifySignal().methodSignature().constData()), this, SIGNAL(forwardResult(int))));
});
e.setRpm(3456);
spy.wait();
QCOMPARE(spy.count(), 1);
const QList<QVariant> &arguments = spy.first();
bool ok;
int res = arguments.at(0).toInt(&ok);
QVERIFY(ok);
QCOMPARE(res, e.rpm());
}
void slotTest()
{
setupHost();
Engine e;
host->enableRemoting(&e);
setupClient();
e.setStarted(false);
const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
QEventLoop loop;
QTimer::singleShot(100, &loop, &QEventLoop::quit);
connect(engine_r.data(), &EngineReplica::initialized, &loop, &QEventLoop::quit);
if (!engine_r->isInitialized())
loop.exec();
QCOMPARE(engine_r->started(), false);
QRemoteObjectPendingReply<bool> reply = engine_r->start();
QCOMPARE(reply.error(), QRemoteObjectPendingCall::InvalidMessage);
QVERIFY(reply.waitForFinished());
QVERIFY(reply.isFinished());
QCOMPARE(reply.returnValue(), true);
QCOMPARE(reply.error(), QRemoteObjectPendingCall::NoError);
QCOMPARE(engine_r->started(), true);
}
void slotTestWithWatcher()
{
setupHost();
Engine e;
host->enableRemoting(&e);
setupClient();
e.setStarted(false);
const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
QEventLoop loop;
QTimer::singleShot(100, &loop, &QEventLoop::quit);
connect(engine_r.data(), &EngineReplica::initialized, &loop, &QEventLoop::quit);
if (!engine_r->isInitialized())
loop.exec();
QCOMPARE(engine_r->started(), false);
QRemoteObjectPendingReply<bool> reply = engine_r->start();
QCOMPARE(reply.error(), QRemoteObjectPendingCall::InvalidMessage);
QRemoteObjectPendingCallWatcher watcher(reply);
QSignalSpy spy(&watcher, SIGNAL(finished(QRemoteObjectPendingCallWatcher *)));
spy.wait();
QCOMPARE(spy.count(), 1);
QVERIFY(reply.isFinished());
QCOMPARE(reply.returnValue(), true);
QCOMPARE(engine_r->started(), true);
}
void slotTestDynamicReplica()
{
setupHost();
Engine e;
host->enableRemoting(&e);
setupClient();
e.setStarted(false);
const QScopedPointer<QRemoteObjectDynamicReplica> engine_r(client->acquireDynamic(QStringLiteral("Engine")));
Q_ASSERT(engine_r);
QEventLoop loop;
QTimer::singleShot(100, &loop, &QEventLoop::quit);
connect(engine_r.data(), &EngineReplica::initialized, &loop, &QEventLoop::quit);
if (!engine_r->isInitialized())
loop.exec();
const QMetaObject *metaObject = engine_r->metaObject();
const int propIndex = metaObject->indexOfProperty("started");
QVERIFY(propIndex >= 0);
const QMetaProperty property = metaObject->property(propIndex);
bool started = property.read(engine_r.data()).value<bool>();
QCOMPARE(started, false);
const int methodIndex = metaObject->indexOfMethod("start()");
QVERIFY(methodIndex >= 0);
const QMetaMethod method = metaObject->method(methodIndex);
QRemoteObjectPendingCall call;
QVERIFY(method.invoke(engine_r.data(), Q_RETURN_ARG(QRemoteObjectPendingCall, call)));
QCOMPARE(call.error(), QRemoteObjectPendingCall::InvalidMessage);
QVERIFY(call.waitForFinished());
QVERIFY(call.isFinished());
QCOMPARE(call.returnValue().type(), QVariant::Bool);
QCOMPARE(call.returnValue().toBool(), true);
started = property.read(engine_r.data()).value<bool>();
QCOMPARE(started, true);
}
void slotTestDynamicReplicaWithArguments()
{
setupHost();
Engine e;
host->enableRemoting(&e);
setupClient();
const QScopedPointer<QRemoteObjectDynamicReplica> engine_r(client->acquireDynamic(QStringLiteral("Engine")));
Q_ASSERT(engine_r);
bool ok = engine_r->waitForSource();
QVERIFY(ok);
const QMetaObject *metaObject = engine_r->metaObject();
int methodIndex = metaObject->indexOfMethod("setMyTestString(QString)");
QVERIFY(methodIndex >= 0);
QMetaMethod method = metaObject->method(methodIndex);
QVERIFY(method.isValid());
// The slot has no return-value, calling it with a Q_RETURN_ARG should fail.
QRemoteObjectPendingCall setCall;
QString s = QLatin1String("Hello World 1");
QVERIFY(!method.invoke(engine_r.data(), Q_RETURN_ARG(QRemoteObjectPendingCall, setCall), Q_ARG(QString, s)));
QVERIFY(!setCall.waitForFinished());
QVERIFY(!setCall.isFinished());
QCOMPARE(setCall.error(), QRemoteObjectPendingCall::InvalidMessage);
// Now call the method without return-value, that should succeed.
s = QLatin1String("Hello World 2");
QVERIFY(method.invoke(engine_r.data(), Q_ARG(QString, s)));
// Verify that the passed argument was proper set.
methodIndex = metaObject->indexOfMethod("myTestString()");
QVERIFY(methodIndex >= 0);
method = metaObject->method(methodIndex);
QRemoteObjectPendingCall getCall;
QVERIFY(method.invoke(engine_r.data(), Q_RETURN_ARG(QRemoteObjectPendingCall, getCall)));
QVERIFY(getCall.waitForFinished());
QVERIFY(getCall.isFinished());
QCOMPARE(getCall.error(), QRemoteObjectPendingCall::NoError);
QCOMPARE(getCall.returnValue().type(), QVariant::String);
QCOMPARE(getCall.returnValue().toString(), s);
}
void expapiTestDynamicReplica()
{
setupHost();
Engine e;
host->enableRemoting(&e);
setupClient();
const QScopedPointer<QRemoteObjectDynamicReplica> engine_r(client->acquireDynamic(QStringLiteral("Engine")));
const QMetaObject *metaObject = engine_r->metaObject();
const int propIndex = metaObject->indexOfProperty("purchasedPart");
QVERIFY(propIndex < 0);
const int methodIndex = metaObject->indexOfMethod("setpurchasedPart(bool)");
QVERIFY(methodIndex < 0);
}
void slotTestInProcess()
{
setupHost();
Engine e;
host->enableRemoting(&e);
e.setStarted(false);
const QScopedPointer<EngineReplica> engine_r(host->acquire<EngineReplica>());
engine_r->waitForSource();
QCOMPARE(engine_r->started(), false);
QRemoteObjectPendingReply<bool> reply = engine_r->start();
QVERIFY(reply.waitForFinished());
QVERIFY(reply.isFinished());
QCOMPARE(reply.returnValue(), true);
QCOMPARE(reply.error(), QRemoteObjectPendingCall::NoError);
QCOMPARE(engine_r->started(), true);
}
void slotTestWithUnnormalizedSignature()
{
setupHost();
Engine e;
host->enableRemoting(&e);
setupClient();
const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
engine_r->waitForSource();
engine_r->unnormalizedSignature(0, 0);
}
void setterTest()
{
setupHost();
Engine e(6);
QCOMPARE(e.cylinders(), 6);
host->enableRemoting(&e);
setupClient();
const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
QCOMPARE(engine_r->cylinders(), 4); // Default value
engine_r->waitForSource();
QCOMPARE(engine_r->cylinders(), 6);
QSignalSpy spy(engine_r.data(), SIGNAL(rpmChanged(int)));
engine_r->setRpm(42);
spy.wait();
QCOMPARE(spy.count(), 1);
QCOMPARE(engine_r->rpm(), 42);
}
void pushTest()
{
setupHost();
Engine e;
host->enableRemoting(&e);
setupClient();
const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
engine_r->waitForSource();
QCOMPARE(engine_r->started(), false);
QSignalSpy spy(engine_r.data(), SIGNAL(startedChanged(bool)));
engine_r->pushStarted(true);
spy.wait();
QCOMPARE(spy.count(), 1);
QCOMPARE(engine_r->started(), true);
}
void dynamicSetterTest()
{
setupHost();
Engine e(6);
QCOMPARE(e.cylinders(), 6);
host->enableRemoting(&e);
setupClient();
const QScopedPointer<QRemoteObjectDynamicReplica> engine_dr(client->acquireDynamic(QStringLiteral("Engine")));
engine_dr->waitForSource();
const QMetaObject *metaObject = engine_dr->metaObject();
const QMetaProperty const_mp = metaObject->property(metaObject->indexOfProperty("cylinders"));
QCOMPARE(const_mp.read(engine_dr.data()).toInt(), 6);
const int propIndex = metaObject->indexOfProperty("rpm");
const QMetaProperty mp = metaObject->property(propIndex);
QSignalSpy spy(engine_dr.data(), QByteArray(QByteArrayLiteral("2")+mp.notifySignal().methodSignature().constData()));
mp.write(engine_dr.data(), 44);
spy.wait();
QCOMPARE(spy.count(), 1);
QCOMPARE(mp.read(engine_dr.data()).toInt(), 44);
}
void slotWithParameterTest()
{
setupHost();
Engine e;
host->enableRemoting(&e);
e.setRpm(0);
setupClient();
const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
engine_r->waitForSource();
QCOMPARE(engine_r->rpm(), 0);
QSignalSpy spy(engine_r.data(), SIGNAL(rpmChanged(int)));
engine_r->increaseRpm(1000);
spy.wait();
QCOMPARE(spy.count(), 1);
QCOMPARE(engine_r->rpm(), 1000);
}
void slotWithUserReturnTypeTest() {
setupHost();
Engine e;
host->enableRemoting(&e);
setupClient();
e.setTemperature(Temperature(400, QStringLiteral("Kelvin")));
const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
engine_r->waitForSource();
QRemoteObjectPendingReply<Temperature> pendingReply = engine_r->temperature();
pendingReply.waitForFinished();
Temperature temperature = pendingReply.returnValue();
QCOMPARE(temperature, Temperature(400, QStringLiteral("Kelvin")));
}
void sequentialReplicaTest()
{
setupHost();
Engine e;
host->enableRemoting(&e);
setupClient();
e.setRpm(3456);
QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
engine_r->waitForSource();
QCOMPARE(engine_r->rpm(), e.rpm());
engine_r.reset(client->acquire<EngineReplica>());
engine_r->waitForSource();
QCOMPARE(engine_r->rpm(), e.rpm());
}
void doubleReplicaTest()
{
setupHost();
Engine e;
host->enableRemoting(&e);
e.setRpm(3412);
setupClient();
const QScopedPointer<EngineReplica> engine_r1(client->acquire< EngineReplica >());
const QScopedPointer<EngineReplica> engine_r2(client->acquire< EngineReplica >());
engine_r1->waitForSource();
engine_r2->waitForSource();
QCOMPARE(engine_r1->rpm(), e.rpm());
QCOMPARE(engine_r2->rpm(), e.rpm());
}
// verify that our second replica emits "Changed" signals when initialized
void doubleReplicaTest2()
{
setupHost();
Engine e;
host->enableRemoting(&e);
e.setRpm(3412);
setupClient();
const QScopedPointer<EngineReplica> engine_r1(client->acquire< EngineReplica >());
QSignalSpy spy_r1(engine_r1.data(), SIGNAL(rpmChanged(int)));
engine_r1->waitForSource();
QCOMPARE(engine_r1->rpm(), e.rpm());
QCOMPARE(spy_r1.count(), 1);
// NOTE: A second replica will have initialized and notify signals emitted as part of acquire,
// which leads to different semantics for first and second replicas. Specifically, there is no
// way to hook in to initialized and the initial notify signals. We should consider changing this.
const QScopedPointer<EngineReplica> engine_r2(client->acquire< EngineReplica >());
// QSignalSpy spy_r2(engine_r2.data(), SIGNAL(rpmChanged(int)));
// engine_r2->waitForSource();
QCOMPARE(engine_r2->rpm(), e.rpm());
// QCOMPARE(spy_r2.count(), 1);
}
void twoReplicaTest() {
setupHost();
Engine e;
Speedometer s;
host->enableRemoting(&e);
host->enableRemoting(&s);
setupClient();
e.setRpm(1234);
s.setMph(70);
const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
engine_r->waitForSource();
const QScopedPointer<SpeedometerReplica> speedometer_r(client->acquire<SpeedometerReplica>());
speedometer_r->waitForSource();
QCOMPARE(engine_r->rpm(), e.rpm());
QCOMPARE(speedometer_r->mph(), s.mph());
}
void rawDynamicReplicaTest()
{
setupHost();
TestDynamic source;
host->enableRemoting(&source, "TestDynamic");
setupClient();
const QScopedPointer<QRemoteObjectDynamicReplica> replica(client->acquireDynamic(QStringLiteral("TestDynamic")));
replica->waitForSource();
QVERIFY(replica->isInitialized());
QSignalSpy spy(replica.data(), SIGNAL(valueChanged()));
const QMetaObject *metaObject = replica->metaObject();
const int propIndex = metaObject->indexOfProperty("value");
QVERIFY(propIndex != -1);
const int signalIndex = metaObject->indexOfSignal("valueChanged()");
QVERIFY(signalIndex != -1);
// replica gets source change
source.setValue(1);
QTRY_COMPARE(spy.count(), 1);
QCOMPARE(replica->property("value"), QVariant(1));
// source gets replica change
replica->setProperty("value", 2);
QTRY_COMPARE(replica->property("value"), QVariant(2));
QCOMPARE(source.value(), 2);
// test parent NOTIFY
QSignalSpy otherSpy(replica.data(), SIGNAL(otherValueChanged()));
const int baseSignalIndex = metaObject->indexOfSignal("otherValueChanged()");
QVERIFY(baseSignalIndex != -1);
// replica gets source change
source.setOtherValue(1);
QTRY_COMPARE(otherSpy.count(), 1);
QCOMPARE(replica->property("otherValue"), QVariant(1));
// source gets replica change
replica->setProperty("otherValue", 2);
QTRY_COMPARE(replica->property("otherValue"), QVariant(2));
QCOMPARE(source.otherValue(), 2);
}
void dynamicReplicaTest()
{
setupHost();
TcpDataCenterSimpleSource t;
LocalDataCenterSimpleSource l;
host->enableRemoting(&t);
host->enableRemoting(&l);
setupClient();
const QScopedPointer<QRemoteObjectDynamicReplica> rep1(client->acquireDynamic(QStringLiteral("TcpDataCenter")));
const QScopedPointer<QRemoteObjectDynamicReplica> rep2(client->acquireDynamic(QStringLiteral("TcpDataCenter")));
const QScopedPointer<QRemoteObjectDynamicReplica> rep3(client->acquireDynamic(QStringLiteral("LocalDataCenter")));
rep1->waitForSource();
rep2->waitForSource();
rep3->waitForSource();
const QMetaObject *metaTcpRep1 = rep1->metaObject();
const QMetaObject *metaLocalRep1 = rep3->metaObject();
const QMetaObject *metaTcpSource = t.metaObject();
const QMetaObject *metaLocalSource = l.metaObject();
QVERIFY(rep1->isInitialized());
QVERIFY(rep2->isInitialized());
QVERIFY(rep3->isInitialized());
for (int i = 0; i < metaTcpRep1->propertyCount(); ++i)
{
const QMetaProperty propLhs = metaTcpRep1->property(i);
if (qstrcmp(propLhs.name(), "isReplicaValid") == 0 || qstrcmp(propLhs.name(), "state") == 0 || qstrcmp(propLhs.name(), "node") == 0) //Ignore properties only on the Replica side
continue;
const QMetaProperty propRhs = metaTcpSource->property(metaTcpSource->indexOfProperty(propLhs.name()));
if (propLhs.notifySignalIndex() == -1)
QCOMPARE(propRhs.hasNotifySignal(), false);
else {
QCOMPARE(propRhs.notifySignalIndex() != -1, true);
QCOMPARE(metaTcpRep1->method(propLhs.notifySignalIndex()).name(), metaTcpSource->method(propRhs.notifySignalIndex()).name());
}
QCOMPARE(propLhs.read(rep1.data()), propRhs.read(&t));
}
for (int i = 0; i < metaLocalRep1->propertyCount(); ++i )
{
const QMetaProperty propLhs = metaLocalRep1->property(i);
if (qstrcmp(propLhs.name(), "isReplicaValid") == 0 || qstrcmp(propLhs.name(), "state") == 0 || qstrcmp(propLhs.name(), "node") == 0) //Ignore properties only on the Replica side
continue;
const QMetaProperty propRhs = metaLocalSource->property(metaTcpSource->indexOfProperty(propLhs.name()));
if (propLhs.notifySignalIndex() == -1)
QCOMPARE(propRhs.hasNotifySignal(), false);
else {
QCOMPARE(propRhs.notifySignalIndex() != -1, true);
QCOMPARE(metaTcpRep1->method(propLhs.notifySignalIndex()).name(), metaTcpSource->method(propRhs.notifySignalIndex()).name());
}
QCOMPARE(propLhs.read(rep3.data()), propRhs.read(&l));
}
}
void apiTest()
{
setupHost();
Engine e;
host->enableRemoting<EngineSourceAPI>(&e);
e.setRpm(1234);
setupClient();
const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
engine_r->waitForSource();
QCOMPARE(engine_r->rpm(), e.rpm());
}
void apiInProcTest()
{
setupHost();
Engine e;
host->enableRemoting<EngineSourceAPI>(&e);
e.setRpm(1234);
const QScopedPointer<EngineReplica> engine_r_inProc(host->acquire<EngineReplica>());
engine_r_inProc->waitForSource();
QCOMPARE(engine_r_inProc->rpm(), e.rpm());
}
void errorSignalTest()
{
QRemoteObjectNode _client;
Q_SET_OBJECT_NAME(_client);
QSignalSpy errorSpy(&_client, SIGNAL(error(QRemoteObjectNode::ErrorCode)));
QVERIFY(!_client.connectToNode(QUrl(QLatin1String("invalid:invalid"))));
QCOMPARE(errorSpy.count(), 1);
auto emittedErrorCode = errorSpy.first().at(0).value<QRemoteObjectNode::ErrorCode>();
QCOMPARE(emittedErrorCode, QRemoteObjectNode::RegistryNotAcquired);
QCOMPARE(_client.lastError(), QRemoteObjectNode::RegistryNotAcquired);
}
void clientBeforeServerTest() {
setupClient();
const QScopedPointer<EngineReplica> engine_d(client->acquire<EngineReplica>());
setupHost();
Engine e;
host->enableRemoting<EngineSourceAPI>(&e);
QSignalSpy spy(engine_d.data(), SIGNAL(rpmChanged(int)));
e.setRpm(50);
spy.wait();
QCOMPARE(spy.count(), 1);
QCOMPARE(engine_d->rpm(), e.rpm());
}
void largeDataTest()
{
TestLargeData t;
setupHost();
host->enableRemoting(&t, QStringLiteral("large"));
setupClient();
const QScopedPointer<QRemoteObjectDynamicReplica> rep(client->acquireDynamic(QStringLiteral("large")));
rep->waitForSource();
QVERIFY(rep->isInitialized());
const QMetaObject *metaObject = rep->metaObject();
const int sigIndex = metaObject->indexOfSignal("send(QByteArray)");
QVERIFY(sigIndex != -1);
const QMetaMethod mm = metaObject->method(sigIndex);
QSignalSpy spy(rep.data(), QByteArray(QByteArrayLiteral("2")+mm.methodSignature().constData()));
const QByteArray data(16384,'y');
emit t.send(data);
spy.wait();
QCOMPARE(spy.count(), 1);
const QList<QVariant> &arguments = spy.first();
QVERIFY(arguments.at(0).toByteArray() == data);
QVERIFY(host->disableRemoting(&t));
}
void PODTest()
{
setupHost();
setupClient();
MyPOD shouldPass(1, 2.0, QStringLiteral("pass"));
MyPOD shouldFail(1, 2.0, QStringLiteral("fail"));
MyClassSimpleSource m;
m.setMyPOD(shouldPass);
host->enableRemoting(&m);
const QScopedPointer<MyClassReplica> myclass_r(client->acquire<MyClassReplica>());
myclass_r->waitForSource();
QVERIFY(myclass_r->myPOD() == m.myPOD());
QVERIFY(myclass_r->myPOD() != shouldFail);
}
void SchemeTest()
{
QFETCH_GLOBAL(QUrl, hostUrl);
QFETCH_GLOBAL(QUrl, registryUrl);
QRemoteObjectHost valid(hostUrl);
QVERIFY(valid.lastError() == QRemoteObjectNode::NoError);
QRemoteObjectHost invalid(QUrl(QLatin1String("invalid:invalid")));
QVERIFY(invalid.lastError() == QRemoteObjectNode::HostUrlInvalid);
QRemoteObjectHost validExternal(QUrl(QLatin1String("invalid:invalid")), registryUrl, QRemoteObjectHost::AllowExternalRegistration);
QVERIFY(validExternal.lastError() == QRemoteObjectNode::NoError);
QRemoteObjectNode invalidRegistry(QUrl(QLatin1String("invalid:invalid")));
QVERIFY(invalidRegistry.lastError() == QRemoteObjectNode::RegistryNotAcquired);
}
#if defined(Q_OS_LINUX) || defined(Q_OS_DARWIN)
void localServerConnectionTest()
{
QFETCH_GLOBAL(QUrl, hostUrl);
if (hostUrl.scheme() != QRemoteObjectStringLiterals::local())
QSKIP("Skipping 'local' specific backend for non-local test.");
const auto progName = TestUtils::findExecutable("localsockettestserver", {
QCoreApplication::applicationDirPath() + "/../localsockettestserver"
});
//create a fake socket as killing doesn't produce a necessarily unusable socket
QFile fake(QDir::temp().absoluteFilePath(QStringLiteral("crashMe")));
fake.remove();
QVERIFY(fake.open(QFile::Truncate | QFile::WriteOnly));
QFileInfo info(QDir::temp().absoluteFilePath(QStringLiteral("crashMe")));
QVERIFY(info.exists());
QRemoteObjectNode localSocketTestClient;
const QUrl connection = QUrl(QStringLiteral("local:crashMe"));
const QString objectname = QStringLiteral("connectme");
localSocketTestClient.connectToNode(connection);
QVERIFY(localSocketTestClient.lastError() == QRemoteObjectNode::NoError);
QScopedPointer<QRemoteObjectDynamicReplica> replica;
replica.reset(localSocketTestClient.acquireDynamic(objectname));
QProcess testServer;
testServer.start(progName, QStringList());
QVERIFY(testServer.waitForStarted());
QVERIFY(localSocketTestClient.lastError() == QRemoteObjectNode::NoError);
replica->waitForSource(1000);
QVERIFY(replica->isInitialized());
testServer.terminate();
QVERIFY(testServer.waitForFinished());
}
// Tests to take over an existing socket if its still valid
void localServerConnectionTest2()
{
QFETCH_GLOBAL(QUrl, hostUrl);
if (hostUrl.scheme() != QRemoteObjectStringLiterals::local())
QSKIP("Skipping 'local' specific backend for non-local test.");
const auto progName = TestUtils::findExecutable("localsockettestserver", {
QCoreApplication::applicationDirPath() + "/../localsockettestserver"
});
QProcess testServer;
testServer.start(progName, QStringList());
QVERIFY(testServer.waitForStarted());
QFileInfo info(QDir::temp().absoluteFilePath(QStringLiteral("crashMe")));
QVERIFY(info.exists());
testServer.kill();
testServer.waitForFinished();
QVERIFY(info.exists());
QRemoteObjectNode localSocketTestClient;
const QUrl connection = QUrl(QStringLiteral("local:crashMe"));
const QString objectname = QStringLiteral("connectme");
localSocketTestClient.connectToNode(connection);
QVERIFY(localSocketTestClient.lastError() == QRemoteObjectNode::NoError);
QScopedPointer<QRemoteObjectDynamicReplica> replica;
replica.reset(localSocketTestClient.acquireDynamic(objectname));
testServer.start(progName, QStringList());
QVERIFY(testServer.waitForStarted());
QVERIFY(localSocketTestClient.lastError() == QRemoteObjectNode::NoError);
replica->waitForSource(1000);
QVERIFY(replica->isInitialized());
testServer.terminate();
QVERIFY(testServer.waitForFinished());
}
#endif
void tcpListenFailedTest()
{
QFETCH_GLOBAL(QUrl, registryUrl);
if (registryUrl.scheme() != QRemoteObjectStringLiterals::tcp())
QSKIP("Skipping test for local and external backends.");
// Need the Host or Registry running so that the port is in use.
setupRegistry();
QRemoteObjectHost badHost;
badHost.setHostUrl(registryUrl);
QCOMPARE(badHost.lastError(), QRemoteObjectNode::ListenFailed);
}
void invalidExternalTest()
{
QFETCH_GLOBAL(QUrl, hostUrl);
if (hostUrl.scheme() != QRemoteObjectStringLiterals::tcp())
QSKIP("Skipping test for tcp and external backends.");
QRemoteObjectHost srcNode;
QTest::ignoreMessage(QtWarningMsg, " Overriding a valid QtRO url ( QUrl(\"tcp://127.0.0.1:65511\") ) with AllowExternalRegistration is not allowed.");
srcNode.setHostUrl(hostUrl, QRemoteObjectHost::AllowExternalRegistration);
QCOMPARE(srcNode.lastError(), QRemoteObjectNode::HostUrlInvalid);
Engine e;
bool res = srcNode.enableRemoting(&e);
QVERIFY(res == false);
}
};
QTEST_MAIN(tst_Integration)
#include "tst_integration.moc"