add rule tests and rest resource

pull/135/head
Simon Stürz 2015-08-01 11:16:06 +02:00 committed by Michael Zanetti
parent 1330ed31a3
commit 1f6cfd4527
15 changed files with 1239 additions and 200 deletions

View File

@ -1,11 +1,13 @@
[JSONRPC]
port=12345
port=1234
interfaces="lo","all"
ip="IPv4", "IPv6"
[Webserver]
port=3001
port=3000
publicFolder=/usr/share/guh-webinterface/
https=false
[GPIO]
rf433rx=27

View File

@ -28,9 +28,8 @@ enable433gpio {
# check webserver support
equals(QT_MAJOR_VERSION, 5):greaterThan(QT_MINOR_VERSION, 3) {
DEFINES += WEBSERVER
DEFINES += WEBSOCKET
}
top_srcdir=$$PWD
top_builddir=$$shadowed($$PWD)

View File

@ -34,10 +34,10 @@ coverage {
message("Building coverage.")
}
contains(DEFINES, WEBSERVER){
message("Building guh with webserver.")
contains(DEFINES, WEBSOCKET){
message("Building guh with websocket.")
} else {
message("Building guh without webserver.")
message("Building guh without websocket.")
}
contains(DEFINES, GPIO433){

View File

@ -1288,6 +1288,168 @@ QPair<bool, QString> JsonTypes::validateBasicType(const QVariant &variant)
return report(false, QString("Error validating basic type %1.").arg(variant.toString()));
}
QVariant::Type JsonTypes::getActionParamType(const ActionTypeId &actionTypeId, const QString &paramName)
{
foreach (const DeviceClass &deviceClass, GuhCore::instance()->supportedDevices()) {
foreach (const ActionType &actionType, deviceClass.actionTypes()) {
if (actionType.id() == actionTypeId) {
foreach (const ParamType &paramType, actionType.paramTypes()) {
if (paramType.name() == paramName) {
return paramType.type();
}
}
}
}
}
return QVariant::Invalid;
}
QVariant::Type JsonTypes::getEventParamType(const EventTypeId &eventTypeId, const QString &paramName)
{
foreach (const DeviceClass &deviceClass, GuhCore::instance()->supportedDevices()) {
foreach (const EventType &eventType, deviceClass.eventTypes()) {
if (eventType.id() == eventTypeId) {
foreach (const ParamType &paramType, eventType.paramTypes()) {
// get ParamType of Event
if (paramType.name() == paramName) {
return paramType.type();
}
}
}
}
}
return QVariant::Invalid;
}
bool JsonTypes::checkEventDescriptors(const QList<EventDescriptor> eventDescriptors, const EventTypeId &eventTypeId)
{
foreach (const EventDescriptor eventDescriptor, eventDescriptors) {
if (eventDescriptor.eventTypeId() == eventTypeId) {
return true;
}
}
return false;
}
RuleEngine::RuleError JsonTypes::verifyRuleConsistency(const QVariantMap &params)
{
// check if there are an eventDescriptor and an eventDescriptorList
if (params.contains("eventDescriptor") && params.contains("eventDescriptorList")) {
qCWarning(dcJsonRpc) << "Only one of eventDesciptor or eventDescriptorList may be used.";
return RuleEngine::RuleErrorInvalidParameter;
}
// check if this rules is based on any event and contains exit actions
if (params.contains("eventDescriptor") || params.contains("eventDescriptorList")) {
if (params.contains("exitActions")) {
qCWarning(dcJsonRpc) << "The exitActions will never be executed if the rule contains an eventDescriptor.";
return RuleEngine::RuleErrorInvalidRuleFormat;
}
}
// check if there are any actions
if (params.value("actions").toList().isEmpty()) {
qCWarning(dcJsonRpc) << "Rule actions missing. A rule without actions has no effect.";
return RuleEngine::RuleErrorMissingParameter;
}
// TODO: check if events and stateEvaluators are missing
return RuleEngine::RuleErrorNoError;
}
QPair<QList<EventDescriptor>, RuleEngine::RuleError> JsonTypes::verifyEventDescriptors(const QVariantMap &params)
{
// Check and unpack eventDescriptors
QList<EventDescriptor> eventDescriptorList = QList<EventDescriptor>();
if (params.contains("eventDescriptor")) {
QVariantMap eventMap = params.value("eventDescriptor").toMap();
qCDebug(dcJsonRpc) << "unpacking eventDescriptor" << eventMap;
eventDescriptorList.append(JsonTypes::unpackEventDescriptor(eventMap));
} else if (params.contains("eventDescriptorList")) {
QVariantList eventDescriptors = params.value("eventDescriptorList").toList();
qCDebug(dcJsonRpc) << "unpacking eventDescriptorList:" << eventDescriptors;
foreach (const QVariant &eventVariant, eventDescriptors) {
QVariantMap eventMap = eventVariant.toMap();
eventDescriptorList.append(JsonTypes::unpackEventDescriptor(eventMap));
}
}
return QPair<QList<EventDescriptor>, RuleEngine::RuleError>(eventDescriptorList, RuleEngine::RuleErrorNoError);
}
QPair<QList<RuleAction>, RuleEngine::RuleError> JsonTypes::verifyActions(const QVariantMap &params, const QList<EventDescriptor> &eventDescriptorList)
{
QList<RuleAction> actions;
QVariantList actionList = params.value("actions").toList();
qCDebug(dcJsonRpc) << "unpacking actions:" << actionList;
foreach (const QVariant &actionVariant, actionList) {
QVariantMap actionMap = actionVariant.toMap();
RuleAction action(ActionTypeId(actionMap.value("actionTypeId").toString()), DeviceId(actionMap.value("deviceId").toString()));
RuleActionParamList actionParamList = JsonTypes::unpackRuleActionParams(actionMap.value("ruleActionParams").toList());
foreach (const RuleActionParam &ruleActionParam, actionParamList) {
if (!ruleActionParam.isValid()) {
qCWarning(dcJsonRpc) << "got an actionParam with value AND eventTypeId!";
return QPair<QList<RuleAction>, RuleEngine::RuleError>(actions, RuleEngine::RuleErrorInvalidRuleActionParameter);
}
}
qCDebug(dcJsonRpc) << "params in exitAction" << action.ruleActionParams();
action.setRuleActionParams(actionParamList);
actions.append(action);
}
// check possible eventTypeIds in params
foreach (const RuleAction &ruleAction, actions) {
if (ruleAction.isEventBased()) {
foreach (const RuleActionParam &ruleActionParam, ruleAction.ruleActionParams()) {
if (ruleActionParam.eventTypeId() != EventTypeId()) {
// We have an eventTypeId
if (eventDescriptorList.isEmpty()) {
qCWarning(dcJsonRpc) << "RuleAction" << ruleAction.actionTypeId() << "contains an eventTypeId, but there are no eventDescriptors.";
return QPair<QList<RuleAction>, RuleEngine::RuleError>(actions, RuleEngine::RuleErrorInvalidRuleActionParameter);
}
// now check if this eventType is in the eventDescriptorList of this rule
if (!checkEventDescriptors(eventDescriptorList, ruleActionParam.eventTypeId())) {
qCWarning(dcJsonRpc) << "eventTypeId from RuleAction" << ruleAction.actionTypeId() << "missing in eventDescriptors.";
return QPair<QList<RuleAction>, RuleEngine::RuleError>(actions, RuleEngine::RuleErrorInvalidRuleActionParameter);
}
// check if the param type of the event and the action match
QVariant::Type eventParamType = getEventParamType(ruleActionParam.eventTypeId(), ruleActionParam.eventParamName());
QVariant::Type actionParamType = getActionParamType(ruleAction.actionTypeId(), ruleActionParam.name());
if (eventParamType != actionParamType) {
qCWarning(dcJsonRpc) << "RuleActionParam" << ruleActionParam.name() << " and given event param " << ruleActionParam.eventParamName() << "have not the same type:";
qCWarning(dcJsonRpc) << " -> actionParamType:" << actionParamType;
qCWarning(dcJsonRpc) << " -> eventParamType:" << eventParamType;
return QPair<QList<RuleAction>, RuleEngine::RuleError>(actions, RuleEngine::RuleErrorTypesNotMatching);
}
}
}
}
}
return QPair<QList<RuleAction>, RuleEngine::RuleError>(actions, RuleEngine::RuleErrorNoError);
}
QPair<QList<RuleAction>, RuleEngine::RuleError> JsonTypes::verifyExitActions(const QVariantMap &params)
{
QList<RuleAction> exitActions;
if (params.contains("exitActions")) {
QVariantList exitActionList = params.value("exitActions").toList();
qCDebug(dcJsonRpc) << "unpacking exitActions:" << exitActionList;
foreach (const QVariant &actionVariant, exitActionList) {
QVariantMap actionMap = actionVariant.toMap();
RuleAction action(ActionTypeId(actionMap.value("actionTypeId").toString()), DeviceId(actionMap.value("deviceId").toString()));
if (action.isEventBased()) {
qCWarning(dcJsonRpc) << "got exitAction with a param value containing an eventTypeId!";
return QPair<QList<RuleAction>, RuleEngine::RuleError>(exitActions, RuleEngine::RuleErrorInvalidRuleActionParameter);
}
qCDebug(dcJsonRpc) << "params in exitAction" << action.ruleActionParams();
action.setRuleActionParams(JsonTypes::unpackRuleActionParams(actionMap.value("ruleActionParams").toList()));
exitActions.append(action);
}
}
return QPair<QList<RuleAction>, RuleEngine::RuleError>(exitActions, RuleEngine::RuleErrorNoError);
}
QPair<bool, QString> JsonTypes::validateEnum(const QVariantList &enumDescription, const QVariant &value)
{
QStringList enumStrings;

View File

@ -197,6 +197,15 @@ public:
static QPair<bool, QString> validateEnum(const QVariantList &enumList, const QVariant &value);
static QPair<bool, QString> validateBasicType(const QVariant &variant);
// rule validation helper methods
static bool checkEventDescriptors(const QList<EventDescriptor> eventDescriptors, const EventTypeId &eventTypeId);
static QVariant::Type getActionParamType(const ActionTypeId &actionTypeId, const QString &paramName);
static QVariant::Type getEventParamType(const EventTypeId &eventTypeId, const QString &paramName);
static RuleEngine::RuleError verifyRuleConsistency(const QVariantMap &params);
static QPair<QList<EventDescriptor>, RuleEngine::RuleError> verifyEventDescriptors(const QVariantMap &params);
static QPair<QList<RuleAction>, RuleEngine::RuleError> verifyActions(const QVariantMap &params, const QList<EventDescriptor> &eventDescriptorList);
static QPair<QList<RuleAction>, RuleEngine::RuleError> verifyExitActions(const QVariantMap &params);
private:
static bool s_initialized;
static void init();

View File

@ -175,7 +175,7 @@ JsonReply *RulesHandler::GetRuleDetails(const QVariantMap &params)
JsonReply* RulesHandler::AddRule(const QVariantMap &params)
{
// check rule consistency
RuleEngine::RuleError ruleConsistencyError = verifyRuleConsistency(params);
RuleEngine::RuleError ruleConsistencyError = JsonTypes::verifyRuleConsistency(params);
if (ruleConsistencyError != RuleEngine::RuleErrorNoError) {
QVariantMap returns;
returns.insert("ruleError", JsonTypes::ruleErrorToString(ruleConsistencyError));
@ -183,7 +183,7 @@ JsonReply* RulesHandler::AddRule(const QVariantMap &params)
}
// Check and upack eventDescriptorList
QPair<QList<EventDescriptor>, RuleEngine::RuleError> eventDescriptorVerification = verifyEventDescriptors(params);
QPair<QList<EventDescriptor>, RuleEngine::RuleError> eventDescriptorVerification = JsonTypes::verifyEventDescriptors(params);
QList<EventDescriptor> eventDescriptorList = eventDescriptorVerification.first;
if (eventDescriptorVerification.second != RuleEngine::RuleErrorNoError) {
QVariantMap returns;
@ -191,13 +191,12 @@ JsonReply* RulesHandler::AddRule(const QVariantMap &params)
return createReply(returns);
}
// Check and unpack stateEvaluator
qCDebug(dcJsonRpc) << "unpacking stateEvaluator:" << params.value("stateEvaluator").toMap();
StateEvaluator stateEvaluator = JsonTypes::unpackStateEvaluator(params.value("stateEvaluator").toMap());
// Check and unpack actions
QPair<QList<RuleAction>, RuleEngine::RuleError> actionsVerification = verifyActions(params, eventDescriptorList);
QPair<QList<RuleAction>, RuleEngine::RuleError> actionsVerification = JsonTypes::verifyActions(params, eventDescriptorList);
QList<RuleAction> actions = actionsVerification.first;
if (actionsVerification.second != RuleEngine::RuleErrorNoError) {
QVariantMap returns;
@ -206,7 +205,7 @@ JsonReply* RulesHandler::AddRule(const QVariantMap &params)
}
// Check and unpack exitActions
QPair<QList<RuleAction>, RuleEngine::RuleError> exitActionsVerification = verifyExitActions(params);
QPair<QList<RuleAction>, RuleEngine::RuleError> exitActionsVerification = JsonTypes::verifyExitActions(params);
QList<RuleAction> exitActions = exitActionsVerification.first;
if (exitActionsVerification.second != RuleEngine::RuleErrorNoError) {
QVariantMap returns;
@ -230,7 +229,7 @@ JsonReply* RulesHandler::AddRule(const QVariantMap &params)
JsonReply *RulesHandler::EditRule(const QVariantMap &params)
{
// check rule consistency
RuleEngine::RuleError ruleConsistencyError = verifyRuleConsistency(params);
RuleEngine::RuleError ruleConsistencyError = JsonTypes::verifyRuleConsistency(params);
if (ruleConsistencyError != RuleEngine::RuleErrorNoError) {
QVariantMap returns;
returns.insert("ruleError", JsonTypes::ruleErrorToString(ruleConsistencyError));
@ -238,7 +237,7 @@ JsonReply *RulesHandler::EditRule(const QVariantMap &params)
}
// Check and upack eventDescriptorList
QPair<QList<EventDescriptor>, RuleEngine::RuleError> eventDescriptorVerification = verifyEventDescriptors(params);
QPair<QList<EventDescriptor>, RuleEngine::RuleError> eventDescriptorVerification = JsonTypes::verifyEventDescriptors(params);
QList<EventDescriptor> eventDescriptorList = eventDescriptorVerification.first;
if (eventDescriptorVerification.second != RuleEngine::RuleErrorNoError) {
QVariantMap returns;
@ -251,7 +250,7 @@ JsonReply *RulesHandler::EditRule(const QVariantMap &params)
StateEvaluator stateEvaluator = JsonTypes::unpackStateEvaluator(params.value("stateEvaluator").toMap());
// Check and unpack actions
QPair<QList<RuleAction>, RuleEngine::RuleError> actionsVerification = verifyActions(params, eventDescriptorList);
QPair<QList<RuleAction>, RuleEngine::RuleError> actionsVerification = JsonTypes::verifyActions(params, eventDescriptorList);
QList<RuleAction> actions = actionsVerification.first;
if (actionsVerification.second != RuleEngine::RuleErrorNoError) {
QVariantMap returns;
@ -260,7 +259,7 @@ JsonReply *RulesHandler::EditRule(const QVariantMap &params)
}
// Check and unpack exitActions
QPair<QList<RuleAction>, RuleEngine::RuleError> exitActionsVerification = verifyExitActions(params);
QPair<QList<RuleAction>, RuleEngine::RuleError> exitActionsVerification = JsonTypes::verifyExitActions(params);
QList<RuleAction> exitActions = exitActionsVerification.first;
if (exitActionsVerification.second != RuleEngine::RuleErrorNoError) {
QVariantMap returns;
@ -315,168 +314,6 @@ JsonReply *RulesHandler::DisableRule(const QVariantMap &params)
return createReply(statusToReply(GuhCore::instance()->disableRule(RuleId(params.value("ruleId").toString()))));
}
QVariant::Type RulesHandler::getActionParamType(const ActionTypeId &actionTypeId, const QString &paramName)
{
foreach (const DeviceClass &deviceClass, GuhCore::instance()->supportedDevices()) {
foreach (const ActionType &actionType, deviceClass.actionTypes()) {
if (actionType.id() == actionTypeId) {
foreach (const ParamType &paramType, actionType.paramTypes()) {
if (paramType.name() == paramName) {
return paramType.type();
}
}
}
}
}
return QVariant::Invalid;
}
QVariant::Type RulesHandler::getEventParamType(const EventTypeId &eventTypeId, const QString &paramName)
{
foreach (const DeviceClass &deviceClass, GuhCore::instance()->supportedDevices()) {
foreach (const EventType &eventType, deviceClass.eventTypes()) {
if (eventType.id() == eventTypeId) {
foreach (const ParamType &paramType, eventType.paramTypes()) {
// get ParamType of Event
if (paramType.name() == paramName) {
return paramType.type();
}
}
}
}
}
return QVariant::Invalid;
}
bool RulesHandler::checkEventDescriptors(const QList<EventDescriptor> eventDescriptors, const EventTypeId &eventTypeId)
{
foreach (const EventDescriptor eventDescriptor, eventDescriptors) {
if (eventDescriptor.eventTypeId() == eventTypeId) {
return true;
}
}
return false;
}
RuleEngine::RuleError RulesHandler::verifyRuleConsistency(const QVariantMap &params)
{
// check if there are an eventDescriptor and an eventDescriptorList
if (params.contains("eventDescriptor") && params.contains("eventDescriptorList")) {
qCWarning(dcJsonRpc) << "Only one of eventDesciptor or eventDescriptorList may be used.";
return RuleEngine::RuleErrorInvalidParameter;
}
// check if this rules is based on any event and contains exit actions
if (params.contains("eventDescriptor") || params.contains("eventDescriptorList")) {
if (params.contains("exitActions")) {
qCWarning(dcJsonRpc) << "The exitActions will never be executed if the rule contains an eventDescriptor.";
return RuleEngine::RuleErrorInvalidRuleFormat;
}
}
// check if there are any actions
if (params.value("actions").toList().isEmpty()) {
qCWarning(dcJsonRpc) << "Rule actions missing. A rule without actions has no effect.";
return RuleEngine::RuleErrorMissingParameter;
}
// TODO: check if events and stateEvaluators are missing
return RuleEngine::RuleErrorNoError;
}
QPair<QList<EventDescriptor>, RuleEngine::RuleError> RulesHandler::verifyEventDescriptors(const QVariantMap &params)
{
// Check and unpack eventDescriptors
QList<EventDescriptor> eventDescriptorList = QList<EventDescriptor>();
if (params.contains("eventDescriptor")) {
QVariantMap eventMap = params.value("eventDescriptor").toMap();
qCDebug(dcJsonRpc) << "unpacking eventDescriptor" << eventMap;
eventDescriptorList.append(JsonTypes::unpackEventDescriptor(eventMap));
} else if (params.contains("eventDescriptorList")) {
QVariantList eventDescriptors = params.value("eventDescriptorList").toList();
qCDebug(dcJsonRpc) << "unpacking eventDescriptorList:" << eventDescriptors;
foreach (const QVariant &eventVariant, eventDescriptors) {
QVariantMap eventMap = eventVariant.toMap();
eventDescriptorList.append(JsonTypes::unpackEventDescriptor(eventMap));
}
}
return QPair<QList<EventDescriptor>, RuleEngine::RuleError>(eventDescriptorList, RuleEngine::RuleErrorNoError);
}
QPair<QList<RuleAction>, RuleEngine::RuleError> RulesHandler::verifyActions(const QVariantMap &params, const QList<EventDescriptor> &eventDescriptorList)
{
QList<RuleAction> actions;
QVariantList actionList = params.value("actions").toList();
qCDebug(dcJsonRpc) << "unpacking actions:" << actionList;
foreach (const QVariant &actionVariant, actionList) {
QVariantMap actionMap = actionVariant.toMap();
RuleAction action(ActionTypeId(actionMap.value("actionTypeId").toString()), DeviceId(actionMap.value("deviceId").toString()));
RuleActionParamList actionParamList = JsonTypes::unpackRuleActionParams(actionMap.value("ruleActionParams").toList());
foreach (const RuleActionParam &ruleActionParam, actionParamList) {
if (!ruleActionParam.isValid()) {
qCWarning(dcJsonRpc) << "got an actionParam with value AND eventTypeId!";
return QPair<QList<RuleAction>, RuleEngine::RuleError>(actions, RuleEngine::RuleErrorInvalidRuleActionParameter);
}
}
qCDebug(dcJsonRpc) << "params in exitAction" << action.ruleActionParams();
action.setRuleActionParams(actionParamList);
actions.append(action);
}
// check possible eventTypeIds in params
foreach (const RuleAction &ruleAction, actions) {
if (ruleAction.isEventBased()) {
foreach (const RuleActionParam &ruleActionParam, ruleAction.ruleActionParams()) {
if (ruleActionParam.eventTypeId() != EventTypeId()) {
// We have an eventTypeId
if (eventDescriptorList.isEmpty()) {
qCWarning(dcJsonRpc) << "RuleAction" << ruleAction.actionTypeId() << "contains an eventTypeId, but there are no eventDescriptors.";
return QPair<QList<RuleAction>, RuleEngine::RuleError>(actions, RuleEngine::RuleErrorInvalidRuleActionParameter);
}
// now check if this eventType is in the eventDescriptorList of this rule
if (!checkEventDescriptors(eventDescriptorList, ruleActionParam.eventTypeId())) {
qCWarning(dcJsonRpc) << "eventTypeId from RuleAction" << ruleAction.actionTypeId() << "missing in eventDescriptors.";
return QPair<QList<RuleAction>, RuleEngine::RuleError>(actions, RuleEngine::RuleErrorInvalidRuleActionParameter);
}
// check if the param type of the event and the action match
QVariant::Type eventParamType = getEventParamType(ruleActionParam.eventTypeId(), ruleActionParam.eventParamName());
QVariant::Type actionParamType = getActionParamType(ruleAction.actionTypeId(), ruleActionParam.name());
if (eventParamType != actionParamType) {
qCWarning(dcJsonRpc) << "RuleActionParam" << ruleActionParam.name() << " and given event param " << ruleActionParam.eventParamName() << "have not the same type:";
qCWarning(dcJsonRpc) << " -> actionParamType:" << actionParamType;
qCWarning(dcJsonRpc) << " -> eventParamType:" << eventParamType;
return QPair<QList<RuleAction>, RuleEngine::RuleError>(actions, RuleEngine::RuleErrorTypesNotMatching);
}
}
}
}
}
return QPair<QList<RuleAction>, RuleEngine::RuleError>(actions, RuleEngine::RuleErrorNoError);
}
QPair<QList<RuleAction>, RuleEngine::RuleError> RulesHandler::verifyExitActions(const QVariantMap &params)
{
QList<RuleAction> exitActions;
if (params.contains("exitActions")) {
QVariantList exitActionList = params.value("exitActions").toList();
qCDebug(dcJsonRpc) << "unpacking exitActions:" << exitActionList;
foreach (const QVariant &actionVariant, exitActionList) {
QVariantMap actionMap = actionVariant.toMap();
RuleAction action(ActionTypeId(actionMap.value("actionTypeId").toString()), DeviceId(actionMap.value("deviceId").toString()));
if (action.isEventBased()) {
qCWarning(dcJsonRpc) << "got exitAction with a param value containing an eventTypeId!";
return QPair<QList<RuleAction>, RuleEngine::RuleError>(exitActions, RuleEngine::RuleErrorInvalidRuleActionParameter);
}
qCDebug(dcJsonRpc) << "params in exitAction" << action.ruleActionParams();
action.setRuleActionParams(JsonTypes::unpackRuleActionParams(actionMap.value("ruleActionParams").toList()));
exitActions.append(action);
}
}
return QPair<QList<RuleAction>, RuleEngine::RuleError>(exitActions, RuleEngine::RuleErrorNoError);
}
void RulesHandler::ruleRemovedNotification(const RuleId &ruleId)
{
QVariantMap params;

View File

@ -51,17 +51,6 @@ signals:
void RuleActiveChanged(const QVariantMap &params);
void RuleConfigurationChanged(const QVariantMap &params);
private:
QVariant::Type getActionParamType(const ActionTypeId &actionTypeId, const QString &paramName);
QVariant::Type getEventParamType(const EventTypeId &eventTypeId, const QString &paramName);
bool checkEventDescriptors(const QList<EventDescriptor> eventDescriptors, const EventTypeId &eventTypeId);
RuleEngine::RuleError verifyRuleConsistency(const QVariantMap &params);
QPair<QList<EventDescriptor>, RuleEngine::RuleError> verifyEventDescriptors(const QVariantMap &params);
QPair<QList<RuleAction>, RuleEngine::RuleError> verifyActions(const QVariantMap &params, const QList<EventDescriptor> &eventDescriptorList);
QPair<QList<RuleAction>, RuleEngine::RuleError> verifyExitActions(const QVariantMap &params);
private slots:
void ruleRemovedNotification(const RuleId &ruleId);
void ruleAddedNotification(const Rule &rule);

View File

@ -45,7 +45,6 @@ HttpReply *DevicesResource::proccessRequest(const HttpRequest &request, const QS
{
m_device = 0;
// get the main resource
if (urlTokens.count() >= 4) {
DeviceId deviceId = DeviceId(urlTokens.at(3));

View File

@ -62,6 +62,9 @@ HttpReply *RulesResource::proccessRequest(const HttpRequest &request, const QStr
case HttpRequest::Put:
reply = proccessPutRequest(request, urlTokens);
break;
case HttpRequest::Post:
reply = proccessPostRequest(request, urlTokens);
break;
case HttpRequest::Delete:
reply = proccessDeleteRequest(request, urlTokens);
break;
@ -129,6 +132,14 @@ HttpReply *RulesResource::proccessPostRequest(const HttpRequest &request, const
if (urlTokens.count() == 3)
return addRule(request.payload());
// POST /api/v1/rules/{ruleId}/enable
if (urlTokens.count() == 5 && urlTokens.at(4) == "enable")
return enableRule(m_ruleId);
// POST /api/v1/rules/{ruleId}/disable
if (urlTokens.count() == 5 && urlTokens.at(4) == "disable")
return disableRule(m_ruleId);
return createErrorReply(HttpReply::NotImplemented);
}
@ -179,19 +190,130 @@ HttpReply *RulesResource::removeRule(const RuleId &ruleId) const
HttpReply *RulesResource::addRule(const QByteArray &payload) const
{
Q_UNUSED(payload)
qCDebug(dcRest) << "Add new rule";
QPair<bool, QVariant> verification = RestResource::verifyPayload(payload);
if (!verification.first)
return createErrorReply(HttpReply::BadRequest);
return createErrorReply(HttpReply::NotImplemented);
QVariantMap params = verification.second.toMap();
// check rule consistency
RuleEngine::RuleError ruleConsistencyError = JsonTypes::verifyRuleConsistency(params);
if (ruleConsistencyError != RuleEngine::RuleErrorNoError)
return createErrorReply(HttpReply::BadRequest);
// Check and upack eventDescriptorList
QPair<QList<EventDescriptor>, RuleEngine::RuleError> eventDescriptorVerification = JsonTypes::verifyEventDescriptors(params);
QList<EventDescriptor> eventDescriptorList = eventDescriptorVerification.first;
if (eventDescriptorVerification.second != RuleEngine::RuleErrorNoError)
return createErrorReply(HttpReply::BadRequest);
// Check and unpack stateEvaluator
qCDebug(dcRest) << "unpacking stateEvaluator:" << params.value("stateEvaluator").toMap();
StateEvaluator stateEvaluator = JsonTypes::unpackStateEvaluator(params.value("stateEvaluator").toMap());
// Check and unpack actions
QPair<QList<RuleAction>, RuleEngine::RuleError> actionsVerification = JsonTypes::verifyActions(params, eventDescriptorList);
QList<RuleAction> actions = actionsVerification.first;
if (actionsVerification.second != RuleEngine::RuleErrorNoError)
return createErrorReply(HttpReply::BadRequest);
// Check and unpack exitActions
QPair<QList<RuleAction>, RuleEngine::RuleError> exitActionsVerification = JsonTypes::verifyExitActions(params);
QList<RuleAction> exitActions = exitActionsVerification.first;
if (exitActionsVerification.second != RuleEngine::RuleErrorNoError)
return createErrorReply(HttpReply::BadRequest);
QString name = params.value("name", QString()).toString();
bool enabled = params.value("enabled", true).toBool();
RuleId newRuleId = RuleId::createRuleId();
RuleEngine::RuleError status = GuhCore::instance()->addRule(newRuleId, name, eventDescriptorList, stateEvaluator, actions, exitActions, enabled);
if (status == RuleEngine::RuleErrorNoError) {
QVariantMap returns;
returns.insert("ruleId", newRuleId.toString());
HttpReply *reply = createSuccessReply();
reply->setPayload(QJsonDocument::fromVariant(returns).toJson());
return reply;
}
return createErrorReply(HttpReply::BadRequest);
}
HttpReply *RulesResource::enableRule(const RuleId &ruleId) const
{
qCDebug(dcRest) << "Enable rule with id" << ruleId.toString();
RuleEngine::RuleError status = GuhCore::instance()->enableRule(ruleId);
if (status == RuleEngine::RuleErrorNoError)
return createSuccessReply();
return createErrorReply(HttpReply::BadRequest);
}
HttpReply *RulesResource::disableRule(const RuleId &ruleId) const
{
qCDebug(dcRest) << "Disable rule with id" << ruleId.toString();
RuleEngine::RuleError status = GuhCore::instance()->disableRule(ruleId);
if (status == RuleEngine::RuleErrorNoError)
return createSuccessReply();
return createErrorReply(HttpReply::BadRequest);
}
HttpReply *RulesResource::editRule(const RuleId &ruleId, const QByteArray &payload) const
{
Q_UNUSED(payload)
qCDebug(dcRest) << "Edit rule with id" << ruleId;
qCDebug(dcRest) << "Edit rule with id" << ruleId.toString();
return createErrorReply(HttpReply::NotImplemented);
QPair<bool, QVariant> verification = RestResource::verifyPayload(payload);
if (!verification.first)
return createErrorReply(HttpReply::BadRequest);
QVariantMap params = verification.second.toMap();
// check rule consistency
RuleEngine::RuleError ruleConsistencyError = JsonTypes::verifyRuleConsistency(params);
if (ruleConsistencyError != RuleEngine::RuleErrorNoError)
return createErrorReply(HttpReply::BadRequest);
// Check and upack eventDescriptorList
QPair<QList<EventDescriptor>, RuleEngine::RuleError> eventDescriptorVerification = JsonTypes::verifyEventDescriptors(params);
QList<EventDescriptor> eventDescriptorList = eventDescriptorVerification.first;
if (eventDescriptorVerification.second != RuleEngine::RuleErrorNoError)
return createErrorReply(HttpReply::BadRequest);
// Check and unpack stateEvaluator
qCDebug(dcRest) << "unpacking stateEvaluator:" << params.value("stateEvaluator").toMap();
StateEvaluator stateEvaluator = JsonTypes::unpackStateEvaluator(params.value("stateEvaluator").toMap());
// Check and unpack actions
QPair<QList<RuleAction>, RuleEngine::RuleError> actionsVerification = JsonTypes::verifyActions(params, eventDescriptorList);
QList<RuleAction> actions = actionsVerification.first;
if (actionsVerification.second != RuleEngine::RuleErrorNoError)
return createErrorReply(HttpReply::BadRequest);
// Check and unpack exitActions
QPair<QList<RuleAction>, RuleEngine::RuleError> exitActionsVerification = JsonTypes::verifyExitActions(params);
QList<RuleAction> exitActions = exitActionsVerification.first;
if (exitActionsVerification.second != RuleEngine::RuleErrorNoError)
return createErrorReply(HttpReply::BadRequest);
QString name = params.value("name", QString()).toString();
bool enabled = params.value("enabled", true).toBool();
RuleEngine::RuleError status = GuhCore::instance()->editRule(ruleId, name, eventDescriptorList, stateEvaluator, actions, exitActions, enabled);
if (status == RuleEngine::RuleErrorNoError) {
qCDebug(dcRest) << "Edit rule successfully finished";
return createSuccessReply();
}
qCWarning(dcRest) << "Edit rule finished with error" << status;
return createErrorReply(HttpReply::BadRequest);
}
}

View File

@ -60,6 +60,8 @@ private:
// Post methods
HttpReply *addRule(const QByteArray &payload) const;
HttpReply *enableRule(const RuleId &ruleId) const;
HttpReply *disableRule(const RuleId &ruleId) const;
// Put methods
HttpReply *editRule(const RuleId &ruleId, const QByteArray &payload) const;

View File

@ -1,5 +1,5 @@
contains(DEFINES, WEBSERVER){
contains(DEFINES, WEBSOCKET){
QT += websockets
}

View File

@ -1,6 +1,6 @@
TEMPLATE=subdirs
TEMPLATE = subdirs
SUBDIRS=versioning \
SUBDIRS = versioning \
devices \
jsonrpc \
events \
@ -13,3 +13,4 @@ SUBDIRS=versioning \
restdeviceclasses \
restplugins \
restvendors \
restrules \

View File

@ -248,6 +248,7 @@ void TestRestDeviceClasses::discoverDevices()
QNetworkAccessManager *nam = new QNetworkAccessManager();
QSignalSpy clientSpy(nam, SIGNAL(finished(QNetworkReply*)));
// DISCOVER
QUrl url(QString("http://localhost:3000/api/v1/deviceclasses/%1/discover").arg(deviceClassId.toString()));
if (!discoveryParams.isEmpty()) {
@ -275,7 +276,7 @@ void TestRestDeviceClasses::discoverDevices()
QVariantList foundDevices = jsonDoc.toVariant().toList();
QCOMPARE(foundDevices.count(), resultCount);
// add the discovered device
// ADD the discovered device
request.setUrl(QUrl("http://localhost:3000/api/v1/devices"));
DeviceDescriptorId descriptorId = DeviceDescriptorId(foundDevices.first().toMap().value("id").toString());
qDebug() << descriptorId;
@ -294,7 +295,7 @@ void TestRestDeviceClasses::discoverDevices()
reply->deleteLater();
QCOMPARE(statusCode, expectedStatusCode);
// remove added device
// REMOVE added device
jsonDoc = QJsonDocument::fromJson(data, &error);
QCOMPARE(error.error, QJsonParseError::NoError);
QVariantMap response = jsonDoc.toVariant().toMap();

View File

@ -0,0 +1,5 @@
include(../../../guh.pri)
include(../autotests.pri)
TARGET = restrules
SOURCES += testrestrules.cpp

View File

@ -0,0 +1,911 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "guhtestbase.h"
#include "guhcore.h"
#include "devicemanager.h"
#include "mocktcpserver.h"
#include "webserver.h"
#include <QtTest/QtTest>
#include <QCoreApplication>
#include <QTcpSocket>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QCoreApplication>
#include <QJsonDocument>
#include <QHttpPart>
#include <QMetaType>
using namespace guhserver;
class TestRestRules: public GuhTestBase
{
Q_OBJECT
private:
void cleanupMockHistory();
void cleanupRules();
void verifyRuleExecuted(const ActionTypeId &actionTypeId);
void verifyRuleNotExecuted();
private slots:
void addRemoveRules_data();
void addRemoveRules();
void editRules_data();
void editRules();
void enableDisableRule();
void getRules();
};
void TestRestRules::cleanupMockHistory()
{
QNetworkAccessManager nam;
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
QNetworkRequest request(QUrl(QString("http://localhost:%1/clearactionhistory").arg(m_mockDevice1Port).arg(mockEvent1Id.toString())));
QNetworkReply *reply = nam.get(request);
spy.wait(500);
QCOMPARE(spy.count(), 1);
reply->deleteLater();
}
void TestRestRules::cleanupRules()
{
QNetworkAccessManager *nam = new QNetworkAccessManager(this);
QSignalSpy clientSpy(nam, SIGNAL(finished(QNetworkReply*)));
// Get all rules
QNetworkRequest request = QNetworkRequest(QUrl("http://localhost:3000/api/v1/rules"));
QNetworkReply *reply = nam->get(request);
clientSpy.wait();
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QCOMPARE(statusCode, 200);
QByteArray data = reply->readAll();
reply->deleteLater();
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
QCOMPARE(error.error, QJsonParseError::NoError);
QVariantList rulesList = jsonDoc.toVariant().toList();
// delete each rule
foreach (const QVariant &rule, rulesList) {
clientSpy.clear();
QVariantMap ruleMap = rule.toMap();
QNetworkRequest request(QUrl(QString("http://localhost:3000/api/v1/rules/%1").arg(ruleMap.value("id").toString())));
request.setHeader(QNetworkRequest::ContentTypeHeader, "text/json");
reply = nam->deleteResource(request);
clientSpy.wait();
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QCOMPARE(statusCode, 200);
reply->deleteLater();
}
nam->deleteLater();
}
void TestRestRules::verifyRuleExecuted(const ActionTypeId &actionTypeId)
{
// Verify rule got executed
QNetworkAccessManager nam;
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
QNetworkRequest request(QUrl(QString("http://localhost:%1/actionhistory").arg(m_mockDevice1Port)));
QNetworkReply *reply = nam.get(request);
spy.wait(500);
QCOMPARE(spy.count(), 1);
QByteArray actionHistory = reply->readAll();
qDebug() << "have action history" << actionHistory;
QVERIFY2(actionTypeId == ActionTypeId(actionHistory), "Action not triggered");
reply->deleteLater();
}
void TestRestRules::verifyRuleNotExecuted()
{
QNetworkAccessManager nam;
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
QNetworkRequest request(QUrl(QString("http://localhost:%1/actionhistory").arg(m_mockDevice1Port)));
QNetworkReply *reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
QByteArray actionHistory = reply->readAll();
qDebug() << "have action history" << actionHistory;
QVERIFY2(actionHistory.isEmpty(), "Action is triggered while it should not have been.");
reply->deleteLater();
}
void TestRestRules::addRemoveRules_data()
{
// RuleAction
QVariantMap validActionNoParams;
validActionNoParams.insert("actionTypeId", mockActionIdNoParams);
validActionNoParams.insert("deviceId", m_mockDeviceId);
validActionNoParams.insert("ruleActionParams", QVariantList());
QVariantMap invalidAction;
invalidAction.insert("actionTypeId", ActionTypeId());
invalidAction.insert("deviceId", m_mockDeviceId);
invalidAction.insert("ruleActionParams", QVariantList());
// RuleExitAction
QVariantMap validExitActionNoParams;
validExitActionNoParams.insert("actionTypeId", mockActionIdNoParams);
validExitActionNoParams.insert("deviceId", m_mockDeviceId);
validExitActionNoParams.insert("ruleActionParams", QVariantList());
QVariantMap invalidExitAction;
invalidExitAction.insert("actionTypeId", ActionTypeId());
invalidExitAction.insert("deviceId", m_mockDeviceId);
invalidExitAction.insert("ruleActionParams", QVariantList());
// StateDescriptor
QVariantMap stateDescriptor;
stateDescriptor.insert("stateTypeId", mockIntStateId);
stateDescriptor.insert("deviceId", m_mockDeviceId);
stateDescriptor.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorLess));
stateDescriptor.insert("value", "20");
// StateEvaluator
QVariantMap validStateEvaluator;
validStateEvaluator.insert("stateDescriptor", stateDescriptor);
validStateEvaluator.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd));
QVariantMap invalidStateEvaluator;
stateDescriptor.remove("deviceId");
invalidStateEvaluator.insert("stateDescriptor", stateDescriptor);
// EventDescriptor
QVariantMap validEventDescriptor1;
validEventDescriptor1.insert("eventTypeId", mockEvent1Id);
validEventDescriptor1.insert("deviceId", m_mockDeviceId);
validEventDescriptor1.insert("paramDescriptors", QVariantList());
QVariantMap validEventDescriptor2;
validEventDescriptor2.insert("eventTypeId", mockEvent2Id);
validEventDescriptor2.insert("deviceId", m_mockDeviceId);
QVariantList params;
QVariantMap param1;
param1.insert("name", "mockParamInt");
param1.insert("value", 3);
param1.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals));
params.append(param1);
validEventDescriptor2.insert("paramDescriptors", params);
QVariantMap validEventDescriptor3;
validEventDescriptor3.insert("eventTypeId", mockEvent2Id);
validEventDescriptor3.insert("deviceId", m_mockDeviceId);
validEventDescriptor3.insert("paramDescriptors", QVariantList());
// EventDescriptorList
QVariantList eventDescriptorList;
eventDescriptorList.append(validEventDescriptor1);
eventDescriptorList.append(validEventDescriptor2);
QVariantMap invalidEventDescriptor;
invalidEventDescriptor.insert("eventTypeId", mockEvent1Id);
invalidEventDescriptor.insert("deviceId", DeviceId());
invalidEventDescriptor.insert("paramDescriptors", QVariantList());
// RuleAction event based
QVariantMap validActionEventBased;
validActionEventBased.insert("actionTypeId", mockActionIdWithParams);
validActionEventBased.insert("deviceId", m_mockDeviceId);
QVariantMap validActionEventBasedParam1;
validActionEventBasedParam1.insert("name", "mockActionParam1");
validActionEventBasedParam1.insert("eventTypeId", mockEvent2Id);
validActionEventBasedParam1.insert("eventParamName", "mockParamInt");
QVariantMap validActionEventBasedParam2;
validActionEventBasedParam2.insert("name", "mockActionParam2");
validActionEventBasedParam2.insert("value", false);
validActionEventBased.insert("ruleActionParams", QVariantList() << validActionEventBasedParam1 << validActionEventBasedParam2);
QVariantMap invalidActionEventBased;
invalidActionEventBased.insert("actionTypeId", mockActionIdNoParams);
invalidActionEventBased.insert("deviceId", m_mockDeviceId);
validActionEventBasedParam1.insert("value", 10);
invalidActionEventBased.insert("ruleActionParams", QVariantList() << validActionEventBasedParam1);
QVariantMap invalidActionEventBased2;
invalidActionEventBased2.insert("actionTypeId", mockActionIdWithParams);
invalidActionEventBased2.insert("deviceId", m_mockDeviceId);
QVariantMap invalidActionEventBasedParam2;
invalidActionEventBasedParam2.insert("name", "mockActionParam1");
invalidActionEventBasedParam2.insert("eventTypeId", mockEvent1Id);
invalidActionEventBasedParam2.insert("eventParamName", "value");
QVariantMap invalidActionEventBasedParam3;
invalidActionEventBasedParam3.insert("name", "mockActionParam2");
invalidActionEventBasedParam3.insert("value", 2);
invalidActionEventBased2.insert("ruleActionParams", QVariantList() << invalidActionEventBasedParam2 << invalidActionEventBasedParam3);
QVariantMap invalidActionEventBased3;
invalidActionEventBased3.insert("actionTypeId", mockActionIdWithParams);
invalidActionEventBased3.insert("deviceId", m_mockDeviceId);
QVariantMap invalidActionEventBasedParam4;
invalidActionEventBasedParam4.insert("name", "mockActionParam1");
invalidActionEventBasedParam4.insert("eventTypeId", mockEvent1Id);
invalidActionEventBasedParam4.insert("eventParamName", "mockParamInt");
invalidActionEventBased3.insert("ruleActionParams", QVariantList() << invalidActionEventBasedParam4);
QTest::addColumn<bool>("enabled");
QTest::addColumn<QVariantMap>("action1");
QTest::addColumn<QVariantMap>("exitAction1");
QTest::addColumn<QVariantMap>("eventDescriptor");
QTest::addColumn<QVariantList>("eventDescriptorList");
QTest::addColumn<QVariantMap>("stateEvaluator");
QTest::addColumn<int>("expectedStatusCode");
QTest::addColumn<bool>("jsonError");
QTest::addColumn<QString>("name");
// Rules with event based actions
QTest::newRow("valid rule. enabled, 1 Action (eventBased), 1 EventDescriptor, name") << true << validActionEventBased << QVariantMap() << validEventDescriptor3 << QVariantList() << QVariantMap() << 200 << true << "ActionEventRule1";
QTest::newRow("invalid rule. enabled, 1 Action (eventBased), 1 EventDescriptor, name") << true << invalidActionEventBased2 << QVariantMap() << validEventDescriptor3 << QVariantList() << QVariantMap() << 400 << false << "TestRule";
QTest::newRow("invalid rule. enabled, 1 Action (eventBased), types not matching, name") << true << invalidActionEventBased3 << QVariantMap() << validEventDescriptor1 << QVariantList() << QVariantMap() << 400 << false << "TestRule";
QTest::newRow("invalid rule. enabled, 1 Action (eventBased), 1 EventDescriptor, name") << true << invalidActionEventBased << QVariantMap() << validEventDescriptor2 << QVariantList() << QVariantMap() << 400 << false << "TestRule";
QTest::newRow("invalid rule. enabled, 1 Action (eventBased), 1 StateEvaluator, name") << true << validActionEventBased << QVariantMap() << QVariantMap() << QVariantList() << validStateEvaluator << 400 << false << "TestRule";
QTest::newRow("invalid rule. enabled, 1 Action (eventBased), 1 EventDescriptor, name") << true << validActionEventBased << validActionEventBased << validEventDescriptor2 << QVariantList() << QVariantMap() << 400 << false << "TestRule";
QTest::newRow("invalid rule. enabled, 1 Action, 1 ExitAction (EventBased), name") << true << validActionNoParams << validActionEventBased << validEventDescriptor2 << QVariantList() << QVariantMap() << 400 << false << "TestRule";
// Rules with exit actions
QTest::newRow("valid rule. enabled, 1 Action, 1 Exit Action, 1 StateEvaluator, name") << true << validActionNoParams << validExitActionNoParams << QVariantMap() << QVariantList() << validStateEvaluator << 200 << true << "TestRule";
QTest::newRow("valid rule. disabled, 1 Action, 1 Exit Action, 1 StateEvaluator, name") << false << validActionNoParams << validExitActionNoParams << QVariantMap() << QVariantList() << validStateEvaluator << 200 << true << "TestRule";
QTest::newRow("invalid rule. disabled, 1 Action, 1 invalid Exit Action, 1 StateEvaluator, name") << false << validActionNoParams << invalidExitAction << QVariantMap() << QVariantList() << validStateEvaluator << 400 << false << "TestRule";
QTest::newRow("invalid rule. 1 Action, 1 Exit Action, 1 EventDescriptor, 1 StateEvaluator, name") << true << validActionNoParams << validExitActionNoParams << validEventDescriptor1 << QVariantList() << validStateEvaluator << 400 << false << "TestRule";
QTest::newRow("invalid rule. 1 Action, 1 Exit Action, eventDescriptorList, 1 StateEvaluator, name") << true << validActionNoParams << validExitActionNoParams << QVariantMap() << eventDescriptorList << validStateEvaluator << 400 << false << "TestRule";
// Rules without exit actions
QTest::newRow("valid rule. enabled, 1 EventDescriptor, StateEvaluator, 1 Action, name") << true << validActionNoParams << QVariantMap() << validEventDescriptor1 << QVariantList() << validStateEvaluator << 200 << true << "TestRule";
QTest::newRow("valid rule. diabled, 1 EventDescriptor, StateEvaluator, 1 Action, name") << false << validActionNoParams << QVariantMap() << validEventDescriptor1 << QVariantList() << validStateEvaluator << 200 << true << "TestRule";
QTest::newRow("valid rule. 2 EventDescriptors, 1 Action, name") << true << validActionNoParams << QVariantMap() << QVariantMap() << eventDescriptorList << validStateEvaluator << 200 << true << "TestRule";
QTest::newRow("invalid rule: eventDescriptor and eventDescriptorList used") << true << validActionNoParams << QVariantMap() << validEventDescriptor1 << eventDescriptorList << validStateEvaluator << 400 << false << "TestRule";
QTest::newRow("invalid action") << true << invalidAction << QVariantMap() << validEventDescriptor1 << QVariantList() << validStateEvaluator << 400 << false << "TestRule";
QTest::newRow("invalid event descriptor") << true << validActionNoParams << QVariantMap() << invalidEventDescriptor << QVariantList() << validStateEvaluator << 400 << false << "TestRule";
}
void TestRestRules::addRemoveRules()
{
QFETCH(bool, enabled);
QFETCH(QVariantMap, action1);
QFETCH(QVariantMap, exitAction1);
QFETCH(QVariantMap, eventDescriptor);
QFETCH(QVariantList, eventDescriptorList);
QFETCH(QVariantMap, stateEvaluator);
QFETCH(int, expectedStatusCode);
QFETCH(bool, jsonError);
QFETCH(QString, name);
Q_UNUSED(jsonError)
// create add params for rule
QVariantMap params;
params.insert("name", name);
QVariantList actions;
actions.append(action1);
params.insert("actions", actions);
if (!eventDescriptor.isEmpty()) {
params.insert("eventDescriptor", eventDescriptor);
}
if (!eventDescriptorList.isEmpty()) {
params.insert("eventDescriptorList", eventDescriptorList);
}
QVariantList exitActions;
if (!exitAction1.isEmpty()) {
exitActions.append(exitAction1);
params.insert("exitActions", exitActions);
}
params.insert("stateEvaluator", stateEvaluator);
if (!enabled) {
params.insert("enabled", enabled);
}
QNetworkAccessManager *nam = new QNetworkAccessManager(this);
QSignalSpy clientSpy(nam, SIGNAL(finished(QNetworkReply*)));
// Get rules and verify there is no rule added
QNetworkRequest request;
request.setUrl(QUrl("http://localhost:3000/api/v1/rules"));
QNetworkReply *reply = nam->get(request);
clientSpy.wait();
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QCOMPARE(statusCode, 200);
QByteArray data = reply->readAll();
reply->deleteLater();
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
QCOMPARE(error.error, QJsonParseError::NoError);
QVariantList rulesList = jsonDoc.toVariant().toList();
QVERIFY2(rulesList.count() == 0, "there should be no rules.");
// ADD rule
clientSpy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:3000/api/v1/rules")));
request.setHeader(QNetworkRequest::ContentTypeHeader, "text/json");
reply = nam->post(request, QJsonDocument::fromVariant(params).toJson(QJsonDocument::Compact));
clientSpy.wait();
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QCOMPARE(statusCode, expectedStatusCode);
if (expectedStatusCode != 200)
return;
jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error);
QCOMPARE(error.error, QJsonParseError::NoError);
reply->deleteLater();
RuleId ruleId = RuleId(jsonDoc.toVariant().toMap().value("ruleId").toString());
QVERIFY(!ruleId.isNull());
// GET rule details
clientSpy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:3000/api/v1/rules/%1").arg(ruleId.toString())));
request.setHeader(QNetworkRequest::ContentTypeHeader, "text/json");
reply = nam->get(request);
clientSpy.wait();
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QCOMPARE(statusCode, 200);
data = reply->readAll();
reply->deleteLater();
jsonDoc = QJsonDocument::fromJson(data, &error);
QCOMPARE(error.error, QJsonParseError::NoError);
// REMOVE rule
clientSpy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:3000/api/v1/rules/%1").arg(ruleId.toString())));
request.setHeader(QNetworkRequest::ContentTypeHeader, "text/json");
reply = nam->deleteResource(request);
clientSpy.wait();
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QCOMPARE(statusCode, 200);
reply->deleteLater();
nam->deleteLater();
}
void TestRestRules::editRules_data()
{
// RuleAction
QVariantMap validActionNoParams;
validActionNoParams.insert("actionTypeId", mockActionIdNoParams);
validActionNoParams.insert("deviceId", m_mockDeviceId);
validActionNoParams.insert("ruleActionParams", QVariantList());
QVariantMap invalidAction;
invalidAction.insert("actionTypeId", ActionTypeId());
invalidAction.insert("deviceId", m_mockDeviceId);
invalidAction.insert("ruleActionParams", QVariantList());
// RuleExitAction
QVariantMap validExitActionNoParams;
validExitActionNoParams.insert("actionTypeId", mockActionIdNoParams);
validExitActionNoParams.insert("deviceId", m_mockDeviceId);
validExitActionNoParams.insert("ruleActionParams", QVariantList());
QVariantMap invalidExitAction;
invalidExitAction.insert("actionTypeId", ActionTypeId());
invalidExitAction.insert("deviceId", m_mockDeviceId);
invalidExitAction.insert("ruleActionParams", QVariantList());
// StateDescriptor
QVariantMap stateDescriptor;
stateDescriptor.insert("stateTypeId", mockIntStateId);
stateDescriptor.insert("deviceId", m_mockDeviceId);
stateDescriptor.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorLess));
stateDescriptor.insert("value", "20");
// StateEvaluator
QVariantMap validStateEvaluator;
validStateEvaluator.insert("stateDescriptor", stateDescriptor);
validStateEvaluator.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd));
QVariantMap invalidStateEvaluator;
stateDescriptor.remove("deviceId");
invalidStateEvaluator.insert("stateDescriptor", stateDescriptor);
// EventDescriptor
QVariantMap validEventDescriptor1;
validEventDescriptor1.insert("eventTypeId", mockEvent1Id);
validEventDescriptor1.insert("deviceId", m_mockDeviceId);
validEventDescriptor1.insert("paramDescriptors", QVariantList());
QVariantMap validEventDescriptor2;
validEventDescriptor2.insert("eventTypeId", mockEvent2Id);
validEventDescriptor2.insert("deviceId", m_mockDeviceId);
QVariantList params;
QVariantMap param1;
param1.insert("name", "mockParamInt");
param1.insert("value", 3);
param1.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals));
params.append(param1);
validEventDescriptor2.insert("paramDescriptors", params);
QVariantMap validEventDescriptor3;
validEventDescriptor3.insert("eventTypeId", mockEvent2Id);
validEventDescriptor3.insert("deviceId", m_mockDeviceId);
validEventDescriptor3.insert("paramDescriptors", QVariantList());
// EventDescriptorList
QVariantList eventDescriptorList;
eventDescriptorList.append(validEventDescriptor1);
eventDescriptorList.append(validEventDescriptor2);
QVariantMap invalidEventDescriptor;
invalidEventDescriptor.insert("eventTypeId", mockEvent1Id);
invalidEventDescriptor.insert("deviceId", DeviceId());
invalidEventDescriptor.insert("paramDescriptors", QVariantList());
// RuleAction event based
QVariantMap validActionEventBased;
validActionEventBased.insert("actionTypeId", mockActionIdWithParams);
validActionEventBased.insert("deviceId", m_mockDeviceId);
QVariantMap validActionEventBasedParam1;
validActionEventBasedParam1.insert("name", "mockActionParam1");
validActionEventBasedParam1.insert("eventTypeId", mockEvent2Id);
validActionEventBasedParam1.insert("eventParamName", "mockParamInt");
QVariantMap validActionEventBasedParam2;
validActionEventBasedParam2.insert("name", "mockActionParam2");
validActionEventBasedParam2.insert("value", false);
validActionEventBased.insert("ruleActionParams", QVariantList() << validActionEventBasedParam1 << validActionEventBasedParam2);
QVariantMap invalidActionEventBased;
invalidActionEventBased.insert("actionTypeId", mockActionIdNoParams);
invalidActionEventBased.insert("deviceId", m_mockDeviceId);
validActionEventBasedParam1.insert("value", 10);
invalidActionEventBased.insert("ruleActionParams", QVariantList() << validActionEventBasedParam1);
QVariantMap invalidActionEventBased2;
invalidActionEventBased2.insert("actionTypeId", mockActionIdWithParams);
invalidActionEventBased2.insert("deviceId", m_mockDeviceId);
QVariantMap invalidActionEventBasedParam2;
invalidActionEventBasedParam2.insert("name", "mockActionParam1");
invalidActionEventBasedParam2.insert("eventTypeId", mockEvent1Id);
invalidActionEventBasedParam2.insert("eventParamName", "value");
QVariantMap invalidActionEventBasedParam3;
invalidActionEventBasedParam3.insert("name", "mockActionParam2");
invalidActionEventBasedParam3.insert("value", 2);
invalidActionEventBased2.insert("ruleActionParams", QVariantList() << invalidActionEventBasedParam2 << invalidActionEventBasedParam3);
QVariantMap invalidActionEventBased3;
invalidActionEventBased3.insert("actionTypeId", mockActionIdWithParams);
invalidActionEventBased3.insert("deviceId", m_mockDeviceId);
QVariantMap invalidActionEventBasedParam4;
invalidActionEventBasedParam4.insert("name", "mockActionParam1");
invalidActionEventBasedParam4.insert("eventTypeId", mockEvent1Id);
invalidActionEventBasedParam4.insert("eventParamName", "mockParamInt");
invalidActionEventBased3.insert("ruleActionParams", QVariantList() << invalidActionEventBasedParam4);
QTest::addColumn<bool>("enabled");
QTest::addColumn<QVariantMap>("action");
QTest::addColumn<QVariantMap>("exitAction");
QTest::addColumn<QVariantMap>("eventDescriptor");
QTest::addColumn<QVariantList>("eventDescriptorList");
QTest::addColumn<QVariantMap>("stateEvaluator");
QTest::addColumn<int>("expectedStatusCode");
QTest::addColumn<QString>("name");
// Rules with event based actions
QTest::newRow("valid rule. enabled, 1 Action (eventBased), 1 EventDescriptor, name") << true << validActionEventBased << QVariantMap() << validEventDescriptor3 << QVariantList() << QVariantMap() << 200 << "ActionEventRule1";
QTest::newRow("invalid rule. enabled, 1 Action (eventBased), 1 EventDescriptor, name") << true << invalidActionEventBased2 << QVariantMap() << validEventDescriptor3 << QVariantList() << QVariantMap() << 400 << "TestRule";
QTest::newRow("invalid rule. enabled, 1 Action (eventBased), types not matching, name") << true << invalidActionEventBased3 << QVariantMap() << validEventDescriptor1 << QVariantList() << QVariantMap() << 400 << "TestRule";
QTest::newRow("invalid rule. enabled, 1 Action (eventBased), 1 EventDescriptor, name") << true << invalidActionEventBased << QVariantMap() << validEventDescriptor2 << QVariantList() << QVariantMap() << 400 << "TestRule";
QTest::newRow("invalid rule. enabled, 1 Action (eventBased), 1 StateEvaluator, name") << true << validActionEventBased << QVariantMap() << QVariantMap() << QVariantList() << validStateEvaluator << 400 << "TestRule";
QTest::newRow("invalid rule. enabled, 1 Action (eventBased), 1 EventDescriptor, name") << true << validActionEventBased << validActionEventBased << validEventDescriptor2 << QVariantList() << QVariantMap() << 400 << "TestRule";
QTest::newRow("invalid rule. enabled, 1 Action, 1 ExitAction (EventBased), name") << true << validActionNoParams << validActionEventBased << validEventDescriptor2 << QVariantList() << QVariantMap() << 400 << "TestRule";
// Rules with exit actions
QTest::newRow("valid rule. enabled, 1 Action, 1 Exit Action, 1 StateEvaluator, name") << true << validActionNoParams << validExitActionNoParams << QVariantMap() << QVariantList() << validStateEvaluator << 200 << "TestRule";
QTest::newRow("valid rule. disabled, 1 Action, 1 Exit Action, 1 StateEvaluator, name") << false << validActionNoParams << validExitActionNoParams << QVariantMap() << QVariantList() << validStateEvaluator << 200 << "TestRule";
QTest::newRow("invalid rule. 1 Action, 1 Exit Action, 1 EventDescriptor, 1 StateEvaluator, name") << true << validActionNoParams << validExitActionNoParams << validEventDescriptor1 << QVariantList() << validStateEvaluator << 400 << "TestRule";
QTest::newRow("invalid rule. 1 Action, 1 Exit Action, eventDescriptorList, 1 StateEvaluator, name") << true << validActionNoParams << validExitActionNoParams << QVariantMap() << eventDescriptorList << validStateEvaluator << 400 << "TestRule";
// Rules without exit actions
QTest::newRow("valid rule. enabled, 1 EventDescriptor, StateEvaluator, 1 Action, name") << true << validActionNoParams << QVariantMap() << validEventDescriptor1 << QVariantList() << validStateEvaluator << 200 << "TestRule";
QTest::newRow("valid rule. diabled, 1 EventDescriptor, StateEvaluator, 1 Action, name") << false << validActionNoParams << QVariantMap() << validEventDescriptor1 << QVariantList() << validStateEvaluator << 200 << "TestRule";
QTest::newRow("valid rule. 2 EventDescriptors, 1 Action, name") << true << validActionNoParams << QVariantMap() << QVariantMap() << eventDescriptorList << validStateEvaluator << 200 << "TestRule";
QTest::newRow("invalid rule: eventDescriptor and eventDescriptorList used") << true << validActionNoParams << QVariantMap() << validEventDescriptor1 << eventDescriptorList << validStateEvaluator << 400 << "TestRule";
}
void TestRestRules::editRules()
{
QFETCH(bool, enabled);
QFETCH(QVariantMap, action);
QFETCH(QVariantMap, exitAction);
QFETCH(QVariantMap, eventDescriptor);
QFETCH(QVariantList, eventDescriptorList);
QFETCH(QVariantMap, stateEvaluator);
QFETCH(int, expectedStatusCode);
QFETCH(QString, name);
// Add the rule we want to edit
QVariantList eventParamDescriptors;
QVariantMap eventDescriptor1;
eventDescriptor1.insert("eventTypeId", mockEvent1Id);
eventDescriptor1.insert("deviceId", m_mockDeviceId);
eventDescriptor1.insert("paramDescriptors", QVariantList());
QVariantMap eventDescriptor2;
eventDescriptor2.insert("eventTypeId", mockEvent2Id);
eventDescriptor2.insert("deviceId", m_mockDeviceId);
eventDescriptor2.insert("paramDescriptors", QVariantList());
QVariantMap eventParam1;
eventParam1.insert("name", "mockParamInt");
eventParam1.insert("value", 3);
eventParam1.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals));
eventParamDescriptors.append(eventParam1);
eventDescriptor2.insert("paramDescriptors", eventParamDescriptors);
QVariantList eventDescriptorList1;
eventDescriptorList1.append(eventDescriptor1);
eventDescriptorList1.append(eventDescriptor2);
QVariantMap stateEvaluator0;
QVariantMap stateDescriptor1;
stateDescriptor1.insert("deviceId", m_mockDeviceId);
stateDescriptor1.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals));
stateDescriptor1.insert("stateTypeId", mockIntStateId);
stateDescriptor1.insert("value", 1);
QVariantMap stateDescriptor2;
stateDescriptor2.insert("deviceId", m_mockDeviceId);
stateDescriptor2.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals));
stateDescriptor2.insert("stateTypeId", mockBoolStateId);
stateDescriptor2.insert("value", true);
QVariantMap stateEvaluator1;
stateEvaluator1.insert("stateDescriptor", stateDescriptor1);
stateEvaluator1.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd));
QVariantMap stateEvaluator2;
stateEvaluator2.insert("stateDescriptor", stateDescriptor2);
stateEvaluator2.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd));
QVariantList childEvaluators;
childEvaluators.append(stateEvaluator1);
childEvaluators.append(stateEvaluator2);
stateEvaluator0.insert("childEvaluators", childEvaluators);
stateEvaluator0.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd));
QVariantMap action1;
action1.insert("actionTypeId", mockActionIdNoParams);
action1.insert("deviceId", m_mockDeviceId);
action1.insert("ruleActionParams", QVariantList());
QVariantMap action2;
action2.insert("actionTypeId", mockActionIdWithParams);
qDebug() << "got action id" << mockActionIdWithParams;
action2.insert("deviceId", m_mockDeviceId);
QVariantList action2Params;
QVariantMap action2Param1;
action2Param1.insert("name", "mockActionParam1");
action2Param1.insert("value", 5);
action2Params.append(action2Param1);
QVariantMap action2Param2;
action2Param2.insert("name", "mockActionParam2");
action2Param2.insert("value", true);
action2Params.append(action2Param2);
action2.insert("ruleActionParams", action2Params);
// RuleAction event based
QVariantMap validActionEventBased;
validActionEventBased.insert("actionTypeId", mockActionIdWithParams);
validActionEventBased.insert("deviceId", m_mockDeviceId);
QVariantMap validActionEventBasedParam1;
validActionEventBasedParam1.insert("name", "mockActionParam1");
validActionEventBasedParam1.insert("eventTypeId", mockEvent2Id);
validActionEventBasedParam1.insert("eventParamName", "mockParamInt");
QVariantMap validActionEventBasedParam2;
validActionEventBasedParam2.insert("name", "mockActionParam2");
validActionEventBasedParam2.insert("value", false);
validActionEventBased.insert("ruleActionParams", QVariantList() << validActionEventBasedParam1 << validActionEventBasedParam2);
QVariantList validEventDescriptors3;
QVariantMap validEventDescriptor3;
validEventDescriptor3.insert("eventTypeId", mockEvent2Id);
validEventDescriptor3.insert("deviceId", m_mockDeviceId);
validEventDescriptor3.insert("paramDescriptors", QVariantList());
validEventDescriptors3.append(validEventDescriptor3);
QVariantMap params;
QVariantList actions;
actions.append(action1);
actions.append(action2);
params.insert("actions", actions);
params.insert("eventDescriptorList", eventDescriptorList1);
params.insert("stateEvaluator", stateEvaluator0);
params.insert("name", "TestRule");
QNetworkAccessManager *nam = new QNetworkAccessManager(this);
QSignalSpy clientSpy(nam, SIGNAL(finished(QNetworkReply*)));
// Get rules and verify there is no rule added
QNetworkRequest request;
request.setUrl(QUrl("http://localhost:3000/api/v1/rules"));
QNetworkReply *reply = nam->get(request);
clientSpy.wait();
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QCOMPARE(statusCode, 200);
QByteArray data = reply->readAll();
reply->deleteLater();
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
QCOMPARE(error.error, QJsonParseError::NoError);
QVariantList rulesList = jsonDoc.toVariant().toList();
QVERIFY2(rulesList.count() == 0, "there should be no rules.");
// ADD rule
clientSpy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:3000/api/v1/rules")));
request.setHeader(QNetworkRequest::ContentTypeHeader, "text/json");
reply = nam->post(request, QJsonDocument::fromVariant(params).toJson(QJsonDocument::Compact));
clientSpy.wait();
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QCOMPARE(statusCode, 200);
jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error);
QCOMPARE(error.error, QJsonParseError::NoError);
reply->deleteLater();
RuleId ruleId = RuleId(jsonDoc.toVariant().toMap().value("ruleId").toString());
QVERIFY(!ruleId.isNull());
// now create the new rule and edit the original one
params.clear();
params.insert("ruleId", ruleId.toString());
params.insert("name", name);
if (!eventDescriptor.isEmpty()) {
params.insert("eventDescriptor", eventDescriptor);
}
if (!eventDescriptorList.isEmpty()) {
params.insert("eventDescriptorList", eventDescriptorList);
}
actions.clear();
actions.append(action);
params.insert("actions", actions);
QVariantList exitActions;
if (!exitAction.isEmpty()) {
exitActions.append(exitAction);
params.insert("exitActions", exitActions);
}
params.insert("stateEvaluator", stateEvaluator);
if (!enabled) {
params.insert("enabled", enabled);
}
// EDIT rule
clientSpy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:3000/api/v1/rules/%1").arg(ruleId.toString())));
request.setHeader(QNetworkRequest::ContentTypeHeader, "text/json");
reply = nam->put(request, QJsonDocument::fromVariant(params).toJson(QJsonDocument::Compact));
clientSpy.wait();
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QCOMPARE(statusCode, expectedStatusCode);
if (expectedStatusCode == 200) {
// get edit rule and verify params
clientSpy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:3000/api/v1/rules")));
request.setHeader(QNetworkRequest::ContentTypeHeader, "text/json");
reply = nam->get(request);
clientSpy.wait();
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QCOMPARE(statusCode, 200);
jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error);
QCOMPARE(error.error, QJsonParseError::NoError);
reply->deleteLater();
}
// REMOVE rule
clientSpy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:3000/api/v1/rules/%1").arg(ruleId.toString())));
request.setHeader(QNetworkRequest::ContentTypeHeader, "text/json");
reply = nam->deleteResource(request);
clientSpy.wait();
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QCOMPARE(statusCode, 200);
reply->deleteLater();
// check if removed
clientSpy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:3000/api/v1/rules/%1").arg(ruleId.toString())));
request.setHeader(QNetworkRequest::ContentTypeHeader, "text/json");
reply = nam->get(request);
clientSpy.wait();
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QCOMPARE(statusCode, 404);
reply->deleteLater();
nam->deleteLater();
}
void TestRestRules::enableDisableRule()
{
QVariantMap addRuleParams;
QVariantList events;
QVariantMap event1;
event1.insert("eventTypeId", mockEvent1Id);
event1.insert("deviceId", m_mockDeviceId);
events.append(event1);
addRuleParams.insert("eventDescriptorList", events);
addRuleParams.insert("name", "TestRule");
QVariantList actions;
QVariantMap action;
action.insert("actionTypeId", mockActionIdNoParams);
action.insert("deviceId", m_mockDeviceId);
actions.append(action);
addRuleParams.insert("actions", actions);
QNetworkAccessManager *nam = new QNetworkAccessManager(this);
QSignalSpy clientSpy(nam, SIGNAL(finished(QNetworkReply*)));
// ADD rule
QNetworkRequest request = QNetworkRequest(QUrl(QString("http://localhost:3000/api/v1/rules")));
request.setHeader(QNetworkRequest::ContentTypeHeader, "text/json");
QNetworkReply *reply = nam->post(request, QJsonDocument::fromVariant(addRuleParams).toJson(QJsonDocument::Compact));
clientSpy.wait();
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QCOMPARE(statusCode, 200);
QByteArray data = reply->readAll();
reply->deleteLater();
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
QCOMPARE(error.error, QJsonParseError::NoError);
RuleId ruleId = RuleId(jsonDoc.toVariant().toMap().value("ruleId").toString());
QVERIFY(!ruleId.isNull());
// ENABLE rule
clientSpy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:3000/api/v1/rules/%1/enable").arg(ruleId.toString())));
reply = nam->post(request, QByteArray());
clientSpy.wait();
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QCOMPARE(statusCode, 200);
reply->deleteLater();
// Trigger an event
// trigger event in mock device
clientSpy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:%1/generateevent?eventtypeid=%2").arg(m_mockDevice1Port).arg(mockEvent1Id.toString())));
reply = nam->get(request);
clientSpy.wait();
QCOMPARE(clientSpy.count(), 1);
reply->deleteLater();
verifyRuleExecuted(mockActionIdNoParams);
cleanupMockHistory();
// DISABLE the rule
clientSpy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:3000/api/v1/rules/%1/disable").arg(ruleId.toString())));
reply = nam->post(request, QByteArray());
clientSpy.wait();
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QCOMPARE(statusCode, 200);
reply->deleteLater();
// trigger event in mock device
clientSpy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:%1/generateevent?eventtypeid=%2").arg(m_mockDevice1Port).arg(mockEvent1Id.toString())));
reply = nam->get(request);
clientSpy.wait();
QCOMPARE(clientSpy.count(), 1);
reply->deleteLater();
verifyRuleNotExecuted();
cleanupMockHistory();
// ENABLE again
clientSpy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:3000/api/v1/rules/%1/enable").arg(ruleId.toString())));
reply = nam->post(request, QByteArray());
clientSpy.wait();
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QCOMPARE(statusCode, 200);
reply->deleteLater();
// trigger event in mock device
clientSpy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:%1/generateevent?eventtypeid=%2").arg(m_mockDevice1Port).arg(mockEvent1Id.toString())));
reply = nam->get(request);
clientSpy.wait();
QCOMPARE(clientSpy.count(), 1);
reply->deleteLater();
verifyRuleExecuted(mockActionIdNoParams);
cleanupRules();
}
void TestRestRules::getRules()
{
QNetworkAccessManager *nam = new QNetworkAccessManager(this);
QSignalSpy clientSpy(nam, SIGNAL(finished(QNetworkReply*)));
// Get all rules
QNetworkRequest request;
request.setUrl(QUrl("http://localhost:3000/api/v1/rules"));
QNetworkReply *reply = nam->get(request);
clientSpy.wait();
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QCOMPARE(statusCode, 200);
QByteArray data = reply->readAll();
reply->deleteLater();
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
QCOMPARE(error.error, QJsonParseError::NoError);
QVariantList rulesList = jsonDoc.toVariant().toList();
QVERIFY2(rulesList.count() == 0, "there should be at least one vendor.");
// Get each of thouse rules individualy
foreach (const QVariant &rule, rulesList) {
QVariantMap ruleMap = rule.toMap();
QNetworkRequest request(QUrl(QString("http://localhost:3000/api/v1/rules/%1").arg(ruleMap.value("id").toString())));
request.setHeader(QNetworkRequest::ContentTypeHeader, "text/json");
clientSpy.clear();
QNetworkReply *reply = nam->get(request);
clientSpy.wait();
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QCOMPARE(statusCode, 200);
jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error);
QCOMPARE(error.error, QJsonParseError::NoError);
reply->deleteLater();
}
nam->deleteLater();
}
#include "testrestrules.moc"
QTEST_MAIN(TestRestRules)