Fix re-import of rule chains, and different not related test

This commit is contained in:
Andrii Shvaika 2022-06-18 09:28:54 +03:00
parent 3d85fb7c0a
commit 7a4fec93cd
13 changed files with 76 additions and 33 deletions

View File

@ -43,7 +43,7 @@ public class DefaultTbCustomerService extends AbstractTbEntityService implements
try {
Customer savedCustomer = checkNotNull(customerService.saveCustomer(customer));
vcService.autoCommit(user, savedCustomer.getId());
notificationEntityService.notifyCreateOrUpdateEntity(tenantId, savedCustomer.getId(), savedCustomer, savedCustomer.getId(), actionType, user);
notificationEntityService.notifyCreateOrUpdateEntity(tenantId, savedCustomer.getId(), savedCustomer, null, actionType, user);
return savedCustomer;
} catch (Exception e) {
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.CUSTOMER), customer, null, actionType, user, e);

View File

@ -1,5 +1,5 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
* 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.

View File

@ -87,6 +87,7 @@ public abstract class BaseEntityImportService<I extends EntityId, E extends Expo
@Override
public EntityImportResult<E> importEntity(EntitiesImportCtx ctx, D exportData) throws ThingsboardException {
EntityImportResult<E> importResult = new EntityImportResult<>();
ctx.setCurrentImportResult(importResult);
importResult.setEntityType(getEntityType());
IdProvider idProvider = new IdProvider(ctx, importResult);

View File

@ -81,7 +81,7 @@ public class DashboardImportService extends BaseEntityImportService<DashboardId,
if (field.equals("id")) continue;
JsonNode oldFieldValue = entityAlias.get(field);
JsonNode newFieldValue = JacksonUtil.toJsonNode(RegexUtils.replace(oldFieldValue.toString(), RegexUtils.UUID_PATTERN, uuid -> {
return idProvider.getInternalIdByUuid(UUID.fromString(uuid), ctx.isFetchAllUUIDs(), HINTS)
return idProvider.getInternalIdByUuid(UUID.fromString(uuid), ctx.isFinalImportAttempt(), HINTS)
.map(entityId -> entityId.getId().toString()).orElse(uuid);
}));
((ObjectNode) entityAlias).set(field, newFieldValue);

View File

@ -77,15 +77,12 @@ public class RuleChainImportService extends BaseEntityImportService<RuleChainId,
RuleChainMetaData metaData = exportData.getMetaData();
List<RuleNode> ruleNodes = Optional.ofNullable(metaData.getNodes()).orElse(Collections.emptyList());
if (old != null) {
// boolean original = old.getId().equals(old.getExternalId());
List<RuleNodeId> nodeIds = ruleNodes.stream().map(RuleNode::getId).collect(Collectors.toList());
List<RuleNode> existing = ruleNodeDao.findByExternalIds(old.getId(), nodeIds);
existing.forEach(node -> ctx.putInternalId(node.getExternalId(), node.getId()));
ruleNodes.forEach(node -> {
node.setRuleChainId(old.getId());
// if (!original) {
node.setExternalId(node.getId());
// }
node.setId((RuleNodeId) ctx.getInternalId(node.getId()));
});
} else {
@ -99,7 +96,7 @@ public class RuleChainImportService extends BaseEntityImportService<RuleChainId,
ruleNodes.forEach(ruleNode -> {
JsonNode ruleNodeConfig = ruleNode.getConfiguration();
String newRuleNodeConfigJson = RegexUtils.replace(ruleNodeConfig.toString(), RegexUtils.UUID_PATTERN, uuid -> {
return idProvider.getInternalIdByUuid(UUID.fromString(uuid), ctx.isFetchAllUUIDs(), HINTS)
return idProvider.getInternalIdByUuid(UUID.fromString(uuid), ctx.isFinalImportAttempt(), HINTS)
.map(entityId -> entityId.getId().toString())
.orElse(uuid);
});
@ -119,9 +116,13 @@ public class RuleChainImportService extends BaseEntityImportService<RuleChainId,
@Override
protected RuleChain saveOrUpdate(EntitiesImportCtx ctx, RuleChain ruleChain, RuleChainExportData exportData, IdProvider idProvider) {
ruleChain = ruleChainService.saveRuleChain(ruleChain);
if (ctx.isFinalImportAttempt() || ctx.getCurrentImportResult().isUpdatedAllExternalIds()) {
exportData.getMetaData().setRuleChainId(ruleChain.getId());
ruleChainService.saveRuleChainMetaData(ctx.getTenantId(), exportData.getMetaData());
return ruleChainService.findRuleChainById(ctx.getTenantId(), ruleChain.getId());
} else {
return ruleChain;
}
}
@Override

View File

@ -259,6 +259,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
.saveCredentials(config.isLoadCredentials())
.findExistingByName(false)
.build());
ctx.setFinalImportAttempt(true);
EntityImportResult<?> importResult = exportImportService.importEntity(ctx, entityData);
exportImportService.saveReferencesAndRelations(ctx);
@ -329,6 +330,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
throw new RuntimeException(e);
}
for (EntityExportData entityData : entityDataList) {
EntityExportData reimportBackup = JacksonUtil.clone(entityData);
log.debug("[{}] Loading {} entities", ctx.getTenantId(), entityType);
EntityImportResult<?> importResult;
try {
@ -336,8 +338,8 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
} catch (Exception e) {
throw new LoadEntityException(entityData, e);
}
if (importResult.getUpdatedAllExternalIds() != null && !importResult.getUpdatedAllExternalIds()) {
ctx.getToReimport().put(entityData.getEntity().getExternalId(), new ReimportTask(entityData, ctx.getSettings()));
if (!importResult.isUpdatedAllExternalIds()) {
ctx.getToReimport().put(entityData.getEntity().getExternalId(), new ReimportTask(reimportBackup, ctx.getSettings()));
continue;
}
@ -351,7 +353,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
@SuppressWarnings({"rawtypes", "unchecked"})
private void reimport(EntitiesImportCtx ctx) {
ctx.setFetchAllUUIDs(true);
ctx.setFinalImportAttempt(true);
ctx.getToReimport().forEach((externalId, task) -> {
try {
EntityExportData entityData = task.getData();

View File

@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.sync.ThrowingRunnable;
import org.thingsboard.server.common.data.sync.ie.EntityImportResult;
import org.thingsboard.server.common.data.sync.ie.EntityImportSettings;
import org.thingsboard.server.common.data.sync.vc.EntityTypeLoadResult;
import org.thingsboard.server.service.security.model.SecurityUser;
@ -52,8 +53,9 @@ public class EntitiesImportCtx {
private final Set<EntityRelation> relations = new LinkedHashSet<>();
private boolean fetchAllUUIDs = false;
private boolean finalImportAttempt = false;
private EntityImportSettings settings;
private EntityImportResult<?> currentImportResult;
public EntitiesImportCtx(SecurityUser user, String versionId) {
this(user, versionId, null);
@ -134,4 +136,6 @@ public class EntitiesImportCtx {
return notFoundIds.contains(externalId);
}
}

View File

@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
@ -108,7 +109,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
doPost("/api/customer", savedCustomer, Customer.class);
testNotifyEntityAllOneTime(savedCustomer, savedCustomer.getId(), savedCustomer.getId(), savedCustomer.getTenantId(),
savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
new CustomerId(CustomerId.NULL_UUID), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.UPDATED);
Customer foundCustomer = doGet("/api/customer/" + savedCustomer.getId().getId().toString(), Customer.class);

View File

@ -434,7 +434,7 @@ public abstract class BaseExportImportServiceTest extends AbstractControllerTest
protected <E extends ExportableEntity<I>, I extends EntityId> EntityImportResult<E> importEntity(User user, EntityExportData<E> exportData, EntityImportSettings importSettings) throws Exception {
EntitiesImportCtx ctx = new EntitiesImportCtx(getSecurityUser(user), null, importSettings);
ctx.setFetchAllUUIDs(true);
ctx.setFinalImportAttempt(true);
exportData = JacksonUtil.treeToValue(JacksonUtil.valueToTree(exportData), EntityExportData.class);
EntityImportResult<E> importResult = exportImportService.importEntity(ctx, exportData);
exportImportService.saveReferencesAndRelations(ctx);

View File

@ -20,6 +20,7 @@ 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.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.thingsboard.common.util.JacksonUtil;
@ -433,6 +434,12 @@ public class ExportImportServiceSqlTest extends BaseExportImportServiceTest {
}
@SuppressWarnings("rawTypes")
private static EntityExportData getAndClone(Map<EntityType, EntityExportData> map, EntityType entityType) {
return JacksonUtil.clone(map.get(entityType));
}
@SuppressWarnings({"rawTypes", "unchecked"})
@Test
public void testEntityEventsOnImport() throws Exception {
Customer customer = createCustomer(tenantId1, "Customer 1");
@ -455,32 +462,50 @@ public class ExportImportServiceSqlTest extends BaseExportImportServiceTest {
})
.collect(Collectors.toMap(EntityExportData::getEntityType, d -> d));
Customer importedCustomer = (Customer) importEntity(tenantAdmin2, entitiesExportData.get(EntityType.CUSTOMER)).getSavedEntity();
Mockito.reset(entityActionService);
Customer importedCustomer = (Customer) importEntity(tenantAdmin2, getAndClone(entitiesExportData, EntityType.CUSTOMER)).getSavedEntity();
verify(entityActionService).logEntityAction(any(), eq(importedCustomer.getId()), eq(importedCustomer),
any(), eq(ActionType.ADDED), isNull());
importEntity(tenantAdmin2, entitiesExportData.get(EntityType.CUSTOMER));
verify(entityActionService).logEntityAction(any(), eq(importedCustomer.getId()), eq(importedCustomer),
Mockito.reset(entityActionService);
importEntity(tenantAdmin2, getAndClone(entitiesExportData, EntityType.CUSTOMER));
verify(entityActionService, Mockito.never()).logEntityAction(any(), eq(importedCustomer.getId()), eq(importedCustomer),
any(), eq(ActionType.UPDATED), isNull());
EntityExportData<Customer> updatedCustomerEntity = getAndClone(entitiesExportData, EntityType.CUSTOMER);
updatedCustomerEntity.getEntity().setEmail("t" + updatedCustomerEntity.getEntity().getEmail());
Customer updatedCustomer = importEntity(tenantAdmin2, updatedCustomerEntity).getSavedEntity();
verify(entityActionService).logEntityAction(any(), eq(importedCustomer.getId()), eq(updatedCustomer),
any(), eq(ActionType.UPDATED), isNull());
verify(tbClusterService).sendNotificationMsgToEdgeService(any(), any(), eq(importedCustomer.getId()), any(), any(), eq(EdgeEventActionType.UPDATED));
Asset importedAsset = (Asset) importEntity(tenantAdmin2, entitiesExportData.get(EntityType.ASSET)).getSavedEntity();
Mockito.reset(entityActionService);
Asset importedAsset = (Asset) importEntity(tenantAdmin2, getAndClone(entitiesExportData, EntityType.ASSET)).getSavedEntity();
verify(entityActionService).logEntityAction(any(), eq(importedAsset.getId()), eq(importedAsset),
any(), eq(ActionType.ADDED), isNull());
importEntity(tenantAdmin2, entitiesExportData.get(EntityType.ASSET));
verify(entityActionService).logEntityAction(any(), eq(importedAsset.getId()), eq(importedAsset),
verify(entityActionService, Mockito.never()).logEntityAction(any(), eq(importedAsset.getId()), eq(importedAsset),
any(), eq(ActionType.UPDATED), isNull());
EntityExportData<Asset> updatedAssetEntity = getAndClone(entitiesExportData, EntityType.ASSET);
updatedAssetEntity.getEntity().setLabel("t" + updatedAssetEntity.getEntity().getLabel());
Asset updatedAsset = importEntity(tenantAdmin2, updatedAssetEntity).getSavedEntity();
verify(entityActionService).logEntityAction(any(), eq(importedAsset.getId()), eq(updatedAsset),
any(), eq(ActionType.UPDATED), isNull());
verify(tbClusterService).sendNotificationMsgToEdgeService(any(), any(), eq(importedAsset.getId()), any(), any(), eq(EdgeEventActionType.UPDATED));
RuleChain importedRuleChain = (RuleChain) importEntity(tenantAdmin2, entitiesExportData.get(EntityType.RULE_CHAIN)).getSavedEntity();
RuleChain importedRuleChain = (RuleChain) importEntity(tenantAdmin2, getAndClone(entitiesExportData, EntityType.RULE_CHAIN)).getSavedEntity();
verify(entityActionService).logEntityAction(any(), eq(importedRuleChain.getId()), eq(importedRuleChain),
any(), eq(ActionType.ADDED), isNull());
verify(tbClusterService).broadcastEntityStateChangeEvent(any(), eq(importedRuleChain.getId()), eq(ComponentLifecycleEvent.CREATED));
Dashboard importedDashboard = (Dashboard) importEntity(tenantAdmin2, entitiesExportData.get(EntityType.DASHBOARD)).getSavedEntity();
Dashboard importedDashboard = (Dashboard) importEntity(tenantAdmin2, getAndClone(entitiesExportData, EntityType.DASHBOARD)).getSavedEntity();
verify(entityActionService).logEntityAction(any(), eq(importedDashboard.getId()), eq(importedDashboard),
any(), eq(ActionType.ADDED), isNull());
DeviceProfile importedDeviceProfile = (DeviceProfile) importEntity(tenantAdmin2, entitiesExportData.get(EntityType.DEVICE_PROFILE)).getSavedEntity();
DeviceProfile importedDeviceProfile = (DeviceProfile) importEntity(tenantAdmin2, getAndClone(entitiesExportData, EntityType.DEVICE_PROFILE)).getSavedEntity();
verify(entityActionService).logEntityAction(any(), eq(importedDeviceProfile.getId()), eq(importedDeviceProfile),
any(), eq(ActionType.ADDED), isNull());
verify(tbClusterService).onDeviceProfileChange(eq(importedDeviceProfile), any());
@ -488,12 +513,17 @@ public class ExportImportServiceSqlTest extends BaseExportImportServiceTest {
verify(tbClusterService).sendNotificationMsgToEdgeService(any(), any(), eq(importedDeviceProfile.getId()), any(), any(), eq(EdgeEventActionType.ADDED));
verify(otaPackageStateService).update(eq(importedDeviceProfile), eq(false), eq(false));
Device importedDevice = (Device) importEntity(tenantAdmin2, entitiesExportData.get(EntityType.DEVICE)).getSavedEntity();
Device importedDevice = (Device) importEntity(tenantAdmin2, getAndClone(entitiesExportData, EntityType.DEVICE)).getSavedEntity();
verify(entityActionService).logEntityAction(any(), eq(importedDevice.getId()), eq(importedDevice),
any(), eq(ActionType.ADDED), isNull());
verify(tbClusterService).onDeviceUpdated(eq(importedDevice), isNull());
importEntity(tenantAdmin2, entitiesExportData.get(EntityType.DEVICE));
verify(tbClusterService).onDeviceUpdated(eq(importedDevice), eq(importedDevice));
importEntity(tenantAdmin2, getAndClone(entitiesExportData, EntityType.DEVICE));
verify(tbClusterService, Mockito.never()).onDeviceUpdated(eq(importedDevice), eq(importedDevice));
EntityExportData<Device> updatedDeviceEntity = getAndClone(entitiesExportData, EntityType.DEVICE);
updatedDeviceEntity.getEntity().setLabel("t" + updatedDeviceEntity.getEntity().getLabel());
Device updatedDevice = importEntity(tenantAdmin2, updatedDeviceEntity).getSavedEntity();
verify(tbClusterService).onDeviceUpdated(eq(updatedDevice), eq(importedDevice));
}
@Test

View File

@ -31,7 +31,7 @@ public class EntityImportResult<E extends ExportableEntity<? extends EntityId>>
private ThrowingRunnable saveReferencesCallback = () -> {};
private ThrowingRunnable sendEventsCallback = () -> {};
private Boolean updatedAllExternalIds;
private boolean updatedAllExternalIds = true;
private boolean created;
private boolean updated;

View File

@ -301,8 +301,10 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
}
}
}
if (ruleChainMetaData.getConnections() != null) {
Collections.sort(ruleChainMetaData.getConnections(), Comparator.comparingInt(NodeConnectionInfo::getFromIndex)
.thenComparing(NodeConnectionInfo::getToIndex).thenComparing(NodeConnectionInfo::getType));
}
return ruleChainMetaData;
}

View File

@ -1109,7 +1109,7 @@ public class TbDeviceProfileNodeTest {
AttributeKvEntity attributeKvEntityActiveSchedule = new AttributeKvEntity();
attributeKvEntityActiveSchedule.setId(compositeKeyActiveSchedule);
attributeKvEntityActiveSchedule.setJsonValue(
"{\"timezone\":\"Europe/Kiev\",\"items\":[{\"enabled\":true,\"dayOfWeek\":1,\"startsOn\":0,\"endsOn\":8.64e+7},{\"enabled\":true,\"dayOfWeek\":2,\"startsOn\":0,\"endsOn\":8.64e+7},{\"enabled\":true,\"dayOfWeek\":3,\"startsOn\":0,\"endsOn\":8.64e+7},{\"enabled\":true,\"dayOfWeek\":4,\"startsOn\":0,\"endsOn\":8.64e+7},{\"enabled\":true,\"dayOfWeek\":5,\"startsOn\":0,\"endsOn\":8.64e+7},{\"enabled\":true,\"dayOfWeek\":6,\"startsOn\":8.64e+7,\"endsOn\":8.64e+7},{\"enabled\":true,\"dayOfWeek\":7,\"startsOn\":0,\"endsOn\":8.64e+7}],\"dynamicValue\":null}"
"{\"timezone\":\"Europe/Kiev\",\"items\":[{\"enabled\":true,\"dayOfWeek\":1,\"startsOn\":0,\"endsOn\":8.64e+7},{\"enabled\":true,\"dayOfWeek\":2,\"startsOn\":0,\"endsOn\":8.64e+7},{\"enabled\":true,\"dayOfWeek\":3,\"startsOn\":0,\"endsOn\":8.64e+7},{\"enabled\":true,\"dayOfWeek\":4,\"startsOn\":0,\"endsOn\":8.64e+7},{\"enabled\":true,\"dayOfWeek\":5,\"startsOn\":0,\"endsOn\":8.64e+7},{\"enabled\":true,\"dayOfWeek\":6,\"startsOn\":0,\"endsOn\":8.64e+7},{\"enabled\":true,\"dayOfWeek\":7,\"startsOn\":0,\"endsOn\":8.64e+7}],\"dynamicValue\":null}"
);
attributeKvEntityActiveSchedule.setLastUpdateTs(0L);
@ -1166,6 +1166,8 @@ public class TbDeviceProfileNodeTest {
TbMsg msg = TbMsg.newMsg(SessionMsgType.POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(),
TbMsgDataType.JSON, mapper.writeValueAsString(data), null, null);
// Mockito.reset(ctx);
node.onMsg(ctx, msg);
verify(ctx).tellSuccess(msg);
verify(ctx).enqueueForTellNext(theMsg, "Alarm Created");