|
|
@ -27,7 +27,7 @@ import org.springframework.data.util.Pair; |
|
|
import org.springframework.test.context.TestPropertySource; |
|
|
import org.springframework.test.context.TestPropertySource; |
|
|
import org.thingsboard.common.util.JacksonUtil; |
|
|
import org.thingsboard.common.util.JacksonUtil; |
|
|
import org.thingsboard.server.cache.limits.RateLimitService; |
|
|
import org.thingsboard.server.cache.limits.RateLimitService; |
|
|
import org.thingsboard.server.common.data.DataConstants; |
|
|
import org.thingsboard.server.common.data.AttributeScope; |
|
|
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; |
|
|
import org.thingsboard.server.common.data.EntityType; |
|
|
import org.thingsboard.server.common.data.EntityType; |
|
|
@ -39,17 +39,19 @@ import org.thingsboard.server.common.data.alarm.AlarmCommentType; |
|
|
import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; |
|
|
import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; |
|
|
import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
|
|
import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
|
|
import org.thingsboard.server.common.data.alarm.AlarmStatus; |
|
|
import org.thingsboard.server.common.data.alarm.AlarmStatus; |
|
|
|
|
|
import org.thingsboard.server.common.data.alarm.rule.AlarmRule; |
|
|
|
|
|
import org.thingsboard.server.common.data.alarm.rule.condition.SimpleAlarmCondition; |
|
|
|
|
|
import org.thingsboard.server.common.data.alarm.rule.condition.expression.TbelAlarmConditionExpression; |
|
|
import org.thingsboard.server.common.data.asset.Asset; |
|
|
import org.thingsboard.server.common.data.asset.Asset; |
|
|
|
|
|
import org.thingsboard.server.common.data.cf.CalculatedField; |
|
|
|
|
|
import org.thingsboard.server.common.data.cf.CalculatedFieldType; |
|
|
|
|
|
import org.thingsboard.server.common.data.cf.configuration.AlarmCalculatedFieldConfiguration; |
|
|
|
|
|
import org.thingsboard.server.common.data.cf.configuration.Argument; |
|
|
|
|
|
import org.thingsboard.server.common.data.cf.configuration.ArgumentType; |
|
|
|
|
|
import org.thingsboard.server.common.data.cf.configuration.ReferencedEntityKey; |
|
|
import org.thingsboard.server.common.data.device.data.DefaultDeviceConfiguration; |
|
|
import org.thingsboard.server.common.data.device.data.DefaultDeviceConfiguration; |
|
|
import org.thingsboard.server.common.data.device.data.DefaultDeviceTransportConfiguration; |
|
|
import org.thingsboard.server.common.data.device.data.DefaultDeviceTransportConfiguration; |
|
|
import org.thingsboard.server.common.data.device.data.DeviceData; |
|
|
import org.thingsboard.server.common.data.device.data.DeviceData; |
|
|
import org.thingsboard.server.common.data.device.profile.AlarmCondition; |
|
|
|
|
|
import org.thingsboard.server.common.data.device.profile.AlarmConditionFilter; |
|
|
|
|
|
import org.thingsboard.server.common.data.device.profile.AlarmConditionFilterKey; |
|
|
|
|
|
import org.thingsboard.server.common.data.device.profile.AlarmConditionKeyType; |
|
|
|
|
|
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.SimpleAlarmConditionSpec; |
|
|
|
|
|
import org.thingsboard.server.common.data.edge.Edge; |
|
|
import org.thingsboard.server.common.data.edge.Edge; |
|
|
import org.thingsboard.server.common.data.id.AlarmId; |
|
|
import org.thingsboard.server.common.data.id.AlarmId; |
|
|
import org.thingsboard.server.common.data.id.DeviceId; |
|
|
import org.thingsboard.server.common.data.id.DeviceId; |
|
|
@ -87,9 +89,6 @@ import org.thingsboard.server.common.data.notification.targets.platform.SystemAd |
|
|
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.query.BooleanFilterPredicate; |
|
|
|
|
|
import org.thingsboard.server.common.data.query.EntityKeyValueType; |
|
|
|
|
|
import org.thingsboard.server.common.data.query.FilterPredicateValue; |
|
|
|
|
|
import org.thingsboard.server.common.data.rule.RuleChain; |
|
|
import org.thingsboard.server.common.data.rule.RuleChain; |
|
|
import org.thingsboard.server.common.data.rule.RuleChainMetaData; |
|
|
import org.thingsboard.server.common.data.rule.RuleChainMetaData; |
|
|
import org.thingsboard.server.common.data.security.Authority; |
|
|
import org.thingsboard.server.common.data.security.Authority; |
|
|
@ -106,12 +105,10 @@ import org.thingsboard.server.service.system.DefaultSystemInfoService; |
|
|
import org.thingsboard.server.service.telemetry.AlarmSubscriptionService; |
|
|
import org.thingsboard.server.service.telemetry.AlarmSubscriptionService; |
|
|
|
|
|
|
|
|
import java.lang.reflect.Method; |
|
|
import java.lang.reflect.Method; |
|
|
import java.util.ArrayList; |
|
|
|
|
|
import java.util.HashMap; |
|
|
import java.util.HashMap; |
|
|
import java.util.List; |
|
|
import java.util.List; |
|
|
import java.util.Map; |
|
|
import java.util.Map; |
|
|
import java.util.Set; |
|
|
import java.util.Set; |
|
|
import java.util.TreeMap; |
|
|
|
|
|
import java.util.UUID; |
|
|
import java.util.UUID; |
|
|
import java.util.concurrent.Callable; |
|
|
import java.util.concurrent.Callable; |
|
|
import java.util.concurrent.TimeUnit; |
|
|
import java.util.concurrent.TimeUnit; |
|
|
@ -193,7 +190,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { |
|
|
@Test |
|
|
@Test |
|
|
public void testNotificationRuleProcessing_alarmTrigger() throws Exception { |
|
|
public void testNotificationRuleProcessing_alarmTrigger() throws Exception { |
|
|
String notificationSubject = "Alarm type: ${alarmType}, status: ${alarmStatus}, " + |
|
|
String notificationSubject = "Alarm type: ${alarmType}, status: ${alarmStatus}, " + |
|
|
"severity: ${alarmSeverity}, deviceId: ${alarmOriginatorId}"; |
|
|
"severity: ${alarmSeverity}, deviceId: ${alarmOriginatorId}"; |
|
|
String notificationText = "Status: ${alarmStatus}, severity: ${alarmSeverity}"; |
|
|
String notificationText = "Status: ${alarmStatus}, severity: ${alarmSeverity}"; |
|
|
NotificationTemplate notificationTemplate = createNotificationTemplate(NotificationType.ALARM, notificationSubject, notificationText, NotificationDeliveryMethod.WEB); |
|
|
NotificationTemplate notificationTemplate = createNotificationTemplate(NotificationType.ALARM, notificationSubject, notificationText, NotificationDeliveryMethod.WEB); |
|
|
|
|
|
|
|
|
@ -234,8 +231,8 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
JsonNode attr = JacksonUtil.newObjectNode() |
|
|
JsonNode attr = JacksonUtil.newObjectNode() |
|
|
.set("bool", BooleanNode.TRUE); |
|
|
.set("createAlarm", BooleanNode.TRUE); |
|
|
doPost("/api/plugins/telemetry/" + device.getId() + "/" + DataConstants.SHARED_SCOPE, attr); |
|
|
postAttributes(device.getId(), AttributeScope.SERVER_SCOPE, attr.toString()); |
|
|
|
|
|
|
|
|
await().atMost(10, TimeUnit.SECONDS) |
|
|
await().atMost(10, TimeUnit.SECONDS) |
|
|
.until(() -> alarmSubscriptionService.findLatestByOriginatorAndType(tenantId, device.getId(), alarmType) != null); |
|
|
.until(() -> alarmSubscriptionService.findLatestByOriginatorAndType(tenantId, device.getId(), alarmType) != null); |
|
|
@ -250,7 +247,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { |
|
|
assertThat(actualDelay).isCloseTo(expectedDelay, offset(2.0)); |
|
|
assertThat(actualDelay).isCloseTo(expectedDelay, offset(2.0)); |
|
|
|
|
|
|
|
|
assertThat(notification.getSubject()).isEqualTo("Alarm type: " + alarmType + ", status: " + AlarmStatus.ACTIVE_UNACK + ", " + |
|
|
assertThat(notification.getSubject()).isEqualTo("Alarm type: " + alarmType + ", status: " + AlarmStatus.ACTIVE_UNACK + ", " + |
|
|
"severity: " + AlarmSeverity.CRITICAL.toString().toLowerCase() + ", deviceId: " + device.getId()); |
|
|
"severity: " + AlarmSeverity.CRITICAL.toString().toLowerCase() + ", deviceId: " + device.getId()); |
|
|
assertThat(notification.getText()).isEqualTo("Status: " + AlarmStatus.ACTIVE_UNACK + ", severity: " + AlarmSeverity.CRITICAL.toString().toLowerCase()); |
|
|
assertThat(notification.getText()).isEqualTo("Status: " + AlarmStatus.ACTIVE_UNACK + ", severity: " + AlarmSeverity.CRITICAL.toString().toLowerCase()); |
|
|
|
|
|
|
|
|
assertThat(notification.getType()).isEqualTo(NotificationType.ALARM); |
|
|
assertThat(notification.getType()).isEqualTo(NotificationType.ALARM); |
|
|
@ -270,7 +267,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { |
|
|
wsClient.waitForUpdate(true); |
|
|
wsClient.waitForUpdate(true); |
|
|
Notification updatedNotification = wsClient.getLastDataUpdate().getUpdate(); |
|
|
Notification updatedNotification = wsClient.getLastDataUpdate().getUpdate(); |
|
|
assertThat(updatedNotification.getSubject()).isEqualTo("Alarm type: " + alarmType + ", status: " + expectedStatus + ", " + |
|
|
assertThat(updatedNotification.getSubject()).isEqualTo("Alarm type: " + alarmType + ", status: " + expectedStatus + ", " + |
|
|
"severity: " + expectedSeverity.toString().toLowerCase() + ", deviceId: " + device.getId()); |
|
|
"severity: " + expectedSeverity.toString().toLowerCase() + ", deviceId: " + device.getId()); |
|
|
assertThat(updatedNotification.getText()).isEqualTo("Status: " + expectedStatus + ", severity: " + expectedSeverity.toString().toLowerCase()); |
|
|
assertThat(updatedNotification.getText()).isEqualTo("Status: " + expectedStatus + ", severity: " + expectedSeverity.toString().toLowerCase()); |
|
|
|
|
|
|
|
|
wsClient.close(); |
|
|
wsClient.close(); |
|
|
@ -296,7 +293,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { |
|
|
List<Notification> notifications = getMyNotifications(false, 10); |
|
|
List<Notification> notifications = getMyNotifications(false, 10); |
|
|
assertThat(notifications).singleElement().matches(notification -> { |
|
|
assertThat(notifications).singleElement().matches(notification -> { |
|
|
return notification.getType() == NotificationType.ALARM && |
|
|
return notification.getType() == NotificationType.ALARM && |
|
|
notification.getSubject().equals("New alarm 'testAlarm'"); |
|
|
notification.getSubject().equals("New alarm 'testAlarm'"); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
@ -341,8 +338,8 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { |
|
|
getWsClient().subscribeForUnreadNotifications(10).waitForReply(true); |
|
|
getWsClient().subscribeForUnreadNotifications(10).waitForReply(true); |
|
|
getWsClient().registerWaitForUpdate(); |
|
|
getWsClient().registerWaitForUpdate(); |
|
|
JsonNode attr = JacksonUtil.newObjectNode() |
|
|
JsonNode attr = JacksonUtil.newObjectNode() |
|
|
.set("bool", BooleanNode.TRUE); |
|
|
.set("createAlarm", BooleanNode.TRUE); |
|
|
doPost("/api/plugins/telemetry/" + device.getId() + "/" + DataConstants.SHARED_SCOPE, attr); |
|
|
postAttributes(device.getId(), AttributeScope.SERVER_SCOPE, attr.toString()); |
|
|
|
|
|
|
|
|
await().atMost(10, TimeUnit.SECONDS) |
|
|
await().atMost(10, TimeUnit.SECONDS) |
|
|
.until(() -> alarmSubscriptionService.findLatestByOriginatorAndType(tenantId, device.getId(), alarmType) != null); |
|
|
.until(() -> alarmSubscriptionService.findLatestByOriginatorAndType(tenantId, device.getId(), alarmType) != null); |
|
|
@ -491,11 +488,11 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { |
|
|
}); |
|
|
}); |
|
|
assertThat(notifications).anySatisfy(notification -> { |
|
|
assertThat(notifications).anySatisfy(notification -> { |
|
|
assertThat(notification.getText()).isEqualTo("Rate limits for REST API requests per customer " + |
|
|
assertThat(notification.getText()).isEqualTo("Rate limits for REST API requests per customer " + |
|
|
"exceeded for 'Customer'"); |
|
|
"exceeded for 'Customer'"); |
|
|
}); |
|
|
}); |
|
|
assertThat(notifications).anySatisfy(notification -> { |
|
|
assertThat(notifications).anySatisfy(notification -> { |
|
|
assertThat(notification.getText()).isEqualTo("Rate limits for notification requests " + |
|
|
assertThat(notification.getText()).isEqualTo("Rate limits for notification requests " + |
|
|
"per rule exceeded for '" + rule.getName() + "'"); |
|
|
"per rule exceeded for '" + rule.getName() + "'"); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
loginSysAdmin(); |
|
|
loginSysAdmin(); |
|
|
@ -748,7 +745,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { |
|
|
.build(); |
|
|
.build(); |
|
|
assertThat(DefaultNotificationDeduplicationService.getDeduplicationKey(expectedTrigger, rule)) |
|
|
assertThat(DefaultNotificationDeduplicationService.getDeduplicationKey(expectedTrigger, rule)) |
|
|
.isEqualTo("RATE_LIMITS:TENANT:" + tenantId + ":ENTITY_EXPORT_" + |
|
|
.isEqualTo("RATE_LIMITS:TENANT:" + tenantId + ":ENTITY_EXPORT_" + |
|
|
target.getId() + ":ENTITY_EXPORT,TRANSPORT_MESSAGES_PER_DEVICE"); |
|
|
target.getId() + ":ENTITY_EXPORT,TRANSPORT_MESSAGES_PER_DEVICE"); |
|
|
|
|
|
|
|
|
loginTenantAdmin(); |
|
|
loginTenantAdmin(); |
|
|
getWsClient().subscribeForUnreadNotifications(10).waitForReply(); |
|
|
getWsClient().subscribeForUnreadNotifications(10).waitForReply(); |
|
|
@ -944,35 +941,27 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { |
|
|
private DeviceProfile createDeviceProfileWithAlarmRules(String alarmType) { |
|
|
private DeviceProfile createDeviceProfileWithAlarmRules(String alarmType) { |
|
|
DeviceProfile deviceProfile = createDeviceProfile("For notification rule test"); |
|
|
DeviceProfile deviceProfile = createDeviceProfile("For notification rule test"); |
|
|
deviceProfile.setTenantId(tenantId); |
|
|
deviceProfile.setTenantId(tenantId); |
|
|
|
|
|
deviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); |
|
|
|
|
|
|
|
|
List<DeviceProfileAlarm> alarms = new ArrayList<>(); |
|
|
CalculatedField alarmCf = new CalculatedField(); |
|
|
DeviceProfileAlarm alarm = new DeviceProfileAlarm(); |
|
|
alarmCf.setType(CalculatedFieldType.ALARM); |
|
|
alarm.setAlarmType(alarmType); |
|
|
alarmCf.setEntityId(deviceProfile.getId()); |
|
|
alarm.setId(alarmType); |
|
|
alarmCf.setName(alarmType); |
|
|
|
|
|
AlarmCalculatedFieldConfiguration configuration = new AlarmCalculatedFieldConfiguration(); |
|
|
|
|
|
Argument argument = new Argument(); |
|
|
|
|
|
argument.setRefEntityKey(new ReferencedEntityKey("createAlarm", ArgumentType.ATTRIBUTE, AttributeScope.SERVER_SCOPE)); |
|
|
|
|
|
configuration.setArguments(Map.of("createAlarm", argument)); |
|
|
AlarmRule alarmRule = new AlarmRule(); |
|
|
AlarmRule alarmRule = new AlarmRule(); |
|
|
alarmRule.setAlarmDetails("Details"); |
|
|
SimpleAlarmCondition condition = new SimpleAlarmCondition(); |
|
|
AlarmCondition alarmCondition = new AlarmCondition(); |
|
|
TbelAlarmConditionExpression expression = new TbelAlarmConditionExpression(); |
|
|
alarmCondition.setSpec(new SimpleAlarmConditionSpec()); |
|
|
expression.setExpression("return createAlarm == true;"); |
|
|
List<AlarmConditionFilter> condition = new ArrayList<>(); |
|
|
condition.setExpression(expression); |
|
|
|
|
|
alarmRule.setCondition(condition); |
|
|
AlarmConditionFilter alarmConditionFilter = new AlarmConditionFilter(); |
|
|
configuration.setCreateRules(Map.of( |
|
|
alarmConditionFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.ATTRIBUTE, "bool")); |
|
|
AlarmSeverity.CRITICAL, alarmRule |
|
|
BooleanFilterPredicate predicate = new BooleanFilterPredicate(); |
|
|
)); |
|
|
predicate.setOperation(BooleanFilterPredicate.BooleanOperation.EQUAL); |
|
|
alarmCf.setConfiguration(configuration); |
|
|
predicate.setValue(new FilterPredicateValue<>(true)); |
|
|
saveCalculatedField(alarmCf); |
|
|
|
|
|
|
|
|
alarmConditionFilter.setPredicate(predicate); |
|
|
|
|
|
alarmConditionFilter.setValueType(EntityKeyValueType.BOOLEAN); |
|
|
|
|
|
condition.add(alarmConditionFilter); |
|
|
|
|
|
alarmCondition.setCondition(condition); |
|
|
|
|
|
alarmRule.setCondition(alarmCondition); |
|
|
|
|
|
TreeMap<AlarmSeverity, AlarmRule> createRules = new TreeMap<>(); |
|
|
|
|
|
createRules.put(AlarmSeverity.CRITICAL, alarmRule); |
|
|
|
|
|
alarm.setCreateRules(createRules); |
|
|
|
|
|
alarms.add(alarm); |
|
|
|
|
|
|
|
|
|
|
|
deviceProfile.getProfileData().setAlarms(alarms); |
|
|
|
|
|
deviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); |
|
|
|
|
|
return deviceProfile; |
|
|
return deviceProfile; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|