More tests for export/import api; refactoring

This commit is contained in:
Viacheslav Klimov 2022-04-04 15:09:46 +03:00
parent 4dcd037a61
commit 2a77c90d13
24 changed files with 420 additions and 134 deletions

View File

@ -20,9 +20,12 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity; import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.HasId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.ExportableEntityDao; import org.thingsboard.server.dao.ExportableEntityDao;
import org.thingsboard.server.dao.TenantEntityDao;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.exporting.EntityExportService; import org.thingsboard.server.service.sync.exporting.EntityExportService;
import org.thingsboard.server.service.sync.exporting.EntityExportSettings; import org.thingsboard.server.service.sync.exporting.EntityExportSettings;
@ -37,7 +40,6 @@ import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service
@ -46,7 +48,7 @@ public class DefaultEntitiesExportImportService implements EntitiesExportImportS
private final Map<EntityType, EntityExportService<?, ?, ?>> exportServices = new HashMap<>(); private final Map<EntityType, EntityExportService<?, ?, ?>> exportServices = new HashMap<>();
private final Map<EntityType, EntityImportService<?, ?, ?>> importServices = new HashMap<>(); private final Map<EntityType, EntityImportService<?, ?, ?>> importServices = new HashMap<>();
private final Map<EntityType, ExportableEntityDao<?>> daos = new HashMap<>(); private final Map<EntityType, TenantEntityDao<?>> daos = new HashMap<>();
protected static final List<EntityType> SUPPORTED_ENTITY_TYPES = List.of( protected static final List<EntityType> SUPPORTED_ENTITY_TYPES = List.of(
EntityType.CUSTOMER, EntityType.ASSET, EntityType.RULE_CHAIN, EntityType.CUSTOMER, EntityType.ASSET, EntityType.RULE_CHAIN,
@ -85,16 +87,22 @@ public class DefaultEntitiesExportImportService implements EntitiesExportImportS
@Override @Override
public <E extends ExportableEntity<I>, I extends EntityId> E findEntityById(TenantId tenantId, I id) { public <E extends HasId<I> & HasTenantId, I extends EntityId> E findEntityById(TenantId tenantId, I id) {
ExportableEntityDao<E> dao = getDao(id.getEntityType()); TenantEntityDao<E> dao = (TenantEntityDao<E>) getDao(id.getEntityType());
return dao.findByTenantIdAndId(tenantId.getId(), id.getId()); return dao.findByTenantIdAndId(tenantId.getId(), id.getId());
} }
@Override @Override
public <E extends ExportableEntity<I>, I extends EntityId> E findEntityByExternalId(TenantId tenantId, I externalId) { public <E extends ExportableEntity<I>, I extends EntityId> E findEntityByExternalId(TenantId tenantId, I externalId) {
ExportableEntityDao<E> dao = getDao(externalId.getEntityType()); EntityType entityType = externalId.getEntityType();
return Optional.ofNullable(dao.findByTenantIdAndExternalId(tenantId.getId(), externalId.getId())) if (SUPPORTED_ENTITY_TYPES.contains(entityType)) {
.orElseGet(() -> findEntityById(tenantId, externalId)); ExportableEntityDao<E> dao = (ExportableEntityDao<E>) getDao(entityType);
E entity = dao.findByTenantIdAndExternalId(tenantId.getId(), externalId.getId());
if (entity != null) {
return entity;
}
}
return findEntityById(tenantId, externalId);
} }
@ -114,15 +122,14 @@ public class DefaultEntitiesExportImportService implements EntitiesExportImportS
return (EntityImportService<I, E, D>) importServices.get(entityType); return (EntityImportService<I, E, D>) importServices.get(entityType);
} }
@SuppressWarnings("unchecked") private TenantEntityDao<?> getDao(EntityType entityType) {
private <E> ExportableEntityDao<E> getDao(EntityType entityType) { return daos.get(entityType);
return (ExportableEntityDao<E>) daos.get(entityType);
} }
@Autowired @Autowired
private void setServices(Collection<EntityExportService<?, ?, ?>> exportServices, private void setServices(Collection<EntityExportService<?, ?, ?>> exportServices,
Collection<EntityImportService<?, ?, ?>> importServices, Collection<EntityImportService<?, ?, ?>> importServices,
Collection<ExportableEntityDao<?>> daos) { Collection<TenantEntityDao<?>> daos) {
exportServices.forEach(entityExportService -> { exportServices.forEach(entityExportService -> {
this.exportServices.put(entityExportService.getEntityType(), entityExportService); this.exportServices.put(entityExportService.getEntityType(), entityExportService);
}); });

View File

@ -16,12 +16,12 @@
package org.thingsboard.server.service.sync.exporting; package org.thingsboard.server.service.sync.exporting;
import org.thingsboard.server.common.data.ExportableEntity; import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.HasId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
public interface ExportableEntitiesService { public interface ExportableEntitiesService extends TenantEntitiesService {
<E extends ExportableEntity<I>, I extends EntityId> E findEntityById(TenantId tenantId, I id);
<E extends ExportableEntity<I>, I extends EntityId> E findEntityByExternalId(TenantId tenantId, I externalId); <E extends ExportableEntity<I>, I extends EntityId> E findEntityByExternalId(TenantId tenantId, I externalId);

View File

@ -0,0 +1,27 @@
/**
* 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.exporting;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.HasId;
import org.thingsboard.server.common.data.id.TenantId;
public interface TenantEntitiesService {
<E extends HasId<I> & HasTenantId, I extends EntityId> E findEntityById(TenantId tenantId, I id);
}

View File

@ -27,7 +27,9 @@ import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.exporting.data.DashboardExportData; import org.thingsboard.server.service.sync.exporting.data.DashboardExportData;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -49,8 +51,8 @@ public class DashboardImportService extends BaseEntityImportService<DashboardId,
dashboardService.assignDashboardToCustomer(tenantId, dashboard.getId(), customerInfo.getCustomerId()); dashboardService.assignDashboardToCustomer(tenantId, dashboard.getId(), customerInfo.getCustomerId());
} }
} else { } else {
Set<CustomerId> existingAssignedCustomers = dashboardService.findDashboardById(tenantId, dashboard.getId()).getAssignedCustomers().stream() Set<CustomerId> existingAssignedCustomers = Optional.ofNullable(dashboardService.findDashboardById(tenantId, dashboard.getId()).getAssignedCustomers())
.map(ShortCustomerInfo::getCustomerId).collect(Collectors.toSet()); .orElse(Collections.emptySet()).stream().map(ShortCustomerInfo::getCustomerId).collect(Collectors.toSet());
Set<CustomerId> newAssignedCustomers = idProvider.get(tenantId, Dashboard::getAssignedCustomers, ShortCustomerInfo::getCustomerId, ShortCustomerInfo::setCustomerId).stream() Set<CustomerId> newAssignedCustomers = idProvider.get(tenantId, Dashboard::getAssignedCustomers, ShortCustomerInfo::getCustomerId, ShortCustomerInfo::setCustomerId).stream()
.map(ShortCustomerInfo::getCustomerId).collect(Collectors.toSet()); .map(ShortCustomerInfo::getCustomerId).collect(Collectors.toSet());

View File

@ -38,7 +38,13 @@ public class DeviceImportService extends BaseEntityImportService<DeviceId, Devic
device.setDeviceProfileId(idProvider.get(tenantId, Device::getDeviceProfileId)); device.setDeviceProfileId(idProvider.get(tenantId, Device::getDeviceProfileId));
device.setFirmwareId(idProvider.get(tenantId, Device::getFirmwareId)); device.setFirmwareId(idProvider.get(tenantId, Device::getFirmwareId));
device.setSoftwareId(idProvider.get(tenantId, Device::getSoftwareId)); device.setSoftwareId(idProvider.get(tenantId, Device::getSoftwareId));
if (exportData.getCredentials() != null) {
exportData.getCredentials().setId(null);
exportData.getCredentials().setDeviceId(null);
return deviceService.saveDeviceWithCredentials(device, exportData.getCredentials()); return deviceService.saveDeviceWithCredentials(device, exportData.getCredentials());
} else { // TODO [viacheslav]: add option not to export device credentials
return deviceService.saveDevice(device);
}
} }
@Override @Override

View File

@ -31,7 +31,8 @@ import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
@ -50,8 +51,8 @@ import org.thingsboard.server.service.sync.exporting.data.RuleChainExportData;
import org.thingsboard.server.service.sync.importing.EntityImportResult; import org.thingsboard.server.service.sync.importing.EntityImportResult;
import java.util.List; import java.util.List;
import java.util.function.Consumer;
import static org.assertj.core.api.Assertions.as;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -100,105 +101,278 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
tenantService.deleteTenant(tenantId2); tenantService.deleteTenant(tenantId2);
} }
@Test @Test
public void testExportImport_singleEntityOneByOne_betweenTenants() throws Exception { public void testExportImportSingleAsset_betweenTenants() throws Exception {
logInAsTenantAdmin1();
Asset asset = createAsset(tenantId1, null, "AB", "Asset of tenant 1"); Asset asset = createAsset(tenantId1, null, "AB", "Asset of tenant 1");
testExportImportBetweenTenants(asset, importedAsset -> { EntityExportData<Asset> exportData = exportSingleEntity(asset.getId());
assertThat(importedAsset.getName()).isEqualTo(asset.getName()); assertThat(exportData.getEntity()).isEqualTo(asset);
assertThat(importedAsset.getType()).isEqualTo(asset.getType());
assertThat(importedAsset.getLabel()).isEqualTo(asset.getLabel());
assertThat(importedAsset.getAdditionalInfo()).isEqualTo(asset.getAdditionalInfo());
});
Customer customer = createCustomer(tenantId1, "Customer of tenant 1"); logInAsTenantAdmin2();
testExportImportBetweenTenants(customer, importedCustomer -> { EntityImportResult<Asset> importResult = importEntities(List.of(exportData)).get(0);
assertThat(importedCustomer.getTitle()).isEqualTo(customer.getTitle());
assertThat(importedCustomer.getCountry()).isEqualTo(customer.getCountry());
assertThat(importedCustomer.getAddress()).isEqualTo(customer.getAddress());
assertThat(importedCustomer.getEmail()).isEqualTo(customer.getEmail());
});
checkImportedEntity(tenantId1, asset, tenantId2, importResult);
checkImportedAssetData(asset, importResult.getSavedEntity());
}
@Test
public void testExportImportSingleAsset_sameTenant() throws Exception {
logInAsTenantAdmin1();
Asset asset = createAsset(tenantId1, null, "AB", "Asset v1.0");
EntityExportData<Asset> exportData = exportSingleEntity(asset.getId());
EntityImportResult<Asset> importResult = importEntities(List.of(exportData)).get(0);
checkImportedEntity(tenantId1, asset, tenantId1, importResult);
checkImportedAssetData(asset, importResult.getSavedEntity());
}
@Test
public void testExportImportAsset_withCustomer_betweenTenants() throws Exception {
logInAsTenantAdmin1();
Customer customer = createCustomer(tenantId1, "My customer");
Asset asset = createAsset(tenantId1, customer.getId(), "AB", "My asset");
EntityExportData<Customer> customerExportData = exportSingleEntity(customer.getId());
EntityExportData<Asset> assetExportData = exportSingleEntity(asset.getId());
logInAsTenantAdmin2();
Customer importedCustomer = importEntities(List.of(customerExportData)).get(0).getSavedEntity();
Asset importedAsset = importEntities(List.of(assetExportData)).get(0).getSavedEntity();
assertThat(importedAsset.getCustomerId()).isEqualTo(importedCustomer.getId());
}
@Test
public void testExportImportAsset_withCustomer_sameTenant() throws Exception {
logInAsTenantAdmin1();
Customer customer = createCustomer(tenantId1, "My customer");
Asset asset = createAsset(tenantId1, customer.getId(), "AB", "My asset");
Asset importedAsset = this.<Asset>importEntities(List.of(exportSingleEntity(asset.getId()))).get(0).getSavedEntity();
assertThat(importedAsset.getCustomerId()).isEqualTo(asset.getCustomerId());
}
private 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());
}
@Test
public void testExportImportSingleCustomer_betweenTenants() throws Exception {
logInAsTenantAdmin1();
Customer customer = createCustomer(tenantAdmin1.getTenantId(), "Customer of tenant 1");
EntityExportData<Customer> exportData = exportSingleEntity(customer.getId());
assertThat(exportData.getEntity()).isEqualTo(customer);
logInAsTenantAdmin2();
EntityImportResult<Customer> importResult = importEntities(List.of(exportData)).get(0);
checkImportedEntity(tenantId1, customer, tenantId2, importResult);
checkImportedCustomerData(customer, importResult.getSavedEntity());
}
@Test
public void testExportImportSingleCustomer_sameTenant() throws Exception {
logInAsTenantAdmin1();
Customer customer = createCustomer(tenantAdmin1.getTenantId(), "Customer v1.0");
EntityExportData<Customer> exportData = exportSingleEntity(customer.getId());
EntityImportResult<Customer> importResult = importEntities(List.of(exportData)).get(0);
checkImportedEntity(tenantId1, customer, tenantId1, importResult);
checkImportedCustomerData(customer, importResult.getSavedEntity());
}
private 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());
}
@Test
public void testExportImportDeviceWithProfile_betweenTenants() throws Exception {
logInAsTenantAdmin1();
DeviceProfile deviceProfile = createDeviceProfile(tenantId1, "Device profile of tenant 1"); DeviceProfile deviceProfile = createDeviceProfile(tenantId1, "Device profile of tenant 1");
DeviceProfileId importedDeviceProfileId = testExportImportBetweenTenants(deviceProfile, importedDeviceProfile -> {
assertThat(importedDeviceProfile.getName()).isEqualTo(deviceProfile.getName());
assertThat(importedDeviceProfile.getType()).isEqualTo(deviceProfile.getType());
assertThat(importedDeviceProfile.getTransportType()).isEqualTo(deviceProfile.getTransportType());
assertThat(importedDeviceProfile.getProfileData()).isEqualTo(deviceProfile.getProfileData());
assertThat(importedDeviceProfile.getDescription()).isEqualTo(deviceProfile.getDescription());
}).getSavedEntity().getId();
Device device = createDevice(tenantId1, null, deviceProfile.getId(), "Device of tenant 1"); Device device = createDevice(tenantId1, null, deviceProfile.getId(), "Device of tenant 1");
DeviceCredentials credentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId1, device.getId()); DeviceCredentials credentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId1, device.getId());
this.<Device, DeviceExportData>testExportImportBetweenTenants(device, deviceExportData -> {
assertThat(deviceExportData.getCredentials()).isEqualTo(credentials); EntityExportData<DeviceProfile> profileExportData = exportSingleEntity(deviceProfile.getId());
}, importedDevice -> { assertThat(profileExportData.getEntity()).isEqualTo(deviceProfile);
assertThat(importedDevice.getName()).isEqualTo(device.getName());
assertThat(importedDevice.getType()).isEqualTo(device.getType()); EntityExportData<Device> deviceExportData = exportSingleEntity(device.getId());
assertThat(importedDevice.getDeviceData()).isEqualTo(device.getDeviceData()); assertThat(deviceExportData.getEntity()).isEqualTo(device);
assertThat(importedDevice.getDeviceProfileId()).isEqualTo(importedDeviceProfileId); assertThat(((DeviceExportData) deviceExportData).getCredentials()).isEqualTo(credentials);
assertThat(importedDevice.getLabel()).isEqualTo(device.getLabel()); DeviceCredentials exportedCredentials = ((DeviceExportData) deviceExportData).getCredentials();
exportedCredentials.setCredentialsId(credentials.getCredentialsId() + "a");
logInAsTenantAdmin2();
EntityImportResult<DeviceProfile> profileImportResult = importEntities(List.of(profileExportData)).get(0);
checkImportedEntity(tenantId1, deviceProfile, tenantId2, profileImportResult);
checkImportedDeviceProfileData(deviceProfile, profileImportResult.getSavedEntity());
EntityImportResult<Device> deviceImportResult = importEntities(List.of(deviceExportData)).get(0);
Device importedDevice = deviceImportResult.getSavedEntity();
checkImportedEntity(tenantId1, device, tenantId2, deviceImportResult);
checkImportedDeviceData(device, importedDevice);
assertThat(importedDevice.getDeviceProfileId()).isEqualTo(profileImportResult.getSavedEntity().getId());
DeviceCredentials importedCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId2, importedDevice.getId()); DeviceCredentials importedCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId2, importedDevice.getId());
assertThat(importedCredentials.getCredentialsId()).isEqualTo(credentials.getCredentialsId()); assertThat(importedCredentials.getId()).isNotEqualTo(credentials.getId());
assertThat(importedCredentials.getCredentialsId()).isEqualTo(exportedCredentials.getCredentialsId());
assertThat(importedCredentials.getCredentialsValue()).isEqualTo(credentials.getCredentialsValue()); assertThat(importedCredentials.getCredentialsValue()).isEqualTo(credentials.getCredentialsValue());
assertThat(importedCredentials.getCredentialsType()).isEqualTo(credentials.getCredentialsType()); assertThat(importedCredentials.getCredentialsType()).isEqualTo(credentials.getCredentialsType());
}); }
@Test
public void testExportImportDevice_sameTenant() throws Exception {
logInAsTenantAdmin1();
DeviceProfile deviceProfile = createDeviceProfile(tenantId1, "Device profile v1.0");
Device device = createDevice(tenantId1, null, deviceProfile.getId(), "Device v1.0");
DeviceCredentials credentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId1, device.getId());
EntityExportData<Device> deviceExportData = exportSingleEntity(device.getId());
EntityImportResult<Device> importResult = importEntities(List.of(deviceExportData)).get(0);
Device importedDevice = importResult.getSavedEntity();
checkImportedEntity(tenantId1, device, tenantId1, importResult);
assertThat(importedDevice.getDeviceProfileId()).isEqualTo(device.getDeviceProfileId());
assertThat(deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId1, device.getId())).isEqualTo(credentials);
}
private 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());
}
private 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());
}
@Test
public void testExportImportSingleRuleChain_betweenTenants() throws Exception {
logInAsTenantAdmin1();
RuleChain ruleChain = createRuleChain(tenantId1, "Rule chain of tenant 1"); RuleChain ruleChain = createRuleChain(tenantId1, "Rule chain of tenant 1");
RuleChainMetaData metaData = ruleChainService.loadRuleChainMetaData(tenantId1, ruleChain.getId()); RuleChainMetaData metaData = ruleChainService.loadRuleChainMetaData(tenantId1, ruleChain.getId());
this.<RuleChain, RuleChainExportData>testExportImportBetweenTenants(ruleChain, ruleChainExportData -> {
assertThat(ruleChainExportData.getMetaData()).isEqualTo(metaData); EntityExportData<RuleChain> exportData = exportSingleEntity(ruleChain.getId());
}, importedRuleChain -> { assertThat(exportData.getEntity()).isEqualTo(ruleChain);
assertThat(importedRuleChain.getType()).isEqualTo(ruleChain.getType()); assertThat(((RuleChainExportData) exportData).getMetaData()).isEqualTo(metaData);
assertThat(importedRuleChain.getName()).isEqualTo(ruleChain.getName());
assertThat(importedRuleChain.isDebugMode()).isEqualTo(ruleChain.isDebugMode()); logInAsTenantAdmin2();
assertThat(importedRuleChain.getConfiguration()).isEqualTo(ruleChain.getConfiguration()); EntityImportResult<RuleChain> importResult = importEntities(List.of(exportData)).get(0);
RuleChain importedRuleChain = importResult.getSavedEntity();
RuleChainMetaData importedMetaData = ruleChainService.loadRuleChainMetaData(tenantId2, importedRuleChain.getId()); RuleChainMetaData importedMetaData = ruleChainService.loadRuleChainMetaData(tenantId2, importedRuleChain.getId());
assertThat(importedMetaData.getConnections()).isEqualTo(metaData.getConnections());
assertThat(importedMetaData.getFirstNodeIndex()).isEqualTo(metaData.getFirstNodeIndex()); checkImportedEntity(tenantId1, ruleChain, tenantId2, importResult);
for (int i = 0; i < metaData.getNodes().size(); i++) { checkImportedRuleChainData(ruleChain, metaData, importedRuleChain, importedMetaData);
RuleNode initialNode = metaData.getNodes().get(i); }
@Test
public void testExportImportSingleRuleChain_sameTenant() throws Exception {
logInAsTenantAdmin1();
RuleChain ruleChain = createRuleChain(tenantId1, "Rule chain v1.0");
RuleChainMetaData metaData = ruleChainService.loadRuleChainMetaData(tenantId1, ruleChain.getId());
EntityExportData<RuleChain> exportData = exportSingleEntity(ruleChain.getId());
EntityImportResult<RuleChain> importResult = importEntities(List.of(exportData)).get(0);
RuleChain importedRuleChain = importResult.getSavedEntity();
RuleChainMetaData importedMetaData = ruleChainService.loadRuleChainMetaData(tenantId1, importedRuleChain.getId());
checkImportedEntity(tenantId1, ruleChain, tenantId1, importResult);
checkImportedRuleChainData(ruleChain, metaData, importedRuleChain, importedMetaData);
}
private 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); RuleNode importedNode = importedMetaData.getNodes().get(i);
assertThat(importedNode.getRuleChainId()).isEqualTo(importedRuleChain.getId());
assertThat(importedNode.getName()).isEqualTo(initialNode.getName()); assertThat(importedNode.getName()).isEqualTo(initialNode.getName());
assertThat(importedNode.getType()).isEqualTo(initialNode.getType()); assertThat(importedNode.getType()).isEqualTo(initialNode.getType());
assertThat(importedNode.getConfiguration()).isEqualTo(initialNode.getConfiguration()); assertThat(importedNode.getConfiguration()).isEqualTo(initialNode.getConfiguration());
assertThat(importedNode.getAdditionalInfo()).isEqualTo(initialNode.getAdditionalInfo()); assertThat(importedNode.getAdditionalInfo()).isEqualTo(initialNode.getAdditionalInfo());
} }
});
Dashboard dashboard = createDashboard(tenantId1, null, "Dashboard of tenant 1");
testExportImportBetweenTenants(dashboard, importedDashboard -> {
assertThat(importedDashboard.getTitle()).isEqualTo(dashboard.getTitle());
assertThat(importedDashboard.getConfiguration()).isEqualTo(dashboard.getConfiguration());
assertThat(importedDashboard.getImage()).isEqualTo(dashboard.getImage());
assertThat(importedDashboard.isMobileHide()).isEqualTo(dashboard.isMobileHide());
});
} }
private <E extends ExportableEntity<?>, D extends EntityExportData<E>> EntityImportResult<E> testExportImportBetweenTenants(E entity, Consumer<D> exportDataRequirements, Consumer<E> importedEntityRequirements) throws Exception {
@Test
public void testExportImportSingleDashboard_betweenTenants() throws Exception {
logInAsTenantAdmin1(); logInAsTenantAdmin1();
D exportData = readResponse(doPost("/api/entities/export/" + entity.getId().getEntityType() + "/" + entity.getId()) Dashboard dashboard = createDashboard(tenantAdmin1.getTenantId(), null, "Dashboard of tenant 1");
.andExpect(status().isOk()), new TypeReference<D>() {});
assertThat(exportData.getEntity()).isEqualTo(entity); EntityExportData<Dashboard> exportData = exportSingleEntity(dashboard.getId());
exportDataRequirements.accept(exportData); assertThat(exportData.getEntity()).isEqualTo(dashboard);
logInAsTenantAdmin2(); logInAsTenantAdmin2();
EntityImportResult<E> importResult = importEntities(List.of(exportData)).get(0); EntityImportResult<Dashboard> importResult = importEntities(List.of(exportData)).get(0);
checkImportedEntity(tenantId1, dashboard, tenantId2, importResult);
E importedEntity = (E) exportableEntitiesService.findEntityById(tenantId2, importResult.getSavedEntity().getId()); checkImportedDashboardData(dashboard, importResult.getSavedEntity());
assertThat(importedEntity).isNotNull();
assertThat(importResult.getSavedEntity()).isEqualTo(importedEntity);
assertThat(importResult.getOldEntity()).isNull();
assertThat(importedEntity.getId()).isNotEqualTo(entity.getId());
assertThat(importedEntity.getExternalId()).isEqualTo(entity.getId());
assertThat(importedEntity.getTenantId()).isEqualTo(tenantId2);
importedEntityRequirements.accept(importedEntity);
return importResult;
} }
private <E extends ExportableEntity<?>> EntityImportResult<E> testExportImportBetweenTenants(E entity, Consumer<E> importedEntityRequirements) throws Exception { @Test
return testExportImportBetweenTenants(entity, exportData -> {}, importedEntityRequirements); public void testExportImportSingleDashboard_sameTenant() throws Exception {
logInAsTenantAdmin1();
Dashboard dashboard = createDashboard(tenantAdmin1.getTenantId(), null, "Dashboard v1.0");
EntityExportData<Dashboard> exportData = exportSingleEntity(dashboard.getId());
EntityImportResult<Dashboard> importResult = importEntities(List.of(exportData)).get(0);
checkImportedEntity(tenantId1, dashboard, tenantId1, importResult);
checkImportedDashboardData(dashboard, importResult.getSavedEntity());
}
private 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());
}
}
private <E extends ExportableEntity<?>> void checkImportedEntity(TenantId tenantId1, E initialEntity, TenantId tenantId2, EntityImportResult<E> importResult) {
E importedEntity = importResult.getSavedEntity();
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());
assertThat(importResult.getOldEntity()).isEqualTo(initialEntity);
}
} }
@ -217,6 +391,12 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
} }
} }
private <E extends ExportableEntity<I>, I extends EntityId> EntityExportData<E> exportSingleEntity(I entityId) throws Exception {
return readResponse(doPost("/api/entities/export/" + entityId.getEntityType() + "/" + entityId.getId().toString())
.andExpect(status().isOk()), new TypeReference<EntityExportData<E>>() {});
}
private void logInAsTenantAdmin1() throws Exception { private void logInAsTenantAdmin1() throws Exception {
login(tenantAdmin1.getEmail(), "12345678"); login(tenantAdmin1.getEmail(), "12345678");
} }

View File

@ -15,16 +15,12 @@
*/ */
package org.thingsboard.server.dao; package org.thingsboard.server.dao;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.ExportableEntity;
import java.util.UUID; import java.util.UUID;
public interface ExportableEntityDao<T> { public interface ExportableEntityDao<T extends ExportableEntity<?>> extends TenantEntityDao<T> {
T findByTenantIdAndExternalId(UUID tenantId, UUID externalId); T findByTenantIdAndExternalId(UUID tenantId, UUID externalId);
T findByTenantIdAndId(UUID tenantId, UUID id);
EntityType getEntityType();
} }

View File

@ -17,10 +17,8 @@ package org.thingsboard.server.dao;
import java.util.UUID; import java.util.UUID;
public interface ExportableEntityRepository<D> { public interface ExportableEntityRepository<D> extends TenantEntityRepository<D> {
D findByTenantIdAndExternalId(UUID tenantId, UUID externalId); D findByTenantIdAndExternalId(UUID tenantId, UUID externalId);
D findByTenantIdAndId(UUID tenantId, UUID id);
} }

View File

@ -15,9 +15,18 @@
*/ */
package org.thingsboard.server.dao; package org.thingsboard.server.dao;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
public interface TenantEntityDao { import java.util.UUID;
public interface TenantEntityDao<T extends HasTenantId> {
Long countByTenantId(TenantId tenantId); Long countByTenantId(TenantId tenantId);
T findByTenantIdAndId(UUID tenantId, UUID id);
EntityType getEntityType();
} }

View File

@ -0,0 +1,26 @@
/**
* 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.dao;
import java.util.UUID;
public interface TenantEntityRepository<D> {
D findByTenantIdAndId(UUID tenantId, UUID id);
Long countByTenantId(UUID tenantId);
}

View File

@ -34,7 +34,7 @@ import java.util.UUID;
* The Interface AssetDao. * The Interface AssetDao.
* *
*/ */
public interface AssetDao extends Dao<Asset>, TenantEntityDao, ExportableEntityDao<Asset> { public interface AssetDao extends Dao<Asset>, ExportableEntityDao<Asset> {
/** /**
* Find asset info by id. * Find asset info by id.

View File

@ -29,7 +29,7 @@ import java.util.UUID;
/** /**
* The Interface CustomerDao. * The Interface CustomerDao.
*/ */
public interface CustomerDao extends Dao<Customer>, TenantEntityDao, ExportableEntityDao<Customer> { public interface CustomerDao extends Dao<Customer>, ExportableEntityDao<Customer> {
/** /**
* Save or update customer object * Save or update customer object

View File

@ -24,7 +24,7 @@ import org.thingsboard.server.dao.TenantEntityDao;
/** /**
* The Interface DashboardDao. * The Interface DashboardDao.
*/ */
public interface DashboardDao extends Dao<Dashboard>, TenantEntityDao, ExportableEntityDao<Dashboard> { public interface DashboardDao extends Dao<Dashboard>, ExportableEntityDao<Dashboard> {
/** /**
* Save or update dashboard object * Save or update dashboard object

View File

@ -36,7 +36,7 @@ import java.util.UUID;
* The Interface DeviceDao. * The Interface DeviceDao.
* *
*/ */
public interface DeviceDao extends Dao<Device>, TenantEntityDao, ExportableEntityDao<Device> { public interface DeviceDao extends Dao<Device>, ExportableEntityDao<Device> {
/** /**
* Find device info by id. * Find device info by id.

View File

@ -21,6 +21,6 @@ import org.thingsboard.server.dao.Dao;
import org.thingsboard.server.dao.TenantEntityDao; import org.thingsboard.server.dao.TenantEntityDao;
import org.thingsboard.server.dao.TenantEntityWithDataDao; import org.thingsboard.server.dao.TenantEntityWithDataDao;
public interface OtaPackageDao extends Dao<OtaPackage>, TenantEntityWithDataDao { public interface OtaPackageDao extends Dao<OtaPackage>, TenantEntityWithDataDao, TenantEntityDao<OtaPackage> {
Long sumDataSizeByTenantId(TenantId tenantId); Long sumDataSizeByTenantId(TenantId tenantId);
} }

View File

@ -30,7 +30,7 @@ import java.util.UUID;
/** /**
* Created by igor on 3/12/18. * Created by igor on 3/12/18.
*/ */
public interface RuleChainDao extends Dao<RuleChain>, TenantEntityDao, ExportableEntityDao<RuleChain> { public interface RuleChainDao extends Dao<RuleChain>, ExportableEntityDao<RuleChain> {
/** /**
* Find rule chains by tenantId and page link. * Find rule chains by tenantId and page link.

View File

@ -38,5 +38,4 @@ public interface CustomerRepository extends JpaRepository<CustomerEntity, UUID>,
CustomerEntity findByTenantIdAndTitle(UUID tenantId, String title); CustomerEntity findByTenantIdAndTitle(UUID tenantId, String title);
Long countByTenantId(UUID tenantId);
} }

View File

@ -116,6 +116,11 @@ public class JpaDeviceProfileDao extends JpaAbstractSearchTextDao<DeviceProfileE
return DaoUtil.getData(deviceProfileRepository.findByTenantIdAndExternalId(tenantId, externalId)); return DaoUtil.getData(deviceProfileRepository.findByTenantIdAndExternalId(tenantId, externalId));
} }
@Override
public Long countByTenantId(TenantId tenantId) {
return deviceProfileRepository.countByTenantId(tenantId.getId());
}
@Override @Override
public DeviceProfile findByTenantIdAndId(UUID tenantId, UUID id) { public DeviceProfile findByTenantIdAndId(UUID tenantId, UUID id) {
return DaoUtil.getData(deviceProfileRepository.findByTenantIdAndId(tenantId, id)); return DaoUtil.getData(deviceProfileRepository.findByTenantIdAndId(tenantId, id));

View File

@ -19,8 +19,10 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.OtaPackage; import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.ota.OtaPackageDao; import org.thingsboard.server.dao.ota.OtaPackageDao;
import org.thingsboard.server.dao.model.sql.OtaPackageEntity; import org.thingsboard.server.dao.model.sql.OtaPackageEntity;
import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
@ -48,4 +50,20 @@ public class JpaOtaPackageDao extends JpaAbstractSearchTextDao<OtaPackageEntity,
public Long sumDataSizeByTenantId(TenantId tenantId) { public Long sumDataSizeByTenantId(TenantId tenantId) {
return otaPackageRepository.sumDataSizeByTenantId(tenantId.getId()); return otaPackageRepository.sumDataSizeByTenantId(tenantId.getId());
} }
@Override
public Long countByTenantId(TenantId tenantId) {
return otaPackageRepository.countByTenantId(tenantId.getId());
}
@Override
public OtaPackage findByTenantIdAndId(UUID tenantId, UUID id) {
return DaoUtil.getData(otaPackageRepository.findByTenantIdAndId(tenantId, id));
}
@Override
public EntityType getEntityType() {
return EntityType.OTA_PACKAGE;
}
} }

View File

@ -18,11 +18,12 @@ package org.thingsboard.server.dao.sql.ota;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
import org.thingsboard.server.dao.TenantEntityRepository;
import org.thingsboard.server.dao.model.sql.OtaPackageEntity; import org.thingsboard.server.dao.model.sql.OtaPackageEntity;
import java.util.UUID; import java.util.UUID;
public interface OtaPackageRepository extends JpaRepository<OtaPackageEntity, UUID> { public interface OtaPackageRepository extends JpaRepository<OtaPackageEntity, UUID>, TenantEntityRepository<OtaPackageEntity> {
@Query(value = "SELECT COALESCE(SUM(ota.data_size), 0) FROM ota_package ota WHERE ota.tenant_id = :tenantId AND ota.data IS NOT NULL", nativeQuery = true) @Query(value = "SELECT COALESCE(SUM(ota.data_size), 0) FROM ota_package ota WHERE ota.tenant_id = :tenantId AND ota.data IS NOT NULL", nativeQuery = true)
Long sumDataSizeByTenantId(@Param("tenantId") UUID tenantId); Long sumDataSizeByTenantId(@Param("tenantId") UUID tenantId);
} }

View File

@ -63,8 +63,6 @@ public interface RuleChainRepository extends JpaRepository<RuleChainEntity, UUID
RuleChainEntity findByTenantIdAndTypeAndRootIsTrue(UUID tenantId, RuleChainType ruleChainType); RuleChainEntity findByTenantIdAndTypeAndRootIsTrue(UUID tenantId, RuleChainType ruleChainType);
Long countByTenantId(UUID tenantId);
List<RuleChainEntity> findByTenantIdAndTypeAndName(UUID tenantId, RuleChainType type, String name); List<RuleChainEntity> findByTenantIdAndTypeAndName(UUID tenantId, RuleChainType type, String name);
} }

View File

@ -18,6 +18,8 @@ package org.thingsboard.server.dao.sql.user;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
@ -96,4 +98,15 @@ public class JpaUserDao extends JpaAbstractSearchTextDao<UserEntity, User> imple
public Long countByTenantId(TenantId tenantId) { public Long countByTenantId(TenantId tenantId) {
return userRepository.countByTenantId(tenantId.getId()); return userRepository.countByTenantId(tenantId.getId());
} }
@Override
public User findByTenantIdAndId(UUID tenantId, UUID id) {
return DaoUtil.getData(userRepository.findByTenantIdAndId(tenantId, id));
}
@Override
public EntityType getEntityType() {
return EntityType.USER;
}
} }

View File

@ -21,6 +21,8 @@ import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.dao.TenantEntityDao;
import org.thingsboard.server.dao.TenantEntityRepository;
import org.thingsboard.server.dao.model.sql.UserEntity; import org.thingsboard.server.dao.model.sql.UserEntity;
import java.util.UUID; import java.util.UUID;
@ -28,7 +30,7 @@ import java.util.UUID;
/** /**
* @author Valerii Sosliuk * @author Valerii Sosliuk
*/ */
public interface UserRepository extends JpaRepository<UserEntity, UUID> { public interface UserRepository extends JpaRepository<UserEntity, UUID>, TenantEntityRepository<UserEntity> {
UserEntity findByEmail(String email); UserEntity findByEmail(String email);
@ -47,5 +49,4 @@ public interface UserRepository extends JpaRepository<UserEntity, UUID> {
@Param("searchText") String searchText, @Param("searchText") String searchText,
Pageable pageable); Pageable pageable);
Long countByTenantId(UUID tenantId);
} }

View File

@ -24,7 +24,7 @@ import org.thingsboard.server.dao.TenantEntityDao;
import java.util.UUID; import java.util.UUID;
public interface UserDao extends Dao<User>, TenantEntityDao { public interface UserDao extends Dao<User>, TenantEntityDao<User> {
/** /**
* Save or update user object * Save or update user object