More tests for export/import api; improvements

This commit is contained in:
Viacheslav Klimov 2022-04-12 13:04:25 +03:00
parent a35b16d7cb
commit c04a0ff3a6
18 changed files with 881 additions and 269 deletions

View File

@ -17,13 +17,13 @@ package org.thingsboard.server.controller;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
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.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
@ -41,9 +41,9 @@ import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.EntitiesExportImportService;
import org.thingsboard.server.service.sync.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.exporting.data.request.EntityFilterExportRequest;
import org.thingsboard.server.service.sync.exporting.data.request.CustomEntityFilterExportRequest;
import org.thingsboard.server.service.sync.exporting.data.request.CustomEntityQueryExportRequest;
import org.thingsboard.server.service.sync.exporting.data.request.EntityListExportRequest;
import org.thingsboard.server.service.sync.exporting.data.request.EntityQueryExportRequest;
import org.thingsboard.server.service.sync.exporting.data.request.EntityTypeExportRequest;
import org.thingsboard.server.service.sync.exporting.data.request.ExportRequest;
import org.thingsboard.server.service.sync.exporting.data.request.SingleEntityExportRequest;
@ -71,7 +71,7 @@ public class EntitiesExportImportController extends BaseController {
@PostMapping("/export")
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
public List<EntityExportData<ExportableEntity<EntityId>>> exportEntities(@RequestBody ExportRequest exportRequest) throws ThingsboardException {
public List<EntityExportData<?>> exportEntities(@RequestBody ExportRequest exportRequest) throws ThingsboardException {
SecurityUser user = getCurrentUser();
try {
return exportEntitiesByRequest(user, exportRequest);
@ -82,10 +82,10 @@ public class EntitiesExportImportController extends BaseController {
@PostMapping(value = "/export", params = {"multiple"})
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
public List<EntityExportData<ExportableEntity<EntityId>>> exportEntities(@RequestBody List<ExportRequest> exportRequests) throws ThingsboardException {
public List<EntityExportData<?>> exportEntities(@RequestBody List<ExportRequest> exportRequests) throws ThingsboardException {
SecurityUser user = getCurrentUser();
try {
List<EntityExportData<ExportableEntity<EntityId>>> exportDataList = new ArrayList<>();
List<EntityExportData<?>> exportDataList = new ArrayList<>();
for (ExportRequest exportRequest : exportRequests) {
exportDataList.addAll(exportEntitiesByRequest(user, exportRequest));
}
@ -96,10 +96,10 @@ public class EntitiesExportImportController extends BaseController {
}
private List<EntityExportData<ExportableEntity<EntityId>>> exportEntitiesByRequest(SecurityUser user, ExportRequest request) throws ThingsboardException {
private List<EntityExportData<?>> exportEntitiesByRequest(SecurityUser user, ExportRequest request) throws ThingsboardException {
List<EntityId> entitiesIds = findEntitiesForRequest(user, request);
List<EntityExportData<ExportableEntity<EntityId>>> exportDataList = new ArrayList<>();
List<EntityExportData<?>> exportDataList = new ArrayList<>();
for (EntityId entityId : entitiesIds) {
exportDataList.add(exportImportService.exportEntity(user, entityId, request.getExportSettings()));
}
@ -122,15 +122,15 @@ public class EntitiesExportImportController extends BaseController {
CustomerId customerId = Optional.ofNullable(exportRequest.getCustomerId()).orElse(emptyId(EntityType.CUSTOMER));
return findEntitiesByFilter(user.getTenantId(), customerId, entityTypeFilter, exportRequest.getPage(), exportRequest.getPageSize());
}
case ENTITY_FILTER: {
EntityFilterExportRequest exportRequest = (EntityFilterExportRequest) request;
case CUSTOM_ENTITY_FILTER: {
CustomEntityFilterExportRequest exportRequest = (CustomEntityFilterExportRequest) request;
EntityFilter filter = exportRequest.getFilter();
CustomerId customerId = Optional.ofNullable(exportRequest.getCustomerId()).orElse(emptyId(EntityType.CUSTOMER));
return findEntitiesByFilter(user.getTenantId(), customerId, filter, exportRequest.getPage(), exportRequest.getPageSize());
}
case ENTITY_QUERY:{
EntityQueryExportRequest exportRequest = (EntityQueryExportRequest) request;
case CUSTOM_ENTITY_QUERY: {
CustomEntityQueryExportRequest exportRequest = (CustomEntityQueryExportRequest) request;
EntityDataQuery query = exportRequest.getQuery();
CustomerId customerId = Optional.ofNullable(exportRequest.getCustomerId()).orElse(emptyId(EntityType.CUSTOMER));
@ -153,24 +153,29 @@ public class EntitiesExportImportController extends BaseController {
}
private List<EntityId> findEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query) {
return entityService.findEntityDataByQuery(tenantId, customerId, query).getData().stream()
.map(EntityData::getEntityId)
.collect(Collectors.toList());
try {
return entityService.findEntityDataByQuery(tenantId, customerId, query).getData().stream()
.map(EntityData::getEntityId)
.collect(Collectors.toList());
} catch (DataAccessException e) {
log.error("Failed to find entity data by query: {}", e.getMessage());
throw new IllegalArgumentException("Entity filter cannot be processed");
}
}
@PostMapping("/import")
public List<EntityImportResult<ExportableEntity<EntityId>>> importEntities(@RequestBody ImportRequest importRequest) throws ThingsboardException {
public List<EntityImportResult<?>> importEntities(@RequestBody ImportRequest importRequest) throws ThingsboardException {
SecurityUser user = getCurrentUser();
try {
List<EntityImportResult<ExportableEntity<EntityId>>> importResults = exportImportService.importEntities(user, importRequest.getExportDataList(), importRequest.getImportSettings());
List<EntityImportResult<?>> importResults = exportImportService.importEntities(user, importRequest.getExportDataList(), importRequest.getImportSettings());
importResults.stream()
.map(EntityImportResult::getPushEventsCallback)
.map(EntityImportResult::getSendEventsCallback)
.filter(Objects::nonNull)
.forEach(pushEventsCallback -> {
.forEach(sendEventsCallback -> {
try {
pushEventsCallback.run();
sendEventsCallback.run();
} catch (Exception e) {
log.error("Failed to send event for entity", e);
}

View File

@ -67,7 +67,7 @@ public class DefaultEntitiesExportImportService implements EntitiesExportImportS
protected static final List<EntityType> SUPPORTED_ENTITY_TYPES = List.of(
EntityType.CUSTOMER, EntityType.ASSET, EntityType.RULE_CHAIN,
EntityType.DEVICE_PROFILE, EntityType.DEVICE, EntityType.DASHBOARD
EntityType.DASHBOARD, EntityType.DEVICE_PROFILE, EntityType.DEVICE
);
@ -82,12 +82,12 @@ public class DefaultEntitiesExportImportService implements EntitiesExportImportS
@Transactional(rollbackFor = Exception.class)
@Override
public List<EntityImportResult<ExportableEntity<EntityId>>> importEntities(SecurityUser user, List<EntityExportData<ExportableEntity<EntityId>>> exportDataList, EntityImportSettings importSettings) throws ThingsboardException {
public List<EntityImportResult<?>> importEntities(SecurityUser user, List<EntityExportData<?>> exportDataList, EntityImportSettings importSettings) throws ThingsboardException {
exportDataList.sort(Comparator.comparing(exportData -> SUPPORTED_ENTITY_TYPES.indexOf(exportData.getEntityType())));
List<EntityImportResult<ExportableEntity<EntityId>>> importResults = new ArrayList<>();
List<EntityImportResult<?>> importResults = new ArrayList<>();
for (EntityExportData<ExportableEntity<EntityId>> exportData : exportDataList) {
EntityImportResult<ExportableEntity<EntityId>> importResult = importEntity(user, exportData, importSettings);
for (EntityExportData exportData : exportDataList) {
EntityImportResult<?> importResult = importEntity(user, exportData, importSettings);
importResults.add(importResult);
}

View File

@ -30,6 +30,6 @@ public interface EntitiesExportImportService {
<E extends ExportableEntity<I>, I extends EntityId> EntityExportData<E> exportEntity(SecurityUser user, I entityId, EntityExportSettings exportSettings) throws ThingsboardException;
List<EntityImportResult<ExportableEntity<EntityId>>> importEntities(SecurityUser user, List<EntityExportData<ExportableEntity<EntityId>>> exportDataList, EntityImportSettings importSettings) throws ThingsboardException;
List<EntityImportResult<?>> importEntities(SecurityUser user, List<EntityExportData<?>> exportDataList, EntityImportSettings importSettings) throws ThingsboardException;
}

View File

@ -21,21 +21,16 @@ import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import lombok.Data;
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.ExportableEntity;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.utils.JsonTbEntity;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "entityType", defaultImpl = EntityExportData.class, visible = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "entityType", defaultImpl = EntityExportData.class)
@JsonSubTypes({
@Type(name = "DEVICE", value = DeviceExportData.class),
@Type(name = "RULE_CHAIN", value = RuleChainExportData.class)
@ -44,15 +39,7 @@ import java.util.List;
@Data
public class EntityExportData<E extends ExportableEntity<? extends EntityId>> {
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "entityType", include = JsonTypeInfo.As.EXTERNAL_PROPERTY)
@JsonSubTypes({
@Type(name = "DEVICE", value = Device.class),
@Type(name = "RULE_CHAIN", value = RuleChain.class),
@Type(name = "DEVICE_PROFILE", value = DeviceProfile.class),
@Type(name = "ASSET", value = Asset.class),
@Type(name = "DASHBOARD", value = Dashboard.class),
@Type(name = "CUSTOMER", value = Customer.class)
})
@JsonTbEntity
private E entity;
private EntityType entityType;

View File

@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.query.EntityFilter;
@EqualsAndHashCode(callSuper = true)
@Data
public class EntityFilterExportRequest extends ExportRequest {
public class CustomEntityFilterExportRequest extends ExportRequest {
private EntityFilter filter;
private int page;
@ -31,7 +31,7 @@ public class EntityFilterExportRequest extends ExportRequest {
@Override
public ExportRequestType getType() {
return ExportRequestType.ENTITY_FILTER;
return ExportRequestType.CUSTOM_ENTITY_FILTER;
}
}

View File

@ -22,14 +22,14 @@ import org.thingsboard.server.common.data.query.EntityDataQuery;
@EqualsAndHashCode(callSuper = true)
@Data
public class EntityQueryExportRequest extends ExportRequest {
public class CustomEntityQueryExportRequest extends ExportRequest {
private EntityDataQuery query;
private CustomerId customerId;
@Override
public ExportRequestType getType() {
return ExportRequestType.ENTITY_QUERY;
return ExportRequestType.CUSTOM_ENTITY_QUERY;
}
}

View File

@ -15,7 +15,6 @@
*/
package org.thingsboard.server.service.sync.exporting.data.request;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
@ -27,15 +26,14 @@ import lombok.Data;
@Type(name = "SINGLE_ENTITY", value = SingleEntityExportRequest.class),
@Type(name = "ENTITY_LIST", value = EntityListExportRequest.class),
@Type(name = "ENTITY_TYPE", value = EntityTypeExportRequest.class),
@Type(name = "ENTITY_FILTER", value = EntityFilterExportRequest.class),
@Type(name = "ENTITY_QUERY", value = EntityQueryExportRequest.class)
@Type(name = "CUSTOM_ENTITY_FILTER", value = CustomEntityFilterExportRequest.class),
@Type(name = "CUSTOM_ENTITY_QUERY", value = CustomEntityQueryExportRequest.class)
})
@Data
public abstract class ExportRequest {
private EntityExportSettings exportSettings;
@JsonIgnore
public abstract ExportRequestType getType();
}

View File

@ -20,6 +20,6 @@ public enum ExportRequestType {
ENTITY_LIST,
ENTITY_TYPE,
ENTITY_FILTER,
ENTITY_QUERY
CUSTOM_ENTITY_FILTER,
CUSTOM_ENTITY_QUERY
}

View File

@ -16,32 +16,33 @@
package org.thingsboard.server.service.sync.importing.data;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.Setter;
import lombok.Data;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.utils.JsonTbEntity;
import org.thingsboard.server.utils.ThrowingRunnable;
@Data
public class EntityImportResult<E extends ExportableEntity<? extends EntityId>> {
@Getter @Setter
@JsonTbEntity
private E savedEntity;
@Getter @Setter
@JsonTbEntity
private E oldEntity;
@Getter @Setter
private EntityType entityType;
@Getter @JsonIgnore
@JsonIgnore
private ThrowingRunnable saveReferencesCallback = () -> {};
@Getter @JsonIgnore
private ThrowingRunnable pushEventsCallback = () -> {};
@JsonIgnore
private ThrowingRunnable sendEventsCallback = () -> {};
public void addSaveReferencesCallback(ThrowingRunnable callback) {
this.saveReferencesCallback = this.saveReferencesCallback.andThen(callback);
}
public void addPushEventsCallback(ThrowingRunnable callback) {
this.pushEventsCallback = this.pushEventsCallback.andThen(callback);
public void addSendEventsCallback(ThrowingRunnable callback) {
this.sendEventsCallback = this.sendEventsCallback.andThen(callback);
}
}

View File

@ -26,8 +26,10 @@ import lombok.NoArgsConstructor;
@Builder
public class EntityImportSettings {
private boolean findExistingByName;
private boolean importInboundRelations;
private boolean importOutboundRelations;
private boolean removeExistingRelations;
private boolean updateReferencesToOtherEntities;
}

View File

@ -26,7 +26,7 @@ import java.util.List;
@Data
public class ImportRequest {
private List<EntityExportData<ExportableEntity<EntityId>>> exportDataList;
private List<EntityExportData<?>> exportDataList;
private EntityImportSettings importSettings;
}

View File

@ -21,7 +21,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.transaction.annotation.Transactional;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.HasCustomerId;
import org.thingsboard.server.common.data.audit.ActionType;
@ -76,6 +75,7 @@ public abstract class BaseEntityImportService<I extends EntityId, E extends Expo
exportableEntitiesService.checkPermission(user, entity, getEntityType(), Operation.CREATE);
} else {
entity.setId(existingEntity.getId());
entity.setCreatedTime(existingEntity.getCreatedTime());
exportableEntitiesService.checkPermission(user, existingEntity, getEntityType(), Operation.WRITE);
}
@ -146,7 +146,7 @@ public abstract class BaseEntityImportService<I extends EntityId, E extends Expo
}
});
importResult.addPushEventsCallback(() -> {
importResult.addSendEventsCallback(() -> {
onEntitySaved(user, savedEntity, oldEntity);
});
}
@ -172,8 +172,6 @@ public abstract class BaseEntityImportService<I extends EntityId, E extends Expo
}
private <ID extends EntityId> HasId<ID> findInternalEntity(TenantId tenantId, ID externalId) {
if (externalId == null || externalId.isNullUid()) return null;
return (HasId<ID>) Optional.ofNullable(exportableEntitiesService.findEntityByTenantIdAndExternalId(tenantId, externalId))
.or(() -> Optional.ofNullable(exportableEntitiesService.findEntityByTenantIdAndId(tenantId, externalId)))
.orElseThrow(() -> new IllegalArgumentException("Cannot find " + externalId.getEntityType() + " by external id " + externalId));
@ -187,19 +185,18 @@ public abstract class BaseEntityImportService<I extends EntityId, E extends Expo
private final E existingEntity;
private final EntityImportSettings importSettings;
private final Set<EntityType> ALWAYS_UPDATE_REFERENCED_IDS = Set.of(
EntityType.RULE_CHAIN
);
public <ID extends EntityId> ID get(Function<E, ID> idExtractor) {
if (existingEntity == null || importSettings.isUpdateReferencesToOtherEntities()
|| ALWAYS_UPDATE_REFERENCED_IDS.contains(getEntityType())) {
if (existingEntity == null || importSettings.isUpdateReferencesToOtherEntities()) {
return getInternalId(idExtractor.apply(this.entity));
} else {
return idExtractor.apply(existingEntity);
}
}
public <ID extends EntityId> ID getInternal(ID externalId) {
return getInternalId(externalId);
}
public <ID extends EntityId, T> Set<T> get(Function<E, Set<T>> listExtractor, Function<T, ID> idGetter, BiConsumer<T, ID> idSetter) {
if (existingEntity == null || importSettings.isUpdateReferencesToOtherEntities()) {
return Optional.ofNullable(listExtractor.apply(entity)).orElse(Collections.emptySet()).stream()
@ -213,17 +210,15 @@ public abstract class BaseEntityImportService<I extends EntityId, E extends Expo
}
private <ID extends EntityId> ID getInternalId(ID externalId) {
if (externalId == null || externalId.isNullUid()) return null;
HasId<ID> entity = findInternalEntity(user.getTenantId(), externalId);
if (entity != null) {
try {
exportableEntitiesService.checkPermission(user, entity, entity.getId().getEntityType(), Operation.READ);
} catch (ThingsboardException e) {
throw new IllegalArgumentException(e.getMessage(), e);
}
return entity.getId();
} else {
return null;
try {
exportableEntitiesService.checkPermission(user, entity, entity.getId().getEntityType(), Operation.READ);
} catch (ThingsboardException e) {
throw new IllegalArgumentException(e.getMessage(), e);
}
return entity.getId();
}
}

View File

@ -74,7 +74,7 @@ public class DashboardImportService extends BaseEntityImportService<DashboardId,
String newFilterJson = UUID_PATTERN.matcher(filterJson).replaceAll(matchResult -> {
String uuid = matchResult.group();
EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, uuid);
return idProvider.get(d -> entityId).toString();
return idProvider.getInternal(entityId).toString();
});
((ObjectNode) entityAlias).set("filter", JacksonUtil.toJsonNode(newFilterJson));
});
@ -86,7 +86,7 @@ public class DashboardImportService extends BaseEntityImportService<DashboardId,
dashboard.setAssignedCustomers(null);
dashboard = dashboardService.saveDashboard(dashboard);
for (ShortCustomerInfo customerInfo : assignedCustomers) {
dashboardService.assignDashboardToCustomer(tenantId, dashboard.getId(), customerInfo.getCustomerId());
dashboard = dashboardService.assignDashboardToCustomer(tenantId, dashboard.getId(), customerInfo.getCustomerId());
}
} else {
Set<CustomerId> existingAssignedCustomers = Optional.ofNullable(dashboardService.findDashboardById(tenantId, dashboard.getId()).getAssignedCustomers())

View File

@ -63,14 +63,14 @@ public class RuleChainImportService extends BaseEntityImportService<RuleChainId,
.map(JsonNode::asText).map(UUID::fromString)
.ifPresent(otherRuleChainUuid -> {
((ObjectNode) ruleNodeConfig).set("ruleChainId", new TextNode(
idProvider.get(rc -> new RuleChainId(otherRuleChainUuid)).toString()
idProvider.getInternal(new RuleChainId(otherRuleChainUuid)).toString()
));
ruleNode.setConfiguration(ruleNodeConfig);
});
});
Optional.ofNullable(metaData.getRuleChainConnections()).orElse(Collections.emptyList())
.forEach(ruleChainConnectionInfo -> {
ruleChainConnectionInfo.setTargetRuleChainId(idProvider.get(rc -> ruleChainConnectionInfo.getTargetRuleChainId()));
ruleChainConnectionInfo.setTargetRuleChainId(idProvider.getInternal(ruleChainConnectionInfo.getTargetRuleChainId()));
});
ruleChain.setFirstRuleNodeId(null);

View File

@ -0,0 +1,47 @@
/**
* 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.utils;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
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.asset.Asset;
import org.thingsboard.server.common.data.rule.RuleChain;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "entityType", include = JsonTypeInfo.As.EXTERNAL_PROPERTY)
@JsonSubTypes({
@Type(name = "DEVICE", value = Device.class),
@Type(name = "RULE_CHAIN", value = RuleChain.class),
@Type(name = "DEVICE_PROFILE", value = DeviceProfile.class),
@Type(name = "ASSET", value = Asset.class),
@Type(name = "DASHBOARD", value = Dashboard.class),
@Type(name = "CUSTOMER", value = Customer.class)
})
public @interface JsonTbEntity {
}

View File

@ -17,6 +17,8 @@ package org.thingsboard.server.controller;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.node.TextNode;
import org.junit.After;
import org.junit.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.web.servlet.ResultActions;
import org.thingsboard.common.util.JacksonUtil;
@ -28,6 +30,10 @@ 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.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;
@ -35,19 +41,29 @@ import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileCon
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.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.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.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.sync.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.exporting.data.request.EntityExportSettings;
import org.thingsboard.server.service.sync.exporting.data.request.ExportRequest;
@ -56,11 +72,12 @@ import org.thingsboard.server.service.sync.importing.data.EntityImportResult;
import org.thingsboard.server.service.sync.importing.data.EntityImportSettings;
import org.thingsboard.server.service.sync.importing.data.request.ImportRequest;
import java.lang.reflect.Type;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
public abstract class BaseEntitiesExportImportControllerTest extends AbstractControllerTest {
@ -68,6 +85,8 @@ public abstract class BaseEntitiesExportImportControllerTest extends AbstractCon
@Autowired
protected DeviceService deviceService;
@Autowired
protected OtaPackageService otaPackageService;
@Autowired
protected DeviceProfileService deviceProfileService;
@Autowired
protected AssetService assetService;
@ -77,6 +96,45 @@ public abstract class BaseEntitiesExportImportControllerTest extends AbstractCon
protected RuleChainService ruleChainService;
@Autowired
protected DashboardService dashboardService;
@Autowired
protected RelationService relationService;
@Autowired
protected TenantService tenantService;
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();
@ -91,13 +149,38 @@ public abstract class BaseEntitiesExportImportControllerTest extends AbstractCon
return deviceService.saveDevice(device);
}
protected DeviceProfile createDeviceProfile(TenantId tenantId, String name) {
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());
@ -105,6 +188,14 @@ public abstract class BaseEntitiesExportImportControllerTest extends AbstractCon
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);
@ -116,6 +207,13 @@ public abstract class BaseEntitiesExportImportControllerTest extends AbstractCon
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);
@ -127,6 +225,13 @@ public abstract class BaseEntitiesExportImportControllerTest extends AbstractCon
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);
@ -142,6 +247,16 @@ public abstract class BaseEntitiesExportImportControllerTest extends AbstractCon
return 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) {
RuleChain ruleChain = new RuleChain();
ruleChain.setTenantId(tenantId);
@ -178,6 +293,50 @@ public abstract class BaseEntitiesExportImportControllerTest extends AbstractCon
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 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> exportSingleEntity(I entityId) throws Exception {
SingleEntityExportRequest exportRequest = new SingleEntityExportRequest();
@ -186,33 +345,30 @@ public abstract class BaseEntitiesExportImportControllerTest extends AbstractCon
return (EntityExportData<E>) exportEntities(exportRequest).get(0);
}
protected List<EntityExportData<ExportableEntity<EntityId>>> exportEntities(ExportRequest exportRequest) throws Exception {
return getResponse(doPost("/api/entities/export", exportRequest), new TypeReference<List<EntityExportData<ExportableEntity<EntityId>>>>() {});
protected List<EntityExportData<?>> exportEntities(ExportRequest exportRequest) throws Exception {
return getResponse(doPost("/api/entities/export", exportRequest), new TypeReference<List<EntityExportData<?>>>() {});
}
protected List<EntityExportData<ExportableEntity<EntityId>>> exportEntities(List<ExportRequest> exportRequests) throws Exception {
return getResponse(doPost("/api/entities/export?multiple", exportRequests), new TypeReference<List<EntityExportData<ExportableEntity<EntityId>>>>() {});
protected List<EntityExportData<?>> exportEntities(List<ExportRequest> exportRequests) throws Exception {
return getResponse(doPost("/api/entities/export?multiple", exportRequests), new TypeReference<List<EntityExportData<?>>>() {});
}
protected <E extends ExportableEntity<I>, I extends EntityId> EntityImportResult<E> importEntity(EntityExportData<E> exportData) throws Exception {
return (EntityImportResult<E>) importEntities(List.of((EntityExportData<ExportableEntity<EntityId>>)exportData)).get(0);
return (EntityImportResult<E>) importEntities(List.of((EntityExportData<ExportableEntity<EntityId>>) exportData)).get(0);
}
protected List<EntityImportResult<ExportableEntity<EntityId>>> importEntities(List<EntityExportData<ExportableEntity<EntityId>>> exportDataList) throws Exception {
protected List<EntityImportResult<?>> importEntities(List<EntityExportData<?>> exportDataList) throws Exception {
ImportRequest importRequest = new ImportRequest();
importRequest.setImportSettings(EntityImportSettings.builder()
.updateReferencesToOtherEntities(true)
.build());
importRequest.setExportDataList(exportDataList);
return getResponse(doPost("/api/entities/import", importRequest), new TypeReference<List<EntityImportResult<ExportableEntity<EntityId>>>>() {
@Override
public Type getType() {
return mapper.getTypeFactory().constructCollectionType(List.class,
mapper.getTypeFactory().constructParametricType(EntityImportResult.class,
exportDataList.get(0).getEntity().getClass()));
}
});
return importEntities(importRequest);
}
protected List<EntityImportResult<?>> importEntities(ImportRequest importRequest) throws Exception {
return getResponse(doPost("/api/entities/import", importRequest), new TypeReference<List<EntityImportResult<?>>>() {});
}
protected <T> T getResponse(ResultActions resultActions, TypeReference<T> typeReference) throws Exception {
@ -223,4 +379,13 @@ public abstract class BaseEntitiesExportImportControllerTest extends AbstractCon
}
}
protected void logInAsTenantAdmin1() throws Exception {
login(tenantAdmin1.getEmail(), "12345678");
}
protected void logInAsTenantAdmin2() throws Exception {
login(tenantAdmin2.getEmail(), "12345678");
}
}

View File

@ -15,86 +15,81 @@
*/
package org.thingsboard.server.controller.sql;
import org.junit.After;
import org.junit.Before;
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.testcontainers.shaded.org.apache.commons.lang.RandomStringUtils;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.cluster.TbClusterService;
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.ExportableEntity;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
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.TenantId;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.data.query.EntityListFilter;
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.Authority;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.controller.BaseEntitiesExportImportControllerTest;
import org.thingsboard.server.dao.device.DeviceCredentialsService;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.service.sync.exporting.ExportableEntitiesService;
import org.thingsboard.server.service.action.EntityActionService;
import org.thingsboard.server.service.ota.OtaPackageStateService;
import org.thingsboard.server.service.sync.exporting.data.DeviceExportData;
import org.thingsboard.server.service.sync.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.exporting.data.RuleChainExportData;
import org.thingsboard.server.service.sync.exporting.data.request.CustomEntityFilterExportRequest;
import org.thingsboard.server.service.sync.exporting.data.request.EntityExportSettings;
import org.thingsboard.server.service.sync.exporting.data.request.EntityListExportRequest;
import org.thingsboard.server.service.sync.exporting.data.request.EntityTypeExportRequest;
import org.thingsboard.server.service.sync.exporting.data.request.ExportRequest;
import org.thingsboard.server.service.sync.exporting.data.request.SingleEntityExportRequest;
import org.thingsboard.server.service.sync.importing.data.EntityImportResult;
import org.thingsboard.server.service.sync.importing.data.EntityImportSettings;
import org.thingsboard.server.service.sync.importing.data.request.ImportRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
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.Mockito.verify;
@DaoSqlTest
public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImportControllerTest {
@Autowired
private TenantService tenantService;
@Autowired
private DeviceCredentialsService deviceCredentialsService;
@Autowired
private ExportableEntitiesService exportableEntitiesService;
private TenantId tenantId1;
private User tenantAdmin1;
private TenantId tenantId2;
private 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);
}
@SpyBean
private EntityActionService entityActionService;
@SpyBean
private TbClusterService clusterService;
@SpyBean
private OtaPackageStateService otaPackageStateService;
@Test
public void testExportImportSingleAsset_betweenTenants() throws Exception {
public void testExportImportAsset_betweenTenants() throws Exception {
logInAsTenantAdmin1();
Asset asset = createAsset(tenantId1, null, "AB", "Asset of tenant 1");
EntityExportData<Asset> exportData = exportSingleEntity(asset.getId());
@ -103,40 +98,24 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
logInAsTenantAdmin2();
EntityImportResult<Asset> importResult = importEntity(exportData);
checkImportedEntity(tenantId1, asset, tenantId2, importResult);
checkImportedEntity(tenantId1, asset, tenantId2, importResult.getSavedEntity());
checkImportedAssetData(asset, importResult.getSavedEntity());
}
@Test
public void testExportImportSingleAsset_sameTenant() throws Exception {
public void testExportImportAsset_sameTenant() throws Exception {
logInAsTenantAdmin1();
Asset asset = createAsset(tenantId1, null, "AB", "Asset v1.0");
EntityExportData<Asset> exportData = exportSingleEntity(asset.getId());
EntityImportResult<Asset> importResult = importEntity(exportData);
checkImportedEntity(tenantId1, asset, tenantId1, importResult);
checkImportedEntity(tenantId1, asset, tenantId1, importResult.getSavedEntity());
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 = importEntity(customerExportData).getSavedEntity();
Asset importedAsset = importEntity(assetExportData).getSavedEntity();
assertThat(importedAsset.getCustomerId()).isEqualTo(importedCustomer.getId());
}
@Test
public void testExportImportAsset_withCustomer_sameTenant() throws Exception {
public void testExportImportAsset_sameTenant_withCustomer() throws Exception {
logInAsTenantAdmin1();
Customer customer = createCustomer(tenantId1, "My customer");
Asset asset = createAsset(tenantId1, customer.getId(), "AB", "My asset");
@ -146,16 +125,9 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
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 {
public void testExportImportCustomer_betweenTenants() throws Exception {
logInAsTenantAdmin1();
Customer customer = createCustomer(tenantAdmin1.getTenantId(), "Customer of tenant 1");
EntityExportData<Customer> exportData = exportSingleEntity(customer.getId());
@ -164,34 +136,27 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
logInAsTenantAdmin2();
EntityImportResult<Customer> importResult = importEntity(exportData);
checkImportedEntity(tenantId1, customer, tenantId2, importResult);
checkImportedEntity(tenantId1, customer, tenantId2, importResult.getSavedEntity());
checkImportedCustomerData(customer, importResult.getSavedEntity());
}
@Test
public void testExportImportSingleCustomer_sameTenant() throws Exception {
public void testExportImportCustomer_sameTenant() throws Exception {
logInAsTenantAdmin1();
Customer customer = createCustomer(tenantAdmin1.getTenantId(), "Customer v1.0");
EntityExportData<Customer> exportData = exportSingleEntity(customer.getId());
EntityImportResult<Customer> importResult = importEntity(exportData);
checkImportedEntity(tenantId1, customer, tenantId1, importResult);
checkImportedEntity(tenantId1, customer, tenantId1, importResult.getSavedEntity());
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, 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());
@ -206,13 +171,13 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
logInAsTenantAdmin2();
EntityImportResult<DeviceProfile> profileImportResult = importEntity(profileExportData);
checkImportedEntity(tenantId1, deviceProfile, tenantId2, profileImportResult);
checkImportedEntity(tenantId1, deviceProfile, tenantId2, profileImportResult.getSavedEntity());
checkImportedDeviceProfileData(deviceProfile, profileImportResult.getSavedEntity());
EntityImportResult<Device> deviceImportResult = importEntity(deviceExportData);
Device importedDevice = deviceImportResult.getSavedEntity();
checkImportedEntity(tenantId1, device, tenantId2, deviceImportResult);
checkImportedEntity(tenantId1, device, tenantId2, deviceImportResult.getSavedEntity());
checkImportedDeviceData(device, importedDevice);
assertThat(importedDevice.getDeviceProfileId()).isEqualTo(profileImportResult.getSavedEntity().getId());
@ -227,8 +192,14 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
@Test
public void testExportImportDevice_sameTenant() throws Exception {
logInAsTenantAdmin1();
DeviceProfile deviceProfile = createDeviceProfile(tenantId1, "Device profile v1.0");
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 = exportSingleEntity(device.getId());
@ -236,29 +207,119 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
EntityImportResult<Device> importResult = importEntity(deviceExportData);
Device importedDevice = importResult.getSavedEntity();
checkImportedEntity(tenantId1, device, tenantId1, importResult);
checkImportedEntity(tenantId1, device, tenantId1, importResult.getSavedEntity());
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());
assertThat(importedDevice.getFirmwareId()).isEqualTo(firmware.getId());
assertThat(importedDevice.getSoftwareId()).isEqualTo(software.getId());
}
@Test
public void testExportImportSingleRuleChain_betweenTenants() throws Exception {
public void testExportImportDashboard_betweenTenants() throws Exception {
logInAsTenantAdmin1();
Dashboard dashboard = createDashboard(tenantAdmin1.getTenantId(), null, "Dashboard of tenant 1");
EntityExportData<Dashboard> exportData = exportSingleEntity(dashboard.getId());
assertThat(exportData.getEntity()).isEqualTo(dashboard);
logInAsTenantAdmin2();
EntityImportResult<Dashboard> importResult = importEntity(exportData);
checkImportedEntity(tenantId1, dashboard, tenantId2, importResult.getSavedEntity());
checkImportedDashboardData(dashboard, importResult.getSavedEntity());
}
@Test
public void testExportImportDashboard_sameTenant() throws Exception {
logInAsTenantAdmin1();
Dashboard dashboard = createDashboard(tenantAdmin1.getTenantId(), null, "Dashboard v1.0");
EntityExportData<Dashboard> exportData = exportSingleEntity(dashboard.getId());
EntityImportResult<Dashboard> importResult = importEntity(exportData);
checkImportedEntity(tenantId1, dashboard, tenantId1, importResult.getSavedEntity());
checkImportedDashboardData(dashboard, importResult.getSavedEntity());
}
@Test
public void testExportImportDashboard_betweenTenants_withCustomer_updated() throws Exception {
logInAsTenantAdmin1();
Dashboard dashboard = createDashboard(tenantAdmin1.getTenantId(), null, "Dashboard of tenant 1");
EntityExportData<Dashboard> exportData = exportSingleEntity(dashboard.getId());
logInAsTenantAdmin2();
Dashboard importedDashboard = (Dashboard) importEntities(List.of(exportData)).get(0).getSavedEntity();
checkImportedEntity(tenantId1, dashboard, tenantId2, importedDashboard);
logInAsTenantAdmin1();
Customer customer = createCustomer(tenantId1, "Customer 1");
EntityExportData<Customer> customerExportData = exportSingleEntity(customer.getId());
dashboardService.assignDashboardToCustomer(tenantId1, dashboard.getId(), customer.getId());
exportData = exportSingleEntity(dashboard.getId());
logInAsTenantAdmin2();
Customer importedCustomer = (Customer) importEntities(List.of(customerExportData)).get(0).getSavedEntity();
importedDashboard = (Dashboard) importEntities(List.of(exportData)).get(0).getSavedEntity();
assertThat(importedDashboard.getAssignedCustomers()).hasOnlyOneElementSatisfying(customerInfo -> {
assertThat(customerInfo.getCustomerId()).isEqualTo(importedCustomer.getId());
});
}
@Test
public void testExportImportDashboard_betweenTenants_withEntityAliases() throws Exception {
logInAsTenantAdmin1();
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);
EntityTypeExportRequest assetsExportRequest = new EntityTypeExportRequest();
assetsExportRequest.setEntityType(EntityType.ASSET);
assetsExportRequest.setPageSize(10);
assetsExportRequest.setExportSettings(new EntityExportSettings());
EntityTypeExportRequest dashboardsExportRequest = new EntityTypeExportRequest();
dashboardsExportRequest.setEntityType(EntityType.DASHBOARD);
dashboardsExportRequest.setPageSize(10);
dashboardsExportRequest.setExportSettings(new EntityExportSettings());
List<EntityExportData<?>> exportDataList = exportEntities(List.of(assetsExportRequest, dashboardsExportRequest));
logInAsTenantAdmin2();
Map<EntityType, List<EntityImportResult<?>>> importResults = importEntities(exportDataList).stream().collect(Collectors.groupingBy(EntityImportResult::getEntityType));
Asset importedAsset1 = (Asset) importResults.get(EntityType.ASSET).get(0).getSavedEntity();
Asset importedAsset2 = (Asset) importResults.get(EntityType.ASSET).get(1).getSavedEntity();
Dashboard importedDashboard = (Dashboard) importResults.get(EntityType.DASHBOARD).get(0).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 {
logInAsTenantAdmin1();
RuleChain ruleChain = createRuleChain(tenantId1, "Rule chain of tenant 1");
RuleChainMetaData metaData = ruleChainService.loadRuleChainMetaData(tenantId1, ruleChain.getId());
@ -272,12 +333,12 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
RuleChain importedRuleChain = importResult.getSavedEntity();
RuleChainMetaData importedMetaData = ruleChainService.loadRuleChainMetaData(tenantId2, importedRuleChain.getId());
checkImportedEntity(tenantId1, ruleChain, tenantId2, importResult);
checkImportedEntity(tenantId1, ruleChain, tenantId2, importResult.getSavedEntity());
checkImportedRuleChainData(ruleChain, metaData, importedRuleChain, importedMetaData);
}
@Test
public void testExportImportSingleRuleChain_sameTenant() throws Exception {
public void testExportImportRuleChain_sameTenant() throws Exception {
logInAsTenantAdmin1();
RuleChain ruleChain = createRuleChain(tenantId1, "Rule chain v1.0");
RuleChainMetaData metaData = ruleChainService.loadRuleChainMetaData(tenantId1, ruleChain.getId());
@ -288,91 +349,439 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
RuleChain importedRuleChain = importResult.getSavedEntity();
RuleChainMetaData importedMetaData = ruleChainService.loadRuleChainMetaData(tenantId1, importedRuleChain.getId());
checkImportedEntity(tenantId1, ruleChain, tenantId1, importResult);
checkImportedEntity(tenantId1, ruleChain, tenantId1, importResult.getSavedEntity());
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);
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());
}
}
@Test
public void testExportImportSingleDashboard_betweenTenants() throws Exception {
public void testExportImportBatch_betweenTenants() throws Exception {
logInAsTenantAdmin1();
Dashboard dashboard = createDashboard(tenantAdmin1.getTenantId(), null, "Dashboard of tenant 1");
EntityExportData<Dashboard> exportData = exportSingleEntity(dashboard.getId());
assertThat(exportData.getEntity()).isEqualTo(dashboard);
Customer customer = createCustomer(tenantId1, "Customer 1");
Asset asset = createAsset(tenantId1, customer.getId(), "A", "Customer 1 - Asset 1");
RuleChain ruleChain = createRuleChain(tenantId1, "Rule chain 1");
Dashboard dashboard = createDashboard(tenantId1, customer.getId(), "Customer 1 - Dashboard 1");
DeviceProfile deviceProfile = createDeviceProfile(tenantId1, ruleChain.getId(), dashboard.getId(), "Device profile 1");
Device device = createDevice(tenantId1, customer.getId(), deviceProfile.getId(), "Customer 1 - Device 1");
EntityListExportRequest exportRequest = new EntityListExportRequest();
exportRequest.setExportSettings(new EntityExportSettings());
exportRequest.setEntitiesIds(List.of(customer.getId(), asset.getId(), ruleChain.getId(), deviceProfile.getId(), dashboard.getId()));
List<EntityExportData<?>> exportDataList = exportEntities(exportRequest);
exportRequest.setEntitiesIds(List.of(device.getId()));
DeviceExportData deviceExportData = (DeviceExportData) exportEntities(exportRequest).get(0);
deviceExportData.getCredentials().setCredentialsId(RandomStringUtils.randomAlphanumeric(10));
exportDataList.add(deviceExportData);
logInAsTenantAdmin2();
EntityImportResult<Dashboard> importResult = importEntity(exportData);
checkImportedEntity(tenantId1, dashboard, tenantId2, importResult);
checkImportedDashboardData(dashboard, importResult.getSavedEntity());
ImportRequest importRequest = new ImportRequest();
importRequest.setImportSettings(EntityImportSettings.builder()
.updateReferencesToOtherEntities(true)
.build());
importRequest.setExportDataList(exportDataList);
Map<EntityType, EntityImportResult<?>> importResults = importEntities(importRequest).stream()
.collect(Collectors.toMap(EntityImportResult::getEntityType, r -> r));
Customer importedCustomer = (Customer) importResults.get(EntityType.CUSTOMER).getSavedEntity();
checkImportedEntity(tenantId1, customer, tenantId2, importedCustomer);
Asset importedAsset = (Asset) importResults.get(EntityType.ASSET).getSavedEntity();
checkImportedEntity(tenantId1, asset, tenantId2, importedAsset);
assertThat(importedAsset.getCustomerId()).isEqualTo(importedCustomer.getId());
RuleChain importedRuleChain = (RuleChain) importResults.get(EntityType.RULE_CHAIN).getSavedEntity();
checkImportedEntity(tenantId1, ruleChain, tenantId2, importedRuleChain);
Dashboard importedDashboard = (Dashboard) importResults.get(EntityType.DASHBOARD).getSavedEntity();
checkImportedEntity(tenantId1, dashboard, tenantId2, importedDashboard);
assertThat(importedDashboard.getAssignedCustomers()).size().isOne();
assertThat(importedDashboard.getAssignedCustomers()).hasOnlyOneElementSatisfying(customerInfo -> {
assertThat(customerInfo.getCustomerId()).isEqualTo(importedCustomer.getId());
});
DeviceProfile importedDeviceProfile = (DeviceProfile) importResults.get(EntityType.DEVICE_PROFILE).getSavedEntity();
checkImportedEntity(tenantId1, deviceProfile, tenantId2, importedDeviceProfile);
assertThat(importedDeviceProfile.getDefaultRuleChainId()).isEqualTo(importedRuleChain.getId());
assertThat(importedDeviceProfile.getDefaultDashboardId()).isEqualTo(importedDashboard.getId());
Device importedDevice = (Device) importResults.get(EntityType.DEVICE).getSavedEntity();
checkImportedEntity(tenantId1, device, tenantId2, importedDevice);
assertThat(importedDevice.getCustomerId()).isEqualTo(importedCustomer.getId());
assertThat(importedDevice.getDeviceProfileId()).isEqualTo(importedDeviceProfile.getId());
}
@Test
public void testExportImportWithInboundRelations_betweenTenants() throws Exception {
logInAsTenantAdmin1();
Asset asset = createAsset(tenantId1, null, "A", "Asset 1");
Device device = createDevice(tenantId1, null, null, "Device 1");
EntityRelation relation = createRelation(asset.getId(), device.getId());
EntityListExportRequest exportRequest = new EntityListExportRequest();
exportRequest.setEntitiesIds(List.of(asset.getId(), device.getId()));
exportRequest.setExportSettings(EntityExportSettings.builder()
.exportInboundRelations(true)
.exportOutboundRelations(false)
.build());
List<EntityExportData<?>> exportDataList = exportEntities(exportRequest);
EntityExportData<?> deviceExportData = exportDataList.stream().filter(exportData -> exportData.getEntityType() == EntityType.DEVICE).findFirst().orElse(null);
assertThat(deviceExportData.getInboundRelations()).size().isOne();
assertThat(deviceExportData.getInboundRelations().get(0)).matches(entityRelation -> {
return entityRelation.getFrom().equals(asset.getId()) && entityRelation.getTo().equals(device.getId());
});
((DeviceExportData) deviceExportData).getCredentials().setCredentialsId("ab");
((Device) deviceExportData.getEntity()).setDeviceProfileId(null);
logInAsTenantAdmin2();
ImportRequest importRequest = new ImportRequest();
importRequest.setExportDataList(exportDataList);
importRequest.setImportSettings(EntityImportSettings.builder()
.importInboundRelations(true)
.build());
Map<EntityType, EntityImportResult<?>> importResults = importEntities(importRequest).stream().collect(Collectors.toMap(EntityImportResult::getEntityType, r -> r));
Device importedDevice = (Device) importResults.get(EntityType.DEVICE).getSavedEntity();
Asset importedAsset = (Asset) importResults.get(EntityType.ASSET).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 testExportImportSingleDashboard_sameTenant() throws Exception {
public void testExportImportWithRelations_betweenTenants() throws Exception {
logInAsTenantAdmin1();
Dashboard dashboard = createDashboard(tenantAdmin1.getTenantId(), null, "Dashboard v1.0");
EntityExportData<Dashboard> exportData = exportSingleEntity(dashboard.getId());
Asset asset = createAsset(tenantId1, null, "A", "Asset 1");
Device device = createDevice(tenantId1, null, null, "Device 1");
EntityRelation relation = createRelation(asset.getId(), device.getId());
EntityImportResult<Dashboard> importResult = importEntity(exportData);
checkImportedEntity(tenantId1, dashboard, tenantId1, importResult);
checkImportedDashboardData(dashboard, importResult.getSavedEntity());
EntityListExportRequest exportRequest = new EntityListExportRequest();
exportRequest.setEntitiesIds(List.of(asset.getId(), device.getId()));
exportRequest.setExportSettings(EntityExportSettings.builder()
.exportInboundRelations(true)
.exportOutboundRelations(true)
.build());
List<EntityExportData<?>> exportDataList = exportEntities(exportRequest);
assertThat(exportDataList).allMatch(exportData -> exportData.getInboundRelations().size() + exportData.getOutboundRelations().size() == 1);
EntityExportData<?> deviceExportData = exportDataList.stream().filter(exportData -> exportData.getEntityType() == EntityType.DEVICE).findFirst().orElse(null);
((DeviceExportData) deviceExportData).getCredentials().setCredentialsId("ab");
((Device) deviceExportData.getEntity()).setDeviceProfileId(null);
logInAsTenantAdmin2();
ImportRequest importRequest = new ImportRequest();
importRequest.setExportDataList(exportDataList);
importRequest.setImportSettings(EntityImportSettings.builder()
.importInboundRelations(true)
.importOutboundRelations(true)
.build());
Map<EntityType, EntityImportResult<?>> importResults = importEntities(importRequest).stream().collect(Collectors.toMap(EntityImportResult::getEntityType, r -> r));
Device importedDevice = (Device) importResults.get(EntityType.DEVICE).getSavedEntity();
Asset importedAsset = (Asset) importResults.get(EntityType.ASSET).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());
});
}
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());
@Test
public void testExportImportWithRelations_sameTenant() throws Exception {
logInAsTenantAdmin1();
Asset asset = createAsset(tenantId1, null, "A", "Asset 1");
Device device1 = createDevice(tenantId1, null, null, "Device 1");
EntityRelation relation1 = createRelation(asset.getId(), device1.getId());
SingleEntityExportRequest exportRequest = new SingleEntityExportRequest();
exportRequest.setEntityId(asset.getId());
exportRequest.setExportSettings(EntityExportSettings.builder()
.exportOutboundRelations(true)
.build());
EntityExportData<Asset> assetExportData = (EntityExportData<Asset>) exportEntities(exportRequest).get(0);
assertThat(assetExportData.getOutboundRelations()).size().isOne();
Device device2 = createDevice(tenantId1, null, null, "Device 2");
EntityRelation relation2 = createRelation(asset.getId(), device2.getId());
ImportRequest importRequest = new ImportRequest();
importRequest.setExportDataList(List.of(assetExportData));
importRequest.setImportSettings(EntityImportSettings.builder()
.importOutboundRelations(true)
.build());
importEntities(importRequest);
List<EntityRelation> relations = relationService.findByFrom(TenantId.SYS_TENANT_ID, asset.getId(), RelationTypeGroup.COMMON);
assertThat(relations).contains(relation1, relation2);
}
@Test
public void textExportImportWithRelations_sameTenant_removeExisting() throws Exception {
logInAsTenantAdmin1();
Asset asset1 = createAsset(tenantId1, null, "A", "Asset 1");
Device device = createDevice(tenantId1, null, null, "Device 1");
EntityRelation relation1 = createRelation(asset1.getId(), device.getId());
SingleEntityExportRequest exportRequest = new SingleEntityExportRequest();
exportRequest.setEntityId(device.getId());
exportRequest.setExportSettings(EntityExportSettings.builder()
.exportInboundRelations(true)
.build());
EntityExportData<?> deviceExportData = exportEntities(exportRequest).get(0);
assertThat(deviceExportData.getInboundRelations()).size().isOne();
Asset asset2 = createAsset(tenantId1, null, "A", "Asset 2");
EntityRelation relation2 = createRelation(asset2.getId(), device.getId());
ImportRequest importRequest = new ImportRequest();
importRequest.setExportDataList(List.of(deviceExportData));
importRequest.setImportSettings(EntityImportSettings.builder()
.importInboundRelations(true)
.removeExistingRelations(true)
.build());
importEntities(importRequest);
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 {
logInAsTenantAdmin1();
DeviceProfile defaultDeviceProfile = deviceProfileService.findDefaultDeviceProfile(tenantId1);
EntityListExportRequest exportRequest = new EntityListExportRequest();
exportRequest.setEntitiesIds(List.of(defaultDeviceProfile.getId()));
exportRequest.setExportSettings(new EntityExportSettings());
List<EntityExportData<?>> exportDataList = exportEntities(exportRequest);
logInAsTenantAdmin2();
ImportRequest importRequest = new ImportRequest();
importRequest.setExportDataList(exportDataList);
importRequest.setImportSettings(EntityImportSettings.builder()
.findExistingByName(false)
.updateReferencesToOtherEntities(true)
.build());
assertThatThrownBy(() -> {
importEntities(importRequest);
}).hasMessageContaining("default device profile is present");
importRequest.getImportSettings().setFindExistingByName(true);
importEntities(importRequest);
checkImportedEntity(tenantId1, defaultDeviceProfile, tenantId2, deviceProfileService.findDefaultDeviceProfile(tenantId2));
}
@Test
public void testExportImportDashboard_betweenTenants_doNotUpdateReferencesToOtherEntities() throws Exception {
logInAsTenantAdmin1();
Customer customer = createCustomer(tenantId1, "Customer 1");
Dashboard dashboard = createDashboard(tenantId1, customer.getId(), "Dashboard 1");
EntityListExportRequest exportRequest = new EntityListExportRequest();
exportRequest.setEntitiesIds(List.of(customer.getId(), dashboard.getId()));
exportRequest.setExportSettings(new EntityExportSettings());
List<EntityExportData<?>> exportDataList = exportEntities(exportRequest);
logInAsTenantAdmin2();
Map<EntityType, EntityImportResult<?>> importResults = importEntities(exportDataList).stream().collect(Collectors.toMap(EntityImportResult::getEntityType, r -> r));
Customer importedCustomer = (Customer) importResults.get(EntityType.CUSTOMER).getSavedEntity();
Dashboard importedDashboard = (Dashboard) importResults.get(EntityType.DASHBOARD).getSavedEntity();
assertThat(importedDashboard.getAssignedCustomers()).hasOnlyOneElementSatisfying(customerInfo -> {
assertThat(customerInfo.getCustomerId()).isEqualTo(importedCustomer.getId());
});
assertThat(importedDashboard.getConfiguration()).isEqualTo(dashboard.getConfiguration());
logInAsTenantAdmin1();
dashboard.setConfiguration(JacksonUtil.newObjectNode().set("aaa", new TextNode("bbb")));
dashboard = dashboardService.saveDashboard(dashboard);
dashboard = dashboardService.unassignDashboardFromCustomer(tenantId1, dashboard.getId(), customer.getId());
EntityExportData<Dashboard> updatedDashboardExportData = exportSingleEntity(dashboard.getId());
assertThat(updatedDashboardExportData.getEntity().getAssignedCustomers()).isNullOrEmpty();
logInAsTenantAdmin2();
ImportRequest importRequest = new ImportRequest();
importRequest.setExportDataList(List.of(updatedDashboardExportData));
importRequest.setImportSettings(EntityImportSettings.builder()
.updateReferencesToOtherEntities(false)
.build());
importedDashboard = (Dashboard) importEntities(importRequest).get(0).getSavedEntity();
assertThat(importedDashboard.getConfiguration()).isEqualTo(dashboard.getConfiguration());
assertThat(importedDashboard.getAssignedCustomers()).hasOnlyOneElementSatisfying(customerInfo -> {
assertThat(customerInfo.getCustomerId()).isEqualTo(importedCustomer.getId());
});
}
@Test
public void testExportRequests() throws Exception {
logInAsTenantAdmin1();
Device device = createDevice(tenantId1, null, null, "Device 1");
DeviceProfile deviceProfile = createDeviceProfile(tenantId1, null, null, "Device profile 1");
RuleChain ruleChain = createRuleChain(tenantId1, "Rule chain 1");
Asset asset = createAsset(tenantId1, null, "A", "Asset 1");
Dashboard dashboard = createDashboard(tenantId1, null, "Dashboard 1");
Customer customer = createCustomer(tenantId1, "Customer 1");
Map<EntityType, ExportableEntity<?>> entities = Map.of(
EntityType.DEVICE, device, EntityType.DEVICE_PROFILE, deviceProfile,
EntityType.RULE_CHAIN, ruleChain, EntityType.ASSET, asset,
EntityType.DASHBOARD, dashboard, EntityType.CUSTOMER, customer
);
for (ExportableEntity<?> entity : entities.values()) {
testEntityTypeExportRequest(entity);
testCustomEntityFilterExportRequest(entity);
}
}
private void testEntityTypeExportRequest(ExportableEntity<?> entity) throws Exception {
EntityTypeExportRequest exportRequest = new EntityTypeExportRequest();
exportRequest.setExportSettings(new EntityExportSettings());
exportRequest.setPageSize(10);
exportRequest.setEntityType(entity.getId().getEntityType());
private <E extends ExportableEntity<?> & HasTenantId> void checkImportedEntity(TenantId tenantId1, E initialEntity, TenantId tenantId2, EntityImportResult<E> importResult) {
E importedEntity = importResult.getSavedEntity();
List<EntityExportData<?>> exportDataList = exportEntities(exportRequest);
assertThat(exportDataList).size().isNotZero();
assertThat(exportDataList).anySatisfy(exportData -> {
assertThat(exportData.getEntity()).isEqualTo(entity);
});
}
assertThat(initialEntity.getTenantId()).isEqualTo(tenantId1);
assertThat(importedEntity.getTenantId()).isEqualTo(tenantId2);
private void testCustomEntityFilterExportRequest(ExportableEntity<?> entity) throws Exception {
CustomEntityFilterExportRequest exportRequest = new CustomEntityFilterExportRequest();
exportRequest.setExportSettings(new EntityExportSettings());
exportRequest.setPageSize(10);
assertThat(importedEntity.getExternalId()).isEqualTo(initialEntity.getId());
EntityListFilter filter = new EntityListFilter();
filter.setEntityType(entity.getId().getEntityType());
filter.setEntityList(List.of(entity.getId().toString()));
exportRequest.setFilter(filter);
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);
List<EntityExportData<?>> exportDataList = exportEntities(exportRequest);
assertThat(exportDataList).hasOnlyOneElementSatisfying(exportData -> {
assertThat(exportData.getEntity()).isEqualTo(entity);
});
}
@Test
public void testExportImportCustomerEntities_betweenTenants() throws Exception {
logInAsTenantAdmin1();
Customer customer = createCustomer(tenantId1, "Customer 1");
Device tenantDevice = createDevice(tenantId1, null, null, "Tenant device 1");
Device customerDevice = createDevice(tenantId1, customer.getId(), null, "Customer device 1");
Asset tenantAsset = createAsset(tenantId1, null, "A", "Tenant asset 1");
Asset customerAsset = createAsset(tenantId1, customer.getId(), "A", "Customer asset 1");
List<ExportRequest> exportRequests = new ArrayList<>();
for (EntityType entityType : Set.of(EntityType.DEVICE, EntityType.ASSET)) {
EntityTypeExportRequest exportRequest = new EntityTypeExportRequest();
exportRequest.setExportSettings(new EntityExportSettings());
exportRequest.setPageSize(10);
exportRequest.setEntityType(entityType);
exportRequest.setCustomerId(customer.getId());
exportRequests.add(exportRequest);
}
List<EntityExportData<?>> exportDataList = exportEntities(exportRequests);
assertThat(exportDataList).size().isEqualTo(2);
assertThat(exportDataList).anySatisfy(exportData -> {
assertThat(exportData.getEntity()).isEqualTo(customerDevice);
});
assertThat(exportDataList).anySatisfy(exportData -> {
assertThat(exportData.getEntity()).isEqualTo(customerAsset);
});
}
private void logInAsTenantAdmin1() throws Exception {
login(tenantAdmin1.getEmail(), "12345678");
}
@Test
public void testEntityEventsOnImport() throws Exception {
logInAsTenantAdmin1();
private void logInAsTenantAdmin2() throws Exception {
login(tenantAdmin2.getEmail(), "12345678");
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");
EntityListExportRequest exportRequest = new EntityListExportRequest();
exportRequest.setEntitiesIds(List.of(customer.getId(), asset.getId(), device.getId(), ruleChain.getId(), dashboard.getId(), deviceProfile.getId()));
exportRequest.setExportSettings(new EntityExportSettings());
Map<EntityType, EntityExportData> entitiesExportData = exportEntities(exportRequest).stream()
.collect(Collectors.toMap(EntityExportData::getEntityType, r -> r));
logInAsTenantAdmin2();
Customer importedCustomer = (Customer) importEntity(entitiesExportData.get(EntityType.CUSTOMER)).getSavedEntity();
verify(entityActionService).logEntityAction(any(), eq(importedCustomer.getId()), eq(importedCustomer),
any(), eq(ActionType.ADDED), isNull());
importEntity(entitiesExportData.get(EntityType.CUSTOMER));
verify(entityActionService).logEntityAction(any(), eq(importedCustomer.getId()), eq(importedCustomer),
any(), eq(ActionType.UPDATED), isNull());
verify(clusterService).sendNotificationMsgToEdgeService(any(), any(), eq(importedCustomer.getId()), any(), any(), eq(EdgeEventActionType.UPDATED));
Asset importedAsset = (Asset) importEntity(entitiesExportData.get(EntityType.ASSET)).getSavedEntity();
verify(entityActionService).logEntityAction(any(), eq(importedAsset.getId()), eq(importedAsset),
any(), eq(ActionType.ADDED), isNull());
importEntity(entitiesExportData.get(EntityType.ASSET));
verify(entityActionService).logEntityAction(any(), eq(importedAsset.getId()), eq(importedAsset),
any(), eq(ActionType.UPDATED), isNull());
verify(clusterService).sendNotificationMsgToEdgeService(any(), any(), eq(importedAsset.getId()), any(), any(), eq(EdgeEventActionType.UPDATED));
RuleChain importedRuleChain = (RuleChain) importEntity(entitiesExportData.get(EntityType.RULE_CHAIN)).getSavedEntity();
verify(entityActionService).logEntityAction(any(), eq(importedRuleChain.getId()), eq(importedRuleChain),
any(), eq(ActionType.ADDED), isNull());
verify(clusterService).broadcastEntityStateChangeEvent(any(), eq(importedRuleChain.getId()), eq(ComponentLifecycleEvent.CREATED));
Dashboard importedDashboard = (Dashboard) importEntity(entitiesExportData.get(EntityType.DASHBOARD)).getSavedEntity();
verify(entityActionService).logEntityAction(any(), eq(importedDashboard.getId()), eq(importedDashboard),
any(), eq(ActionType.ADDED), isNull());
DeviceProfile importedDeviceProfile = (DeviceProfile) importEntity(entitiesExportData.get(EntityType.DEVICE_PROFILE)).getSavedEntity();
verify(entityActionService).logEntityAction(any(), eq(importedDeviceProfile.getId()), eq(importedDeviceProfile),
any(), eq(ActionType.ADDED), isNull());
verify(clusterService).onDeviceProfileChange(eq(importedDeviceProfile), any());
verify(clusterService).broadcastEntityStateChangeEvent(any(), eq(importedDeviceProfile.getId()), eq(ComponentLifecycleEvent.CREATED));
verify(clusterService).sendNotificationMsgToEdgeService(any(), any(), eq(importedDeviceProfile.getId()), any(), any(), eq(EdgeEventActionType.ADDED));
verify(otaPackageStateService).update(eq(importedDeviceProfile), eq(false), eq(false));
((DeviceExportData)entitiesExportData.get(EntityType.DEVICE)).getCredentials().setCredentialsId("abc");
Device importedDevice = (Device) importEntity(entitiesExportData.get(EntityType.DEVICE)).getSavedEntity();
verify(entityActionService).logEntityAction(any(), eq(importedDevice.getId()), eq(importedDevice),
any(), eq(ActionType.ADDED), isNull());
verify(clusterService).onDeviceUpdated(eq(importedDevice), isNull());
importEntity(entitiesExportData.get(EntityType.DEVICE));
verify(clusterService).onDeviceUpdated(eq(importedDevice), eq(importedDevice));
}
}

View File

@ -26,4 +26,7 @@ public interface ExportableEntity<I extends EntityId> extends HasId<I>, HasName
I getExternalId();
void setExternalId(I externalId);
long getCreatedTime();
void setCreatedTime(long createdTime);
}