From a6ae072bc9223a16b22751245058debc41a23014 Mon Sep 17 00:00:00 2001 From: Bohdan Smetaniuk Date: Tue, 22 Sep 2020 12:41:49 +0300 Subject: [PATCH 1/9] edge services code coverage --- .../src/main/resources/thingsboard.yml | 2 +- msa/black-box-tests/pom.xml | 5 + .../server/msa/ContainerTestSuite.java | 2 +- .../server/msa/edge/EdgeImitator.java | 156 ++++++++ .../server/msa/edge/EdgeStorage.java | 120 ++++++ .../thingsboard/server/msa/edge/EdgeTest.java | 341 ++++++++++++++++++ .../src/test/resources/RootRuleChain.json | 133 +++++++ 7 files changed, 757 insertions(+), 2 deletions(-) create mode 100644 msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeImitator.java create mode 100644 msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeStorage.java create mode 100644 msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeTest.java create mode 100644 msa/black-box-tests/src/test/resources/RootRuleChain.json diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index bcf3425f53..db83fd700a 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -588,7 +588,7 @@ transport: # Edges parameters edges: rpc: - enabled: "${EDGES_RPC_ENABLED:false}" + enabled: "${EDGES_RPC_ENABLED:true}" port: "${EDGES_RPC_PORT:7070}" ssl: # Enable/disable SSL support diff --git a/msa/black-box-tests/pom.xml b/msa/black-box-tests/pom.xml index d24f38bc36..1602d24185 100644 --- a/msa/black-box-tests/pom.xml +++ b/msa/black-box-tests/pom.xml @@ -94,6 +94,11 @@ org.thingsboard rest-client + + org.thingsboard.common + edge-api + test + diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java index 647c8878b7..5a798a8cc8 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java @@ -31,7 +31,7 @@ import java.util.List; import java.util.Map; @RunWith(ClasspathSuite.class) -@ClasspathSuite.ClassnameFilters({"org.thingsboard.server.msa.*Test"}) +@ClasspathSuite.ClassnameFilters({"org.thingsboard.server.msa.*EdgeTest"}) public class ContainerTestSuite { private static DockerComposeContainer testContainer; diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeImitator.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeImitator.java new file mode 100644 index 0000000000..823d180261 --- /dev/null +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeImitator.java @@ -0,0 +1,156 @@ +/** + * Copyright © 2016-2020 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.msa.edge; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.thingsboard.edge.rpc.EdgeGrpcClient; +import org.thingsboard.edge.rpc.EdgeRpcClient; +import org.thingsboard.server.common.data.edge.EdgeEventType; +import org.thingsboard.server.gen.edge.AlarmUpdateMsg; +import org.thingsboard.server.gen.edge.AssetUpdateMsg; +import org.thingsboard.server.gen.edge.DashboardUpdateMsg; +import org.thingsboard.server.gen.edge.DeviceUpdateMsg; +import org.thingsboard.server.gen.edge.DownlinkMsg; +import org.thingsboard.server.gen.edge.DownlinkResponseMsg; +import org.thingsboard.server.gen.edge.EdgeConfiguration; +import org.thingsboard.server.gen.edge.EntityDataProto; +import org.thingsboard.server.gen.edge.RelationUpdateMsg; +import org.thingsboard.server.gen.edge.RuleChainUpdateMsg; +import org.thingsboard.server.gen.edge.UplinkResponseMsg; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@Slf4j +public class EdgeImitator { + + private String routingKey; + private String routingSecret; + + private EdgeRpcClient edgeRpcClient; + + @Getter + private EdgeStorage storage; + + + public EdgeImitator(String host, int port, String routingKey, String routingSecret) throws NoSuchFieldException, IllegalAccessException { + edgeRpcClient = new EdgeGrpcClient(); + storage = new EdgeStorage(); + this.routingKey = routingKey; + this.routingSecret = routingSecret; + setEdgeCredentials("rpcHost", host); + setEdgeCredentials("rpcPort", port); + } + + private void setEdgeCredentials(String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException { + Field fieldToSet = edgeRpcClient.getClass().getDeclaredField(fieldName); + fieldToSet.setAccessible(true); + fieldToSet.set(edgeRpcClient, value); + fieldToSet.setAccessible(false); + } + + public void connect() { + edgeRpcClient.connect(routingKey, routingSecret, + this::onUplinkResponse, + this::onEdgeUpdate, + this::onDownlink, + this::onError); + } + + public void disconnect() throws InterruptedException { + edgeRpcClient.disconnect(); + } + + private void onUplinkResponse(UplinkResponseMsg msg) { + log.info("onUplinkResponse: {}", msg); + } + + private void onEdgeUpdate(EdgeConfiguration edgeConfiguration) { + storage.setConfiguration(edgeConfiguration); + } + + private void onDownlink(DownlinkMsg downlinkMsg) { + ListenableFuture> future = processDownlinkMsg(downlinkMsg); + Futures.addCallback(future, new FutureCallback>() { + @Override + public void onSuccess(@Nullable List result) { + DownlinkResponseMsg downlinkResponseMsg = DownlinkResponseMsg.newBuilder().setSuccess(true).build(); + edgeRpcClient.sendDownlinkResponseMsg(downlinkResponseMsg); + } + + @Override + public void onFailure(Throwable t) { + DownlinkResponseMsg downlinkResponseMsg = DownlinkResponseMsg.newBuilder().setSuccess(false).setErrorMsg(t.getMessage()).build(); + edgeRpcClient.sendDownlinkResponseMsg(downlinkResponseMsg); + } + }, MoreExecutors.directExecutor()); + } + + private void onError(Exception e) { + log.error("Error during Edge lifecycle: ", e); + } + + private ListenableFuture> processDownlinkMsg(DownlinkMsg downlinkMsg) { + List> result = new ArrayList<>(); + if (downlinkMsg.getDeviceUpdateMsgList() != null && !downlinkMsg.getDeviceUpdateMsgList().isEmpty()) { + for (DeviceUpdateMsg deviceUpdateMsg: downlinkMsg.getDeviceUpdateMsgList()) { + result.add(storage.processEntity(deviceUpdateMsg.getMsgType(), EdgeEventType.DEVICE, new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB()))); + } + } + if (downlinkMsg.getAssetUpdateMsgList() != null && !downlinkMsg.getAssetUpdateMsgList().isEmpty()) { + for (AssetUpdateMsg assetUpdateMsg: downlinkMsg.getAssetUpdateMsgList()) { + result.add(storage.processEntity(assetUpdateMsg.getMsgType(), EdgeEventType.ASSET, new UUID(assetUpdateMsg.getIdMSB(), assetUpdateMsg.getIdLSB()))); + } + } + if (downlinkMsg.getRuleChainUpdateMsgList() != null && !downlinkMsg.getRuleChainUpdateMsgList().isEmpty()) { + for (RuleChainUpdateMsg ruleChainUpdateMsg: downlinkMsg.getRuleChainUpdateMsgList()) { + result.add(storage.processEntity(ruleChainUpdateMsg.getMsgType(), EdgeEventType.RULE_CHAIN, new UUID(ruleChainUpdateMsg.getIdMSB(), ruleChainUpdateMsg.getIdLSB()))); + } + } + if (downlinkMsg.getDashboardUpdateMsgList() != null && !downlinkMsg.getDashboardUpdateMsgList().isEmpty()) { + for (DashboardUpdateMsg dashboardUpdateMsg: downlinkMsg.getDashboardUpdateMsgList()) { + result.add(storage.processEntity(dashboardUpdateMsg.getMsgType(), EdgeEventType.DASHBOARD, new UUID(dashboardUpdateMsg.getIdMSB(), dashboardUpdateMsg.getIdLSB()))); + } + } + if (downlinkMsg.getRelationUpdateMsgList() != null && !downlinkMsg.getRelationUpdateMsgList().isEmpty()) { + for (RelationUpdateMsg relationUpdateMsg: downlinkMsg.getRelationUpdateMsgList()) { + result.add(storage.processRelation(relationUpdateMsg)); + } + } + if (downlinkMsg.getAlarmUpdateMsgList() != null && !downlinkMsg.getAlarmUpdateMsgList().isEmpty()) { + for (AlarmUpdateMsg alarmUpdateMsg: downlinkMsg.getAlarmUpdateMsgList()) { + result.add(storage.processAlarm(alarmUpdateMsg)); + } + } + if (downlinkMsg.getEntityDataList() != null && !downlinkMsg.getEntityDataList().isEmpty()) { + for (EntityDataProto entityDataProto: downlinkMsg.getEntityDataList()) { + if (entityDataProto.hasPostTelemetryMsg()) { + result.add(storage.processTelemetry(new UUID(entityDataProto.getEntityIdMSB(), entityDataProto.getEntityIdLSB()), entityDataProto.getPostTelemetryMsg())); + } + } + } + return Futures.allAsList(result); + } + +} diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeStorage.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeStorage.java new file mode 100644 index 0000000000..0bad7473cf --- /dev/null +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeStorage.java @@ -0,0 +1,120 @@ +/** + * Copyright © 2016-2020 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.msa.edge; + +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.server.common.data.alarm.AlarmStatus; +import org.thingsboard.server.common.data.edge.EdgeEventType; +import org.thingsboard.server.common.data.id.EntityIdFactory; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.gen.edge.AlarmUpdateMsg; +import org.thingsboard.server.gen.edge.EdgeConfiguration; +import org.thingsboard.server.gen.edge.RelationUpdateMsg; +import org.thingsboard.server.gen.edge.UpdateMsgType; +import org.thingsboard.server.gen.transport.TransportProtos; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +@Slf4j +@Getter +@Setter +public class EdgeStorage { + + private EdgeConfiguration configuration; + + private Map entities; + private Map alarms; + private List relations; + private Map latestTelemetry; + + + public EdgeStorage() { + entities = new HashMap<>(); + alarms = new HashMap<>(); + relations = new ArrayList<>(); + latestTelemetry = new HashMap<>(); + } + + public ListenableFuture processEntity(UpdateMsgType msgType, EdgeEventType type, UUID uuid) { + switch (msgType) { + case ENTITY_CREATED_RPC_MESSAGE: + case ENTITY_UPDATED_RPC_MESSAGE: + entities.put(uuid, type); + break; + case ENTITY_DELETED_RPC_MESSAGE: + entities.remove(uuid); + break; + } + return Futures.immediateFuture(null); + } + + public ListenableFuture processRelation(RelationUpdateMsg relationMsg) { + EntityRelation relation = new EntityRelation(); + relation.setType(relationMsg.getType()); + relation.setTypeGroup(RelationTypeGroup.valueOf(relationMsg.getTypeGroup())); + relation.setTo(EntityIdFactory.getByTypeAndUuid(relationMsg.getToEntityType(), new UUID(relationMsg.getToIdMSB(), relationMsg.getToIdLSB()))); + relation.setFrom(EntityIdFactory.getByTypeAndUuid(relationMsg.getFromEntityType(), new UUID(relationMsg.getFromIdMSB(), relationMsg.getFromIdLSB()))); + switch (relationMsg.getMsgType()) { + case ENTITY_CREATED_RPC_MESSAGE: + case ENTITY_UPDATED_RPC_MESSAGE: + relations.add(relation); + break; + case ENTITY_DELETED_RPC_MESSAGE: + relations.remove(relation); + break; + } + return Futures.immediateFuture(null); + } + + public ListenableFuture processAlarm(AlarmUpdateMsg alarmMsg) { + switch (alarmMsg.getMsgType()) { + case ENTITY_CREATED_RPC_MESSAGE: + case ENTITY_UPDATED_RPC_MESSAGE: + case ALARM_ACK_RPC_MESSAGE: + case ALARM_CLEAR_RPC_MESSAGE: + alarms.put(alarmMsg.getType(), AlarmStatus.valueOf(alarmMsg.getStatus())); + break; + case ENTITY_DELETED_RPC_MESSAGE: + alarms.remove(alarmMsg.getName()); + break; + } + return Futures.immediateFuture(null); + } + + public ListenableFuture processTelemetry(UUID uuid, TransportProtos.PostTelemetryMsg telemetryMsg) { + latestTelemetry.put(uuid, telemetryMsg); + return Futures.immediateFuture(null); + } + + public Set getEntitiesByType(EdgeEventType type) { + Map filtered = entities.entrySet().stream() + .filter(entry -> entry.getValue().equals(type)) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + return filtered.keySet(); + } + +} diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeTest.java new file mode 100644 index 0000000000..a1f8c8e374 --- /dev/null +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeTest.java @@ -0,0 +1,341 @@ +/** + * Copyright © 2016-2020 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.msa.edge; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.junit.*; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.thingsboard.server.common.data.Dashboard; +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.AlarmSeverity; +import org.thingsboard.server.common.data.alarm.AlarmStatus; +import org.thingsboard.server.common.data.asset.Asset; +import org.thingsboard.server.common.data.edge.Edge; +import org.thingsboard.server.common.data.edge.EdgeEventType; +import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.common.data.page.TimePageLink; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.common.data.rule.RuleChain; +import org.thingsboard.server.common.data.rule.RuleChainMetaData; +import org.thingsboard.server.common.data.rule.RuleChainType; +import org.thingsboard.server.common.data.security.DeviceCredentials; +import org.thingsboard.server.gen.edge.EdgeConfiguration; +import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.msa.AbstractContainerTest; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +@Slf4j +public class EdgeTest extends AbstractContainerTest { + + private static EdgeImitator edgeImitator; + + @BeforeClass + public static void init() throws NoSuchFieldException, IllegalAccessException, InterruptedException, IOException { + restClient.login("tenant@thingsboard.org", "tenant"); + installation(); + edgeImitator = new EdgeImitator("localhost", 7070, "routing", "secret"); + edgeImitator.connect(); + Thread.sleep(10000); + } + + @Test + public void testReceivedData() { + Edge edge = restClient.getTenantEdge("Edge1").get(); + + EdgeConfiguration configuration = edgeImitator.getStorage().getConfiguration(); + Assert.assertNotNull(configuration); + + Map entities = edgeImitator.getStorage().getEntities(); + Assert.assertFalse(entities.isEmpty()); + + Set devices = edgeImitator.getStorage().getEntitiesByType(EdgeEventType.DEVICE); + Assert.assertEquals(1, devices.size()); + for (Device device: restClient.getEdgeDevices(edge.getId(), new TextPageLink(1)).getData()) { + Assert.assertTrue(devices.contains(device.getUuidId())); + } + + Set ruleChains = edgeImitator.getStorage().getEntitiesByType(EdgeEventType.RULE_CHAIN); + Assert.assertEquals(1, ruleChains.size()); + for (RuleChain ruleChain: restClient.getEdgeRuleChains(edge.getId(), new TimePageLink(1)).getData()) { + Assert.assertTrue(ruleChains.contains(ruleChain.getUuidId())); + } + + Set assets = edgeImitator.getStorage().getEntitiesByType(EdgeEventType.ASSET); + Assert.assertEquals(1, assets.size()); + for (Asset asset: restClient.getEdgeAssets(edge.getId(), new TextPageLink(1)).getData()) { + Assert.assertTrue(assets.contains(asset.getUuidId())); + } + } + + @Test + public void testDevices() throws Exception { + Edge edge = restClient.getTenantEdge("Edge1").get(); + + Device device = new Device(); + device.setName("Edge Device 2"); + device.setType("test"); + Device savedDevice = restClient.saveDevice(device); + restClient.assignDeviceToEdge(edge.getId(), savedDevice.getId()); + + Thread.sleep(1000); + Assert.assertTrue(restClient.getEdgeDevices(edge.getId(), new TextPageLink(2)).getData().contains(savedDevice)); + Set devices = edgeImitator.getStorage().getEntitiesByType(EdgeEventType.DEVICE); + Assert.assertEquals(2, devices.size()); + Assert.assertTrue(devices.contains(savedDevice.getUuidId())); + + restClient.unassignDeviceFromEdge(edge.getId(), savedDevice.getId()); + Thread.sleep(1000); + Assert.assertFalse(restClient.getEdgeDevices(edge.getId(), new TextPageLink(2)).getData().contains(savedDevice)); + devices = edgeImitator.getStorage().getEntitiesByType(EdgeEventType.DEVICE); + Assert.assertEquals(1, devices.size()); + Assert.assertFalse(devices.contains(savedDevice.getUuidId())); + + restClient.deleteDevice(savedDevice.getId()); + } + + @Test + public void testAssets() throws Exception { + Edge edge = restClient.getTenantEdge("Edge1").get(); + + Asset asset = new Asset(); + asset.setName("Edge Asset 2"); + asset.setType("test"); + Asset savedAsset = restClient.saveAsset(asset); + restClient.assignAssetToEdge(edge.getId(), savedAsset.getId()); + + Thread.sleep(1000); + Assert.assertTrue(restClient.getEdgeAssets(edge.getId(), new TextPageLink(2)).getData().contains(savedAsset)); + Set assets = edgeImitator.getStorage().getEntitiesByType(EdgeEventType.ASSET); + Assert.assertEquals(2, assets.size()); + Assert.assertTrue(assets.contains(savedAsset.getUuidId())); + + restClient.unassignAssetFromEdge(edge.getId(), savedAsset.getId()); + Thread.sleep(1000); + Assert.assertFalse(restClient.getEdgeAssets(edge.getId(), new TextPageLink(2)).getData().contains(savedAsset)); + assets = edgeImitator.getStorage().getEntitiesByType(EdgeEventType.ASSET); + Assert.assertEquals(1, assets.size()); + Assert.assertFalse(assets.contains(savedAsset.getUuidId())); + + restClient.deleteAsset(savedAsset.getId()); + } + + @Test + public void testRuleChains() throws Exception { + Edge edge = restClient.getTenantEdge("Edge1").get(); + + RuleChain ruleChain = new RuleChain(); + ruleChain.setName("Edge Test Rule Chain"); + ruleChain.setType(RuleChainType.EDGE); + RuleChain savedRuleChain = restClient.saveRuleChain(ruleChain); + restClient.assignRuleChainToEdge(edge.getId(), savedRuleChain.getId()); + + Thread.sleep(1000); + Assert.assertTrue(restClient.getEdgeRuleChains(edge.getId(), new TimePageLink(2)).getData().contains(savedRuleChain)); + Set ruleChains = edgeImitator.getStorage().getEntitiesByType(EdgeEventType.RULE_CHAIN); + Assert.assertEquals(2, ruleChains.size()); + Assert.assertTrue(ruleChains.contains(savedRuleChain.getUuidId())); + + restClient.unassignRuleChainFromEdge(edge.getId(), savedRuleChain.getId()); + Thread.sleep(1000); + Assert.assertFalse(restClient.getEdgeRuleChains(edge.getId(), new TimePageLink(2)).getData().contains(savedRuleChain)); + ruleChains = edgeImitator.getStorage().getEntitiesByType(EdgeEventType.RULE_CHAIN); + Assert.assertEquals(1, ruleChains.size()); + Assert.assertFalse(ruleChains.contains(savedRuleChain.getUuidId())); + + restClient.deleteRuleChain(savedRuleChain.getId()); + + } + + @Test + public void testDashboards() throws Exception { + Edge edge = restClient.getTenantEdge("Edge1").get(); + + Dashboard dashboard = new Dashboard(); + dashboard.setTitle("Edge Test Dashboard"); + Dashboard savedDashboard = restClient.saveDashboard(dashboard); + restClient.assignDashboardToEdge(edge.getId(), savedDashboard.getId()); + + Thread.sleep(1000); + Assert.assertTrue(restClient.getEdgeDashboards(edge.getId(), new TimePageLink(2)).getData().stream().allMatch(dashboardInfo -> dashboardInfo.getUuidId().equals(savedDashboard.getUuidId()))); + Set dashboards = edgeImitator.getStorage().getEntitiesByType(EdgeEventType.DASHBOARD); + Assert.assertEquals(1, dashboards.size()); + Assert.assertTrue(dashboards.contains(savedDashboard.getUuidId())); + + restClient.unassignDashboardFromEdge(edge.getId(), savedDashboard.getId()); + Thread.sleep(1000); + Assert.assertFalse(restClient.getEdgeDashboards(edge.getId(), new TimePageLink(2)).getData().stream().anyMatch(dashboardInfo -> dashboardInfo.getUuidId().equals(savedDashboard.getUuidId()))); + dashboards = edgeImitator.getStorage().getEntitiesByType(EdgeEventType.DASHBOARD); + Assert.assertEquals(0, dashboards.size()); + Assert.assertFalse(dashboards.contains(savedDashboard.getUuidId())); + + restClient.deleteDashboard(savedDashboard.getId()); + + } + + @Test + public void testRelations() throws InterruptedException { + Device device = restClient.getTenantDevice("Edge Device 1").get(); + Asset asset = restClient.getTenantAsset("Edge Asset 1").get(); + + EntityRelation relation = new EntityRelation(); + relation.setType("test"); + relation.setFrom(device.getId()); + relation.setTo(asset.getId()); + relation.setTypeGroup(RelationTypeGroup.COMMON); + restClient.saveRelation(relation); + + Thread.sleep(1000); + List relations = edgeImitator.getStorage().getRelations(); + Assert.assertEquals(1, relations.size()); + Assert.assertTrue(relations.contains(relation)); + restClient.deleteRelation(relation.getFrom(), relation.getType(), relation.getTypeGroup(), relation.getTo()); + + Thread.sleep(1000); + relations = edgeImitator.getStorage().getRelations(); + Assert.assertEquals(0, relations.size()); + Assert.assertFalse(relations.contains(relation)); + } + + @Test + public void testAlarms() throws Exception { + Device device = restClient.getTenantDevice("Edge Device 1").get(); + Alarm alarm = new Alarm(); + alarm.setOriginator(device.getId()); + alarm.setStatus(AlarmStatus.ACTIVE_UNACK); + alarm.setType("alarm"); + alarm.setSeverity(AlarmSeverity.CRITICAL); + + Alarm savedAlarm = restClient.saveAlarm(alarm); + AlarmInfo alarmInfo = restClient.getAlarmInfoById(savedAlarm.getId()).get(); + Thread.sleep(1000); + + Assert.assertEquals(1, edgeImitator.getStorage().getAlarms().size()); + Assert.assertTrue(edgeImitator.getStorage().getAlarms().containsKey(alarmInfo.getType())); + Assert.assertEquals(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()), alarmInfo.getStatus()); + restClient.ackAlarm(savedAlarm.getId()); + + Thread.sleep(1000); + alarmInfo = restClient.getAlarmInfoById(savedAlarm.getId()).get(); + Assert.assertTrue(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()).isAck()); + Assert.assertEquals(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()), alarmInfo.getStatus()); + restClient.clearAlarm(savedAlarm.getId()); + + Thread.sleep(1000); + alarmInfo = restClient.getAlarmInfoById(savedAlarm.getId()).get(); + Assert.assertTrue(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()).isAck()); + Assert.assertTrue(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()).isCleared()); + Assert.assertEquals(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()), alarmInfo.getStatus()); + + restClient.deleteAlarm(savedAlarm.getId()); + + } + + @Ignore + @Test + public void testTelemetry() throws Exception { + Device device = restClient.getTenantDevice("Edge Device 1").get(); + DeviceCredentials deviceCredentials = restClient.getDeviceCredentialsByDeviceId(device.getId()).get(); + ResponseEntity response = restClient.getRestTemplate() + .postForEntity(HTTPS_URL + "/api/v1/{credentialsId}/telemetry", + "{'test': 25}", + ResponseEntity.class, + deviceCredentials.getCredentialsId()); + Assert.assertEquals(response.getStatusCode(), HttpStatus.OK); + Thread.sleep(1000); + List keys = restClient.getTimeseriesKeys(device.getId()); + List latestTimeseries = restClient.getLatestTimeseries(device.getId(), keys); + Assert.assertEquals(1, latestTimeseries.size()); + TsKvEntry tsKvEntry = latestTimeseries.get(0); + Map telemetry = edgeImitator.getStorage().getLatestTelemetry(); + Assert.assertEquals(1, telemetry.size()); + Assert.assertTrue(telemetry.containsKey(device.getUuidId())); + TransportProtos.PostTelemetryMsg telemetryMsg = telemetry.get(device.getUuidId()); + Assert.assertEquals(1, telemetryMsg.getTsKvListCount()); + TransportProtos.TsKvListProto tsKv = telemetryMsg.getTsKvListList().get(0); + Assert.assertEquals(tsKvEntry.getTs(), tsKv.getTs()); + Assert.assertEquals(1, tsKv.getKvCount()); + TransportProtos.KeyValueProto keyValue = tsKv.getKvList().get(0); + Assert.assertEquals(tsKvEntry.getKey(), keyValue.getKey()); + Assert.assertEquals(tsKvEntry.getValueAsString(), Long.toString(keyValue.getLongV())); + } + + @AfterClass + public static void destroy() throws InterruptedException { + uninstallation(); + edgeImitator.disconnect(); + } + + private static void installation() throws IOException { + Edge edge = new Edge(); + edge.setName("Edge1"); + edge.setType("test"); + edge.setRoutingKey("routing"); + edge.setSecret("secret"); + Edge savedEdge = restClient.saveEdge(edge); + + Device device = new Device(); + device.setName("Edge Device 1"); + device.setType("test"); + Device savedDevice = restClient.saveDevice(device); + restClient.assignDeviceToEdge(savedEdge.getId(), savedDevice.getId()); + + Asset asset = new Asset(); + asset.setName("Edge Asset 1"); + asset.setType("test"); + Asset savedAsset = restClient.saveAsset(asset); + restClient.assignAssetToEdge(savedEdge.getId(), savedAsset.getId()); + + ObjectMapper mapper = new ObjectMapper(); + Class edgeTestClass = EdgeTest.class; + JsonNode configuration = mapper.readTree(edgeTestClass.getClassLoader().getResourceAsStream("RootRuleChain.json")); + RuleChain ruleChain = mapper.treeToValue(configuration.get("ruleChain"), RuleChain.class); + RuleChainMetaData ruleChainMetaData = mapper.treeToValue(configuration.get("metadata"), RuleChainMetaData.class); + RuleChain savedRuleChain = restClient.saveRuleChain(ruleChain); + ruleChainMetaData.setRuleChainId(savedRuleChain.getId()); + restClient.saveRuleChainMetaData(ruleChainMetaData); + restClient.setRootRuleChain(savedRuleChain.getId()); + } + + private static void uninstallation() { + Device device = restClient.getTenantDevice("Edge Device 1").get(); + restClient.deleteDevice(device.getId()); + + Asset asset = restClient.getTenantAsset("Edge Asset 1").get(); + restClient.deleteAsset(asset.getId()); + + Edge edge = restClient.getTenantEdge("Edge1").get(); + restClient.deleteEdge(edge.getId()); + + List ruleChains = restClient.getRuleChains(new TextPageLink(3)).getData(); + RuleChain oldRoot = ruleChains.stream().filter(ruleChain -> ruleChain.getName().equals("Root Rule Chain")).findAny().get(); + RuleChain newRoot = ruleChains.stream().filter(ruleChain -> ruleChain.getName().equals("Test Root Rule Chain")).findAny().get(); + restClient.setRootRuleChain(oldRoot.getId()); + restClient.deleteRuleChain(newRoot.getId()); + } + +} diff --git a/msa/black-box-tests/src/test/resources/RootRuleChain.json b/msa/black-box-tests/src/test/resources/RootRuleChain.json new file mode 100644 index 0000000000..56324e72f5 --- /dev/null +++ b/msa/black-box-tests/src/test/resources/RootRuleChain.json @@ -0,0 +1,133 @@ +{ + "ruleChain": { + "additionalInfo": null, + "name": "Test Root Rule Chain", + "type": "CORE", + "firstRuleNodeId": null, + "root": false, + "debugMode": false, + "configuration": null + }, + "metadata": { + "firstNodeIndex": 4, + "nodes": [ + { + "additionalInfo": { + "layoutX": 1117, + "layoutY": 156 + }, + "type": "org.thingsboard.rule.engine.edge.TbMsgPushToEdgeNode", + "name": "Push to edge", + "debugMode": false, + "configuration": { + "version": 0 + } + }, + { + "additionalInfo": { + "layoutX": 825, + "layoutY": 407 + }, + "type": "org.thingsboard.rule.engine.rpc.TbSendRPCRequestNode", + "name": "RPC Call Request", + "debugMode": false, + "configuration": { + "timeoutInSeconds": 60 + } + }, + { + "additionalInfo": { + "layoutX": 826, + "layoutY": 327 + }, + "type": "org.thingsboard.rule.engine.action.TbLogNode", + "name": "Log Other", + "debugMode": false, + "configuration": { + "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);" + } + }, + { + "additionalInfo": { + "layoutX": 827, + "layoutY": 244 + }, + "type": "org.thingsboard.rule.engine.action.TbLogNode", + "name": "Log RPC from Device", + "debugMode": false, + "configuration": { + "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);" + } + }, + { + "additionalInfo": { + "layoutX": 347, + "layoutY": 149 + }, + "type": "org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode", + "name": "Message Type Switch", + "debugMode": false, + "configuration": { + "version": 0 + } + }, + { + "additionalInfo": { + "layoutX": 821, + "layoutY": 72 + }, + "type": "org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode", + "name": "Save Client Attributes", + "debugMode": false, + "configuration": { + "scope": "CLIENT_SCOPE" + } + }, + { + "additionalInfo": { + "layoutX": 824, + "layoutY": 156 + }, + "type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode", + "name": "Save Timeseries", + "debugMode": false, + "configuration": { + "defaultTTL": 0 + } + } + ], + "connections": [ + { + "fromIndex": 4, + "toIndex": 1, + "type": "RPC Request to Device" + }, + { + "fromIndex": 4, + "toIndex": 3, + "type": "RPC Request from Device" + }, + { + "fromIndex": 4, + "toIndex": 6, + "type": "Post telemetry" + }, + { + "fromIndex": 4, + "toIndex": 5, + "type": "Post attributes" + }, + { + "fromIndex": 4, + "toIndex": 2, + "type": "Other" + }, + { + "fromIndex": 6, + "toIndex": 0, + "type": "Success" + } + ], + "ruleChainConnections": null + } +} \ No newline at end of file From 43b913ffdb45b14f9a2e6cdc0b2ac1b44be37ee5 Mon Sep 17 00:00:00 2001 From: Bohdan Smetaniuk Date: Thu, 24 Sep 2020 12:59:58 +0300 Subject: [PATCH 2/9] edge services test --- .../thingsboard/server/edge/BaseEdgeTest.java | 403 ++++++++++++++++++ .../server/edge/EdgeNoSqlTestSuite.java | 47 ++ .../server/edge/EdgeSqlTestSuite.java | 41 ++ .../server/edge/imitator}/EdgeImitator.java | 26 +- .../server/edge/imitator}/EdgeStorage.java | 24 +- .../server/edge/nosql/EdgeNoSqlTest.java | 23 + .../server/edge/sql/EdgeSqlTest.java | 23 + msa/black-box-tests/pom.xml | 5 - .../server/msa/ContainerTestSuite.java | 2 +- .../thingsboard/server/msa/edge/EdgeTest.java | 341 --------------- .../src/test/resources/RootRuleChain.json | 133 ------ 11 files changed, 554 insertions(+), 514 deletions(-) create mode 100644 application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java create mode 100644 application/src/test/java/org/thingsboard/server/edge/EdgeNoSqlTestSuite.java create mode 100644 application/src/test/java/org/thingsboard/server/edge/EdgeSqlTestSuite.java rename {msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge => application/src/test/java/org/thingsboard/server/edge/imitator}/EdgeImitator.java (83%) rename {msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge => application/src/test/java/org/thingsboard/server/edge/imitator}/EdgeStorage.java (83%) create mode 100644 application/src/test/java/org/thingsboard/server/edge/nosql/EdgeNoSqlTest.java create mode 100644 application/src/test/java/org/thingsboard/server/edge/sql/EdgeSqlTest.java delete mode 100644 msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeTest.java delete mode 100644 msa/black-box-tests/src/test/resources/RootRuleChain.json diff --git a/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java new file mode 100644 index 0000000000..3f5f9ee0e4 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java @@ -0,0 +1,403 @@ +/** + * Copyright © 2016-2020 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.edge; + +import com.fasterxml.jackson.core.type.TypeReference; +import lombok.extern.slf4j.Slf4j; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.thingsboard.server.common.data.Dashboard; +import org.thingsboard.server.common.data.DashboardInfo; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmInfo; +import org.thingsboard.server.common.data.alarm.AlarmSeverity; +import org.thingsboard.server.common.data.alarm.AlarmStatus; +import org.thingsboard.server.common.data.asset.Asset; +import org.thingsboard.server.common.data.edge.Edge; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.common.data.page.TimePageData; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.common.data.rule.RuleChain; +import org.thingsboard.server.common.data.rule.RuleChainType; +import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.controller.AbstractControllerTest; +import org.thingsboard.server.dao.rule.RuleChainService; +import org.thingsboard.server.edge.imitator.EdgeImitator; +import org.thingsboard.server.gen.edge.EdgeConfiguration; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + + +@Slf4j +abstract public class BaseEdgeTest extends AbstractControllerTest { + + private Tenant savedTenant; + private TenantId tenantId; + private User tenantAdmin; + + private EdgeImitator edgeImitator; + private Edge edge; + + @Autowired + RuleChainService ruleChainService; + + @Before + public void beforeTest() throws Exception { + loginSysAdmin(); + + Tenant tenant = new Tenant(); + tenant.setTitle("My tenant"); + savedTenant = doPost("/api/tenant", tenant, Tenant.class); + tenantId = savedTenant.getId(); + Assert.assertNotNull(savedTenant); + + tenantAdmin = new User(); + tenantAdmin.setAuthority(Authority.TENANT_ADMIN); + tenantAdmin.setTenantId(savedTenant.getId()); + tenantAdmin.setEmail("tenant2@thingsboard.org"); + tenantAdmin.setFirstName("Joe"); + tenantAdmin.setLastName("Downs"); + + tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); + + installation(); + + edgeImitator = new EdgeImitator("localhost", 7070, edge.getRoutingKey(), edge.getSecret()); + edgeImitator.connect(); + Thread.sleep(5000); + } + + @After + public void afterTest() throws Exception { + edgeImitator.disconnect(); + uninstallation(); + + loginSysAdmin(); + + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) + .andExpect(status().isOk()); + } + + + @Test + public void test() throws Exception { + testReceivedData(); + testDevices(); + testAssets(); + testRuleChains(); + testDashboards(); + testRelations(); + testAlarms(); + } + + private void testReceivedData() throws Exception { + log.info("Checking received data"); + EdgeConfiguration configuration = edgeImitator.getStorage().getConfiguration(); + Assert.assertNotNull(configuration); + + Map entities = edgeImitator.getStorage().getEntities(); + Assert.assertFalse(entities.isEmpty()); + + Set devices = edgeImitator.getStorage().getEntitiesByType(EntityType.DEVICE); + Assert.assertEquals(1, devices.size()); + TimePageData pageDataDevices = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/devices?", + new TypeReference>() {}, new TextPageLink(100)); + for (Device device: pageDataDevices.getData()) { + Assert.assertTrue(devices.contains(device.getUuidId())); + } + + Set assets = edgeImitator.getStorage().getEntitiesByType(EntityType.ASSET); + Assert.assertEquals(1, assets.size()); + TimePageData pageDataAssets = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/assets?", + new TypeReference>() {}, new TextPageLink(100)); + for (Asset asset: pageDataAssets.getData()) { + Assert.assertTrue(assets.contains(asset.getUuidId())); + } + + Set ruleChains = edgeImitator.getStorage().getEntitiesByType(EntityType.RULE_CHAIN); + Assert.assertEquals(1, ruleChains.size()); + TimePageData pageDataRuleChains = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/ruleChains?", + new TypeReference>() {}, new TextPageLink(100)); + for (RuleChain ruleChain: pageDataRuleChains.getData()) { + Assert.assertTrue(ruleChains.contains(ruleChain.getUuidId())); + } + log.info("Received data checked"); + } + + private void testDevices() throws Exception { + log.info("Testing devices"); + Device device = new Device(); + device.setName("Edge Device 2"); + device.setType("test"); + Device savedDevice = doPost("/api/device", device, Device.class); + doPost("/api/edge/" + edge.getId().getId().toString() + + "/device/" + savedDevice.getId().getId().toString(), Device.class); + + TimePageData pageDataDevices = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/devices?", + new TypeReference>() {}, new TextPageLink(100)); + Assert.assertTrue(pageDataDevices.getData().contains(savedDevice)); + Thread.sleep(1000); + Set devices = edgeImitator.getStorage().getEntitiesByType(EntityType.DEVICE); + Assert.assertEquals(2, devices.size()); + Assert.assertTrue(devices.contains(savedDevice.getUuidId())); + + doDelete("/api/edge/" + edge.getId().getId().toString() + + "/device/" + savedDevice.getId().getId().toString(), Device.class); + pageDataDevices = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/devices?", + new TypeReference>() {}, new TextPageLink(100)); + Assert.assertFalse(pageDataDevices.getData().contains(savedDevice)); + Thread.sleep(1000); + devices = edgeImitator.getStorage().getEntitiesByType(EntityType.DEVICE); + Assert.assertEquals(1, devices.size()); + Assert.assertFalse(devices.contains(savedDevice.getUuidId())); + + doDelete("/api/device/" + savedDevice.getId().getId().toString()) + .andExpect(status().isOk()); + log.info("Devices tested successfully"); + } + + private void testAssets() throws Exception { + log.info("Testing assets"); + Asset asset = new Asset(); + asset.setName("Edge Asset 2"); + asset.setType("test"); + Asset savedAsset = doPost("/api/asset", asset, Asset.class); + doPost("/api/edge/" + edge.getId().getId().toString() + + "/asset/" + savedAsset.getId().getId().toString(), Asset.class); + + TimePageData pageDataAssets = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/assets?", + new TypeReference>() {}, new TextPageLink(100)); + Assert.assertTrue(pageDataAssets.getData().contains(savedAsset)); + Thread.sleep(1000); + Set assets = edgeImitator.getStorage().getEntitiesByType(EntityType.ASSET); + Assert.assertEquals(2, assets.size()); + Assert.assertTrue(assets.contains(savedAsset.getUuidId())); + + doDelete("/api/edge/" + edge.getId().getId().toString() + + "/asset/" + savedAsset.getId().getId().toString(), Asset.class); + pageDataAssets = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/assets?", + new TypeReference>() {}, new TextPageLink(100)); + Assert.assertFalse(pageDataAssets.getData().contains(savedAsset)); + Thread.sleep(1000); + assets = edgeImitator.getStorage().getEntitiesByType(EntityType.ASSET); + Assert.assertEquals(1, assets.size()); + Assert.assertFalse(assets.contains(savedAsset.getUuidId())); + + doDelete("/api/asset/" + savedAsset.getId().getId().toString()) + .andExpect(status().isOk()); + log.info("Assets tested successfully"); + } + + private void testRuleChains() throws Exception { + log.info("Testing RuleChains"); + RuleChain ruleChain = new RuleChain(); + ruleChain.setName("Edge Test Rule Chain"); + ruleChain.setType(RuleChainType.EDGE); + RuleChain savedRuleChain = doPost("/api/ruleChain", ruleChain, RuleChain.class); + doPost("/api/edge/" + edge.getId().getId().toString() + + "/ruleChain/" + savedRuleChain.getId().getId().toString(), RuleChain.class); + + TimePageData pageDataRuleChain = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/ruleChains?", + new TypeReference>() {}, new TextPageLink(100)); + Assert.assertTrue(pageDataRuleChain.getData().contains(savedRuleChain)); + Thread.sleep(1000); + Set ruleChains = edgeImitator.getStorage().getEntitiesByType(EntityType.RULE_CHAIN); + Assert.assertEquals(2, ruleChains.size()); + Assert.assertTrue(ruleChains.contains(savedRuleChain.getUuidId())); + + doDelete("/api/edge/" + edge.getId().getId().toString() + + "/ruleChain/" + savedRuleChain.getId().getId().toString(), RuleChain.class); + pageDataRuleChain = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/ruleChains?", + new TypeReference>() {}, new TextPageLink(100)); + Assert.assertFalse(pageDataRuleChain.getData().contains(savedRuleChain)); + Thread.sleep(1000); + ruleChains = edgeImitator.getStorage().getEntitiesByType(EntityType.RULE_CHAIN); + Assert.assertEquals(1, ruleChains.size()); + Assert.assertFalse(ruleChains.contains(savedRuleChain.getUuidId())); + + doDelete("/api/ruleChain/" + savedRuleChain.getId().getId().toString()) + .andExpect(status().isOk()); + log.info("RuleChains tested successfully"); + + } + + private void testDashboards() throws Exception { + log.info("Testing Dashboards"); + Dashboard dashboard = new Dashboard(); + dashboard.setTitle("Edge Test Dashboard"); + Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class); + doPost("/api/edge/" + edge.getId().getId().toString() + + "/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class); + + TimePageData pageDataDashboard = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/dashboards?", + new TypeReference>() {}, new TextPageLink(100)); + Assert.assertTrue(pageDataDashboard.getData().stream().allMatch(dashboardInfo -> dashboardInfo.getUuidId().equals(savedDashboard.getUuidId()))); + Thread.sleep(1000); + Set dashboards = edgeImitator.getStorage().getEntitiesByType(EntityType.DASHBOARD); + Assert.assertEquals(1, dashboards.size()); + Assert.assertTrue(dashboards.contains(savedDashboard.getUuidId())); + + doDelete("/api/edge/" + edge.getId().getId().toString() + + "/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class); + pageDataDashboard = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/dashboards?", + new TypeReference>() {}, new TextPageLink(100)); + Assert.assertFalse(pageDataDashboard.getData().stream().anyMatch(dashboardInfo -> dashboardInfo.getUuidId().equals(savedDashboard.getUuidId()))); + Thread.sleep(1000); + dashboards = edgeImitator.getStorage().getEntitiesByType(EntityType.DASHBOARD); + Assert.assertEquals(0, dashboards.size()); + Assert.assertFalse(dashboards.contains(savedDashboard.getUuidId())); + + doDelete("/api/dashboard/" + savedDashboard.getId().getId().toString()) + .andExpect(status().isOk()); + log.info("Dashboards tested successfully"); + + } + + private void installation() throws Exception { + edge = doPost("/api/edge", constructEdge("Test Edge", "test"), Edge.class); + + Device device = new Device(); + device.setName("Edge Device 1"); + device.setType("test"); + Device savedDevice = doPost("/api/device", device, Device.class); + doPost("/api/edge/" + edge.getId().getId().toString() + + "/device/" + savedDevice.getId().getId().toString(), Device.class); + + Asset asset = new Asset(); + asset.setName("Edge Asset 1"); + asset.setType("test"); + Asset savedAsset = doPost("/api/asset", asset, Asset.class); + doPost("/api/edge/" + edge.getId().getId().toString() + + "/asset/" + savedAsset.getId().getId().toString(), Asset.class); + } + + private void uninstallation() throws Exception { + + TimePageData pageDataDevices = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/devices?", + new TypeReference>() {}, new TextPageLink(100)); + for (Device device: pageDataDevices.getData()) { + doDelete("/api/device/" + device.getId().getId().toString()) + .andExpect(status().isOk()); + } + + TimePageData pageDataAssets = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/assets?", + new TypeReference>() {}, new TextPageLink(100)); + for (Asset asset: pageDataAssets.getData()) { + doDelete("/api/asset/" + asset.getId().getId().toString()) + .andExpect(status().isOk()); + } + + doDelete("/api/edge/" + edge.getId().getId().toString()) + .andExpect(status().isOk()); + } + + private void testRelations() throws Exception { + log.info("Testing Relations"); + List edgeDevices = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/devices?", + new TypeReference>() {}, new TextPageLink(100)).getData(); + List edgeAssets = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/assets?", + new TypeReference>() {}, new TextPageLink(100)).getData(); + + Assert.assertEquals(1, edgeDevices.size()); + Assert.assertEquals(1, edgeAssets.size()); + Device device = edgeDevices.get(0); + Asset asset = edgeAssets.get(0); + Assert.assertEquals("Edge Device 1", device.getName()); + Assert.assertEquals("Edge Asset 1", asset.getName()); + + EntityRelation relation = new EntityRelation(); + relation.setType("test"); + relation.setFrom(device.getId()); + relation.setTo(asset.getId()); + relation.setTypeGroup(RelationTypeGroup.COMMON); + doPost("/api/relation", relation); + + Thread.sleep(1000); + List relations = edgeImitator.getStorage().getRelations(); + Assert.assertEquals(1, relations.size()); + Assert.assertTrue(relations.contains(relation)); + doDelete("/api/relation?" + + "fromId=" + relation.getFrom().getId().toString() + + "&fromType=" + relation.getFrom().getEntityType().name() + + "&relationType=" + relation.getType() + + "&relationTypeGroup=" + relation.getTypeGroup().name() + + "&toId=" + relation.getTo().getId().toString() + + "&toType=" + relation.getTo().getEntityType().name()) + .andExpect(status().isOk()); + + Thread.sleep(1000); + relations = edgeImitator.getStorage().getRelations(); + Assert.assertEquals(0, relations.size()); + Assert.assertFalse(relations.contains(relation)); + log.info("Relations tested successfully"); + } + + + private void testAlarms() throws Exception { + log.info("Testing Alarms"); + List edgeDevices = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/devices?", + new TypeReference>() {}, new TextPageLink(100)).getData(); + Assert.assertEquals(1, edgeDevices.size()); + Device device = edgeDevices.get(0); + Assert.assertEquals("Edge Device 1", device.getName()); + + Alarm alarm = new Alarm(); + alarm.setOriginator(device.getId()); + alarm.setStatus(AlarmStatus.ACTIVE_UNACK); + alarm.setType("alarm"); + alarm.setSeverity(AlarmSeverity.CRITICAL); + + Alarm savedAlarm = doPost("/api/alarm", alarm, Alarm.class); + AlarmInfo alarmInfo = doGet("/api/alarm/info/" + savedAlarm.getId().getId().toString(), AlarmInfo.class); + Thread.sleep(1000); + + Assert.assertEquals(1, edgeImitator.getStorage().getAlarms().size()); + Assert.assertTrue(edgeImitator.getStorage().getAlarms().containsKey(alarmInfo.getType())); + Assert.assertEquals(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()), alarmInfo.getStatus()); + doPost("/api/alarm/" + savedAlarm.getId().getId().toString() + "/ack"); + + Thread.sleep(1000); + alarmInfo = doGet("/api/alarm/info/" + savedAlarm.getId().getId().toString(), AlarmInfo.class); + Assert.assertTrue(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()).isAck()); + Assert.assertEquals(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()), alarmInfo.getStatus()); + doPost("/api/alarm/" + savedAlarm.getId().getId().toString() + "/clear"); + + Thread.sleep(1000); + alarmInfo = doGet("/api/alarm/info/" + savedAlarm.getId().getId().toString(), AlarmInfo.class); + Assert.assertTrue(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()).isAck()); + Assert.assertTrue(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()).isCleared()); + Assert.assertEquals(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()), alarmInfo.getStatus()); + + doDelete("/api/alarm/" + savedAlarm.getId().getId().toString()) + .andExpect(status().isOk()); + log.info("Alarms tested successfully"); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/edge/EdgeNoSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/edge/EdgeNoSqlTestSuite.java new file mode 100644 index 0000000000..06d566d410 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/edge/EdgeNoSqlTestSuite.java @@ -0,0 +1,47 @@ +/** + * Copyright © 2016-2020 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.edge; + +import org.cassandraunit.dataset.cql.ClassPathCQLDataSet; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.extensions.cpsuite.ClasspathSuite; +import org.junit.runner.RunWith; +import org.thingsboard.server.dao.CustomCassandraCQLUnit; +import org.thingsboard.server.queue.memory.InMemoryStorage; + +import java.util.Arrays; + +@RunWith(ClasspathSuite.class) +@ClasspathSuite.ClassnameFilters({ + "org.thingsboard.server.edge.nosql.*Test"}) +public class EdgeNoSqlTestSuite { + + @ClassRule + public static CustomCassandraCQLUnit cassandraUnit = + new CustomCassandraCQLUnit( + Arrays.asList( + new ClassPathCQLDataSet("cassandra/schema-ts.cql", false, false), + new ClassPathCQLDataSet("cassandra/schema-entities.cql", false, false), + new ClassPathCQLDataSet("cassandra/system-data.cql", false, false), + new ClassPathCQLDataSet("cassandra/system-test.cql", false, false)), + "cassandra-test.yaml", 30000l); + + @BeforeClass + public static void cleanupInMemStorage(){ + InMemoryStorage.getInstance().cleanup(); + } +} diff --git a/application/src/test/java/org/thingsboard/server/edge/EdgeSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/edge/EdgeSqlTestSuite.java new file mode 100644 index 0000000000..5d0e4f977c --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/edge/EdgeSqlTestSuite.java @@ -0,0 +1,41 @@ +/** + * Copyright © 2016-2020 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.edge; + +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.extensions.cpsuite.ClasspathSuite; +import org.junit.runner.RunWith; +import org.thingsboard.server.dao.CustomSqlUnit; +import org.thingsboard.server.queue.memory.InMemoryStorage; + +import java.util.Arrays; + +@RunWith(ClasspathSuite.class) +@ClasspathSuite.ClassnameFilters({"org.thingsboard.server.edge.sql.*Test"}) +public class EdgeSqlTestSuite { + + @ClassRule + public static CustomSqlUnit sqlUnit = new CustomSqlUnit( + Arrays.asList("sql/schema-ts-hsql.sql", "sql/schema-entities-hsql.sql", "sql/schema-entities-idx.sql", "sql/system-data.sql"), + "sql/hsql/drop-all-tables.sql", + "sql-test.properties"); + + @BeforeClass + public static void cleanupInMemStorage(){ + InMemoryStorage.getInstance().cleanup(); + } +} diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeImitator.java b/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java similarity index 83% rename from msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeImitator.java rename to application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java index 823d180261..9f6d51a601 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeImitator.java +++ b/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.msa.edge; +package org.thingsboard.server.edge.imitator; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; @@ -24,7 +24,7 @@ import lombok.extern.slf4j.Slf4j; import org.checkerframework.checker.nullness.qual.Nullable; import org.thingsboard.edge.rpc.EdgeGrpcClient; import org.thingsboard.edge.rpc.EdgeRpcClient; -import org.thingsboard.server.common.data.edge.EdgeEventType; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.gen.edge.AlarmUpdateMsg; import org.thingsboard.server.gen.edge.AssetUpdateMsg; import org.thingsboard.server.gen.edge.DashboardUpdateMsg; @@ -32,7 +32,6 @@ import org.thingsboard.server.gen.edge.DeviceUpdateMsg; import org.thingsboard.server.gen.edge.DownlinkMsg; import org.thingsboard.server.gen.edge.DownlinkResponseMsg; import org.thingsboard.server.gen.edge.EdgeConfiguration; -import org.thingsboard.server.gen.edge.EntityDataProto; import org.thingsboard.server.gen.edge.RelationUpdateMsg; import org.thingsboard.server.gen.edge.RuleChainUpdateMsg; import org.thingsboard.server.gen.edge.UplinkResponseMsg; @@ -75,7 +74,7 @@ public class EdgeImitator { this::onUplinkResponse, this::onEdgeUpdate, this::onDownlink, - this::onError); + this::onClose); } public void disconnect() throws InterruptedException { @@ -107,30 +106,30 @@ public class EdgeImitator { }, MoreExecutors.directExecutor()); } - private void onError(Exception e) { - log.error("Error during Edge lifecycle: ", e); + private void onClose(Exception e) { + log.info("onClose: {}", e.getMessage()); } private ListenableFuture> processDownlinkMsg(DownlinkMsg downlinkMsg) { List> result = new ArrayList<>(); if (downlinkMsg.getDeviceUpdateMsgList() != null && !downlinkMsg.getDeviceUpdateMsgList().isEmpty()) { for (DeviceUpdateMsg deviceUpdateMsg: downlinkMsg.getDeviceUpdateMsgList()) { - result.add(storage.processEntity(deviceUpdateMsg.getMsgType(), EdgeEventType.DEVICE, new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB()))); + result.add(storage.processEntity(deviceUpdateMsg.getMsgType(), EntityType.DEVICE, new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB()))); } } if (downlinkMsg.getAssetUpdateMsgList() != null && !downlinkMsg.getAssetUpdateMsgList().isEmpty()) { for (AssetUpdateMsg assetUpdateMsg: downlinkMsg.getAssetUpdateMsgList()) { - result.add(storage.processEntity(assetUpdateMsg.getMsgType(), EdgeEventType.ASSET, new UUID(assetUpdateMsg.getIdMSB(), assetUpdateMsg.getIdLSB()))); + result.add(storage.processEntity(assetUpdateMsg.getMsgType(), EntityType.ASSET, new UUID(assetUpdateMsg.getIdMSB(), assetUpdateMsg.getIdLSB()))); } } if (downlinkMsg.getRuleChainUpdateMsgList() != null && !downlinkMsg.getRuleChainUpdateMsgList().isEmpty()) { for (RuleChainUpdateMsg ruleChainUpdateMsg: downlinkMsg.getRuleChainUpdateMsgList()) { - result.add(storage.processEntity(ruleChainUpdateMsg.getMsgType(), EdgeEventType.RULE_CHAIN, new UUID(ruleChainUpdateMsg.getIdMSB(), ruleChainUpdateMsg.getIdLSB()))); + result.add(storage.processEntity(ruleChainUpdateMsg.getMsgType(), EntityType.RULE_CHAIN, new UUID(ruleChainUpdateMsg.getIdMSB(), ruleChainUpdateMsg.getIdLSB()))); } } if (downlinkMsg.getDashboardUpdateMsgList() != null && !downlinkMsg.getDashboardUpdateMsgList().isEmpty()) { for (DashboardUpdateMsg dashboardUpdateMsg: downlinkMsg.getDashboardUpdateMsgList()) { - result.add(storage.processEntity(dashboardUpdateMsg.getMsgType(), EdgeEventType.DASHBOARD, new UUID(dashboardUpdateMsg.getIdMSB(), dashboardUpdateMsg.getIdLSB()))); + result.add(storage.processEntity(dashboardUpdateMsg.getMsgType(), EntityType.DASHBOARD, new UUID(dashboardUpdateMsg.getIdMSB(), dashboardUpdateMsg.getIdLSB()))); } } if (downlinkMsg.getRelationUpdateMsgList() != null && !downlinkMsg.getRelationUpdateMsgList().isEmpty()) { @@ -143,13 +142,6 @@ public class EdgeImitator { result.add(storage.processAlarm(alarmUpdateMsg)); } } - if (downlinkMsg.getEntityDataList() != null && !downlinkMsg.getEntityDataList().isEmpty()) { - for (EntityDataProto entityDataProto: downlinkMsg.getEntityDataList()) { - if (entityDataProto.hasPostTelemetryMsg()) { - result.add(storage.processTelemetry(new UUID(entityDataProto.getEntityIdMSB(), entityDataProto.getEntityIdLSB()), entityDataProto.getPostTelemetryMsg())); - } - } - } return Futures.allAsList(result); } diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeStorage.java b/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeStorage.java similarity index 83% rename from msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeStorage.java rename to application/src/test/java/org/thingsboard/server/edge/imitator/EdgeStorage.java index 0bad7473cf..a52d1e7f6e 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeStorage.java +++ b/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeStorage.java @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.msa.edge; +package org.thingsboard.server.edge.imitator; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.alarm.AlarmStatus; -import org.thingsboard.server.common.data.edge.EdgeEventType; import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.RelationTypeGroup; @@ -29,7 +29,6 @@ import org.thingsboard.server.gen.edge.AlarmUpdateMsg; import org.thingsboard.server.gen.edge.EdgeConfiguration; import org.thingsboard.server.gen.edge.RelationUpdateMsg; import org.thingsboard.server.gen.edge.UpdateMsgType; -import org.thingsboard.server.gen.transport.TransportProtos; import java.util.ArrayList; import java.util.HashMap; @@ -46,20 +45,17 @@ public class EdgeStorage { private EdgeConfiguration configuration; - private Map entities; + private Map entities; private Map alarms; private List relations; - private Map latestTelemetry; - public EdgeStorage() { entities = new HashMap<>(); alarms = new HashMap<>(); relations = new ArrayList<>(); - latestTelemetry = new HashMap<>(); } - public ListenableFuture processEntity(UpdateMsgType msgType, EdgeEventType type, UUID uuid) { + public ListenableFuture processEntity(UpdateMsgType msgType, EntityType type, UUID uuid) { switch (msgType) { case ENTITY_CREATED_RPC_MESSAGE: case ENTITY_UPDATED_RPC_MESSAGE: @@ -105,16 +101,10 @@ public class EdgeStorage { return Futures.immediateFuture(null); } - public ListenableFuture processTelemetry(UUID uuid, TransportProtos.PostTelemetryMsg telemetryMsg) { - latestTelemetry.put(uuid, telemetryMsg); - return Futures.immediateFuture(null); - } - - public Set getEntitiesByType(EdgeEventType type) { - Map filtered = entities.entrySet().stream() + public Set getEntitiesByType(EntityType type) { + return entities.entrySet().stream() .filter(entry -> entry.getValue().equals(type)) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - return filtered.keySet(); + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)).keySet(); } } diff --git a/application/src/test/java/org/thingsboard/server/edge/nosql/EdgeNoSqlTest.java b/application/src/test/java/org/thingsboard/server/edge/nosql/EdgeNoSqlTest.java new file mode 100644 index 0000000000..c612eab16c --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/edge/nosql/EdgeNoSqlTest.java @@ -0,0 +1,23 @@ +/** + * Copyright © 2016-2020 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.edge.nosql; + +import org.thingsboard.server.dao.service.DaoNoSqlTest; +import org.thingsboard.server.edge.BaseEdgeTest; + +@DaoNoSqlTest +public class EdgeNoSqlTest extends BaseEdgeTest { +} diff --git a/application/src/test/java/org/thingsboard/server/edge/sql/EdgeSqlTest.java b/application/src/test/java/org/thingsboard/server/edge/sql/EdgeSqlTest.java new file mode 100644 index 0000000000..4b2d087fc0 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/edge/sql/EdgeSqlTest.java @@ -0,0 +1,23 @@ +/** + * Copyright © 2016-2020 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.edge.sql; + +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.edge.BaseEdgeTest; + +@DaoSqlTest +public class EdgeSqlTest extends BaseEdgeTest { +} diff --git a/msa/black-box-tests/pom.xml b/msa/black-box-tests/pom.xml index 1602d24185..d24f38bc36 100644 --- a/msa/black-box-tests/pom.xml +++ b/msa/black-box-tests/pom.xml @@ -94,11 +94,6 @@ org.thingsboard rest-client - - org.thingsboard.common - edge-api - test - diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java index 5a798a8cc8..647c8878b7 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java @@ -31,7 +31,7 @@ import java.util.List; import java.util.Map; @RunWith(ClasspathSuite.class) -@ClasspathSuite.ClassnameFilters({"org.thingsboard.server.msa.*EdgeTest"}) +@ClasspathSuite.ClassnameFilters({"org.thingsboard.server.msa.*Test"}) public class ContainerTestSuite { private static DockerComposeContainer testContainer; diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeTest.java deleted file mode 100644 index a1f8c8e374..0000000000 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/edge/EdgeTest.java +++ /dev/null @@ -1,341 +0,0 @@ -/** - * Copyright © 2016-2020 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.msa.edge; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.extern.slf4j.Slf4j; -import org.junit.*; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.thingsboard.server.common.data.Dashboard; -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.AlarmSeverity; -import org.thingsboard.server.common.data.alarm.AlarmStatus; -import org.thingsboard.server.common.data.asset.Asset; -import org.thingsboard.server.common.data.edge.Edge; -import org.thingsboard.server.common.data.edge.EdgeEventType; -import org.thingsboard.server.common.data.kv.TsKvEntry; -import org.thingsboard.server.common.data.page.TextPageLink; -import org.thingsboard.server.common.data.page.TimePageLink; -import org.thingsboard.server.common.data.relation.EntityRelation; -import org.thingsboard.server.common.data.relation.RelationTypeGroup; -import org.thingsboard.server.common.data.rule.RuleChain; -import org.thingsboard.server.common.data.rule.RuleChainMetaData; -import org.thingsboard.server.common.data.rule.RuleChainType; -import org.thingsboard.server.common.data.security.DeviceCredentials; -import org.thingsboard.server.gen.edge.EdgeConfiguration; -import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.msa.AbstractContainerTest; - -import java.io.IOException; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - -@Slf4j -public class EdgeTest extends AbstractContainerTest { - - private static EdgeImitator edgeImitator; - - @BeforeClass - public static void init() throws NoSuchFieldException, IllegalAccessException, InterruptedException, IOException { - restClient.login("tenant@thingsboard.org", "tenant"); - installation(); - edgeImitator = new EdgeImitator("localhost", 7070, "routing", "secret"); - edgeImitator.connect(); - Thread.sleep(10000); - } - - @Test - public void testReceivedData() { - Edge edge = restClient.getTenantEdge("Edge1").get(); - - EdgeConfiguration configuration = edgeImitator.getStorage().getConfiguration(); - Assert.assertNotNull(configuration); - - Map entities = edgeImitator.getStorage().getEntities(); - Assert.assertFalse(entities.isEmpty()); - - Set devices = edgeImitator.getStorage().getEntitiesByType(EdgeEventType.DEVICE); - Assert.assertEquals(1, devices.size()); - for (Device device: restClient.getEdgeDevices(edge.getId(), new TextPageLink(1)).getData()) { - Assert.assertTrue(devices.contains(device.getUuidId())); - } - - Set ruleChains = edgeImitator.getStorage().getEntitiesByType(EdgeEventType.RULE_CHAIN); - Assert.assertEquals(1, ruleChains.size()); - for (RuleChain ruleChain: restClient.getEdgeRuleChains(edge.getId(), new TimePageLink(1)).getData()) { - Assert.assertTrue(ruleChains.contains(ruleChain.getUuidId())); - } - - Set assets = edgeImitator.getStorage().getEntitiesByType(EdgeEventType.ASSET); - Assert.assertEquals(1, assets.size()); - for (Asset asset: restClient.getEdgeAssets(edge.getId(), new TextPageLink(1)).getData()) { - Assert.assertTrue(assets.contains(asset.getUuidId())); - } - } - - @Test - public void testDevices() throws Exception { - Edge edge = restClient.getTenantEdge("Edge1").get(); - - Device device = new Device(); - device.setName("Edge Device 2"); - device.setType("test"); - Device savedDevice = restClient.saveDevice(device); - restClient.assignDeviceToEdge(edge.getId(), savedDevice.getId()); - - Thread.sleep(1000); - Assert.assertTrue(restClient.getEdgeDevices(edge.getId(), new TextPageLink(2)).getData().contains(savedDevice)); - Set devices = edgeImitator.getStorage().getEntitiesByType(EdgeEventType.DEVICE); - Assert.assertEquals(2, devices.size()); - Assert.assertTrue(devices.contains(savedDevice.getUuidId())); - - restClient.unassignDeviceFromEdge(edge.getId(), savedDevice.getId()); - Thread.sleep(1000); - Assert.assertFalse(restClient.getEdgeDevices(edge.getId(), new TextPageLink(2)).getData().contains(savedDevice)); - devices = edgeImitator.getStorage().getEntitiesByType(EdgeEventType.DEVICE); - Assert.assertEquals(1, devices.size()); - Assert.assertFalse(devices.contains(savedDevice.getUuidId())); - - restClient.deleteDevice(savedDevice.getId()); - } - - @Test - public void testAssets() throws Exception { - Edge edge = restClient.getTenantEdge("Edge1").get(); - - Asset asset = new Asset(); - asset.setName("Edge Asset 2"); - asset.setType("test"); - Asset savedAsset = restClient.saveAsset(asset); - restClient.assignAssetToEdge(edge.getId(), savedAsset.getId()); - - Thread.sleep(1000); - Assert.assertTrue(restClient.getEdgeAssets(edge.getId(), new TextPageLink(2)).getData().contains(savedAsset)); - Set assets = edgeImitator.getStorage().getEntitiesByType(EdgeEventType.ASSET); - Assert.assertEquals(2, assets.size()); - Assert.assertTrue(assets.contains(savedAsset.getUuidId())); - - restClient.unassignAssetFromEdge(edge.getId(), savedAsset.getId()); - Thread.sleep(1000); - Assert.assertFalse(restClient.getEdgeAssets(edge.getId(), new TextPageLink(2)).getData().contains(savedAsset)); - assets = edgeImitator.getStorage().getEntitiesByType(EdgeEventType.ASSET); - Assert.assertEquals(1, assets.size()); - Assert.assertFalse(assets.contains(savedAsset.getUuidId())); - - restClient.deleteAsset(savedAsset.getId()); - } - - @Test - public void testRuleChains() throws Exception { - Edge edge = restClient.getTenantEdge("Edge1").get(); - - RuleChain ruleChain = new RuleChain(); - ruleChain.setName("Edge Test Rule Chain"); - ruleChain.setType(RuleChainType.EDGE); - RuleChain savedRuleChain = restClient.saveRuleChain(ruleChain); - restClient.assignRuleChainToEdge(edge.getId(), savedRuleChain.getId()); - - Thread.sleep(1000); - Assert.assertTrue(restClient.getEdgeRuleChains(edge.getId(), new TimePageLink(2)).getData().contains(savedRuleChain)); - Set ruleChains = edgeImitator.getStorage().getEntitiesByType(EdgeEventType.RULE_CHAIN); - Assert.assertEquals(2, ruleChains.size()); - Assert.assertTrue(ruleChains.contains(savedRuleChain.getUuidId())); - - restClient.unassignRuleChainFromEdge(edge.getId(), savedRuleChain.getId()); - Thread.sleep(1000); - Assert.assertFalse(restClient.getEdgeRuleChains(edge.getId(), new TimePageLink(2)).getData().contains(savedRuleChain)); - ruleChains = edgeImitator.getStorage().getEntitiesByType(EdgeEventType.RULE_CHAIN); - Assert.assertEquals(1, ruleChains.size()); - Assert.assertFalse(ruleChains.contains(savedRuleChain.getUuidId())); - - restClient.deleteRuleChain(savedRuleChain.getId()); - - } - - @Test - public void testDashboards() throws Exception { - Edge edge = restClient.getTenantEdge("Edge1").get(); - - Dashboard dashboard = new Dashboard(); - dashboard.setTitle("Edge Test Dashboard"); - Dashboard savedDashboard = restClient.saveDashboard(dashboard); - restClient.assignDashboardToEdge(edge.getId(), savedDashboard.getId()); - - Thread.sleep(1000); - Assert.assertTrue(restClient.getEdgeDashboards(edge.getId(), new TimePageLink(2)).getData().stream().allMatch(dashboardInfo -> dashboardInfo.getUuidId().equals(savedDashboard.getUuidId()))); - Set dashboards = edgeImitator.getStorage().getEntitiesByType(EdgeEventType.DASHBOARD); - Assert.assertEquals(1, dashboards.size()); - Assert.assertTrue(dashboards.contains(savedDashboard.getUuidId())); - - restClient.unassignDashboardFromEdge(edge.getId(), savedDashboard.getId()); - Thread.sleep(1000); - Assert.assertFalse(restClient.getEdgeDashboards(edge.getId(), new TimePageLink(2)).getData().stream().anyMatch(dashboardInfo -> dashboardInfo.getUuidId().equals(savedDashboard.getUuidId()))); - dashboards = edgeImitator.getStorage().getEntitiesByType(EdgeEventType.DASHBOARD); - Assert.assertEquals(0, dashboards.size()); - Assert.assertFalse(dashboards.contains(savedDashboard.getUuidId())); - - restClient.deleteDashboard(savedDashboard.getId()); - - } - - @Test - public void testRelations() throws InterruptedException { - Device device = restClient.getTenantDevice("Edge Device 1").get(); - Asset asset = restClient.getTenantAsset("Edge Asset 1").get(); - - EntityRelation relation = new EntityRelation(); - relation.setType("test"); - relation.setFrom(device.getId()); - relation.setTo(asset.getId()); - relation.setTypeGroup(RelationTypeGroup.COMMON); - restClient.saveRelation(relation); - - Thread.sleep(1000); - List relations = edgeImitator.getStorage().getRelations(); - Assert.assertEquals(1, relations.size()); - Assert.assertTrue(relations.contains(relation)); - restClient.deleteRelation(relation.getFrom(), relation.getType(), relation.getTypeGroup(), relation.getTo()); - - Thread.sleep(1000); - relations = edgeImitator.getStorage().getRelations(); - Assert.assertEquals(0, relations.size()); - Assert.assertFalse(relations.contains(relation)); - } - - @Test - public void testAlarms() throws Exception { - Device device = restClient.getTenantDevice("Edge Device 1").get(); - Alarm alarm = new Alarm(); - alarm.setOriginator(device.getId()); - alarm.setStatus(AlarmStatus.ACTIVE_UNACK); - alarm.setType("alarm"); - alarm.setSeverity(AlarmSeverity.CRITICAL); - - Alarm savedAlarm = restClient.saveAlarm(alarm); - AlarmInfo alarmInfo = restClient.getAlarmInfoById(savedAlarm.getId()).get(); - Thread.sleep(1000); - - Assert.assertEquals(1, edgeImitator.getStorage().getAlarms().size()); - Assert.assertTrue(edgeImitator.getStorage().getAlarms().containsKey(alarmInfo.getType())); - Assert.assertEquals(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()), alarmInfo.getStatus()); - restClient.ackAlarm(savedAlarm.getId()); - - Thread.sleep(1000); - alarmInfo = restClient.getAlarmInfoById(savedAlarm.getId()).get(); - Assert.assertTrue(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()).isAck()); - Assert.assertEquals(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()), alarmInfo.getStatus()); - restClient.clearAlarm(savedAlarm.getId()); - - Thread.sleep(1000); - alarmInfo = restClient.getAlarmInfoById(savedAlarm.getId()).get(); - Assert.assertTrue(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()).isAck()); - Assert.assertTrue(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()).isCleared()); - Assert.assertEquals(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()), alarmInfo.getStatus()); - - restClient.deleteAlarm(savedAlarm.getId()); - - } - - @Ignore - @Test - public void testTelemetry() throws Exception { - Device device = restClient.getTenantDevice("Edge Device 1").get(); - DeviceCredentials deviceCredentials = restClient.getDeviceCredentialsByDeviceId(device.getId()).get(); - ResponseEntity response = restClient.getRestTemplate() - .postForEntity(HTTPS_URL + "/api/v1/{credentialsId}/telemetry", - "{'test': 25}", - ResponseEntity.class, - deviceCredentials.getCredentialsId()); - Assert.assertEquals(response.getStatusCode(), HttpStatus.OK); - Thread.sleep(1000); - List keys = restClient.getTimeseriesKeys(device.getId()); - List latestTimeseries = restClient.getLatestTimeseries(device.getId(), keys); - Assert.assertEquals(1, latestTimeseries.size()); - TsKvEntry tsKvEntry = latestTimeseries.get(0); - Map telemetry = edgeImitator.getStorage().getLatestTelemetry(); - Assert.assertEquals(1, telemetry.size()); - Assert.assertTrue(telemetry.containsKey(device.getUuidId())); - TransportProtos.PostTelemetryMsg telemetryMsg = telemetry.get(device.getUuidId()); - Assert.assertEquals(1, telemetryMsg.getTsKvListCount()); - TransportProtos.TsKvListProto tsKv = telemetryMsg.getTsKvListList().get(0); - Assert.assertEquals(tsKvEntry.getTs(), tsKv.getTs()); - Assert.assertEquals(1, tsKv.getKvCount()); - TransportProtos.KeyValueProto keyValue = tsKv.getKvList().get(0); - Assert.assertEquals(tsKvEntry.getKey(), keyValue.getKey()); - Assert.assertEquals(tsKvEntry.getValueAsString(), Long.toString(keyValue.getLongV())); - } - - @AfterClass - public static void destroy() throws InterruptedException { - uninstallation(); - edgeImitator.disconnect(); - } - - private static void installation() throws IOException { - Edge edge = new Edge(); - edge.setName("Edge1"); - edge.setType("test"); - edge.setRoutingKey("routing"); - edge.setSecret("secret"); - Edge savedEdge = restClient.saveEdge(edge); - - Device device = new Device(); - device.setName("Edge Device 1"); - device.setType("test"); - Device savedDevice = restClient.saveDevice(device); - restClient.assignDeviceToEdge(savedEdge.getId(), savedDevice.getId()); - - Asset asset = new Asset(); - asset.setName("Edge Asset 1"); - asset.setType("test"); - Asset savedAsset = restClient.saveAsset(asset); - restClient.assignAssetToEdge(savedEdge.getId(), savedAsset.getId()); - - ObjectMapper mapper = new ObjectMapper(); - Class edgeTestClass = EdgeTest.class; - JsonNode configuration = mapper.readTree(edgeTestClass.getClassLoader().getResourceAsStream("RootRuleChain.json")); - RuleChain ruleChain = mapper.treeToValue(configuration.get("ruleChain"), RuleChain.class); - RuleChainMetaData ruleChainMetaData = mapper.treeToValue(configuration.get("metadata"), RuleChainMetaData.class); - RuleChain savedRuleChain = restClient.saveRuleChain(ruleChain); - ruleChainMetaData.setRuleChainId(savedRuleChain.getId()); - restClient.saveRuleChainMetaData(ruleChainMetaData); - restClient.setRootRuleChain(savedRuleChain.getId()); - } - - private static void uninstallation() { - Device device = restClient.getTenantDevice("Edge Device 1").get(); - restClient.deleteDevice(device.getId()); - - Asset asset = restClient.getTenantAsset("Edge Asset 1").get(); - restClient.deleteAsset(asset.getId()); - - Edge edge = restClient.getTenantEdge("Edge1").get(); - restClient.deleteEdge(edge.getId()); - - List ruleChains = restClient.getRuleChains(new TextPageLink(3)).getData(); - RuleChain oldRoot = ruleChains.stream().filter(ruleChain -> ruleChain.getName().equals("Root Rule Chain")).findAny().get(); - RuleChain newRoot = ruleChains.stream().filter(ruleChain -> ruleChain.getName().equals("Test Root Rule Chain")).findAny().get(); - restClient.setRootRuleChain(oldRoot.getId()); - restClient.deleteRuleChain(newRoot.getId()); - } - -} diff --git a/msa/black-box-tests/src/test/resources/RootRuleChain.json b/msa/black-box-tests/src/test/resources/RootRuleChain.json deleted file mode 100644 index 56324e72f5..0000000000 --- a/msa/black-box-tests/src/test/resources/RootRuleChain.json +++ /dev/null @@ -1,133 +0,0 @@ -{ - "ruleChain": { - "additionalInfo": null, - "name": "Test Root Rule Chain", - "type": "CORE", - "firstRuleNodeId": null, - "root": false, - "debugMode": false, - "configuration": null - }, - "metadata": { - "firstNodeIndex": 4, - "nodes": [ - { - "additionalInfo": { - "layoutX": 1117, - "layoutY": 156 - }, - "type": "org.thingsboard.rule.engine.edge.TbMsgPushToEdgeNode", - "name": "Push to edge", - "debugMode": false, - "configuration": { - "version": 0 - } - }, - { - "additionalInfo": { - "layoutX": 825, - "layoutY": 407 - }, - "type": "org.thingsboard.rule.engine.rpc.TbSendRPCRequestNode", - "name": "RPC Call Request", - "debugMode": false, - "configuration": { - "timeoutInSeconds": 60 - } - }, - { - "additionalInfo": { - "layoutX": 826, - "layoutY": 327 - }, - "type": "org.thingsboard.rule.engine.action.TbLogNode", - "name": "Log Other", - "debugMode": false, - "configuration": { - "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);" - } - }, - { - "additionalInfo": { - "layoutX": 827, - "layoutY": 244 - }, - "type": "org.thingsboard.rule.engine.action.TbLogNode", - "name": "Log RPC from Device", - "debugMode": false, - "configuration": { - "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);" - } - }, - { - "additionalInfo": { - "layoutX": 347, - "layoutY": 149 - }, - "type": "org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode", - "name": "Message Type Switch", - "debugMode": false, - "configuration": { - "version": 0 - } - }, - { - "additionalInfo": { - "layoutX": 821, - "layoutY": 72 - }, - "type": "org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode", - "name": "Save Client Attributes", - "debugMode": false, - "configuration": { - "scope": "CLIENT_SCOPE" - } - }, - { - "additionalInfo": { - "layoutX": 824, - "layoutY": 156 - }, - "type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode", - "name": "Save Timeseries", - "debugMode": false, - "configuration": { - "defaultTTL": 0 - } - } - ], - "connections": [ - { - "fromIndex": 4, - "toIndex": 1, - "type": "RPC Request to Device" - }, - { - "fromIndex": 4, - "toIndex": 3, - "type": "RPC Request from Device" - }, - { - "fromIndex": 4, - "toIndex": 6, - "type": "Post telemetry" - }, - { - "fromIndex": 4, - "toIndex": 5, - "type": "Post attributes" - }, - { - "fromIndex": 4, - "toIndex": 2, - "type": "Other" - }, - { - "fromIndex": 6, - "toIndex": 0, - "type": "Success" - } - ], - "ruleChainConnections": null - } -} \ No newline at end of file From afacaf25471f144f31575b46b737a04f718b3ce7 Mon Sep 17 00:00:00 2001 From: Bohdan Smetaniuk Date: Thu, 24 Sep 2020 15:25:38 +0300 Subject: [PATCH 3/9] switched EDGES_RPC_ENABLED to false --- application/src/main/resources/thingsboard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index db83fd700a..bcf3425f53 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -588,7 +588,7 @@ transport: # Edges parameters edges: rpc: - enabled: "${EDGES_RPC_ENABLED:true}" + enabled: "${EDGES_RPC_ENABLED:false}" port: "${EDGES_RPC_PORT:7070}" ssl: # Enable/disable SSL support From 8eda901fee34f0dc834e1e641db3ae5b2278f22c Mon Sep 17 00:00:00 2001 From: Bohdan Smetaniuk Date: Thu, 24 Sep 2020 19:03:02 +0300 Subject: [PATCH 4/9] added countDownLatch for saving time --- .../thingsboard/server/edge/BaseEdgeTest.java | 125 +++++++++--------- .../server/edge/imitator/EdgeImitator.java | 1 + .../server/edge/imitator/EdgeStorage.java | 22 ++- 3 files changed, 85 insertions(+), 63 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java index 3f5f9ee0e4..303307af25 100644 --- a/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java @@ -45,12 +45,11 @@ import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.controller.AbstractControllerTest; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.edge.imitator.EdgeImitator; -import org.thingsboard.server.gen.edge.EdgeConfiguration; +import org.thingsboard.server.gen.edge.*; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; +import java.util.*; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -91,7 +90,6 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { edgeImitator = new EdgeImitator("localhost", 7070, edge.getRoutingKey(), edge.getSecret()); edgeImitator.connect(); - Thread.sleep(5000); } @After @@ -108,7 +106,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { @Test public void test() throws Exception { - testReceivedData(); + testReceivedInitialData(); testDevices(); testAssets(); testRuleChains(); @@ -117,8 +115,10 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { testAlarms(); } - private void testReceivedData() throws Exception { + private void testReceivedInitialData() throws Exception { log.info("Checking received data"); + waitForMessages(6); // should be 3, but 3 events from sync service + 3 from controller. will be fixed in next releases + EdgeConfiguration configuration = edgeImitator.getStorage().getConfiguration(); Assert.assertNotNull(configuration); @@ -163,7 +163,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { TimePageData pageDataDevices = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/devices?", new TypeReference>() {}, new TextPageLink(100)); Assert.assertTrue(pageDataDevices.getData().contains(savedDevice)); - Thread.sleep(1000); + waitForMessages(1); Set devices = edgeImitator.getStorage().getEntitiesByType(EntityType.DEVICE); Assert.assertEquals(2, devices.size()); Assert.assertTrue(devices.contains(savedDevice.getUuidId())); @@ -173,7 +173,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { pageDataDevices = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/devices?", new TypeReference>() {}, new TextPageLink(100)); Assert.assertFalse(pageDataDevices.getData().contains(savedDevice)); - Thread.sleep(1000); + waitForMessages(1); devices = edgeImitator.getStorage().getEntitiesByType(EntityType.DEVICE); Assert.assertEquals(1, devices.size()); Assert.assertFalse(devices.contains(savedDevice.getUuidId())); @@ -195,7 +195,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { TimePageData pageDataAssets = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/assets?", new TypeReference>() {}, new TextPageLink(100)); Assert.assertTrue(pageDataAssets.getData().contains(savedAsset)); - Thread.sleep(1000); + waitForMessages(1); Set assets = edgeImitator.getStorage().getEntitiesByType(EntityType.ASSET); Assert.assertEquals(2, assets.size()); Assert.assertTrue(assets.contains(savedAsset.getUuidId())); @@ -205,7 +205,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { pageDataAssets = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/assets?", new TypeReference>() {}, new TextPageLink(100)); Assert.assertFalse(pageDataAssets.getData().contains(savedAsset)); - Thread.sleep(1000); + waitForMessages(1); assets = edgeImitator.getStorage().getEntitiesByType(EntityType.ASSET); Assert.assertEquals(1, assets.size()); Assert.assertFalse(assets.contains(savedAsset.getUuidId())); @@ -227,7 +227,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { TimePageData pageDataRuleChain = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/ruleChains?", new TypeReference>() {}, new TextPageLink(100)); Assert.assertTrue(pageDataRuleChain.getData().contains(savedRuleChain)); - Thread.sleep(1000); + waitForMessages(1); Set ruleChains = edgeImitator.getStorage().getEntitiesByType(EntityType.RULE_CHAIN); Assert.assertEquals(2, ruleChains.size()); Assert.assertTrue(ruleChains.contains(savedRuleChain.getUuidId())); @@ -237,7 +237,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { pageDataRuleChain = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/ruleChains?", new TypeReference>() {}, new TextPageLink(100)); Assert.assertFalse(pageDataRuleChain.getData().contains(savedRuleChain)); - Thread.sleep(1000); + waitForMessages(1); ruleChains = edgeImitator.getStorage().getEntitiesByType(EntityType.RULE_CHAIN); Assert.assertEquals(1, ruleChains.size()); Assert.assertFalse(ruleChains.contains(savedRuleChain.getUuidId())); @@ -259,7 +259,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { TimePageData pageDataDashboard = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/dashboards?", new TypeReference>() {}, new TextPageLink(100)); Assert.assertTrue(pageDataDashboard.getData().stream().allMatch(dashboardInfo -> dashboardInfo.getUuidId().equals(savedDashboard.getUuidId()))); - Thread.sleep(1000); + waitForMessages(1); Set dashboards = edgeImitator.getStorage().getEntitiesByType(EntityType.DASHBOARD); Assert.assertEquals(1, dashboards.size()); Assert.assertTrue(dashboards.contains(savedDashboard.getUuidId())); @@ -269,7 +269,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { pageDataDashboard = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/dashboards?", new TypeReference>() {}, new TextPageLink(100)); Assert.assertFalse(pageDataDashboard.getData().stream().anyMatch(dashboardInfo -> dashboardInfo.getUuidId().equals(savedDashboard.getUuidId()))); - Thread.sleep(1000); + waitForMessages(1); dashboards = edgeImitator.getStorage().getEntitiesByType(EntityType.DASHBOARD); Assert.assertEquals(0, dashboards.size()); Assert.assertFalse(dashboards.contains(savedDashboard.getUuidId())); @@ -280,44 +280,6 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { } - private void installation() throws Exception { - edge = doPost("/api/edge", constructEdge("Test Edge", "test"), Edge.class); - - Device device = new Device(); - device.setName("Edge Device 1"); - device.setType("test"); - Device savedDevice = doPost("/api/device", device, Device.class); - doPost("/api/edge/" + edge.getId().getId().toString() - + "/device/" + savedDevice.getId().getId().toString(), Device.class); - - Asset asset = new Asset(); - asset.setName("Edge Asset 1"); - asset.setType("test"); - Asset savedAsset = doPost("/api/asset", asset, Asset.class); - doPost("/api/edge/" + edge.getId().getId().toString() - + "/asset/" + savedAsset.getId().getId().toString(), Asset.class); - } - - private void uninstallation() throws Exception { - - TimePageData pageDataDevices = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/devices?", - new TypeReference>() {}, new TextPageLink(100)); - for (Device device: pageDataDevices.getData()) { - doDelete("/api/device/" + device.getId().getId().toString()) - .andExpect(status().isOk()); - } - - TimePageData pageDataAssets = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/assets?", - new TypeReference>() {}, new TextPageLink(100)); - for (Asset asset: pageDataAssets.getData()) { - doDelete("/api/asset/" + asset.getId().getId().toString()) - .andExpect(status().isOk()); - } - - doDelete("/api/edge/" + edge.getId().getId().toString()) - .andExpect(status().isOk()); - } - private void testRelations() throws Exception { log.info("Testing Relations"); List edgeDevices = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/devices?", @@ -339,7 +301,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { relation.setTypeGroup(RelationTypeGroup.COMMON); doPost("/api/relation", relation); - Thread.sleep(1000); + waitForMessages(1); List relations = edgeImitator.getStorage().getRelations(); Assert.assertEquals(1, relations.size()); Assert.assertTrue(relations.contains(relation)); @@ -352,7 +314,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { "&toType=" + relation.getTo().getEntityType().name()) .andExpect(status().isOk()); - Thread.sleep(1000); + waitForMessages(1); relations = edgeImitator.getStorage().getRelations(); Assert.assertEquals(0, relations.size()); Assert.assertFalse(relations.contains(relation)); @@ -376,20 +338,20 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { Alarm savedAlarm = doPost("/api/alarm", alarm, Alarm.class); AlarmInfo alarmInfo = doGet("/api/alarm/info/" + savedAlarm.getId().getId().toString(), AlarmInfo.class); - Thread.sleep(1000); + waitForMessages(1); Assert.assertEquals(1, edgeImitator.getStorage().getAlarms().size()); Assert.assertTrue(edgeImitator.getStorage().getAlarms().containsKey(alarmInfo.getType())); Assert.assertEquals(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()), alarmInfo.getStatus()); doPost("/api/alarm/" + savedAlarm.getId().getId().toString() + "/ack"); - Thread.sleep(1000); + waitForMessages(1); alarmInfo = doGet("/api/alarm/info/" + savedAlarm.getId().getId().toString(), AlarmInfo.class); Assert.assertTrue(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()).isAck()); Assert.assertEquals(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()), alarmInfo.getStatus()); doPost("/api/alarm/" + savedAlarm.getId().getId().toString() + "/clear"); - Thread.sleep(1000); + waitForMessages(1); alarmInfo = doGet("/api/alarm/info/" + savedAlarm.getId().getId().toString(), AlarmInfo.class); Assert.assertTrue(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()).isAck()); Assert.assertTrue(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()).isCleared()); @@ -400,4 +362,49 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { log.info("Alarms tested successfully"); } + private void installation() throws Exception { + edge = doPost("/api/edge", constructEdge("Test Edge", "test"), Edge.class); + + Device device = new Device(); + device.setName("Edge Device 1"); + device.setType("test"); + Device savedDevice = doPost("/api/device", device, Device.class); + doPost("/api/edge/" + edge.getId().getId().toString() + + "/device/" + savedDevice.getId().getId().toString(), Device.class); + + Asset asset = new Asset(); + asset.setName("Edge Asset 1"); + asset.setType("test"); + Asset savedAsset = doPost("/api/asset", asset, Asset.class); + doPost("/api/edge/" + edge.getId().getId().toString() + + "/asset/" + savedAsset.getId().getId().toString(), Asset.class); + } + + private void uninstallation() throws Exception { + + TimePageData pageDataDevices = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/devices?", + new TypeReference>() {}, new TextPageLink(100)); + for (Device device: pageDataDevices.getData()) { + doDelete("/api/device/" + device.getId().getId().toString()) + .andExpect(status().isOk()); + } + + TimePageData pageDataAssets = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/assets?", + new TypeReference>() {}, new TextPageLink(100)); + for (Asset asset: pageDataAssets.getData()) { + doDelete("/api/asset/" + asset.getId().getId().toString()) + .andExpect(status().isOk()); + } + + doDelete("/api/edge/" + edge.getId().getId().toString()) + .andExpect(status().isOk()); + } + + private void waitForMessages(int messageAmount) throws InterruptedException { + edgeImitator.getStorage().setLatch(new CountDownLatch(messageAmount)); + while (!edgeImitator.getStorage().getLatch().await(1, TimeUnit.SECONDS)) { + log.warn("Waiting for messages.."); + } + } + } diff --git a/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java b/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java index 9f6d51a601..e91e57e9a6 100644 --- a/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java +++ b/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java @@ -111,6 +111,7 @@ public class EdgeImitator { } private ListenableFuture> processDownlinkMsg(DownlinkMsg downlinkMsg) { + log.info(String.valueOf(downlinkMsg)); List> result = new ArrayList<>(); if (downlinkMsg.getDeviceUpdateMsgList() != null && !downlinkMsg.getDeviceUpdateMsgList().isEmpty()) { for (DeviceUpdateMsg deviceUpdateMsg: downlinkMsg.getDeviceUpdateMsgList()) { diff --git a/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeStorage.java b/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeStorage.java index a52d1e7f6e..7320b93054 100644 --- a/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeStorage.java +++ b/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeStorage.java @@ -36,6 +36,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.concurrent.CountDownLatch; import java.util.stream.Collectors; @Slf4j @@ -45,11 +46,14 @@ public class EdgeStorage { private EdgeConfiguration configuration; + private CountDownLatch latch; + private Map entities; private Map alarms; private List relations; public EdgeStorage() { + latch = new CountDownLatch(0); entities = new HashMap<>(); alarms = new HashMap<>(); relations = new ArrayList<>(); @@ -60,15 +64,19 @@ public class EdgeStorage { case ENTITY_CREATED_RPC_MESSAGE: case ENTITY_UPDATED_RPC_MESSAGE: entities.put(uuid, type); + latch.countDown(); break; case ENTITY_DELETED_RPC_MESSAGE: - entities.remove(uuid); + if (entities.remove(uuid) != null) { + latch.countDown(); + } break; } return Futures.immediateFuture(null); } public ListenableFuture processRelation(RelationUpdateMsg relationMsg) { + boolean result = false; EntityRelation relation = new EntityRelation(); relation.setType(relationMsg.getType()); relation.setTypeGroup(RelationTypeGroup.valueOf(relationMsg.getTypeGroup())); @@ -77,12 +85,15 @@ public class EdgeStorage { switch (relationMsg.getMsgType()) { case ENTITY_CREATED_RPC_MESSAGE: case ENTITY_UPDATED_RPC_MESSAGE: - relations.add(relation); + result = relations.add(relation); break; case ENTITY_DELETED_RPC_MESSAGE: - relations.remove(relation); + result = relations.remove(relation); break; } + if (result) { + latch.countDown(); + } return Futures.immediateFuture(null); } @@ -93,9 +104,12 @@ public class EdgeStorage { case ALARM_ACK_RPC_MESSAGE: case ALARM_CLEAR_RPC_MESSAGE: alarms.put(alarmMsg.getType(), AlarmStatus.valueOf(alarmMsg.getStatus())); + latch.countDown(); break; case ENTITY_DELETED_RPC_MESSAGE: - alarms.remove(alarmMsg.getName()); + if (alarms.remove(alarmMsg.getName()) != null) { + latch.countDown(); + } break; } return Futures.immediateFuture(null); From 199c175396085bfcd851459ef5631af84d627a40 Mon Sep 17 00:00:00 2001 From: Bohdan Smetaniuk Date: Thu, 24 Sep 2020 19:06:28 +0300 Subject: [PATCH 5/9] deleted logs and wildcard imports --- .../java/org/thingsboard/server/edge/BaseEdgeTest.java | 7 +++++-- .../org/thingsboard/server/edge/imitator/EdgeImitator.java | 1 - 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java index 303307af25..25ad8d7e94 100644 --- a/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java @@ -45,9 +45,12 @@ import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.controller.AbstractControllerTest; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.edge.imitator.EdgeImitator; -import org.thingsboard.server.gen.edge.*; +import org.thingsboard.server.gen.edge.EdgeConfiguration; -import java.util.*; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; diff --git a/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java b/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java index e91e57e9a6..9f6d51a601 100644 --- a/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java +++ b/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java @@ -111,7 +111,6 @@ public class EdgeImitator { } private ListenableFuture> processDownlinkMsg(DownlinkMsg downlinkMsg) { - log.info(String.valueOf(downlinkMsg)); List> result = new ArrayList<>(); if (downlinkMsg.getDeviceUpdateMsgList() != null && !downlinkMsg.getDeviceUpdateMsgList().isEmpty()) { for (DeviceUpdateMsg deviceUpdateMsg: downlinkMsg.getDeviceUpdateMsgList()) { From 3f36e15ee6f3064b350b0cc1b52389791adfdc7b Mon Sep 17 00:00:00 2001 From: Bohdan Smetaniuk Date: Thu, 24 Sep 2020 19:49:31 +0300 Subject: [PATCH 6/9] last methods --- .../thingsboard/rest/client/RestClient.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java index ab04b16b66..4e2f12e8c2 100644 --- a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java +++ b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java @@ -2251,6 +2251,53 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable { }, params).getBody(); } + public Optional addDefaultEdgeRuleChain(RuleChainId ruleChainId) { + try { + ResponseEntity ruleChain = restTemplate.postForEntity(baseURL + "/api/ruleChain/{ruleChainId}/defaultEdge", null, RuleChain.class, ruleChainId.getId()); + return Optional.ofNullable(ruleChain.getBody()); + } catch (HttpClientErrorException exception) { + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) { + return Optional.empty(); + } else { + throw exception; + } + } + } + + public Optional removeDefaultEdgeRuleChain(RuleChainId ruleChainId) { + try { + ResponseEntity ruleChain = restTemplate.exchange(baseURL + "/api/ruleChain/{ruleChainId}/defaultEdge", HttpMethod.DELETE, HttpEntity.EMPTY, RuleChain.class, ruleChainId.getId()); + return Optional.ofNullable(ruleChain.getBody()); + } catch (HttpClientErrorException exception) { + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) { + return Optional.empty(); + } else { + throw exception; + } + } + } + + public List getDefaultEdgeRuleChains() { + return restTemplate.exchange(baseURL + "/ruleChain/defaultEdgeRuleChains", + HttpMethod.GET, + HttpEntity.EMPTY, + new ParameterizedTypeReference>() { + }).getBody(); + } + + public Optional setDefaultRootEdgeRuleChain(RuleChainId ruleChainId) { + try { + ResponseEntity ruleChain = restTemplate.postForEntity(baseURL + "/api/ruleChain/{ruleChainId}/defaultRootEdge", null, RuleChain.class, ruleChainId.getId()); + return Optional.ofNullable(ruleChain.getBody()); + } catch (HttpClientErrorException exception) { + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) { + return Optional.empty(); + } else { + throw exception; + } + } + } + public TextPageData getTenantEdges(String type, TextPageLink pageLink) { Map params = new HashMap<>(); params.put("type", type); From fd32ba176175cb4e12b2a13911b4bd57a8a51b95 Mon Sep 17 00:00:00 2001 From: Bohdan Smetaniuk Date: Fri, 25 Sep 2020 12:04:38 +0300 Subject: [PATCH 7/9] concurrency fixes --- .../thingsboard/server/edge/BaseEdgeTest.java | 55 ++++++++++--------- .../server/edge/imitator/EdgeStorage.java | 9 +++ 2 files changed, 38 insertions(+), 26 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java index 25ad8d7e94..be26e64f1a 100644 --- a/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java @@ -67,9 +67,6 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { private EdgeImitator edgeImitator; private Edge edge; - @Autowired - RuleChainService ruleChainService; - @Before public void beforeTest() throws Exception { loginSysAdmin(); @@ -88,10 +85,11 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { tenantAdmin.setLastName("Downs"); tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); - installation(); edgeImitator = new EdgeImitator("localhost", 7070, edge.getRoutingKey(), edge.getSecret()); + // should be 3, but 3 events from sync service + 3 from controller. will be fixed in next releases + edgeImitator.getStorage().expectMessageAmount(6); edgeImitator.connect(); } @@ -120,7 +118,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { private void testReceivedInitialData() throws Exception { log.info("Checking received data"); - waitForMessages(6); // should be 3, but 3 events from sync service + 3 from controller. will be fixed in next releases + edgeImitator.getStorage().waitForMessages(); EdgeConfiguration configuration = edgeImitator.getStorage().getConfiguration(); Assert.assertNotNull(configuration); @@ -160,23 +158,25 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { device.setName("Edge Device 2"); device.setType("test"); Device savedDevice = doPost("/api/device", device, Device.class); + edgeImitator.getStorage().expectMessageAmount(1); doPost("/api/edge/" + edge.getId().getId().toString() + "/device/" + savedDevice.getId().getId().toString(), Device.class); TimePageData pageDataDevices = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/devices?", new TypeReference>() {}, new TextPageLink(100)); Assert.assertTrue(pageDataDevices.getData().contains(savedDevice)); - waitForMessages(1); + edgeImitator.getStorage().waitForMessages(); Set devices = edgeImitator.getStorage().getEntitiesByType(EntityType.DEVICE); Assert.assertEquals(2, devices.size()); Assert.assertTrue(devices.contains(savedDevice.getUuidId())); + edgeImitator.getStorage().expectMessageAmount(1); doDelete("/api/edge/" + edge.getId().getId().toString() + "/device/" + savedDevice.getId().getId().toString(), Device.class); pageDataDevices = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/devices?", new TypeReference>() {}, new TextPageLink(100)); Assert.assertFalse(pageDataDevices.getData().contains(savedDevice)); - waitForMessages(1); + edgeImitator.getStorage().waitForMessages(); devices = edgeImitator.getStorage().getEntitiesByType(EntityType.DEVICE); Assert.assertEquals(1, devices.size()); Assert.assertFalse(devices.contains(savedDevice.getUuidId())); @@ -192,23 +192,25 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { asset.setName("Edge Asset 2"); asset.setType("test"); Asset savedAsset = doPost("/api/asset", asset, Asset.class); + edgeImitator.getStorage().expectMessageAmount(1); doPost("/api/edge/" + edge.getId().getId().toString() + "/asset/" + savedAsset.getId().getId().toString(), Asset.class); TimePageData pageDataAssets = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/assets?", new TypeReference>() {}, new TextPageLink(100)); Assert.assertTrue(pageDataAssets.getData().contains(savedAsset)); - waitForMessages(1); + edgeImitator.getStorage().waitForMessages(); Set assets = edgeImitator.getStorage().getEntitiesByType(EntityType.ASSET); Assert.assertEquals(2, assets.size()); Assert.assertTrue(assets.contains(savedAsset.getUuidId())); + edgeImitator.getStorage().expectMessageAmount(1); doDelete("/api/edge/" + edge.getId().getId().toString() + "/asset/" + savedAsset.getId().getId().toString(), Asset.class); pageDataAssets = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/assets?", new TypeReference>() {}, new TextPageLink(100)); Assert.assertFalse(pageDataAssets.getData().contains(savedAsset)); - waitForMessages(1); + edgeImitator.getStorage().waitForMessages(); assets = edgeImitator.getStorage().getEntitiesByType(EntityType.ASSET); Assert.assertEquals(1, assets.size()); Assert.assertFalse(assets.contains(savedAsset.getUuidId())); @@ -224,23 +226,25 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { ruleChain.setName("Edge Test Rule Chain"); ruleChain.setType(RuleChainType.EDGE); RuleChain savedRuleChain = doPost("/api/ruleChain", ruleChain, RuleChain.class); + edgeImitator.getStorage().expectMessageAmount(1); doPost("/api/edge/" + edge.getId().getId().toString() + "/ruleChain/" + savedRuleChain.getId().getId().toString(), RuleChain.class); TimePageData pageDataRuleChain = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/ruleChains?", new TypeReference>() {}, new TextPageLink(100)); Assert.assertTrue(pageDataRuleChain.getData().contains(savedRuleChain)); - waitForMessages(1); + edgeImitator.getStorage().waitForMessages(); Set ruleChains = edgeImitator.getStorage().getEntitiesByType(EntityType.RULE_CHAIN); Assert.assertEquals(2, ruleChains.size()); Assert.assertTrue(ruleChains.contains(savedRuleChain.getUuidId())); + edgeImitator.getStorage().expectMessageAmount(1); doDelete("/api/edge/" + edge.getId().getId().toString() + "/ruleChain/" + savedRuleChain.getId().getId().toString(), RuleChain.class); pageDataRuleChain = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/ruleChains?", new TypeReference>() {}, new TextPageLink(100)); Assert.assertFalse(pageDataRuleChain.getData().contains(savedRuleChain)); - waitForMessages(1); + edgeImitator.getStorage().waitForMessages(); ruleChains = edgeImitator.getStorage().getEntitiesByType(EntityType.RULE_CHAIN); Assert.assertEquals(1, ruleChains.size()); Assert.assertFalse(ruleChains.contains(savedRuleChain.getUuidId())); @@ -256,23 +260,25 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { Dashboard dashboard = new Dashboard(); dashboard.setTitle("Edge Test Dashboard"); Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class); + edgeImitator.getStorage().expectMessageAmount(1); doPost("/api/edge/" + edge.getId().getId().toString() + "/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class); TimePageData pageDataDashboard = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/dashboards?", new TypeReference>() {}, new TextPageLink(100)); Assert.assertTrue(pageDataDashboard.getData().stream().allMatch(dashboardInfo -> dashboardInfo.getUuidId().equals(savedDashboard.getUuidId()))); - waitForMessages(1); + edgeImitator.getStorage().waitForMessages(); Set dashboards = edgeImitator.getStorage().getEntitiesByType(EntityType.DASHBOARD); Assert.assertEquals(1, dashboards.size()); Assert.assertTrue(dashboards.contains(savedDashboard.getUuidId())); + edgeImitator.getStorage().expectMessageAmount(1); doDelete("/api/edge/" + edge.getId().getId().toString() + "/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class); pageDataDashboard = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/dashboards?", new TypeReference>() {}, new TextPageLink(100)); Assert.assertFalse(pageDataDashboard.getData().stream().anyMatch(dashboardInfo -> dashboardInfo.getUuidId().equals(savedDashboard.getUuidId()))); - waitForMessages(1); + edgeImitator.getStorage().waitForMessages(); dashboards = edgeImitator.getStorage().getEntitiesByType(EntityType.DASHBOARD); Assert.assertEquals(0, dashboards.size()); Assert.assertFalse(dashboards.contains(savedDashboard.getUuidId())); @@ -302,12 +308,14 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { relation.setFrom(device.getId()); relation.setTo(asset.getId()); relation.setTypeGroup(RelationTypeGroup.COMMON); + edgeImitator.getStorage().expectMessageAmount(1); doPost("/api/relation", relation); - waitForMessages(1); + edgeImitator.getStorage().waitForMessages(); List relations = edgeImitator.getStorage().getRelations(); Assert.assertEquals(1, relations.size()); Assert.assertTrue(relations.contains(relation)); + edgeImitator.getStorage().expectMessageAmount(1); doDelete("/api/relation?" + "fromId=" + relation.getFrom().getId().toString() + "&fromType=" + relation.getFrom().getEntityType().name() + @@ -317,7 +325,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { "&toType=" + relation.getTo().getEntityType().name()) .andExpect(status().isOk()); - waitForMessages(1); + edgeImitator.getStorage().waitForMessages(); relations = edgeImitator.getStorage().getRelations(); Assert.assertEquals(0, relations.size()); Assert.assertFalse(relations.contains(relation)); @@ -339,22 +347,25 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { alarm.setType("alarm"); alarm.setSeverity(AlarmSeverity.CRITICAL); + edgeImitator.getStorage().expectMessageAmount(1); Alarm savedAlarm = doPost("/api/alarm", alarm, Alarm.class); AlarmInfo alarmInfo = doGet("/api/alarm/info/" + savedAlarm.getId().getId().toString(), AlarmInfo.class); - waitForMessages(1); + edgeImitator.getStorage().waitForMessages(); Assert.assertEquals(1, edgeImitator.getStorage().getAlarms().size()); Assert.assertTrue(edgeImitator.getStorage().getAlarms().containsKey(alarmInfo.getType())); Assert.assertEquals(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()), alarmInfo.getStatus()); + edgeImitator.getStorage().expectMessageAmount(1); doPost("/api/alarm/" + savedAlarm.getId().getId().toString() + "/ack"); - waitForMessages(1); + edgeImitator.getStorage().waitForMessages(); alarmInfo = doGet("/api/alarm/info/" + savedAlarm.getId().getId().toString(), AlarmInfo.class); Assert.assertTrue(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()).isAck()); Assert.assertEquals(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()), alarmInfo.getStatus()); + edgeImitator.getStorage().expectMessageAmount(1); doPost("/api/alarm/" + savedAlarm.getId().getId().toString() + "/clear"); - waitForMessages(1); + edgeImitator.getStorage().waitForMessages(); alarmInfo = doGet("/api/alarm/info/" + savedAlarm.getId().getId().toString(), AlarmInfo.class); Assert.assertTrue(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()).isAck()); Assert.assertTrue(edgeImitator.getStorage().getAlarms().get(alarmInfo.getType()).isCleared()); @@ -402,12 +413,4 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { doDelete("/api/edge/" + edge.getId().getId().toString()) .andExpect(status().isOk()); } - - private void waitForMessages(int messageAmount) throws InterruptedException { - edgeImitator.getStorage().setLatch(new CountDownLatch(messageAmount)); - while (!edgeImitator.getStorage().getLatch().await(1, TimeUnit.SECONDS)) { - log.warn("Waiting for messages.."); - } - } - } diff --git a/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeStorage.java b/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeStorage.java index 7320b93054..cadd580f58 100644 --- a/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeStorage.java +++ b/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeStorage.java @@ -37,6 +37,7 @@ import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @Slf4j @@ -121,4 +122,12 @@ public class EdgeStorage { .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)).keySet(); } + public void waitForMessages() throws InterruptedException { + latch.await(5, TimeUnit.SECONDS); + } + + public void expectMessageAmount(int messageAmount) { + latch = new CountDownLatch(messageAmount); + } + } From 05a7f3b2de15ff95e8c89718efff3759d3d032c8 Mon Sep 17 00:00:00 2001 From: Bohdan Smetaniuk Date: Fri, 25 Sep 2020 13:12:30 +0300 Subject: [PATCH 8/9] fixed setRootRuleChain for Edges --- .../src/main/java/org/thingsboard/rest/client/RestClient.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java index 4e2f12e8c2..0232bc5216 100644 --- a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java +++ b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java @@ -2029,9 +2029,9 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable { } } - public Optional setRootRuleChain(RuleChainId ruleChainId, EdgeId edgeId) { + public Optional setRootRuleChain(EdgeId edgeId, RuleChainId ruleChainId) { try { - ResponseEntity ruleChain = restTemplate.postForEntity(baseURL + "/api/edge/{edgeId}/{ruleChainId}/root", null, RuleChain.class, edgeId.getId(), ruleChainId.getId()); + ResponseEntity ruleChain = restTemplate.postForEntity(baseURL + "/api/edge/{edgeId}/{ruleChainId}/root", null, Edge.class, edgeId.getId(), ruleChainId.getId()); return Optional.ofNullable(ruleChain.getBody()); } catch (HttpClientErrorException exception) { if (exception.getStatusCode() == HttpStatus.NOT_FOUND) { From c39cfe490a3b2f26be55979341401a563944aca2 Mon Sep 17 00:00:00 2001 From: Bohdan Smetaniuk Date: Fri, 25 Sep 2020 14:19:22 +0300 Subject: [PATCH 9/9] fixed getDefaultEdgeRuleChains method --- .../src/main/java/org/thingsboard/rest/client/RestClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java index 0232bc5216..904e662e12 100644 --- a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java +++ b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java @@ -2278,7 +2278,7 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable { } public List getDefaultEdgeRuleChains() { - return restTemplate.exchange(baseURL + "/ruleChain/defaultEdgeRuleChains", + return restTemplate.exchange(baseURL + "/api/ruleChain/defaultEdgeRuleChains", HttpMethod.GET, HttpEntity.EMPTY, new ParameterizedTypeReference>() {