Merge PR #140: Drop deprecated api
This commit is contained in:
commit
2d91a6243c
4
debian/changelog
vendored
4
debian/changelog
vendored
@ -1,3 +1,7 @@
|
||||
nymea (0.12.0) UNRELEASED; urgency=medium
|
||||
|
||||
-- Michael Zanetti <michael.zanetti@guh.io> Fri, 22 Mar 2019 00:49:04 +0100
|
||||
|
||||
nymea (0.11.1) xenial; urgency=medium
|
||||
|
||||
[ Simon Stürz ]
|
||||
|
||||
@ -30,29 +30,6 @@ See also: \l{Param}
|
||||
}
|
||||
\endcode
|
||||
See also: \l{ParamType}
|
||||
\section2 BasicTag
|
||||
\code
|
||||
[
|
||||
"BasicTagService",
|
||||
"BasicTagDevice",
|
||||
"BasicTagSensor",
|
||||
"BasicTagActuator",
|
||||
"BasicTagLighting",
|
||||
"BasicTagEnergy",
|
||||
"BasicTagMultimedia",
|
||||
"BasicTagWeather",
|
||||
"BasicTagGateway",
|
||||
"BasicTagHeating",
|
||||
"BasicTagCooling",
|
||||
"BasicTagNotification",
|
||||
"BasicTagSecurity",
|
||||
"BasicTagTime",
|
||||
"BasicTagShading",
|
||||
"BasicTagAppliance",
|
||||
"BasicTagCamera",
|
||||
"BasicTagLock"
|
||||
]
|
||||
\endcode
|
||||
\section2 BasicType
|
||||
\code
|
||||
[
|
||||
@ -134,13 +111,9 @@ See also: \l{Param}
|
||||
"actionTypes": [
|
||||
"$ref:ActionType"
|
||||
],
|
||||
"basicTags": [
|
||||
"$ref:BasicTag"
|
||||
],
|
||||
"createMethods": [
|
||||
"$ref:CreateMethod"
|
||||
],
|
||||
"deviceIcon": "$ref:DeviceIcon",
|
||||
"discoveryParamTypes": [
|
||||
"$ref:ParamType"
|
||||
],
|
||||
@ -153,9 +126,6 @@ See also: \l{Param}
|
||||
"String"
|
||||
],
|
||||
"name": "String",
|
||||
"o:criticalStateTypeId": "Uuid",
|
||||
"o:primaryActionTypeId": "Uuid",
|
||||
"o:primaryStateTypeId": "Uuid",
|
||||
"paramTypes": [
|
||||
"$ref:ParamType"
|
||||
],
|
||||
@ -167,7 +137,7 @@ See also: \l{Param}
|
||||
"vendorId": "Uuid"
|
||||
}
|
||||
\endcode
|
||||
See also: \l{ActionType}, \l{CreateMethod}, \l{DeviceIcon}, \l{BasicTag}, \l{ParamType}, \l{SetupMethod}, \l{StateType}, \l{EventType}, \l{ParamType}
|
||||
See also: \l{ActionType}, \l{CreateMethod}, \l{ParamType}, \l{SetupMethod}, \l{StateType}, \l{EventType}, \l{ParamType}
|
||||
\section2 DeviceDescriptor
|
||||
\code
|
||||
{
|
||||
@ -206,47 +176,6 @@ See also: \l{ActionType}, \l{CreateMethod}, \l{DeviceIcon}, \l{BasicTag}, \l{Par
|
||||
"DeviceErrorParameterNotWritable"
|
||||
]
|
||||
\endcode
|
||||
\section2 DeviceIcon
|
||||
\code
|
||||
[
|
||||
"DeviceIconNone",
|
||||
"DeviceIconBed",
|
||||
"DeviceIconBlinds",
|
||||
"DeviceIconCeilingLamp",
|
||||
"DeviceIconCouch",
|
||||
"DeviceIconDeskLamp",
|
||||
"DeviceIconDesk",
|
||||
"DeviceIconHifi",
|
||||
"DeviceIconPower",
|
||||
"DeviceIconEnergy",
|
||||
"DeviceIconRadio",
|
||||
"DeviceIconSmartPhone",
|
||||
"DeviceIconSocket",
|
||||
"DeviceIconStandardLamp",
|
||||
"DeviceIconSun",
|
||||
"DeviceIconTablet",
|
||||
"DeviceIconThermometer",
|
||||
"DeviceIconTune",
|
||||
"DeviceIconTv",
|
||||
"DeviceIconBattery",
|
||||
"DeviceIconDishwasher",
|
||||
"DeviceIconWashingMachine",
|
||||
"DeviceIconLaundryDryer",
|
||||
"DeviceIconIrHeater",
|
||||
"DeviceIconRadiator",
|
||||
"DeviceIconSwitch",
|
||||
"DeviceIconMotionDetectors",
|
||||
"DeviceIconWeather",
|
||||
"DeviceIconTime",
|
||||
"DeviceIconLightBulb",
|
||||
"DeviceIconGateway",
|
||||
"DeviceIconMail",
|
||||
"DeviceIconNetwork",
|
||||
"DeviceIconCloud",
|
||||
"DeviceIconGarage",
|
||||
"DeviceIconRollerShutter"
|
||||
]
|
||||
\endcode
|
||||
\section2 Event
|
||||
\code
|
||||
{
|
||||
@ -278,8 +207,6 @@ See also: \l{ParamDescriptor}
|
||||
"id": "Uuid",
|
||||
"index": "Int",
|
||||
"name": "String",
|
||||
"o:graphRelevant": "Bool",
|
||||
"o:ruleRelevant": "Bool",
|
||||
"paramTypes": [
|
||||
"$ref:ParamType"
|
||||
]
|
||||
@ -628,13 +555,11 @@ See also: \l{StateEvaluator}, \l{StateDescriptor}, \l{StateOperator}
|
||||
"id": "Uuid",
|
||||
"index": "Int",
|
||||
"name": "String",
|
||||
"o:graphRelevant": "Bool",
|
||||
"o:maxValue": "Variant",
|
||||
"o:minValue": "Variant",
|
||||
"o:possibleValues": [
|
||||
"Variant"
|
||||
],
|
||||
"o:ruleRelevant": "Bool",
|
||||
"o:unit": "$ref:Unit",
|
||||
"type": "$ref:BasicType"
|
||||
}
|
||||
@ -3403,26 +3328,6 @@ See also: \l{Tag}
|
||||
"$ref:ParamType"
|
||||
]
|
||||
},
|
||||
"BasicTag": [
|
||||
"BasicTagService",
|
||||
"BasicTagDevice",
|
||||
"BasicTagSensor",
|
||||
"BasicTagActuator",
|
||||
"BasicTagLighting",
|
||||
"BasicTagEnergy",
|
||||
"BasicTagMultimedia",
|
||||
"BasicTagWeather",
|
||||
"BasicTagGateway",
|
||||
"BasicTagHeating",
|
||||
"BasicTagCooling",
|
||||
"BasicTagNotification",
|
||||
"BasicTagSecurity",
|
||||
"BasicTagTime",
|
||||
"BasicTagShading",
|
||||
"BasicTagAppliance",
|
||||
"BasicTagCamera",
|
||||
"BasicTagLock"
|
||||
],
|
||||
"BasicType": [
|
||||
"Uuid",
|
||||
"String",
|
||||
@ -3482,13 +3387,9 @@ See also: \l{Tag}
|
||||
"actionTypes": [
|
||||
"$ref:ActionType"
|
||||
],
|
||||
"basicTags": [
|
||||
"$ref:BasicTag"
|
||||
],
|
||||
"createMethods": [
|
||||
"$ref:CreateMethod"
|
||||
],
|
||||
"deviceIcon": "$ref:DeviceIcon",
|
||||
"discoveryParamTypes": [
|
||||
"$ref:ParamType"
|
||||
],
|
||||
@ -3501,9 +3402,6 @@ See also: \l{Tag}
|
||||
"String"
|
||||
],
|
||||
"name": "String",
|
||||
"o:criticalStateTypeId": "Uuid",
|
||||
"o:primaryActionTypeId": "Uuid",
|
||||
"o:primaryStateTypeId": "Uuid",
|
||||
"paramTypes": [
|
||||
"$ref:ParamType"
|
||||
],
|
||||
@ -3545,44 +3443,6 @@ See also: \l{Tag}
|
||||
"DeviceErrorPairingTransactionIdNotFound",
|
||||
"DeviceErrorParameterNotWritable"
|
||||
],
|
||||
"DeviceIcon": [
|
||||
"DeviceIconNone",
|
||||
"DeviceIconBed",
|
||||
"DeviceIconBlinds",
|
||||
"DeviceIconCeilingLamp",
|
||||
"DeviceIconCouch",
|
||||
"DeviceIconDeskLamp",
|
||||
"DeviceIconDesk",
|
||||
"DeviceIconHifi",
|
||||
"DeviceIconPower",
|
||||
"DeviceIconEnergy",
|
||||
"DeviceIconRadio",
|
||||
"DeviceIconSmartPhone",
|
||||
"DeviceIconSocket",
|
||||
"DeviceIconStandardLamp",
|
||||
"DeviceIconSun",
|
||||
"DeviceIconTablet",
|
||||
"DeviceIconThermometer",
|
||||
"DeviceIconTune",
|
||||
"DeviceIconTv",
|
||||
"DeviceIconBattery",
|
||||
"DeviceIconDishwasher",
|
||||
"DeviceIconWashingMachine",
|
||||
"DeviceIconLaundryDryer",
|
||||
"DeviceIconIrHeater",
|
||||
"DeviceIconRadiator",
|
||||
"DeviceIconSwitch",
|
||||
"DeviceIconMotionDetectors",
|
||||
"DeviceIconWeather",
|
||||
"DeviceIconTime",
|
||||
"DeviceIconLightBulb",
|
||||
"DeviceIconGateway",
|
||||
"DeviceIconMail",
|
||||
"DeviceIconNetwork",
|
||||
"DeviceIconCloud",
|
||||
"DeviceIconGarage",
|
||||
"DeviceIconRollerShutter"
|
||||
],
|
||||
"Event": {
|
||||
"deviceId": "Uuid",
|
||||
"eventTypeId": "Uuid",
|
||||
@ -3604,8 +3464,6 @@ See also: \l{Tag}
|
||||
"id": "Uuid",
|
||||
"index": "Int",
|
||||
"name": "String",
|
||||
"o:graphRelevant": "Bool",
|
||||
"o:ruleRelevant": "Bool",
|
||||
"paramTypes": [
|
||||
"$ref:ParamType"
|
||||
]
|
||||
@ -3855,13 +3713,11 @@ See also: \l{Tag}
|
||||
"id": "Uuid",
|
||||
"index": "Int",
|
||||
"name": "String",
|
||||
"o:graphRelevant": "Bool",
|
||||
"o:maxValue": "Variant",
|
||||
"o:minValue": "Variant",
|
||||
"o:possibleValues": [
|
||||
"Variant"
|
||||
],
|
||||
"o:ruleRelevant": "Bool",
|
||||
"o:unit": "$ref:Unit",
|
||||
"type": "$ref:BasicType"
|
||||
},
|
||||
|
||||
@ -192,13 +192,8 @@
|
||||
"displayName": "The name of the device class (translatable)",
|
||||
"o:createMethods": [ ],
|
||||
"o:setupMethod": "SetupMethod",
|
||||
"o:deviceIcon": "Icon",
|
||||
"o:interfaces": [ "interfacename" ],
|
||||
"o:basicTags": [ ],
|
||||
"o:pairingInfo": "Information how to pair the device. (translatable)",
|
||||
"o:criticalStateTypeId": "uuid",
|
||||
"o:primaryStateTypeId": "uuid",
|
||||
"o:primaryActionTypeId": "uuid",
|
||||
"o:discoveryParamTypes": [ ],
|
||||
"o:paramTypes": [ ],
|
||||
"o:stateTypes": [ ],
|
||||
@ -233,34 +228,9 @@
|
||||
\li \tt interfaces
|
||||
\li \b O
|
||||
\li array
|
||||
\li A string list of \l{Interfaces for DeviceClasses}{interfaces} this plugin implements. Interfaces show you how types
|
||||
of this DeviceClass \underline{must} look like.
|
||||
\li A string list of \l{Interfaces for DeviceClasses}{interfaces} this plugin implements. Interfaces define states, events and actions to
|
||||
provide more defined ways of creating device class. A plugin developer should always try to follow interface definitions if possible.
|
||||
\row
|
||||
\li \tt basicTags
|
||||
\li \b O
|
||||
\li array
|
||||
\li A string list of \l{DeviceClass::BasicTag}{BasicTags} for this device \unicode{0x2192} \l{DeviceClass::basicTags()}. A \l{DeviceClass} can have
|
||||
multiple \l{DeviceClass::BasicTag}{BasicTags} which describe the basic category of the DeviceClass.
|
||||
A \l{DeviceClass} should be eighter a Service or a Device, never both. See enum \l{DeviceClass::BasicTag} for more information.
|
||||
The expected value for the \e basicTags parameters matches the enum name like this:
|
||||
|
||||
\tt {DeviceClass::BasicTagService} \unicode{0x2192} \tt {"basicTags": [ "Service" ]}
|
||||
|
||||
\tt {DeviceClass::BasicTagLighting} \unicode{0x2192} \tt {"basicTags": [ "Lighting" ]}
|
||||
|
||||
\tt ...
|
||||
\row
|
||||
\li \tt deviceIcon
|
||||
\li \b O
|
||||
\li string
|
||||
\li Defines the icon for this \l{DeviceClass}. See enum \l{DeviceClass::DeviceIcon} for more information. The expected value for the \tt deviceIcon
|
||||
parameters matches the enum name like this:
|
||||
|
||||
\tt {DeviceClass::DeviceIconBed} \unicode{0x2192} \tt {"deviceIcon": "Bed"}
|
||||
|
||||
\tt {DeviceClass::DeviceIconPower} \unicode{0x2192} \tt {"deviceIcon": "Power"}
|
||||
|
||||
\tt ...
|
||||
\row
|
||||
\li \tt createMethods
|
||||
\li \b O
|
||||
@ -295,21 +265,6 @@
|
||||
\li The \l{DeviceClass::pairingInfo()}{pairingInfo} will inform the user how to pair the device \unicode{0x2192} \l{DeviceClass::setupMethod()}.
|
||||
This parameter will only be used for \l{DeviceClass::SetupMethodDisplayPin}{DisplayPin} and \l{DeviceClass::SetupMethodEnterPin}{EnterPin}
|
||||
and \l{DeviceClass::SetupMethodPushButton}{PushButton}. Example: "Please press the button on the device before continue."
|
||||
\row
|
||||
\li \tt criticalStateTypeId
|
||||
\li \b O
|
||||
\li string
|
||||
\li Deprecated: please use \l{Interfaces for DeviceClasses}{interfaces} instead.
|
||||
\row
|
||||
\li \tt primaryStateTypeId
|
||||
\li \b O
|
||||
\li string
|
||||
\li Deprecated: please use \l{Interfaces for DeviceClasses}{interfaces} instead.
|
||||
\row
|
||||
\li \tt primaryActionTypeId
|
||||
\li \b O
|
||||
\li string
|
||||
\li Deprecated: please use \l{Interfaces for DeviceClasses}{interfaces} instead.
|
||||
\row
|
||||
\li \tt discoveryParamTypes
|
||||
\li \b O
|
||||
@ -476,9 +431,6 @@ A \l{StateType} has following parameters:
|
||||
"type": "DataType",
|
||||
"defaultValue": "The state will be initialized with this value."
|
||||
"o:cached": "bool",
|
||||
"o:ruleRelevant": "bool",
|
||||
"o:eventRuleRelevant": "bool",
|
||||
"o:graphRelevant": "bool",
|
||||
"o:unit": "The unit of the state value.",
|
||||
"o:minValue": "Numeric minimum value for this state.",
|
||||
"o:maxValue": "Numeric maximum value for this state.",
|
||||
@ -537,23 +489,6 @@ A \l{StateType} has following parameters:
|
||||
\li Indicates if a state value should be cached over reboot of the server. The value will be initialized with the last known value.
|
||||
By default all states get chached. If you want to disable that behaviour you can set this property to \tt{false}. In that case the
|
||||
value will be initialized with the default value of the State.
|
||||
\row
|
||||
\li \tt ruleRelevant
|
||||
\li \b O
|
||||
\li bool
|
||||
\li Since not all \l{State}{States} make sense for the user in a rule, with this flag can be specified if this state should be visible
|
||||
in the rule engine for the user or not. This flag has no effect to the ruleengine mechanism and is only ment to filter out not
|
||||
interesting \l{State}{States}. By default, every state is rule relevant.
|
||||
\row
|
||||
\li \tt eventRuleRelevant
|
||||
\li \b O
|
||||
\li bool
|
||||
\li Deprecated: please use \l{Interfaces for DeviceClasses}{interfaces} instead.
|
||||
\row
|
||||
\li \tt graphRelevant
|
||||
\li \b O
|
||||
\li bool
|
||||
\li Deprecated: please use \l{Interfaces for DeviceClasses}{interfaces} instead.
|
||||
\row
|
||||
\li \tt unit
|
||||
\li \b O
|
||||
@ -710,8 +645,6 @@ A \l{StateType} has following parameters:
|
||||
"id": "uuid",
|
||||
"name": "eventName",
|
||||
"displayName": "Name of the event (translatable)",
|
||||
"o:ruleRelevant": "bool",
|
||||
"o:graphRelevant": "bool",
|
||||
"o:paramTypes": [
|
||||
...
|
||||
]
|
||||
@ -745,18 +678,6 @@ A \l{StateType} has following parameters:
|
||||
\li A list of \l{ParamType}{ParamTypes} which define the parameters of this event \unicode{0x2192} \l{EventType::paramTypes()}.
|
||||
|
||||
\b{See also:} \l{The ParamType definition}"
|
||||
\row
|
||||
\li \tt ruleRelevant
|
||||
\li \b O
|
||||
\li bool
|
||||
\li Since not all \l{Event}{Events} make sense for the user in a rule, with this flag can be specidied if this event should be visible in the rule engine
|
||||
for the user or not. This flag has no effect to the ruleengine mechanism and is only ment to filter out not interesting \l{Event}{Events}. By default,
|
||||
every event is rule relevant.
|
||||
\row
|
||||
\li \tt graphRelevant
|
||||
\li \b O
|
||||
\li bool
|
||||
\li Deprecated: please use \l{Interfaces for DeviceClasses}{interfaces} instead.
|
||||
\endtable
|
||||
|
||||
*/
|
||||
|
||||
@ -298,6 +298,12 @@ DeviceHandler::DeviceHandler(QObject *parent) :
|
||||
params.insert("device", JsonTypes::deviceRef());
|
||||
setParams("DeviceChanged", params);
|
||||
|
||||
params.clear(); returns.clear();
|
||||
setDescription("PluginConfigurationChanged", "Emitted whenever a plugin's configuration is changed.");
|
||||
params.insert("pluginId", JsonTypes::basicTypeToString(JsonTypes::Uuid));
|
||||
params.insert("configuration", QVariantList() << JsonTypes::paramRef());
|
||||
setParams("PluginConfigurationChanged", params);
|
||||
|
||||
connect(NymeaCore::instance(), &NymeaCore::pluginConfigChanged, this, &DeviceHandler::pluginConfigChanged);
|
||||
connect(NymeaCore::instance(), &NymeaCore::deviceStateChanged, this, &DeviceHandler::deviceStateChanged);
|
||||
connect(NymeaCore::instance(), &NymeaCore::deviceRemoved, this, &DeviceHandler::deviceRemovedNotification);
|
||||
@ -637,11 +643,11 @@ void DeviceHandler::pluginConfigChanged(const PluginId &id, const ParamList &con
|
||||
{
|
||||
QVariantMap params;
|
||||
params.insert("pluginId", id);
|
||||
QVariantMap configMap;
|
||||
QVariantList configList;
|
||||
foreach (const Param ¶m, config) {
|
||||
configMap.insert(param.paramTypeId().toString(), param.value());
|
||||
configList << JsonTypes::packParam(param);
|
||||
}
|
||||
params.insert("configuration", configMap);
|
||||
params.insert("configuration", configList);
|
||||
emit PluginConfigurationChanged(params);
|
||||
}
|
||||
|
||||
|
||||
@ -248,6 +248,11 @@ JsonReply *JsonRPCServer::Hello(const QVariantMap ¶ms)
|
||||
|
||||
qCDebug(dcJsonRpc()) << "Client" << clientId << "initiated handshake." << m_clientLocales.value(clientId);
|
||||
|
||||
// If we waited for the handshake, here it is. Remove the timer...
|
||||
if (m_newConnectionWaitTimers.contains(clientId)) {
|
||||
delete m_newConnectionWaitTimers.take(clientId);
|
||||
}
|
||||
|
||||
return createReply(createWelcomeMessage(interface, clientId));
|
||||
}
|
||||
|
||||
@ -285,6 +290,7 @@ JsonReply* JsonRPCServer::Version(const QVariantMap ¶ms) const
|
||||
JsonReply* JsonRPCServer::SetNotificationStatus(const QVariantMap ¶ms)
|
||||
{
|
||||
QUuid clientId = this->property("clientId").toUuid();
|
||||
Q_ASSERT_X(m_clientNotifications.contains(clientId), "JsonRPCServer", "SetNotificationStatus for an unknown client called");
|
||||
m_clientNotifications[clientId] = params.value("enabled").toBool();
|
||||
QVariantMap returns;
|
||||
returns.insert("enabled", m_clientNotifications[clientId]);
|
||||
@ -585,12 +591,16 @@ void JsonRPCServer::processJsonPacket(TransportInterface *interface, const QUuid
|
||||
if (NymeaCore::instance()->userManager()->initRequired()) {
|
||||
if (!(targetNamespace == "JSONRPC" && authExemptMethodsNoUser.contains(method)) && (token.isEmpty() || !NymeaCore::instance()->userManager()->verifyToken(token))) {
|
||||
sendUnauthorizedResponse(interface, clientId, commandId, "Initial setup required. Call CreateUser first.");
|
||||
qCWarning(dcJsonRpc()) << "Initial setup required but client does not call the setup. Dropping connection.";
|
||||
interface->terminateClientConnection(clientId);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// ok, we have a user. if there isn't a valid token, let's fail unless this is a Authenticate, Introspect Hello call
|
||||
if (!(targetNamespace == "JSONRPC" && authExemptMethodsWithUser.contains(method)) && (token.isEmpty() || !NymeaCore::instance()->userManager()->verifyToken(token))) {
|
||||
sendUnauthorizedResponse(interface, clientId, commandId, "Forbidden: Invalid token.");
|
||||
qCWarning(dcJsonRpc()) << "Client did not not present a valid token. Dropping connection.";
|
||||
interface->terminateClientConnection(clientId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -622,7 +632,16 @@ void JsonRPCServer::processJsonPacket(TransportInterface *interface, const QUuid
|
||||
|
||||
qCDebug(dcJsonRpc()) << "Invoking method" << targetNamespace << method.toLatin1().data();
|
||||
|
||||
if (targetNamespace != "JSONRPC" || method != "Hello") {
|
||||
if (!(targetNamespace == "JSONRPC" && method == "Hello")) {
|
||||
// This is not the handshake message. If we've waited for it, consider this a protocol violation and drop connection
|
||||
if (m_newConnectionWaitTimers.contains(clientId)) {
|
||||
sendErrorResponse(interface, clientId, commandId, "Handshake required. Call JSONRPC.Hello first.");
|
||||
qCWarning(dcJsonRpc()) << "Connection requires a handshake but client did not initiate handshake. Dropping connection";
|
||||
interface->terminateClientConnection(clientId);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Unless this is the Hello message, which allows setting the locale explicity, attach the locale
|
||||
// for this connection
|
||||
// If the client did request a locale in the Hello message, use that locale
|
||||
@ -767,7 +786,17 @@ void JsonRPCServer::clientConnected(const QUuid &clientId)
|
||||
// Initialize the connection locale to the settings default
|
||||
m_clientLocales.insert(clientId, NymeaCore::instance()->configuration()->locale());
|
||||
|
||||
interface->sendData(clientId, QJsonDocument::fromVariant(createWelcomeMessage(interface, clientId)).toJson(QJsonDocument::Compact));
|
||||
QTimer *timer = new QTimer(this);
|
||||
connect(timer, &QTimer::timeout, this, [this, timer, clientId, interface](){
|
||||
// Client did not initiate handshake within timeout. Drop connection...
|
||||
m_clientTransports.value(clientId)->disconnect();
|
||||
timer->deleteLater();
|
||||
m_newConnectionWaitTimers.remove(clientId);
|
||||
qCDebug(dcJsonRpc()) << "Client" << clientId << "did not initiate the handshake within the required timeout. Dropping connection.";
|
||||
interface->terminateClientConnection(clientId);
|
||||
});
|
||||
m_newConnectionWaitTimers.insert(clientId, timer);
|
||||
timer->start(10000);
|
||||
}
|
||||
|
||||
void JsonRPCServer::clientDisconnected(const QUuid &clientId)
|
||||
@ -780,6 +809,9 @@ void JsonRPCServer::clientDisconnected(const QUuid &clientId)
|
||||
if (m_pushButtonTransactions.values().contains(clientId)) {
|
||||
NymeaCore::instance()->userManager()->cancelPushButtonAuth(m_pushButtonTransactions.key(clientId));
|
||||
}
|
||||
if (m_newConnectionWaitTimers.contains(clientId)) {
|
||||
delete m_newConnectionWaitTimers.take(clientId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -107,6 +107,7 @@ private:
|
||||
QHash<QUuid, bool> m_clientNotifications;
|
||||
QHash<QUuid, QLocale> m_clientLocales;
|
||||
QHash<int, QUuid> m_pushButtonTransactions;
|
||||
QHash<QUuid, QTimer*> m_newConnectionWaitTimers;
|
||||
|
||||
QHash<QString, JsonReply*> m_pairingRequests;
|
||||
|
||||
|
||||
@ -70,8 +70,6 @@ bool JsonTypes::s_initialized = false;
|
||||
QString JsonTypes::s_lastError;
|
||||
|
||||
QVariantList JsonTypes::s_basicType;
|
||||
QVariantList JsonTypes::s_basicTag;
|
||||
QVariantList JsonTypes::s_deviceIcon;
|
||||
QVariantList JsonTypes::s_stateOperator;
|
||||
QVariantList JsonTypes::s_valueOperator;
|
||||
QVariantList JsonTypes::s_inputType;
|
||||
@ -139,8 +137,6 @@ void JsonTypes::init()
|
||||
s_unit = enumToStrings(Types::staticMetaObject, "Unit");
|
||||
s_createMethod = enumToStrings(DeviceClass::staticMetaObject, "CreateMethod");
|
||||
s_setupMethod = enumToStrings(DeviceClass::staticMetaObject, "SetupMethod");
|
||||
s_basicTag = enumToStrings(DeviceClass::staticMetaObject, "BasicTag");
|
||||
s_deviceIcon = enumToStrings(DeviceClass::staticMetaObject, "DeviceIcon");
|
||||
s_removePolicy = enumToStrings(RuleEngine::staticMetaObject, "RemovePolicy");
|
||||
s_deviceError = enumToStrings(DeviceManager::staticMetaObject, "DeviceError");
|
||||
s_ruleError = enumToStrings(RuleEngine::staticMetaObject, "RuleError");
|
||||
@ -203,8 +199,6 @@ void JsonTypes::init()
|
||||
s_stateType.insert("index", basicTypeToString(Int));
|
||||
s_stateType.insert("defaultValue", basicTypeToString(Variant));
|
||||
s_stateType.insert("o:unit", unitRef());
|
||||
s_stateType.insert("o:ruleRelevant", basicTypeToString(Bool));
|
||||
s_stateType.insert("o:graphRelevant", basicTypeToString(Bool));
|
||||
s_stateType.insert("o:minValue", basicTypeToString(Variant));
|
||||
s_stateType.insert("o:maxValue", basicTypeToString(Variant));
|
||||
s_stateType.insert("o:possibleValues", QVariantList() << basicTypeToString(Variant));
|
||||
@ -233,8 +227,6 @@ void JsonTypes::init()
|
||||
s_eventType.insert("displayName", basicTypeToString(String));
|
||||
s_eventType.insert("index", basicTypeToString(Int));
|
||||
s_eventType.insert("paramTypes", QVariantList() << paramTypeRef());
|
||||
s_eventType.insert("o:ruleRelevant", basicTypeToString(Bool));
|
||||
s_eventType.insert("o:graphRelevant", basicTypeToString(Bool));
|
||||
|
||||
// Event
|
||||
s_event.insert("eventTypeId", basicTypeToString(Uuid));
|
||||
@ -277,14 +269,9 @@ void JsonTypes::init()
|
||||
s_deviceClass.insert("pluginId", basicTypeToString(Uuid));
|
||||
s_deviceClass.insert("name", basicTypeToString(String));
|
||||
s_deviceClass.insert("displayName", basicTypeToString(String));
|
||||
s_deviceClass.insert("deviceIcon", deviceIconRef());
|
||||
s_deviceClass.insert("interfaces", QVariantList() << basicTypeToString(String));
|
||||
s_deviceClass.insert("basicTags", QVariantList() << basicTagRef());
|
||||
s_deviceClass.insert("setupMethod", setupMethodRef());
|
||||
s_deviceClass.insert("createMethods", QVariantList() << createMethodRef());
|
||||
s_deviceClass.insert("o:criticalStateTypeId", basicTypeToString(Uuid));
|
||||
s_deviceClass.insert("o:primaryStateTypeId", basicTypeToString(Uuid));
|
||||
s_deviceClass.insert("o:primaryActionTypeId", basicTypeToString(Uuid));
|
||||
s_deviceClass.insert("stateTypes", QVariantList() << stateTypeRef());
|
||||
s_deviceClass.insert("eventTypes", QVariantList() << eventTypeRef());
|
||||
s_deviceClass.insert("actionTypes", QVariantList() << actionTypeRef());
|
||||
@ -437,13 +424,11 @@ QVariantMap JsonTypes::allTypes()
|
||||
{
|
||||
QVariantMap allTypes;
|
||||
allTypes.insert("BasicType", basicType());
|
||||
allTypes.insert("BasicTag", basicTag());
|
||||
allTypes.insert("ParamType", paramTypeDescription());
|
||||
allTypes.insert("InputType", inputType());
|
||||
allTypes.insert("Unit", unit());
|
||||
allTypes.insert("CreateMethod", createMethod());
|
||||
allTypes.insert("SetupMethod", setupMethod());
|
||||
allTypes.insert("DeviceIcon", deviceIcon());
|
||||
allTypes.insert("ValueOperator", valueOperator());
|
||||
allTypes.insert("StateOperator", stateOperator());
|
||||
allTypes.insert("RemovePolicy", removePolicy());
|
||||
@ -507,11 +492,6 @@ QVariantMap JsonTypes::packEventType(const EventType &eventType, const PluginId
|
||||
variant.insert("name", eventType.name());
|
||||
variant.insert("displayName", NymeaCore::instance()->deviceManager()->translator()->translate(pluginId, eventType.displayName(), locale));
|
||||
variant.insert("index", eventType.index());
|
||||
if (!eventType.ruleRelevant())
|
||||
variant.insert("ruleRelevant", false);
|
||||
|
||||
if (eventType.graphRelevant())
|
||||
variant.insert("graphRelevant", true);
|
||||
|
||||
QVariantList paramTypes;
|
||||
foreach (const ParamType ¶mType, eventType.paramTypes())
|
||||
@ -642,12 +622,6 @@ QVariantMap JsonTypes::packStateType(const StateType &stateType, const PluginId
|
||||
variantMap.insert("type", basicTypeToString(stateType.type()));
|
||||
variantMap.insert("defaultValue", stateType.defaultValue());
|
||||
|
||||
if (!stateType.ruleRelevant())
|
||||
variantMap.insert("ruleRelevant", false);
|
||||
|
||||
if (stateType.graphRelevant())
|
||||
variantMap.insert("graphRelevant", true);
|
||||
|
||||
if (stateType.maxValue().isValid())
|
||||
variantMap.insert("maxValue", stateType.maxValue());
|
||||
|
||||
@ -782,13 +756,8 @@ QVariantMap JsonTypes::packDeviceClass(const DeviceClass &deviceClass, const QLo
|
||||
variant.insert("displayName", NymeaCore::instance()->deviceManager()->translator()->translate(deviceClass.pluginId(), deviceClass.displayName(), locale));
|
||||
variant.insert("vendorId", deviceClass.vendorId().toString());
|
||||
variant.insert("pluginId", deviceClass.pluginId().toString());
|
||||
variant.insert("deviceIcon", s_deviceIcon.at(deviceClass.deviceIcon()));
|
||||
variant.insert("interfaces", deviceClass.interfaces());
|
||||
|
||||
QVariantList basicTags;
|
||||
foreach (const DeviceClass::BasicTag &basicTag, deviceClass.basicTags())
|
||||
basicTags.append(s_basicTag.at(basicTag));
|
||||
|
||||
QVariantList stateTypes;
|
||||
foreach (const StateType &stateType, deviceClass.stateTypes())
|
||||
stateTypes.append(packStateType(stateType, deviceClass.pluginId(), locale));
|
||||
@ -809,16 +778,6 @@ QVariantMap JsonTypes::packDeviceClass(const DeviceClass &deviceClass, const QLo
|
||||
foreach (const ParamType ¶mType, deviceClass.discoveryParamTypes())
|
||||
discoveryParamTypes.append(packParamType(paramType, deviceClass.pluginId(), locale));
|
||||
|
||||
if (!deviceClass.criticalStateTypeId().isNull())
|
||||
variant.insert("criticalStateTypeId", deviceClass.criticalStateTypeId().toString());
|
||||
|
||||
if (!deviceClass.primaryStateTypeId().isNull())
|
||||
variant.insert("primaryStateTypeId", deviceClass.primaryStateTypeId().toString());
|
||||
|
||||
if (!deviceClass.primaryActionTypeId().isNull())
|
||||
variant.insert("primaryActionTypeId", deviceClass.primaryActionTypeId().toString());
|
||||
|
||||
variant.insert("basicTags", basicTags);
|
||||
variant.insert("paramTypes", paramTypes);
|
||||
variant.insert("discoveryParamTypes", discoveryParamTypes);
|
||||
variant.insert("stateTypes", stateTypes);
|
||||
@ -1372,7 +1331,6 @@ Rule JsonTypes::unpackRule(const QVariantMap &ruleMap)
|
||||
QList<EventDescriptor> eventDescriptors;
|
||||
if (ruleMap.contains("eventDescriptors")) {
|
||||
QVariantList eventDescriptorVariantList = ruleMap.value("eventDescriptors").toList();
|
||||
qCDebug(dcJsonRpc) << "unpacking eventDescriptors:" << eventDescriptorVariantList;
|
||||
foreach (const QVariant &eventDescriptorVariant, eventDescriptorVariantList) {
|
||||
eventDescriptors.append(JsonTypes::unpackEventDescriptor(eventDescriptorVariant.toMap()));
|
||||
}
|
||||
@ -2122,18 +2080,6 @@ QPair<bool, QString> JsonTypes::validateVariant(const QVariant &templateVariant,
|
||||
qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(unitRef());
|
||||
return result;
|
||||
}
|
||||
} else if (refName == basicTagRef()) {
|
||||
QPair<bool, QString> result = validateEnum(s_basicTag, variant);
|
||||
if (!result.first) {
|
||||
qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(basicTagRef());
|
||||
return result;
|
||||
}
|
||||
} else if (refName == deviceIconRef()) {
|
||||
QPair<bool, QString> result = validateEnum(s_deviceIcon, variant);
|
||||
if (!result.first) {
|
||||
qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(deviceIconRef());
|
||||
return result;
|
||||
}
|
||||
} else if (refName == repeatingModeRef()) {
|
||||
QPair<bool, QString> result = validateEnum(s_repeatingMode, variant);
|
||||
if (!result.first) {
|
||||
|
||||
@ -120,14 +120,12 @@ public:
|
||||
static QVariantMap allTypes();
|
||||
|
||||
DECLARE_TYPE(basicType, "BasicType", JsonTypes, BasicType)
|
||||
DECLARE_TYPE(basicTag, "BasicTag", DeviceClass, BasicTag)
|
||||
DECLARE_TYPE(stateOperator, "StateOperator", Types, StateOperator)
|
||||
DECLARE_TYPE(valueOperator, "ValueOperator", Types, ValueOperator)
|
||||
DECLARE_TYPE(inputType, "InputType", Types, InputType)
|
||||
DECLARE_TYPE(unit, "Unit", Types, Unit)
|
||||
DECLARE_TYPE(createMethod, "CreateMethod", DeviceClass, CreateMethod)
|
||||
DECLARE_TYPE(setupMethod, "SetupMethod", DeviceClass, SetupMethod)
|
||||
DECLARE_TYPE(deviceIcon, "DeviceIcon", DeviceClass, DeviceIcon)
|
||||
DECLARE_TYPE(deviceError, "DeviceError", DeviceManager, DeviceError)
|
||||
DECLARE_TYPE(removePolicy, "RemovePolicy", RuleEngine, RemovePolicy)
|
||||
DECLARE_TYPE(ruleError, "RuleError", RuleEngine, RuleError)
|
||||
|
||||
@ -33,6 +33,14 @@ MockTcpServer::MockTcpServer(QObject *parent):
|
||||
TransportInterface(ServerConfiguration(), parent)
|
||||
{
|
||||
s_allServers.append(this);
|
||||
|
||||
connect(this, &TransportInterface::clientConnected, this, [this](const QUuid &clientId){
|
||||
m_connectedClients.append(clientId);
|
||||
});
|
||||
|
||||
connect(this, &TransportInterface::clientDisconnected, this, [this](const QUuid &clientId){
|
||||
m_connectedClients.removeAll(clientId);
|
||||
});
|
||||
}
|
||||
|
||||
MockTcpServer::~MockTcpServer()
|
||||
@ -65,6 +73,7 @@ QList<MockTcpServer *> MockTcpServer::servers()
|
||||
|
||||
void MockTcpServer::injectData(const QUuid &clientId, const QByteArray &data)
|
||||
{
|
||||
Q_ASSERT_X(m_connectedClients.contains(clientId), "MockTcpServer", "Cannot inject data. Client is not connected");
|
||||
emit dataAvailable(clientId, data);
|
||||
}
|
||||
|
||||
|
||||
@ -57,6 +57,8 @@ public slots:
|
||||
|
||||
private:
|
||||
static QList<MockTcpServer*> s_allServers;
|
||||
|
||||
QList<QUuid> m_connectedClients;
|
||||
};
|
||||
|
||||
#endif // TCPSERVER_H
|
||||
|
||||
@ -594,15 +594,6 @@ void DevicePlugin::loadMetaData()
|
||||
}
|
||||
deviceClass.setCreateMethods(createMethods);
|
||||
|
||||
// Read device icon
|
||||
QPair<bool, DeviceClass::DeviceIcon> deviceIconVerification = loadAndVerifyDeviceIcon(deviceClassObject.value("deviceIcon").toString());
|
||||
if (!deviceIconVerification.first) {
|
||||
broken = true;
|
||||
break;
|
||||
} else {
|
||||
deviceClass.setDeviceIcon(deviceIconVerification.second);
|
||||
}
|
||||
|
||||
// Read params
|
||||
QPair<bool, QList<ParamType> > paramTypesVerification = parseParamTypes(deviceClassObject.value("paramTypes").toArray());
|
||||
if (!paramTypesVerification.first) {
|
||||
@ -644,19 +635,6 @@ void DevicePlugin::loadMetaData()
|
||||
// Read pairing info
|
||||
deviceClass.setPairingInfo(deviceClassObject.value("pairingInfo").toString());
|
||||
|
||||
// Read basic tags
|
||||
QList<DeviceClass::BasicTag> basicTags;
|
||||
foreach (const QJsonValue &basicTagJson, deviceClassObject.value("basicTags").toArray()) {
|
||||
QPair<bool, DeviceClass::BasicTag> basicTagVerification = loadAndVerifyBasicTag(basicTagJson.toString());
|
||||
if (!basicTagVerification.first) {
|
||||
broken = true;
|
||||
break;
|
||||
} else {
|
||||
basicTags.append(basicTagVerification.second);
|
||||
}
|
||||
}
|
||||
deviceClass.setBasicTags(basicTags);
|
||||
|
||||
QList<ActionType> actionTypes;
|
||||
QList<StateType> stateTypes;
|
||||
QList<EventType> eventTypes;
|
||||
@ -720,12 +698,6 @@ void DevicePlugin::loadMetaData()
|
||||
if (st.contains("maxValue"))
|
||||
stateType.setMaxValue(st.value("maxValue").toVariant());
|
||||
|
||||
if (st.contains("ruleRelevant"))
|
||||
stateType.setRuleRelevant(st.value("ruleRelevant").toBool());
|
||||
|
||||
if (st.contains("graphRelevant"))
|
||||
stateType.setGraphRelevant(st.value("graphRelevant").toBool());
|
||||
|
||||
if (st.contains("possibleValues")) {
|
||||
QVariantList possibleValues;
|
||||
foreach (const QJsonValue &possibleValueJson, st.value("possibleValues").toArray()) {
|
||||
@ -748,9 +720,6 @@ void DevicePlugin::loadMetaData()
|
||||
|
||||
// Events for state changed
|
||||
EventType eventType(EventTypeId(stateType.id().toString()));
|
||||
if (st.contains("eventRuleRelevant"))
|
||||
eventType.setRuleRelevant(st.value("eventRuleRelevant").toBool());
|
||||
|
||||
eventType.setName(st.value("name").toString());
|
||||
eventType.setDisplayName(st.value("displayNameEvent").toString());
|
||||
ParamType paramType(ParamTypeId(stateType.id().toString()), st.value("name").toString(), stateType.type());
|
||||
@ -838,11 +807,6 @@ void DevicePlugin::loadMetaData()
|
||||
eventType.setName(et.value("name").toString());
|
||||
eventType.setDisplayName(et.value("displayName").toString());
|
||||
eventType.setIndex(index++);
|
||||
if (et.contains("ruleRelevant"))
|
||||
eventType.setRuleRelevant(et.value("ruleRelevant").toBool());
|
||||
|
||||
if (et.contains("graphRelevant"))
|
||||
eventType.setGraphRelevant(et.value("graphRelevant").toBool());
|
||||
|
||||
QPair<bool, QList<ParamType> > paramVerification = parseParamTypes(et.value("paramTypes").toArray());
|
||||
if (!paramVerification.first) {
|
||||
@ -855,41 +819,6 @@ void DevicePlugin::loadMetaData()
|
||||
}
|
||||
deviceClass.setEventTypes(eventTypes);
|
||||
|
||||
// Note: keep this after the actionType / stateType / eventType parsing
|
||||
if (deviceClassObject.contains("criticalStateTypeId")) {
|
||||
StateTypeId criticalStateTypeId = StateTypeId(deviceClassObject.value("criticalStateTypeId").toString());
|
||||
if (!deviceClass.hasStateType(criticalStateTypeId)) {
|
||||
qCWarning(dcDeviceManager()) << "Skipping device class" << deviceClass.name() << ": the definend critical stateTypeId" << criticalStateTypeId.toString() << "does not match any StateType of this DeviceClass.";
|
||||
broken = true;
|
||||
} else if (deviceClass.getStateType(criticalStateTypeId).type() != QVariant::Bool) {
|
||||
// Make sure the critical stateType is a bool state
|
||||
qCWarning(dcDeviceManager()) << "Skipping device class" << deviceClass.name() << ": the definend critical stateTypeId" << criticalStateTypeId.toString() << "is not a bool StateType.";
|
||||
broken = true;
|
||||
} else {
|
||||
deviceClass.setCriticalStateTypeId(criticalStateTypeId);
|
||||
}
|
||||
}
|
||||
|
||||
if (deviceClassObject.contains("primaryStateTypeId")) {
|
||||
StateTypeId primaryStateTypeId = StateTypeId(deviceClassObject.value("primaryStateTypeId").toString());
|
||||
if (!deviceClass.hasStateType(primaryStateTypeId)) {
|
||||
qCWarning(dcDeviceManager()) << "Skipping device class" << deviceClass.name() << ": the definend primary stateTypeId" << primaryStateTypeId.toString() << "does not match any StateType of this DeviceClass.";
|
||||
broken = true;
|
||||
} else {
|
||||
deviceClass.setPrimaryStateTypeId(primaryStateTypeId);
|
||||
}
|
||||
}
|
||||
|
||||
if (deviceClassObject.contains("primaryActionTypeId")) {
|
||||
ActionTypeId primaryActionTypeId = ActionTypeId(deviceClassObject.value("primaryActionTypeId").toString());
|
||||
if (!deviceClass.hasActionType(primaryActionTypeId)) {
|
||||
qCWarning(dcDeviceManager()) << "Skipping device class" << deviceClass.name() << ": the definend primary actionTypeId" << primaryActionTypeId.toString() << "does not match any ActionType of this DeviceClass.";
|
||||
broken = true;
|
||||
} else {
|
||||
deviceClass.setPrimaryActionTypeId(primaryActionTypeId);
|
||||
}
|
||||
}
|
||||
|
||||
// Read interfaces
|
||||
QStringList interfaces;
|
||||
foreach (const QJsonValue &value, deviceClassObject.value("interfaces").toArray()) {
|
||||
@ -1053,58 +982,6 @@ QPair<bool, Types::InputType> DevicePlugin::loadAndVerifyInputType(const QString
|
||||
return QPair<bool, Types::InputType>(true, (Types::InputType)enumValue);
|
||||
}
|
||||
|
||||
QPair<bool, DeviceClass::BasicTag> DevicePlugin::loadAndVerifyBasicTag(const QString &basicTag) const
|
||||
{
|
||||
if (basicTag.isEmpty())
|
||||
return QPair<bool, DeviceClass::BasicTag>(true, DeviceClass::BasicTagDevice);
|
||||
|
||||
QMetaObject metaObject = DeviceClass::staticMetaObject;
|
||||
int enumIndex = metaObject.indexOfEnumerator(QString("BasicTag").toLatin1().data());
|
||||
QMetaEnum metaEnum = metaObject.enumerator(enumIndex);
|
||||
|
||||
int enumValue = -1;
|
||||
for (int i = 0; i < metaEnum.keyCount(); i++) {
|
||||
if (QString(metaEnum.valueToKey(metaEnum.value(i))) == QString("BasicTag" + basicTag)) {
|
||||
enumValue = metaEnum.value(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// inform the plugin developer about the error in the plugin json file
|
||||
if (enumValue == -1) {
|
||||
qCWarning(dcDeviceManager()) << QString("\"%1\" plugin:").arg(pluginName()).toLatin1().data() << QString("Invalid basicTag \"%1\" in json file.").arg(basicTag).toLatin1().data();
|
||||
return QPair<bool, DeviceClass::BasicTag>(false, DeviceClass::BasicTagDevice);
|
||||
}
|
||||
|
||||
return QPair<bool, DeviceClass::BasicTag>(true, (DeviceClass::BasicTag)enumValue);
|
||||
}
|
||||
|
||||
QPair<bool, DeviceClass::DeviceIcon> DevicePlugin::loadAndVerifyDeviceIcon(const QString &deviceIcon) const
|
||||
{
|
||||
if (deviceIcon.isEmpty())
|
||||
return QPair<bool, DeviceClass::DeviceIcon>(true, DeviceClass::DeviceIconNone);
|
||||
|
||||
QMetaObject metaObject = DeviceClass::staticMetaObject;
|
||||
int enumIndex = metaObject.indexOfEnumerator(QString("DeviceIcon").toLatin1().data());
|
||||
QMetaEnum metaEnum = metaObject.enumerator(enumIndex);
|
||||
|
||||
int enumValue = -1;
|
||||
for (int i = 0; i < metaEnum.keyCount(); i++) {
|
||||
if (QString(metaEnum.valueToKey(metaEnum.value(i))) == QString("DeviceIcon" + deviceIcon)) {
|
||||
enumValue = metaEnum.value(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// inform the plugin developer about the error in the plugin json file
|
||||
if (enumValue == -1) {
|
||||
qCWarning(dcDeviceManager()) << QString("\"%1\" plugin:").arg(pluginName()).toLatin1().data() << QString("Invalid deviceIcon \"%1\" in json file.").arg(deviceIcon).toLatin1().data();
|
||||
return QPair<bool, DeviceClass::DeviceIcon>(false, DeviceClass::DeviceIconNone);
|
||||
}
|
||||
|
||||
return QPair<bool, DeviceClass::DeviceIcon>(true, (DeviceClass::DeviceIcon)enumValue);
|
||||
}
|
||||
|
||||
Interfaces DevicePlugin::allInterfaces()
|
||||
{
|
||||
Interfaces ret;
|
||||
|
||||
@ -113,8 +113,6 @@ private:
|
||||
// load and verify enum values
|
||||
QPair<bool, Types::Unit> loadAndVerifyUnit(const QString &unitString) const;
|
||||
QPair<bool, Types::InputType> loadAndVerifyInputType(const QString &inputType) const;
|
||||
QPair<bool, DeviceClass::BasicTag> loadAndVerifyBasicTag(const QString &basicTag) const;
|
||||
QPair<bool, DeviceClass::DeviceIcon> loadAndVerifyDeviceIcon(const QString &deviceIcon) const;
|
||||
|
||||
// FIXME: This is expensive because it will open all the files.
|
||||
// Once DeviceManager is in libnymea-core this should probably be there too.
|
||||
|
||||
@ -62,103 +62,6 @@
|
||||
During the setup, a button has to be pushed in order to pair the \l{Device}.
|
||||
*/
|
||||
|
||||
/*! \enum DeviceClass::BasicTag
|
||||
|
||||
This enum type specifies the basic tags which describe the categories of the DeviceClass.
|
||||
A DeviceClass can have multiple tags.
|
||||
|
||||
\value BasicTagService
|
||||
The \l{DeviceClass} describes a service.
|
||||
\value BasicTagDevice
|
||||
The \l{DeviceClass} describes a real device.
|
||||
\value BasicTagSensor
|
||||
The \l{DeviceClass} describes a sensor. Any device which can measure or detect something is a sensor.
|
||||
\value BasicTagActuator
|
||||
The \l{DeviceClass} describes an actuator. Any device which can do something is an actuator.
|
||||
\value BasicTagLighting
|
||||
The \l{DeviceClass} describes a lighting device.
|
||||
\value BasicTagEnergy
|
||||
The \l{DeviceClass} describes an energy device.
|
||||
\value BasicTagMultimedia
|
||||
The \l{DeviceClass} describes a multimedia device/service.
|
||||
\value BasicTagWeather
|
||||
The \l{DeviceClass} describes a weather device/service.
|
||||
\value BasicTagGateway
|
||||
The \l{DeviceClass} describes a gateway device.
|
||||
\value BasicTagHeating
|
||||
The \l{DeviceClass} describes a heating device.
|
||||
\value BasicTagCooling
|
||||
The \l{DeviceClass} describes a cooling device.
|
||||
\value BasicTagNotification
|
||||
The \l{DeviceClass} describes a notification service.
|
||||
\value BasicTagSecurity
|
||||
The \l{DeviceClass} describes a security device/service.
|
||||
\value BasicTagTime
|
||||
The \l{DeviceClass} describes a time device/service.
|
||||
\value BasicTagShading
|
||||
The \l{DeviceClass} describes a shading device.
|
||||
\value BasicTagAppliance
|
||||
The \l{DeviceClass} describes an appliance.
|
||||
\value BasicTagCamera
|
||||
The \l{DeviceClass} describes a camera device.
|
||||
\value BasicTagLock
|
||||
The \l{DeviceClass} describes a lock device.
|
||||
|
||||
*/
|
||||
|
||||
/*! \enum DeviceClass::DeviceIcon
|
||||
|
||||
This enum type specifies the default device icon of the DeviceClass.
|
||||
Each client should have an icon set containing this list of icon types.
|
||||
If a client want's to offer special icons for a special DeviceClass or device type,
|
||||
he can bring it's own icon for a special DeviceClassId. If there is no special icon
|
||||
defined, he can fallback to the default icon.
|
||||
|
||||
\value DeviceIconNone
|
||||
\value DeviceIconBed
|
||||
\value DeviceIconBlinds
|
||||
\value DeviceIconCeilingLamp
|
||||
\value DeviceIconCouch
|
||||
\value DeviceIconDeskLamp
|
||||
\value DeviceIconDesk
|
||||
\value DeviceIconHifi
|
||||
\value DeviceIconPower
|
||||
\value DeviceIconEnergy
|
||||
\value DeviceIconRadio
|
||||
\value DeviceIconSmartPhone
|
||||
\value DeviceIconSocket
|
||||
\value DeviceIconStandardLamp
|
||||
\value DeviceIconSun
|
||||
\value DeviceIconTablet
|
||||
\value DeviceIconThermometer
|
||||
\value DeviceIconTune
|
||||
\value DeviceIconTv
|
||||
\value DeviceIconBattery
|
||||
\value DeviceIconDishwasher
|
||||
\value DeviceIconWashingMachine
|
||||
\value DeviceIconLaundryDryer
|
||||
\value DeviceIconIrHeater
|
||||
\value DeviceIconRadiator
|
||||
\value DeviceIconSwitch
|
||||
\value DeviceIconMotionDetectors
|
||||
\value DeviceIconWeather
|
||||
\value DeviceIconTime
|
||||
\value DeviceIconLightBulb
|
||||
\value DeviceIconGateway
|
||||
\value DeviceIconMail
|
||||
\value DeviceIconNetwork
|
||||
\value DeviceIconCloud
|
||||
\value DeviceIconGarage,
|
||||
\value DeviceIconRollerShutter
|
||||
*/
|
||||
|
||||
/*! \fn void DeviceClass::setBasicTags(const QList<BasicTag> &basicTags);
|
||||
Set the list of \a basicTags of this DeviceClass.
|
||||
*/
|
||||
|
||||
/*! \fn void DeviceClass::setDeviceIcon(const DeviceIcon &deviceIcon);
|
||||
Set the \a deviceIcon of this DeviceClass.
|
||||
*/
|
||||
|
||||
#include "deviceclass.h"
|
||||
|
||||
@ -170,10 +73,6 @@ DeviceClass::DeviceClass(const PluginId &pluginId, const VendorId &vendorId, con
|
||||
m_id(id),
|
||||
m_vendorId(vendorId),
|
||||
m_pluginId(pluginId),
|
||||
m_criticalStateTypeId(StateTypeId()),
|
||||
m_primaryStateTypeId(StateTypeId()),
|
||||
m_primaryActionTypeId(ActionTypeId()),
|
||||
m_deviceIcon(DeviceIconPower),
|
||||
m_createMethods(CreateMethodUser),
|
||||
m_setupMethod(SetupMethodJustAdd)
|
||||
{
|
||||
@ -228,76 +127,6 @@ void DeviceClass::setDisplayName(const QString &displayName)
|
||||
m_displayName = displayName;
|
||||
}
|
||||
|
||||
/*! Returns the critical \l{StateTypeId} of this \l{DeviceClass}.
|
||||
* A critical \l{State} describes the state which disables the whole device (i.e. connected, available or reachable). */
|
||||
StateTypeId DeviceClass::criticalStateTypeId() const
|
||||
{
|
||||
return m_criticalStateTypeId;
|
||||
}
|
||||
|
||||
/*! Set the \a criticalStateTypeId of this \l{DeviceClass}. */
|
||||
void DeviceClass::setCriticalStateTypeId(const StateTypeId &criticalStateTypeId)
|
||||
{
|
||||
m_criticalStateTypeId = criticalStateTypeId;
|
||||
}
|
||||
|
||||
/*! Returns the primary \l{StateTypeId} of this \l{DeviceClass}. */
|
||||
StateTypeId DeviceClass::primaryStateTypeId() const
|
||||
{
|
||||
return m_primaryStateTypeId;
|
||||
}
|
||||
|
||||
/*! Set the \a primaryStateTypeId of this \l{DeviceClass}. */
|
||||
void DeviceClass::setPrimaryStateTypeId(const StateTypeId &primaryStateTypeId)
|
||||
{
|
||||
m_primaryStateTypeId = primaryStateTypeId;
|
||||
}
|
||||
|
||||
/*! Returns the primary \l{ActionTypeId} of this \l{DeviceClass}. */
|
||||
ActionTypeId DeviceClass::primaryActionTypeId() const
|
||||
{
|
||||
return m_primaryActionTypeId;
|
||||
}
|
||||
|
||||
/*! Set the \a primaryActionTypeId of this \l{DeviceClass}. */
|
||||
void DeviceClass::setPrimaryActionTypeId(const ActionTypeId &primaryActionTypeId)
|
||||
{
|
||||
m_primaryActionTypeId = primaryActionTypeId;
|
||||
}
|
||||
|
||||
/*! Returns the default \l{DeviceIcon} of this \l{DeviceClass}. */
|
||||
DeviceClass::DeviceIcon DeviceClass::deviceIcon() const
|
||||
{
|
||||
return m_deviceIcon;
|
||||
}
|
||||
|
||||
/*! Set the \a deviceIcon of this \l{DeviceClass}.
|
||||
|
||||
\sa DeviceClass::DeviceIcon
|
||||
*/
|
||||
void DeviceClass::setDeviceIcon(const DeviceClass::DeviceIcon &deviceIcon)
|
||||
{
|
||||
m_deviceIcon = deviceIcon;
|
||||
}
|
||||
|
||||
/*! Returns the list of basicTags of this DeviceClass.
|
||||
|
||||
\sa DeviceClass::BasicTag
|
||||
*/
|
||||
QList<DeviceClass::BasicTag> DeviceClass::basicTags() const
|
||||
{
|
||||
return m_basicTags;
|
||||
}
|
||||
|
||||
/*! Set the list of \a basicTags of this DeviceClass.
|
||||
|
||||
\sa DeviceClass::BasicTag
|
||||
*/
|
||||
void DeviceClass::setBasicTags(const QList<DeviceClass::BasicTag> &basicTags)
|
||||
{
|
||||
m_basicTags = basicTags;
|
||||
}
|
||||
|
||||
/*! Returns the statesTypes of this DeviceClass. \{Device}{Devices} created
|
||||
from this \l{DeviceClass} must have their states matching to this template. */
|
||||
StateTypes DeviceClass::stateTypes() const
|
||||
@ -474,10 +303,9 @@ bool DeviceClass::operator==(const DeviceClass &deviceClass) const
|
||||
/*! Returns a list of all valid JSON properties a DeviceClass JSON definition can have. */
|
||||
QStringList DeviceClass::typeProperties()
|
||||
{
|
||||
return QStringList() << "id" << "name" << "displayName" << "createMethods" << "setupMethod" << "deviceIcon"
|
||||
<< "interfaces" << "basicTags" << "pairingInfo" << "criticalStateTypeId"
|
||||
<< "primaryStateTypeId" << "primaryActionTypeId" << "discoveryParamTypes"
|
||||
<< "discoveryParamTypes" << "paramTypes" << "stateTypes" << "actionTypes" << "eventTypes";
|
||||
return QStringList() << "id" << "name" << "displayName" << "createMethods" << "setupMethod"
|
||||
<< "interfaces" << "pairingInfo" << "discoveryParamTypes" << "discoveryParamTypes"
|
||||
<< "paramTypes" << "stateTypes" << "actionTypes" << "eventTypes";
|
||||
}
|
||||
|
||||
/*! Returns a list of mandatory JSON properties a DeviceClass JSON definition must have. */
|
||||
|
||||
@ -41,8 +41,7 @@ class LIBNYMEA_EXPORT DeviceClass
|
||||
Q_ENUMS(CreateMethod)
|
||||
Q_ENUMS(SetupMethod)
|
||||
Q_ENUMS(BasicTag)
|
||||
Q_ENUMS(DeviceIcon)
|
||||
Q_FLAGS(CreateMethods)
|
||||
Q_ENUMS(CreateMethods)
|
||||
|
||||
public:
|
||||
enum CreateMethod {
|
||||
@ -59,66 +58,6 @@ public:
|
||||
SetupMethodPushButton
|
||||
};
|
||||
|
||||
enum BasicTag {
|
||||
BasicTagService,
|
||||
BasicTagDevice,
|
||||
BasicTagSensor,
|
||||
BasicTagActuator,
|
||||
BasicTagLighting,
|
||||
BasicTagEnergy,
|
||||
BasicTagMultimedia,
|
||||
BasicTagWeather,
|
||||
BasicTagGateway,
|
||||
BasicTagHeating,
|
||||
BasicTagCooling,
|
||||
BasicTagNotification,
|
||||
BasicTagSecurity,
|
||||
BasicTagTime,
|
||||
BasicTagShading,
|
||||
BasicTagAppliance,
|
||||
BasicTagCamera,
|
||||
BasicTagLock
|
||||
};
|
||||
|
||||
enum DeviceIcon {
|
||||
DeviceIconNone,
|
||||
DeviceIconBed,
|
||||
DeviceIconBlinds,
|
||||
DeviceIconCeilingLamp,
|
||||
DeviceIconCouch,
|
||||
DeviceIconDeskLamp,
|
||||
DeviceIconDesk,
|
||||
DeviceIconHifi,
|
||||
DeviceIconPower,
|
||||
DeviceIconEnergy,
|
||||
DeviceIconRadio,
|
||||
DeviceIconSmartPhone,
|
||||
DeviceIconSocket,
|
||||
DeviceIconStandardLamp,
|
||||
DeviceIconSun,
|
||||
DeviceIconTablet,
|
||||
DeviceIconThermometer,
|
||||
DeviceIconTune,
|
||||
DeviceIconTv,
|
||||
DeviceIconBattery,
|
||||
DeviceIconDishwasher,
|
||||
DeviceIconWashingMachine,
|
||||
DeviceIconLaundryDryer,
|
||||
DeviceIconIrHeater,
|
||||
DeviceIconRadiator,
|
||||
DeviceIconSwitch,
|
||||
DeviceIconMotionDetectors,
|
||||
DeviceIconWeather,
|
||||
DeviceIconTime,
|
||||
DeviceIconLightBulb,
|
||||
DeviceIconGateway,
|
||||
DeviceIconMail,
|
||||
DeviceIconNetwork,
|
||||
DeviceIconCloud,
|
||||
DeviceIconGarage,
|
||||
DeviceIconRollerShutter
|
||||
};
|
||||
|
||||
DeviceClass(const PluginId &pluginId = PluginId(), const VendorId &vendorId = VendorId(), const DeviceClassId &id = DeviceClassId());
|
||||
|
||||
DeviceClassId id() const;
|
||||
@ -132,21 +71,6 @@ public:
|
||||
QString displayName() const;
|
||||
void setDisplayName(const QString &displayName);
|
||||
|
||||
StateTypeId criticalStateTypeId() const;
|
||||
void setCriticalStateTypeId(const StateTypeId &criticalStateTypeId);
|
||||
|
||||
StateTypeId primaryStateTypeId() const;
|
||||
void setPrimaryStateTypeId(const StateTypeId &primaryStateTypeId);
|
||||
|
||||
ActionTypeId primaryActionTypeId() const;
|
||||
void setPrimaryActionTypeId(const ActionTypeId &primaryActionTypeId);
|
||||
|
||||
DeviceIcon deviceIcon() const;
|
||||
void setDeviceIcon(const DeviceIcon &deviceIcon);
|
||||
|
||||
QList<BasicTag> basicTags() const;
|
||||
void setBasicTags(const QList<BasicTag> &basicTags);
|
||||
|
||||
StateTypes stateTypes() const;
|
||||
StateType getStateType(const StateTypeId &stateTypeId);
|
||||
void setStateTypes(const QList<StateType> &stateTypes);
|
||||
@ -189,11 +113,6 @@ private:
|
||||
PluginId m_pluginId;
|
||||
QString m_name;
|
||||
QString m_displayName;
|
||||
StateTypeId m_criticalStateTypeId;
|
||||
StateTypeId m_primaryStateTypeId;
|
||||
ActionTypeId m_primaryActionTypeId;
|
||||
DeviceIcon m_deviceIcon;
|
||||
QList<BasicTag> m_basicTags;
|
||||
QList<StateType> m_stateTypes;
|
||||
QList<EventType> m_eventTypes;
|
||||
QList<ActionType> m_actionTypes;
|
||||
|
||||
@ -36,9 +36,7 @@
|
||||
/*! Constructs a EventType object with the given \a id. */
|
||||
EventType::EventType(const EventTypeId &id):
|
||||
m_id(id),
|
||||
m_index(0),
|
||||
m_ruleRelevant(true),
|
||||
m_graphRelevant(false)
|
||||
m_index(0)
|
||||
{
|
||||
|
||||
}
|
||||
@ -100,30 +98,6 @@ void EventType::setParamTypes(const ParamTypes ¶mTypes)
|
||||
m_paramTypes = paramTypes;
|
||||
}
|
||||
|
||||
/*! Returns true if this EventType is relevant for the rule from a user perspective. */
|
||||
bool EventType::ruleRelevant() const
|
||||
{
|
||||
return m_ruleRelevant;
|
||||
}
|
||||
|
||||
/*! Sets this EventType relevant for the rule from a user perspective to \a ruleRelevant. */
|
||||
void EventType::setRuleRelevant(const bool &ruleRelevant)
|
||||
{
|
||||
m_ruleRelevant = ruleRelevant;
|
||||
}
|
||||
|
||||
/*! Returns true if this EventType is interesting to visualize the logs in a graph/chart from a user perspective. */
|
||||
bool EventType::graphRelevant() const
|
||||
{
|
||||
return m_graphRelevant;
|
||||
}
|
||||
|
||||
/*! Sets this EventType \a graphRelevant to inform the client application if this \l{EventType} is interesting to visualize the logs in a graph/chart. */
|
||||
void EventType::setGraphRelevant(const bool &graphRelevant)
|
||||
{
|
||||
m_graphRelevant = graphRelevant;
|
||||
}
|
||||
|
||||
/*! Returns true if this EventType has a valid id and name */
|
||||
bool EventType::isValid() const
|
||||
{
|
||||
@ -133,7 +107,7 @@ bool EventType::isValid() const
|
||||
/*! Returns a list of all valid JSON properties a EventType JSON definition can have. */
|
||||
QStringList EventType::typeProperties()
|
||||
{
|
||||
return QStringList() << "id" << "name" << "displayName" << "paramTypes" << "ruleRelevant" << "graphRelevant";
|
||||
return QStringList() << "id" << "name" << "displayName" << "paramTypes";
|
||||
}
|
||||
|
||||
/*! Returns a list of mandatory JSON properties a EventType JSON definition must have. */
|
||||
|
||||
@ -49,12 +49,6 @@ public:
|
||||
ParamTypes paramTypes() const;
|
||||
void setParamTypes(const ParamTypes ¶mTypes);
|
||||
|
||||
bool ruleRelevant() const;
|
||||
void setRuleRelevant(const bool &ruleRelevant);
|
||||
|
||||
bool graphRelevant() const;
|
||||
void setGraphRelevant(const bool &graphRelevant);
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
static QStringList typeProperties();
|
||||
@ -66,8 +60,6 @@ private:
|
||||
QString m_displayName;
|
||||
int m_index;
|
||||
QList<ParamType> m_paramTypes;
|
||||
bool m_ruleRelevant;
|
||||
bool m_graphRelevant;
|
||||
};
|
||||
|
||||
class EventTypes: public QList<EventType>
|
||||
|
||||
@ -160,30 +160,6 @@ void StateType::setUnit(const Types::Unit &unit)
|
||||
m_unit = unit;
|
||||
}
|
||||
|
||||
/*! Returns true if this StateType is relevant for the rule from a user perspective. */
|
||||
bool StateType::ruleRelevant() const
|
||||
{
|
||||
return m_ruleRelevant;
|
||||
}
|
||||
|
||||
/*! Sets this StateType relevant for the rule from a user perspective to \a ruleRelevant. */
|
||||
void StateType::setRuleRelevant(const bool &ruleRelevant)
|
||||
{
|
||||
m_ruleRelevant = ruleRelevant;
|
||||
}
|
||||
|
||||
/*! Returns true if this StateType is interesting to visualize the logs in a graph/chart from a user perspective. */
|
||||
bool StateType::graphRelevant() const
|
||||
{
|
||||
return m_graphRelevant;
|
||||
}
|
||||
|
||||
/*! Sets this StateType \a graphRelevant to inform the client application if this \l{StateType} is interesting to visualize the logs in a graph/chart. */
|
||||
void StateType::setGraphRelevant(const bool &graphRelevant)
|
||||
{
|
||||
m_graphRelevant = graphRelevant;
|
||||
}
|
||||
|
||||
/*! Returns true if this StateType is to be cached. This means, the last state value will be stored to disk upon shutdown and restored on reboot. If this is false, states will be initialized with the default value on each boot. By default all states are cached by the system. */
|
||||
bool StateType::cached() const
|
||||
{
|
||||
@ -200,8 +176,8 @@ void StateType::setCached(bool cached)
|
||||
QStringList StateType::typeProperties()
|
||||
{
|
||||
return QStringList() << "id" << "name" << "displayName" << "displayNameEvent" << "type" << "defaultValue"
|
||||
<< "cached" << "ruleRelevant" << "eventRuleRelevant" << "graphRelevant" << "unit"
|
||||
<< "minValue" << "maxValue" << "possibleValues" << "writable" << "displayNameAction";
|
||||
<< "cached" << "unit" << "minValue" << "maxValue" << "possibleValues" << "writable"
|
||||
<< "displayNameAction";
|
||||
}
|
||||
|
||||
/*! Returns a list of mandatory properties a DeviceClass definition must have. */
|
||||
|
||||
@ -64,12 +64,6 @@ public:
|
||||
Types::Unit unit() const;
|
||||
void setUnit(const Types::Unit &unit);
|
||||
|
||||
bool ruleRelevant() const;
|
||||
void setRuleRelevant(const bool &ruleRelevant);
|
||||
|
||||
bool graphRelevant() const;
|
||||
void setGraphRelevant(const bool &graphRelevant);
|
||||
|
||||
bool cached() const;
|
||||
void setCached(bool cached);
|
||||
|
||||
@ -87,8 +81,6 @@ private:
|
||||
QVariant m_maxValue;
|
||||
QVariantList m_possibleValues;
|
||||
Types::Unit m_unit = Types::UnitNone;
|
||||
bool m_ruleRelevant = true;
|
||||
bool m_graphRelevant = false;
|
||||
bool m_cached = true;
|
||||
};
|
||||
|
||||
|
||||
@ -5,8 +5,8 @@ NYMEA_VERSION_STRING=$$system('dpkg-parsechangelog | sed -n -e "s/^Version: //p"
|
||||
NYMEA_PLUGINS_PATH=/usr/lib/$$system('dpkg-architecture -q DEB_HOST_MULTIARCH')/nymea/plugins/
|
||||
|
||||
# define protocol versions
|
||||
JSON_PROTOCOL_VERSION_MAJOR=1
|
||||
JSON_PROTOCOL_VERSION_MINOR=14
|
||||
JSON_PROTOCOL_VERSION_MAJOR=2
|
||||
JSON_PROTOCOL_VERSION_MINOR=0
|
||||
REST_API_VERSION=1
|
||||
|
||||
COPYRIGHT_YEAR_FROM=2013
|
||||
|
||||
11
nymea.pro
11
nymea.pro
@ -15,11 +15,10 @@ doc.commands += cd $$top_srcdir/doc; ./generate-interfaces-qdoc.py;
|
||||
doc.commands += cd $$top_srcdir/doc; ./generate-api-qdoc.py;
|
||||
doc.commands += cd $$top_srcdir/doc; qdoc --highlighting config.qdocconf; cp -r images/* html/images/; \
|
||||
cp -r favicons/* html/; cp -r $$top_srcdir/doc/html $$top_builddir/
|
||||
QMAKE_EXTRA_TARGETS += doc
|
||||
|
||||
licensecheck.commands = $$top_srcdir/tests/auto/checklicenseheaders.sh $$top_srcdir
|
||||
|
||||
test.depends = licensecheck
|
||||
test.commands = LD_LIBRARY_PATH=$$top_builddir/libnymea-core:$$top_builddir/libnymea make check
|
||||
QMAKE_EXTRA_TARGETS += licensecheck
|
||||
|
||||
# Translations:
|
||||
# make lupdate to update .ts files
|
||||
@ -42,7 +41,11 @@ translations.path = /usr/share/nymea/translations
|
||||
translations.depends = lrelease
|
||||
INSTALLS += translations
|
||||
|
||||
QMAKE_EXTRA_TARGETS += licensecheck doc test lupdate lrelease
|
||||
QMAKE_EXTRA_TARGETS += lupdate lrelease
|
||||
|
||||
test.depends = licensecheck lrelease
|
||||
test.commands = LD_LIBRARY_PATH=$$top_builddir/libnymea-core:$$top_builddir/libnymea make check
|
||||
QMAKE_EXTRA_TARGETS += test
|
||||
|
||||
# Show doc files in project tree
|
||||
OTHER_FILES += doc/*.qdoc* \
|
||||
|
||||
@ -30,16 +30,8 @@
|
||||
"id": "753f0d32-0468-4d08-82ed-1964aab03298",
|
||||
"name": "mock",
|
||||
"displayName": "Mock Device",
|
||||
"deviceIcon": "Tune",
|
||||
"interfaces": ["system", "light", "gateway", "battery"],
|
||||
"basicTags": [
|
||||
"Device",
|
||||
"Actuator",
|
||||
"Gateway"
|
||||
],
|
||||
"createMethods": ["user", "discovery"],
|
||||
"primaryActionTypeId": "defd3ed6-1a0d-400b-8879-a0202cf39935",
|
||||
"primaryStateTypeId": "80baec19-54de-4948-ac46-31eabfaceb83",
|
||||
"discoveryParamTypes": [
|
||||
{
|
||||
"id": "d222adb4-2f9c-4c3f-8655-76400d0fb6ce",
|
||||
@ -80,7 +72,6 @@
|
||||
"displayName": "Dummy int state",
|
||||
"displayNameEvent": "Dummy int state changed",
|
||||
"defaultValue": 10,
|
||||
"graphRelevant": true,
|
||||
"type": "int"
|
||||
},
|
||||
{
|
||||
@ -136,8 +127,7 @@
|
||||
{
|
||||
"id": "45bf3752-0fc6-46b9-89fd-ffd878b5b22b",
|
||||
"name": "mockEvent1",
|
||||
"displayName": "Mock Event 1",
|
||||
"graphRelevant": true
|
||||
"displayName": "Mock Event 1"
|
||||
},
|
||||
{
|
||||
"id": "863d5920-b1cf-4eb9-88bd-8f7b8583b1cf",
|
||||
@ -201,15 +191,7 @@
|
||||
"name": "mockDeviceAuto",
|
||||
"displayName": "Mock Device (Auto created)",
|
||||
"interfaces": ["system"],
|
||||
"basicTags": [
|
||||
"Device",
|
||||
"Actuator",
|
||||
"Gateway"
|
||||
],
|
||||
"createMethods": ["auto"],
|
||||
"primaryActionTypeId": "defd3ed6-1a0d-400b-8879-a0202cf39935",
|
||||
"primaryStateTypeId": "80baec19-54de-4948-ac46-31eabfaceb83",
|
||||
"deviceIcon": "Tune",
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "d4f06047-125e-4479-9810-b54c189917f5",
|
||||
@ -240,7 +222,6 @@
|
||||
"displayName": "Dummy int state",
|
||||
"displayNameEvent": "Dummy int state changed",
|
||||
"defaultValue": 10,
|
||||
"graphRelevant": true,
|
||||
"type": "int"
|
||||
},
|
||||
{
|
||||
@ -321,14 +302,8 @@
|
||||
"name": "mockPushButton",
|
||||
"displayName": "Mock Device (Push Button)",
|
||||
"interfaces": ["system"],
|
||||
"basicTags": [
|
||||
"Device",
|
||||
"Actuator",
|
||||
"Gateway"
|
||||
],
|
||||
"createMethods": ["discovery"],
|
||||
"setupMethod": "pushButton",
|
||||
"deviceIcon": "Tune",
|
||||
"pairingInfo": "Wait 3 second before you continue, the push button will be pressed automatically.",
|
||||
"paramTypes": [ ],
|
||||
"discoveryParamTypes": [
|
||||
@ -350,8 +325,6 @@
|
||||
"displayNameAction": "Set color",
|
||||
"type": "QColor",
|
||||
"defaultValue": "#000000",
|
||||
"ruleRelevant": false,
|
||||
"eventRuleRelevant": false,
|
||||
"writable": true
|
||||
},
|
||||
{
|
||||
@ -363,7 +336,6 @@
|
||||
"type": "int",
|
||||
"unit": "Percentage",
|
||||
"defaultValue": 0,
|
||||
"ruleRelevant": false,
|
||||
"minValue": 0,
|
||||
"maxValue": 100,
|
||||
"writable": true
|
||||
@ -419,13 +391,7 @@
|
||||
"id": "296f1fd4-e893-46b2-8a42-50d1bceb8730",
|
||||
"name": "mockDisplayPin",
|
||||
"displayName": "Mock Device (Display Pin)",
|
||||
"deviceIcon": "Tune",
|
||||
"interfaces": ["system"],
|
||||
"basicTags": [
|
||||
"Device",
|
||||
"Actuator",
|
||||
"Gateway"
|
||||
],
|
||||
"createMethods": ["discovery"],
|
||||
"setupMethod": "displayPin",
|
||||
"pairingInfo": "Please enter the secret which normaly will be displayed on the device. For the mockdevice the pin is 243681.",
|
||||
@ -459,8 +425,6 @@
|
||||
"displayNameAction": "Set color",
|
||||
"type": "QColor",
|
||||
"defaultValue": "#000000",
|
||||
"ruleRelevant": false,
|
||||
"eventRuleRelevant": false,
|
||||
"writable": true
|
||||
},
|
||||
{
|
||||
@ -472,7 +436,6 @@
|
||||
"type": "int",
|
||||
"unit": "Percentage",
|
||||
"defaultValue": 0,
|
||||
"ruleRelevant": false,
|
||||
"minValue": 0,
|
||||
"maxValue": 100,
|
||||
"writable": true
|
||||
@ -528,13 +491,7 @@
|
||||
"id": "a71fbde9-9a38-4bf8-beab-c8aade2608ba",
|
||||
"name": "mockParent",
|
||||
"displayName": "Mock Device (Parent)",
|
||||
"deviceIcon": "Tune",
|
||||
"interfaces": ["system"],
|
||||
"basicTags": [
|
||||
"Device",
|
||||
"Actuator",
|
||||
"Gateway"
|
||||
],
|
||||
"createMethods": ["user"],
|
||||
"paramTypes": [ ],
|
||||
"stateTypes": [
|
||||
@ -556,10 +513,6 @@
|
||||
"displayName": "Mock Device (Child)",
|
||||
"createMethods": ["auto"],
|
||||
"paramTypes": [],
|
||||
"basicTags": [
|
||||
"Device",
|
||||
"Actuator"
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "d24ede5f-4064-4898-bb84-cfb533b1fbc0",
|
||||
@ -577,10 +530,6 @@
|
||||
"id": "515ffdf1-55e5-498d-9abc-4e2fe768f3a9",
|
||||
"name": "mockInputType",
|
||||
"displayName": "Mock Device (InputTypes)",
|
||||
"deviceIcon": "Tune",
|
||||
"basicTags": [
|
||||
"Device"
|
||||
],
|
||||
"createMethods": ["user"],
|
||||
"paramTypes": [
|
||||
{
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
1.14
|
||||
2.0
|
||||
{
|
||||
"methods": {
|
||||
"Actions.ExecuteAction": {
|
||||
@ -1008,6 +1008,15 @@
|
||||
"deviceId": "Uuid"
|
||||
}
|
||||
},
|
||||
"Devices.PluginConfigurationChanged": {
|
||||
"description": "Emitted whenever a plugin's configuration is changed.",
|
||||
"params": {
|
||||
"configuration": [
|
||||
"$ref:Param"
|
||||
],
|
||||
"pluginId": "Uuid"
|
||||
}
|
||||
},
|
||||
"Devices.StateChanged": {
|
||||
"description": "Emitted whenever a State of a device changes.",
|
||||
"params": {
|
||||
@ -1155,26 +1164,6 @@
|
||||
"$ref:ParamType"
|
||||
]
|
||||
},
|
||||
"BasicTag": [
|
||||
"BasicTagService",
|
||||
"BasicTagDevice",
|
||||
"BasicTagSensor",
|
||||
"BasicTagActuator",
|
||||
"BasicTagLighting",
|
||||
"BasicTagEnergy",
|
||||
"BasicTagMultimedia",
|
||||
"BasicTagWeather",
|
||||
"BasicTagGateway",
|
||||
"BasicTagHeating",
|
||||
"BasicTagCooling",
|
||||
"BasicTagNotification",
|
||||
"BasicTagSecurity",
|
||||
"BasicTagTime",
|
||||
"BasicTagShading",
|
||||
"BasicTagAppliance",
|
||||
"BasicTagCamera",
|
||||
"BasicTagLock"
|
||||
],
|
||||
"BasicType": [
|
||||
"Uuid",
|
||||
"String",
|
||||
@ -1235,13 +1224,9 @@
|
||||
"actionTypes": [
|
||||
"$ref:ActionType"
|
||||
],
|
||||
"basicTags": [
|
||||
"$ref:BasicTag"
|
||||
],
|
||||
"createMethods": [
|
||||
"$ref:CreateMethod"
|
||||
],
|
||||
"deviceIcon": "$ref:DeviceIcon",
|
||||
"discoveryParamTypes": [
|
||||
"$ref:ParamType"
|
||||
],
|
||||
@ -1254,9 +1239,6 @@
|
||||
"String"
|
||||
],
|
||||
"name": "String",
|
||||
"o:criticalStateTypeId": "Uuid",
|
||||
"o:primaryActionTypeId": "Uuid",
|
||||
"o:primaryStateTypeId": "Uuid",
|
||||
"paramTypes": [
|
||||
"$ref:ParamType"
|
||||
],
|
||||
@ -1302,44 +1284,6 @@
|
||||
"DeviceErrorPairingTransactionIdNotFound",
|
||||
"DeviceErrorParameterNotWritable"
|
||||
],
|
||||
"DeviceIcon": [
|
||||
"DeviceIconNone",
|
||||
"DeviceIconBed",
|
||||
"DeviceIconBlinds",
|
||||
"DeviceIconCeilingLamp",
|
||||
"DeviceIconCouch",
|
||||
"DeviceIconDeskLamp",
|
||||
"DeviceIconDesk",
|
||||
"DeviceIconHifi",
|
||||
"DeviceIconPower",
|
||||
"DeviceIconEnergy",
|
||||
"DeviceIconRadio",
|
||||
"DeviceIconSmartPhone",
|
||||
"DeviceIconSocket",
|
||||
"DeviceIconStandardLamp",
|
||||
"DeviceIconSun",
|
||||
"DeviceIconTablet",
|
||||
"DeviceIconThermometer",
|
||||
"DeviceIconTune",
|
||||
"DeviceIconTv",
|
||||
"DeviceIconBattery",
|
||||
"DeviceIconDishwasher",
|
||||
"DeviceIconWashingMachine",
|
||||
"DeviceIconLaundryDryer",
|
||||
"DeviceIconIrHeater",
|
||||
"DeviceIconRadiator",
|
||||
"DeviceIconSwitch",
|
||||
"DeviceIconMotionDetectors",
|
||||
"DeviceIconWeather",
|
||||
"DeviceIconTime",
|
||||
"DeviceIconLightBulb",
|
||||
"DeviceIconGateway",
|
||||
"DeviceIconMail",
|
||||
"DeviceIconNetwork",
|
||||
"DeviceIconCloud",
|
||||
"DeviceIconGarage",
|
||||
"DeviceIconRollerShutter"
|
||||
],
|
||||
"Event": {
|
||||
"deviceId": "Uuid",
|
||||
"eventTypeId": "Uuid",
|
||||
@ -1361,8 +1305,6 @@
|
||||
"id": "Uuid",
|
||||
"index": "Int",
|
||||
"name": "String",
|
||||
"o:graphRelevant": "Bool",
|
||||
"o:ruleRelevant": "Bool",
|
||||
"paramTypes": [
|
||||
"$ref:ParamType"
|
||||
]
|
||||
@ -1619,13 +1561,11 @@
|
||||
"id": "Uuid",
|
||||
"index": "Int",
|
||||
"name": "String",
|
||||
"o:graphRelevant": "Bool",
|
||||
"o:maxValue": "Variant",
|
||||
"o:minValue": "Variant",
|
||||
"o:possibleValues": [
|
||||
"Variant"
|
||||
],
|
||||
"o:ruleRelevant": "Bool",
|
||||
"o:unit": "$ref:Unit",
|
||||
"type": "$ref:BasicType"
|
||||
},
|
||||
|
||||
@ -133,25 +133,22 @@ void TestJSONRPC::initTestCase()
|
||||
{
|
||||
NymeaTestBase::initTestCase();
|
||||
QLoggingCategory::setFilterRules("*.debug=false\n"
|
||||
// "JsonRpc*.debug=true\n"
|
||||
// "JsonRpcTraffic.debug=true\n"
|
||||
"JsonRpc.debug=true\n"
|
||||
"Translations.debug=true\n"
|
||||
"Tests.debug=true");
|
||||
}
|
||||
|
||||
void TestJSONRPC::testHandshake()
|
||||
{
|
||||
// first test if the handshake message is auto-sent upon connecting
|
||||
QSignalSpy spy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
|
||||
|
||||
QUuid newClientId = QUuid::createUuid();
|
||||
m_mockTcpServer->clientConnected(newClientId);
|
||||
QVERIFY2(spy.count() > 0, "Did not get the handshake message upon connect.");
|
||||
QVERIFY2(spy.first().first() == newClientId, "Handshake message addressed at the wrong client.");
|
||||
qApp->processEvents();
|
||||
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
|
||||
QVariantMap handShake = jsonDoc.toVariant().toMap();
|
||||
// Check the Hello reply
|
||||
QVariantMap handShake = injectAndWait("JSONRPC.Hello", QVariantMap(), newClientId).toMap();
|
||||
QString nymeaVersionString(NYMEA_VERSION_STRING);
|
||||
QVERIFY2(handShake.value("version").toString() == nymeaVersionString, "Handshake version doesn't match nymea version.");
|
||||
QVERIFY2(handShake.value("params").toMap().value("version").toString() == nymeaVersionString, "Handshake version doesn't match nymea version.");
|
||||
|
||||
// Check whether pushButtonAuth is disabled
|
||||
QCOMPARE(handShake.value("pushButtonAuthAvailable").toBool(), false);
|
||||
@ -164,11 +161,12 @@ void TestJSONRPC::testHandshake()
|
||||
handShake = injectAndWait("JSONRPC.Hello").toMap();
|
||||
QCOMPARE(handShake.value("params").toMap().value("version").toString(), nymeaVersionString);
|
||||
|
||||
m_mockTcpServer->clientDisconnected(newClientId);
|
||||
|
||||
// Check whether pushButtonAuth is now
|
||||
// Check whether pushButtonAuth is now enabled
|
||||
QCOMPARE(handShake.value("params").toMap().value("pushButtonAuthAvailable").toBool(), true);
|
||||
|
||||
emit m_mockTcpServer->clientDisconnected(newClientId);
|
||||
|
||||
|
||||
// And now check if it is sent again when calling JSONRPC.Hello
|
||||
handShake = injectAndWait("JSONRPC.Hello").toMap();
|
||||
QCOMPARE(handShake.value("params").toMap().value("version").toString(), nymeaVersionString);
|
||||
@ -222,8 +220,11 @@ void TestJSONRPC::testInitialSetup()
|
||||
|
||||
QSignalSpy spy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
|
||||
QVERIFY(spy.isValid());
|
||||
QSignalSpy connectedSpy(m_mockTcpServer, &MockTcpServer::clientConnected);
|
||||
QSignalSpy disconnectedSpy(m_mockTcpServer, &MockTcpServer::clientDisconnected);
|
||||
|
||||
// Introspect call should work in any case
|
||||
qCDebug(dcTests()) << "Calling Introspect, expecting success";
|
||||
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.Introspect\"}\n");
|
||||
if (spy.count() == 0) {
|
||||
spy.wait();
|
||||
@ -231,12 +232,13 @@ void TestJSONRPC::testInitialSetup()
|
||||
QVERIFY(spy.count() == 1);
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
|
||||
QVariantMap response = jsonDoc.toVariant().toMap();
|
||||
qWarning() << "Calling introspect on uninitialized instance:" << response.value("status").toString() << response.value("error").toString();
|
||||
qCDebug(dcTests()) << "Result:" << response.value("status").toString() << response.value("error").toString();
|
||||
QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
|
||||
|
||||
|
||||
// Hello call should work in any case too
|
||||
spy.clear();
|
||||
qCDebug(dcTests()) << "Calling Hello, expecting success";
|
||||
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.Hello\"}\n");
|
||||
if (spy.count() == 0) {
|
||||
spy.wait();
|
||||
@ -244,12 +246,14 @@ void TestJSONRPC::testInitialSetup()
|
||||
QVERIFY(spy.count() == 1);
|
||||
jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
|
||||
response = jsonDoc.toVariant().toMap();
|
||||
qWarning() << "Calling Hello on uninitialized instance:" << response.value("status").toString() << response.value("error").toString();
|
||||
qCDebug(dcTests()) << "Result:" << response.value("status").toString() << response.value("error").toString();
|
||||
QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
|
||||
QCOMPARE(response.value("params").toMap().value("initialSetupRequired").toBool(), true);
|
||||
|
||||
// Any other call should fail with "unauthorized" even if we use a previously valid token
|
||||
spy.clear();
|
||||
disconnectedSpy.clear();
|
||||
qCDebug(dcTests()) << "Calling Version, expecting failure (unauthenticated)";
|
||||
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"token\": \"" + m_apiToken + "\", \"method\": \"JSONRPC.Version\"}\n");
|
||||
if (spy.count() == 0) {
|
||||
spy.wait();
|
||||
@ -257,13 +261,31 @@ void TestJSONRPC::testInitialSetup()
|
||||
QVERIFY(spy.count() == 1);
|
||||
jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
|
||||
response = jsonDoc.toVariant().toMap();
|
||||
qWarning() << "Calling Version on uninitialized instance:" << response.value("status").toString() << response.value("error").toString();
|
||||
qCDebug(dcTests()) << "Result:" << response.value("status").toString() << response.value("error").toString();
|
||||
QCOMPARE(response.value("status").toString(), QStringLiteral("unauthorized"));
|
||||
|
||||
// Connection should terminate
|
||||
if (disconnectedSpy.count() == 0) disconnectedSpy.wait();
|
||||
QCOMPARE(disconnectedSpy.count(), 1);
|
||||
qCDebug(dcTests()) << "Mock client disconnected";
|
||||
connectedSpy.clear();
|
||||
emit m_mockTcpServer->clientConnected(m_clientId);
|
||||
if (connectedSpy.count() == 0) connectedSpy.wait();
|
||||
QCOMPARE(connectedSpy.count(), 1);
|
||||
qCDebug(dcTests()) << "Mock client connected";
|
||||
|
||||
spy.clear();
|
||||
m_mockTcpServer->injectData(m_clientId, "{\"id\": 0, \"method\": \"JSONRPC.Hello\"}");
|
||||
if (spy.count() == 0) {
|
||||
spy.wait();
|
||||
}
|
||||
QVERIFY(spy.count() == 1);
|
||||
|
||||
// Except CreateUser
|
||||
|
||||
// But it should still fail when giving a an invalid username
|
||||
spy.clear();
|
||||
qCDebug(dcTests()) << "Calling CreateUser, expecting failure (bad username)";
|
||||
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.CreateUser\", \"params\": {\"username\": \"dummy\", \"password\": \"DummyPW1!\"}}\n");
|
||||
if (spy.count() == 0) {
|
||||
spy.wait();
|
||||
@ -271,12 +293,13 @@ void TestJSONRPC::testInitialSetup()
|
||||
QVERIFY(spy.count() == 1);
|
||||
jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
|
||||
response = jsonDoc.toVariant().toMap();
|
||||
qWarning() << "Calling CreateUser on uninitialized instance with invalid user:" << response.value("status").toString() << response.value("params").toMap().value("error").toString();
|
||||
qCDebug(dcTests()) << "Calling CreateUser on uninitialized instance with invalid user:" << response.value("status").toString() << response.value("params").toMap().value("error").toString();
|
||||
QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
|
||||
QCOMPARE(NymeaCore::instance()->userManager()->users().count(), 0);
|
||||
|
||||
// or when giving a bad password
|
||||
spy.clear();
|
||||
qCDebug(dcTests()) << "Calling CreateUser, expecting failure (bad password)";
|
||||
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.CreateUser\", \"params\": {\"username\": \"dummy@guh.io\", \"password\": \"weak\"}}\n");
|
||||
if (spy.count() == 0) {
|
||||
spy.wait();
|
||||
@ -284,12 +307,13 @@ void TestJSONRPC::testInitialSetup()
|
||||
QVERIFY(spy.count() == 1);
|
||||
jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
|
||||
response = jsonDoc.toVariant().toMap();
|
||||
qWarning() << "Calling CreateUser on uninitialized instance with weak password:" << response.value("status").toString() << response.value("params").toMap().value("error").toString();
|
||||
qCDebug(dcTests()) << "Calling CreateUser on uninitialized instance with weak password:" << response.value("status").toString() << response.value("params").toMap().value("error").toString();
|
||||
QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
|
||||
QCOMPARE(NymeaCore::instance()->userManager()->users().count(), 0);
|
||||
|
||||
// Now lets play by the rules (with an uppercase email)
|
||||
spy.clear();
|
||||
qCDebug(dcTests()) << "Calling CreateUser, expecting success";
|
||||
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.CreateUser\", \"params\": {\"username\": \"Dummy@guh.io\", \"password\": \"DummyPW1!\"}}\n");
|
||||
if (spy.count() == 0) {
|
||||
spy.wait();
|
||||
@ -297,12 +321,13 @@ void TestJSONRPC::testInitialSetup()
|
||||
QVERIFY(spy.count() == 1);
|
||||
jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
|
||||
response = jsonDoc.toVariant().toMap();
|
||||
qWarning() << "Calling CreateUser on uninitialized instance:" << response.value("status").toString() << response.value("error").toString();
|
||||
qCDebug(dcTests) << "Calling CreateUser on uninitialized instance:" << response.value("status").toString() << response.value("error").toString();
|
||||
QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
|
||||
QCOMPARE(NymeaCore::instance()->userManager()->users().count(), 1);
|
||||
|
||||
// Now that we have a user, initialSetup should be false in the Hello call
|
||||
spy.clear();
|
||||
qCDebug(dcTests()) << "Calling Hello, expecting success";
|
||||
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.Hello\"}\n");
|
||||
if (spy.count() == 0) {
|
||||
spy.wait();
|
||||
@ -310,12 +335,14 @@ void TestJSONRPC::testInitialSetup()
|
||||
QVERIFY(spy.count() == 1);
|
||||
jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
|
||||
response = jsonDoc.toVariant().toMap();
|
||||
qWarning() << "Calling Hello on initialized instance:" << response.value("status").toString() << response.value("error").toString();
|
||||
qCDebug(dcTests) << "Calling Hello on initialized instance:" << response.value("status").toString() << response.value("error").toString();
|
||||
QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
|
||||
QCOMPARE(response.value("params").toMap().value("initialSetupRequired").toBool(), false);
|
||||
|
||||
// Calls should still fail, given we didn't get a new token yet
|
||||
spy.clear();
|
||||
disconnectedSpy.clear();
|
||||
qCDebug(dcTests()) << "Calling Version, expecting failure (bad token)";
|
||||
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"token\": \"" + m_apiToken + "\", \"method\": \"JSONRPC.Version\"}\n");
|
||||
if (spy.count() == 0) {
|
||||
spy.wait();
|
||||
@ -323,11 +350,30 @@ void TestJSONRPC::testInitialSetup()
|
||||
QVERIFY(spy.count() == 1);
|
||||
jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
|
||||
response = jsonDoc.toVariant().toMap();
|
||||
qWarning() << "Calling Version with old token:" << response.value("status").toString() << response.value("error").toString();
|
||||
qCDebug(dcTests) << "Calling Version with old token:" << response.value("status").toString() << response.value("error").toString();
|
||||
QCOMPARE(response.value("status").toString(), QStringLiteral("unauthorized"));
|
||||
|
||||
// Connection should terminate
|
||||
if (disconnectedSpy.count() == 0) disconnectedSpy.wait();
|
||||
QCOMPARE(disconnectedSpy.count(), 1);
|
||||
qCDebug(dcTests()) << "Mock client disconnected";
|
||||
connectedSpy.clear();
|
||||
emit m_mockTcpServer->clientConnected(m_clientId);
|
||||
if (connectedSpy.count() == 0) connectedSpy.wait();
|
||||
QCOMPARE(connectedSpy.count(), 1);
|
||||
qCDebug(dcTests()) << "Mock client connected";
|
||||
|
||||
spy.clear();
|
||||
m_mockTcpServer->injectData(m_clientId, "{\"id\": 0, \"method\": \"JSONRPC.Hello\"}");
|
||||
if (spy.count() == 0) {
|
||||
spy.wait();
|
||||
}
|
||||
QVERIFY(spy.count() == 1);
|
||||
|
||||
|
||||
// Now lets authenticate with a wrong user
|
||||
spy.clear();
|
||||
qCDebug(dcTests()) << "Calling Authenticate, expecting failure (bad user)";
|
||||
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.Authenticate\", \"params\": {\"username\": \"Dummy@wrong.domain\", \"password\": \"DummyPW1!\", \"deviceName\": \"testcase\"}}\n");
|
||||
if (spy.count() == 0) {
|
||||
spy.wait();
|
||||
@ -335,7 +381,7 @@ void TestJSONRPC::testInitialSetup()
|
||||
QVERIFY(spy.count() == 1);
|
||||
jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
|
||||
response = jsonDoc.toVariant().toMap();
|
||||
qWarning() << "Calling Authenticate with wrong user:" << response.value("params").toMap().value("success").toString() << response.value("params").toMap().value("token").toString();
|
||||
qCDebug(dcTests()) << "Calling Authenticate with wrong user:" << response.value("params").toMap().value("success").toString() << response.value("params").toMap().value("token").toString();
|
||||
QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
|
||||
QCOMPARE(response.value("params").toMap().value("success").toBool(), false);
|
||||
QVERIFY(response.value("params").toMap().value("token").toByteArray().isEmpty());
|
||||
@ -343,6 +389,7 @@ void TestJSONRPC::testInitialSetup()
|
||||
|
||||
// Now lets authenticate with a wrong password
|
||||
spy.clear();
|
||||
qCDebug(dcTests()) << "Calling Authenticate, expecting failure (bad password)";
|
||||
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.Authenticate\", \"params\": {\"username\": \"Dummy@guh.io\", \"password\": \"wrongpw\", \"deviceName\": \"testcase\"}}\n");
|
||||
if (spy.count() == 0) {
|
||||
spy.wait();
|
||||
@ -350,7 +397,7 @@ void TestJSONRPC::testInitialSetup()
|
||||
QVERIFY(spy.count() == 1);
|
||||
jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
|
||||
response = jsonDoc.toVariant().toMap();
|
||||
qWarning() << "Calling Authenticate with wrong password:" << response.value("params").toMap().value("success").toString() << response.value("params").toMap().value("token").toString();
|
||||
qCDebug(dcTests()) << "Calling Authenticate with wrong password:" << response.value("params").toMap().value("success").toString() << response.value("params").toMap().value("token").toString();
|
||||
QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
|
||||
QCOMPARE(response.value("params").toMap().value("success").toBool(), false);
|
||||
QVERIFY(response.value("params").toMap().value("token").toByteArray().isEmpty());
|
||||
@ -358,6 +405,7 @@ void TestJSONRPC::testInitialSetup()
|
||||
|
||||
// Now lets authenticate for real (but intentionally use a lowercase email here, should still work)
|
||||
spy.clear();
|
||||
qCDebug(dcTests()) << "Calling Authenticate, expecting success";
|
||||
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.Authenticate\", \"params\": {\"username\": \"dummy@guh.io\", \"password\": \"DummyPW1!\", \"deviceName\": \"testcase\"}}\n");
|
||||
if (spy.count() == 0) {
|
||||
spy.wait();
|
||||
@ -365,7 +413,7 @@ void TestJSONRPC::testInitialSetup()
|
||||
QVERIFY(spy.count() == 1);
|
||||
jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
|
||||
response = jsonDoc.toVariant().toMap();
|
||||
qWarning() << "Calling Authenticate with valid credentials:" << response.value("params").toMap().value("success").toString() << response.value("params").toMap().value("token").toString();
|
||||
qCDebug(dcTests()) << "Calling Authenticate with valid credentials:" << response.value("params").toMap().value("success").toString() << response.value("params").toMap().value("token").toString();
|
||||
QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
|
||||
QCOMPARE(response.value("params").toMap().value("success").toBool(), true);
|
||||
m_apiToken = response.value("params").toMap().value("token").toByteArray();
|
||||
@ -373,6 +421,7 @@ void TestJSONRPC::testInitialSetup()
|
||||
|
||||
// Now do a Version call with the valid token and it should work
|
||||
spy.clear();
|
||||
qCDebug(dcTests()) << "Calling Version, expecting success";
|
||||
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"token\": \"" + m_apiToken + "\", \"method\": \"JSONRPC.Version\"}\n");
|
||||
if (spy.count() == 0) {
|
||||
spy.wait();
|
||||
@ -380,15 +429,19 @@ void TestJSONRPC::testInitialSetup()
|
||||
QVERIFY(spy.count() == 1);
|
||||
jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
|
||||
response = jsonDoc.toVariant().toMap();
|
||||
qWarning() << "Calling Version with valid token:" << response.value("status").toString() << response.value("error").toString();
|
||||
qCDebug(dcTests()) << "Calling Version with valid token:" << response.value("status").toString() << response.value("error").toString();
|
||||
QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
|
||||
|
||||
}
|
||||
|
||||
void TestJSONRPC::testRevokeToken()
|
||||
{
|
||||
QSignalSpy spy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
|
||||
QSignalSpy spy(m_mockTcpServer, &MockTcpServer::outgoingData);
|
||||
QVERIFY(spy.isValid());
|
||||
QSignalSpy disconnectedSpy(m_mockTcpServer, &MockTcpServer::clientDisconnected);
|
||||
QVERIFY(disconnectedSpy.isValid());
|
||||
QSignalSpy connectedSpy(m_mockTcpServer, &MockTcpServer::clientConnected);
|
||||
QVERIFY(connectedSpy.isValid());
|
||||
|
||||
// Now get all the tokens
|
||||
spy.clear();
|
||||
@ -399,7 +452,7 @@ void TestJSONRPC::testRevokeToken()
|
||||
QVERIFY(spy.count() == 1);
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
|
||||
QVariantMap response = jsonDoc.toVariant().toMap();
|
||||
qWarning() << "Getting existing Tokens" << response.value("status").toString() << response;
|
||||
qCDebug(dcTests()) << "Getting existing Tokens" << response.value("status").toString() << response;
|
||||
QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
|
||||
QVariantList tokenList = response.value("params").toMap().value("tokenInfoList").toList();
|
||||
QCOMPARE(tokenList.count(), 1);
|
||||
@ -414,7 +467,7 @@ void TestJSONRPC::testRevokeToken()
|
||||
QVERIFY(spy.count() == 1);
|
||||
jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
|
||||
response = jsonDoc.toVariant().toMap();
|
||||
qWarning() << "Calling Authenticate with valid credentials:" << response.value("params").toMap().value("success").toString() << response.value("params").toMap().value("token").toString();
|
||||
qCDebug(dcTests()) << "Calling Authenticate with valid credentials:" << response.value("params").toMap().value("success").toString() << response.value("params").toMap().value("token").toString();
|
||||
QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
|
||||
QCOMPARE(response.value("params").toMap().value("success").toBool(), true);
|
||||
QByteArray newToken = response.value("params").toMap().value("token").toByteArray();
|
||||
@ -429,7 +482,7 @@ void TestJSONRPC::testRevokeToken()
|
||||
QVERIFY(spy.count() == 1);
|
||||
jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
|
||||
response = jsonDoc.toVariant().toMap();
|
||||
qWarning() << "Calling Version with valid token:" << response.value("status").toString() << response.value("error").toString();
|
||||
qCDebug(dcTests()) << "Calling Version with valid token:" << response.value("status").toString() << response.value("error").toString();
|
||||
QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
|
||||
|
||||
// Now get all the tokens using the old token
|
||||
@ -441,7 +494,7 @@ void TestJSONRPC::testRevokeToken()
|
||||
QVERIFY(spy.count() == 1);
|
||||
jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
|
||||
response = jsonDoc.toVariant().toMap();
|
||||
qWarning() << "Calling Tokens" << response.value("status").toString();
|
||||
qCDebug(dcTests()) << "Calling Tokens" << response.value("status").toString();
|
||||
QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
|
||||
tokenList = response.value("params").toMap().value("tokenInfoList").toList();
|
||||
QCOMPARE(tokenList.count(), 2);
|
||||
@ -464,11 +517,12 @@ void TestJSONRPC::testRevokeToken()
|
||||
QVERIFY(spy.count() == 1);
|
||||
jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
|
||||
response = jsonDoc.toVariant().toMap();
|
||||
qWarning() << "Calling RemoveToken" << response.value("status").toString() << response;
|
||||
qCDebug(dcTests()) << "Calling RemoveToken" << response.value("status").toString() << response;
|
||||
QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
|
||||
|
||||
// Do a call with the now removed token, it should be forbidden
|
||||
spy.clear();
|
||||
disconnectedSpy.clear();
|
||||
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"token\": \"" + newToken + "\", \"method\": \"JSONRPC.Version\"}\n");
|
||||
if (spy.count() == 0) {
|
||||
spy.wait();
|
||||
@ -476,8 +530,19 @@ void TestJSONRPC::testRevokeToken()
|
||||
QVERIFY(spy.count() == 1);
|
||||
jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
|
||||
response = jsonDoc.toVariant().toMap();
|
||||
qWarning() << "Calling Version with valid token:" << response.value("status").toString() << response.value("error").toString();
|
||||
qCDebug(dcTests()) << "Calling Version with valid token:" << response.value("status").toString() << response.value("error").toString();
|
||||
QCOMPARE(response.value("status").toString(), QStringLiteral("unauthorized"));
|
||||
|
||||
// And connection should drop
|
||||
if (disconnectedSpy.count() == 0) disconnectedSpy.wait();
|
||||
QCOMPARE(disconnectedSpy.count(), 1);
|
||||
|
||||
// Connect again to not impact subsequent tests...
|
||||
connectedSpy.clear();
|
||||
emit m_mockTcpServer->clientConnected(m_clientId);
|
||||
if (connectedSpy.count() == 0) connectedSpy.wait();
|
||||
QCOMPARE(connectedSpy.count(), 1);
|
||||
injectAndWait("JSONRPC.Hello");
|
||||
}
|
||||
|
||||
void TestJSONRPC::testBasicCall_data()
|
||||
@ -492,9 +557,9 @@ void TestJSONRPC::testBasicCall_data()
|
||||
QTest::newRow("missing id") << QByteArray("{\"method\":\"JSONRPC.Introspect\"}\n") << false << false;
|
||||
QTest::newRow("missing method") << QByteArray("{\"id\":42}\n") << true << false;
|
||||
QTest::newRow("borked") << QByteArray("{\"id\":42, \"method\":\"JSO}\n") << false << false;
|
||||
QTest::newRow("invalid function") << QByteArray("{\"id\":42, \"method\":\"JSONRPC.Foobar\"}\n") << true << false;
|
||||
QTest::newRow("invalid namespace") << QByteArray("{\"id\":42, \"method\":\"FOO.Introspect\"}\n") << true << false;
|
||||
QTest::newRow("missing dot") << QByteArray("{\"id\":42, \"method\":\"JSONRPCIntrospect\"}\n") << true << false;
|
||||
QTest::newRow("invalid function") << QByteArray("{\"id\":42, \"method\":\"JSONRPC.Foobar\", \"token\": \"" + m_apiToken + "\"}\n") << true << false;
|
||||
QTest::newRow("invalid namespace") << QByteArray("{\"id\":42, \"method\":\"FOO.Introspect\", \"token\": \"" + m_apiToken + "\"}\n") << true << false;
|
||||
QTest::newRow("missing dot") << QByteArray("{\"id\":42, \"method\":\"JSONRPCIntrospect\", \"token\": \"" + m_apiToken + "\"}\n") << true << false;
|
||||
QTest::newRow("invalid params") << QByteArray("{\"id\":42, \"method\":\"JSONRPC.Introspect\", \"params\":{\"törööö\":\"chooo-chooo\"}}\n") << true << false;
|
||||
}
|
||||
|
||||
@ -594,7 +659,7 @@ void TestJSONRPC::deviceAddedRemovedNotifications()
|
||||
params.insert("name", "Mock device");
|
||||
params.insert("deviceParams", deviceParams);
|
||||
QVariant response = injectAndWait("Devices.AddConfiguredDevice", params);
|
||||
clientSpy.wait(2000);
|
||||
if (clientSpy.count() == 0) clientSpy.wait();
|
||||
verifyDeviceError(response);
|
||||
QVariantMap notificationDeviceMap = checkNotification(clientSpy, "Devices.DeviceAdded").toMap().value("params").toMap().value("device").toMap();
|
||||
|
||||
@ -614,7 +679,7 @@ void TestJSONRPC::deviceAddedRemovedNotifications()
|
||||
params.clear(); response.clear(); clientSpy.clear();
|
||||
params.insert("deviceId", deviceId);
|
||||
response = injectAndWait("Devices.RemoveConfiguredDevice", params);
|
||||
clientSpy.wait(2000);
|
||||
if (clientSpy.count() == 0) clientSpy.wait();
|
||||
verifyDeviceError(response);
|
||||
checkNotification(clientSpy, "Devices.DeviceRemoved");
|
||||
|
||||
@ -659,7 +724,7 @@ void TestJSONRPC::ruleAddedRemovedNotifications()
|
||||
params.insert("stateEvaluator", stateEvaluator);
|
||||
|
||||
QVariant response = injectAndWait("Rules.AddRule", params);
|
||||
clientSpy.wait(2000);
|
||||
if (clientSpy.count() == 0) clientSpy.wait();
|
||||
QVariantMap notificationRuleMap = checkNotification(clientSpy, "Rules.RuleAdded").toMap().value("params").toMap().value("rule").toMap();
|
||||
verifyRuleError(response);
|
||||
|
||||
@ -678,7 +743,7 @@ void TestJSONRPC::ruleAddedRemovedNotifications()
|
||||
params.clear(); response.clear(); clientSpy.clear();
|
||||
params.insert("ruleId", ruleId);
|
||||
response = injectAndWait("Rules.RemoveRule", params);
|
||||
clientSpy.wait(2000);
|
||||
if (clientSpy.count() == 0) clientSpy.wait();
|
||||
checkNotification(clientSpy, "Devices.DeviceRemoved");
|
||||
verifyRuleError(response);
|
||||
|
||||
@ -719,7 +784,7 @@ void TestJSONRPC::ruleActiveChangedNotifications()
|
||||
QSignalSpy clientSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
|
||||
|
||||
response = injectAndWait("Rules.AddRule", params);
|
||||
clientSpy.wait();
|
||||
if (clientSpy.count() == 0) clientSpy.wait();
|
||||
QVariant notificationVariant = checkNotification(clientSpy, "Rules.RuleAdded");
|
||||
verifyRuleError(response);
|
||||
|
||||
@ -743,7 +808,7 @@ void TestJSONRPC::ruleActiveChangedNotifications()
|
||||
QNetworkReply *reply = nam.get(request);
|
||||
connect(reply, SIGNAL(finished()), reply, SLOT(deleteLater()));
|
||||
|
||||
spy.wait();
|
||||
if (spy.count() == 0) spy.wait();
|
||||
notificationVariant = checkNotification(clientSpy, "Rules.RuleActiveChanged");
|
||||
verifyRuleError(response);
|
||||
|
||||
@ -756,12 +821,12 @@ void TestJSONRPC::ruleActiveChangedNotifications()
|
||||
qDebug() << "setting mock int state to 42";
|
||||
QNetworkRequest request2(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockIntStateId.toString()).arg(42)));
|
||||
QNetworkReply *reply2 = nam.get(request2);
|
||||
spy.wait();
|
||||
if (spy.count() == 0) spy.wait();
|
||||
QCOMPARE(spy.count(), 1);
|
||||
connect(reply2, SIGNAL(finished()), reply2, SLOT(deleteLater()));
|
||||
|
||||
|
||||
clientSpy.wait();
|
||||
if (clientSpy.count() == 0) clientSpy.wait();
|
||||
notificationVariant = checkNotification(clientSpy, "Rules.RuleActiveChanged");
|
||||
verifyRuleError(response);
|
||||
|
||||
@ -773,7 +838,7 @@ void TestJSONRPC::ruleActiveChangedNotifications()
|
||||
params.insert("ruleId", ruleId);
|
||||
response = injectAndWait("Rules.RemoveRule", params);
|
||||
|
||||
clientSpy.wait();
|
||||
if (clientSpy.count() == 0) clientSpy.wait();
|
||||
notificationVariant = checkNotification(clientSpy, "Rules.RuleRemoved");
|
||||
checkNotification(clientSpy, "Logging.LogDatabaseUpdated");
|
||||
verifyRuleError(response);
|
||||
@ -807,7 +872,7 @@ void TestJSONRPC::deviceChangedNotifications()
|
||||
response = injectAndWait("Devices.AddConfiguredDevice", params);
|
||||
DeviceId deviceId = DeviceId(response.toMap().value("params").toMap().value("deviceId").toString());
|
||||
QVERIFY(!deviceId.isNull());
|
||||
clientSpy.wait();
|
||||
if (clientSpy.count() == 0) clientSpy.wait();
|
||||
verifyDeviceError(response);
|
||||
QVariantMap notificationDeviceMap = checkNotification(clientSpy, "Devices.DeviceAdded").toMap().value("params").toMap().value("device").toMap();
|
||||
|
||||
@ -831,7 +896,7 @@ void TestJSONRPC::deviceChangedNotifications()
|
||||
params.insert("deviceId", deviceId);
|
||||
params.insert("deviceParams", newDeviceParams);
|
||||
response = injectAndWait("Devices.ReconfigureDevice", params);
|
||||
clientSpy.wait(2000);
|
||||
if (clientSpy.count() == 0) clientSpy.wait();
|
||||
verifyDeviceError(response);
|
||||
QVariantMap reconfigureDeviceNotificationMap = checkNotification(clientSpy, "Devices.DeviceChanged").toMap().value("params").toMap().value("device").toMap();
|
||||
QCOMPARE(reconfigureDeviceNotificationMap.value("deviceClassId").toString(), mockDeviceClassId.toString());
|
||||
@ -848,7 +913,7 @@ void TestJSONRPC::deviceChangedNotifications()
|
||||
params.insert("deviceId", deviceId);
|
||||
params.insert("name", deviceName);
|
||||
response = injectAndWait("Devices.EditDevice", params);
|
||||
clientSpy.wait(2000);
|
||||
if (clientSpy.count() == 0) clientSpy.wait();
|
||||
verifyDeviceError(response);
|
||||
QVariantMap editDeviceNotificationMap = checkNotification(clientSpy, "Devices.DeviceChanged").toMap().value("params").toMap().value("device").toMap();
|
||||
QCOMPARE(editDeviceNotificationMap.value("deviceClassId").toString(), mockDeviceClassId.toString());
|
||||
@ -860,7 +925,7 @@ void TestJSONRPC::deviceChangedNotifications()
|
||||
params.clear(); response.clear(); clientSpy.clear();
|
||||
params.insert("deviceId", deviceId);
|
||||
response = injectAndWait("Devices.RemoveConfiguredDevice", params);
|
||||
clientSpy.wait();
|
||||
if (clientSpy.count() == 0) clientSpy.wait();
|
||||
verifyDeviceError(response);
|
||||
checkNotification(clientSpy, "Devices.DeviceRemoved");
|
||||
checkNotification(clientSpy, "Logging.LogDatabaseUpdated");
|
||||
@ -882,7 +947,7 @@ void TestJSONRPC::stateChangeEmitsNotifications()
|
||||
QNetworkReply *reply = nam.get(request);
|
||||
connect(reply, SIGNAL(finished()), reply, SLOT(deleteLater()));
|
||||
QSignalSpy replySpy(reply, SIGNAL(finished()));
|
||||
replySpy.wait();
|
||||
if (replySpy.count() == 0) replySpy.wait();
|
||||
|
||||
// Make sure the notification contains all the stuff we expect
|
||||
QVariantList stateChangedVariants = checkNotifications(clientSpy, "Devices.StateChanged");
|
||||
@ -1001,9 +1066,7 @@ void TestJSONRPC::testPushButtonAuth()
|
||||
|
||||
pushButtonAgent.sendButtonPressed();
|
||||
|
||||
if (clientSpy.count() == 0) {
|
||||
clientSpy.wait();
|
||||
}
|
||||
if (clientSpy.count() == 0) clientSpy.wait();
|
||||
QVariantMap rsp = checkNotification(clientSpy, "JSONRPC.PushButtonAuthFinished").toMap();
|
||||
|
||||
QCOMPARE(rsp.value("params").toMap().value("transactionId").toInt(), transactionId);
|
||||
@ -1023,6 +1086,9 @@ void TestJSONRPC::testPushButtonAuthInterrupt()
|
||||
// Create a new clientId for mallory and connect it to the server
|
||||
QUuid malloryId = QUuid::createUuid();
|
||||
m_mockTcpServer->clientConnected(malloryId);
|
||||
QSignalSpy responseSpy(m_mockTcpServer, &MockTcpServer::outgoingData);
|
||||
m_mockTcpServer->injectData(malloryId, "{\"id\": 0, \"method\": \"JSONRPC.Hello\"}");
|
||||
if (responseSpy.count() == 0) responseSpy.wait();
|
||||
|
||||
// Snoop in on everything the TCP server sends to its clients.
|
||||
QSignalSpy clientSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
|
||||
@ -1120,11 +1186,13 @@ void TestJSONRPC::testPushButtonAuthConnectionDrop()
|
||||
pushButtonAgent.init();
|
||||
|
||||
// Snoop in on everything the TCP server sends to its clients.
|
||||
QSignalSpy clientSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
|
||||
QSignalSpy clientSpy(m_mockTcpServer, &MockTcpServer::outgoingData);
|
||||
|
||||
// Create a new clientId for alice and connect it to the server
|
||||
QUuid aliceId = QUuid::createUuid();
|
||||
m_mockTcpServer->clientConnected(aliceId);
|
||||
m_mockTcpServer->injectData(aliceId, "{\"id\": 0, \"method\": \"JSONRPC.Hello\"}");
|
||||
if (clientSpy.count() == 0) clientSpy.wait();
|
||||
|
||||
// request push button auth for client 1 (alice) and check for OK reply
|
||||
QVariantMap params;
|
||||
@ -1139,6 +1207,9 @@ void TestJSONRPC::testPushButtonAuthConnectionDrop()
|
||||
// Create a new clientId for bob and connect it to the server
|
||||
QUuid bobId = QUuid::createUuid();
|
||||
m_mockTcpServer->clientConnected(bobId);
|
||||
clientSpy.clear();
|
||||
m_mockTcpServer->injectData(bobId, "{\"id\": 0, \"method\": \"JSONRPC.Hello\"}");
|
||||
if (clientSpy.count() == 0) clientSpy.wait();
|
||||
|
||||
// request push button auth for client 2 (bob) and check for OK reply
|
||||
params.clear();
|
||||
@ -1175,7 +1246,7 @@ void TestJSONRPC::testInitialSetupWithPushButtonAuth()
|
||||
NymeaCore::instance()->userManager()->removeUser("");
|
||||
QVERIFY(NymeaCore::instance()->userManager()->initRequired());
|
||||
|
||||
QSignalSpy spy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
|
||||
QSignalSpy spy(m_mockTcpServer, &MockTcpServer::outgoingData);
|
||||
QVERIFY(spy.isValid());
|
||||
|
||||
PushButtonAgent pushButtonAgent;
|
||||
@ -1183,6 +1254,7 @@ void TestJSONRPC::testInitialSetupWithPushButtonAuth()
|
||||
|
||||
// Hello call should work in any case, telling us initial setup is required
|
||||
spy.clear();
|
||||
qCDebug(dcTests()) << "Calling Hello on uninitialized instance";
|
||||
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.Hello\"}\n");
|
||||
if (spy.count() == 0) {
|
||||
spy.wait();
|
||||
@ -1190,13 +1262,16 @@ void TestJSONRPC::testInitialSetupWithPushButtonAuth()
|
||||
QVERIFY(spy.count() == 1);
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
|
||||
QVariant response = jsonDoc.toVariant();
|
||||
qWarning() << "Calling Hello on uninitialized instance:" << response.toMap().value("status").toString() << response.toMap().value("error").toString();
|
||||
qCDebug(dcTests()) << "Result:" << response.toMap().value("status").toString() << response.toMap().value("error").toString();
|
||||
QCOMPARE(response.toMap().value("status").toString(), QStringLiteral("success"));
|
||||
QCOMPARE(response.toMap().value("params").toMap().value("initialSetupRequired").toBool(), true);
|
||||
|
||||
// request push button auth for alice and check for OK reply
|
||||
QUuid aliceId = QUuid::createUuid();
|
||||
m_mockTcpServer->clientConnected(aliceId);
|
||||
spy.clear();
|
||||
m_mockTcpServer->injectData(aliceId, "{\"id\": 0, \"method\": \"JSONRPC.Hello\"}");
|
||||
if (spy.count() == 0) spy.wait();
|
||||
|
||||
QVariantMap params;
|
||||
params.insert("deviceName", "alice");
|
||||
@ -1223,6 +1298,7 @@ void TestJSONRPC::testInitialSetupWithPushButtonAuth()
|
||||
|
||||
// initialSetupRequired should be false in Hello call now
|
||||
spy.clear();
|
||||
qCDebug(dcTests()) << "Calling Hello on uninitialized instance";
|
||||
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.Hello\"}\n");
|
||||
if (spy.count() == 0) {
|
||||
spy.wait();
|
||||
@ -1230,13 +1306,15 @@ void TestJSONRPC::testInitialSetupWithPushButtonAuth()
|
||||
QVERIFY(spy.count() == 1);
|
||||
jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
|
||||
response = jsonDoc.toVariant();
|
||||
qWarning() << "Calling Hello on uninitialized instance:" << response.toMap().value("status").toString() << response.toMap().value("error").toString();
|
||||
qCDebug(dcTests()) << "Result:" << response.toMap().value("status").toString() << response.toMap().value("error").toString();
|
||||
QCOMPARE(response.toMap().value("status").toString(), QStringLiteral("success"));
|
||||
QCOMPARE(response.toMap().value("params").toMap().value("initialSetupRequired").toBool(), false);
|
||||
|
||||
|
||||
// CreateUser without a token should fail now even though there are 0 users in the DB
|
||||
spy.clear();
|
||||
QSignalSpy disconnectedSpy(m_mockTcpServer, &MockTcpServer::clientDisconnected);
|
||||
qCDebug(dcTests()) << "Calling CreateUser on uninitialized instance";
|
||||
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.CreateUser\", \"params\": {\"username\": \"Dummy@guh.io\", \"password\": \"DummyPW1!\"}}\n");
|
||||
if (spy.count() == 0) {
|
||||
spy.wait();
|
||||
@ -1244,10 +1322,19 @@ void TestJSONRPC::testInitialSetupWithPushButtonAuth()
|
||||
QVERIFY(spy.count() == 1);
|
||||
jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
|
||||
response = jsonDoc.toVariant();
|
||||
qWarning() << "Calling CreateUser on uninitialized instance:" << response.toMap().value("status").toString() << response.toMap().value("error").toString();
|
||||
qCDebug(dcTests()) << "Result:" << response.toMap().value("status").toString() << response.toMap().value("error").toString();
|
||||
QCOMPARE(response.toMap().value("status").toString(), QStringLiteral("unauthorized"));
|
||||
QCOMPARE(NymeaCore::instance()->userManager()->users().count(), 0);
|
||||
|
||||
// Connection should drop
|
||||
if (disconnectedSpy.isEmpty()) disconnectedSpy.wait();
|
||||
QCOMPARE(disconnectedSpy.count(), 1);
|
||||
|
||||
// Reconnect to not impact subsequent tests
|
||||
m_mockTcpServer->clientConnected(m_clientId);
|
||||
spy.clear();
|
||||
m_mockTcpServer->injectData(m_clientId, "{\"id\": 0, \"method\": \"JSONRPC.Hello\"}");
|
||||
if (spy.isEmpty()) spy.wait();
|
||||
}
|
||||
|
||||
void TestJSONRPC::testDataFragmentation_data()
|
||||
@ -1302,12 +1389,10 @@ void TestJSONRPC::testGarbageData()
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
data.append("a");
|
||||
}
|
||||
for (int i = 0; i < 11; i ++) {
|
||||
for (int i = 0; i < 11 && spy.count() == 0; i ++) {
|
||||
m_mockTcpServer->injectData(m_clientId, data);
|
||||
}
|
||||
|
||||
QCOMPARE(spy.count(), 1);
|
||||
|
||||
}
|
||||
|
||||
#include "testjsonrpc.moc"
|
||||
|
||||
@ -143,9 +143,11 @@ void NymeaTestBase::initTestCase()
|
||||
m_clientId = QUuid::createUuid();
|
||||
m_mockTcpServer->clientConnected(m_clientId);
|
||||
|
||||
QVariant response = injectAndWait("JSONRPC.Hello");
|
||||
|
||||
createMockDevice();
|
||||
|
||||
QVariant response = injectAndWait("Devices.GetConfiguredDevices", {});
|
||||
response = injectAndWait("Devices.GetConfiguredDevices", {});
|
||||
foreach (const QVariant &device, response.toMap().value("params").toMap().value("devices").toList()) {
|
||||
if (device.toMap().value("deviceClassId").toUuid() == mockDeviceAutoClassId) {
|
||||
m_mockDeviceAutoId = DeviceId(device.toMap().value("id").toString());
|
||||
@ -442,6 +444,8 @@ void NymeaTestBase::restartServer()
|
||||
coreSpy.wait();
|
||||
m_mockTcpServer = MockTcpServer::servers().first();
|
||||
m_mockTcpServer->clientConnected(m_clientId);
|
||||
|
||||
injectAndWait("JSONRPC.Hello");
|
||||
}
|
||||
|
||||
void NymeaTestBase::clearLoggingDatabase()
|
||||
|
||||
@ -91,7 +91,7 @@ void TestVersioning::apiChangeBumpsVersion()
|
||||
p.waitForFinished();
|
||||
QByteArray apiDiff = p.readAll();
|
||||
|
||||
qDebug() << "API Differences:" << endl << qUtf8Printable(apiDiff);
|
||||
qCDebug(dcTests()) << "API Differences:" << endl << qUtf8Printable(apiDiff);
|
||||
|
||||
if (oldVersion == newVersionStripped && oldApi != newApi) {
|
||||
QVERIFY2(false, "JSONRPC API has changed but version is still the same. You need to bump the API version.");
|
||||
|
||||
@ -81,8 +81,14 @@ void TestWebSocketServer::testHandshake()
|
||||
{
|
||||
QWebSocket *socket = new QWebSocket("nymea tests", QWebSocketProtocol::Version13);
|
||||
connect(socket, &QWebSocket::sslErrors, this, &TestWebSocketServer::sslErrors);
|
||||
QSignalSpy spy(socket, SIGNAL(textMessageReceived(QString)));
|
||||
|
||||
QSignalSpy connectedSpy(socket, &QWebSocket::connected);
|
||||
socket->open(QUrl(QStringLiteral("wss://localhost:4444")));
|
||||
connectedSpy.wait();
|
||||
|
||||
QSignalSpy spy(socket, SIGNAL(textMessageReceived(QString)));
|
||||
socket->sendTextMessage("{\"id\":0, \"method\": \"JSONRPC.Hello\"}");
|
||||
|
||||
spy.wait();
|
||||
QVERIFY2(spy.count() > 0, "Did not get the handshake message upon connect.");
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(spy.first().first().toByteArray());
|
||||
@ -90,8 +96,8 @@ void TestWebSocketServer::testHandshake()
|
||||
|
||||
QString nymeaVersionString(NYMEA_VERSION_STRING);
|
||||
QString jsonProtocolVersionString(JSON_PROTOCOL_VERSION);
|
||||
QCOMPARE(handShake.value("version").toString(), nymeaVersionString);
|
||||
QCOMPARE(handShake.value("protocol version").toString(), jsonProtocolVersionString);
|
||||
QCOMPARE(handShake.value("params").toMap().value("version").toString(), nymeaVersionString);
|
||||
QCOMPARE(handShake.value("params").toMap().value("protocol version").toString(), jsonProtocolVersionString);
|
||||
|
||||
socket->close();
|
||||
socket->deleteLater();
|
||||
@ -173,6 +179,10 @@ QVariant TestWebSocketServer::injectSocketAndWait(const QString &method, const Q
|
||||
}
|
||||
|
||||
QSignalSpy spy(socket, SIGNAL(textMessageReceived(QString)));
|
||||
socket->sendTextMessage("{\"id\":0, \"method\": \"JSONRPC.Hello\"}");
|
||||
spy.wait();
|
||||
|
||||
spy.clear();
|
||||
socket->sendTextMessage(QString(jsonDoc.toJson(QJsonDocument::Compact)));
|
||||
spy.wait();
|
||||
|
||||
@ -214,6 +224,11 @@ QVariant TestWebSocketServer::injectSocketData(const QByteArray &data)
|
||||
}
|
||||
|
||||
QSignalSpy spy(socket, SIGNAL(textMessageReceived(QString)));
|
||||
|
||||
socket->sendTextMessage("{\"id\":0, \"method\": \"JSONRPC.Hello\"}");
|
||||
spy.wait();
|
||||
|
||||
spy.clear();
|
||||
socket->sendTextMessage(QString(data));
|
||||
spy.wait();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user