From 4145c22f06ed5413c860a5ba24c29d43bc5ff886 Mon Sep 17 00:00:00 2001 From: Andrii Landiak <50847617+AndriiLandiak@users.noreply.github.com> Date: Tue, 23 Jan 2024 15:00:02 +0200 Subject: [PATCH] Edge - alarm comment support (#94) --- .../cloud/CloudEventSourcingListener.java | 53 ++++++++++++--- .../service/cloud/CloudManagerService.java | 5 ++ .../DefaultCloudNotificationService.java | 66 +++++++++--------- .../cloud/DefaultDownlinkMessageService.java | 6 ++ .../rpc/processor/AlarmCloudProcessor.java | 31 +++++++++ .../rpc/processor/DeviceCloudProcessor.java | 2 +- .../rpc/processor/RelationCloudProcessor.java | 2 +- .../tenant/DefaultTbTenantService.java | 2 + .../oauth2/AbstractOAuth2ClientMapper.java | 9 +-- .../server/edge/AlarmEdgeTest.java | 2 + .../server/common/data/CloudUtils.java | 44 ++++-------- .../common/data/cloud/CloudEventType.java | 48 +++++++------ .../server/msa/AbstractContainerTest.java | 45 +++++++----- .../server/msa/ContainerTestSuite.java | 1 + .../server/msa/DockerComposeExecutor.java | 1 + .../server/msa/edge/AlarmClientTest.java | 68 ++++++++++++++----- .../server/msa/edge/AssetClientTest.java | 1 + .../msa/edge/AssetProfileClientTest.java | 1 + .../server/msa/edge/CustomerClientTest.java | 1 + .../server/msa/edge/DashboardClientTest.java | 1 + .../server/msa/edge/DeviceClientTest.java | 1 + .../msa/edge/DeviceProfileClientTest.java | 1 + .../server/msa/edge/EdgeClientTest.java | 1 + .../server/msa/edge/EntityViewClientTest.java | 1 + .../server/msa/edge/OtaPackageClientTest.java | 1 + .../server/msa/edge/QueueClientTest.java | 1 + .../server/msa/edge/RelationClientTest.java | 1 + .../server/msa/edge/ResourceClientTest.java | 1 + .../server/msa/edge/RuleChainClientTest.java | 1 + .../server/msa/edge/TelemetryClientTest.java | 1 + .../server/msa/edge/TenantClientTest.java | 1 + .../server/msa/edge/UserClientTest.java | 1 + .../edge/WidgetBundleAndTypeClientTest.java | 1 + .../Updated_EdgeRootRuleChainMetadata.json | 67 ++++++++++++++++-- .../Updated_RootRuleChainMetadata.json | 54 ++++++++++++++- 35 files changed, 376 insertions(+), 147 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/cloud/CloudEventSourcingListener.java b/application/src/main/java/org/thingsboard/server/service/cloud/CloudEventSourcingListener.java index 966638ef1b..6b7dfb9708 100644 --- a/application/src/main/java/org/thingsboard/server/service/cloud/CloudEventSourcingListener.java +++ b/application/src/main/java/org/thingsboard/server/service/cloud/CloudEventSourcingListener.java @@ -21,7 +21,9 @@ import org.springframework.transaction.event.TransactionalEventListener; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.cluster.TbClusterService; +import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.alarm.AlarmComment; import org.thingsboard.server.common.data.cloud.CloudEventType; import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.relation.EntityRelation; @@ -37,8 +39,6 @@ import java.util.Arrays; import java.util.List; -import static org.thingsboard.server.service.entitiy.DefaultTbNotificationEntityService.edgeTypeByActionType; - /** * This event listener does not support async event processing because relay on ThreadLocal * Another possible approach is to implement a special annotation and a bunch of classes similar to TransactionalApplicationListener @@ -87,13 +87,17 @@ public void handleEvent(SaveEntityEvent event) { return; } try { - if (event.getEntityId() != null && !saveEventSupportableEntityTypes.contains(event.getEntityId().getEntityType())) { + if (event.getEntityId() != null && !saveEventSupportableEntityTypes.contains(event.getEntityId().getEntityType()) + && !(event.getEntity() instanceof AlarmComment)) { return; } log.trace("SaveEntityEvent called: {}", event); - EdgeEventActionType action = Boolean.TRUE.equals(event.getAdded()) ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED; + boolean isCreated = Boolean.TRUE.equals(event.getCreated()); + String body = getBodyMsgForEntityEvent(event.getEntity()); + CloudEventType cloudEventType = getCloudEventTypeForEntityEvent(event.getEntity()); + EdgeEventActionType action = getActionForEntityEvent(event.getEntity(), isCreated); tbClusterService.sendNotificationMsgToCloud(event.getTenantId(), event.getEntityId(), - null, null, action); + body, cloudEventType, action); } catch (Exception e) { log.error("failed to process SaveEntityEvent: {}", event); } @@ -105,12 +109,15 @@ public void handleEvent(DeleteEntityEvent event) { return; } try { - if (event.getEntityId() != null && !supportableEntityTypes.contains(event.getEntityId().getEntityType())) { + if (event.getEntityId() != null && !supportableEntityTypes.contains(event.getEntityId().getEntityType()) + && !(event.getEntity() instanceof AlarmComment)) { return; } log.trace("DeleteEntityEvent called: {}", event); + CloudEventType type = getCloudEventTypeForEntityEvent(event.getEntity()); + EdgeEventActionType actionType = getEdgeEventActionTypeForEntityEvent(event.getEntity()); tbClusterService.sendNotificationMsgToCloud(event.getTenantId(), event.getEntityId(), - JacksonUtil.toString(event.getEntity()), null, EdgeEventActionType.DELETED); + JacksonUtil.toString(event.getEntity()), type, actionType); } catch (Exception e) { log.error("failed to process DeleteEntityEvent: {}", event); } @@ -127,7 +134,7 @@ public void handleEvent(ActionEntityEvent event) { } log.trace("ActionEntityEvent called: {}", event); tbClusterService.sendNotificationMsgToCloud(event.getTenantId(), event.getEntityId(), - event.getBody(), null, edgeTypeByActionType(event.getActionType())); + event.getBody(), null, EdgeUtils.getEdgeEventActionTypeByActionType(event.getActionType())); } catch (Exception e) { log.error("failed to process ActionEntityEvent: {}", event); } @@ -150,9 +157,37 @@ public void handleEvent(RelationActionEvent event) { } log.trace("RelationActionEvent called: {}", event); tbClusterService.sendNotificationMsgToCloud(event.getTenantId(), null, - JacksonUtil.toString(event.getRelation()), CloudEventType.RELATION, edgeTypeByActionType(event.getActionType())); + JacksonUtil.toString(event.getRelation()), CloudEventType.RELATION, EdgeUtils.getEdgeEventActionTypeByActionType(event.getActionType())); } catch (Exception e) { log.error("failed to process RelationActionEvent: {}", event); } } + + private CloudEventType getCloudEventTypeForEntityEvent(Object entity) { + if (entity instanceof AlarmComment) { + return CloudEventType.ALARM_COMMENT; + } + return null; + } + + private EdgeEventActionType getEdgeEventActionTypeForEntityEvent(Object entity) { + if (entity instanceof AlarmComment) { + return EdgeEventActionType.DELETED_COMMENT; + } + return EdgeEventActionType.DELETED; + } + + private String getBodyMsgForEntityEvent(Object entity) { + if (entity instanceof AlarmComment) { + return JacksonUtil.toString(entity); + } + return null; + } + + private EdgeEventActionType getActionForEntityEvent(Object entity, boolean isCreated) { + if (entity instanceof AlarmComment) { + return isCreated ? EdgeEventActionType.ADDED_COMMENT : EdgeEventActionType.UPDATED_COMMENT; + } + return isCreated ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED; + } } diff --git a/application/src/main/java/org/thingsboard/server/service/cloud/CloudManagerService.java b/application/src/main/java/org/thingsboard/server/service/cloud/CloudManagerService.java index aba5d8c016..edd7ad2d88 100644 --- a/application/src/main/java/org/thingsboard/server/service/cloud/CloudManagerService.java +++ b/application/src/main/java/org/thingsboard/server/service/cloud/CloudManagerService.java @@ -408,6 +408,9 @@ private List convertToUplinkMsgsPack(List cloudEvents) { case RELATION_DELETED: case ASSIGNED_TO_CUSTOMER: case UNASSIGNED_FROM_CUSTOMER: + case ADDED_COMMENT: + case UPDATED_COMMENT: + case DELETED_COMMENT: uplinkMsg = convertEntityEventToUplink(this.tenantId, cloudEvent); break; case ATTRIBUTES_UPDATED: @@ -458,6 +461,8 @@ private UplinkMsg convertEntityEventToUplink(TenantId tenantId, CloudEvent cloud return deviceProfileProcessor.convertDeviceProfileEventToUplink(cloudEvent, edgeVersion); case ALARM: return alarmProcessor.convertAlarmEventToUplink(cloudEvent, edgeVersion); + case ALARM_COMMENT: + return alarmProcessor.convertAlarmCommentEventToUplink(cloudEvent, edgeVersion); case ASSET: return assetProcessor.convertAssetEventToUplink(cloudEvent, edgeVersion); case ASSET_PROFILE: diff --git a/application/src/main/java/org/thingsboard/server/service/cloud/DefaultCloudNotificationService.java b/application/src/main/java/org/thingsboard/server/service/cloud/DefaultCloudNotificationService.java index aefcacf3de..7f3656ee41 100644 --- a/application/src/main/java/org/thingsboard/server/service/cloud/DefaultCloudNotificationService.java +++ b/application/src/main/java/org/thingsboard/server/service/cloud/DefaultCloudNotificationService.java @@ -26,6 +26,7 @@ import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.CloudUtils; import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmComment; import org.thingsboard.server.common.data.cloud.CloudEventType; import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.id.AlarmId; @@ -95,6 +96,9 @@ public void pushNotificationToCloud(TransportProtos.CloudNotificationMsgProto cl case RELATION: future = processRelation(tenantId, cloudNotificationMsg); break; + case ALARM_COMMENT: + future = processAlarmComment(tenantId, cloudNotificationMsg); + break; default: log.warn("Cloud event type [{}] is not designed to be pushed to cloud", cloudEventType); future = Futures.immediateFuture(null); @@ -121,7 +125,7 @@ private void callBackFailure(TransportProtos.CloudNotificationMsgProto cloudNoti } - private ListenableFuture processEntity(TenantId tenantId, TransportProtos.CloudNotificationMsgProto cloudNotificationMsg) throws Exception { + private ListenableFuture processEntity(TenantId tenantId, TransportProtos.CloudNotificationMsgProto cloudNotificationMsg) { EdgeEventActionType cloudEventActionType = EdgeEventActionType.valueOf(cloudNotificationMsg.getCloudEventAction()); CloudEventType cloudEventType = CloudEventType.valueOf(cloudNotificationMsg.getCloudEventType()); EntityId entityId = EntityIdFactory.getByCloudEventTypeAndUuid(cloudEventType, new UUID(cloudNotificationMsg.getEntityIdMSB(), cloudNotificationMsg.getEntityIdLSB())); @@ -138,45 +142,37 @@ private ListenableFuture processEntity(TenantId tenantId, TransportProtos. } } - private ListenableFuture processAlarm(TenantId tenantId, TransportProtos.CloudNotificationMsgProto cloudNotificationMsg) throws Exception { + private ListenableFuture processAlarm(TenantId tenantId, TransportProtos.CloudNotificationMsgProto cloudNotificationMsg) { EdgeEventActionType actionType = EdgeEventActionType.valueOf(cloudNotificationMsg.getCloudEventAction()); AlarmId alarmId = new AlarmId(new UUID(cloudNotificationMsg.getEntityIdMSB(), cloudNotificationMsg.getEntityIdLSB())); - switch (actionType) { - case DELETED: - Alarm deletedAlarm = JacksonUtil.OBJECT_MAPPER.readValue(cloudNotificationMsg.getEntityBody(), Alarm.class); - return cloudEventService.saveCloudEventAsync(tenantId, - CloudEventType.ALARM, - actionType, - alarmId, - JacksonUtil.OBJECT_MAPPER.valueToTree(deletedAlarm), - 0L); - default: - ListenableFuture future = alarmService.findAlarmByIdAsync(tenantId, alarmId); - return Futures.transformAsync(future, alarm -> { - if (alarm != null) { - CloudEventType cloudEventType = CloudUtils.getCloudEventTypeByEntityType(alarm.getOriginator().getEntityType()); - if (cloudEventType != null) { - return cloudEventService.saveCloudEventAsync(tenantId, - CloudEventType.ALARM, - EdgeEventActionType.valueOf(cloudNotificationMsg.getCloudEventAction()), - alarmId, - null, - 0L); - } - } - return Futures.immediateFuture(null); - }, dbCallBackExecutor); + if (EdgeEventActionType.DELETED.equals(actionType)) { + Alarm deletedAlarm = JacksonUtil.fromString(cloudNotificationMsg.getEntityBody(), Alarm.class); + return cloudEventService.saveCloudEventAsync(tenantId, CloudEventType.ALARM, actionType, alarmId, JacksonUtil.valueToTree(deletedAlarm), 0L); + } + ListenableFuture future = alarmService.findAlarmByIdAsync(tenantId, alarmId); + return Futures.transformAsync(future, alarm -> { + if (alarm != null) { + CloudEventType cloudEventType = CloudUtils.getCloudEventTypeByEntityType(alarm.getOriginator().getEntityType()); + if (cloudEventType != null) { + return cloudEventService.saveCloudEventAsync(tenantId, CloudEventType.ALARM, EdgeEventActionType.valueOf(cloudNotificationMsg.getCloudEventAction()), alarmId, null, 0L); + } + } + return Futures.immediateFuture(null); + }, dbCallBackExecutor); + } + public ListenableFuture processAlarmComment(TenantId tenantId, TransportProtos.CloudNotificationMsgProto cloudNotificationMsg) { + EdgeEventActionType actionType = EdgeEventActionType.valueOf(cloudNotificationMsg.getCloudEventAction()); + AlarmId alarmId = new AlarmId(new UUID(cloudNotificationMsg.getEntityIdMSB(), cloudNotificationMsg.getEntityIdLSB())); + AlarmComment alarmComment = JacksonUtil.fromString(cloudNotificationMsg.getEntityBody(), AlarmComment.class); + if (alarmComment == null) { + return Futures.immediateFuture(null); } + return cloudEventService.saveCloudEventAsync(tenantId, CloudEventType.ALARM_COMMENT, actionType, alarmId, JacksonUtil.valueToTree(alarmComment), 0L); } - private ListenableFuture processRelation(TenantId tenantId, TransportProtos.CloudNotificationMsgProto cloudNotificationMsg) throws Exception { - EntityRelation relation = JacksonUtil.OBJECT_MAPPER.readValue(cloudNotificationMsg.getEntityBody(), EntityRelation.class); - return cloudEventService.saveCloudEventAsync(tenantId, - CloudEventType.RELATION, - EdgeEventActionType.valueOf(cloudNotificationMsg.getCloudEventAction()), - null, - JacksonUtil.OBJECT_MAPPER.valueToTree(relation), - 0L); + private ListenableFuture processRelation(TenantId tenantId, TransportProtos.CloudNotificationMsgProto cloudNotificationMsg) { + EntityRelation relation = JacksonUtil.fromString(cloudNotificationMsg.getEntityBody(), EntityRelation.class); + return cloudEventService.saveCloudEventAsync(tenantId, CloudEventType.RELATION, EdgeEventActionType.valueOf(cloudNotificationMsg.getCloudEventAction()), null, JacksonUtil.valueToTree(relation), 0L); } } diff --git a/application/src/main/java/org/thingsboard/server/service/cloud/DefaultDownlinkMessageService.java b/application/src/main/java/org/thingsboard/server/service/cloud/DefaultDownlinkMessageService.java index 939f5f691f..40f8a53439 100644 --- a/application/src/main/java/org/thingsboard/server/service/cloud/DefaultDownlinkMessageService.java +++ b/application/src/main/java/org/thingsboard/server/service/cloud/DefaultDownlinkMessageService.java @@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.cloud.CloudEventService; import org.thingsboard.server.gen.edge.v1.AdminSettingsUpdateMsg; +import org.thingsboard.server.gen.edge.v1.AlarmCommentUpdateMsg; import org.thingsboard.server.gen.edge.v1.AlarmUpdateMsg; import org.thingsboard.server.gen.edge.v1.AssetProfileUpdateMsg; import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg; @@ -239,6 +240,11 @@ public ListenableFuture> processDownlinkMsg(TenantId tenantId, result.add(alarmProcessor.processAlarmMsgFromCloud(tenantId, alarmUpdateMsg)); } } + if (downlinkMsg.getAlarmCommentUpdateMsgCount() > 0) { + for (AlarmCommentUpdateMsg alarmCommentUpdateMsg : downlinkMsg.getAlarmCommentUpdateMsgList()) { + result.add(alarmProcessor.processAlarmCommentMsgFromCloud(tenantId, alarmCommentUpdateMsg)); + } + } if (downlinkMsg.getCustomerUpdateMsgCount() > 0) { for (CustomerUpdateMsg customerUpdateMsg : downlinkMsg.getCustomerUpdateMsgList()) { sequenceDependencyLock.lock(); diff --git a/application/src/main/java/org/thingsboard/server/service/cloud/rpc/processor/AlarmCloudProcessor.java b/application/src/main/java/org/thingsboard/server/service/cloud/rpc/processor/AlarmCloudProcessor.java index a5418b3706..ea1cb65cba 100644 --- a/application/src/main/java/org/thingsboard/server/service/cloud/rpc/processor/AlarmCloudProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/cloud/rpc/processor/AlarmCloudProcessor.java @@ -21,13 +21,17 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmComment; import org.thingsboard.server.common.data.cloud.CloudEvent; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.gen.edge.v1.AlarmCommentUpdateMsg; import org.thingsboard.server.gen.edge.v1.AlarmUpdateMsg; import org.thingsboard.server.gen.edge.v1.EdgeVersion; +import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.gen.edge.v1.UplinkMsg; +import org.thingsboard.server.service.edge.rpc.constructor.alarm.AlarmMsgConstructor; import org.thingsboard.server.service.edge.rpc.processor.alarm.BaseAlarmProcessor; @Component @@ -43,6 +47,15 @@ public ListenableFuture processAlarmMsgFromCloud(TenantId tenantId, AlarmU } } + public ListenableFuture processAlarmCommentMsgFromCloud(TenantId tenantId, AlarmCommentUpdateMsg alarmCommentUpdateMsg) { + try { + cloudSynchronizationManager.getSync().set(true); + return processAlarmCommentMsg(tenantId, alarmCommentUpdateMsg); + } finally { + cloudSynchronizationManager.getSync().remove(); + } + } + public UplinkMsg convertAlarmEventToUplink(CloudEvent cloudEvent, EdgeVersion edgeVersion) { AlarmUpdateMsg alarmUpdateMsg = convertAlarmEventToAlarmMsg(cloudEvent.getTenantId(), cloudEvent.getEntityId(), cloudEvent.getAction(), cloudEvent.getEntityBody(), edgeVersion); @@ -55,6 +68,24 @@ public UplinkMsg convertAlarmEventToUplink(CloudEvent cloudEvent, EdgeVersion ed return null; } + public UplinkMsg convertAlarmCommentEventToUplink(CloudEvent cloudEvent, EdgeVersion edgeVersion) { + UpdateMsgType msgType = getUpdateMsgType(cloudEvent.getAction()); + AlarmComment alarmComment; + switch (cloudEvent.getAction()) { + case ADDED_COMMENT: + case UPDATED_COMMENT: + case DELETED_COMMENT: + alarmComment = JacksonUtil.convertValue(cloudEvent.getEntityBody(), AlarmComment.class); + return UplinkMsg.newBuilder() + .setUplinkMsgId(EdgeUtils.nextPositiveInt()) + .addAlarmCommentUpdateMsg(((AlarmMsgConstructor) alarmMsgConstructorFactory + .getMsgConstructorByEdgeVersion(edgeVersion)).constructAlarmCommentUpdatedMsg(msgType, alarmComment)) + .build(); + default: + return null; + } + } + @Override protected EntityId getAlarmOriginatorFromMsg(TenantId tenantId, AlarmUpdateMsg alarmUpdateMsg) { Alarm alarm = JacksonUtil.fromString(alarmUpdateMsg.getEntity(), Alarm.class, true); diff --git a/application/src/main/java/org/thingsboard/server/service/cloud/rpc/processor/DeviceCloudProcessor.java b/application/src/main/java/org/thingsboard/server/service/cloud/rpc/processor/DeviceCloudProcessor.java index f1d9ff630e..1866c2b3a0 100644 --- a/application/src/main/java/org/thingsboard/server/service/cloud/rpc/processor/DeviceCloudProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/cloud/rpc/processor/DeviceCloudProcessor.java @@ -191,7 +191,7 @@ private ListenableFuture processDeviceRpcRequestFromCloud(TenantId tenantI private void reply(ToDeviceRpcRequest rpcRequest, int requestId, FromDeviceRpcResponse response) { try { Optional rpcError = response.getError(); - ObjectNode body = JacksonUtil.OBJECT_MAPPER.createObjectNode(); + ObjectNode body = JacksonUtil.newObjectNode(); body.put("requestUUID", rpcRequest.getId().toString()); body.put("expirationTime", rpcRequest.getExpirationTime()); body.put("oneway", rpcRequest.isOneway()); diff --git a/application/src/main/java/org/thingsboard/server/service/cloud/rpc/processor/RelationCloudProcessor.java b/application/src/main/java/org/thingsboard/server/service/cloud/rpc/processor/RelationCloudProcessor.java index 71fa7aab43..f274b90422 100644 --- a/application/src/main/java/org/thingsboard/server/service/cloud/rpc/processor/RelationCloudProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/cloud/rpc/processor/RelationCloudProcessor.java @@ -63,7 +63,7 @@ public UplinkMsg convertRelationRequestEventToUplink(CloudEvent cloudEvent) { public UplinkMsg convertRelationEventToUplink(CloudEvent cloudEvent, EdgeVersion edgeVersion) { UplinkMsg msg = null; UpdateMsgType msgType = getUpdateMsgType(cloudEvent.getAction()); - EntityRelation entityRelation = JacksonUtil.OBJECT_MAPPER.convertValue(cloudEvent.getEntityBody(), EntityRelation.class); + EntityRelation entityRelation = JacksonUtil.convertValue(cloudEvent.getEntityBody(), EntityRelation.class); if (entityRelation != null) { RelationUpdateMsg relationUpdateMsg = ((RelationMsgConstructor) relationMsgConstructorFactory.getMsgConstructorByEdgeVersion(edgeVersion)) .constructRelationUpdatedMsg(msgType, entityRelation); diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/tenant/DefaultTbTenantService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/tenant/DefaultTbTenantService.java index 99896ae2da..33789537b9 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/tenant/DefaultTbTenantService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/tenant/DefaultTbTenantService.java @@ -51,11 +51,13 @@ public Tenant save(Tenant tenant) throws Exception { Tenant oldTenant = !created ? tenantService.findTenantById(tenant.getId()) : null; Tenant savedTenant = checkNotNull(tenantService.saveTenant(tenant)); + /* edge: DefaultRuleChains and DefaultEdgeRuleChains are configured on Cloud if (created) { installScripts.createDefaultRuleChains(savedTenant.getId()); installScripts.createDefaultEdgeRuleChains(savedTenant.getId()); installScripts.createDefaultTenantDashboards(savedTenant.getId(), null); } + */ tenantProfileCache.evict(savedTenant.getId()); notificationEntityService.notifyCreateOrUpdateTenant(savedTenant, created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/AbstractOAuth2ClientMapper.java b/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/AbstractOAuth2ClientMapper.java index cfb919c9b8..9b560b4ed9 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/AbstractOAuth2ClientMapper.java +++ b/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/AbstractOAuth2ClientMapper.java @@ -38,7 +38,6 @@ import org.thingsboard.server.common.data.oauth2.OAuth2Registration; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.UserCredentials; import org.thingsboard.server.dao.customer.CustomerService; @@ -180,14 +179,7 @@ private TenantId getTenantId(String tenantName) throws Exception { if (tenants == null || tenants.isEmpty()) { tenant = new Tenant(); tenant.setTitle(tenantName); - tenant = tenantService.saveTenant(tenant); - tenantProfileCache.evict(tenant.getId()); - tbClusterService.onTenantChange(tenant, null); - tbClusterService.broadcastEntityStateChangeEvent(tenant.getId(), tenant.getId(), - ComponentLifecycleEvent.CREATED); - /* voba - merge comment - we do not need to createDefaultRuleChains and createDefaultEdgeRuleChains tenant = tbTenantService.save(tenant); - */ } else { tenant = tenants.get(0); } @@ -228,4 +220,5 @@ private Optional getDashboardId(TenantId tenantId, CustomerId custo } while (dashboardsPage.hasNext()); return Optional.empty(); } + } diff --git a/application/src/test/java/org/thingsboard/server/edge/AlarmEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/AlarmEdgeTest.java index fa0159ec6d..080018d122 100644 --- a/application/src/test/java/org/thingsboard/server/edge/AlarmEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/AlarmEdgeTest.java @@ -143,6 +143,7 @@ public void testAlarms() throws Exception { } @Test + @Ignore public void testSendAlarmCommentToCloud() throws Exception { Device device = saveDeviceOnCloudAndVerifyDeliveryToEdge(); @@ -188,6 +189,7 @@ public void testSendAlarmCommentToCloud() throws Exception { } @Test + @Ignore public void testAlarmComments() throws Exception { Device device = findDeviceByName("Edge Device 1"); Alarm alarm = new Alarm(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/CloudUtils.java b/common/data/src/main/java/org/thingsboard/server/common/data/CloudUtils.java index 3f3964da93..d873a605e2 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/CloudUtils.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/CloudUtils.java @@ -18,41 +18,25 @@ import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.cloud.CloudEventType; +import java.util.EnumMap; + @Slf4j public final class CloudUtils { - private CloudUtils() { + private static final EnumMap entityTypeCloudEventTypeEnumMap; + + static { + entityTypeCloudEventTypeEnumMap = new EnumMap<>(EntityType.class); + for (CloudEventType cloudEventType : CloudEventType.values()) { + if (cloudEventType.getEntityType() != null) { + entityTypeCloudEventTypeEnumMap.put(cloudEventType.getEntityType(), cloudEventType); + } + } } + private CloudUtils() {} + public static CloudEventType getCloudEventTypeByEntityType(EntityType entityType) { - switch (entityType) { - case DEVICE: - return CloudEventType.DEVICE; - case DEVICE_PROFILE: - return CloudEventType.DEVICE_PROFILE; - case ASSET: - return CloudEventType.ASSET; - case ASSET_PROFILE: - return CloudEventType.ASSET_PROFILE; - case ENTITY_VIEW: - return CloudEventType.ENTITY_VIEW; - case DASHBOARD: - return CloudEventType.DASHBOARD; - case USER: - return CloudEventType.USER; - case ALARM: - return CloudEventType.ALARM; - case TENANT: - return CloudEventType.TENANT; - case CUSTOMER: - return CloudEventType.CUSTOMER; - case EDGE: - return CloudEventType.EDGE; - case TB_RESOURCE: - return CloudEventType.TB_RESOURCE; - default: - log.warn("Unsupported entity type: [{}]", entityType); - return null; - } + return entityTypeCloudEventTypeEnumMap.get(entityType); } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/cloud/CloudEventType.java b/common/data/src/main/java/org/thingsboard/server/common/data/cloud/CloudEventType.java index 4130247e94..6300c650dd 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/cloud/CloudEventType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/cloud/CloudEventType.java @@ -15,24 +15,34 @@ */ package org.thingsboard.server.common.data.cloud; +import lombok.Getter; +import org.thingsboard.server.common.data.EntityType; + +@Getter public enum CloudEventType { - DASHBOARD, - ASSET, - ASSET_PROFILE, - DEVICE, - DEVICE_PROFILE, - ENTITY_VIEW, - ALARM, - RULE_CHAIN, - RULE_CHAIN_METADATA, - USER, - TENANT, - TENANT_PROFILE, - CUSTOMER, - RELATION, - ENTITY_GROUP, - WIDGETS_BUNDLE, - WIDGET_TYPE, - EDGE, - TB_RESOURCE + DASHBOARD(EntityType.DASHBOARD), + ASSET(EntityType.ASSET), + ASSET_PROFILE(EntityType.ASSET_PROFILE), + DEVICE(EntityType.DEVICE), + DEVICE_PROFILE(EntityType.DEVICE_PROFILE), + ENTITY_VIEW(EntityType.ENTITY_VIEW), + ALARM(EntityType.ALARM), + ALARM_COMMENT(null), + RULE_CHAIN(EntityType.RULE_CHAIN), + RULE_CHAIN_METADATA(null), + USER(EntityType.USER), + TENANT(EntityType.TENANT), + TENANT_PROFILE(EntityType.TENANT_PROFILE), + CUSTOMER(EntityType.CUSTOMER), + RELATION(null), + WIDGETS_BUNDLE(EntityType.WIDGETS_BUNDLE), + WIDGET_TYPE(EntityType.WIDGET_TYPE), + EDGE(EntityType.EDGE), + TB_RESOURCE(EntityType.TB_RESOURCE); + + private final EntityType entityType; + + CloudEventType(EntityType entityType) { + this.entityType = entityType; + } } diff --git a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java index d5ad7ce634..c98d603ec5 100644 --- a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java +++ b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java @@ -110,7 +110,7 @@ public abstract class AbstractContainerTest { public static final String TB_MONOLITH_SERVICE_NAME = "tb-monolith"; public static final String TB_EDGE_SERVICE_NAME = "tb-edge"; - private static final String CUSTOM_DEVICE_PROFILE_NAME = "Custom Device Profile"; + protected static final String CUSTOM_DEVICE_PROFILE_NAME = "Custom Device Profile"; protected static RestClient cloudRestClient = null; @@ -137,8 +137,8 @@ public static void before() throws Exception { edgeUrl = "http://" + edgeHost + ":" + edgePort; edgeRestClient = new RestClient(edgeUrl); - updateRootRuleChain(); - updateEdgeRootRuleChain(); + RuleChainId ruleChainId = updateRootRuleChain(); + RuleChainId edgeRuleChainId = updateEdgeRootRuleChain(); edge = createEdge("test", CLOUD_ROUTING_KEY, CLOUD_ROUTING_SECRET); @@ -150,7 +150,7 @@ public static void before() throws Exception { Assert.assertTrue(tenant.isPresent()); Assert.assertEquals(edge.getTenantId(), tenant.get().getId()); - createCustomDeviceProfile(CUSTOM_DEVICE_PROFILE_NAME); + createCustomDeviceProfile(CUSTOM_DEVICE_PROFILE_NAME, ruleChainId, edgeRuleChainId); // This is a starting point to start other tests verifyWidgetBundles(); @@ -158,7 +158,7 @@ public static void before() throws Exception { } private static void getEdgeVersion() { - List attributes = cloudRestClient.getAttributeKvEntries(edge.getId(), List.of("edgeVersion")); + List attributes = cloudRestClient.getAttributeKvEntries(edge.getId(), List.of(DataConstants.EDGE_VERSION_ATTR_KEY)); edgeVersion = EdgeVersion.valueOf(attributes.get(0).getValueAsString()); } @@ -216,22 +216,22 @@ private static void verifyWidgetBundles() { } } - private static void updateRootRuleChain() throws IOException { + private static RuleChainId updateRootRuleChain() throws IOException { // Modifications: // - add rule node 'script' to create RPC reply message // - add rule node 'rpc call reply' to send RPC reply // - add connection - from 'RPC from Device' to 'script' // - add connection - from 'script' to 'rpc call reply' - updateRootRuleChain(RuleChainType.CORE, "Updated_RootRuleChainMetadata.json"); + return updateRootRuleChain(RuleChainType.CORE, "Updated_RootRuleChainMetadata.json"); } - private static void updateEdgeRootRuleChain() throws IOException { + private static RuleChainId updateEdgeRootRuleChain() throws IOException { // Modifications: // - add connection - from 'RPC from Device' to 'Push to cloud' - updateRootRuleChain(RuleChainType.EDGE, "Updated_EdgeRootRuleChainMetadata.json"); + return updateRootRuleChain(RuleChainType.EDGE, "Updated_EdgeRootRuleChainMetadata.json"); } - private static void updateRootRuleChain(RuleChainType ruleChainType, String updatedRootRuleChainFileName) throws IOException { + private static RuleChainId updateRootRuleChain(RuleChainType ruleChainType, String updatedRootRuleChainFileName) throws IOException { PageData ruleChains = cloudRestClient.getRuleChains(ruleChainType, new PageLink(100)); RuleChainId rootRuleChainId = null; for (RuleChain datum : ruleChains.getData()) { @@ -248,17 +248,22 @@ private static void updateRootRuleChain(RuleChainType ruleChainType, String upda ruleChainMetaData.setNodes(Arrays.asList(JacksonUtil.OBJECT_MAPPER.treeToValue(configuration.get("nodes"), RuleNode[].class))); ruleChainMetaData.setConnections(Arrays.asList(JacksonUtil.OBJECT_MAPPER.treeToValue(configuration.get("connections"), NodeConnectionInfo[].class))); cloudRestClient.saveRuleChainMetaData(ruleChainMetaData); + return rootRuleChainId; } protected static DeviceProfile createCustomDeviceProfile(String deviceProfileName, DeviceProfileTransportConfiguration deviceProfileTransportConfiguration) { - return doCreateDeviceProfile(deviceProfileName, deviceProfileTransportConfiguration, cloudRestClient); + return doCreateDeviceProfile(deviceProfileName, null, null, deviceProfileTransportConfiguration, cloudRestClient); } protected static DeviceProfile createCustomDeviceProfile(String deviceProfileName) { return createCustomDeviceProfile(deviceProfileName, null); } + protected static DeviceProfile createCustomDeviceProfile(String deviceProfileName, RuleChainId defaultRuleChain, RuleChainId defaultEdgeRuleChainId) { + return doCreateDeviceProfile(deviceProfileName, defaultRuleChain, defaultEdgeRuleChainId, null, cloudRestClient); + } + @Rule public TestRule watcher = new TestWatcher() { protected void starting(Description description) { @@ -287,10 +292,15 @@ protected void failed(Throwable e, Description description) { }; protected static DeviceProfile createDeviceProfileOnEdge(String name) { - return doCreateDeviceProfile(name, new DefaultDeviceProfileTransportConfiguration(), edgeRestClient); + return doCreateDeviceProfile(name, null, null, new DefaultDeviceProfileTransportConfiguration(), edgeRestClient); } - private static DeviceProfile doCreateDeviceProfile(String name, DeviceProfileTransportConfiguration deviceProfileTransportConfiguration, RestClient restClient) { + protected static DeviceProfile createDeviceProfileOnEdge(String name, RuleChainId defaultRuleChain, RuleChainId defaultEdgeRuleChainId) { + return doCreateDeviceProfile(name, defaultRuleChain, defaultEdgeRuleChainId, new DefaultDeviceProfileTransportConfiguration(), edgeRestClient); + } + + private static DeviceProfile doCreateDeviceProfile(String name, RuleChainId defaultRuleChain, RuleChainId defaultEdgeRuleChainId, + DeviceProfileTransportConfiguration deviceProfileTransportConfiguration, RestClient restClient) { DeviceProfile deviceProfile = new DeviceProfile(); deviceProfile.setName(name); deviceProfile.setType(DeviceProfileType.DEFAULT); @@ -305,8 +315,9 @@ private static DeviceProfile doCreateDeviceProfile(String name, DeviceProfileTra DefaultDeviceProfileTransportConfiguration::new)); deviceProfile.setProfileData(deviceProfileData); deviceProfile.setDefault(false); - deviceProfile.setDefaultRuleChainId(null); + deviceProfile.setDefaultRuleChainId(defaultRuleChain); deviceProfile.setDefaultQueueName("Main"); + deviceProfile.setDefaultEdgeRuleChainId(defaultEdgeRuleChainId); extendDeviceProfileData(deviceProfile); return restClient.saveDeviceProfile(deviceProfile); } @@ -322,16 +333,15 @@ protected static void extendDeviceProfileData(DeviceProfile deviceProfile) { alarmCondition.setSpec(new SimpleAlarmConditionSpec()); List condition = new ArrayList<>(); AlarmConditionFilter alarmConditionFilter = new AlarmConditionFilter(); - alarmConditionFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.ATTRIBUTE, "temperature")); + alarmConditionFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.TIME_SERIES, "temperature")); NumericFilterPredicate predicate = new NumericFilterPredicate(); - predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); + predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER_OR_EQUAL); predicate.setValue(new FilterPredicateValue<>(55.0)); alarmConditionFilter.setPredicate(predicate); alarmConditionFilter.setValueType(EntityKeyValueType.NUMERIC); condition.add(alarmConditionFilter); alarmCondition.setCondition(condition); alarmRule.setCondition(alarmCondition); - deviceProfileAlarm.setClearRule(alarmRule); TreeMap createRules = new TreeMap<>(); createRules.put(AlarmSeverity.CRITICAL, alarmRule); deviceProfileAlarm.setCreateRules(createRules); @@ -838,4 +848,5 @@ protected Customer findPublicCustomer() { PageData customers = cloudRestClient.getCustomers(new PageLink(100)); return customers.getData().stream().filter(Customer::isPublic).findFirst().get(); } + } diff --git a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java index 576d0474cb..3fcd80732a 100644 --- a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java +++ b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java @@ -101,4 +101,5 @@ private static void tryDeleteDir(String targetDir) { log.error("Can't delete temp directory " + targetDir, e); } } + } diff --git a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/DockerComposeExecutor.java b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/DockerComposeExecutor.java index a9de9acd46..cc9de4507d 100644 --- a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/DockerComposeExecutor.java +++ b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/DockerComposeExecutor.java @@ -113,4 +113,5 @@ void validateFileList(List composeFiles) { checkNotNull(composeFiles); checkArgument(!composeFiles.isEmpty(), "No docker compose file have been provided"); } + } diff --git a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/AlarmClientTest.java b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/AlarmClientTest.java index 9649193338..686143ca81 100644 --- a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/AlarmClientTest.java +++ b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/AlarmClientTest.java @@ -15,20 +15,23 @@ */ package org.thingsboard.server.msa.edge; +import com.google.gson.JsonObject; import lombok.extern.slf4j.Slf4j; import org.awaitility.Awaitility; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; +import org.springframework.http.ResponseEntity; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rest.client.RestClient; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; -import org.thingsboard.server.common.data.alarm.AlarmSeverity; -import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.TimePageLink; +import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.msa.AbstractContainerTest; import java.util.Optional; @@ -38,21 +41,36 @@ public class AlarmClientTest extends AbstractContainerTest { @Test - public void testAlarms() { + public void testAlarms() throws Exception { // create alarm - Device device = saveAndAssignDeviceToEdge(); + Device device = saveAndAssignDeviceToEdge(CUSTOM_DEVICE_PROFILE_NAME); - Alarm alarm = new Alarm(); - alarm.setOriginator(device.getId()); - alarm.setType("alarm"); - alarm.setSeverity(AlarmSeverity.CRITICAL); - Alarm savedAlarm = cloudRestClient.saveAlarm(alarm); + Awaitility.await() + .pollInterval(500, TimeUnit.MILLISECONDS) + .atMost(30, TimeUnit.SECONDS) + .until(() -> cloudRestClient.getDeviceCredentialsByDeviceId(device.getId()).isPresent()); + + DeviceCredentials deviceCredentials = cloudRestClient.getDeviceCredentialsByDeviceId(device.getId()).get(); + String accessToken = deviceCredentials.getCredentialsId(); + + JsonObject telemetry = new JsonObject(); + telemetry.addProperty("temperature", 100); + + ResponseEntity deviceTelemetryResponse = edgeRestClient.getRestTemplate() + .postForEntity(edgeUrl + "/api/v1/{credentialsId}/telemetry", + JacksonUtil.OBJECT_MAPPER.readTree(telemetry.toString()), + ResponseEntity.class, + accessToken); + + Assert.assertTrue(deviceTelemetryResponse.getStatusCode().is2xxSuccessful()); Awaitility.await() .pollInterval(500, TimeUnit.MILLISECONDS) .atMost(30, TimeUnit.SECONDS) .until(() -> getLatestAlarmByEntityIdFromEdge(device.getId()).isPresent()); + Alarm savedAlarm = getLatestAlarmByEntityIdFromEdge(device.getId()).get(); + // ack alarm cloudRestClient.ackAlarm(savedAlarm.getId()); Awaitility.await() @@ -100,17 +118,32 @@ private Optional getLatestAnyAlarmByEntityId(EntityId entityId, RestC @Test public void sendAlarmToCloud() { - // create alarm on cloud (creation on edge possible using Send to Cloud node) - Device device = saveAndAssignDeviceToEdge(); - Alarm alarm = new Alarm(); - alarm.setOriginator(device.getId()); - alarm.setType("alarm"); - alarm.setSeverity(AlarmSeverity.CRITICAL); - Alarm savedAlarm = cloudRestClient.saveAlarm(alarm); + // create alarm on edge + Device device = saveAndAssignDeviceToEdge(CUSTOM_DEVICE_PROFILE_NAME); + Awaitility.await() .pollInterval(500, TimeUnit.MILLISECONDS) .atMost(30, TimeUnit.SECONDS) - .until(() -> getLatestAlarmByEntityIdFromEdge(device.getId()).isPresent()); + .until(() -> cloudRestClient.getDeviceCredentialsByDeviceId(device.getId()).isPresent()); + + DeviceCredentials deviceCredentials = cloudRestClient.getDeviceCredentialsByDeviceId(device.getId()).get(); + String accessToken = deviceCredentials.getCredentialsId(); + + JsonObject telemetry = new JsonObject(); + telemetry.addProperty("temperature", 100); + + ResponseEntity deviceTelemetryResponse = edgeRestClient.getRestTemplate() + .postForEntity(edgeUrl + "/api/v1/" + accessToken + "/telemetry", + JacksonUtil.toJsonNode(telemetry.toString()), + ResponseEntity.class); + Assert.assertTrue(deviceTelemetryResponse.getStatusCode().is2xxSuccessful()); + + Awaitility.await() + .pollInterval(500, TimeUnit.MILLISECONDS) + .atMost(30, TimeUnit.SECONDS) + .until(() -> getLatestAlarmByEntityIdFromCloud(device.getId()).isPresent()); + + Alarm savedAlarm = getLatestAlarmByEntityIdFromEdge(device.getId()).get(); // ack alarm edgeRestClient.ackAlarm(savedAlarm.getId()); @@ -146,4 +179,5 @@ public void sendAlarmToCloud() { private Optional getLatestAlarmByEntityIdFromCloud(EntityId entityId) { return getLatestAnyAlarmByEntityId(entityId, cloudRestClient); } + } diff --git a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/AssetClientTest.java b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/AssetClientTest.java index 4e152f72a3..71166cdd12 100644 --- a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/AssetClientTest.java +++ b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/AssetClientTest.java @@ -205,4 +205,5 @@ public void testSendAssetToCloudWithNameThatAlreadyExistsOnCloud() { .atMost(30, TimeUnit.SECONDS) .until(() -> edgeRestClient.getAssetProfileById(savedAssetOnCloud.getAssetProfileId()).isEmpty()); } + } diff --git a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/AssetProfileClientTest.java b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/AssetProfileClientTest.java index d1ea433aaa..41144f8b70 100644 --- a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/AssetProfileClientTest.java +++ b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/AssetProfileClientTest.java @@ -117,4 +117,5 @@ private AssetProfile saveAssetProfileOnEdge(String assetProfileName) { assetProfile.setName(assetProfileName); return edgeRestClient.saveAssetProfile(assetProfile); } + } diff --git a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/CustomerClientTest.java b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/CustomerClientTest.java index 157020b900..dc195e9e90 100644 --- a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/CustomerClientTest.java +++ b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/CustomerClientTest.java @@ -62,4 +62,5 @@ public void testPublicCustomerCreatedOnEdge() { .atMost(30, TimeUnit.SECONDS) .until(() -> edgeRestClient.getCustomerById(publicCustomer.getId()).isPresent()); } + } diff --git a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/DashboardClientTest.java b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/DashboardClientTest.java index 4be27cee45..ec766513ac 100644 --- a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/DashboardClientTest.java +++ b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/DashboardClientTest.java @@ -173,4 +173,5 @@ public void testSendDashboardToCloud() { cloudRestClient.deleteDashboard(savedDashboardOnEdge.getId()); } + } diff --git a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/DeviceClientTest.java b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/DeviceClientTest.java index eb14b9d17e..c85b7cc7b7 100644 --- a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/DeviceClientTest.java +++ b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/DeviceClientTest.java @@ -753,4 +753,5 @@ public void testSharedAttributeUpdates() throws JsonProcessingException { // cleanup cloudRestClient.deleteDevice(savedDevice.getId()); } + } diff --git a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/DeviceProfileClientTest.java b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/DeviceProfileClientTest.java index 4a2d21ab76..e722fa9ba6 100644 --- a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/DeviceProfileClientTest.java +++ b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/DeviceProfileClientTest.java @@ -298,4 +298,5 @@ private void verifyDeviceProfilesOnEdge(int expectedDeviceProfilesCnt) { PageData pageData = edgeRestClient.getDeviceProfiles(new PageLink(100)); assertEntitiesByIdsAndType(pageData.getData().stream().map(IdBased::getId).collect(Collectors.toList()), EntityType.DEVICE_PROFILE); } + } diff --git a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeClientTest.java b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeClientTest.java index ed629f5a66..54cd6aa5a7 100644 --- a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeClientTest.java +++ b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeClientTest.java @@ -51,4 +51,5 @@ public void testEdge_assignToCustomer_unassignFromCustomer() { .atMost(30, TimeUnit.SECONDS) .until(() -> EntityId.NULL_UUID.equals(edgeRestClient.getEdgeById(edge.getId()).get().getCustomerId().getId())); } + } diff --git a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EntityViewClientTest.java b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EntityViewClientTest.java index 89c2b9de1a..426dfb4d97 100644 --- a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EntityViewClientTest.java +++ b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EntityViewClientTest.java @@ -214,4 +214,5 @@ private EntityView saveEntityView(String entityViewName, String type, EntityId e entityView.setEntityId(entityId); return restClient.saveEntityView(entityView); } + } diff --git a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/OtaPackageClientTest.java b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/OtaPackageClientTest.java index 3650ac5cec..bebac2f7b0 100644 --- a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/OtaPackageClientTest.java +++ b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/OtaPackageClientTest.java @@ -71,4 +71,5 @@ public void testOtaPackages() throws Exception { return otaPackages.getData().stream().map(OtaPackageInfo::getId).noneMatch(otaPackageId::equals); }); } + } diff --git a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/QueueClientTest.java b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/QueueClientTest.java index b51ba6ddd1..b908e1b87e 100644 --- a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/QueueClientTest.java +++ b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/QueueClientTest.java @@ -82,4 +82,5 @@ public void testQueues() { cloudRestClient.login("tenant@thingsboard.org", "tenant"); } + } diff --git a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/RelationClientTest.java b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/RelationClientTest.java index 2ba928034e..d9563fd8e3 100644 --- a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/RelationClientTest.java +++ b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/RelationClientTest.java @@ -93,4 +93,5 @@ public void sendRelationToCloud() { cloudRestClient.deleteDevice(device.getId()); cloudRestClient.deleteDevice(savedDeviceOnEdge.getId()); } + } diff --git a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/ResourceClientTest.java b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/ResourceClientTest.java index 7f0a4e3a1e..b22655c844 100644 --- a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/ResourceClientTest.java +++ b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/ResourceClientTest.java @@ -100,4 +100,5 @@ private TbResource saveResourceOnEdge(String title, String resourceKey, RestClie tbResource.setData("Data".getBytes()); return restClient.saveResource(tbResource); } + } diff --git a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/RuleChainClientTest.java b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/RuleChainClientTest.java index b170956a0d..8a180d8915 100644 --- a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/RuleChainClientTest.java +++ b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/RuleChainClientTest.java @@ -60,4 +60,5 @@ public void testRuleChains() throws Exception { unAssignFromEdgeAndDeleteRuleChain(savedRuleChainId); } + } diff --git a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/TelemetryClientTest.java b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/TelemetryClientTest.java index c37ec2487f..9365c7df79 100644 --- a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/TelemetryClientTest.java +++ b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/TelemetryClientTest.java @@ -352,4 +352,5 @@ private void verifyAttributesUpdatedToCloud(List kvEntries) { } } } + } diff --git a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/TenantClientTest.java b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/TenantClientTest.java index 39eeccc616..6207ce2da7 100644 --- a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/TenantClientTest.java +++ b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/TenantClientTest.java @@ -60,4 +60,5 @@ public void testUpdateTenant() { cloudRestClient.login("tenant@thingsboard.org", "tenant"); } + } diff --git a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/UserClientTest.java b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/UserClientTest.java index 225fadeafb..88de0ec945 100644 --- a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/UserClientTest.java +++ b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/UserClientTest.java @@ -107,4 +107,5 @@ public void testCreateUpdateDeleteCustomerUser() { .atMost(30, TimeUnit.SECONDS) .until(() -> edgeRestClient.getUserById(savedUser.getId()).isEmpty()); } + } diff --git a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/WidgetBundleAndTypeClientTest.java b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/WidgetBundleAndTypeClientTest.java index 2bcf3cae70..387e0598f2 100644 --- a/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/WidgetBundleAndTypeClientTest.java +++ b/msa/edge-black-box-tests/src/test/java/org/thingsboard/server/msa/edge/WidgetBundleAndTypeClientTest.java @@ -118,4 +118,5 @@ public void testWidgetsBundleAndWidgetType() { .atMost(30, TimeUnit.SECONDS) .until(() -> edgeRestClient.getWidgetsBundleById(savedWidgetsBundle.getId()).isEmpty()); } + } diff --git a/msa/edge-black-box-tests/src/test/resources/Updated_EdgeRootRuleChainMetadata.json b/msa/edge-black-box-tests/src/test/resources/Updated_EdgeRootRuleChainMetadata.json index aff0c56a28..97213fde48 100644 --- a/msa/edge-black-box-tests/src/test/resources/Updated_EdgeRootRuleChainMetadata.json +++ b/msa/edge-black-box-tests/src/test/resources/Updated_EdgeRootRuleChainMetadata.json @@ -10,6 +10,9 @@ "type": "org.thingsboard.rule.engine.profile.TbDeviceProfileNode", "name": "Device Profile Node", "debugMode": false, + "singletonMode": false, + "queueName": null, + "configurationVersion": 0, "configuration": { "persistAlarmRulesState": false, "fetchAlarmRulesStateOnStart": false @@ -24,6 +27,9 @@ "type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode", "name": "Save Timeseries", "debugMode": false, + "singletonMode": false, + "queueName": null, + "configurationVersion": 0, "configuration": { "defaultTTL": 0 }, @@ -37,8 +43,14 @@ "type": "org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode", "name": "Save Client Attributes", "debugMode": false, + "singletonMode": false, + "queueName": null, + "configurationVersion": 2, "configuration": { - "scope": "CLIENT_SCOPE" + "scope": "CLIENT_SCOPE", + "notifyDevice": false, + "sendAttributesUpdatedNotification": false, + "updateAttributesOnlyOnValueChange": true }, "externalId": null }, @@ -50,6 +62,9 @@ "type": "org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode", "name": "Message Type Switch", "debugMode": false, + "singletonMode": false, + "queueName": null, + "configurationVersion": 0, "configuration": { "version": 0 }, @@ -63,6 +78,9 @@ "type": "org.thingsboard.rule.engine.action.TbLogNode", "name": "Log RPC from Device", "debugMode": false, + "singletonMode": false, + "queueName": null, + "configurationVersion": 0, "configuration": { "scriptLang": "TBEL", "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);", @@ -78,6 +96,9 @@ "type": "org.thingsboard.rule.engine.action.TbLogNode", "name": "Log Other", "debugMode": false, + "singletonMode": false, + "queueName": null, + "configurationVersion": 0, "configuration": { "scriptLang": "TBEL", "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);", @@ -93,6 +114,9 @@ "type": "org.thingsboard.rule.engine.rpc.TbSendRPCRequestNode", "name": "RPC Call Request", "debugMode": false, + "singletonMode": false, + "queueName": null, + "configurationVersion": 0, "configuration": { "timeoutInSeconds": 60 }, @@ -100,12 +124,31 @@ }, { "additionalInfo": { - "layoutX": 1129, - "layoutY": 52 + "layoutX": 1126, + "layoutY": 104 + }, + "type": "org.thingsboard.rule.engine.edge.TbMsgPushToCloudNode", + "name": "Push to cloud", + "debugMode": false, + "singletonMode": false, + "queueName": null, + "configurationVersion": 0, + "configuration": { + "scope": "SERVER_SCOPE" + }, + "externalId": null + }, + { + "additionalInfo": { + "layoutX": 826, + "layoutY": 601 }, "type": "org.thingsboard.rule.engine.edge.TbMsgPushToCloudNode", "name": "Push to cloud", "debugMode": false, + "singletonMode": false, + "queueName": null, + "configurationVersion": 0, "configuration": { "scope": "SERVER_SCOPE" }, @@ -118,6 +161,16 @@ "toIndex": 3, "type": "Success" }, + { + "fromIndex": 0, + "toIndex": 8, + "type": "Alarm Created" + }, + { + "fromIndex": 0, + "toIndex": 8, + "type": "Alarm Updated" + }, { "fromIndex": 1, "toIndex": 7, @@ -155,22 +208,22 @@ }, { "fromIndex": 3, - "toIndex": 7, + "toIndex": 8, "type": "Attributes Deleted" }, { "fromIndex": 3, - "toIndex": 7, + "toIndex": 8, "type": "Attributes Updated" }, { "fromIndex": 3, - "toIndex": 7, + "toIndex": 8, "type": "Timeseries Deleted" }, { "fromIndex": 3, - "toIndex": 7, + "toIndex": 8, "type": "Timeseries Updated" }, { diff --git a/msa/edge-black-box-tests/src/test/resources/Updated_RootRuleChainMetadata.json b/msa/edge-black-box-tests/src/test/resources/Updated_RootRuleChainMetadata.json index 0af05315a3..9305dc3595 100644 --- a/msa/edge-black-box-tests/src/test/resources/Updated_RootRuleChainMetadata.json +++ b/msa/edge-black-box-tests/src/test/resources/Updated_RootRuleChainMetadata.json @@ -4,12 +4,15 @@ { "additionalInfo": { "description": "", - "layoutX": 1132, - "layoutY": 51 + "layoutX": 703, + "layoutY": 714 }, "type": "org.thingsboard.rule.engine.edge.TbMsgPushToEdgeNode", "name": "Push to Edge", "debugMode": true, + "singletonMode": false, + "queueName": null, + "configurationVersion": 0, "configuration": { "scope": "CLIENT_SCOPE" }, @@ -24,6 +27,9 @@ "type": "org.thingsboard.rule.engine.profile.TbDeviceProfileNode", "name": "Device Profile Node", "debugMode": true, + "singletonMode": false, + "queueName": null, + "configurationVersion": 0, "configuration": { "persistAlarmRulesState": false, "fetchAlarmRulesStateOnStart": false @@ -39,6 +45,9 @@ "type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode", "name": "Save Timeseries", "debugMode": true, + "singletonMode": false, + "queueName": null, + "configurationVersion": 0, "configuration": { "defaultTTL": 7776000 }, @@ -52,8 +61,14 @@ "type": "org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode", "name": "Save Client Attributes", "debugMode": false, + "singletonMode": false, + "queueName": null, + "configurationVersion": 2, "configuration": { - "scope": "CLIENT_SCOPE" + "scope": "CLIENT_SCOPE", + "updateAttributesOnlyOnValueChange": false, + "notifyDevice": true, + "sendAttributesUpdatedNotification": false }, "externalId": null }, @@ -65,6 +80,9 @@ "type": "org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode", "name": "Message Type Switch", "debugMode": true, + "singletonMode": false, + "queueName": null, + "configurationVersion": 0, "configuration": { "version": 0 }, @@ -78,6 +96,9 @@ "type": "org.thingsboard.rule.engine.action.TbLogNode", "name": "Log RPC from Device", "debugMode": false, + "singletonMode": false, + "queueName": null, + "configurationVersion": 0, "configuration": { "scriptLang": "TBEL", "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);", @@ -93,6 +114,9 @@ "type": "org.thingsboard.rule.engine.action.TbLogNode", "name": "Log Other", "debugMode": true, + "singletonMode": false, + "queueName": null, + "configurationVersion": 0, "configuration": { "scriptLang": "TBEL", "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);", @@ -108,6 +132,9 @@ "type": "org.thingsboard.rule.engine.rpc.TbSendRPCRequestNode", "name": "RPC Call Request", "debugMode": false, + "singletonMode": false, + "queueName": null, + "configurationVersion": 0, "configuration": { "timeoutInSeconds": 60 }, @@ -122,6 +149,9 @@ "type": "org.thingsboard.rule.engine.transform.TbTransformMsgNode", "name": "Create RPC reply", "debugMode": false, + "singletonMode": false, + "queueName": null, + "configurationVersion": 0, "configuration": { "scriptLang": "TBEL", "jsScript": "return {msg: msg, metadata: metadata, msgType: msgType};", @@ -138,6 +168,9 @@ "type": "org.thingsboard.rule.engine.rpc.TbSendRPCReplyNode", "name": "Reply", "debugMode": false, + "singletonMode": false, + "queueName": null, + "configurationVersion": 0, "configuration": { "serviceIdMetaDataAttribute": "serviceId", "sessionIdMetaDataAttribute": "sessionId", @@ -147,6 +180,16 @@ } ], "connections": [ + { + "fromIndex": 1, + "toIndex": 0, + "type": "Alarm Created" + }, + { + "fromIndex": 1, + "toIndex": 0, + "type": "Alarm Updated" + }, { "fromIndex": 1, "toIndex": 4, @@ -216,6 +259,11 @@ "fromIndex": 8, "toIndex": 9, "type": "Success" + }, + { + "fromIndex": 9, + "toIndex": 0, + "type": "Success" } ], "ruleChainConnections": null