Fix parenting mechanism for discovered devices

This commit is contained in:
Michael Zanetti 2019-07-15 17:00:36 +02:00
parent 09fb3ef4c5
commit c6a0cecb0f
6 changed files with 105 additions and 5 deletions

View File

@ -361,7 +361,7 @@ Device::DeviceError DeviceManagerImplementation::addConfiguredDevice(const Devic
}
}
return addConfiguredDeviceInternal(deviceClassId, name, finalParams, deviceId);
return addConfiguredDeviceInternal(deviceClassId, name, finalParams, deviceId, descriptor.parentDeviceId());
}
@ -619,7 +619,7 @@ Device::DeviceError DeviceManagerImplementation::confirmPairing(const PairingTra
/*! This method will only be used from the DeviceManagerImplementation in order to add a \l{Device} with the given \a deviceClassId, \a name, \a params and \ id.
* Returns \l{DeviceError} to inform about the result. */
Device::DeviceError DeviceManagerImplementation::addConfiguredDeviceInternal(const DeviceClassId &deviceClassId, const QString &name, const ParamList &params, const DeviceId id)
Device::DeviceError DeviceManagerImplementation::addConfiguredDeviceInternal(const DeviceClassId &deviceClassId, const QString &name, const ParamList &params, const DeviceId id, const DeviceId &parentDeviceId)
{
DeviceClass deviceClass = findDeviceClass(deviceClassId);
if (deviceClass.id().isNull()) {
@ -648,6 +648,7 @@ Device::DeviceError DeviceManagerImplementation::addConfiguredDeviceInternal(con
}
Device *device = new Device(plugin, deviceClass, id, this);
device->setParentId(parentDeviceId);
if (name.isEmpty()) {
device->setName(deviceClass.name());
} else {

View File

@ -125,7 +125,7 @@ private slots:
void slotDeviceSettingChanged(const ParamTypeId &paramTypeId, const QVariant &value);
private:
Device::DeviceError addConfiguredDeviceInternal(const DeviceClassId &deviceClassId, const QString &name, const ParamList &params, const DeviceId id = DeviceId::createDeviceId());
Device::DeviceError addConfiguredDeviceInternal(const DeviceClassId &deviceClassId, const QString &name, const ParamList &params, const DeviceId id = DeviceId::createDeviceId(), const DeviceId &parentDeviceId = DeviceId());
Device::DeviceSetupStatus setupDevice(Device *device);
void postSetupDevice(Device *device);
void storeDeviceStates(Device *device);

View File

@ -75,7 +75,28 @@ Device::DeviceError DevicePluginMock::discoverDevices(const DeviceClassId &devic
m_discoveredDeviceCount = params.paramValue(mockDisplayPinDiscoveryResultCountParamTypeId).toInt();
QTimer::singleShot(1000, this, SLOT(emitDisplayPinDevicesDiscovered()));
return Device::DeviceErrorAsync;
} else if (deviceClassId == mockParentDeviceClassId) {
qCDebug(dcMockDevice()) << "Starting discovery for mock device parent";
QTimer::singleShot(1000, this, [this](){
DeviceDescriptor descriptor(mockParentDeviceClassId, "Mock Parent (Discovered)");
emit devicesDiscovered(mockParentDeviceClassId, {descriptor});
});
return Device::DeviceErrorAsync;
} else if (deviceClassId == mockChildDeviceClassId) {
QTimer::singleShot(1000, this, [this](){
QList<DeviceDescriptor> descriptors;
if (!myDevices().filterByDeviceClassId(mockParentDeviceClassId).isEmpty()) {
Device *parent = myDevices().filterByDeviceClassId(mockParentDeviceClassId).first();
DeviceDescriptor descriptor(mockChildDeviceClassId, "Mock Child (Discovered)", QString(), parent->id());
descriptors.append(descriptor);
}
emit devicesDiscovered(mockChildDeviceClassId, descriptors);
});
return Device::DeviceErrorAsync;
}
qCWarning(dcMockDevice()) << "Cannot discover for deviceClassId" << deviceClassId;
return Device::DeviceErrorDeviceClassNotFound;
}

View File

@ -501,7 +501,7 @@
"name": "mockParent",
"displayName": "Mock Device (Parent)",
"interfaces": ["system"],
"createMethods": ["user"],
"createMethods": ["user", "discovery"],
"paramTypes": [ ],
"stateTypes": [
{
@ -520,7 +520,7 @@
"id": "40893c9f-bc47-40c1-8bf7-b390c7c1b4fc",
"name": "mockChild",
"displayName": "Mock Device (Child)",
"createMethods": ["auto"],
"createMethods": ["auto", "discovery"],
"paramTypes": [],
"stateTypes": [
{

View File

@ -4,6 +4,8 @@ QT+= network
TARGET = $$qtLibraryTarget(nymea_devicepluginmock)
OTHER_FILES += devicepluginmock.json
SOURCES += \
devicepluginmock.cpp \
httpdaemon.cpp

View File

@ -29,6 +29,9 @@ class TestDevices : public NymeaTestBase
{
Q_OBJECT
protected slots:
void initTestCase();
private slots:
void getPlugins();
@ -99,8 +102,20 @@ private slots:
void removeDevice();
void removeAutoDevice();
void discoverDeviceParenting();
};
void TestDevices::initTestCase()
{
NymeaTestBase::initTestCase();
QLoggingCategory::setFilterRules("*.debug=false\n"
"Tests.debug=true\n"
"MockDevice.debug=true\n"
);
}
void TestDevices::getPlugins()
{
QVariant response = injectAndWait("Devices.GetPlugins");
@ -1466,6 +1481,67 @@ void TestDevices::removeAutoDevice()
QVERIFY2(NymeaCore::instance()->deviceManager()->findConfiguredDevices(mockDeviceAutoDeviceClassId).count() == 0, "Mock device has not disappeared even though it should have.");
}
void TestDevices::discoverDeviceParenting()
{
// Try to discover a mock child device. We don't have a mockParent yet, so it should fail
QSignalSpy spy(NymeaCore::instance()->deviceManager(), &DeviceManager::devicesDiscovered);
Device::DeviceError status = NymeaCore::instance()->deviceManager()->discoverDevices(mockChildDeviceClassId, ParamList());
QCOMPARE(status, Device::DeviceErrorAsync);
spy.wait();
QCOMPARE(spy.first().at(0).value<DeviceClassId>().toString(), mockChildDeviceClassId.toString());
QList<DeviceDescriptor> descriptors = spy.first().at(1).value<QList<DeviceDescriptor> >();
QVERIFY(descriptors.count() == 0);
// Now create a mock parent by discovering...
spy.clear();
status = NymeaCore::instance()->deviceManager()->discoverDevices(mockParentDeviceClassId, ParamList());
QCOMPARE(status, Device::DeviceErrorAsync);
spy.wait();
QVERIFY(spy.count() == 1);
QCOMPARE(spy.first().at(0).value<DeviceClassId>().toString(), mockParentDeviceClassId.toString());
descriptors = spy.first().at(1).value<QList<DeviceDescriptor> >();
QVERIFY(descriptors.count() == 1);
DeviceDescriptorId descriptorId = descriptors.first().id();
QSignalSpy addSpy(NymeaCore::instance()->deviceManager(), &DeviceManager::deviceAdded);
status = NymeaCore::instance()->deviceManager()->addConfiguredDevice(mockParentDeviceClassId, "Mock Parent (Discovered)", descriptorId);
QCOMPARE(status, Device::DeviceErrorNoError);
QCOMPARE(addSpy.count(), 2); // Mock device parent will also auto-create a child instantly
Device *parentDevice = addSpy.at(1).first().value<Device*>();
qCDebug(dcTests()) << "Added device:" << parentDevice->name();
QVERIFY(parentDevice->deviceClassId() == mockParentDeviceClassId);
// Ok we have our parent device, let's discover for childs again
spy.clear();
status = NymeaCore::instance()->deviceManager()->discoverDevices(mockChildDeviceClassId, ParamList());
QCOMPARE(status, Device::DeviceErrorAsync);
spy.wait();
QCOMPARE(spy.first().at(0).value<DeviceClassId>().toString(), mockChildDeviceClassId.toString());
descriptors = spy.first().at(1).value<QList<DeviceDescriptor> >();
QVERIFY(descriptors.count() == 1);
descriptorId = descriptors.first().id();
// Found one! Adding it...
addSpy.clear();
status = NymeaCore::instance()->deviceManager()->addConfiguredDevice(mockChildDeviceClassId, "Mock Child (Discovered)", descriptorId);
QCOMPARE(status, Device::DeviceErrorNoError);
QCOMPARE(addSpy.count(), 1);
Device *childDevice = addSpy.at(0).first().value<Device*>();
qCDebug(dcTests()) << "Added device:" << childDevice->name();
QVERIFY(childDevice->deviceClassId() == mockChildDeviceClassId);
// Now delete the parent and make sure the child will be deleted too
QSignalSpy removeSpy(NymeaCore::instance(), &NymeaCore::deviceRemoved);
QPair<Device::DeviceError, QList<RuleId> > ret = NymeaCore::instance()->removeConfiguredDevice(parentDevice->id(), QHash<RuleId, RuleEngine::RemovePolicy>());
QCOMPARE(ret.first, Device::DeviceErrorNoError);
QCOMPARE(removeSpy.count(), 3); // The parent, the auto-mock and the discovered mock
}
#include "testdevices.moc"
QTEST_MAIN(TestDevices)