added upgrade logic tests && added fixes for review comments
This commit is contained in:
parent
21e5a1a130
commit
cfcf539c50
@ -27,6 +27,7 @@ import java.util.Arrays;
|
||||
@Slf4j
|
||||
@SpringBootConfiguration
|
||||
@ComponentScan({"org.thingsboard.server.install",
|
||||
"org.thingsboard.server.service.bean",
|
||||
"org.thingsboard.server.service.component",
|
||||
"org.thingsboard.server.service.install",
|
||||
"org.thingsboard.server.service.security.auth.jwt.settings",
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright © 2016-2023 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.service.bean;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@Service
|
||||
public class AnnotationBeanDiscoveryService implements BeanDiscoveryService {
|
||||
|
||||
@Value("${plugins.scan_packages}")
|
||||
private String[] scanPackages;
|
||||
|
||||
@Override
|
||||
public Set<BeanDefinition> discoverBeansByAnnotationType(Class<? extends Annotation> annotationType) {
|
||||
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
|
||||
scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType));
|
||||
Set<BeanDefinition> defs = new HashSet<>();
|
||||
for (String scanPackage : scanPackages) {
|
||||
defs.addAll(scanner.findCandidateComponents(scanPackage));
|
||||
}
|
||||
return defs;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright © 2016-2023 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.service.bean;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Set;
|
||||
|
||||
public interface BeanDiscoveryService {
|
||||
|
||||
Set<BeanDefinition> discoverBeansByAnnotationType(Class<? extends Annotation> annotationType);
|
||||
|
||||
}
|
||||
@ -20,12 +20,9 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.Profiles;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.rule.engine.api.NodeConfiguration;
|
||||
import org.thingsboard.rule.engine.api.NodeDefinition;
|
||||
@ -36,14 +33,13 @@ import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
|
||||
import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||
import org.thingsboard.server.common.data.rule.RuleChainType;
|
||||
import org.thingsboard.server.dao.component.ComponentDescriptorService;
|
||||
import org.thingsboard.server.service.bean.BeanDiscoveryService;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@ -54,12 +50,13 @@ import java.util.Set;
|
||||
public class AnnotationComponentDiscoveryService implements ComponentDiscoveryService {
|
||||
|
||||
public static final int MAX_OPTIMISITC_RETRIES = 3;
|
||||
@Value("${plugins.scan_packages}")
|
||||
private String[] scanPackages;
|
||||
|
||||
@Autowired
|
||||
private Environment environment;
|
||||
|
||||
@Autowired(required = false)
|
||||
private BeanDiscoveryService beanDiscoveryService;
|
||||
|
||||
@Autowired
|
||||
private ComponentDescriptorService componentDescriptorService;
|
||||
|
||||
@ -83,7 +80,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
|
||||
}
|
||||
|
||||
private void registerRuleNodeComponents() {
|
||||
Set<BeanDefinition> ruleNodeBeanDefinitions = getBeanDefinitions(RuleNode.class);
|
||||
Set<BeanDefinition> ruleNodeBeanDefinitions = beanDiscoveryService.discoverBeansByAnnotationType(RuleNode.class);
|
||||
for (BeanDefinition def : ruleNodeBeanDefinitions) {
|
||||
int retryCount = 0;
|
||||
Exception cause = null;
|
||||
@ -212,16 +209,6 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
|
||||
return relationTypes.toArray(new String[relationTypes.size()]);
|
||||
}
|
||||
|
||||
private Set<BeanDefinition> getBeanDefinitions(Class<? extends Annotation> componentType) {
|
||||
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
|
||||
scanner.addIncludeFilter(new AnnotationTypeFilter(componentType));
|
||||
Set<BeanDefinition> defs = new HashSet<>();
|
||||
for (String scanPackage : scanPackages) {
|
||||
defs.addAll(scanner.findCandidateComponents(scanPackage));
|
||||
}
|
||||
return defs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void discoverComponents() {
|
||||
registerRuleNodeComponents();
|
||||
|
||||
@ -17,22 +17,18 @@ package org.thingsboard.server.service.install.update;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.common.util.JacksonUtil;
|
||||
import org.thingsboard.rule.engine.api.TbNode;
|
||||
import org.thingsboard.rule.engine.api.TbNodeException;
|
||||
import org.thingsboard.rule.engine.api.VersionedNode;
|
||||
import org.thingsboard.rule.engine.api.TbVersionedNode;
|
||||
import org.thingsboard.rule.engine.flow.TbRuleChainInputNode;
|
||||
import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration;
|
||||
import org.thingsboard.rule.engine.profile.TbDeviceProfileNode;
|
||||
@ -86,17 +82,14 @@ import org.thingsboard.server.dao.sql.device.DeviceProfileRepository;
|
||||
import org.thingsboard.server.dao.tenant.TenantProfileService;
|
||||
import org.thingsboard.server.dao.tenant.TenantService;
|
||||
import org.thingsboard.server.dao.timeseries.TimeseriesService;
|
||||
import org.thingsboard.server.service.bean.BeanDiscoveryService;
|
||||
import org.thingsboard.server.service.install.InstallScripts;
|
||||
import org.thingsboard.server.service.install.SystemDataLoaderService;
|
||||
import org.thingsboard.server.service.install.TbRuleEngineQueueConfigService;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.stream.Collectors;
|
||||
@ -108,9 +101,6 @@ import static org.thingsboard.server.common.data.StringUtils.isBlank;
|
||||
@Slf4j
|
||||
public class DefaultDataUpdateService implements DataUpdateService {
|
||||
|
||||
@Value("${plugins.scan_packages}")
|
||||
private String[] scanPackages;
|
||||
|
||||
@Autowired
|
||||
private TenantService tenantService;
|
||||
|
||||
@ -149,7 +139,7 @@ public class DefaultDataUpdateService implements DataUpdateService {
|
||||
private QueueService queueService;
|
||||
|
||||
@Autowired
|
||||
private TbRuleEngineQueueConfigService queueConfig;
|
||||
private BeanDiscoveryService beanDiscoveryService;
|
||||
|
||||
@Autowired
|
||||
private SystemDataLoaderService systemDataLoaderService;
|
||||
@ -229,57 +219,54 @@ public class DefaultDataUpdateService implements DataUpdateService {
|
||||
}
|
||||
|
||||
private void upgradeRuleNodes() {
|
||||
var ruleChainIdToTenantIdMap = new HashMap<RuleChainId, TenantId>();
|
||||
try {
|
||||
log.info("Starting rule nodes upgrade ...");
|
||||
var ruleNodeDefinitions = getBeanDefinitions(
|
||||
org.thingsboard.rule.engine.api.RuleNode.class
|
||||
);
|
||||
for (BeanDefinition def : ruleNodeDefinitions) {
|
||||
String clazzName = def.getBeanClassName();
|
||||
Class<?> clazz = Class.forName(clazzName);
|
||||
TbNode tbNode = (TbNode) clazz.getDeclaredConstructor().newInstance();
|
||||
if (tbNode instanceof VersionedNode) {
|
||||
var versionedNode = (VersionedNode) tbNode;
|
||||
var ruleNodeName = versionedNode.getClass().getName();
|
||||
int currentVersion = versionedNode.getCurrentVersion();
|
||||
log.info("Lookup rule nodes to upgrade ...");
|
||||
ArrayList<TbVersionedNode> tbVersionedNodes = getTbVersionedNodes();
|
||||
log.info("Found {} versioned nodes to check for upgrade!", tbVersionedNodes.size());
|
||||
for (TbVersionedNode tbVersionedNode : tbVersionedNodes) {
|
||||
String ruleNodeType = tbVersionedNode.getClass().getName();
|
||||
String ruleNodeTypeForLogs = tbVersionedNode.getClass().getSimpleName();
|
||||
int toVersion = tbVersionedNode.getCurrentVersion();
|
||||
log.info("Going to check for nodes with type: {} to upgrade to version: {}.", ruleNodeTypeForLogs, toVersion);
|
||||
var ruleNodesToUpdate = new PageDataIterable<>(
|
||||
pageLink ->
|
||||
ruleChainService.findAllRuleNodesByTypeAndVersionLessThan(ruleNodeName, currentVersion, pageLink),
|
||||
ruleChainService.findAllRuleNodesByTypeAndVersionLessThan(
|
||||
ruleNodeType,
|
||||
toVersion,
|
||||
pageLink
|
||||
),
|
||||
1024
|
||||
);
|
||||
if (Iterables.isEmpty(ruleNodesToUpdate)) {
|
||||
log.info("There are no active nodes with type: {}, or all nodes with this type already set to latest version!", ruleNodeTypeForLogs);
|
||||
} else {
|
||||
for (RuleNode ruleNode : ruleNodesToUpdate) {
|
||||
RuleNodeId ruleNodeId = ruleNode.getId();
|
||||
var oldConfiguration = ruleNode.getConfiguration();
|
||||
int fromVersion = ruleNode.getConfigurationVersion();
|
||||
log.info("Going to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}",
|
||||
ruleNodeId,
|
||||
clazzName,
|
||||
ruleNodeTypeForLogs,
|
||||
fromVersion,
|
||||
currentVersion);
|
||||
toVersion);
|
||||
try {
|
||||
TbPair<Boolean, JsonNode> upgradeRuleNodeConfigurationResult = versionedNode.upgrade(ruleNodeId, fromVersion, oldConfiguration);
|
||||
TbPair<Boolean, JsonNode> upgradeRuleNodeConfigurationResult = tbVersionedNode.upgrade(fromVersion, oldConfiguration);
|
||||
if (upgradeRuleNodeConfigurationResult.getFirst()) {
|
||||
ruleNode.setConfiguration(upgradeRuleNodeConfigurationResult.getSecond());
|
||||
var ruleChainId = ruleNode.getRuleChainId();
|
||||
var tenantId = getTenantId(ruleChainIdToTenantIdMap, ruleNodeId, ruleChainId);
|
||||
if (tenantId == null) {
|
||||
log.warn("Failed to find tenant id for rule chain with id: {}", ruleChainId);
|
||||
continue;
|
||||
}
|
||||
ruleChainService.saveRuleNode(tenantId, ruleNode);
|
||||
ruleNode.setConfigurationVersion(toVersion);
|
||||
ruleChainService.saveRuleNode(TenantId.SYS_TENANT_ID, ruleNode);
|
||||
log.info("Successfully upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}",
|
||||
ruleNodeId,
|
||||
clazzName,
|
||||
ruleNodeTypeForLogs,
|
||||
fromVersion,
|
||||
currentVersion);
|
||||
}
|
||||
toVersion);
|
||||
} catch (TbNodeException e) {
|
||||
log.warn("Failed to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {} due to: ",
|
||||
ruleNodeId,
|
||||
clazzName,
|
||||
ruleNodeTypeForLogs,
|
||||
fromVersion,
|
||||
currentVersion,
|
||||
toVersion,
|
||||
e);
|
||||
}
|
||||
}
|
||||
@ -290,27 +277,28 @@ public class DefaultDataUpdateService implements DataUpdateService {
|
||||
log.error("Unexpected error during rule nodes upgrade: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
private TenantId getTenantId(HashMap<RuleChainId, TenantId> ruleChainIdToTenantId, RuleNodeId ruleNodeId, RuleChainId ruleChainId) {
|
||||
return ruleChainIdToTenantId.computeIfAbsent(ruleChainId,
|
||||
id -> {
|
||||
RuleChain ruleChain = ruleChainService.findRuleChainById(TenantId.SYS_TENANT_ID, id);
|
||||
if (ruleChain == null) {
|
||||
log.warn("Failed to find rule chain by id: {} ruleNodeId: {}", ruleChainId, ruleNodeId);
|
||||
return null;
|
||||
private ArrayList<TbVersionedNode> getTbVersionedNodes() {
|
||||
var ruleNodeDefinitions = beanDiscoveryService.discoverBeansByAnnotationType(
|
||||
org.thingsboard.rule.engine.api.RuleNode.class
|
||||
);
|
||||
var tbVersionedNodes = new ArrayList<TbVersionedNode>();
|
||||
for (var def : ruleNodeDefinitions) {
|
||||
String clazzName = def.getBeanClassName();
|
||||
try {
|
||||
var clazz = Class.forName(clazzName);
|
||||
if (TbVersionedNode.class.isAssignableFrom(clazz)) {
|
||||
tbVersionedNodes.add((TbVersionedNode) clazz.getDeclaredConstructor().newInstance());
|
||||
}
|
||||
return ruleChain.getTenantId();
|
||||
});
|
||||
} catch (NoSuchMethodException |
|
||||
InstantiationException |
|
||||
IllegalAccessException |
|
||||
InvocationTargetException |
|
||||
ClassNotFoundException e
|
||||
) {
|
||||
log.warn("Failed to create instance of rule node type: {} due to: ", clazzName, e);
|
||||
}
|
||||
|
||||
private Set<BeanDefinition> getBeanDefinitions(Class<? extends Annotation> componentType) {
|
||||
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
|
||||
scanner.addIncludeFilter(new AnnotationTypeFilter(componentType));
|
||||
Set<BeanDefinition> defs = new HashSet<>();
|
||||
for (String scanPackage : scanPackages) {
|
||||
defs.addAll(scanner.findCandidateComponents(scanPackage));
|
||||
}
|
||||
return defs;
|
||||
return tbVersionedNodes;
|
||||
}
|
||||
|
||||
private final PaginatedUpdater<String, DeviceProfileEntity> deviceProfileEntityDynamicConditionsUpdater =
|
||||
|
||||
@ -27,8 +27,11 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.thingsboard.common.util.JacksonUtil;
|
||||
import org.thingsboard.rule.engine.action.TbCreateAlarmNode;
|
||||
import org.thingsboard.rule.engine.action.TbCreateAlarmNodeConfiguration;
|
||||
import org.thingsboard.rule.engine.api.TbVersionedNode;
|
||||
import org.thingsboard.rule.engine.metadata.TbGetRelatedAttributeNode;
|
||||
import org.thingsboard.server.common.data.StringUtils;
|
||||
import org.thingsboard.server.common.data.Tenant;
|
||||
import org.thingsboard.server.common.data.User;
|
||||
@ -128,6 +131,82 @@ public class RuleChainControllerTest extends AbstractControllerTest {
|
||||
ActionType.UPDATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveRuleChainMetadataWithVersionedNodes() throws Exception {
|
||||
RuleChain ruleChain = new RuleChain();
|
||||
ruleChain.setName("RuleChain");
|
||||
|
||||
RuleChain savedRuleChain = doPost("/api/ruleChain", ruleChain, RuleChain.class);
|
||||
Assert.assertNotNull(savedRuleChain);
|
||||
RuleChainId ruleChainId = savedRuleChain.getId();
|
||||
Assert.assertNotNull(ruleChainId);
|
||||
Assert.assertTrue(savedRuleChain.getCreatedTime() > 0);
|
||||
Assert.assertEquals(ruleChain.getName(), savedRuleChain.getName());
|
||||
|
||||
TbVersionedNode tbVersionedNode = new TbGetRelatedAttributeNode();
|
||||
String ruleNodeType = tbVersionedNode.getClass().getName();
|
||||
int currentVersion = tbVersionedNode.getCurrentVersion();
|
||||
|
||||
String oldConfig = "{\"attrMapping\":{\"serialNumber\":\"sn\"}," +
|
||||
"\"relationsQuery\":{\"direction\":\"FROM\",\"maxLevel\":1," +
|
||||
"\"filters\":[{\"relationType\":\"Contains\",\"entityTypes\":[]}]," +
|
||||
"\"fetchLastLevelOnly\":false},\"telemetry\":false}";
|
||||
|
||||
String newConfig = "{\"fetchTo\":\"METADATA\"," +
|
||||
"\"attrMapping\":{\"serialNumber\":\"sn\"}," +
|
||||
"\"dataToFetch\":\"ATTRIBUTES\"," +
|
||||
"\"relationsQuery\":{\"direction\":\"FROM\",\"maxLevel\":1," +
|
||||
"\"filters\":[{\"relationType\":\"Contains\",\"entityTypes\":[]}]," +
|
||||
"\"fetchLastLevelOnly\":false}}";
|
||||
|
||||
var ruleChainMetaData = createRuleChainMetadataWithTbVersionedNodes(
|
||||
ruleChainId,
|
||||
ruleNodeType,
|
||||
currentVersion,
|
||||
oldConfig,
|
||||
newConfig
|
||||
);
|
||||
var savedRuleChainMetaData = doPost("/api/ruleChain/metadata", ruleChainMetaData, RuleChainMetaData.class);
|
||||
|
||||
Assert.assertEquals(ruleChainId, savedRuleChainMetaData.getRuleChainId());
|
||||
Assert.assertEquals(2, savedRuleChainMetaData.getNodes().size());
|
||||
|
||||
for (RuleNode ruleNode : savedRuleChainMetaData.getNodes()) {
|
||||
Assert.assertNotNull(ruleNode.getId());
|
||||
Assert.assertEquals(currentVersion, ruleNode.getConfigurationVersion());
|
||||
Assert.assertEquals(JacksonUtil.toJsonNode(newConfig), ruleNode.getConfiguration());
|
||||
}
|
||||
}
|
||||
|
||||
private RuleChainMetaData createRuleChainMetadataWithTbVersionedNodes(
|
||||
RuleChainId ruleChainId,
|
||||
String ruleNodeType,
|
||||
int currentVersion,
|
||||
String oldConfig,
|
||||
String newConfig
|
||||
) {
|
||||
RuleChainMetaData ruleChainMetaData = new RuleChainMetaData();
|
||||
ruleChainMetaData.setRuleChainId(ruleChainId);
|
||||
|
||||
var ruleNodeWithOldConfig = new RuleNode();
|
||||
ruleNodeWithOldConfig.setName("Old Rule Node");
|
||||
ruleNodeWithOldConfig.setType(ruleNodeType);
|
||||
ruleNodeWithOldConfig.setConfiguration(JacksonUtil.toJsonNode(oldConfig));
|
||||
|
||||
var ruleNodeWithNewConfig = new RuleNode();
|
||||
ruleNodeWithNewConfig.setName("New Rule Node");
|
||||
ruleNodeWithNewConfig.setType(ruleNodeType);
|
||||
ruleNodeWithNewConfig.setConfigurationVersion(currentVersion);
|
||||
ruleNodeWithNewConfig.setConfiguration(JacksonUtil.toJsonNode(newConfig));
|
||||
|
||||
List<RuleNode> ruleNodes = new ArrayList<>();
|
||||
ruleNodes.add(ruleNodeWithOldConfig);
|
||||
ruleNodes.add(ruleNodeWithNewConfig);
|
||||
ruleChainMetaData.setFirstNodeIndex(0);
|
||||
ruleChainMetaData.setNodes(ruleNodes);
|
||||
return ruleChainMetaData;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveRuleChainWithViolationOfLengthValidation() throws Exception {
|
||||
|
||||
|
||||
@ -28,7 +28,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.thingsboard.common.util.JacksonUtil;
|
||||
import org.thingsboard.rule.engine.api.TbNodeException;
|
||||
import org.thingsboard.rule.engine.api.VersionedNode;
|
||||
import org.thingsboard.rule.engine.api.TbVersionedNode;
|
||||
import org.thingsboard.server.common.data.BaseData;
|
||||
import org.thingsboard.server.common.data.EntityType;
|
||||
import org.thingsboard.server.common.data.edge.Edge;
|
||||
@ -185,17 +185,62 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
|
||||
}
|
||||
updatedRuleNodes.add(new RuleNodeUpdateResult(existingNode, newRuleNode));
|
||||
}
|
||||
RuleChainId ruleChainId = ruleChain.getId();
|
||||
if (nodes != null) {
|
||||
for (RuleNode node : toAddOrUpdate) {
|
||||
node.setRuleChainId(ruleChain.getId());
|
||||
node.setRuleChainId(ruleChainId);
|
||||
String ruleNodeType = node.getType();
|
||||
RuleNodeId ruleNodeId = node.getId();
|
||||
try {
|
||||
var ruleNodeClazz = Class.forName(ruleNodeType);
|
||||
if (TbVersionedNode.class.isAssignableFrom(ruleNodeClazz)) {
|
||||
TbVersionedNode tbVersionedNode = (TbVersionedNode) ruleNodeClazz.getDeclaredConstructor().newInstance();
|
||||
int fromVersion = node.getConfigurationVersion();
|
||||
int toVersion = tbVersionedNode.getCurrentVersion();
|
||||
if (fromVersion < toVersion) {
|
||||
log.debug("Going to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}",
|
||||
ruleNodeId,
|
||||
ruleNodeType,
|
||||
fromVersion,
|
||||
toVersion);
|
||||
try {
|
||||
TbPair<Boolean, JsonNode> upgradeResult = tbVersionedNode.upgrade(fromVersion, node.getConfiguration());
|
||||
if (upgradeResult.getFirst()) {
|
||||
node.setConfiguration(upgradeResult.getSecond());
|
||||
log.info("Successfully upgrade rule node with id: {} type: {}, rule chain id: {} fromVersion: {} toVersion: {}",
|
||||
ruleNodeId,
|
||||
ruleNodeType,
|
||||
ruleChainId,
|
||||
fromVersion,
|
||||
toVersion);
|
||||
}
|
||||
node.setConfigurationVersion(toVersion);
|
||||
} catch (TbNodeException e) {
|
||||
log.warn("Failed to upgrade rule node with id: {} type: {} rule chain id: {} fromVersion: {} toVersion: {} due to: ",
|
||||
ruleNodeId,
|
||||
ruleNodeType,
|
||||
ruleChainId,
|
||||
fromVersion,
|
||||
toVersion,
|
||||
e);
|
||||
}
|
||||
} else {
|
||||
log.debug("Rule node with id: {} type: {} ruleChainId: {} already set to latest version!",
|
||||
ruleNodeId,
|
||||
ruleChainId,
|
||||
ruleNodeType);
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFoundException |
|
||||
InvocationTargetException |
|
||||
InstantiationException |
|
||||
IllegalAccessException |
|
||||
NoSuchMethodException e) {
|
||||
log.error("Failed to create instance of rule node with id: {} type: {}, rule chain id: {}", ruleNodeId, ruleNodeType, ruleChainId);
|
||||
}
|
||||
RuleNode savedNode = ruleNodeDao.save(tenantId, node);
|
||||
relations.add(new EntityRelation(ruleChainMetaData.getRuleChainId(), savedNode.getId(),
|
||||
EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN));
|
||||
// TbPair<Boolean, JsonNode> upgradeResult = upgradeRuleNode(savedNode);
|
||||
// if (upgradeResult.getFirst()) {
|
||||
// savedNode.setConfiguration(upgradeResult.getSecond());
|
||||
// savedNode = ruleNodeDao.save(tenantId, savedNode);
|
||||
// }
|
||||
int index = nodes.indexOf(node);
|
||||
nodes.set(index, savedNode);
|
||||
ruleNodeIndexMap.put(savedNode.getId(), index);
|
||||
@ -228,7 +273,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
|
||||
RuleChain targetRuleChain = findRuleChainById(TenantId.SYS_TENANT_ID, targetRuleChainId);
|
||||
RuleNode targetNode = new RuleNode();
|
||||
targetNode.setName(targetRuleChain != null ? targetRuleChain.getName() : "Rule Chain Input");
|
||||
targetNode.setRuleChainId(ruleChain.getId());
|
||||
targetNode.setRuleChainId(ruleChainId);
|
||||
targetNode.setType("org.thingsboard.rule.engine.flow.TbRuleChainInputNode");
|
||||
var configuration = JacksonUtil.newObjectNode();
|
||||
configuration.put("ruleChainId", targetRuleChainId.getId().toString());
|
||||
@ -241,7 +286,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
|
||||
targetNode = ruleNodeDao.save(tenantId, targetNode);
|
||||
|
||||
EntityRelation sourceRuleChainToRuleNode = new EntityRelation();
|
||||
sourceRuleChainToRuleNode.setFrom(ruleChain.getId());
|
||||
sourceRuleChainToRuleNode.setFrom(ruleChainId);
|
||||
sourceRuleChainToRuleNode.setTo(targetNode.getId());
|
||||
sourceRuleChainToRuleNode.setType(EntityRelation.CONTAINS_TYPE);
|
||||
sourceRuleChainToRuleNode.setTypeGroup(RelationTypeGroup.RULE_CHAIN);
|
||||
@ -265,40 +310,6 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
|
||||
return RuleChainUpdateResult.successful(updatedRuleNodes);
|
||||
}
|
||||
|
||||
private TbPair<Boolean, JsonNode> upgradeRuleNode(RuleNode ruleNode) {
|
||||
RuleNodeId ruleNodeId = ruleNode.getId();
|
||||
String ruleNodeType = ruleNode.getType();
|
||||
int fromVersion = ruleNode.getConfigurationVersion();
|
||||
try {
|
||||
var ruleNodeClass = Class.forName(ruleNodeType).getDeclaredConstructor().newInstance();
|
||||
if (ruleNodeClass instanceof VersionedNode) {
|
||||
VersionedNode versionedNode = (VersionedNode) ruleNodeClass;
|
||||
int toVersion = versionedNode.getCurrentVersion();
|
||||
log.info("Going to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}",
|
||||
ruleNodeId,
|
||||
ruleNodeType,
|
||||
fromVersion,
|
||||
toVersion);
|
||||
try {
|
||||
return versionedNode.upgrade(ruleNodeId, fromVersion, ruleNode.getConfiguration());
|
||||
} catch (TbNodeException e) {
|
||||
log.warn("Failed to upgrade rule node with id: {} fromVersion: {} toVersion: {} due to: ",
|
||||
ruleNodeId,
|
||||
fromVersion,
|
||||
toVersion,
|
||||
e);
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFoundException |
|
||||
InvocationTargetException |
|
||||
InstantiationException |
|
||||
IllegalAccessException |
|
||||
NoSuchMethodException e) {
|
||||
log.warn("Failed to create instance of rule node with id: {} and type: {}", ruleNodeId, ruleNodeType);
|
||||
}
|
||||
return new TbPair<>(false, ruleNode.getConfiguration());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RuleChainMetaData loadRuleChainMetaData(TenantId tenantId, RuleChainId ruleChainId) {
|
||||
Validator.validateId(ruleChainId, "Incorrect rule chain id.");
|
||||
|
||||
@ -16,12 +16,11 @@
|
||||
package org.thingsboard.rule.engine.api;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.thingsboard.server.common.data.id.RuleNodeId;
|
||||
import org.thingsboard.server.common.data.util.TbPair;
|
||||
|
||||
public interface VersionedNode extends TbNode {
|
||||
public interface TbVersionedNode extends TbNode {
|
||||
|
||||
TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, int fromVersion, JsonNode oldConfiguration) throws TbNodeException;
|
||||
TbPair<Boolean, JsonNode> upgrade(int fromVersion, JsonNode oldConfiguration) throws TbNodeException;
|
||||
|
||||
int getCurrentVersion();
|
||||
|
||||
@ -22,12 +22,10 @@ import com.google.common.util.concurrent.Futures;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.thingsboard.common.util.JacksonUtil;
|
||||
import org.thingsboard.rule.engine.api.TbContext;
|
||||
import org.thingsboard.rule.engine.api.TbNode;
|
||||
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
|
||||
import org.thingsboard.rule.engine.api.TbNodeException;
|
||||
import org.thingsboard.rule.engine.api.VersionedNode;
|
||||
import org.thingsboard.rule.engine.api.TbVersionedNode;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.id.RuleNodeId;
|
||||
import org.thingsboard.server.common.data.kv.KvEntry;
|
||||
import org.thingsboard.server.common.data.util.TbPair;
|
||||
import org.thingsboard.server.common.msg.TbMsg;
|
||||
@ -36,7 +34,7 @@ import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
@Slf4j
|
||||
public abstract class TbAbstractNodeWithFetchTo<C extends TbAbstractFetchToNodeConfiguration> implements VersionedNode {
|
||||
public abstract class TbAbstractNodeWithFetchTo<C extends TbAbstractFetchToNodeConfiguration> implements TbVersionedNode {
|
||||
|
||||
protected final static String FETCH_TO_PROPERTY_NAME = "fetchTo";
|
||||
|
||||
|
||||
@ -25,7 +25,6 @@ import org.thingsboard.rule.engine.api.TbNodeException;
|
||||
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
||||
import org.thingsboard.server.common.data.EntityType;
|
||||
import org.thingsboard.server.common.data.id.DeviceId;
|
||||
import org.thingsboard.server.common.data.id.RuleNodeId;
|
||||
import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||
import org.thingsboard.server.common.data.security.DeviceCredentialsType;
|
||||
import org.thingsboard.server.common.data.util.TbPair;
|
||||
@ -89,7 +88,7 @@ public class TbFetchDeviceCredentialsNode extends TbAbstractNodeWithFetchTo<TbFe
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
public TbPair<Boolean, JsonNode> upgrade(int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
return fromVersion == 0 ?
|
||||
upgradeRuleNodesWithOldPropertyToUseFetchTo(
|
||||
oldConfiguration,
|
||||
|
||||
@ -25,7 +25,6 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
|
||||
import org.thingsboard.rule.engine.api.TbNodeException;
|
||||
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.id.RuleNodeId;
|
||||
import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||
import org.thingsboard.server.common.data.util.TbPair;
|
||||
import org.thingsboard.server.common.msg.TbMsg;
|
||||
@ -57,7 +56,7 @@ public class TbGetAttributesNode extends TbAbstractGetAttributesNode<TbGetAttrib
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
public TbPair<Boolean, JsonNode> upgrade(int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
return fromVersion == 0 ?
|
||||
upgradeRuleNodesWithOldPropertyToUseFetchTo(
|
||||
oldConfiguration,
|
||||
|
||||
@ -27,7 +27,6 @@ import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
||||
import org.thingsboard.rule.engine.util.EntitiesCustomerIdAsyncLoader;
|
||||
import org.thingsboard.server.common.data.id.CustomerId;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.id.RuleNodeId;
|
||||
import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||
import org.thingsboard.server.common.data.util.TbPair;
|
||||
|
||||
@ -72,7 +71,7 @@ public class TbGetCustomerAttributeNode extends TbAbstractGetEntityAttrNode<Cust
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
public TbPair<Boolean, JsonNode> upgrade(int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
return fromVersion == 0 ?
|
||||
upgradeToUseFetchToAndDataToFetch(oldConfiguration) :
|
||||
new TbPair<>(false, oldConfiguration);
|
||||
|
||||
@ -33,7 +33,6 @@ import org.thingsboard.server.common.data.id.DeviceId;
|
||||
import org.thingsboard.server.common.data.id.EdgeId;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.id.EntityViewId;
|
||||
import org.thingsboard.server.common.data.id.RuleNodeId;
|
||||
import org.thingsboard.server.common.data.id.UserId;
|
||||
import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||
import org.thingsboard.server.common.data.util.TbPair;
|
||||
@ -107,7 +106,7 @@ public class TbGetCustomerDetailsNode extends TbAbstractGetEntityDetailsNode<TbG
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
public TbPair<Boolean, JsonNode> upgrade(int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
return fromVersion == 0 ?
|
||||
upgradeRuleNodesWithOldPropertyToUseFetchTo(
|
||||
oldConfiguration,
|
||||
|
||||
@ -26,7 +26,6 @@ import org.thingsboard.rule.engine.api.TbNodeException;
|
||||
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
||||
import org.thingsboard.rule.engine.util.EntitiesRelatedDeviceIdAsyncLoader;
|
||||
import org.thingsboard.server.common.data.id.DeviceId;
|
||||
import org.thingsboard.server.common.data.id.RuleNodeId;
|
||||
import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||
import org.thingsboard.server.common.data.util.TbPair;
|
||||
import org.thingsboard.server.common.msg.TbMsg;
|
||||
@ -60,7 +59,7 @@ public class TbGetDeviceAttrNode extends TbAbstractGetAttributesNode<TbGetDevice
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
public TbPair<Boolean, JsonNode> upgrade(int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
return fromVersion == 0 ?
|
||||
upgradeRuleNodesWithOldPropertyToUseFetchTo(
|
||||
oldConfiguration,
|
||||
|
||||
@ -28,7 +28,6 @@ import org.thingsboard.rule.engine.api.TbNodeException;
|
||||
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
||||
import org.thingsboard.rule.engine.util.EntitiesFieldsAsyncLoader;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.id.RuleNodeId;
|
||||
import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||
import org.thingsboard.server.common.data.util.TbPair;
|
||||
import org.thingsboard.server.common.msg.TbMsg;
|
||||
@ -102,7 +101,7 @@ public class TbGetOriginatorFieldsNode extends TbAbstractNodeWithFetchTo<TbGetOr
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, int fromVersion, JsonNode oldConfiguration) {
|
||||
public TbPair<Boolean, JsonNode> upgrade(int fromVersion, JsonNode oldConfiguration) {
|
||||
if (fromVersion == 0) {
|
||||
var newConfigObjectNode = (ObjectNode) oldConfiguration;
|
||||
newConfigObjectNode.put(FETCH_TO_PROPERTY_NAME, FetchTo.METADATA.name());
|
||||
|
||||
@ -26,7 +26,6 @@ import org.thingsboard.rule.engine.api.TbNodeException;
|
||||
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
||||
import org.thingsboard.rule.engine.util.EntitiesRelatedEntityIdAsyncLoader;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.id.RuleNodeId;
|
||||
import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||
import org.thingsboard.server.common.data.util.TbPair;
|
||||
|
||||
@ -75,7 +74,7 @@ public class TbGetRelatedAttributeNode extends TbAbstractGetEntityAttrNode<Entit
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
public TbPair<Boolean, JsonNode> upgrade(int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
return fromVersion == 0 ? upgradeToUseFetchToAndDataToFetch(oldConfiguration) : new TbPair<>(false, oldConfiguration);
|
||||
}
|
||||
|
||||
|
||||
@ -25,7 +25,6 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
|
||||
import org.thingsboard.rule.engine.api.TbNodeException;
|
||||
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.id.RuleNodeId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||
import org.thingsboard.server.common.data.util.TbPair;
|
||||
@ -66,7 +65,7 @@ public class TbGetTenantAttributeNode extends TbAbstractGetEntityAttrNode<Tenant
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
public TbPair<Boolean, JsonNode> upgrade(int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
return fromVersion == 0 ? upgradeToUseFetchToAndDataToFetch(oldConfiguration) : new TbPair<>(false, oldConfiguration);
|
||||
}
|
||||
|
||||
|
||||
@ -24,7 +24,6 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
|
||||
import org.thingsboard.rule.engine.api.TbNodeException;
|
||||
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
||||
import org.thingsboard.server.common.data.Tenant;
|
||||
import org.thingsboard.server.common.data.id.RuleNodeId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||
import org.thingsboard.server.common.data.util.TbPair;
|
||||
@ -62,7 +61,7 @@ public class TbGetTenantDetailsNode extends TbAbstractGetEntityDetailsNode<TbGet
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
public TbPair<Boolean, JsonNode> upgrade(int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
return fromVersion == 0 ?
|
||||
upgradeRuleNodesWithOldPropertyToUseFetchTo(
|
||||
oldConfiguration,
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.thingsboard.rule.engine.metadata;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@ -31,6 +32,7 @@ import org.thingsboard.server.common.data.id.CustomerId;
|
||||
import org.thingsboard.server.common.data.id.DeviceId;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.security.DeviceCredentials;
|
||||
import org.thingsboard.server.common.data.util.TbPair;
|
||||
import org.thingsboard.server.common.msg.TbMsg;
|
||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||
import org.thingsboard.server.common.msg.queue.TbMsgCallback;
|
||||
@ -40,6 +42,8 @@ import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.willAnswer;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
@ -67,7 +71,6 @@ public class TbFetchDeviceCredentialsNodeTest {
|
||||
void setUp() throws TbNodeException {
|
||||
deviceId = new DeviceId(UUID.randomUUID());
|
||||
config = new TbFetchDeviceCredentialsNodeConfiguration().defaultConfiguration();
|
||||
config.setFetchTo(FetchTo.METADATA);
|
||||
node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config)));
|
||||
}
|
||||
|
||||
@ -150,6 +153,15 @@ public class TbFetchDeviceCredentialsNodeTest {
|
||||
assertThat(exceptionCaptor.getValue()).isInstanceOf(RuntimeException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenOldConfig_whenUpgrade_thenShouldReturnSuccessResult() throws Exception {
|
||||
String oldConfig = "{\"fetchToMetadata\":true}";
|
||||
JsonNode configJson = JacksonUtil.toJsonNode(oldConfig);
|
||||
TbPair<Boolean, JsonNode> upgrade = node.upgrade(0, configJson);
|
||||
assertTrue(upgrade.getFirst());
|
||||
assertEquals(JacksonUtil.valueToTree(config), upgrade.getSecond());
|
||||
}
|
||||
|
||||
private TbMsg getTbMsg(EntityId entityId) {
|
||||
final Map<String, String> mdMap = Map.of(
|
||||
"country", "US",
|
||||
|
||||
@ -16,10 +16,12 @@
|
||||
package org.thingsboard.rule.engine.metadata;
|
||||
|
||||
import com.datastax.oss.driver.api.core.uuid.Uuids;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
@ -39,6 +41,7 @@ import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
|
||||
import org.thingsboard.server.common.data.kv.JsonDataEntry;
|
||||
import org.thingsboard.server.common.data.kv.StringDataEntry;
|
||||
import org.thingsboard.server.common.data.kv.TsKvEntry;
|
||||
import org.thingsboard.server.common.data.util.TbPair;
|
||||
import org.thingsboard.server.common.msg.TbMsg;
|
||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||
import org.thingsboard.server.dao.attributes.AttributesService;
|
||||
@ -247,6 +250,23 @@ public class TbGetAttributesNodeTest {
|
||||
assertThat(exception.getMessage()).isEqualTo("Message body is not an object!");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenOldConfig_whenUpgrade_thenShouldReturnSuccessResult() throws Exception {
|
||||
var defaultConfig = new TbGetAttributesNodeConfiguration().defaultConfiguration();
|
||||
var node = new TbGetAttributesNode();
|
||||
String oldConfig = "{\"fetchToData\":false," +
|
||||
"\"clientAttributeNames\":[]," +
|
||||
"\"sharedAttributeNames\":[]," +
|
||||
"\"serverAttributeNames\":[]," +
|
||||
"\"latestTsKeyNames\":[]," +
|
||||
"\"tellFailureIfAbsent\":true," +
|
||||
"\"getLatestValueWithTs\":false}";
|
||||
JsonNode configJson = JacksonUtil.toJsonNode(oldConfig);
|
||||
TbPair<Boolean, JsonNode> upgrade = node.upgrade(0, configJson);
|
||||
Assertions.assertTrue(upgrade.getFirst());
|
||||
Assertions.assertEquals(JacksonUtil.valueToTree(defaultConfig), upgrade.getSecond());
|
||||
}
|
||||
|
||||
private TbMsg checkMsg(boolean checkSuccess) {
|
||||
var msgCaptor = ArgumentCaptor.forClass(TbMsg.class);
|
||||
if (checkSuccess) {
|
||||
|
||||
@ -15,10 +15,12 @@
|
||||
*/
|
||||
package org.thingsboard.rule.engine.metadata;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@ -46,6 +48,7 @@ import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
|
||||
import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
|
||||
import org.thingsboard.server.common.data.kv.StringDataEntry;
|
||||
import org.thingsboard.server.common.data.kv.TsKvEntry;
|
||||
import org.thingsboard.server.common.data.util.TbPair;
|
||||
import org.thingsboard.server.common.msg.TbMsg;
|
||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||
import org.thingsboard.server.dao.asset.AssetService;
|
||||
@ -451,6 +454,17 @@ public class TbGetCustomerAttributeNodeTest {
|
||||
assertThat(actualMessageCaptor.getValue().getMetaData()).isEqualTo(expectedMsgMetaData);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenOldConfig_whenUpgrade_thenShouldReturnSuccessResult() throws Exception {
|
||||
var defaultConfig = new TbGetEntityAttrNodeConfiguration().defaultConfiguration();
|
||||
var node = new TbGetCustomerAttributeNode();
|
||||
String oldConfig = "{\"attrMapping\":{\"alarmThreshold\":\"threshold\"},\"telemetry\":false}";
|
||||
JsonNode configJson = JacksonUtil.toJsonNode(oldConfig);
|
||||
TbPair<Boolean, JsonNode> upgrade = node.upgrade(0, configJson);
|
||||
Assertions.assertTrue(upgrade.getFirst());
|
||||
Assertions.assertEquals(JacksonUtil.valueToTree(defaultConfig), upgrade.getSecond());
|
||||
}
|
||||
|
||||
private void prepareMsgAndConfig(FetchTo fetchTo, DataToFetch dataToFetch, EntityId originator) {
|
||||
config.setAttrMapping(Map.of(
|
||||
"sourceKey1", "targetKey1",
|
||||
|
||||
@ -15,9 +15,11 @@
|
||||
*/
|
||||
package org.thingsboard.rule.engine.metadata;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@ -44,6 +46,7 @@ import org.thingsboard.server.common.data.id.EdgeId;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.id.UserId;
|
||||
import org.thingsboard.server.common.data.util.TbPair;
|
||||
import org.thingsboard.server.common.msg.TbMsg;
|
||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||
import org.thingsboard.server.dao.asset.AssetService;
|
||||
@ -444,6 +447,17 @@ public class TbGetCustomerDetailsNodeTest {
|
||||
assertThat(actualException.getMessage()).isEqualTo("Entity with entityType 'DASHBOARD' is not supported.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenOldConfig_whenUpgrade_thenShouldReturnSuccessResult() throws Exception {
|
||||
var defaultConfig = new TbGetCustomerDetailsNodeConfiguration().defaultConfiguration();
|
||||
var node = new TbGetCustomerDetailsNode();
|
||||
String oldConfig = "{\"detailsList\":[],\"addToMetadata\":false}";
|
||||
JsonNode configJson = JacksonUtil.toJsonNode(oldConfig);
|
||||
TbPair<Boolean, JsonNode> upgrade = node.upgrade(0, configJson);
|
||||
Assertions.assertTrue(upgrade.getFirst());
|
||||
Assertions.assertEquals(JacksonUtil.valueToTree(defaultConfig), upgrade.getSecond());
|
||||
}
|
||||
|
||||
private void prepareMsgAndConfig(FetchTo fetchTo, List<ContactBasedEntityDetails> detailsList, EntityId originator) {
|
||||
config.setDetailsList(detailsList);
|
||||
config.setFetchTo(fetchTo);
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright © 2016-2023 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.rule.engine.metadata;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.thingsboard.common.util.JacksonUtil;
|
||||
import org.thingsboard.server.common.data.util.TbPair;
|
||||
|
||||
public class TbGetDeviceAttrNodeTest {
|
||||
|
||||
@Test
|
||||
public void givenOldConfig_whenUpgrade_thenShouldReturnSuccessResult() throws Exception {
|
||||
var defaultConfig = new TbGetDeviceAttrNodeConfiguration().defaultConfiguration();
|
||||
var node = new TbGetDeviceAttrNode();
|
||||
String oldConfig = "{\"fetchToData\":false," +
|
||||
"\"clientAttributeNames\":[]," +
|
||||
"\"sharedAttributeNames\":[]," +
|
||||
"\"serverAttributeNames\":[]," +
|
||||
"\"latestTsKeyNames\":[]," +
|
||||
"\"tellFailureIfAbsent\":true," +
|
||||
"\"getLatestValueWithTs\":false," +
|
||||
"\"deviceRelationsQuery\":{\"direction\":\"FROM\",\"maxLevel\":1,\"relationType\":\"Contains\",\"deviceTypes\":[\"default\"]," +
|
||||
"\"fetchLastLevelOnly\":false}}";
|
||||
JsonNode configJson = JacksonUtil.toJsonNode(oldConfig);
|
||||
TbPair<Boolean, JsonNode> upgrade = node.upgrade(0, configJson);
|
||||
Assertions.assertTrue(upgrade.getFirst());
|
||||
Assertions.assertEquals(JacksonUtil.valueToTree(defaultConfig), upgrade.getSecond());
|
||||
}
|
||||
|
||||
}
|
||||
@ -15,9 +15,11 @@
|
||||
*/
|
||||
package org.thingsboard.rule.engine.metadata;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@ -33,6 +35,7 @@ import org.thingsboard.server.common.data.Device;
|
||||
import org.thingsboard.server.common.data.id.DashboardId;
|
||||
import org.thingsboard.server.common.data.id.DeviceId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.util.TbPair;
|
||||
import org.thingsboard.server.common.msg.TbMsg;
|
||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||
import org.thingsboard.server.dao.device.DeviceService;
|
||||
@ -339,4 +342,15 @@ public class TbGetOriginatorFieldsNodeTest {
|
||||
assertThat(actualMessageCaptor.getValue().getMetaData()).isEqualTo(msgMetaData);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenOldConfig_whenUpgrade_thenShouldReturnSuccessResult() throws Exception {
|
||||
var defaultConfig = new TbGetOriginatorFieldsConfiguration().defaultConfiguration();
|
||||
var node = new TbGetOriginatorFieldsNode();
|
||||
String oldConfig = "{\"fieldsMapping\":{\"name\":\"originatorName\",\"type\":\"originatorType\"},\"ignoreNullStrings\":false}";
|
||||
JsonNode configJson = JacksonUtil.toJsonNode(oldConfig);
|
||||
TbPair<Boolean, JsonNode> upgrade = node.upgrade(0, configJson);
|
||||
Assertions.assertTrue(upgrade.getFirst());
|
||||
Assertions.assertEquals(JacksonUtil.valueToTree(defaultConfig), upgrade.getSecond());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -15,10 +15,12 @@
|
||||
*/
|
||||
package org.thingsboard.rule.engine.metadata;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@ -43,6 +45,7 @@ import org.thingsboard.server.common.data.kv.TsKvEntry;
|
||||
import org.thingsboard.server.common.data.relation.EntityRelation;
|
||||
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
|
||||
import org.thingsboard.server.common.data.relation.RelationEntityTypeFilter;
|
||||
import org.thingsboard.server.common.data.util.TbPair;
|
||||
import org.thingsboard.server.common.msg.TbMsg;
|
||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||
import org.thingsboard.server.common.msg.session.SessionMsgType;
|
||||
@ -548,6 +551,21 @@ public class TbGetRelatedAttributeNodeTest {
|
||||
assertThat(actualMessageCaptor.getValue().getMetaData()).isEqualTo(expectedMsgMetadata);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenOldConfig_whenUpgrade_thenShouldReturnSuccessResult() throws Exception {
|
||||
var defaultConfig = new TbGetRelatedAttrNodeConfiguration().defaultConfiguration();
|
||||
var node = new TbGetRelatedAttributeNode();
|
||||
String oldConfig = "{\"attrMapping\":{\"serialNumber\":\"sn\"}," +
|
||||
"\"relationsQuery\":{\"direction\":\"FROM\",\"maxLevel\":1," +
|
||||
"\"filters\":[{\"relationType\":\"Contains\",\"entityTypes\":[]}]," +
|
||||
"\"fetchLastLevelOnly\":false}," +
|
||||
"\"telemetry\":false}";
|
||||
JsonNode configJson = JacksonUtil.toJsonNode(oldConfig);
|
||||
TbPair<Boolean, JsonNode> upgrade = node.upgrade(0, configJson);
|
||||
Assertions.assertTrue(upgrade.getFirst());
|
||||
Assertions.assertEquals(JacksonUtil.valueToTree(defaultConfig), upgrade.getSecond());
|
||||
}
|
||||
|
||||
private void prepareMsgAndConfig(FetchTo fetchTo, DataToFetch dataToFetch, EntityId originator) {
|
||||
|
||||
config.setDataToFetch(dataToFetch);
|
||||
|
||||
@ -15,10 +15,12 @@
|
||||
*/
|
||||
package org.thingsboard.rule.engine.metadata;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@ -41,6 +43,7 @@ import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
|
||||
import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
|
||||
import org.thingsboard.server.common.data.kv.StringDataEntry;
|
||||
import org.thingsboard.server.common.data.kv.TsKvEntry;
|
||||
import org.thingsboard.server.common.data.util.TbPair;
|
||||
import org.thingsboard.server.common.msg.TbMsg;
|
||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||
import org.thingsboard.server.dao.attributes.AttributesService;
|
||||
@ -381,6 +384,17 @@ public class TbGetTenantAttributeNodeTest {
|
||||
assertThat(actualMessageCaptor.getValue().getMetaData()).isEqualTo(expectedMsgMetaData);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenOldConfig_whenUpgrade_thenShouldReturnSuccessResult() throws Exception {
|
||||
var defaultConfig = new TbGetEntityAttrNodeConfiguration().defaultConfiguration();
|
||||
var node = new TbGetTenantAttributeNode();
|
||||
String oldConfig = "{\"attrMapping\":{\"alarmThreshold\":\"threshold\"},\"telemetry\":false}";
|
||||
JsonNode configJson = JacksonUtil.toJsonNode(oldConfig);
|
||||
TbPair<Boolean, JsonNode> upgrade = node.upgrade(0, configJson);
|
||||
Assertions.assertTrue(upgrade.getFirst());
|
||||
Assertions.assertEquals(JacksonUtil.valueToTree(defaultConfig), upgrade.getSecond());
|
||||
}
|
||||
|
||||
private void prepareMsgAndConfig(FetchTo fetchTo, DataToFetch dataToFetch, EntityId originator) {
|
||||
config.setAttrMapping(Map.of(
|
||||
"sourceKey1", "targetKey1",
|
||||
|
||||
@ -15,7 +15,9 @@
|
||||
*/
|
||||
package org.thingsboard.rule.engine.metadata;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@ -30,6 +32,7 @@ import org.thingsboard.rule.engine.util.ContactBasedEntityDetails;
|
||||
import org.thingsboard.server.common.data.Tenant;
|
||||
import org.thingsboard.server.common.data.id.DeviceId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.util.TbPair;
|
||||
import org.thingsboard.server.common.msg.TbMsg;
|
||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||
import org.thingsboard.server.dao.tenant.TenantService;
|
||||
@ -259,6 +262,17 @@ public class TbGetTenantDetailsNodeTest {
|
||||
assertThat(actualMessageCaptor.getValue().getMetaData()).isEqualTo(msg.getMetaData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenOldConfig_whenUpgrade_thenShouldReturnSuccessResult() throws Exception {
|
||||
var defaultConfig = new TbGetTenantDetailsNodeConfiguration().defaultConfiguration();
|
||||
var node = new TbGetTenantDetailsNode();
|
||||
String oldConfig = "{\"detailsList\":[],\"addToMetadata\":false}";
|
||||
JsonNode configJson = JacksonUtil.toJsonNode(oldConfig);
|
||||
TbPair<Boolean, JsonNode> upgrade = node.upgrade(0, configJson);
|
||||
Assertions.assertTrue(upgrade.getFirst());
|
||||
Assertions.assertEquals(JacksonUtil.valueToTree(defaultConfig), upgrade.getSecond());
|
||||
}
|
||||
|
||||
private void prepareMsgAndConfig(FetchTo fetchTo, List<ContactBasedEntityDetails> detailsList) {
|
||||
config.setDetailsList(detailsList);
|
||||
config.setFetchTo(fetchTo);
|
||||
|
||||
@ -555,6 +555,7 @@ export class RuleChainPageComponent extends PageComponent
|
||||
ruleNodeId: ruleNode.id,
|
||||
additionalInfo: ruleNode.additionalInfo,
|
||||
configuration: ruleNode.configuration,
|
||||
configurationVersion: ruleNode.configurationVersion,
|
||||
debugMode: ruleNode.debugMode,
|
||||
singletonMode: ruleNode.singletonMode,
|
||||
x: Math.round(ruleNode.additionalInfo.layoutX),
|
||||
@ -1424,6 +1425,7 @@ export class RuleChainPageComponent extends PageComponent
|
||||
id: node.ruleNodeId,
|
||||
type: node.component.clazz,
|
||||
name: node.name,
|
||||
configurationVersion: node.configurationVersion,
|
||||
configuration: node.configuration,
|
||||
additionalInfo: node.additionalInfo ? node.additionalInfo : {},
|
||||
debugMode: node.debugMode,
|
||||
|
||||
@ -37,6 +37,7 @@ export interface RuleNode extends BaseData<RuleNodeId> {
|
||||
name: string;
|
||||
debugMode: boolean;
|
||||
singletonMode: boolean;
|
||||
configurationVersion?: number;
|
||||
configuration: RuleNodeConfiguration;
|
||||
additionalInfo?: any;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user