reenable strict argument checking, now that we can mark parameters as optional

pull/1/head
Michael Zanetti 2014-04-06 01:32:46 +02:00
parent 913d544386
commit c027bb1481
7 changed files with 75 additions and 21 deletions

View File

@ -31,6 +31,8 @@
The JSONRPC API is self documenting and can be introspected by calling \c"JSONRPC.Introspect".
Parameters are optional if the type is the type is prefixed with "o:" for optional.
\section1 Communicating with the server
The server listens on TCP port 1234 for incoming TCP connections. It will respond to incoming
connections with a some information about the server. Telnet can be used to issue commands for

View File

@ -121,10 +121,20 @@ QList<Vendor> DeviceManager::supportedVendors() const
return m_supportedVendors.values();
}
/*! Returns all the supported \l{DeviceClass}{DeviceClasses} by all \l{DevicePlugin}{DevicePlugins} loaded in the system. */
/*! Returns all the supported \l{DeviceClass}{DeviceClasses} by all \l{DevicePlugin}{DevicePlugins} loaded in the system.
Optionally filtered by vendorId. */
QList<DeviceClass> DeviceManager::supportedDevices(const VendorId &vendorId) const
{
return m_supportedDevices.values();
qDebug() << "returning devices" << vendorId;
QList<DeviceClass> ret;
if (vendorId.isNull()) {
ret = m_supportedDevices.values();
} else {
foreach (const DeviceClassId &deviceClassId, m_vendorDeviceMap.value(vendorId)) {
ret.append(m_supportedDevices.value(deviceClassId));
}
}
return ret;
}
/*! Add a new configured device for the given \l{DeviceClass} and the given parameters.

View File

@ -1,6 +1,7 @@
#ifndef TYPEUTILS_H
#define TYPEUTILS_H
#include <QMetaType>
#include <QUuid>
#define DECLARE_TYPE_ID(type) class type##Id: public QUuid \
@ -10,12 +11,13 @@ public: \
type##Id(): QUuid() {} \
static type##Id create##type##Id() { return type##Id(QUuid::createUuid().toString()); } \
static type##Id fromUuid(const QUuid &uuid) { return type##Id(uuid.toString()); } \
};
}; \
Q_DECLARE_METATYPE(type##Id);
DECLARE_TYPE_ID(Device)
DECLARE_TYPE_ID(DeviceClass)
DECLARE_TYPE_ID(Vendor)
DECLARE_TYPE_ID(DeviceClass)
DECLARE_TYPE_ID(Device)
DECLARE_TYPE_ID(EventType)
DECLARE_TYPE_ID(StateType)

View File

@ -40,7 +40,8 @@ DeviceHandler::DeviceHandler(QObject *parent) :
setReturns("GetSupportedVendors", returns);
params.clear(); returns.clear();
setDescription("GetSupportedDevices", "Returns a list of supported Device classes.");
setDescription("GetSupportedDevices", "Returns a list of supported Device classes, optionally filtered by vendorId.");
params.insert("vendorId", "o:uuid");
setParams("GetSupportedDevices", params);
QVariantList deviceClasses;
deviceClasses.append(JsonTypes::deviceClassRef());
@ -73,7 +74,7 @@ DeviceHandler::DeviceHandler(QObject *parent) :
setParams("AddConfiguredDevice", params);
returns.insert("success", "bool");
returns.insert("errorMessage", "string");
returns.insert("deviceId", "uuid");
returns.insert("deviceId", "o:uuid");
setReturns("AddConfiguredDevice", returns);
params.clear(); returns.clear();
@ -126,7 +127,7 @@ DeviceHandler::DeviceHandler(QObject *parent) :
setParams("GetStateValue", params);
returns.insert("success", "bool");
returns.insert("errorMessage", "string");
returns.insert("value", "variant");
returns.insert("value", "o:variant");
setReturns("GetStateValue", returns);
// Notifications
@ -158,10 +159,15 @@ QVariantMap DeviceHandler::GetSupportedVendors(const QVariantMap &params) const
QVariantMap DeviceHandler::GetSupportedDevices(const QVariantMap &params) const
{
Q_UNUSED(params)
QVariantMap returns;
QVariantList supportedDeviceList;
foreach (const DeviceClass &deviceClass, GuhCore::instance()->deviceManager()->supportedDevices()) {
QList<DeviceClass> supportedDevices;
if (params.contains("vendorId")) {
supportedDevices = GuhCore::instance()->deviceManager()->supportedDevices(VendorId(params.value("vendorId").toString()));
} else {
supportedDevices = GuhCore::instance()->deviceManager()->supportedDevices();
}
foreach (const DeviceClass &deviceClass, supportedDevices) {
supportedDeviceList.append(JsonTypes::packDeviceClass(deviceClass));
}
returns.insert("deviceClasses", supportedDeviceList);
@ -202,6 +208,7 @@ QVariantMap DeviceHandler::AddConfiguredDevice(const QVariantMap &params)
switch(status) {
case DeviceManager::DeviceErrorNoError:
returns.insert("success", true);
returns.insert("errorMessage", "");
returns.insert("deviceId", newDeviceId);
break;
case DeviceManager::DeviceErrorDeviceClassNotFound:
@ -310,6 +317,7 @@ QVariantMap DeviceHandler::GetStateValue(const QVariantMap &params) const
QVariant stateValue = device->stateValue(params.value("stateTypeId").toUuid());
returns.insert("success", true);
returns.insert("errorMessage", "");
returns.insert("value", stateValue);
return returns;
}

View File

@ -192,7 +192,7 @@ void JsonRPCServer::processData(const QUuid &clientId, const QByteArray &jsonDat
QVariantMap returns;
QMetaObject::invokeMethod(handler, method.toLatin1().data(), Q_RETURN_ARG(QVariantMap, returns), Q_ARG(QVariantMap, params));
// Q_ASSERT((targetNamespace == "JSONRPC" && method == "Introspect") || handler->validateReturns(method, returns));
Q_ASSERT((targetNamespace == "JSONRPC" && method == "Introspect") || handler->validateReturns(method, returns).first);
sendResponse(clientId, commandId, returns);
}

View File

@ -263,7 +263,10 @@ QPair<bool, QString> JsonTypes::validateMap(const QVariantMap &templateMap, cons
{
s_lastError.clear();
foreach (const QString &key, templateMap.keys()) {
if (key != "params" && !map.contains(key)) {
if (templateMap.value(key).toString().startsWith("o:")) {
continue;
}
if (!map.contains(key)) {
qDebug() << "missing key" << key << templateMap << map;
QJsonDocument jsonDoc = QJsonDocument::fromVariant(map);
return report(false, QString("Missing key \"%1\" in %2").arg(key).arg(QString(jsonDoc.toJson())));
@ -279,20 +282,23 @@ QPair<bool, QString> JsonTypes::validateMap(const QVariantMap &templateMap, cons
QPair<bool, QString> JsonTypes::validateProperty(const QVariant &templateValue, const QVariant &value)
{
if (templateValue == "uuid") {
QString strippedTemplateValue = templateValue.toString();
strippedTemplateValue.remove(QRegExp("^o:"));
if (strippedTemplateValue == "uuid") {
QString errorString = QString("Param %1 is not a uuid.").arg(value.toString());
return report(value.canConvert(QVariant::Uuid), errorString);
}
if (templateValue == "string") {
if (strippedTemplateValue == "string") {
QString errorString = QString("Param %1 is not a string.").arg(value.toString());
return report(value.canConvert(QVariant::String), errorString);
}
if (templateValue == "bool") {
if (strippedTemplateValue == "bool") {
QString errorString = QString("Param %1 is not a bool.").arg(value.toString());
return report(value.canConvert(QVariant::Bool), errorString);
}
qWarning() << QString("Unhandled property type: %1 (expected: %2)").arg(value.toString()).arg(templateValue.toString());
QString errorString = QString("Unhandled property type: %1 (expected: %2)").arg(value.toString()).arg(templateValue.toString());
qWarning() << QString("Unhandled property type: %1 (expected: %2)").arg(value.toString()).arg(strippedTemplateValue);
QString errorString = QString("Unhandled property type: %1 (expected: %2)").arg(value.toString()).arg(strippedTemplateValue);
return report(false, errorString);
}
@ -339,6 +345,11 @@ QPair<bool, QString> JsonTypes::validateVariant(const QVariant &templateVariant,
qDebug() << "device not valid";
return result;
}
} else if (refName == vendorRef()) {
QPair<bool, QString> result = validateMap(vendorDescription(), variant.toMap());
if (!result.first) {
qDebug() << "value not allowed in" << vendorRef();
}
} else if (refName == deviceClassRef()) {
QPair<bool, QString> result = validateMap(deviceClassDescription(), variant.toMap());
if (!result.first) {

View File

@ -46,6 +46,8 @@ private slots:
void introspect();
void getSupportedVendors();
void getSupportedDevices_data();
void getSupportedDevices();
void enableDisableNotifications_data();
@ -217,14 +219,33 @@ void TestJSONRPC::getSupportedVendors()
QCOMPARE(vendorId, guhVendorId);
}
void TestJSONRPC::getSupportedDevices_data()
{
QTest::addColumn<VendorId>("vendorId");
QTest::addColumn<int>("resultCount");
QTest::newRow("vendor guh") << guhVendorId << 1;
QTest::newRow("no filter") << VendorId() << 1;
QTest::newRow("invalid vendor") << VendorId("93e7d361-8025-4354-b17e-b68406c800bc") << 0;
}
void TestJSONRPC::getSupportedDevices()
{
QVariant supportedDevices = injectAndWait("Devices.GetSupportedDevices");
QFETCH(VendorId, vendorId);
QFETCH(int, resultCount);
QVariantMap params;
if (!vendorId.isNull()) {
params.insert("vendorId", vendorId);
}
QVariant supportedDevices = injectAndWait("Devices.GetSupportedDevices", params);
// Make sure there is exactly 1 supported device class with the name Mock Wifi Device
QCOMPARE(supportedDevices.toMap().value("params").toMap().value("deviceClasses").toList().count(), 1);
QString deviceName = supportedDevices.toMap().value("params").toMap().value("deviceClasses").toList().first().toMap().value("name").toString();
QCOMPARE(deviceName, QString("Mock Device"));
QCOMPARE(supportedDevices.toMap().value("params").toMap().value("deviceClasses").toList().count(), resultCount);
if (resultCount > 0) {
QString deviceName = supportedDevices.toMap().value("params").toMap().value("deviceClasses").toList().first().toMap().value("name").toString();
QCOMPARE(deviceName, QString("Mock Device"));
}
}
void TestJSONRPC::enableDisableNotifications_data()