Tests for Rule Engine component lifecycle event notification rule; improvements
This commit is contained in:
parent
ae709351ce
commit
bbaaa6b972
@ -20,7 +20,6 @@ import org.thingsboard.server.actors.TbActor;
|
|||||||
import org.thingsboard.server.actors.TbActorCtx;
|
import org.thingsboard.server.actors.TbActorCtx;
|
||||||
import org.thingsboard.server.actors.TbActorId;
|
import org.thingsboard.server.actors.TbActorId;
|
||||||
import org.thingsboard.server.actors.TbEntityActorId;
|
import org.thingsboard.server.actors.TbEntityActorId;
|
||||||
import org.thingsboard.server.actors.service.ComponentActor;
|
|
||||||
import org.thingsboard.server.actors.service.ContextBasedCreator;
|
import org.thingsboard.server.actors.service.ContextBasedCreator;
|
||||||
import org.thingsboard.server.common.data.id.RuleChainId;
|
import org.thingsboard.server.common.data.id.RuleChainId;
|
||||||
import org.thingsboard.server.common.data.id.TenantId;
|
import org.thingsboard.server.common.data.id.TenantId;
|
||||||
@ -30,7 +29,7 @@ import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
|
|||||||
import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
|
import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
|
||||||
import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
|
import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
|
||||||
|
|
||||||
public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMessageProcessor> {
|
public class RuleChainActor extends RuleEngineComponentActor<RuleChainId, RuleChainActorMessageProcessor> {
|
||||||
|
|
||||||
private final RuleChain ruleChain;
|
private final RuleChain ruleChain;
|
||||||
|
|
||||||
@ -106,6 +105,11 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe
|
|||||||
return ruleChain.getId();
|
return ruleChain.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getRuleChainName() {
|
||||||
|
return ruleChain.getName();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected long getErrorPersistFrequency() {
|
protected long getErrorPersistFrequency() {
|
||||||
return systemContext.getRuleChainErrorPersistFrequency();
|
return systemContext.getRuleChainErrorPersistFrequency();
|
||||||
|
|||||||
@ -0,0 +1,43 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2022 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.server.actors.ruleChain;
|
||||||
|
|
||||||
|
import org.thingsboard.server.actors.ActorSystemContext;
|
||||||
|
import org.thingsboard.server.actors.service.ComponentActor;
|
||||||
|
import org.thingsboard.server.actors.shared.ComponentMsgProcessor;
|
||||||
|
import org.thingsboard.server.common.data.id.EntityId;
|
||||||
|
import org.thingsboard.server.common.data.id.RuleChainId;
|
||||||
|
import org.thingsboard.server.common.data.id.TenantId;
|
||||||
|
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
|
||||||
|
|
||||||
|
public abstract class RuleEngineComponentActor<T extends EntityId, P extends ComponentMsgProcessor<T>> extends ComponentActor<T, P> {
|
||||||
|
|
||||||
|
public RuleEngineComponentActor(ActorSystemContext systemContext, TenantId tenantId, T id) {
|
||||||
|
super(systemContext, tenantId, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void logLifecycleEvent(ComponentLifecycleEvent event, Exception e) {
|
||||||
|
super.logLifecycleEvent(event, e);
|
||||||
|
systemContext.getNotificationRuleProcessingService().process(tenantId, getRuleChainId(), getRuleChainName(),
|
||||||
|
id, processor.getComponentName(), event, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract RuleChainId getRuleChainId();
|
||||||
|
|
||||||
|
protected abstract String getRuleChainName();
|
||||||
|
|
||||||
|
}
|
||||||
@ -21,7 +21,6 @@ import org.thingsboard.server.actors.TbActor;
|
|||||||
import org.thingsboard.server.actors.TbActorCtx;
|
import org.thingsboard.server.actors.TbActorCtx;
|
||||||
import org.thingsboard.server.actors.TbActorId;
|
import org.thingsboard.server.actors.TbActorId;
|
||||||
import org.thingsboard.server.actors.TbEntityActorId;
|
import org.thingsboard.server.actors.TbEntityActorId;
|
||||||
import org.thingsboard.server.actors.service.ComponentActor;
|
|
||||||
import org.thingsboard.server.actors.service.ContextBasedCreator;
|
import org.thingsboard.server.actors.service.ContextBasedCreator;
|
||||||
import org.thingsboard.server.common.data.id.RuleChainId;
|
import org.thingsboard.server.common.data.id.RuleChainId;
|
||||||
import org.thingsboard.server.common.data.id.RuleNodeId;
|
import org.thingsboard.server.common.data.id.RuleNodeId;
|
||||||
@ -32,7 +31,7 @@ import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
|
|||||||
import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
|
import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessageProcessor> {
|
public class RuleNodeActor extends RuleEngineComponentActor<RuleNodeId, RuleNodeActorMessageProcessor> {
|
||||||
|
|
||||||
private final String ruleChainName;
|
private final String ruleChainName;
|
||||||
private final RuleChainId ruleChainId;
|
private final RuleChainId ruleChainId;
|
||||||
@ -138,6 +137,11 @@ public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessa
|
|||||||
return ruleChainId;
|
return ruleChainId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getRuleChainName() {
|
||||||
|
return ruleChainName;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected long getErrorPersistFrequency() {
|
protected long getErrorPersistFrequency() {
|
||||||
return systemContext.getRuleNodeErrorPersistFrequency();
|
return systemContext.getRuleNodeErrorPersistFrequency();
|
||||||
|
|||||||
@ -23,7 +23,6 @@ import org.thingsboard.server.actors.TbRuleNodeUpdateException;
|
|||||||
import org.thingsboard.server.actors.shared.ComponentMsgProcessor;
|
import org.thingsboard.server.actors.shared.ComponentMsgProcessor;
|
||||||
import org.thingsboard.server.actors.stats.StatsPersistMsg;
|
import org.thingsboard.server.actors.stats.StatsPersistMsg;
|
||||||
import org.thingsboard.server.common.data.id.EntityId;
|
import org.thingsboard.server.common.data.id.EntityId;
|
||||||
import org.thingsboard.server.common.data.id.RuleChainId;
|
|
||||||
import org.thingsboard.server.common.data.id.TenantId;
|
import org.thingsboard.server.common.data.id.TenantId;
|
||||||
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
|
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
|
||||||
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
|
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
|
||||||
@ -181,13 +180,10 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP
|
|||||||
logLifecycleEvent(event, null);
|
logLifecycleEvent(event, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logLifecycleEvent(ComponentLifecycleEvent event, Exception e) {
|
protected void logLifecycleEvent(ComponentLifecycleEvent event, Exception e) {
|
||||||
systemContext.persistLifecycleEvent(tenantId, id, event, e);
|
systemContext.persistLifecycleEvent(tenantId, id, event, e);
|
||||||
systemContext.getNotificationRuleProcessingService().process(tenantId, getRuleChainId(), id, processor.getComponentName(), event, e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract RuleChainId getRuleChainId();
|
|
||||||
|
|
||||||
protected abstract long getErrorPersistFrequency();
|
protected abstract long getErrorPersistFrequency();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -100,9 +100,10 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(TenantId tenantId, RuleChainId ruleChainId, EntityId componentId, String componentName, ComponentLifecycleEvent eventType, Exception error) {
|
public void process(TenantId tenantId, RuleChainId ruleChainId, String ruleChainName, EntityId componentId, String componentName, ComponentLifecycleEvent eventType, Exception error) {
|
||||||
RuleEngineComponentLifecycleEventTriggerObject triggerObject = RuleEngineComponentLifecycleEventTriggerObject.builder()
|
RuleEngineComponentLifecycleEventTriggerObject triggerObject = RuleEngineComponentLifecycleEventTriggerObject.builder()
|
||||||
.ruleChainId(ruleChainId)
|
.ruleChainId(ruleChainId)
|
||||||
|
.ruleChainName(ruleChainName)
|
||||||
.componentId(componentId)
|
.componentId(componentId)
|
||||||
.componentName(componentName)
|
.componentName(componentName)
|
||||||
.eventType(eventType)
|
.eventType(eventType)
|
||||||
|
|||||||
@ -28,6 +28,7 @@ public interface NotificationRuleProcessingService {
|
|||||||
|
|
||||||
void process(TenantId tenantId, Alarm alarm, boolean deleted);
|
void process(TenantId tenantId, Alarm alarm, boolean deleted);
|
||||||
|
|
||||||
void process(TenantId tenantId, RuleChainId ruleChainId, EntityId componentId, String componentName, ComponentLifecycleEvent eventType, Exception error);
|
void process(TenantId tenantId, RuleChainId ruleChainId, String ruleChainName,
|
||||||
|
EntityId componentId, String componentName, ComponentLifecycleEvent eventType, Exception error);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,9 +15,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.thingsboard.server.service.notification.rule.trigger;
|
package org.thingsboard.server.service.notification.rule.trigger;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.thingsboard.server.common.data.EntityType;
|
import org.thingsboard.server.common.data.EntityType;
|
||||||
import org.thingsboard.server.common.data.id.EntityId;
|
import org.thingsboard.server.common.data.id.EntityId;
|
||||||
@ -29,7 +31,6 @@ import org.thingsboard.server.common.data.notification.rule.trigger.RuleEngineCo
|
|||||||
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
|
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
|
||||||
import org.thingsboard.server.service.notification.rule.trigger.RuleEngineComponentLifecycleEventTriggerProcessor.RuleEngineComponentLifecycleEventTriggerObject;
|
import org.thingsboard.server.service.notification.rule.trigger.RuleEngineComponentLifecycleEventTriggerProcessor.RuleEngineComponentLifecycleEventTriggerObject;
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@ -72,13 +73,24 @@ public class RuleEngineComponentLifecycleEventTriggerProcessor implements Notifi
|
|||||||
public NotificationInfo constructNotificationInfo(RuleEngineComponentLifecycleEventTriggerObject triggerObject, RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig triggerConfig) {
|
public NotificationInfo constructNotificationInfo(RuleEngineComponentLifecycleEventTriggerObject triggerObject, RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig triggerConfig) {
|
||||||
return RuleEngineComponentLifecycleEventNotificationInfo.builder()
|
return RuleEngineComponentLifecycleEventNotificationInfo.builder()
|
||||||
.ruleChainId(triggerObject.getRuleChainId())
|
.ruleChainId(triggerObject.getRuleChainId())
|
||||||
|
.ruleChainName(triggerObject.getRuleChainName())
|
||||||
.componentId(triggerObject.getComponentId())
|
.componentId(triggerObject.getComponentId())
|
||||||
.componentName(triggerObject.getComponentName())
|
.componentName(triggerObject.getComponentName())
|
||||||
.eventType(triggerObject.getEventType())
|
.eventType(triggerObject.getEventType())
|
||||||
.error(Optional.ofNullable(triggerObject.getError()).map(Throwable::getMessage).orElse(null))
|
.error(getErrorMsg(triggerObject.getError()))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getErrorMsg(Exception error) {
|
||||||
|
String errorMsg = error != null ? error.getMessage() : null;
|
||||||
|
errorMsg = Strings.nullToEmpty(errorMsg);
|
||||||
|
int lengthLimit = 150;
|
||||||
|
if (errorMsg.length() > lengthLimit) {
|
||||||
|
errorMsg = StringUtils.substring(errorMsg, 0, lengthLimit + 1).trim() + "[...]";
|
||||||
|
}
|
||||||
|
return errorMsg;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NotificationRuleTriggerType getTriggerType() {
|
public NotificationRuleTriggerType getTriggerType() {
|
||||||
return NotificationRuleTriggerType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT;
|
return NotificationRuleTriggerType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT;
|
||||||
@ -88,6 +100,7 @@ public class RuleEngineComponentLifecycleEventTriggerProcessor implements Notifi
|
|||||||
@Builder
|
@Builder
|
||||||
public static class RuleEngineComponentLifecycleEventTriggerObject {
|
public static class RuleEngineComponentLifecycleEventTriggerObject {
|
||||||
private final RuleChainId ruleChainId;
|
private final RuleChainId ruleChainId;
|
||||||
|
private final String ruleChainName;
|
||||||
private final EntityId componentId;
|
private final EntityId componentId;
|
||||||
private final String componentName;
|
private final String componentName;
|
||||||
private final ComponentLifecycleEvent eventType;
|
private final ComponentLifecycleEvent eventType;
|
||||||
|
|||||||
@ -24,6 +24,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.boot.test.mock.mockito.SpyBean;
|
import org.springframework.boot.test.mock.mockito.SpyBean;
|
||||||
import org.springframework.data.util.Pair;
|
import org.springframework.data.util.Pair;
|
||||||
import org.thingsboard.common.util.JacksonUtil;
|
import org.thingsboard.common.util.JacksonUtil;
|
||||||
|
import org.thingsboard.rule.engine.debug.TbMsgGeneratorNode;
|
||||||
|
import org.thingsboard.rule.engine.debug.TbMsgGeneratorNodeConfiguration;
|
||||||
import org.thingsboard.server.common.data.DataConstants;
|
import org.thingsboard.server.common.data.DataConstants;
|
||||||
import org.thingsboard.server.common.data.Device;
|
import org.thingsboard.server.common.data.Device;
|
||||||
import org.thingsboard.server.common.data.DeviceProfile;
|
import org.thingsboard.server.common.data.DeviceProfile;
|
||||||
@ -40,6 +42,7 @@ import org.thingsboard.server.common.data.device.profile.AlarmRule;
|
|||||||
import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm;
|
import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm;
|
||||||
import org.thingsboard.server.common.data.device.profile.SimpleAlarmConditionSpec;
|
import org.thingsboard.server.common.data.device.profile.SimpleAlarmConditionSpec;
|
||||||
import org.thingsboard.server.common.data.id.NotificationRuleId;
|
import org.thingsboard.server.common.data.id.NotificationRuleId;
|
||||||
|
import org.thingsboard.server.common.data.id.RuleChainId;
|
||||||
import org.thingsboard.server.common.data.notification.Notification;
|
import org.thingsboard.server.common.data.notification.Notification;
|
||||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
||||||
import org.thingsboard.server.common.data.notification.NotificationRequest;
|
import org.thingsboard.server.common.data.notification.NotificationRequest;
|
||||||
@ -53,13 +56,19 @@ import org.thingsboard.server.common.data.notification.rule.NotificationRuleInfo
|
|||||||
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig;
|
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig;
|
||||||
import org.thingsboard.server.common.data.notification.rule.trigger.EntityActionNotificationRuleTriggerConfig;
|
import org.thingsboard.server.common.data.notification.rule.trigger.EntityActionNotificationRuleTriggerConfig;
|
||||||
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
|
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
|
||||||
|
import org.thingsboard.server.common.data.notification.rule.trigger.RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig;
|
||||||
import org.thingsboard.server.common.data.notification.targets.NotificationTarget;
|
import org.thingsboard.server.common.data.notification.targets.NotificationTarget;
|
||||||
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
|
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
|
||||||
import org.thingsboard.server.common.data.page.PageData;
|
import org.thingsboard.server.common.data.page.PageData;
|
||||||
import org.thingsboard.server.common.data.page.PageLink;
|
import org.thingsboard.server.common.data.page.PageLink;
|
||||||
|
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
|
||||||
import org.thingsboard.server.common.data.query.BooleanFilterPredicate;
|
import org.thingsboard.server.common.data.query.BooleanFilterPredicate;
|
||||||
import org.thingsboard.server.common.data.query.EntityKeyValueType;
|
import org.thingsboard.server.common.data.query.EntityKeyValueType;
|
||||||
import org.thingsboard.server.common.data.query.FilterPredicateValue;
|
import org.thingsboard.server.common.data.query.FilterPredicateValue;
|
||||||
|
import org.thingsboard.server.common.data.rule.RuleChain;
|
||||||
|
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
|
||||||
|
import org.thingsboard.server.common.data.rule.RuleNode;
|
||||||
|
import org.thingsboard.server.common.data.script.ScriptLanguage;
|
||||||
import org.thingsboard.server.common.data.security.Authority;
|
import org.thingsboard.server.common.data.security.Authority;
|
||||||
import org.thingsboard.server.dao.alarm.AlarmService;
|
import org.thingsboard.server.dao.alarm.AlarmService;
|
||||||
import org.thingsboard.server.dao.notification.NotificationRequestService;
|
import org.thingsboard.server.dao.notification.NotificationRequestService;
|
||||||
@ -130,7 +139,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
|
|||||||
getWsClient().waitForUpdate(true);
|
getWsClient().waitForUpdate(true);
|
||||||
|
|
||||||
Notification notification = getWsClient().getLastDataUpdate().getUpdate();
|
Notification notification = getWsClient().getLastDataUpdate().getUpdate();
|
||||||
assertThat(notification.getSubject()).isEqualTo("ADDED: DEVICE [" + device.getId() + "]");
|
assertThat(notification.getSubject()).isEqualTo("added: DEVICE [" + device.getId() + "]");
|
||||||
assertThat(notification.getText()).isEqualTo("User: " + TENANT_ADMIN_EMAIL);
|
assertThat(notification.getText()).isEqualTo("User: " + TENANT_ADMIN_EMAIL);
|
||||||
|
|
||||||
|
|
||||||
@ -140,7 +149,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
|
|||||||
getWsClient().waitForUpdate(true);
|
getWsClient().waitForUpdate(true);
|
||||||
|
|
||||||
notification = getWsClient().getLastDataUpdate().getUpdate();
|
notification = getWsClient().getLastDataUpdate().getUpdate();
|
||||||
assertThat(notification.getSubject()).isEqualTo("UPDATED: DEVICE [" + device.getId() + "]");
|
assertThat(notification.getSubject()).isEqualTo("updated: DEVICE [" + device.getId() + "]");
|
||||||
|
|
||||||
|
|
||||||
getWsClient().registerWaitForUpdate();
|
getWsClient().registerWaitForUpdate();
|
||||||
@ -148,7 +157,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
|
|||||||
getWsClient().waitForUpdate(true);
|
getWsClient().waitForUpdate(true);
|
||||||
|
|
||||||
notification = getWsClient().getLastDataUpdate().getUpdate();
|
notification = getWsClient().getLastDataUpdate().getUpdate();
|
||||||
assertThat(notification.getSubject()).isEqualTo("DELETED: DEVICE [" + device.getId() + "]");
|
assertThat(notification.getSubject()).isEqualTo("deleted: DEVICE [" + device.getId() + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -307,6 +316,48 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
|
|||||||
assertThat(findNotificationRequests(EntityType.ALARM).getData()).filteredOn(NotificationRequest::isScheduled).isEmpty();
|
assertThat(findNotificationRequests(EntityType.ALARM).getData()).filteredOn(NotificationRequest::isScheduled).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotificationRuleProcessing_ruleEngineComponentLifecycleEvent_ruleNodeStartError() {
|
||||||
|
String subject = "Rule Node '${componentName}' in Rule Chain '${ruleChainName}' failed to start";
|
||||||
|
String text = "The error: ${error}";
|
||||||
|
NotificationTemplate template = createNotificationTemplate(NotificationType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT, subject, text, NotificationDeliveryMethod.PUSH);
|
||||||
|
|
||||||
|
NotificationRule rule = new NotificationRule();
|
||||||
|
rule.setName("Rule node start-up failures in my rule chain");
|
||||||
|
rule.setTemplateId(template.getId());
|
||||||
|
rule.setTriggerType(NotificationRuleTriggerType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT);
|
||||||
|
|
||||||
|
RuleChain ruleChain = createEmptyRuleChain("My Rule Chain");
|
||||||
|
var triggerConfig = new RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig();
|
||||||
|
triggerConfig.setRuleChains(Set.of(ruleChain.getUuidId()));
|
||||||
|
triggerConfig.setRuleChainEvents(Set.of(ComponentLifecycleEvent.STARTED));
|
||||||
|
triggerConfig.setOnlyRuleChainLifecycleFailures(true);
|
||||||
|
|
||||||
|
triggerConfig.setTrackRuleNodeEvents(true);
|
||||||
|
triggerConfig.setRuleNodeEvents(Set.of(ComponentLifecycleEvent.STARTED));
|
||||||
|
triggerConfig.setOnlyRuleNodeLifecycleFailures(true);
|
||||||
|
rule.setTriggerConfig(triggerConfig);
|
||||||
|
|
||||||
|
NotificationTarget target = createNotificationTarget(tenantAdminUserId);
|
||||||
|
DefaultNotificationRuleRecipientsConfig recipientsConfig = new DefaultNotificationRuleRecipientsConfig();
|
||||||
|
recipientsConfig.setTriggerType(NotificationRuleTriggerType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT);
|
||||||
|
recipientsConfig.setTargets(List.of(target.getUuidId()));
|
||||||
|
rule.setRecipientsConfig(recipientsConfig);
|
||||||
|
rule = saveNotificationRule(rule);
|
||||||
|
|
||||||
|
getWsClient().subscribeForUnreadNotifications(10).waitForReply(true);
|
||||||
|
getWsClient().registerWaitForUpdate();
|
||||||
|
|
||||||
|
addRuleNodeWithError(ruleChain.getId(), "My generator");
|
||||||
|
|
||||||
|
getWsClient().waitForUpdate(10000, true);
|
||||||
|
Notification notification = getWsClient().getLastDataUpdate().getUpdate();
|
||||||
|
|
||||||
|
assertThat(notification.getType()).isEqualTo(NotificationType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT);
|
||||||
|
assertThat(notification.getSubject()).isEqualTo("Rule Node 'My generator' in Rule Chain 'My Rule Chain' failed to start");
|
||||||
|
assertThat(notification.getText()).startsWith("The error: Can't compile script");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNotificationRuleInfo() throws Exception {
|
public void testNotificationRuleInfo() throws Exception {
|
||||||
NotificationDeliveryMethod[] deliveryMethods = {NotificationDeliveryMethod.PUSH, NotificationDeliveryMethod.EMAIL};
|
NotificationDeliveryMethod[] deliveryMethods = {NotificationDeliveryMethod.PUSH, NotificationDeliveryMethod.EMAIL};
|
||||||
@ -368,6 +419,41 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
|
|||||||
return deviceProfile;
|
return deviceProfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private RuleChain createEmptyRuleChain(String name) {
|
||||||
|
RuleChain ruleChain = new RuleChain();
|
||||||
|
ruleChain.setName(name);
|
||||||
|
ruleChain.setTenantId(tenantId);
|
||||||
|
ruleChain.setRoot(false);
|
||||||
|
ruleChain.setDebugMode(false);
|
||||||
|
ruleChain = doPost("/api/ruleChain", ruleChain, RuleChain.class);
|
||||||
|
|
||||||
|
RuleChainMetaData metaData = new RuleChainMetaData();
|
||||||
|
metaData.setRuleChainId(ruleChain.getId());
|
||||||
|
metaData.setNodes(List.of());
|
||||||
|
metaData = doPost("/api/ruleChain/metadata", metaData, RuleChainMetaData.class);
|
||||||
|
return ruleChain;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RuleNode addRuleNodeWithError(RuleChainId ruleChainId, String name) {
|
||||||
|
RuleChainMetaData metaData = new RuleChainMetaData();
|
||||||
|
metaData.setRuleChainId(ruleChainId);
|
||||||
|
|
||||||
|
RuleNode generatorNodeWithError = new RuleNode();
|
||||||
|
generatorNodeWithError.setName(name);
|
||||||
|
generatorNodeWithError.setType(TbMsgGeneratorNode.class.getName());
|
||||||
|
TbMsgGeneratorNodeConfiguration generatorNodeConfiguration = new TbMsgGeneratorNodeConfiguration();
|
||||||
|
generatorNodeConfiguration.setScriptLang(ScriptLanguage.JS);
|
||||||
|
generatorNodeConfiguration.setPeriodInSeconds(1000);
|
||||||
|
generatorNodeConfiguration.setMsgCount(1);
|
||||||
|
generatorNodeConfiguration.setJsScript("[return");
|
||||||
|
generatorNodeWithError.setConfiguration(mapper.valueToTree(generatorNodeConfiguration));
|
||||||
|
|
||||||
|
metaData.setNodes(List.of(generatorNodeWithError));
|
||||||
|
metaData.setFirstNodeIndex(0);
|
||||||
|
metaData = doPost("/api/ruleChain/metadata", metaData, RuleChainMetaData.class);
|
||||||
|
return metaData.getNodes().get(0);
|
||||||
|
}
|
||||||
|
|
||||||
private NotificationRule saveNotificationRule(NotificationRule notificationRule) {
|
private NotificationRule saveNotificationRule(NotificationRule notificationRule) {
|
||||||
return doPost("/api/notification/rule", notificationRule, NotificationRule.class);
|
return doPost("/api/notification/rule", notificationRule, NotificationRule.class);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,6 +35,7 @@ import org.thingsboard.server.common.data.notification.template.NotificationTemp
|
|||||||
import org.thingsboard.server.common.data.notification.template.NotificationTemplateConfig;
|
import org.thingsboard.server.common.data.notification.template.NotificationTemplateConfig;
|
||||||
import org.thingsboard.server.common.data.notification.template.PushDeliveryMethodNotificationTemplate;
|
import org.thingsboard.server.common.data.notification.template.PushDeliveryMethodNotificationTemplate;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -94,9 +95,10 @@ public class NotificationProcessingContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public <T extends DeliveryMethodNotificationTemplate> T getProcessedTemplate(NotificationDeliveryMethod deliveryMethod, Map<String, String> templateContext) {
|
public <T extends DeliveryMethodNotificationTemplate> T getProcessedTemplate(NotificationDeliveryMethod deliveryMethod, Map<String, String> templateContext) {
|
||||||
if (request.getInfo() != null && deliveryMethod != NotificationDeliveryMethod.PUSH) { // for push notifications we are processing template from info on each serialization
|
NotificationInfo info = request.getInfo();
|
||||||
|
if (info != null && deliveryMethod != NotificationDeliveryMethod.PUSH) { // for push notifications we are processing template from info on each serialization
|
||||||
templateContext = new HashMap<>(templateContext);
|
templateContext = new HashMap<>(templateContext);
|
||||||
templateContext.putAll(request.getInfo().getTemplateData());
|
templateContext.putAll(info.getTemplateData());
|
||||||
}
|
}
|
||||||
|
|
||||||
T template = (T) templates.get(deliveryMethod).copy();
|
T template = (T) templates.get(deliveryMethod).copy();
|
||||||
@ -114,7 +116,7 @@ public class NotificationProcessingContext {
|
|||||||
if (buttonConfig.isPresent()) {
|
if (buttonConfig.isPresent()) {
|
||||||
JsonNode link = buttonConfig.get().get("link");
|
JsonNode link = buttonConfig.get().get("link");
|
||||||
if (link != null && link.isTextual()) {
|
if (link != null && link.isTextual()) {
|
||||||
link = new TextNode(processTemplate(link.asText(), templateContext, request.getInfo().getTemplateData()));
|
link = new TextNode(processTemplate(link.asText(), templateContext, info != null ? info.getTemplateData() : Collections.emptyMap()));
|
||||||
buttonConfig.get().set("link", link);
|
buttonConfig.get().set("link", link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import lombok.AllArgsConstructor;
|
|||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.thingsboard.server.common.data.id.EntityId;
|
import org.thingsboard.server.common.data.id.EntityId;
|
||||||
import org.thingsboard.server.common.data.id.RuleChainId;
|
import org.thingsboard.server.common.data.id.RuleChainId;
|
||||||
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
|
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
|
||||||
@ -33,21 +34,22 @@ import java.util.Map;
|
|||||||
public class RuleEngineComponentLifecycleEventNotificationInfo implements NotificationInfo {
|
public class RuleEngineComponentLifecycleEventNotificationInfo implements NotificationInfo {
|
||||||
|
|
||||||
private RuleChainId ruleChainId;
|
private RuleChainId ruleChainId;
|
||||||
|
private String ruleChainName;
|
||||||
private EntityId componentId;
|
private EntityId componentId;
|
||||||
private String componentName;
|
private String componentName;
|
||||||
private ComponentLifecycleEvent eventType;
|
private ComponentLifecycleEvent eventType;
|
||||||
private String error;
|
private String error;
|
||||||
// TODO: add rule chain name
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, String> getTemplateData() {
|
public Map<String, String> getTemplateData() {
|
||||||
return Map.of(
|
return Map.of(
|
||||||
"ruleChainId", ruleChainId.toString(),
|
"ruleChainId", ruleChainId.toString(),
|
||||||
|
"ruleChainName", ruleChainName,
|
||||||
"componentId", componentId.toString(),
|
"componentId", componentId.toString(),
|
||||||
"componentType", componentId.getEntityType().name(),
|
"componentType", componentId.getEntityType().name(),
|
||||||
"componentName", componentName,
|
"componentName", componentName,
|
||||||
"eventType", eventType.name(),
|
"eventType", eventType.name(),
|
||||||
"error", Strings.nullToEmpty(error)
|
"error", error
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user