init commit for transformation nodes && improved error handling on init for fetchTo based nodes
This commit is contained in:
parent
cc441b4148
commit
40c957aabb
@ -32,6 +32,7 @@ import org.thingsboard.server.common.data.util.TbPair;
|
|||||||
import org.thingsboard.server.common.msg.TbMsg;
|
import org.thingsboard.server.common.msg.TbMsg;
|
||||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -46,10 +47,9 @@ public abstract class TbAbstractNodeWithFetchTo<C extends TbAbstractFetchToNodeC
|
|||||||
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
|
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
|
||||||
config = loadNodeConfiguration(configuration);
|
config = loadNodeConfiguration(configuration);
|
||||||
if (config.getFetchTo() == null) {
|
if (config.getFetchTo() == null) {
|
||||||
throw new TbNodeException("FetchTo cannot be null!");
|
throw new TbNodeException("FetchTo option can't be null! Allowed values: " + Arrays.toString(TbMsgSource.values()));
|
||||||
} else {
|
|
||||||
fetchTo = config.getFetchTo();
|
|
||||||
}
|
}
|
||||||
|
fetchTo = config.getFetchTo();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract C loadNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException;
|
protected abstract C loadNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException;
|
||||||
|
|||||||
@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* 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.transform;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
|
import org.thingsboard.rule.engine.api.TbNode;
|
||||||
|
import org.thingsboard.rule.engine.api.TbNodeException;
|
||||||
|
import org.thingsboard.rule.engine.util.TbMsgSource;
|
||||||
|
import org.thingsboard.server.common.data.util.TbPair;
|
||||||
|
|
||||||
|
public abstract class TbAbstractTransformNodeWithTbMsgSource implements TbNode {
|
||||||
|
|
||||||
|
private static final String FROM_METADATA_PROPERTY = "fromMetadata";
|
||||||
|
|
||||||
|
protected abstract String getKeyToUpgradeFromVersionZero();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbPair<Boolean, JsonNode> upgrade(int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||||
|
return fromVersion == 0 ?
|
||||||
|
upgradeToUseTbMsgSource((ObjectNode) oldConfiguration, getKeyToUpgradeFromVersionZero()) :
|
||||||
|
new TbPair<>(false, oldConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TbPair<Boolean, JsonNode> upgradeToUseTbMsgSource(ObjectNode configToUpdate, String newProperty) throws TbNodeException {
|
||||||
|
if (!configToUpdate.has(FROM_METADATA_PROPERTY)) {
|
||||||
|
throw new TbNodeException("property to update: '" + FROM_METADATA_PROPERTY + "' doesn't exists in configuration!");
|
||||||
|
}
|
||||||
|
var value = configToUpdate.get(FROM_METADATA_PROPERTY).asText();
|
||||||
|
if ("true".equals(value)) {
|
||||||
|
configToUpdate.remove(FROM_METADATA_PROPERTY);
|
||||||
|
configToUpdate.put(newProperty, TbMsgSource.METADATA.name());
|
||||||
|
return new TbPair<>(true, configToUpdate);
|
||||||
|
}
|
||||||
|
if ("false".equals(value)) {
|
||||||
|
configToUpdate.remove(FROM_METADATA_PROPERTY);
|
||||||
|
configToUpdate.put(newProperty, TbMsgSource.DATA.name());
|
||||||
|
return new TbPair<>(true, configToUpdate);
|
||||||
|
}
|
||||||
|
throw new TbNodeException("property to update: '" + FROM_METADATA_PROPERTY + "' has unexpected value: "
|
||||||
|
+ value + ". Allowed values: true or false!");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -43,10 +43,14 @@ import java.util.NoSuchElementException;
|
|||||||
type = ComponentType.TRANSFORMATION,
|
type = ComponentType.TRANSFORMATION,
|
||||||
name = "change originator",
|
name = "change originator",
|
||||||
configClazz = TbChangeOriginatorNodeConfiguration.class,
|
configClazz = TbChangeOriginatorNodeConfiguration.class,
|
||||||
nodeDescription = "Change Message Originator To Tenant/Customer/Related Entity/Alarm Originator",
|
nodeDescription = "Change Message Originator To Tenant/Customer/Related Entity/Alarm Originator/Entity by name pattern",
|
||||||
nodeDetails = "Related Entity found using configured relation direction and Relation Type. " +
|
nodeDetails = "Related Entity found using configured relation direction and Relation Type. " +
|
||||||
"If multiple Related Entities are found, only first Entity is used as new Originator, other entities are discarded.<br/>" +
|
"If multiple related entities are found, only first entity is used as new originator, other entities are discarded.<br/>" +
|
||||||
"Alarm Originator found only in case original Originator is <code>Alarm</code> entity.",
|
"Alarm Originator might be found only if the original Originator is <code>Alarm</code> entity.<br/>" +
|
||||||
|
"Entity by name pattern lookup only if found only in case original Originator is <code>Alarm</code> entity.<br/> " +
|
||||||
|
"Lookup of an entity by name pattern requires selection of entity type and name pattern to be specified in the configuration. " +
|
||||||
|
"Allowed entity types to select: 'DEVICE', 'ASSET', 'ENTITY_VIEW', 'EDGE' and 'USER'.<br><br>" +
|
||||||
|
"Output connections: <code>Success</code>, <code>Failure</code>.",
|
||||||
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
||||||
configDirective = "tbTransformationNodeChangeOriginatorConfig",
|
configDirective = "tbTransformationNodeChangeOriginatorConfig",
|
||||||
icon = "find_replace"
|
icon = "find_replace"
|
||||||
|
|||||||
@ -21,59 +21,63 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.thingsboard.common.util.JacksonUtil;
|
import org.thingsboard.common.util.JacksonUtil;
|
||||||
import org.thingsboard.rule.engine.api.RuleNode;
|
import org.thingsboard.rule.engine.api.RuleNode;
|
||||||
import org.thingsboard.rule.engine.api.TbContext;
|
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.TbNodeConfiguration;
|
||||||
import org.thingsboard.rule.engine.api.TbNodeException;
|
import org.thingsboard.rule.engine.api.TbNodeException;
|
||||||
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
||||||
|
import org.thingsboard.rule.engine.util.TbMsgSource;
|
||||||
import org.thingsboard.server.common.data.plugin.ComponentType;
|
import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||||
import org.thingsboard.server.common.msg.TbMsg;
|
import org.thingsboard.server.common.msg.TbMsg;
|
||||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RuleNode(
|
@RuleNode(
|
||||||
type = ComponentType.TRANSFORMATION,
|
type = ComponentType.TRANSFORMATION,
|
||||||
name = "copy keys",
|
name = "copy key-values",
|
||||||
|
version = 1,
|
||||||
configClazz = TbCopyKeysNodeConfiguration.class,
|
configClazz = TbCopyKeysNodeConfiguration.class,
|
||||||
nodeDescription = "Copies the msg or metadata keys with specified key names selected in the list",
|
nodeDescription = "Copies key-values from message to message metadata or vice-versa.",
|
||||||
nodeDetails = "Will fetch fields values specified in list. If specified field is not part of msg or metadata fields it will be ignored." +
|
nodeDetails = "Fetches key-values from message or message metadata based on the keys list specified in the configuration " +
|
||||||
"Returns transformed messages via <code>Success</code> chain",
|
"and copies them into message metadata or message. Keys that are absent in the fetch source will be ignored. " +
|
||||||
|
"Use regular expression(s) as a key(s) to copy keys by pattern.<br><br>" +
|
||||||
|
"Output connections: <code>Success</code>, <code>Failure</code>.",
|
||||||
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
||||||
configDirective = "tbTransformationNodeCopyKeysConfig",
|
configDirective = "tbTransformationNodeCopyKeysConfig",
|
||||||
icon = "content_copy"
|
icon = "content_copy"
|
||||||
)
|
)
|
||||||
public class TbCopyKeysNode implements TbNode {
|
public class TbCopyKeysNode extends TbAbstractTransformNodeWithTbMsgSource {
|
||||||
|
|
||||||
private TbCopyKeysNodeConfiguration config;
|
private TbCopyKeysNodeConfiguration config;
|
||||||
private List<Pattern> patternKeys;
|
private List<Pattern> patternKeys;
|
||||||
private boolean fromMetadata;
|
private TbMsgSource copyFrom;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
|
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
|
||||||
this.config = TbNodeUtils.convert(configuration, TbCopyKeysNodeConfiguration.class);
|
this.config = TbNodeUtils.convert(configuration, TbCopyKeysNodeConfiguration.class);
|
||||||
this.fromMetadata = config.isFromMetadata();
|
this.copyFrom = config.getCopyFrom();
|
||||||
this.patternKeys = new ArrayList<>();
|
if (copyFrom == null) {
|
||||||
config.getKeys().forEach(key -> {
|
throw new TbNodeException("CopyFrom can't be null! Allowed values: " + Arrays.toString(TbMsgSource.values()));
|
||||||
this.patternKeys.add(Pattern.compile(key));
|
}
|
||||||
});
|
this.patternKeys = config.getKeys().stream().map(Pattern::compile).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException {
|
public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException {
|
||||||
TbMsgMetaData metaData = msg.getMetaData();
|
var metaDataCopy = msg.getMetaData().copy();
|
||||||
String msgData = msg.getData();
|
String msgData = msg.getData();
|
||||||
boolean msgChanged = false;
|
boolean msgChanged = false;
|
||||||
JsonNode dataNode = JacksonUtil.toJsonNode(msgData);
|
JsonNode dataNode = JacksonUtil.toJsonNode(msgData);
|
||||||
if (dataNode.isObject()) {
|
if (dataNode.isObject()) {
|
||||||
if (fromMetadata) {
|
switch (copyFrom) {
|
||||||
|
case METADATA:
|
||||||
ObjectNode msgDataNode = (ObjectNode) dataNode;
|
ObjectNode msgDataNode = (ObjectNode) dataNode;
|
||||||
Map<String, String> metaDataMap = metaData.getData();
|
Map<String, String> metaDataMap = metaDataCopy.getData();
|
||||||
for (Map.Entry<String, String> entry : metaDataMap.entrySet()) {
|
for (Map.Entry<String, String> entry : metaDataMap.entrySet()) {
|
||||||
String keyData = entry.getKey();
|
String keyData = entry.getKey();
|
||||||
if (checkKey(keyData)) {
|
if (checkKey(keyData)) {
|
||||||
@ -82,26 +86,33 @@ public class TbCopyKeysNode implements TbNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
msgData = JacksonUtil.toString(msgDataNode);
|
msgData = JacksonUtil.toString(msgDataNode);
|
||||||
} else {
|
break;
|
||||||
|
case DATA:
|
||||||
Iterator<Map.Entry<String, JsonNode>> iteratorNode = dataNode.fields();
|
Iterator<Map.Entry<String, JsonNode>> iteratorNode = dataNode.fields();
|
||||||
while (iteratorNode.hasNext()) {
|
while (iteratorNode.hasNext()) {
|
||||||
Map.Entry<String, JsonNode> entry = iteratorNode.next();
|
Map.Entry<String, JsonNode> entry = iteratorNode.next();
|
||||||
String keyData = entry.getKey();
|
String keyData = entry.getKey();
|
||||||
if (checkKey(keyData)) {
|
if (checkKey(keyData)) {
|
||||||
msgChanged = true;
|
msgChanged = true;
|
||||||
metaData.putValue(keyData, JacksonUtil.toString(entry.getValue()));
|
metaDataCopy.putValue(keyData, JacksonUtil.toString(entry.getValue()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log.debug("Unexpected CopyFrom value: {}. Allowed values: {}", copyFrom, TbMsgSource.values());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (msgChanged) {
|
ctx.tellSuccess(msgChanged ? TbMsg.transformMsg(msg, metaDataCopy, msgData) : msg);
|
||||||
ctx.tellSuccess(TbMsg.transformMsg(msg, metaData, msgData));
|
|
||||||
} else {
|
|
||||||
ctx.tellSuccess(msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getKeyToUpgradeFromVersionZero() {
|
||||||
|
return "copyFrom";
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean checkKey(String key) {
|
boolean checkKey(String key) {
|
||||||
return patternKeys.stream().anyMatch(pattern -> pattern.matcher(key).matches());
|
return patternKeys.stream().anyMatch(pattern -> pattern.matcher(key).matches());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,7 @@ package org.thingsboard.rule.engine.transform;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.thingsboard.rule.engine.api.NodeConfiguration;
|
import org.thingsboard.rule.engine.api.NodeConfiguration;
|
||||||
|
import org.thingsboard.rule.engine.util.TbMsgSource;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -24,14 +25,14 @@ import java.util.Set;
|
|||||||
@Data
|
@Data
|
||||||
public class TbCopyKeysNodeConfiguration implements NodeConfiguration<TbCopyKeysNodeConfiguration> {
|
public class TbCopyKeysNodeConfiguration implements NodeConfiguration<TbCopyKeysNodeConfiguration> {
|
||||||
|
|
||||||
private boolean fromMetadata;
|
private TbMsgSource copyFrom;
|
||||||
private Set<String> keys;
|
private Set<String> keys;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TbCopyKeysNodeConfiguration defaultConfiguration() {
|
public TbCopyKeysNodeConfiguration defaultConfiguration() {
|
||||||
TbCopyKeysNodeConfiguration configuration = new TbCopyKeysNodeConfiguration();
|
TbCopyKeysNodeConfiguration configuration = new TbCopyKeysNodeConfiguration();
|
||||||
configuration.setKeys(Collections.emptySet());
|
configuration.setKeys(Collections.emptySet());
|
||||||
configuration.setFromMetadata(false);
|
configuration.setCopyFrom(TbMsgSource.DATA);
|
||||||
return configuration;
|
return configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,63 +21,69 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.thingsboard.common.util.JacksonUtil;
|
import org.thingsboard.common.util.JacksonUtil;
|
||||||
import org.thingsboard.rule.engine.api.RuleNode;
|
import org.thingsboard.rule.engine.api.RuleNode;
|
||||||
import org.thingsboard.rule.engine.api.TbContext;
|
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.TbNodeConfiguration;
|
||||||
import org.thingsboard.rule.engine.api.TbNodeException;
|
import org.thingsboard.rule.engine.api.TbNodeException;
|
||||||
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
||||||
|
import org.thingsboard.rule.engine.util.TbMsgSource;
|
||||||
import org.thingsboard.server.common.data.plugin.ComponentType;
|
import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||||
import org.thingsboard.server.common.msg.TbMsg;
|
import org.thingsboard.server.common.msg.TbMsg;
|
||||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RuleNode(
|
@RuleNode(
|
||||||
type = ComponentType.TRANSFORMATION,
|
type = ComponentType.TRANSFORMATION,
|
||||||
name = "delete keys",
|
name = "delete key-values",
|
||||||
|
version = 1,
|
||||||
configClazz = TbDeleteKeysNodeConfiguration.class,
|
configClazz = TbDeleteKeysNodeConfiguration.class,
|
||||||
nodeDescription = "Removes keys from the msg data or metadata with the specified key names selected in the list",
|
nodeDescription = "Removes key-values from message or metadata.",
|
||||||
nodeDetails = "Will fetch fields (regex) values specified in list. If specified field (regex) is not part of msg " +
|
nodeDetails = "Removes key-values from message or message metadata based on the keys list specified in the configuration. " +
|
||||||
"or metadata fields it will be ignored. Returns transformed messages via <code>Success</code> chain",
|
"Use regular expression(s) as a key(s) to remove keys by pattern.<br><br>" +
|
||||||
|
"Output connections: <code>Success</code>, <code>Failure</code>.",
|
||||||
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
||||||
configDirective = "tbTransformationNodeDeleteKeysConfig",
|
configDirective = "tbTransformationNodeDeleteKeysConfig",
|
||||||
icon = "remove_circle"
|
icon = "remove_circle"
|
||||||
)
|
)
|
||||||
public class TbDeleteKeysNode implements TbNode {
|
public class TbDeleteKeysNode extends TbAbstractTransformNodeWithTbMsgSource {
|
||||||
|
|
||||||
private TbDeleteKeysNodeConfiguration config;
|
private TbDeleteKeysNodeConfiguration config;
|
||||||
private List<Pattern> patternKeys;
|
private List<Pattern> patternKeys;
|
||||||
private boolean fromMetadata;
|
private TbMsgSource deleteFrom;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
|
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
|
||||||
this.config = TbNodeUtils.convert(configuration, TbDeleteKeysNodeConfiguration.class);
|
this.config = TbNodeUtils.convert(configuration, TbDeleteKeysNodeConfiguration.class);
|
||||||
this.fromMetadata = config.isFromMetadata();
|
this.deleteFrom = config.getDeleteFrom();
|
||||||
this.patternKeys = new ArrayList<>();
|
if (deleteFrom == null) {
|
||||||
config.getKeys().forEach(key -> {
|
throw new TbNodeException("DeleteFrom can't be null! Allowed values: " + Arrays.toString(TbMsgSource.values()));
|
||||||
this.patternKeys.add(Pattern.compile(key));
|
}
|
||||||
});
|
this.patternKeys = config.getKeys().stream().map(Pattern::compile).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException {
|
public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException {
|
||||||
TbMsgMetaData metaData = msg.getMetaData();
|
TbMsgMetaData metaDataCopy = msg.getMetaData().copy();
|
||||||
String msgData = msg.getData();
|
String msgData = msg.getData();
|
||||||
List<String> keysToDelete = new ArrayList<>();
|
List<String> keysToDelete = new ArrayList<>();
|
||||||
if (fromMetadata) {
|
switch (deleteFrom) {
|
||||||
Map<String, String> metaDataMap = metaData.getData();
|
case METADATA:
|
||||||
|
Map<String, String> metaDataMap = metaDataCopy.getData();
|
||||||
metaDataMap.forEach((keyMetaData, valueMetaData) -> {
|
metaDataMap.forEach((keyMetaData, valueMetaData) -> {
|
||||||
if (checkKey(keyMetaData)) {
|
if (checkKey(keyMetaData)) {
|
||||||
keysToDelete.add(keyMetaData);
|
keysToDelete.add(keyMetaData);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
keysToDelete.forEach(metaDataMap::remove);
|
keysToDelete.forEach(metaDataMap::remove);
|
||||||
metaData = new TbMsgMetaData(metaDataMap);
|
metaDataCopy = new TbMsgMetaData(metaDataMap);
|
||||||
} else {
|
break;
|
||||||
|
case DATA:
|
||||||
JsonNode dataNode = JacksonUtil.toJsonNode(msgData);
|
JsonNode dataNode = JacksonUtil.toJsonNode(msgData);
|
||||||
if (dataNode.isObject()) {
|
if (dataNode.isObject()) {
|
||||||
ObjectNode msgDataObject = (ObjectNode) dataNode;
|
ObjectNode msgDataObject = (ObjectNode) dataNode;
|
||||||
@ -90,15 +96,21 @@ public class TbDeleteKeysNode implements TbNode {
|
|||||||
msgDataObject.remove(keysToDelete);
|
msgDataObject.remove(keysToDelete);
|
||||||
msgData = JacksonUtil.toString(msgDataObject);
|
msgData = JacksonUtil.toString(msgDataObject);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log.debug("Unexpected DeleteFrom value: {}. Allowed values: {}", deleteFrom, TbMsgSource.values());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (keysToDelete.isEmpty()) {
|
ctx.tellSuccess(keysToDelete.isEmpty() ? msg : TbMsg.transformMsg(msg, metaDataCopy, msgData));
|
||||||
ctx.tellSuccess(msg);
|
|
||||||
} else {
|
|
||||||
ctx.tellSuccess(TbMsg.transformMsg(msg, metaData, msgData));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getKeyToUpgradeFromVersionZero() {
|
||||||
|
return "deleteFrom";
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean checkKey(String key) {
|
boolean checkKey(String key) {
|
||||||
return patternKeys.stream().anyMatch(pattern -> pattern.matcher(key).matches());
|
return patternKeys.stream().anyMatch(pattern -> pattern.matcher(key).matches());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,7 @@ package org.thingsboard.rule.engine.transform;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.thingsboard.rule.engine.api.NodeConfiguration;
|
import org.thingsboard.rule.engine.api.NodeConfiguration;
|
||||||
|
import org.thingsboard.rule.engine.util.TbMsgSource;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -24,14 +25,14 @@ import java.util.Set;
|
|||||||
@Data
|
@Data
|
||||||
public class TbDeleteKeysNodeConfiguration implements NodeConfiguration<TbDeleteKeysNodeConfiguration> {
|
public class TbDeleteKeysNodeConfiguration implements NodeConfiguration<TbDeleteKeysNodeConfiguration> {
|
||||||
|
|
||||||
private boolean fromMetadata;
|
private TbMsgSource deleteFrom;
|
||||||
private Set<String> keys;
|
private Set<String> keys;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TbDeleteKeysNodeConfiguration defaultConfiguration() {
|
public TbDeleteKeysNodeConfiguration defaultConfiguration() {
|
||||||
TbDeleteKeysNodeConfiguration configuration = new TbDeleteKeysNodeConfiguration();
|
TbDeleteKeysNodeConfiguration configuration = new TbDeleteKeysNodeConfiguration();
|
||||||
configuration.setKeys(Collections.emptySet());
|
configuration.setKeys(Collections.emptySet());
|
||||||
configuration.setFromMetadata(false);
|
configuration.setDeleteFrom(TbMsgSource.DATA);
|
||||||
return configuration;
|
return configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -38,10 +38,10 @@ import java.util.concurrent.ExecutionException;
|
|||||||
name = "json path",
|
name = "json path",
|
||||||
configClazz = TbJsonPathNodeConfiguration.class,
|
configClazz = TbJsonPathNodeConfiguration.class,
|
||||||
nodeDescription = "Transforms incoming message body using JSONPath expression.",
|
nodeDescription = "Transforms incoming message body using JSONPath expression.",
|
||||||
nodeDetails = "JSONPath expression specifies a path to an element or a set of elements in a JSON structure. <br/>"
|
nodeDetails = "JSONPath expression specifies a path to an element or a set of elements in a JSON structure. <br/>" +
|
||||||
+ "<b>'$'</b> represents the root object or array. <br/>"
|
"<b>'$'</b> represents the root object or array. <br/>" +
|
||||||
+ "If JSONPath expression evaluation failed, incoming message routes via <code>Failure</code> chain, "
|
"If JSONPath expression evaluation failed, incoming message routes via <code>Failure</code> chain.<br><br>" +
|
||||||
+ "otherwise <code>Success</code> chain is used.",
|
"Output connections: <code>Success</code>, <code>Failure</code>.",
|
||||||
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
||||||
icon = "functions",
|
icon = "functions",
|
||||||
configDirective = "tbTransformationNodeJsonPathConfig"
|
configDirective = "tbTransformationNodeJsonPathConfig"
|
||||||
|
|||||||
@ -21,14 +21,15 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.thingsboard.common.util.JacksonUtil;
|
import org.thingsboard.common.util.JacksonUtil;
|
||||||
import org.thingsboard.rule.engine.api.RuleNode;
|
import org.thingsboard.rule.engine.api.RuleNode;
|
||||||
import org.thingsboard.rule.engine.api.TbContext;
|
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.TbNodeConfiguration;
|
||||||
import org.thingsboard.rule.engine.api.TbNodeException;
|
import org.thingsboard.rule.engine.api.TbNodeException;
|
||||||
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
||||||
|
import org.thingsboard.rule.engine.util.TbMsgSource;
|
||||||
import org.thingsboard.server.common.data.plugin.ComponentType;
|
import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||||
import org.thingsboard.server.common.msg.TbMsg;
|
import org.thingsboard.server.common.msg.TbMsg;
|
||||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
@ -36,34 +37,43 @@ import java.util.concurrent.ExecutionException;
|
|||||||
@RuleNode(
|
@RuleNode(
|
||||||
type = ComponentType.TRANSFORMATION,
|
type = ComponentType.TRANSFORMATION,
|
||||||
name = "rename keys",
|
name = "rename keys",
|
||||||
|
version = 1,
|
||||||
configClazz = TbRenameKeysNodeConfiguration.class,
|
configClazz = TbRenameKeysNodeConfiguration.class,
|
||||||
nodeDescription = "Renames msg data or metadata keys to the new key names selected in the key mapping.",
|
nodeDescription = "Renames message or message metadata key names to the new key names selected in the key mapping.",
|
||||||
nodeDetails = "If the key that is selected in the key mapping is missed in the selected msg source(data or metadata), it will be ignored." +
|
nodeDetails = "If the key name that is selected in the key mapping is missed in the " +
|
||||||
" Returns transformed messages via <code>Success</code> chain",
|
"selected source(message or message metadata), it will be ignored.<br><br>" +
|
||||||
|
"Output connections: <code>Success</code>, <code>Failure</code>.",
|
||||||
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
||||||
configDirective = "tbTransformationNodeRenameKeysConfig",
|
configDirective = "tbTransformationNodeRenameKeysConfig",
|
||||||
icon = "find_replace"
|
icon = "find_replace"
|
||||||
)
|
)
|
||||||
public class TbRenameKeysNode implements TbNode {
|
public class TbRenameKeysNode extends TbAbstractTransformNodeWithTbMsgSource {
|
||||||
|
|
||||||
private TbRenameKeysNodeConfiguration config;
|
private TbRenameKeysNodeConfiguration config;
|
||||||
private Map<String, String> renameKeysMapping;
|
private Map<String, String> renameKeysMapping;
|
||||||
private boolean fromMetadata;
|
private TbMsgSource renameIn;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
|
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
|
||||||
this.config = TbNodeUtils.convert(configuration, TbRenameKeysNodeConfiguration.class);
|
this.config = TbNodeUtils.convert(configuration, TbRenameKeysNodeConfiguration.class);
|
||||||
|
this.renameIn = config.getRenameIn();
|
||||||
this.renameKeysMapping = config.getRenameKeysMapping();
|
this.renameKeysMapping = config.getRenameKeysMapping();
|
||||||
this.fromMetadata = config.isFromMetadata();
|
if (renameIn == null) {
|
||||||
|
throw new TbNodeException("RenameIn can't be null! Allowed values: " + Arrays.toString(TbMsgSource.values()));
|
||||||
|
}
|
||||||
|
if (renameKeysMapping == null || renameKeysMapping.isEmpty()) {
|
||||||
|
throw new TbNodeException("At least one mapping entry should be specified!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException {
|
public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException {
|
||||||
TbMsgMetaData metaData = msg.getMetaData();
|
TbMsgMetaData metaDataCopy = msg.getMetaData().copy();
|
||||||
String data = msg.getData();
|
String data = msg.getData();
|
||||||
boolean msgChanged = false;
|
boolean msgChanged = false;
|
||||||
if (fromMetadata) {
|
switch (renameIn) {
|
||||||
Map<String, String> metaDataMap = metaData.getData();
|
case METADATA:
|
||||||
|
Map<String, String> metaDataMap = metaDataCopy.getData();
|
||||||
for (Map.Entry<String, String> entry : renameKeysMapping.entrySet()) {
|
for (Map.Entry<String, String> entry : renameKeysMapping.entrySet()) {
|
||||||
String nameKey = entry.getKey();
|
String nameKey = entry.getKey();
|
||||||
if (metaDataMap.containsKey(nameKey)) {
|
if (metaDataMap.containsKey(nameKey)) {
|
||||||
@ -72,8 +82,9 @@ public class TbRenameKeysNode implements TbNode {
|
|||||||
metaDataMap.remove(nameKey);
|
metaDataMap.remove(nameKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
metaData = new TbMsgMetaData(metaDataMap);
|
metaDataCopy = new TbMsgMetaData(metaDataMap);
|
||||||
} else {
|
break;
|
||||||
|
case DATA:
|
||||||
JsonNode dataNode = JacksonUtil.toJsonNode(data);
|
JsonNode dataNode = JacksonUtil.toJsonNode(data);
|
||||||
if (dataNode.isObject()) {
|
if (dataNode.isObject()) {
|
||||||
ObjectNode msgData = (ObjectNode) dataNode;
|
ObjectNode msgData = (ObjectNode) dataNode;
|
||||||
@ -87,11 +98,17 @@ public class TbRenameKeysNode implements TbNode {
|
|||||||
}
|
}
|
||||||
data = JacksonUtil.toString(msgData);
|
data = JacksonUtil.toString(msgData);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log.debug("Unexpected RenameIn value: {}. Allowed values: {}", renameIn, TbMsgSource.values());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (msgChanged) {
|
ctx.tellSuccess(msgChanged ? TbMsg.transformMsg(msg, metaDataCopy, data) : msg);
|
||||||
ctx.tellSuccess(TbMsg.transformMsg(msg, metaData, data));
|
|
||||||
} else {
|
|
||||||
ctx.tellSuccess(msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getKeyToUpgradeFromVersionZero() {
|
||||||
|
return "renameIn";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,20 +17,21 @@ package org.thingsboard.rule.engine.transform;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.thingsboard.rule.engine.api.NodeConfiguration;
|
import org.thingsboard.rule.engine.api.NodeConfiguration;
|
||||||
|
import org.thingsboard.rule.engine.util.TbMsgSource;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class TbRenameKeysNodeConfiguration implements NodeConfiguration<TbRenameKeysNodeConfiguration> {
|
public class TbRenameKeysNodeConfiguration implements NodeConfiguration<TbRenameKeysNodeConfiguration> {
|
||||||
|
|
||||||
private boolean fromMetadata;
|
private TbMsgSource renameIn;
|
||||||
private Map<String, String> renameKeysMapping;
|
private Map<String, String> renameKeysMapping;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TbRenameKeysNodeConfiguration defaultConfiguration() {
|
public TbRenameKeysNodeConfiguration defaultConfiguration() {
|
||||||
TbRenameKeysNodeConfiguration configuration = new TbRenameKeysNodeConfiguration();
|
TbRenameKeysNodeConfiguration configuration = new TbRenameKeysNodeConfiguration();
|
||||||
configuration.setRenameKeysMapping(Map.of("temp", "temperature"));
|
configuration.setRenameKeysMapping(Map.of("temperatureCelsius", "temperature"));
|
||||||
configuration.setFromMetadata(false);
|
configuration.setRenameIn(TbMsgSource.DATA);
|
||||||
return configuration;
|
return configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -25,8 +25,8 @@ import org.thingsboard.rule.engine.api.TbContext;
|
|||||||
import org.thingsboard.rule.engine.api.TbNode;
|
import org.thingsboard.rule.engine.api.TbNode;
|
||||||
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
|
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
|
||||||
import org.thingsboard.rule.engine.api.TbNodeException;
|
import org.thingsboard.rule.engine.api.TbNodeException;
|
||||||
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
|
|
||||||
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
||||||
|
import org.thingsboard.server.common.data.msg.TbNodeConnectionType;
|
||||||
import org.thingsboard.server.common.data.plugin.ComponentType;
|
import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||||
import org.thingsboard.server.common.msg.TbMsg;
|
import org.thingsboard.server.common.msg.TbMsg;
|
||||||
import org.thingsboard.server.common.msg.queue.RuleEngineException;
|
import org.thingsboard.server.common.msg.queue.RuleEngineException;
|
||||||
@ -39,10 +39,11 @@ import java.util.concurrent.ExecutionException;
|
|||||||
type = ComponentType.TRANSFORMATION,
|
type = ComponentType.TRANSFORMATION,
|
||||||
name = "split array msg",
|
name = "split array msg",
|
||||||
configClazz = EmptyNodeConfiguration.class,
|
configClazz = EmptyNodeConfiguration.class,
|
||||||
nodeDescription = "Split array message into several msgs",
|
nodeDescription = "Split array message into several messages",
|
||||||
nodeDetails = "Split the array fetched from the msg body. If the msg data is not a JSON array returns the "
|
nodeDetails = "Split the array fetched from the message. If the msg data is not a JSON array returns the "
|
||||||
+ "incoming message as outbound message with <code>Failure</code> chain, otherwise returns "
|
+ "incoming message as outbound message with <code>Failure</code> chain, otherwise returns "
|
||||||
+ "inner objects of the extracted array as separate messages via <code>Success</code> chain.",
|
+ "inner objects of the extracted array as separate messages via <code>Success</code> chain.<br><br>" +
|
||||||
|
"Output connections: <code>Success</code>, <code>Failure</code>.",
|
||||||
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
||||||
icon = "content_copy",
|
icon = "content_copy",
|
||||||
configDirective = "tbNodeEmptyConfig"
|
configDirective = "tbNodeEmptyConfig"
|
||||||
|
|||||||
@ -39,7 +39,8 @@ import java.util.List;
|
|||||||
"<code>msgType</code> - is a Message type.<br/>" +
|
"<code>msgType</code> - is a Message type.<br/>" +
|
||||||
"Should return the following structure:<br/>" +
|
"Should return the following structure:<br/>" +
|
||||||
"<code>{ msg: <i style=\"color: #666;\">new payload</i>,<br/>   metadata: <i style=\"color: #666;\">new metadata</i>,<br/>   msgType: <i style=\"color: #666;\">new msgType</i> }</code><br/>" +
|
"<code>{ msg: <i style=\"color: #666;\">new payload</i>,<br/>   metadata: <i style=\"color: #666;\">new metadata</i>,<br/>   msgType: <i style=\"color: #666;\">new msgType</i> }</code><br/>" +
|
||||||
"All fields in resulting object are optional and will be taken from original message if not specified.",
|
"All fields in resulting object are optional and will be taken from original message if not specified.<br><br>" +
|
||||||
|
"Output connections: <code>Success</code>, <code>Failure</code>.",
|
||||||
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
||||||
configDirective = "tbTransformationNodeScriptConfig"
|
configDirective = "tbTransformationNodeScriptConfig"
|
||||||
)
|
)
|
||||||
|
|||||||
@ -59,6 +59,7 @@ import org.thingsboard.server.dao.device.DeviceService;
|
|||||||
import org.thingsboard.server.dao.timeseries.TimeseriesService;
|
import org.thingsboard.server.dao.timeseries.TimeseriesService;
|
||||||
import org.thingsboard.server.dao.user.UserService;
|
import org.thingsboard.server.dao.user.UserService;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -119,7 +120,7 @@ public class TbGetCustomerAttributeNodeTest {
|
|||||||
var exception = assertThrows(TbNodeException.class, () -> node.init(ctxMock, nodeConfiguration));
|
var exception = assertThrows(TbNodeException.class, () -> node.init(ctxMock, nodeConfiguration));
|
||||||
|
|
||||||
// THEN
|
// THEN
|
||||||
assertThat(exception.getMessage()).isEqualTo("FetchTo cannot be null!");
|
assertThat(exception.getMessage()).isEqualTo("FetchTo option can't be null! Allowed values: " + Arrays.toString(TbMsgSource.values()));
|
||||||
verify(ctxMock, never()).tellSuccess(any());
|
verify(ctxMock, never()).tellSuccess(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -57,6 +57,7 @@ import org.thingsboard.server.dao.edge.EdgeService;
|
|||||||
import org.thingsboard.server.dao.entityview.EntityViewService;
|
import org.thingsboard.server.dao.entityview.EntityViewService;
|
||||||
import org.thingsboard.server.dao.user.UserService;
|
import org.thingsboard.server.dao.user.UserService;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
@ -127,7 +128,7 @@ public class TbGetCustomerDetailsNodeTest {
|
|||||||
var exception = assertThrows(TbNodeException.class, () -> node.init(ctxMock, nodeConfiguration));
|
var exception = assertThrows(TbNodeException.class, () -> node.init(ctxMock, nodeConfiguration));
|
||||||
|
|
||||||
// THEN
|
// THEN
|
||||||
assertThat(exception.getMessage()).isEqualTo("FetchTo cannot be null!");
|
assertThat(exception.getMessage()).isEqualTo("FetchTo option can't be null! Allowed values: " + Arrays.toString(TbMsgSource.values()));
|
||||||
verify(ctxMock, never()).tellSuccess(any());
|
verify(ctxMock, never()).tellSuccess(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -40,6 +40,7 @@ import org.thingsboard.server.common.msg.TbMsg;
|
|||||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||||
import org.thingsboard.server.dao.device.DeviceService;
|
import org.thingsboard.server.dao.device.DeviceService;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -86,7 +87,7 @@ public class TbGetOriginatorFieldsNodeTest {
|
|||||||
var exception = assertThrows(TbNodeException.class, () -> node.init(ctxMock, nodeConfiguration));
|
var exception = assertThrows(TbNodeException.class, () -> node.init(ctxMock, nodeConfiguration));
|
||||||
|
|
||||||
// THEN
|
// THEN
|
||||||
assertThat(exception.getMessage()).isEqualTo("FetchTo cannot be null!");
|
assertThat(exception.getMessage()).isEqualTo("FetchTo option can't be null! Allowed values: " + Arrays.toString(TbMsgSource.values()));
|
||||||
verify(ctxMock, never()).tellSuccess(any());
|
verify(ctxMock, never()).tellSuccess(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -127,7 +127,7 @@ public class TbGetRelatedAttributeNodeTest {
|
|||||||
var exception = assertThrows(TbNodeException.class, () -> node.init(ctxMock, nodeConfiguration));
|
var exception = assertThrows(TbNodeException.class, () -> node.init(ctxMock, nodeConfiguration));
|
||||||
|
|
||||||
// THEN
|
// THEN
|
||||||
assertThat(exception.getMessage()).isEqualTo("FetchTo cannot be null!");
|
assertThat(exception.getMessage()).isEqualTo("FetchTo option can't be null! Allowed values: " + Arrays.toString(TbMsgSource.values()));
|
||||||
verify(ctxMock, never()).tellSuccess(any());
|
verify(ctxMock, never()).tellSuccess(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -50,6 +50,7 @@ import org.thingsboard.server.common.msg.TbMsgMetaData;
|
|||||||
import org.thingsboard.server.dao.attributes.AttributesService;
|
import org.thingsboard.server.dao.attributes.AttributesService;
|
||||||
import org.thingsboard.server.dao.timeseries.TimeseriesService;
|
import org.thingsboard.server.dao.timeseries.TimeseriesService;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -99,7 +100,7 @@ public class TbGetTenantAttributeNodeTest {
|
|||||||
var exception = assertThrows(TbNodeException.class, () -> node.init(ctxMock, nodeConfiguration));
|
var exception = assertThrows(TbNodeException.class, () -> node.init(ctxMock, nodeConfiguration));
|
||||||
|
|
||||||
// THEN
|
// THEN
|
||||||
assertThat(exception.getMessage()).isEqualTo("FetchTo cannot be null!");
|
assertThat(exception.getMessage()).isEqualTo("FetchTo option can't be null! Allowed values: " + Arrays.toString(TbMsgSource.values()));
|
||||||
verify(ctxMock, never()).tellSuccess(any());
|
verify(ctxMock, never()).tellSuccess(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -39,6 +39,7 @@ import org.thingsboard.server.common.msg.TbMsg;
|
|||||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||||
import org.thingsboard.server.dao.tenant.TenantService;
|
import org.thingsboard.server.dao.tenant.TenantService;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -96,7 +97,7 @@ public class TbGetTenantDetailsNodeTest {
|
|||||||
var exception = assertThrows(TbNodeException.class, () -> node.init(ctxMock, nodeConfiguration));
|
var exception = assertThrows(TbNodeException.class, () -> node.init(ctxMock, nodeConfiguration));
|
||||||
|
|
||||||
// THEN
|
// THEN
|
||||||
assertThat(exception.getMessage()).isEqualTo("FetchTo cannot be null!");
|
assertThat(exception.getMessage()).isEqualTo("FetchTo option can't be null! Allowed values: " + Arrays.toString(TbMsgSource.values()));
|
||||||
verify(ctxMock, never()).tellSuccess(any());
|
verify(ctxMock, never()).tellSuccess(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
package org.thingsboard.rule.engine.transform;
|
package org.thingsboard.rule.engine.transform;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -24,9 +25,11 @@ import org.thingsboard.common.util.JacksonUtil;
|
|||||||
import org.thingsboard.rule.engine.api.TbContext;
|
import org.thingsboard.rule.engine.api.TbContext;
|
||||||
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
|
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
|
||||||
import org.thingsboard.rule.engine.api.TbNodeException;
|
import org.thingsboard.rule.engine.api.TbNodeException;
|
||||||
|
import org.thingsboard.rule.engine.util.TbMsgSource;
|
||||||
import org.thingsboard.server.common.data.id.DeviceId;
|
import org.thingsboard.server.common.data.id.DeviceId;
|
||||||
import org.thingsboard.server.common.data.id.EntityId;
|
import org.thingsboard.server.common.data.id.EntityId;
|
||||||
import org.thingsboard.server.common.data.msg.TbMsgType;
|
import org.thingsboard.server.common.data.msg.TbMsgType;
|
||||||
|
import org.thingsboard.server.common.data.util.TbPair;
|
||||||
import org.thingsboard.server.common.msg.TbMsg;
|
import org.thingsboard.server.common.msg.TbMsg;
|
||||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||||
import org.thingsboard.server.common.msg.queue.TbMsgCallback;
|
import org.thingsboard.server.common.msg.queue.TbMsgCallback;
|
||||||
@ -37,6 +40,8 @@ import java.util.Set;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
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.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
@ -59,7 +64,7 @@ public class TbCopyKeysNodeTest {
|
|||||||
ctx = mock(TbContext.class);
|
ctx = mock(TbContext.class);
|
||||||
config = new TbCopyKeysNodeConfiguration().defaultConfiguration();
|
config = new TbCopyKeysNodeConfiguration().defaultConfiguration();
|
||||||
config.setKeys(Set.of("TestKey_1", "TestKey_2", "TestKey_3", "(\\w*)Data(\\w*)"));
|
config.setKeys(Set.of("TestKey_1", "TestKey_2", "TestKey_3", "(\\w*)Data(\\w*)"));
|
||||||
config.setFromMetadata(true);
|
config.setCopyFrom(TbMsgSource.METADATA);
|
||||||
nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config));
|
nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config));
|
||||||
node = spy(new TbCopyKeysNode());
|
node = spy(new TbCopyKeysNode());
|
||||||
node.init(ctx, nodeConfiguration);
|
node.init(ctx, nodeConfiguration);
|
||||||
@ -74,7 +79,7 @@ public class TbCopyKeysNodeTest {
|
|||||||
void givenDefaultConfig_whenVerify_thenOK() {
|
void givenDefaultConfig_whenVerify_thenOK() {
|
||||||
TbCopyKeysNodeConfiguration defaultConfig = new TbCopyKeysNodeConfiguration().defaultConfiguration();
|
TbCopyKeysNodeConfiguration defaultConfig = new TbCopyKeysNodeConfiguration().defaultConfiguration();
|
||||||
assertThat(defaultConfig.getKeys()).isEqualTo(Collections.emptySet());
|
assertThat(defaultConfig.getKeys()).isEqualTo(Collections.emptySet());
|
||||||
assertThat(defaultConfig.isFromMetadata()).isEqualTo(false);
|
assertThat(defaultConfig.getCopyFrom()).isEqualTo(TbMsgSource.DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -95,7 +100,7 @@ public class TbCopyKeysNodeTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void givenMsgFromMsg_whenOnMsg_thenVerifyOutput() throws Exception {
|
void givenMsgFromMsg_whenOnMsg_thenVerifyOutput() throws Exception {
|
||||||
config.setFromMetadata(false);
|
config.setCopyFrom(TbMsgSource.DATA);
|
||||||
nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config));
|
nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config));
|
||||||
node.init(ctx, nodeConfiguration);
|
node.init(ctx, nodeConfiguration);
|
||||||
|
|
||||||
@ -149,6 +154,20 @@ public class TbCopyKeysNodeTest {
|
|||||||
assertThat(newMsg).isSameAs(msg);
|
assertThat(newMsg).isSameAs(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenOldConfig_whenUpgrade_thenShouldReturnTrueResultWithNewConfig() throws Exception {
|
||||||
|
// GIVEN
|
||||||
|
var config = new TbCopyKeysNodeConfiguration().defaultConfiguration();
|
||||||
|
var oldConfigJson = (ObjectNode) JacksonUtil.valueToTree(config);
|
||||||
|
oldConfigJson.remove("copyFrom");
|
||||||
|
oldConfigJson.put("fromMetadata", "false");
|
||||||
|
// WHEN
|
||||||
|
TbPair<Boolean, JsonNode> upgrade = node.upgrade(0, oldConfigJson);
|
||||||
|
// THEN
|
||||||
|
assertTrue(upgrade.getFirst());
|
||||||
|
assertEquals(config, JacksonUtil.treeToValue(upgrade.getSecond(), config.getClass()));
|
||||||
|
}
|
||||||
|
|
||||||
private TbMsg getTbMsg(EntityId entityId, String data) {
|
private TbMsg getTbMsg(EntityId entityId, String data) {
|
||||||
final Map<String, String> mdMap = Map.of(
|
final Map<String, String> mdMap = Map.of(
|
||||||
"TestKey_1", "Test",
|
"TestKey_1", "Test",
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
package org.thingsboard.rule.engine.transform;
|
package org.thingsboard.rule.engine.transform;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -24,9 +25,11 @@ import org.thingsboard.common.util.JacksonUtil;
|
|||||||
import org.thingsboard.rule.engine.api.TbContext;
|
import org.thingsboard.rule.engine.api.TbContext;
|
||||||
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
|
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
|
||||||
import org.thingsboard.rule.engine.api.TbNodeException;
|
import org.thingsboard.rule.engine.api.TbNodeException;
|
||||||
|
import org.thingsboard.rule.engine.util.TbMsgSource;
|
||||||
import org.thingsboard.server.common.data.id.DeviceId;
|
import org.thingsboard.server.common.data.id.DeviceId;
|
||||||
import org.thingsboard.server.common.data.id.EntityId;
|
import org.thingsboard.server.common.data.id.EntityId;
|
||||||
import org.thingsboard.server.common.data.msg.TbMsgType;
|
import org.thingsboard.server.common.data.msg.TbMsgType;
|
||||||
|
import org.thingsboard.server.common.data.util.TbPair;
|
||||||
import org.thingsboard.server.common.msg.TbMsg;
|
import org.thingsboard.server.common.msg.TbMsg;
|
||||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||||
import org.thingsboard.server.common.msg.queue.TbMsgCallback;
|
import org.thingsboard.server.common.msg.queue.TbMsgCallback;
|
||||||
@ -37,6 +40,8 @@ import java.util.Set;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
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.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
@ -59,7 +64,7 @@ public class TbDeleteKeysNodeTest {
|
|||||||
ctx = mock(TbContext.class);
|
ctx = mock(TbContext.class);
|
||||||
config = new TbDeleteKeysNodeConfiguration().defaultConfiguration();
|
config = new TbDeleteKeysNodeConfiguration().defaultConfiguration();
|
||||||
config.setKeys(Set.of("TestKey_1", "TestKey_2", "TestKey_3", "(\\w*)Data(\\w*)"));
|
config.setKeys(Set.of("TestKey_1", "TestKey_2", "TestKey_3", "(\\w*)Data(\\w*)"));
|
||||||
config.setFromMetadata(true);
|
config.setDeleteFrom(TbMsgSource.METADATA);
|
||||||
nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config));
|
nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config));
|
||||||
node = spy(new TbDeleteKeysNode());
|
node = spy(new TbDeleteKeysNode());
|
||||||
node.init(ctx, nodeConfiguration);
|
node.init(ctx, nodeConfiguration);
|
||||||
@ -74,7 +79,7 @@ public class TbDeleteKeysNodeTest {
|
|||||||
void givenDefaultConfig_whenVerify_thenOK() {
|
void givenDefaultConfig_whenVerify_thenOK() {
|
||||||
TbDeleteKeysNodeConfiguration defaultConfig = new TbDeleteKeysNodeConfiguration().defaultConfiguration();
|
TbDeleteKeysNodeConfiguration defaultConfig = new TbDeleteKeysNodeConfiguration().defaultConfiguration();
|
||||||
assertThat(defaultConfig.getKeys()).isEqualTo(Collections.emptySet());
|
assertThat(defaultConfig.getKeys()).isEqualTo(Collections.emptySet());
|
||||||
assertThat(defaultConfig.isFromMetadata()).isEqualTo(false);
|
assertThat(defaultConfig.getDeleteFrom()).isEqualTo(TbMsgSource.DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -95,7 +100,7 @@ public class TbDeleteKeysNodeTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void givenMsgFromMsg_whenOnMsg_thenVerifyOutput() throws Exception {
|
void givenMsgFromMsg_whenOnMsg_thenVerifyOutput() throws Exception {
|
||||||
config.setFromMetadata(false);
|
config.setDeleteFrom(TbMsgSource.DATA);
|
||||||
nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config));
|
nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config));
|
||||||
node.init(ctx, nodeConfiguration);
|
node.init(ctx, nodeConfiguration);
|
||||||
|
|
||||||
@ -133,6 +138,20 @@ public class TbDeleteKeysNodeTest {
|
|||||||
assertThat(newMsg.getData()).isEqualTo(data);
|
assertThat(newMsg.getData()).isEqualTo(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenOldConfig_whenUpgrade_thenShouldReturnTrueResultWithNewConfig() throws Exception {
|
||||||
|
// GIVEN
|
||||||
|
var config = new TbDeleteKeysNodeConfiguration().defaultConfiguration();
|
||||||
|
var oldConfigJson = (ObjectNode) JacksonUtil.valueToTree(config);
|
||||||
|
oldConfigJson.remove("deleteFrom");
|
||||||
|
oldConfigJson.put("fromMetadata", "false");
|
||||||
|
// WHEN
|
||||||
|
TbPair<Boolean, JsonNode> upgrade = node.upgrade(0, oldConfigJson);
|
||||||
|
// THEN
|
||||||
|
assertTrue(upgrade.getFirst());
|
||||||
|
assertEquals(config, JacksonUtil.treeToValue(upgrade.getSecond(), config.getClass()));
|
||||||
|
}
|
||||||
|
|
||||||
private TbMsg getTbMsg(EntityId entityId, String data) {
|
private TbMsg getTbMsg(EntityId entityId, String data) {
|
||||||
final Map<String, String> mdMap = Map.of(
|
final Map<String, String> mdMap = Map.of(
|
||||||
"TestKey_1", "Test",
|
"TestKey_1", "Test",
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
package org.thingsboard.rule.engine.transform;
|
package org.thingsboard.rule.engine.transform;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -24,9 +25,11 @@ import org.thingsboard.common.util.JacksonUtil;
|
|||||||
import org.thingsboard.rule.engine.api.TbContext;
|
import org.thingsboard.rule.engine.api.TbContext;
|
||||||
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
|
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
|
||||||
import org.thingsboard.rule.engine.api.TbNodeException;
|
import org.thingsboard.rule.engine.api.TbNodeException;
|
||||||
|
import org.thingsboard.rule.engine.util.TbMsgSource;
|
||||||
import org.thingsboard.server.common.data.id.DeviceId;
|
import org.thingsboard.server.common.data.id.DeviceId;
|
||||||
import org.thingsboard.server.common.data.id.EntityId;
|
import org.thingsboard.server.common.data.id.EntityId;
|
||||||
import org.thingsboard.server.common.data.msg.TbMsgType;
|
import org.thingsboard.server.common.data.msg.TbMsgType;
|
||||||
|
import org.thingsboard.server.common.data.util.TbPair;
|
||||||
import org.thingsboard.server.common.msg.TbMsg;
|
import org.thingsboard.server.common.msg.TbMsg;
|
||||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||||
import org.thingsboard.server.common.msg.queue.TbMsgCallback;
|
import org.thingsboard.server.common.msg.queue.TbMsgCallback;
|
||||||
@ -35,6 +38,8 @@ import java.util.Map;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
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.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
@ -70,8 +75,8 @@ public class TbRenameKeysNodeTest {
|
|||||||
@Test
|
@Test
|
||||||
void givenDefaultConfig_whenVerify_thenOK() {
|
void givenDefaultConfig_whenVerify_thenOK() {
|
||||||
TbRenameKeysNodeConfiguration defaultConfig = new TbRenameKeysNodeConfiguration().defaultConfiguration();
|
TbRenameKeysNodeConfiguration defaultConfig = new TbRenameKeysNodeConfiguration().defaultConfiguration();
|
||||||
assertThat(defaultConfig.getRenameKeysMapping()).isEqualTo(Map.of("temp", "temperature"));
|
assertThat(defaultConfig.getRenameKeysMapping()).isEqualTo(Map.of("temperatureCelsius", "temperature"));
|
||||||
assertThat(defaultConfig.isFromMetadata()).isEqualTo(false);
|
assertThat(defaultConfig.getRenameIn()).isEqualTo(TbMsgSource.DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -95,7 +100,7 @@ public class TbRenameKeysNodeTest {
|
|||||||
void givenMetadata_whenOnMsg_thenVerifyOutput() throws Exception {
|
void givenMetadata_whenOnMsg_thenVerifyOutput() throws Exception {
|
||||||
config = new TbRenameKeysNodeConfiguration().defaultConfiguration();
|
config = new TbRenameKeysNodeConfiguration().defaultConfiguration();
|
||||||
config.setRenameKeysMapping(Map.of("TestKey_1", "Attribute_1", "TestKey_2", "Attribute_2"));
|
config.setRenameKeysMapping(Map.of("TestKey_1", "Attribute_1", "TestKey_2", "Attribute_2"));
|
||||||
config.setFromMetadata(true);
|
config.setRenameIn(TbMsgSource.METADATA);
|
||||||
nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config));
|
nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config));
|
||||||
node.init(ctx, nodeConfiguration);
|
node.init(ctx, nodeConfiguration);
|
||||||
|
|
||||||
@ -148,6 +153,20 @@ public class TbRenameKeysNodeTest {
|
|||||||
assertThat(newMsg).isSameAs(msg);
|
assertThat(newMsg).isSameAs(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenOldConfig_whenUpgrade_thenShouldReturnTrueResultWithNewConfig() throws Exception {
|
||||||
|
// GIVEN
|
||||||
|
var config = new TbRenameKeysNodeConfiguration().defaultConfiguration();
|
||||||
|
var oldConfigJson = (ObjectNode) JacksonUtil.valueToTree(config);
|
||||||
|
oldConfigJson.remove("renameIn");
|
||||||
|
oldConfigJson.put("fromMetadata", "false");
|
||||||
|
// WHEN
|
||||||
|
TbPair<Boolean, JsonNode> upgrade = node.upgrade(0, oldConfigJson);
|
||||||
|
// THEN
|
||||||
|
assertTrue(upgrade.getFirst());
|
||||||
|
assertEquals(config, JacksonUtil.treeToValue(upgrade.getSecond(), config.getClass()));
|
||||||
|
}
|
||||||
|
|
||||||
private TbMsg getTbMsg(EntityId entityId, String data) {
|
private TbMsg getTbMsg(EntityId entityId, String data) {
|
||||||
final Map<String, String> mdMap = Map.of(
|
final Map<String, String> mdMap = Map.of(
|
||||||
"TestKey_1", "Test",
|
"TestKey_1", "Test",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user