Browse Source

Merge #6730

pull/6758/head
Andrii Shvaika 4 years ago
parent
commit
8099c19eb7
  1. 20
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DashboardExportService.java
  2. 31
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DefaultEntityExportService.java
  3. 24
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/RuleChainExportService.java
  4. 451
      application/src/test/java/org/thingsboard/server/service/sync/ie/BaseExportImportServiceTest.java
  5. 546
      application/src/test/java/org/thingsboard/server/service/sync/ie/ExportImportServiceSqlTest.java
  6. 11
      common/data/src/main/java/org/thingsboard/server/common/data/Dashboard.java
  7. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/DeviceExportData.java
  8. 1
      common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/EntityExportData.java
  9. 1
      common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/EntityImportSettings.java
  10. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/RuleChainExportData.java

20
application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DashboardExportService.java

@ -15,16 +15,23 @@
*/
package org.thingsboard.server.service.sync.ie.exporting.impl;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.vc.data.EntitiesExportCtx;
import org.thingsboard.server.utils.RegexUtils;
import java.util.ArrayList;
import java.util.Set;
import java.util.UUID;
@Service
@TbCoreComponent
@ -37,6 +44,19 @@ public class DashboardExportService extends BaseEntityExportService<DashboardId,
customerInfo.setCustomerId(getExternalIdOrElseInternal(ctx, customerInfo.getCustomerId()));
});
}
if (dashboard.getEntityAliasesConfig() != null) {
for (JsonNode entityAlias : dashboard.getEntityAliasesConfig()) {
ArrayList<String> fields = Lists.newArrayList(entityAlias.fieldNames());
for (String field : fields) {
if (field.equals("id")) continue;
JsonNode oldFieldValue = entityAlias.get(field);
JsonNode newFieldValue = JacksonUtil.toJsonNode(RegexUtils.replace(oldFieldValue.toString(), RegexUtils.UUID_PATTERN, uuid -> {
return getExternalIdOrElseInternalByUuid(ctx, UUID.fromString(uuid)).toString();
}));
((ObjectNode) entityAlias).set(field, newFieldValue);
}
}
}
}
@Override

31
application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DefaultEntityExportService.java

@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId;
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.common.data.sync.ie.AttributeExportData;
@ -41,6 +42,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
@ -146,6 +148,35 @@ public class DefaultEntityExportService<I extends EntityId, E extends Exportable
return result;
}
protected UUID getExternalIdOrElseInternalByUuid(EntitiesExportCtx<?> ctx, UUID internalUuid) {
for (EntityType entityType : EntityType.values()) {
EntityId internalId;
try {
internalId = EntityIdFactory.getByTypeAndUuid(entityType, internalUuid);
} catch (Exception e) {
continue;
}
EntityId externalId = ctx.getExternalId(internalId);
if (externalId != null) {
return externalId.getId();
}
}
for (EntityType entityType : EntityType.values()) {
EntityId internalId;
try {
internalId = EntityIdFactory.getByTypeAndUuid(entityType, internalUuid);
} catch (Exception e) {
continue;
}
EntityId externalId = exportableEntitiesService.getExternalIdByInternal(internalId);
if (externalId != null) {
ctx.putExternalId(internalId, externalId);
return externalId.getId();
}
}
return internalUuid;
}
protected D newExportData() {
return (D) new EntityExportData<E>();
}

24
application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/RuleChainExportService.java

@ -15,17 +15,24 @@
*/
package org.thingsboard.server.service.sync.ie.exporting.impl;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.sync.ie.RuleChainExportData;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.vc.data.EntitiesExportCtx;
import org.thingsboard.server.utils.RegexUtils;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
@Service
@TbCoreComponent
@ -36,7 +43,22 @@ public class RuleChainExportService extends BaseEntityExportService<RuleChainId,
@Override
protected void setRelatedEntities(EntitiesExportCtx<?> ctx, RuleChain ruleChain, RuleChainExportData exportData) {
exportData.setMetaData(ruleChainService.loadRuleChainMetaData(ctx.getTenantId(), ruleChain.getId()));
RuleChainMetaData metaData = ruleChainService.loadRuleChainMetaData(ctx.getTenantId(), ruleChain.getId());
Optional.ofNullable(metaData.getNodes()).orElse(Collections.emptyList())
.forEach(ruleNode -> {
ruleNode.setRuleChainId(null);
JsonNode ruleNodeConfig = ruleNode.getConfiguration();
String newRuleNodeConfigJson = RegexUtils.replace(ruleNodeConfig.toString(), RegexUtils.UUID_PATTERN, uuid -> {
return getExternalIdOrElseInternalByUuid(ctx, UUID.fromString(uuid)).toString();
});
ruleNodeConfig = JacksonUtil.toJsonNode(newRuleNodeConfigJson);
ruleNode.setConfiguration(ruleNodeConfig);
});
Optional.ofNullable(metaData.getRuleChainConnections()).orElse(Collections.emptyList())
.forEach(ruleChainConnectionInfo -> {
ruleChainConnectionInfo.setTargetRuleChainId(getExternalIdOrElseInternal(ctx, ruleChainConnectionInfo.getTargetRuleChainId()));
});
exportData.setMetaData(metaData);
}
@Override

451
application/src/test/java/org/thingsboard/server/service/sync/ie/BaseExportImportServiceTest.java

@ -0,0 +1,451 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.ie;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import org.junit.After;
import org.junit.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.debug.TbMsgGeneratorNode;
import org.thingsboard.rule.engine.debug.TbMsgGeneratorNodeConfiguration;
import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileType;
import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.device.data.DefaultDeviceTransportConfiguration;
import org.thingsboard.server.common.data.device.data.DeviceData;
import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;
import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
import org.thingsboard.server.common.data.ota.OtaPackageType;
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.rule.RuleNode;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.sync.ThrowingRunnable;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.common.data.sync.ie.EntityExportSettings;
import org.thingsboard.server.common.data.sync.ie.EntityImportResult;
import org.thingsboard.server.common.data.sync.ie.EntityImportSettings;
import org.thingsboard.server.controller.AbstractControllerTest;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.DeviceProfileService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.model.UserPrincipal;
import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx;
import org.thingsboard.server.service.sync.vc.data.SimpleEntitiesExportCtx;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Collections;
import static org.assertj.core.api.Assertions.assertThat;
public abstract class BaseExportImportServiceTest extends AbstractControllerTest {
@Autowired
protected EntitiesExportImportService exportImportService;
@Autowired
protected DeviceService deviceService;
@Autowired
protected OtaPackageService otaPackageService;
@Autowired
protected DeviceProfileService deviceProfileService;
@Autowired
protected AssetService assetService;
@Autowired
protected CustomerService customerService;
@Autowired
protected RuleChainService ruleChainService;
@Autowired
protected DashboardService dashboardService;
@Autowired
protected RelationService relationService;
@Autowired
protected TenantService tenantService;
@Autowired
protected EntityViewService entityViewService;
protected TenantId tenantId1;
protected User tenantAdmin1;
protected TenantId tenantId2;
protected User tenantAdmin2;
@Before
public void beforeEach() throws Exception {
loginSysAdmin();
Tenant tenant1 = new Tenant();
tenant1.setTitle("Tenant 1");
tenant1.setEmail("tenant1@thingsboard.org");
this.tenantId1 = tenantService.saveTenant(tenant1).getId();
User tenantAdmin1 = new User();
tenantAdmin1.setTenantId(tenantId1);
tenantAdmin1.setAuthority(Authority.TENANT_ADMIN);
tenantAdmin1.setEmail("tenant1-admin@thingsboard.org");
this.tenantAdmin1 = createUser(tenantAdmin1, "12345678");
Tenant tenant2 = new Tenant();
tenant2.setTitle("Tenant 2");
tenant2.setEmail("tenant2@thingsboard.org");
this.tenantId2 = tenantService.saveTenant(tenant2).getId();
User tenantAdmin2 = new User();
tenantAdmin2.setTenantId(tenantId2);
tenantAdmin2.setAuthority(Authority.TENANT_ADMIN);
tenantAdmin2.setEmail("tenant2-admin@thingsboard.org");
this.tenantAdmin2 = createUser(tenantAdmin2, "12345678");
}
@After
public void afterEach() {
tenantService.deleteTenant(tenantId1);
tenantService.deleteTenant(tenantId2);
}
protected Device createDevice(TenantId tenantId, CustomerId customerId, DeviceProfileId deviceProfileId, String name) {
Device device = new Device();
device.setTenantId(tenantId);
device.setCustomerId(customerId);
device.setName(name);
device.setLabel("lbl");
device.setDeviceProfileId(deviceProfileId);
DeviceData deviceData = new DeviceData();
deviceData.setTransportConfiguration(new DefaultDeviceTransportConfiguration());
device.setDeviceData(deviceData);
return deviceService.saveDevice(device);
}
protected OtaPackage createOtaPackage(TenantId tenantId, DeviceProfileId deviceProfileId, OtaPackageType type) {
OtaPackage otaPackage = new OtaPackage();
otaPackage.setTenantId(tenantId);
otaPackage.setDeviceProfileId(deviceProfileId);
otaPackage.setType(type);
otaPackage.setTitle("My " + type);
otaPackage.setVersion("v1.0");
otaPackage.setFileName("filename.txt");
otaPackage.setContentType("text/plain");
otaPackage.setChecksumAlgorithm(ChecksumAlgorithm.SHA256);
otaPackage.setChecksum("4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a");
otaPackage.setDataSize(1L);
otaPackage.setData(ByteBuffer.wrap(new byte[]{(int) 1}));
return otaPackageService.saveOtaPackage(otaPackage);
}
protected void checkImportedDeviceData(Device initialDevice, Device importedDevice) {
assertThat(importedDevice.getName()).isEqualTo(initialDevice.getName());
assertThat(importedDevice.getType()).isEqualTo(initialDevice.getType());
assertThat(importedDevice.getDeviceData()).isEqualTo(initialDevice.getDeviceData());
assertThat(importedDevice.getLabel()).isEqualTo(initialDevice.getLabel());
}
protected DeviceProfile createDeviceProfile(TenantId tenantId, RuleChainId defaultRuleChainId, DashboardId defaultDashboardId, String name) {
DeviceProfile deviceProfile = new DeviceProfile();
deviceProfile.setTenantId(tenantId);
deviceProfile.setName(name);
deviceProfile.setDescription("dscrptn");
deviceProfile.setType(DeviceProfileType.DEFAULT);
deviceProfile.setTransportType(DeviceTransportType.DEFAULT);
deviceProfile.setDefaultRuleChainId(defaultRuleChainId);
deviceProfile.setDefaultDashboardId(defaultDashboardId);
DeviceProfileData profileData = new DeviceProfileData();
profileData.setConfiguration(new DefaultDeviceProfileConfiguration());
profileData.setTransportConfiguration(new DefaultDeviceProfileTransportConfiguration());
deviceProfile.setProfileData(profileData);
return deviceProfileService.saveDeviceProfile(deviceProfile);
}
protected void checkImportedDeviceProfileData(DeviceProfile initialProfile, DeviceProfile importedProfile) {
assertThat(initialProfile.getName()).isEqualTo(importedProfile.getName());
assertThat(initialProfile.getType()).isEqualTo(importedProfile.getType());
assertThat(initialProfile.getTransportType()).isEqualTo(importedProfile.getTransportType());
assertThat(initialProfile.getProfileData()).isEqualTo(importedProfile.getProfileData());
assertThat(initialProfile.getDescription()).isEqualTo(importedProfile.getDescription());
}
protected Asset createAsset(TenantId tenantId, CustomerId customerId, String type, String name) {
Asset asset = new Asset();
asset.setTenantId(tenantId);
asset.setCustomerId(customerId);
asset.setType(type);
asset.setName(name);
asset.setLabel("lbl");
asset.setAdditionalInfo(JacksonUtil.newObjectNode().set("a", new TextNode("b")));
return assetService.saveAsset(asset);
}
protected void checkImportedAssetData(Asset initialAsset, Asset importedAsset) {
assertThat(importedAsset.getName()).isEqualTo(initialAsset.getName());
assertThat(importedAsset.getType()).isEqualTo(initialAsset.getType());
assertThat(importedAsset.getLabel()).isEqualTo(initialAsset.getLabel());
assertThat(importedAsset.getAdditionalInfo()).isEqualTo(initialAsset.getAdditionalInfo());
}
protected Customer createCustomer(TenantId tenantId, String name) {
Customer customer = new Customer();
customer.setTenantId(tenantId);
customer.setTitle(name);
customer.setCountry("ua");
customer.setAddress("abb");
customer.setEmail("ccc@aa.org");
customer.setAdditionalInfo(JacksonUtil.newObjectNode().set("a", new TextNode("b")));
return customerService.saveCustomer(customer);
}
protected void checkImportedCustomerData(Customer initialCustomer, Customer importedCustomer) {
assertThat(importedCustomer.getTitle()).isEqualTo(initialCustomer.getTitle());
assertThat(importedCustomer.getCountry()).isEqualTo(initialCustomer.getCountry());
assertThat(importedCustomer.getAddress()).isEqualTo(initialCustomer.getAddress());
assertThat(importedCustomer.getEmail()).isEqualTo(initialCustomer.getEmail());
}
protected Dashboard createDashboard(TenantId tenantId, CustomerId customerId, String name) {
Dashboard dashboard = new Dashboard();
dashboard.setTenantId(tenantId);
dashboard.setTitle(name);
dashboard.setConfiguration(JacksonUtil.newObjectNode().set("a", new TextNode("b")));
dashboard.setImage("abvregewrg");
dashboard.setMobileHide(true);
dashboard = dashboardService.saveDashboard(dashboard);
if (customerId != null) {
dashboardService.assignDashboardToCustomer(tenantId, dashboard.getId(), customerId);
return dashboardService.findDashboardById(tenantId, dashboard.getId());
}
return dashboard;
}
protected Dashboard createDashboard(TenantId tenantId, CustomerId customerId, String name, AssetId assetForEntityAlias) {
Dashboard dashboard = createDashboard(tenantId, customerId, name);
String entityAliases = "{\n" +
"\t\"23c4185d-1497-9457-30b2-6d91e69a5b2c\": {\n" +
"\t\t\"alias\": \"assets\",\n" +
"\t\t\"filter\": {\n" +
"\t\t\t\"entityList\": [\n" +
"\t\t\t\t\"" + assetForEntityAlias.getId().toString() + "\"\n" +
"\t\t\t],\n" +
"\t\t\t\"entityType\": \"ASSET\",\n" +
"\t\t\t\"resolveMultiple\": true,\n" +
"\t\t\t\"type\": \"entityList\"\n" +
"\t\t},\n" +
"\t\t\"id\": \"23c4185d-1497-9457-30b2-6d91e69a5b2c\"\n" +
"\t}\n" +
"}";
ObjectNode dashboardConfiguration = JacksonUtil.newObjectNode();
dashboardConfiguration.set("entityAliases", JacksonUtil.toJsonNode(entityAliases));
dashboardConfiguration.set("description", new TextNode("hallo"));
dashboard.setConfiguration(dashboardConfiguration);
return dashboardService.saveDashboard(dashboard);
}
protected void checkImportedDashboardData(Dashboard initialDashboard, Dashboard importedDashboard) {
assertThat(importedDashboard.getTitle()).isEqualTo(initialDashboard.getTitle());
assertThat(importedDashboard.getConfiguration()).isEqualTo(initialDashboard.getConfiguration());
assertThat(importedDashboard.getImage()).isEqualTo(initialDashboard.getImage());
assertThat(importedDashboard.isMobileHide()).isEqualTo(initialDashboard.isMobileHide());
if (initialDashboard.getAssignedCustomers() != null) {
assertThat(importedDashboard.getAssignedCustomers()).containsAll(initialDashboard.getAssignedCustomers());
}
}
protected RuleChain createRuleChain(TenantId tenantId, String name, EntityId originatorId) {
RuleChain ruleChain = new RuleChain();
ruleChain.setTenantId(tenantId);
ruleChain.setName(name);
ruleChain.setType(RuleChainType.CORE);
ruleChain.setDebugMode(true);
ruleChain.setConfiguration(JacksonUtil.newObjectNode().set("a", new TextNode("b")));
ruleChain = ruleChainService.saveRuleChain(ruleChain);
RuleChainMetaData metaData = new RuleChainMetaData();
metaData.setRuleChainId(ruleChain.getId());
RuleNode ruleNode1 = new RuleNode();
ruleNode1.setName("Generator 1");
ruleNode1.setType(TbMsgGeneratorNode.class.getName());
ruleNode1.setDebugMode(true);
TbMsgGeneratorNodeConfiguration configuration1 = new TbMsgGeneratorNodeConfiguration();
configuration1.setOriginatorType(originatorId.getEntityType());
configuration1.setOriginatorId(originatorId.getId().toString());
ruleNode1.setConfiguration(mapper.valueToTree(configuration1));
RuleNode ruleNode2 = new RuleNode();
ruleNode2.setName("Simple Rule Node 2");
ruleNode2.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName());
ruleNode2.setDebugMode(true);
TbGetAttributesNodeConfiguration configuration2 = new TbGetAttributesNodeConfiguration();
configuration2.setServerAttributeNames(Collections.singletonList("serverAttributeKey2"));
ruleNode2.setConfiguration(mapper.valueToTree(configuration2));
metaData.setNodes(Arrays.asList(ruleNode1, ruleNode2));
metaData.setFirstNodeIndex(0);
metaData.addConnectionInfo(0, 1, "Success");
ruleChainService.saveRuleChainMetaData(tenantId, metaData);
return ruleChainService.findRuleChainById(tenantId, ruleChain.getId());
}
protected RuleChain createRuleChain(TenantId tenantId, String name) {
RuleChain ruleChain = new RuleChain();
ruleChain.setTenantId(tenantId);
ruleChain.setName(name);
ruleChain.setType(RuleChainType.CORE);
ruleChain.setDebugMode(true);
ruleChain.setConfiguration(JacksonUtil.newObjectNode().set("a", new TextNode("b")));
ruleChain = ruleChainService.saveRuleChain(ruleChain);
RuleChainMetaData metaData = new RuleChainMetaData();
metaData.setRuleChainId(ruleChain.getId());
RuleNode ruleNode1 = new RuleNode();
ruleNode1.setName("Simple Rule Node 1");
ruleNode1.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName());
ruleNode1.setDebugMode(true);
TbGetAttributesNodeConfiguration configuration1 = new TbGetAttributesNodeConfiguration();
configuration1.setServerAttributeNames(Collections.singletonList("serverAttributeKey1"));
ruleNode1.setConfiguration(mapper.valueToTree(configuration1));
RuleNode ruleNode2 = new RuleNode();
ruleNode2.setName("Simple Rule Node 2");
ruleNode2.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName());
ruleNode2.setDebugMode(true);
TbGetAttributesNodeConfiguration configuration2 = new TbGetAttributesNodeConfiguration();
configuration2.setServerAttributeNames(Collections.singletonList("serverAttributeKey2"));
ruleNode2.setConfiguration(mapper.valueToTree(configuration2));
metaData.setNodes(Arrays.asList(ruleNode1, ruleNode2));
metaData.setFirstNodeIndex(0);
metaData.addConnectionInfo(0, 1, "Success");
ruleChainService.saveRuleChainMetaData(tenantId, metaData);
return ruleChainService.findRuleChainById(tenantId, ruleChain.getId());
}
protected void checkImportedRuleChainData(RuleChain initialRuleChain, RuleChainMetaData initialMetaData, RuleChain importedRuleChain, RuleChainMetaData importedMetaData) {
assertThat(importedRuleChain.getType()).isEqualTo(initialRuleChain.getType());
assertThat(importedRuleChain.getName()).isEqualTo(initialRuleChain.getName());
assertThat(importedRuleChain.isDebugMode()).isEqualTo(initialRuleChain.isDebugMode());
assertThat(importedRuleChain.getConfiguration()).isEqualTo(initialRuleChain.getConfiguration());
assertThat(importedMetaData.getConnections()).isEqualTo(initialMetaData.getConnections());
assertThat(importedMetaData.getFirstNodeIndex()).isEqualTo(initialMetaData.getFirstNodeIndex());
for (int i = 0; i < initialMetaData.getNodes().size(); i++) {
RuleNode initialNode = initialMetaData.getNodes().get(i);
RuleNode importedNode = importedMetaData.getNodes().get(i);
assertThat(importedNode.getRuleChainId()).isEqualTo(importedRuleChain.getId());
assertThat(importedNode.getName()).isEqualTo(initialNode.getName());
assertThat(importedNode.getType()).isEqualTo(initialNode.getType());
assertThat(importedNode.getConfiguration()).isEqualTo(initialNode.getConfiguration());
assertThat(importedNode.getAdditionalInfo()).isEqualTo(initialNode.getAdditionalInfo());
}
}
protected EntityView createEntityView(TenantId tenantId, CustomerId customerId, EntityId entityId, String name) {
EntityView entityView = new EntityView();
entityView.setTenantId(tenantId);
entityView.setEntityId(entityId);
entityView.setCustomerId(customerId);
entityView.setName(name);
entityView.setType("A");
return entityViewService.saveEntityView(entityView);
}
protected EntityRelation createRelation(EntityId from, EntityId to) {
EntityRelation relation = new EntityRelation();
relation.setFrom(from);
relation.setTo(to);
relation.setType(EntityRelation.MANAGES_TYPE);
relation.setAdditionalInfo(JacksonUtil.newObjectNode().set("a", new TextNode("b")));
relation.setTypeGroup(RelationTypeGroup.COMMON);
relationService.saveRelation(TenantId.SYS_TENANT_ID, relation);
return relation;
}
protected <E extends ExportableEntity<?> & HasTenantId> void checkImportedEntity(TenantId tenantId1, E initialEntity, TenantId tenantId2, E importedEntity) {
assertThat(initialEntity.getTenantId()).isEqualTo(tenantId1);
assertThat(importedEntity.getTenantId()).isEqualTo(tenantId2);
assertThat(importedEntity.getExternalId()).isEqualTo(initialEntity.getId());
boolean sameTenant = tenantId1.equals(tenantId2);
if (!sameTenant) {
assertThat(importedEntity.getId()).isNotEqualTo(initialEntity.getId());
} else {
assertThat(importedEntity.getId()).isEqualTo(initialEntity.getId());
}
}
protected <E extends ExportableEntity<I>, I extends EntityId> EntityExportData<E> exportEntity(User user, I entityId) throws Exception {
return exportEntity(user, entityId, EntityExportSettings.builder()
.exportCredentials(true)
.build());
}
protected <E extends ExportableEntity<I>, I extends EntityId> EntityExportData<E> exportEntity(User user, I entityId, EntityExportSettings exportSettings) throws Exception {
return exportImportService.exportEntity(new SimpleEntitiesExportCtx(getSecurityUser(user), null, null, exportSettings), entityId);
}
protected <E extends ExportableEntity<I>, I extends EntityId> EntityImportResult<E> importEntity(User user, EntityExportData<E> exportData) throws Exception {
return importEntity(user, exportData, EntityImportSettings.builder()
.saveCredentials(true)
.build());
}
protected <E extends ExportableEntity<I>, I extends EntityId> EntityImportResult<E> importEntity(User user, EntityExportData<E> exportData, EntityImportSettings importSettings) throws Exception {
EntitiesImportCtx ctx = new EntitiesImportCtx(getSecurityUser(user), null, importSettings);
ctx.setFetchAllUUIDs(true);
exportData = JacksonUtil.treeToValue(JacksonUtil.valueToTree(exportData), EntityExportData.class);
EntityImportResult<E> importResult = exportImportService.importEntity(ctx, exportData);
exportImportService.saveReferencesAndRelations(ctx);
for (ThrowingRunnable throwingRunnable : ctx.getEventCallbacks()) {
throwingRunnable.run();
}
return importResult;
}
protected SecurityUser getSecurityUser(User user) {
return new SecurityUser(user, true, new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail()));
}
}

546
application/src/test/java/org/thingsboard/server/service/sync/ie/ExportImportServiceSqlTest.java

@ -0,0 +1,546 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.ie;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.google.common.collect.Streams;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.debug.TbMsgGeneratorNode;
import org.thingsboard.rule.engine.debug.TbMsgGeneratorNodeConfiguration;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
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.RuleNode;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.data.sync.ie.DeviceExportData;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.common.data.sync.ie.EntityExportSettings;
import org.thingsboard.server.common.data.sync.ie.EntityImportResult;
import org.thingsboard.server.common.data.sync.ie.EntityImportSettings;
import org.thingsboard.server.common.data.sync.ie.RuleChainExportData;
import org.thingsboard.server.dao.device.DeviceCredentialsService;
import org.thingsboard.server.dao.device.DeviceProfileDao;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.service.action.EntityActionService;
import org.thingsboard.server.service.ota.OtaPackageStateService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.verify;
@DaoSqlTest
public class ExportImportServiceSqlTest extends BaseExportImportServiceTest {
@Autowired
private DeviceCredentialsService deviceCredentialsService;
@SpyBean
private EntityActionService entityActionService;
@SpyBean
private OtaPackageStateService otaPackageStateService;
@Test
public void testExportImportAsset_betweenTenants() throws Exception {
Asset asset = createAsset(tenantId1, null, "AB", "Asset of tenant 1");
EntityExportData<Asset> exportData = exportEntity(tenantAdmin1, asset.getId());
EntityImportResult<Asset> importResult = importEntity(tenantAdmin2, exportData);
checkImportedEntity(tenantId1, asset, tenantId2, importResult.getSavedEntity());
checkImportedAssetData(asset, importResult.getSavedEntity());
}
@Test
public void testExportImportAsset_sameTenant() throws Exception {
Asset asset = createAsset(tenantId1, null, "AB", "Asset v1.0");
EntityExportData<Asset> exportData = exportEntity(tenantAdmin1, asset.getId());
EntityImportResult<Asset> importResult = importEntity(tenantAdmin1, exportData);
checkImportedEntity(tenantId1, asset, tenantId1, importResult.getSavedEntity());
checkImportedAssetData(asset, importResult.getSavedEntity());
}
@Test
public void testExportImportAsset_sameTenant_withCustomer() throws Exception {
Customer customer = createCustomer(tenantId1, "My customer");
Asset asset = createAsset(tenantId1, customer.getId(), "AB", "My asset");
Asset importedAsset = importEntity(tenantAdmin1, this.<Asset, AssetId>exportEntity(tenantAdmin1, asset.getId())).getSavedEntity();
assertThat(importedAsset.getCustomerId()).isEqualTo(asset.getCustomerId());
}
@Test
public void testExportImportCustomer_betweenTenants() throws Exception {
Customer customer = createCustomer(tenantAdmin1.getTenantId(), "Customer of tenant 1");
EntityExportData<Customer> exportData = exportEntity(tenantAdmin1, customer.getId());
EntityImportResult<Customer> importResult = importEntity(tenantAdmin2, exportData);
checkImportedEntity(tenantId1, customer, tenantId2, importResult.getSavedEntity());
checkImportedCustomerData(customer, importResult.getSavedEntity());
}
@Test
public void testExportImportCustomer_sameTenant() throws Exception {
Customer customer = createCustomer(tenantAdmin1.getTenantId(), "Customer v1.0");
EntityExportData<Customer> exportData = exportEntity(tenantAdmin1, customer.getId());
EntityImportResult<Customer> importResult = importEntity(tenantAdmin1, exportData);
checkImportedEntity(tenantId1, customer, tenantId1, importResult.getSavedEntity());
checkImportedCustomerData(customer, importResult.getSavedEntity());
}
@Test
public void testExportImportDeviceWithProfile_betweenTenants() throws Exception {
DeviceProfile deviceProfile = createDeviceProfile(tenantId1, null, null, "Device profile of tenant 1");
Device device = createDevice(tenantId1, null, deviceProfile.getId(), "Device of tenant 1");
DeviceCredentials credentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId1, device.getId());
EntityExportData<DeviceProfile> profileExportData = exportEntity(tenantAdmin1, deviceProfile.getId());
EntityExportData<Device> deviceExportData = exportEntity(tenantAdmin1, device.getId());
DeviceCredentials exportedCredentials = ((DeviceExportData) deviceExportData).getCredentials();
exportedCredentials.setCredentialsId(credentials.getCredentialsId() + "a");
EntityImportResult<DeviceProfile> profileImportResult = importEntity(tenantAdmin2, profileExportData);
checkImportedEntity(tenantId1, deviceProfile, tenantId2, profileImportResult.getSavedEntity());
checkImportedDeviceProfileData(deviceProfile, profileImportResult.getSavedEntity());
EntityImportResult<Device> deviceImportResult = importEntity(tenantAdmin2, deviceExportData);
Device importedDevice = deviceImportResult.getSavedEntity();
checkImportedEntity(tenantId1, device, tenantId2, deviceImportResult.getSavedEntity());
checkImportedDeviceData(device, importedDevice);
assertThat(importedDevice.getDeviceProfileId()).isEqualTo(profileImportResult.getSavedEntity().getId());
DeviceCredentials importedCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId2, importedDevice.getId());
assertThat(importedCredentials.getId()).isNotEqualTo(credentials.getId());
assertThat(importedCredentials.getCredentialsId()).isEqualTo(exportedCredentials.getCredentialsId());
assertThat(importedCredentials.getCredentialsValue()).isEqualTo(credentials.getCredentialsValue());
assertThat(importedCredentials.getCredentialsType()).isEqualTo(credentials.getCredentialsType());
}
@Test
public void testExportImportDevice_sameTenant() throws Exception {
DeviceProfile deviceProfile = createDeviceProfile(tenantId1, null, null, "Device profile v1.0");
OtaPackage firmware = createOtaPackage(tenantId1, deviceProfile.getId(), OtaPackageType.FIRMWARE);
OtaPackage software = createOtaPackage(tenantId1, deviceProfile.getId(), OtaPackageType.SOFTWARE);
Device device = createDevice(tenantId1, null, deviceProfile.getId(), "Device v1.0");
device.setFirmwareId(firmware.getId());
device.setSoftwareId(software.getId());
device = deviceService.saveDevice(device);
DeviceCredentials credentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId1, device.getId());
EntityExportData<Device> deviceExportData = exportEntity(tenantAdmin1, device.getId());
EntityImportResult<Device> importResult = importEntity(tenantAdmin1, deviceExportData);
Device importedDevice = importResult.getSavedEntity();
checkImportedEntity(tenantId1, device, tenantId1, importResult.getSavedEntity());
assertThat(importedDevice.getDeviceProfileId()).isEqualTo(device.getDeviceProfileId());
assertThat(deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId1, device.getId())).isEqualTo(credentials);
assertThat(importedDevice.getFirmwareId()).isEqualTo(firmware.getId());
assertThat(importedDevice.getSoftwareId()).isEqualTo(software.getId());
}
@Test
public void testExportImportDashboard_betweenTenants() throws Exception {
Dashboard dashboard = createDashboard(tenantAdmin1.getTenantId(), null, "Dashboard of tenant 1");
EntityExportData<Dashboard> exportData = exportEntity(tenantAdmin1, dashboard.getId());
EntityImportResult<Dashboard> importResult = importEntity(tenantAdmin2, exportData);
checkImportedEntity(tenantId1, dashboard, tenantId2, importResult.getSavedEntity());
checkImportedDashboardData(dashboard, importResult.getSavedEntity());
}
@Test
public void testExportImportDashboard_sameTenant() throws Exception {
Dashboard dashboard = createDashboard(tenantAdmin1.getTenantId(), null, "Dashboard v1.0");
EntityExportData<Dashboard> exportData = exportEntity(tenantAdmin1, dashboard.getId());
EntityImportResult<Dashboard> importResult = importEntity(tenantAdmin1, exportData);
checkImportedEntity(tenantId1, dashboard, tenantId1, importResult.getSavedEntity());
checkImportedDashboardData(dashboard, importResult.getSavedEntity());
}
@Test
public void testExportImportDashboard_betweenTenants_withCustomer_updated() throws Exception {
Dashboard dashboard = createDashboard(tenantAdmin1.getTenantId(), null, "Dashboard of tenant 1");
EntityExportData<Dashboard> exportData = exportEntity(tenantAdmin1, dashboard.getId());
Dashboard importedDashboard = importEntity(tenantAdmin2, exportData).getSavedEntity();
checkImportedEntity(tenantId1, dashboard, tenantId2, importedDashboard);
Customer customer = createCustomer(tenantId1, "Customer 1");
EntityExportData<Customer> customerExportData = exportEntity(tenantAdmin1, customer.getId());
dashboardService.assignDashboardToCustomer(tenantId1, dashboard.getId(), customer.getId());
exportData = exportEntity(tenantAdmin1, dashboard.getId());
Customer importedCustomer = importEntity(tenantAdmin2, customerExportData).getSavedEntity();
importedDashboard = importEntity(tenantAdmin2, exportData).getSavedEntity();
assertThat(importedDashboard.getAssignedCustomers()).hasOnlyOneElementSatisfying(customerInfo -> {
assertThat(customerInfo.getCustomerId()).isEqualTo(importedCustomer.getId());
});
}
@Test
public void testExportImportDashboard_betweenTenants_withEntityAliases() throws Exception {
Asset asset1 = createAsset(tenantId1, null, "A", "Asset 1");
Asset asset2 = createAsset(tenantId1, null, "A", "Asset 2");
Dashboard dashboard = createDashboard(tenantId1, null, "Dashboard 1");
String entityAliases = "{\n" +
"\t\"23c4185d-1497-9457-30b2-6d91e69a5b2c\": {\n" +
"\t\t\"alias\": \"assets\",\n" +
"\t\t\"filter\": {\n" +
"\t\t\t\"entityList\": [\n" +
"\t\t\t\t\"" + asset1.getId().toString() + "\",\n" +
"\t\t\t\t\"" + asset2.getId().toString() + "\"\n" +
"\t\t\t],\n" +
"\t\t\t\"entityType\": \"ASSET\",\n" +
"\t\t\t\"resolveMultiple\": true,\n" +
"\t\t\t\"type\": \"entityList\"\n" +
"\t\t},\n" +
"\t\t\"id\": \"23c4185d-1497-9457-30b2-6d91e69a5b2c\"\n" +
"\t}\n" +
"}";
ObjectNode dashboardConfiguration = JacksonUtil.newObjectNode();
dashboardConfiguration.set("entityAliases", JacksonUtil.toJsonNode(entityAliases));
dashboardConfiguration.set("description", new TextNode("hallo"));
dashboard.setConfiguration(dashboardConfiguration);
dashboard = dashboardService.saveDashboard(dashboard);
EntityExportData<Asset> asset1ExportData = exportEntity(tenantAdmin1, asset1.getId());
EntityExportData<Asset> asset2ExportData = exportEntity(tenantAdmin1, asset2.getId());
EntityExportData<Dashboard> dashboardExportData = exportEntity(tenantAdmin1, dashboard.getId());
Asset importedAsset1 = importEntity(tenantAdmin2, asset1ExportData).getSavedEntity();
Asset importedAsset2 = importEntity(tenantAdmin2, asset2ExportData).getSavedEntity();
Dashboard importedDashboard = importEntity(tenantAdmin2, dashboardExportData).getSavedEntity();
Set<String> entityAliasEntitiesIds = Streams.stream(importedDashboard.getConfiguration()
.get("entityAliases").elements().next().get("filter").get("entityList").elements())
.map(JsonNode::asText).collect(Collectors.toSet());
assertThat(entityAliasEntitiesIds).doesNotContain(asset1.getId().toString(), asset2.getId().toString());
assertThat(entityAliasEntitiesIds).contains(importedAsset1.getId().toString(), importedAsset2.getId().toString());
}
@Test
public void testExportImportRuleChain_betweenTenants() throws Exception {
RuleChain ruleChain = createRuleChain(tenantId1, "Rule chain of tenant 1");
RuleChainMetaData metaData = ruleChainService.loadRuleChainMetaData(tenantId1, ruleChain.getId());
EntityExportData<RuleChain> exportData = exportEntity(tenantAdmin1, ruleChain.getId());
EntityImportResult<RuleChain> importResult = importEntity(tenantAdmin2, exportData);
RuleChain importedRuleChain = importResult.getSavedEntity();
RuleChainMetaData importedMetaData = ruleChainService.loadRuleChainMetaData(tenantId2, importedRuleChain.getId());
checkImportedEntity(tenantId1, ruleChain, tenantId2, importResult.getSavedEntity());
checkImportedRuleChainData(ruleChain, metaData, importedRuleChain, importedMetaData);
}
@Test
public void testExportImportRuleChain_sameTenant() throws Exception {
RuleChain ruleChain = createRuleChain(tenantId1, "Rule chain v1.0");
RuleChainMetaData metaData = ruleChainService.loadRuleChainMetaData(tenantId1, ruleChain.getId());
EntityExportData<RuleChain> exportData = exportEntity(tenantAdmin1, ruleChain.getId());
EntityImportResult<RuleChain> importResult = importEntity(tenantAdmin1, exportData);
RuleChain importedRuleChain = importResult.getSavedEntity();
RuleChainMetaData importedMetaData = ruleChainService.loadRuleChainMetaData(tenantId1, importedRuleChain.getId());
checkImportedEntity(tenantId1, ruleChain, tenantId1, importResult.getSavedEntity());
checkImportedRuleChainData(ruleChain, metaData, importedRuleChain, importedMetaData);
}
@Test
public void testExportImportWithInboundRelations_betweenTenants() throws Exception {
Asset asset = createAsset(tenantId1, null, "A", "Asset 1");
Device device = createDevice(tenantId1, null, null, "Device 1");
EntityRelation relation = createRelation(asset.getId(), device.getId());
EntityExportData<Asset> assetExportData = exportEntity(tenantAdmin1, asset.getId());
EntityExportData<Device> deviceExportData = exportEntity(tenantAdmin1, device.getId(), EntityExportSettings.builder()
.exportRelations(true)
.exportCredentials(false)
.build());
assertThat(deviceExportData.getRelations()).size().isOne();
assertThat(deviceExportData.getRelations().get(0)).matches(entityRelation -> {
return entityRelation.getFrom().equals(asset.getId()) && entityRelation.getTo().equals(device.getId());
});
((Device) deviceExportData.getEntity()).setDeviceProfileId(null);
Asset importedAsset = importEntity(tenantAdmin2, assetExportData).getSavedEntity();
Device importedDevice = importEntity(tenantAdmin2, deviceExportData, EntityImportSettings.builder()
.updateRelations(true)
.build()).getSavedEntity();
checkImportedEntity(tenantId1, device, tenantId2, importedDevice);
checkImportedEntity(tenantId1, asset, tenantId2, importedAsset);
List<EntityRelation> importedRelations = relationService.findByTo(TenantId.SYS_TENANT_ID, importedDevice.getId(), RelationTypeGroup.COMMON);
assertThat(importedRelations).size().isOne();
assertThat(importedRelations.get(0)).satisfies(importedRelation -> {
assertThat(importedRelation.getFrom()).isEqualTo(importedAsset.getId());
assertThat(importedRelation.getType()).isEqualTo(relation.getType());
assertThat(importedRelation.getAdditionalInfo()).isEqualTo(relation.getAdditionalInfo());
});
}
@Test
public void testExportImportWithRelations_betweenTenants() throws Exception {
Asset asset = createAsset(tenantId1, null, "A", "Asset 1");
Device device = createDevice(tenantId1, null, null, "Device 1");
EntityRelation relation = createRelation(asset.getId(), device.getId());
EntityExportData<Asset> assetExportData = exportEntity(tenantAdmin1, asset.getId());
EntityExportData<Device> deviceExportData = exportEntity(tenantAdmin1, device.getId(), EntityExportSettings.builder()
.exportRelations(true)
.exportCredentials(false)
.build());
deviceExportData.getEntity().setDeviceProfileId(null);
Asset importedAsset = importEntity(tenantAdmin2, assetExportData).getSavedEntity();
Device importedDevice = importEntity(tenantAdmin2, deviceExportData, EntityImportSettings.builder()
.updateRelations(true)
.build()).getSavedEntity();
List<EntityRelation> importedRelations = relationService.findByTo(TenantId.SYS_TENANT_ID, importedDevice.getId(), RelationTypeGroup.COMMON);
assertThat(importedRelations).size().isOne();
assertThat(importedRelations.get(0)).satisfies(importedRelation -> {
assertThat(importedRelation.getFrom()).isEqualTo(importedAsset.getId());
assertThat(importedRelation.getType()).isEqualTo(relation.getType());
assertThat(importedRelation.getAdditionalInfo()).isEqualTo(relation.getAdditionalInfo());
});
}
@Test
public void testExportImportWithRelations_sameTenant() throws Exception {
Asset asset = createAsset(tenantId1, null, "A", "Asset 1");
Device device1 = createDevice(tenantId1, null, null, "Device 1");
EntityRelation relation1 = createRelation(asset.getId(), device1.getId());
EntityExportData<Asset> assetExportData = exportEntity(tenantAdmin1, asset.getId(), EntityExportSettings.builder()
.exportRelations(true)
.build());
assertThat(assetExportData.getRelations()).size().isOne();
Device device2 = createDevice(tenantId1, null, null, "Device 2");
EntityRelation relation2 = createRelation(asset.getId(), device2.getId());
importEntity(tenantAdmin1, assetExportData, EntityImportSettings.builder()
.updateRelations(true)
.build());
List<EntityRelation> relations = relationService.findByFrom(TenantId.SYS_TENANT_ID, asset.getId(), RelationTypeGroup.COMMON);
assertThat(relations).contains(relation1);
assertThat(relations).doesNotContain(relation2);
}
@Test
public void textExportImportWithRelations_sameTenant_removeExisting() throws Exception {
Asset asset1 = createAsset(tenantId1, null, "A", "Asset 1");
Device device = createDevice(tenantId1, null, null, "Device 1");
EntityRelation relation1 = createRelation(asset1.getId(), device.getId());
EntityExportData<Device> deviceExportData = exportEntity(tenantAdmin1, device.getId(), EntityExportSettings.builder()
.exportRelations(true)
.build());
assertThat(deviceExportData.getRelations()).size().isOne();
Asset asset2 = createAsset(tenantId1, null, "A", "Asset 2");
EntityRelation relation2 = createRelation(asset2.getId(), device.getId());
importEntity(tenantAdmin1, deviceExportData, EntityImportSettings.builder()
.updateRelations(true)
.build());
List<EntityRelation> relations = relationService.findByTo(TenantId.SYS_TENANT_ID, device.getId(), RelationTypeGroup.COMMON);
assertThat(relations).contains(relation1);
assertThat(relations).doesNotContain(relation2);
}
@Test
public void testExportImportDeviceProfile_betweenTenants_findExistingByName() throws Exception {
DeviceProfile defaultDeviceProfile = deviceProfileService.findDefaultDeviceProfile(tenantId1);
EntityExportData<DeviceProfile> deviceProfileExportData = exportEntity(tenantAdmin1, defaultDeviceProfile.getId());
assertThatThrownBy(() -> {
importEntity(tenantAdmin2, deviceProfileExportData, EntityImportSettings.builder()
.findExistingByName(false)
.build());
}).hasMessageContaining("default device profile is present");
importEntity(tenantAdmin2, deviceProfileExportData, EntityImportSettings.builder()
.findExistingByName(true)
.build());
checkImportedEntity(tenantId1, defaultDeviceProfile, tenantId2, deviceProfileService.findDefaultDeviceProfile(tenantId2));
}
@Test
public void testEntityEventsOnImport() throws Exception {
Customer customer = createCustomer(tenantId1, "Customer 1");
Asset asset = createAsset(tenantId1, null, "A", "Asset 1");
RuleChain ruleChain = createRuleChain(tenantId1, "Rule chain 1");
Dashboard dashboard = createDashboard(tenantId1, null, "Dashboard 1");
DeviceProfile deviceProfile = createDeviceProfile(tenantId1, ruleChain.getId(), dashboard.getId(), "Device profile 1");
Device device = createDevice(tenantId1, null, deviceProfile.getId(), "Device 1");
Map<EntityType, EntityExportData> entitiesExportData = Stream.of(customer.getId(), asset.getId(), device.getId(),
ruleChain.getId(), dashboard.getId(), deviceProfile.getId())
.map(entityId -> {
try {
return exportEntity(tenantAdmin1, entityId, EntityExportSettings.builder()
.exportCredentials(false)
.build());
} catch (Exception e) {
throw new RuntimeException(e);
}
})
.collect(Collectors.toMap(EntityExportData::getEntityType, d -> d));
Customer importedCustomer = (Customer) importEntity(tenantAdmin2, entitiesExportData.get(EntityType.CUSTOMER)).getSavedEntity();
verify(entityActionService).logEntityAction(any(), eq(importedCustomer.getId()), eq(importedCustomer),
any(), eq(ActionType.ADDED), isNull());
importEntity(tenantAdmin2, entitiesExportData.get(EntityType.CUSTOMER));
verify(entityActionService).logEntityAction(any(), eq(importedCustomer.getId()), eq(importedCustomer),
any(), eq(ActionType.UPDATED), isNull());
verify(tbClusterService).sendNotificationMsgToEdgeService(any(), any(), eq(importedCustomer.getId()), any(), any(), eq(EdgeEventActionType.UPDATED));
Asset importedAsset = (Asset) importEntity(tenantAdmin2, entitiesExportData.get(EntityType.ASSET)).getSavedEntity();
verify(entityActionService).logEntityAction(any(), eq(importedAsset.getId()), eq(importedAsset),
any(), eq(ActionType.ADDED), isNull());
importEntity(tenantAdmin2, entitiesExportData.get(EntityType.ASSET));
verify(entityActionService).logEntityAction(any(), eq(importedAsset.getId()), eq(importedAsset),
any(), eq(ActionType.UPDATED), isNull());
verify(tbClusterService).sendNotificationMsgToEdgeService(any(), any(), eq(importedAsset.getId()), any(), any(), eq(EdgeEventActionType.UPDATED));
RuleChain importedRuleChain = (RuleChain) importEntity(tenantAdmin2, entitiesExportData.get(EntityType.RULE_CHAIN)).getSavedEntity();
verify(entityActionService).logEntityAction(any(), eq(importedRuleChain.getId()), eq(importedRuleChain),
any(), eq(ActionType.ADDED), isNull());
verify(tbClusterService).broadcastEntityStateChangeEvent(any(), eq(importedRuleChain.getId()), eq(ComponentLifecycleEvent.CREATED));
Dashboard importedDashboard = (Dashboard) importEntity(tenantAdmin2, entitiesExportData.get(EntityType.DASHBOARD)).getSavedEntity();
verify(entityActionService).logEntityAction(any(), eq(importedDashboard.getId()), eq(importedDashboard),
any(), eq(ActionType.ADDED), isNull());
DeviceProfile importedDeviceProfile = (DeviceProfile) importEntity(tenantAdmin2, entitiesExportData.get(EntityType.DEVICE_PROFILE)).getSavedEntity();
verify(entityActionService).logEntityAction(any(), eq(importedDeviceProfile.getId()), eq(importedDeviceProfile),
any(), eq(ActionType.ADDED), isNull());
verify(tbClusterService).onDeviceProfileChange(eq(importedDeviceProfile), any());
verify(tbClusterService).broadcastEntityStateChangeEvent(any(), eq(importedDeviceProfile.getId()), eq(ComponentLifecycleEvent.CREATED));
verify(tbClusterService).sendNotificationMsgToEdgeService(any(), any(), eq(importedDeviceProfile.getId()), any(), any(), eq(EdgeEventActionType.ADDED));
verify(otaPackageStateService).update(eq(importedDeviceProfile), eq(false), eq(false));
Device importedDevice = (Device) importEntity(tenantAdmin2, entitiesExportData.get(EntityType.DEVICE)).getSavedEntity();
verify(entityActionService).logEntityAction(any(), eq(importedDevice.getId()), eq(importedDevice),
any(), eq(ActionType.ADDED), isNull());
verify(tbClusterService).onDeviceUpdated(eq(importedDevice), isNull());
importEntity(tenantAdmin2, entitiesExportData.get(EntityType.DEVICE));
verify(tbClusterService).onDeviceUpdated(eq(importedDevice), eq(importedDevice));
}
@Test
public void testExternalIdsInExportData() throws Exception {
Customer customer = createCustomer(tenantId1, "Customer 1");
Asset asset = createAsset(tenantId1, customer.getId(), "A", "Asset 1");
RuleChain ruleChain = createRuleChain(tenantId1, "Rule chain 1", asset.getId());
Dashboard dashboard = createDashboard(tenantId1, customer.getId(), "Dashboard 1", asset.getId());
DeviceProfile deviceProfile = createDeviceProfile(tenantId1, ruleChain.getId(), dashboard.getId(), "Device profile 1");
Device device = createDevice(tenantId1, customer.getId(), deviceProfile.getId(), "Device 1");
EntityView entityView = createEntityView(tenantId1, customer.getId(), device.getId(), "Entity view 1");
Map<EntityId, EntityId> ids = new HashMap<>();
for (EntityId entityId : List.of(customer.getId(), asset.getId(), ruleChain.getId(), dashboard.getId(),
deviceProfile.getId(), device.getId(), entityView.getId(), ruleChain.getId(), dashboard.getId())) {
EntityExportData exportData = exportEntity(getSecurityUser(tenantAdmin1), entityId);
EntityImportResult importResult = importEntity(getSecurityUser(tenantAdmin2), exportData, EntityImportSettings.builder()
.saveCredentials(false)
.build());
ids.put(entityId, (EntityId) importResult.getSavedEntity().getId());
}
Asset exportedAsset = (Asset) exportEntity(tenantAdmin2, (AssetId) ids.get(asset.getId())).getEntity();
assertThat(exportedAsset.getCustomerId()).isEqualTo(customer.getId());
EntityExportData<RuleChain> ruleChainExportData = exportEntity(tenantAdmin2, (RuleChainId) ids.get(ruleChain.getId()));
TbMsgGeneratorNodeConfiguration exportedRuleNodeConfig = ((RuleChainExportData) ruleChainExportData).getMetaData().getNodes().stream()
.filter(node -> node.getType().equals(TbMsgGeneratorNode.class.getName())).findFirst()
.map(RuleNode::getConfiguration).map(config -> JacksonUtil.treeToValue(config, TbMsgGeneratorNodeConfiguration.class)).orElse(null);
assertThat(exportedRuleNodeConfig.getOriginatorId()).isEqualTo(asset.getId().toString());
Dashboard exportedDashboard = (Dashboard) exportEntity(tenantAdmin2, (DashboardId) ids.get(dashboard.getId())).getEntity();
assertThat(exportedDashboard.getAssignedCustomers()).hasOnlyOneElementSatisfying(shortCustomerInfo -> {
assertThat(shortCustomerInfo.getCustomerId()).isEqualTo(customer.getId());
});
DeviceProfile exportedDeviceProfile = (DeviceProfile) exportEntity(tenantAdmin2, (DeviceProfileId) ids.get(deviceProfile.getId())).getEntity();
assertThat(exportedDeviceProfile.getDefaultRuleChainId()).isEqualTo(ruleChain.getId());
assertThat(exportedDeviceProfile.getDefaultDashboardId()).isEqualTo(dashboard.getId());
Device exportedDevice = (Device) exportEntity(tenantAdmin2, (DeviceId) ids.get(device.getId())).getEntity();
assertThat(exportedDevice.getCustomerId()).isEqualTo(customer.getId());
assertThat(exportedDevice.getDeviceProfileId()).isEqualTo(deviceProfile.getId());
EntityView exportedEntityView = (EntityView) exportEntity(tenantAdmin2, (EntityViewId) ids.get(entityView.getId())).getEntity();
assertThat(exportedEntityView.getCustomerId()).isEqualTo(customer.getId());
assertThat(exportedEntityView.getEntityId()).isEqualTo(device.getId());
}
}

11
common/data/src/main/java/org/thingsboard/server/common/data/Dashboard.java

@ -15,13 +15,17 @@
*/
package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.annotations.ApiModelProperty;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.thingsboard.server.common.data.id.DashboardId;
import java.util.Optional;
@EqualsAndHashCode(callSuper = true)
public class Dashboard extends DashboardInfo implements ExportableEntity<DashboardId> {
@ -62,6 +66,13 @@ public class Dashboard extends DashboardInfo implements ExportableEntity<Dashboa
this.configuration = configuration;
}
@JsonIgnore
public ObjectNode getEntityAliasesConfig() {
return (ObjectNode) Optional.ofNullable(getConfiguration())
.map(config -> config.get("entityAliases"))
.filter(JsonNode::isObject).orElse(null);
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();

2
common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/DeviceExportData.java

@ -16,6 +16,7 @@
package org.thingsboard.server.common.data.sync.ie;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -29,6 +30,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentials;
public class DeviceExportData extends EntityExportData<Device> {
@JsonProperty(index = 3)
@JsonIgnoreProperties({"id", "deviceId", "createdTime"})
private DeviceCredentials credentials;
@JsonIgnore

1
common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/EntityExportData.java

@ -55,6 +55,7 @@ public class EntityExportData<E extends ExportableEntity<? extends EntityId>> {
.comparing(AttributeExportData::getKey).thenComparing(AttributeExportData::getLastUpdateTs);
@JsonProperty(index = 2)
@JsonIgnoreProperties({"tenantId", "createdTime"})
@JsonTbEntity
private E entity;
@JsonProperty(index = 1)

1
common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/EntityImportSettings.java

@ -29,5 +29,4 @@ public class EntityImportSettings {
private boolean updateRelations;
private boolean saveAttributes;
private boolean saveCredentials;
}

2
common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/RuleChainExportData.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.common.data.sync.ie;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -28,6 +29,7 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData;
public class RuleChainExportData extends EntityExportData<RuleChain> {
@JsonProperty(index = 3)
@JsonIgnoreProperties("ruleChainId")
private RuleChainMetaData metaData;
}

Loading…
Cancel
Save